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