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