• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "cert_manager_app_cert_process.h"
17 
18 #include <openssl/bn.h>
19 #include <openssl/bio.h>
20 #include <openssl/ec.h>
21 #include <openssl/err.h>
22 #include <openssl/evp.h>
23 #include <openssl/rsa.h>
24 #include <openssl/x509.h>
25 
26 #include "securec.h"
27 
28 #include "cert_manager_check.h"
29 #include "cert_manager_file_operator.h"
30 #include "cert_manager_key_operation.h"
31 #include "cert_manager_mem.h"
32 #include "cert_manager_storage.h"
33 #include "cert_manager_uri.h"
34 #include "cm_log.h"
35 #include "cm_pfx.h"
36 #include "cm_type.h"
37 
38 #include "hks_type.h"
39 
40 #define ECC_KEYPAIR_CNT 3
41 #define CM_RSA_KEYPAIR_CNT 3
42 #define CURVE25519_KEY_LEN_BYTES 32
43 #define CM_OPENSSL_SUCCESS 1
44 
TransEccKeyToKeyBlob(const EC_KEY * eccKey,const struct HksKeyMaterialEcc * keyMaterial,struct CmBlob * rawMaterial)45 static int32_t TransEccKeyToKeyBlob(const EC_KEY *eccKey, const struct HksKeyMaterialEcc *keyMaterial,
46     struct CmBlob *rawMaterial)
47 {
48     /* rawMaterial size ensure enougth */
49     int32_t ret = CM_FAILURE;
50     BIGNUM *pubX = BN_new();
51     BIGNUM *pubY = BN_new();
52     do {
53         if ((pubX == NULL) || (pubY == NULL)) {
54             CM_LOG_E("new Bn x or y failed");
55             break;
56         }
57 
58         const EC_GROUP *ecGroup = EC_KEY_get0_group(eccKey);
59         int retCode = EC_POINT_get_affine_coordinates_GFp(ecGroup, EC_KEY_get0_public_key(eccKey), pubX, pubY, NULL);
60         if (retCode <= 0) {
61             CM_LOG_E("EC_POINT_get_affine_coordinates_GFp failed");
62             break;
63         }
64 
65         uint32_t offset = sizeof(struct HksKeyMaterialEcc);
66         retCode = BN_bn2binpad(pubX, rawMaterial->data + offset, keyMaterial->xSize);
67         if (retCode <= 0) {
68             CM_LOG_E("BN_bn2binpad pubX failed");
69             break;
70         }
71         offset += keyMaterial->xSize;
72 
73         retCode = BN_bn2binpad(pubY, rawMaterial->data + offset, keyMaterial->ySize);
74         if (retCode <= 0) {
75             CM_LOG_E("BN_bn2binpad pubY failed");
76             break;
77         }
78         offset += keyMaterial->ySize;
79 
80         const BIGNUM *priv = EC_KEY_get0_private_key(eccKey);
81         retCode = BN_bn2binpad(priv, rawMaterial->data + offset, keyMaterial->zSize);
82         if (retCode <= 0) {
83             CM_LOG_E("BN_bn2binpad priv failed");
84             break;
85         }
86         ret = CM_SUCCESS;
87     } while (0);
88     if (pubX != NULL) {
89         BN_free(pubX);
90     }
91     if (pubY != NULL) {
92         BN_free(pubY);
93     }
94 
95     return ret;
96 }
97 
SaveKeyMaterialEcc(const EC_KEY * eccKey,const uint32_t keySize,struct CmBlob * keyOut)98 static int32_t SaveKeyMaterialEcc(const EC_KEY *eccKey, const uint32_t keySize, struct CmBlob *keyOut)
99 {
100     struct CmBlob rawMaterial = { 0, NULL };
101     /* public exponent x and y, and private exponent, so need size is: keySize / 8 * 3 */
102     rawMaterial.size = sizeof(struct HksKeyMaterialEcc) + CM_KEY_BYTES(keySize) * ECC_KEYPAIR_CNT;
103     rawMaterial.data = (uint8_t *)CMMalloc(rawMaterial.size);
104     if (rawMaterial.data == NULL) {
105         CM_LOG_E("malloc buffer failed!");
106         return CMR_ERROR_MALLOC_FAIL;
107     }
108     (void)memset_s(rawMaterial.data, rawMaterial.size, 0, rawMaterial.size);
109 
110     /*
111      * ECC key data internal struct:
112      * struct KeyMaterialEcc + pubX_data + pubY_data + pri_data
113      */
114     struct HksKeyMaterialEcc *keyMaterial = (struct HksKeyMaterialEcc *)rawMaterial.data;
115     keyMaterial->keyAlg = HKS_ALG_ECC;
116     keyMaterial->keySize = keySize;
117     keyMaterial->xSize = CM_KEY_BYTES(keySize);
118     keyMaterial->ySize = CM_KEY_BYTES(keySize);
119     keyMaterial->zSize = CM_KEY_BYTES(keySize);
120 
121     int32_t ret = TransEccKeyToKeyBlob(eccKey, keyMaterial, &rawMaterial);
122     if (ret != CM_SUCCESS) {
123         CM_LOG_E("transfer ecc key to key blob failed");
124         (void)memset_s(rawMaterial.data, rawMaterial.size, 0, rawMaterial.size);
125         CMFree(rawMaterial.data);
126         return ret;
127     }
128 
129     keyOut->data = rawMaterial.data;
130     keyOut->size = rawMaterial.size;
131     return ret;
132 }
133 
SaveKeyMaterialRsa(const RSA * rsa,const uint32_t keySize,struct CmBlob * keyOut)134 static int32_t SaveKeyMaterialRsa(const RSA *rsa, const uint32_t keySize, struct CmBlob *keyOut)
135 {
136     const uint32_t keyByteLen = keySize / CM_BITS_PER_BYTE;
137     const uint32_t rawMaterialLen = sizeof(struct HksKeyMaterialRsa) + keyByteLen * CM_RSA_KEYPAIR_CNT;
138     uint8_t *rawMaterial = (uint8_t *)CMMalloc(rawMaterialLen);
139     if (rawMaterial == NULL) {
140         return CMR_ERROR_MALLOC_FAIL;
141     }
142     (void)memset_s(rawMaterial, rawMaterialLen, 0, rawMaterialLen);
143 
144     struct HksKeyMaterialRsa *keyMaterial = (struct HksKeyMaterialRsa *)rawMaterial;
145     keyMaterial->keyAlg = HKS_ALG_RSA;
146     keyMaterial->keySize = keySize;
147 
148     uint8_t tmpBuff[HKS_RSA_KEY_SIZE_4096] = {0};
149     int32_t ret = CMR_ERROR_INVALID_OPERATION;
150     do {
151         uint32_t offset = sizeof(*keyMaterial);
152         keyMaterial->nSize = (uint32_t)BN_bn2bin(RSA_get0_n(rsa), tmpBuff);
153         if (memcpy_s(rawMaterial + offset, keyByteLen, tmpBuff, keyMaterial->nSize) != EOK) {
154             CM_LOG_E("copy rsa n failed");
155             break;
156         }
157 
158         offset += keyMaterial->nSize;
159         keyMaterial->eSize = (uint32_t)BN_bn2bin(RSA_get0_e(rsa), tmpBuff);
160         if (memcpy_s(rawMaterial + offset, keyByteLen, tmpBuff, keyMaterial->eSize) != EOK) {
161             CM_LOG_E("copy rsa e failed");
162             break;
163         }
164 
165         offset += keyMaterial->eSize;
166         keyMaterial->dSize = (uint32_t)BN_bn2bin(RSA_get0_d(rsa), tmpBuff);
167         if (memcpy_s(rawMaterial + offset, keyByteLen, tmpBuff, keyMaterial->dSize) != EOK) {
168             CM_LOG_E("copy rsa d failed");
169             break;
170         }
171 
172         keyOut->data = rawMaterial;
173         keyOut->size = sizeof(struct HksKeyMaterialRsa) + keyMaterial->nSize + keyMaterial->eSize + keyMaterial->dSize;
174         ret = CM_SUCCESS;
175     } while (0);
176 
177     (void)memset_s(tmpBuff, sizeof(tmpBuff), 0, sizeof(tmpBuff));
178     if (ret != CM_SUCCESS) {
179         (void)memset_s(rawMaterial, rawMaterialLen, 0, rawMaterialLen);
180         CMFree(rawMaterial);
181     }
182 
183     return ret;
184 }
185 
SaveKeyMaterialCurve25519(uint32_t algType,const EVP_PKEY * pKey,struct CmBlob * keyOut)186 static int32_t SaveKeyMaterialCurve25519(uint32_t algType, const EVP_PKEY *pKey, struct CmBlob *keyOut)
187 {
188     uint32_t totalSize = sizeof(struct HksKeyMaterial25519) + (CURVE25519_KEY_LEN_BYTES << 1);
189     uint8_t *buffer = (uint8_t *)CMMalloc(totalSize);
190     if (buffer == NULL) {
191         CM_LOG_E("malloc size %u failed", totalSize);
192         return CMR_ERROR_MALLOC_FAIL;
193     }
194     (void)memset_s(buffer, totalSize, 0, totalSize);
195 
196     uint32_t offset = sizeof(struct HksKeyMaterial25519);
197 
198     size_t tmpPubKeyLen = CURVE25519_KEY_LEN_BYTES;
199     size_t tmpPriKeyLen = CURVE25519_KEY_LEN_BYTES;
200     if (EVP_PKEY_get_raw_public_key(pKey, buffer + offset, &tmpPubKeyLen) != CM_OPENSSL_SUCCESS) {
201         CM_LOG_E("EVP_PKEY_get_raw_public_key failed");
202         (void)memset_s(buffer, totalSize, 0, totalSize);
203         CMFree(buffer);
204         return CMR_ERROR_INVALID_OPERATION;
205     }
206     uint32_t pubKeyLen = (uint32_t)tmpPubKeyLen;
207 
208     offset += pubKeyLen;
209     if (EVP_PKEY_get_raw_private_key(pKey, buffer + offset, &tmpPriKeyLen) != CM_OPENSSL_SUCCESS) {
210         CM_LOG_E("EVP_PKEY_get_raw_private_key");
211         (void)memset_s(buffer, totalSize, 0, totalSize);
212         CMFree(buffer);
213         return CMR_ERROR_INVALID_OPERATION;
214     }
215     uint32_t priKeyLen = (uint32_t)tmpPriKeyLen;
216 
217     struct HksKeyMaterial25519 *keyMaterial = (struct HksKeyMaterial25519 *)buffer;
218     keyMaterial->keyAlg = algType;
219     keyMaterial->keySize = HKS_CURVE25519_KEY_SIZE_256;
220     keyMaterial->pubKeySize = pubKeyLen;
221     keyMaterial->priKeySize = priKeyLen;
222 
223     keyOut->data = buffer;
224     keyOut->size = totalSize;
225     return CM_SUCCESS;
226 }
227 
ImportRsaKey(const EVP_PKEY * priKey,const struct CmBlob * keyUri)228 static int32_t ImportRsaKey(const EVP_PKEY *priKey, const struct CmBlob *keyUri)
229 {
230     struct CmBlob keyPair = { 0, NULL };
231     int32_t ret;
232     do {
233         RSA *rsa = EVP_PKEY_get0_RSA((EVP_PKEY *)priKey);
234         if (rsa == NULL) {
235             CM_LOG_E("EVP_PKEY_get1_RSA error %s", ERR_reason_error_string(ERR_get_error()));
236             ret = CM_FAILURE;
237             break;
238         }
239         uint32_t keySize = ((uint32_t)RSA_size(rsa)) * CM_BITS_PER_BYTE;
240 
241         ret = SaveKeyMaterialRsa(rsa, keySize, &keyPair);
242         if (ret != CMR_OK) {
243             CM_LOG_E("save rsa key material failed ret=0x%x", ret);
244             break;
245         }
246 
247         struct CmKeyProperties props = {
248             .algType = HKS_ALG_RSA,
249             .keySize = keySize,
250             .purpose = CM_KEY_PURPOSE_SIGN | CM_KEY_PURPOSE_VERIFY,
251         };
252 
253         ret = CmKeyOpImportKey(keyUri, &props, &keyPair);
254         if (ret != CMR_OK) {
255             CM_LOG_E("rsa keypair import faild");
256             break;
257         }
258     } while (0);
259     if (keyPair.data != NULL) {
260         (void)memset_s(keyPair.data, keyPair.size, 0, keyPair.size);
261         CMFree(keyPair.data);
262     }
263     return ret;
264 }
265 
ImportEccKey(const EVP_PKEY * priKey,const struct CmBlob * keyUri)266 static int32_t ImportEccKey(const EVP_PKEY *priKey, const struct CmBlob *keyUri)
267 {
268     struct CmBlob keyPair = { 0, NULL };
269     int32_t ret;
270     do {
271         EC_KEY *eccKey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *)priKey);
272         if (eccKey == NULL) {
273             CM_LOG_E("EVP_PKEY_get0_EC_KEY faild");
274             ret = CM_FAILURE;
275             break;
276         }
277 
278         uint32_t keyLen = (uint32_t)EC_GROUP_order_bits(EC_KEY_get0_group(eccKey));
279         ret = SaveKeyMaterialEcc(eccKey, keyLen, &keyPair);
280         if (ret != CMR_OK) {
281             CM_LOG_E("save ec key material failed ret=0x%x", ret);
282             break;
283         }
284 
285         const struct CmKeyProperties props = {
286             .algType = HKS_ALG_ECC,
287             .keySize = keyLen,
288             .purpose = CM_KEY_PURPOSE_SIGN | CM_KEY_PURPOSE_VERIFY,
289         };
290 
291         ret = CmKeyOpImportKey(keyUri, &props, &keyPair);
292         if (ret != CMR_OK) {
293             CM_LOG_E("ecc Key type import faild");
294             break;
295         }
296     } while (0);
297     if (keyPair.data != NULL) {
298         (void)memset_s(keyPair.data, keyPair.size, 0, keyPair.size);
299         CMFree(keyPair.data);
300     }
301 
302     return ret;
303 }
304 
ImportEd25519Key(const EVP_PKEY * priKey,const struct CmBlob * keyUri)305 static int32_t ImportEd25519Key(const EVP_PKEY *priKey, const struct CmBlob *keyUri)
306 {
307     struct CmBlob keyPair = { 0, NULL };
308     int32_t ret = SaveKeyMaterialCurve25519(HKS_ALG_ED25519, priKey, &keyPair);
309     if (ret != CMR_OK) {
310         CM_LOG_E("save curve25519 key material failed");
311         return ret;
312     }
313 
314     struct CmKeyProperties props = {
315         .algType = HKS_ALG_ED25519,
316         .keySize = HKS_CURVE25519_KEY_SIZE_256,
317         .purpose = CM_KEY_PURPOSE_SIGN | CM_KEY_PURPOSE_VERIFY,
318     };
319     ret = CmKeyOpImportKey(keyUri, &props, &keyPair);
320     if (ret != CMR_OK) {
321         CM_LOG_E("Ed25519 key type import faild");
322     }
323     if (keyPair.data != NULL) {
324         (void)memset_s(keyPair.data, keyPair.size, 0, keyPair.size);
325         CMFree(keyPair.data);
326     }
327 
328     return ret;
329 }
330 
ImportKeyPair(const EVP_PKEY * priKey,const struct CmBlob * keyUri)331 static int32_t ImportKeyPair(const EVP_PKEY *priKey, const struct CmBlob *keyUri)
332 {
333     switch (EVP_PKEY_base_id(priKey)) {
334         case EVP_PKEY_RSA:
335             return ImportRsaKey(priKey, keyUri);
336         case EVP_PKEY_EC:
337             return ImportEccKey(priKey, keyUri);
338         case EVP_PKEY_ED25519:
339             return ImportEd25519Key(priKey, keyUri);
340         default:
341             CM_LOG_E("Import key type not suported");
342             return CMR_ERROR_INVALID_ARGUMENT;
343     }
344 }
345 
StoreAppCert(const struct CmContext * context,struct AppCert * appCert,const uint32_t store,const struct CmBlob * keyUri)346 static int32_t StoreAppCert(const struct CmContext *context, struct AppCert *appCert,
347     const uint32_t store, const struct CmBlob *keyUri)
348 {
349     char pathBuf[CERT_MAX_PATH_LEN] = {0};
350     int32_t ret = ConstructUidPath(context, store, pathBuf, sizeof(pathBuf));
351     if (ret != CMR_OK) {
352         CM_LOG_E("Failed obtain path for store:%u", store);
353         return ret;
354     }
355 
356     appCert->keyCount = 1;
357     struct CmBlob certBlob = { 0, NULL };
358     certBlob.size = sizeof(struct AppCert) - MAX_LEN_CERTIFICATE_CHAIN + appCert->certSize;
359     certBlob.data = (uint8_t *)appCert;
360 
361     ret = CmFileWrite(pathBuf, (char *)keyUri->data, 0, certBlob.data, certBlob.size);
362     if (ret != CMR_OK) {
363         CM_LOG_E("Failed to write certificate");
364         return CMR_ERROR_WRITE_FILE_FAIL;
365     }
366     return ret;
367 }
368 
ConstructKeyUri(const struct CmContext * context,const struct CmBlob * certAlias,struct CmBlob * keyUri)369 static int32_t ConstructKeyUri(const struct CmContext *context, const struct CmBlob *certAlias, struct CmBlob *keyUri)
370 {
371     struct CmBlob commonUri = { 0, NULL };
372     int32_t ret;
373     do {
374         ret = CmConstructCommonUri(context, CM_URI_TYPE_APP_KEY, certAlias, &commonUri);
375         if (ret != CM_SUCCESS) {
376             CM_LOG_E("construct key uri get common uri failed");
377             break;
378         }
379 
380         if (keyUri->size < commonUri.size) {
381             CM_LOG_E("out key uri size[%u] too small", keyUri->size);
382             ret = CMR_ERROR_BUFFER_TOO_SMALL;
383             break;
384         }
385 
386         if (memcpy_s(keyUri->data, keyUri->size, commonUri.data, commonUri.size) != EOK) {
387             CM_LOG_E("copy key uri failed");
388             ret = CMR_ERROR_INVALID_OPERATION;
389             break;
390         }
391 
392         keyUri->size = commonUri.size;
393     } while (0);
394 
395     CM_FREE_PTR(commonUri.data);
396     return ret;
397 }
398 
CmInstallAppCertPro(const struct CmContext * context,struct CmAppCertInfo * appCertInfo,const struct CmBlob * certAlias,const uint32_t store,struct CmBlob * keyUri)399 int32_t CmInstallAppCertPro(const struct CmContext *context, struct CmAppCertInfo *appCertInfo,
400     const struct CmBlob *certAlias, const uint32_t store, struct CmBlob *keyUri)
401 {
402     struct AppCert appCert;
403     (void)memset_s(&appCert, sizeof(struct AppCert), 0, sizeof(struct AppCert));
404     EVP_PKEY *priKey = NULL;
405 
406     int32_t ret;
407     do {
408         ret = ConstructKeyUri(context, certAlias, keyUri);
409         if (ret != CM_SUCCESS) {
410             CM_LOG_E("construct app cert uri fail");
411             break;
412         }
413 
414         ret = CmParsePkcs12Cert(&appCertInfo->appCert, (char *)appCertInfo->appCertPwd.data, &priKey, &appCert);
415         if (ret != CM_SUCCESS) {
416             CM_LOG_E("CmParsePkcs12Cert fail");
417             break;
418         }
419 
420         ret = ImportKeyPair(priKey, keyUri);
421         if (ret != CM_SUCCESS) {
422             CM_LOG_E("import key pair failed");
423             break;
424         }
425 
426         ret = StoreAppCert(context, &appCert, store, keyUri);
427         if (ret != CM_SUCCESS) {
428             CM_LOG_E("store App Cert failed");
429             break;
430         }
431     } while (0);
432 
433     EVP_PKEY_free(priKey);
434     return ret;
435 }
436 
437