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 "cm_pfx.h"
17
18 #include <openssl/pkcs12.h>
19 #include <openssl/bio.h>
20 #include <openssl/err.h>
21 #include <openssl/pem.h>
22
23 #include "cm_log.h"
24 #include "cm_mem.h"
25 #include "cm_type_inner.h"
26
CmGetAppCertChain(X509 * cert,STACK_OF (X509)* caCert,struct AppCert * appCert)27 static int32_t CmGetAppCertChain(X509 *cert, STACK_OF(X509) *caCert, struct AppCert *appCert)
28 {
29 int32_t ret = CM_SUCCESS; uint32_t certCount = 0;
30 X509 *xCert = NULL; char *data = NULL; BIO *out = NULL;
31
32 if (cert == NULL) {
33 CM_LOG_E("app terminal cert is null");
34 return CM_FAILURE;
35 }
36
37 do {
38 out = BIO_new(BIO_s_mem());
39 if (out == NULL) {
40 CM_LOG_E("BIO_new_mem_buf faild");
41 ret = CM_FAILURE;
42 break;
43 }
44 /* copy app terminal cert to bio */
45 if (PEM_write_bio_X509(out, cert) == 0) {
46 CM_LOG_E("Copy app cert to bio faild");
47 ret = CM_FAILURE;
48 break;
49 }
50 certCount++;
51 /* copy app ca cert to bio */
52 for (int32_t i = 0; i < sk_X509_num(caCert); i++) {
53 xCert = sk_X509_value(caCert, i);
54 if (PEM_write_bio_X509(out, xCert) == 0) {
55 CM_LOG_E("Copy app ca cert to bio faild");
56 ret = CM_FAILURE;
57 break;
58 }
59 certCount++;
60 }
61
62 long len = BIO_get_mem_data(out, &data);
63 if (len <= 0) {
64 CM_LOG_E("BIO_get_mem_data faild");
65 ret = CM_FAILURE;
66 break;
67 }
68 if (memcpy_s(appCert->appCertdata, MAX_LEN_CERTIFICATE_CHAIN, data, len) != EOK) {
69 CM_LOG_E("Copy appCert->appCertdata faild");
70 ret = CM_FAILURE;
71 break;
72 }
73 /* default certificate chain is packaged as a whole */
74 appCert->certCount = certCount;
75 appCert->certSize = (uint32_t)len;
76 } while (0);
77
78 if (out != NULL) {
79 BIO_free(out);
80 }
81 return ret;
82 }
83
CmParsePkcs12Cert(const struct CmBlob * p12Cert,char * passWd,EVP_PKEY ** pkey,struct AppCert * appCert)84 int32_t CmParsePkcs12Cert(const struct CmBlob *p12Cert, char *passWd, EVP_PKEY **pkey, struct AppCert *appCert)
85 {
86 BIO *bio = NULL;
87 X509 *cert = NULL;
88 PKCS12 *p12 = NULL;
89 int32_t ret = CM_SUCCESS;
90 STACK_OF(X509) *caCert = NULL;
91
92 if (p12Cert == NULL || p12Cert->data == NULL || p12Cert->size > MAX_LEN_CERTIFICATE_CHAIN) {
93 return CMR_ERROR_INVALID_ARGUMENT;
94 }
95
96 do {
97 bio = BIO_new_mem_buf(p12Cert->data, p12Cert->size);
98 if (bio == NULL) {
99 ret = CM_FAILURE;
100 CM_LOG_E("BIO_new_mem_buf faild");
101 break;
102 }
103
104 p12 = d2i_PKCS12_bio(bio, NULL);
105 if (p12 == NULL) {
106 ret = CM_FAILURE;
107 CM_LOG_E("D2i_PKCS12_bio faild:%s", ERR_error_string(ERR_get_error(), NULL));
108 break;
109 }
110 /* 1 the return value of PKCS12_parse 1 is success */
111 if (PKCS12_parse(p12, passWd, pkey, &cert, &caCert) != 1) {
112 ret = CM_FAILURE;
113 CM_LOG_E("Parsing PKCS#12 file faild:%s", ERR_error_string(ERR_get_error(), NULL));
114 break;
115 }
116
117 ret = CmGetAppCertChain(cert, caCert, appCert);
118 if (ret != CM_SUCCESS) {
119 CM_LOG_E("CmGetAppCertChain failed");
120 break;
121 }
122 } while (0);
123
124 if (bio != NULL) {
125 BIO_free(bio);
126 }
127 if (p12 != NULL) {
128 PKCS12_free(p12);
129 }
130 if (caCert != NULL) {
131 sk_X509_pop_free(caCert, X509_free);
132 }
133 if (cert != NULL) {
134 X509_free(cert);
135 }
136 return ret;
137 }
138
139