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