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