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.h"
29 #include "cert_manager_check.h"
30 #include "cert_manager_file_operator.h"
31 #include "cert_manager_key_operation.h"
32 #include "cert_manager_mem.h"
33 #include "cert_manager_storage.h"
34 #include "cert_manager_crypto_operation.h"
35 #include "cert_manager.h"
36 #include "cert_manager_service.h"
37 #include "cert_manager_uri.h"
38 #include "cm_log.h"
39 #include "cm_pfx.h"
40 #include "cm_type.h"
41 #include "cm_x509.h"
42 
43 #include "hks_type.h"
44 
45 #define ECC_KEYPAIR_CNT 3
46 #define CM_RSA_KEYPAIR_CNT 3
47 #define CURVE25519_KEY_LEN_BYTES 32
48 #define CM_OPENSSL_SUCCESS 1
49 
TransEccKeyToKeyBlob(const EC_KEY * eccKey,const struct HksKeyMaterialEcc * keyMaterial,struct CmBlob * rawMaterial)50 static int32_t TransEccKeyToKeyBlob(const EC_KEY *eccKey, const struct HksKeyMaterialEcc *keyMaterial,
51     struct CmBlob *rawMaterial)
52 {
53     /* rawMaterial size ensure enougth */
54     int32_t ret = CM_FAILURE;
55     BIGNUM *pubX = BN_new();
56     BIGNUM *pubY = BN_new();
57     do {
58         if ((pubX == NULL) || (pubY == NULL)) {
59             CM_LOG_E("new Bn x or y failed");
60             break;
61         }
62 
63         const EC_GROUP *ecGroup = EC_KEY_get0_group(eccKey);
64         int retCode = EC_POINT_get_affine_coordinates_GFp(ecGroup, EC_KEY_get0_public_key(eccKey), pubX, pubY, NULL);
65         if (retCode <= 0) {
66             CM_LOG_E("EC_POINT_get_affine_coordinates_GFp failed");
67             break;
68         }
69 
70         uint32_t offset = sizeof(struct HksKeyMaterialEcc);
71         retCode = BN_bn2binpad(pubX, rawMaterial->data + offset, keyMaterial->xSize);
72         if (retCode <= 0) {
73             CM_LOG_E("BN_bn2binpad pubX failed");
74             break;
75         }
76         offset += keyMaterial->xSize;
77 
78         retCode = BN_bn2binpad(pubY, rawMaterial->data + offset, keyMaterial->ySize);
79         if (retCode <= 0) {
80             CM_LOG_E("BN_bn2binpad pubY failed");
81             break;
82         }
83         offset += keyMaterial->ySize;
84 
85         const BIGNUM *priv = EC_KEY_get0_private_key(eccKey);
86         retCode = BN_bn2binpad(priv, rawMaterial->data + offset, keyMaterial->zSize);
87         if (retCode <= 0) {
88             CM_LOG_E("BN_bn2binpad priv failed");
89             break;
90         }
91         ret = CM_SUCCESS;
92     } while (0);
93     if (pubX != NULL) {
94         BN_free(pubX);
95     }
96     if (pubY != NULL) {
97         BN_free(pubY);
98     }
99 
100     return ret;
101 }
102 
SaveKeyMaterialEcc(const EC_KEY * eccKey,const uint32_t keySize,struct CmBlob * keyOut)103 static int32_t SaveKeyMaterialEcc(const EC_KEY *eccKey, const uint32_t keySize, struct CmBlob *keyOut)
104 {
105     struct CmBlob rawMaterial = { 0, NULL };
106     /* public exponent x and y, and private exponent, so need size is: keySize / 8 * 3 */
107     rawMaterial.size = sizeof(struct HksKeyMaterialEcc) + CM_KEY_BYTES(keySize) * ECC_KEYPAIR_CNT;
108     rawMaterial.data = (uint8_t *)CMMalloc(rawMaterial.size);
109     if (rawMaterial.data == NULL) {
110         CM_LOG_E("malloc buffer failed!");
111         return CMR_ERROR_MALLOC_FAIL;
112     }
113     (void)memset_s(rawMaterial.data, rawMaterial.size, 0, rawMaterial.size);
114 
115     /*
116      * ECC key data internal struct:
117      * struct KeyMaterialEcc + pubX_data + pubY_data + pri_data
118      */
119     struct HksKeyMaterialEcc *keyMaterial = (struct HksKeyMaterialEcc *)rawMaterial.data;
120     keyMaterial->keyAlg = HKS_ALG_ECC;
121     keyMaterial->keySize = keySize;
122     keyMaterial->xSize = CM_KEY_BYTES(keySize);
123     keyMaterial->ySize = CM_KEY_BYTES(keySize);
124     keyMaterial->zSize = CM_KEY_BYTES(keySize);
125 
126     int32_t ret = TransEccKeyToKeyBlob(eccKey, keyMaterial, &rawMaterial);
127     if (ret != CM_SUCCESS) {
128         CM_LOG_E("transfer ecc key to key blob failed");
129         (void)memset_s(rawMaterial.data, rawMaterial.size, 0, rawMaterial.size);
130         CMFree(rawMaterial.data);
131         return ret;
132     }
133 
134     keyOut->data = rawMaterial.data;
135     keyOut->size = rawMaterial.size;
136     return ret;
137 }
138 
SaveKeyMaterialRsa(const RSA * rsa,const uint32_t keySize,struct CmBlob * keyOut)139 static int32_t SaveKeyMaterialRsa(const RSA *rsa, const uint32_t keySize, struct CmBlob *keyOut)
140 {
141     const uint32_t keyByteLen = keySize / CM_BITS_PER_BYTE;
142     const uint32_t rawMaterialLen = sizeof(struct HksKeyMaterialRsa) + keyByteLen * CM_RSA_KEYPAIR_CNT;
143     uint8_t *rawMaterial = (uint8_t *)CMMalloc(rawMaterialLen);
144     if (rawMaterial == NULL) {
145         return CMR_ERROR_MALLOC_FAIL;
146     }
147     (void)memset_s(rawMaterial, rawMaterialLen, 0, rawMaterialLen);
148 
149     struct HksKeyMaterialRsa *keyMaterial = (struct HksKeyMaterialRsa *)rawMaterial;
150     keyMaterial->keyAlg = HKS_ALG_RSA;
151     keyMaterial->keySize = keySize;
152 
153     uint8_t tmpBuff[HKS_RSA_KEY_SIZE_4096] = {0};
154     int32_t ret = CMR_ERROR_INVALID_OPERATION;
155     do {
156         uint32_t offset = sizeof(*keyMaterial);
157         keyMaterial->nSize = (uint32_t)BN_bn2bin(RSA_get0_n(rsa), tmpBuff);
158         if (memcpy_s(rawMaterial + offset, keyByteLen, tmpBuff, keyMaterial->nSize) != EOK) {
159             CM_LOG_E("copy rsa n failed");
160             break;
161         }
162 
163         offset += keyMaterial->nSize;
164         keyMaterial->eSize = (uint32_t)BN_bn2bin(RSA_get0_e(rsa), tmpBuff);
165         if (memcpy_s(rawMaterial + offset, keyByteLen, tmpBuff, keyMaterial->eSize) != EOK) {
166             CM_LOG_E("copy rsa e failed");
167             break;
168         }
169 
170         offset += keyMaterial->eSize;
171         keyMaterial->dSize = (uint32_t)BN_bn2bin(RSA_get0_d(rsa), tmpBuff);
172         if (memcpy_s(rawMaterial + offset, keyByteLen, tmpBuff, keyMaterial->dSize) != EOK) {
173             CM_LOG_E("copy rsa d failed");
174             break;
175         }
176 
177         keyOut->data = rawMaterial;
178         keyOut->size = sizeof(struct HksKeyMaterialRsa) + keyMaterial->nSize + keyMaterial->eSize + keyMaterial->dSize;
179         ret = CM_SUCCESS;
180     } while (0);
181 
182     (void)memset_s(tmpBuff, sizeof(tmpBuff), 0, sizeof(tmpBuff));
183     if (ret != CM_SUCCESS) {
184         (void)memset_s(rawMaterial, rawMaterialLen, 0, rawMaterialLen);
185         CMFree(rawMaterial);
186     }
187 
188     return ret;
189 }
190 
SaveKeyMaterialCurve25519(uint32_t algType,const EVP_PKEY * pKey,struct CmBlob * keyOut)191 static int32_t SaveKeyMaterialCurve25519(uint32_t algType, const EVP_PKEY *pKey, struct CmBlob *keyOut)
192 {
193     uint32_t totalSize = sizeof(struct HksKeyMaterial25519) + (CURVE25519_KEY_LEN_BYTES << 1);
194     uint8_t *buffer = (uint8_t *)CMMalloc(totalSize);
195     if (buffer == NULL) {
196         CM_LOG_E("malloc size %u failed", totalSize);
197         return CMR_ERROR_MALLOC_FAIL;
198     }
199     (void)memset_s(buffer, totalSize, 0, totalSize);
200 
201     uint32_t offset = sizeof(struct HksKeyMaterial25519);
202 
203     size_t tmpPubKeyLen = CURVE25519_KEY_LEN_BYTES;
204     size_t tmpPriKeyLen = CURVE25519_KEY_LEN_BYTES;
205     if (EVP_PKEY_get_raw_public_key(pKey, buffer + offset, &tmpPubKeyLen) != CM_OPENSSL_SUCCESS) {
206         CM_LOG_E("EVP_PKEY_get_raw_public_key failed");
207         (void)memset_s(buffer, totalSize, 0, totalSize);
208         CMFree(buffer);
209         return CMR_ERROR_INVALID_OPERATION;
210     }
211     uint32_t pubKeyLen = (uint32_t)tmpPubKeyLen;
212 
213     offset += pubKeyLen;
214     if (EVP_PKEY_get_raw_private_key(pKey, buffer + offset, &tmpPriKeyLen) != CM_OPENSSL_SUCCESS) {
215         CM_LOG_E("EVP_PKEY_get_raw_private_key");
216         (void)memset_s(buffer, totalSize, 0, totalSize);
217         CMFree(buffer);
218         return CMR_ERROR_INVALID_OPERATION;
219     }
220     uint32_t priKeyLen = (uint32_t)tmpPriKeyLen;
221 
222     struct HksKeyMaterial25519 *keyMaterial = (struct HksKeyMaterial25519 *)buffer;
223     keyMaterial->keyAlg = algType;
224     keyMaterial->keySize = HKS_CURVE25519_KEY_SIZE_256;
225     keyMaterial->pubKeySize = pubKeyLen;
226     keyMaterial->priKeySize = priKeyLen;
227 
228     keyOut->data = buffer;
229     keyOut->size = totalSize;
230     return CM_SUCCESS;
231 }
232 
ImportRsaKey(const EVP_PKEY * priKey,const struct CmBlob * keyUri)233 static int32_t ImportRsaKey(const EVP_PKEY *priKey, const struct CmBlob *keyUri)
234 {
235     struct CmBlob keyPair = { 0, NULL };
236     int32_t ret;
237     do {
238         const RSA *rsa = EVP_PKEY_get0_RSA((EVP_PKEY *)priKey);
239         if (rsa == NULL) {
240             CM_LOG_E("EVP_PKEY_get1_RSA error %s", ERR_reason_error_string(ERR_get_error()));
241             ret = CM_FAILURE;
242             break;
243         }
244         uint32_t keySize = ((uint32_t)RSA_size(rsa)) * CM_BITS_PER_BYTE;
245 
246         ret = SaveKeyMaterialRsa(rsa, keySize, &keyPair);
247         if (ret != CMR_OK) {
248             CM_LOG_E("save rsa key material failed ret=0x%x", ret);
249             break;
250         }
251 
252         struct CmKeyProperties props = {
253             .algType = HKS_ALG_RSA,
254             .keySize = keySize,
255             .purpose = CM_KEY_PURPOSE_SIGN | CM_KEY_PURPOSE_VERIFY,
256         };
257 
258         ret = CmKeyOpImportKey(keyUri, &props, &keyPair);
259         if (ret != CMR_OK) {
260             CM_LOG_E("rsa keypair import faild");
261             break;
262         }
263     } while (0);
264     if (keyPair.data != NULL) {
265         (void)memset_s(keyPair.data, keyPair.size, 0, keyPair.size);
266         CMFree(keyPair.data);
267     }
268     return ret;
269 }
270 
ImportEccKey(const EVP_PKEY * priKey,const struct CmBlob * keyUri)271 static int32_t ImportEccKey(const EVP_PKEY *priKey, const struct CmBlob *keyUri)
272 {
273     struct CmBlob keyPair = { 0, NULL };
274     int32_t ret;
275     do {
276         const EC_KEY *eccKey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *)priKey);
277         if (eccKey == NULL) {
278             CM_LOG_E("EVP_PKEY_get0_EC_KEY faild");
279             ret = CM_FAILURE;
280             break;
281         }
282 
283         uint32_t keyLen = (uint32_t)EC_GROUP_order_bits(EC_KEY_get0_group(eccKey));
284         ret = SaveKeyMaterialEcc(eccKey, keyLen, &keyPair);
285         if (ret != CMR_OK) {
286             CM_LOG_E("save ec key material failed ret=0x%x", ret);
287             break;
288         }
289 
290         const struct CmKeyProperties props = {
291             .algType = HKS_ALG_ECC,
292             .keySize = keyLen,
293             .purpose = CM_KEY_PURPOSE_SIGN | CM_KEY_PURPOSE_VERIFY,
294         };
295 
296         ret = CmKeyOpImportKey(keyUri, &props, &keyPair);
297         if (ret != CMR_OK) {
298             CM_LOG_E("ecc Key type import faild");
299             break;
300         }
301     } while (0);
302     if (keyPair.data != NULL) {
303         (void)memset_s(keyPair.data, keyPair.size, 0, keyPair.size);
304         CMFree(keyPair.data);
305     }
306 
307     return ret;
308 }
309 
ImportEd25519Key(const EVP_PKEY * priKey,const struct CmBlob * keyUri)310 static int32_t ImportEd25519Key(const EVP_PKEY *priKey, const struct CmBlob *keyUri)
311 {
312     struct CmBlob keyPair = { 0, NULL };
313     int32_t ret = SaveKeyMaterialCurve25519(HKS_ALG_ED25519, priKey, &keyPair);
314     if (ret != CMR_OK) {
315         CM_LOG_E("save curve25519 key material failed");
316         return ret;
317     }
318 
319     struct CmKeyProperties props = {
320         .algType = HKS_ALG_ED25519,
321         .keySize = HKS_CURVE25519_KEY_SIZE_256,
322         .purpose = CM_KEY_PURPOSE_SIGN | CM_KEY_PURPOSE_VERIFY,
323     };
324     ret = CmKeyOpImportKey(keyUri, &props, &keyPair);
325     if (ret != CMR_OK) {
326         CM_LOG_E("Ed25519 key type import faild");
327     }
328     if (keyPair.data != NULL) {
329         (void)memset_s(keyPair.data, keyPair.size, 0, keyPair.size);
330         CMFree(keyPair.data);
331     }
332 
333     return ret;
334 }
335 
ImportKeyPair(const EVP_PKEY * priKey,const struct CmBlob * keyUri)336 static int32_t ImportKeyPair(const EVP_PKEY *priKey, const struct CmBlob *keyUri)
337 {
338     switch (EVP_PKEY_base_id(priKey)) {
339         case EVP_PKEY_RSA:
340             return ImportRsaKey(priKey, keyUri);
341         case EVP_PKEY_EC:
342             return ImportEccKey(priKey, keyUri);
343         case EVP_PKEY_ED25519:
344             return ImportEd25519Key(priKey, keyUri);
345         default:
346             CM_LOG_E("Import key type not suported");
347             return CMR_ERROR_INVALID_ARGUMENT;
348     }
349 }
350 
StoreAppCert(const struct CmContext * context,struct AppCert * appCert,const uint32_t store,const struct CmBlob * keyUri)351 static int32_t StoreAppCert(const struct CmContext *context, struct AppCert *appCert,
352     const uint32_t store, const struct CmBlob *keyUri)
353 {
354     char pathBuf[CERT_MAX_PATH_LEN] = {0};
355     int32_t ret = ConstructUidPath(context, store, pathBuf, sizeof(pathBuf));
356     if (ret != CMR_OK) {
357         CM_LOG_E("Failed obtain path for store:%u", store);
358         return ret;
359     }
360 
361     appCert->keyCount = 1;
362     struct CmBlob certBlob = { 0, NULL };
363     certBlob.size = sizeof(struct AppCert) - MAX_LEN_CERTIFICATE_CHAIN + appCert->certSize;
364     certBlob.data = (uint8_t *)appCert;
365 
366     ret = CmFileWrite(pathBuf, (char *)keyUri->data, 0, certBlob.data, certBlob.size);
367     if (ret != CMR_OK) {
368         CM_LOG_E("Failed to write certificate");
369         return CMR_ERROR_WRITE_FILE_FAIL;
370     }
371     return ret;
372 }
373 
ConstructKeyUri(const struct CmContext * context,const struct CmBlob * certAlias,uint32_t store,struct CmBlob * keyUri)374 static int32_t ConstructKeyUri(
375     const struct CmContext *context, const struct CmBlob *certAlias, uint32_t store, struct CmBlob *keyUri)
376 {
377     uint32_t type = CM_URI_TYPE_APP_KEY; /* type is 'ak' */
378     if (store == CM_SYS_CREDENTIAL_STORE) {
379         type = CM_URI_TYPE_SYS_KEY; /* type is 'sk' */
380     }
381     struct CmBlob commonUri = { 0, NULL };
382     int32_t ret;
383     do {
384         ret = CmConstructCommonUri(context, type, certAlias, &commonUri);
385         if (ret != CM_SUCCESS) {
386             CM_LOG_E("construct key uri get common uri failed");
387             break;
388         }
389 
390         if (keyUri->size < commonUri.size) {
391             CM_LOG_E("out key uri size[%u] too small", keyUri->size);
392             ret = CMR_ERROR_BUFFER_TOO_SMALL;
393             break;
394         }
395 
396         if (memcpy_s(keyUri->data, keyUri->size, commonUri.data, commonUri.size) != EOK) {
397             CM_LOG_E("copy key uri failed");
398             ret = CMR_ERROR_INVALID_OPERATION;
399             break;
400         }
401 
402         keyUri->size = commonUri.size;
403     } while (0);
404 
405     CM_FREE_PTR(commonUri.data);
406     return ret;
407 }
408 
GetCredCertName(const struct CmContext * context,const struct CmAppCertParam * certParam,EVP_PKEY ** priKey,struct CertName * certName,struct AppCert * appCert)409 static int32_t GetCredCertName(const struct CmContext *context, const struct CmAppCertParam *certParam,
410     EVP_PKEY **priKey, struct CertName *certName, struct AppCert *appCert)
411 {
412     int32_t ret = CM_SUCCESS;
413     X509 *cert = NULL;
414     do {
415         ret = CmParsePkcs12Cert(certParam->appCert, (char *)certParam->appCertPwd->data, priKey, appCert, &cert);
416         if (ret != CM_SUCCESS) {
417             CM_LOG_E("CmParsePkcs12Cert fail");
418             break;
419         }
420 
421         ret = GetSubjectNameAndAlias(cert, certParam->certAlias, certName->subjectName, certName->displayName);
422         if (ret != CM_SUCCESS) {
423             CM_LOG_E("Failed to get alias from subject name");
424             break;
425         }
426 
427         ret = GetObjNameFromCertData(certParam->appCert, certParam->certAlias, certName->objectName);
428         if (ret != CM_SUCCESS) {
429             CM_LOG_E("Failed to get object name from subject name");
430             break;
431         }
432     } while (0);
433     if (cert != NULL) {
434         FreeCertContext(cert);
435     }
436     return ret;
437 }
438 
StoreKeyAndCert(const struct CmContext * context,uint32_t store,struct AppCert * appCert,EVP_PKEY * priKey,struct CmBlob * keyUri)439 static int32_t StoreKeyAndCert(const struct CmContext *context, uint32_t store,
440     struct AppCert *appCert, EVP_PKEY *priKey, struct CmBlob *keyUri)
441 {
442     int32_t ret = CmCheckCertCount(context, store, (char *)keyUri->data);
443     if (ret != CM_SUCCESS) {
444         CM_LOG_E("cert count beyond maxcount, can't install");
445         return CMR_ERROR_MAX_CERT_COUNT_REACHED;
446     }
447 
448     ret = ImportKeyPair(priKey, keyUri);
449     if (ret != CM_SUCCESS) {
450         CM_LOG_E("import key pair failed");
451         return ret;
452     }
453 
454     ret = StoreAppCert(context, appCert, store, keyUri);
455     if (ret != CM_SUCCESS) {
456         CM_LOG_E("store App Cert failed");
457         return ret;
458     }
459     return CM_SUCCESS;
460 }
461 
CmInstallAppCertPro(const struct CmContext * context,const struct CmAppCertParam * certParam,struct CmBlob * keyUri)462 int32_t CmInstallAppCertPro(
463     const struct CmContext *context, const struct CmAppCertParam *certParam, struct CmBlob *keyUri)
464 {
465     struct AppCert appCert;
466     (void)memset_s(&appCert, sizeof(struct AppCert), 0, sizeof(struct AppCert));
467     EVP_PKEY *priKey = NULL;
468     uint8_t subjectBuf[MAX_LEN_SUBJECT_NAME] = { 0 };
469     struct CmBlob subjectName = { sizeof(subjectBuf), subjectBuf };
470     uint8_t objectBuf[MAX_LEN_CERT_ALIAS] = { 0 };
471     struct CmBlob objectName = { sizeof(objectBuf), objectBuf };
472     uint8_t displayBuf[MAX_LEN_CERT_ALIAS] = { 0 };
473     struct CmBlob displayName = { sizeof(displayBuf), displayBuf };
474     struct CertName certName = { &displayName, &objectName, &subjectName };
475     int32_t ret;
476     do {
477         ret = GetCredCertName(context, certParam, &priKey, &certName, &appCert);
478         if (ret != CM_SUCCESS) {
479             CM_LOG_E("GetCredCertName fail");
480             break;
481         }
482 
483         ret = ConstructKeyUri(context, &objectName, certParam->store, keyUri);
484         if (ret != CM_SUCCESS) {
485             CM_LOG_E("construct app cert uri fail");
486             break;
487         }
488 
489         ret = StoreKeyAndCert(context, certParam->store, &appCert, priKey, keyUri);
490         if (ret != CM_SUCCESS) {
491             CM_LOG_E("StoreKeyAndCert fail");
492             break;
493         }
494 
495         ret = RdbInsertCertProperty(context, keyUri, &displayName, &subjectName, certParam->store);
496         if (ret != CM_SUCCESS) {
497             CM_LOG_E("Failed to RdbInsertCertProperty");
498             break;
499         }
500     } while (0);
501 
502     EVP_PKEY_free(priKey);
503     return ret;
504 }
505 
506