1 /*
2  * Copyright (c) 2023-2024 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 <fstream>
17 #include <iostream>
18 #include <string>
19 
20 #include "ipc_skeleton.h"
21 #include "net_ssl_verify_cert.h"
22 #include "netstack_log.h"
23 
24 namespace OHOS {
25 namespace NetStack {
26 namespace Ssl {
27 
28 const char *const SslConstant::SYSPRECAPATH = "/etc/security/certificates";
29 const char *const SslConstant::USERINSTALLEDCAPATH = "/data/certificates/user_cacerts";
30 const int SslConstant::UIDTRANSFORMDIVISOR = 200000;
31 
GetUserInstalledCaPath()32 std::string GetUserInstalledCaPath()
33 {
34     std::string userInstalledCaPath = SslConstant::USERINSTALLEDCAPATH;
35     int32_t uid = OHOS::IPCSkeleton::GetCallingUid();
36     NETSTACK_LOGD("uid: %{public}d\n", uid);
37     uid /= SslConstant::UIDTRANSFORMDIVISOR;
38     return userInstalledCaPath.append("/").append(std::to_string(uid).c_str());
39 }
40 
PemToX509(const uint8_t * pemCert,size_t pemSize)41 X509 *PemToX509(const uint8_t *pemCert, size_t pemSize)
42 {
43     BIO *bio = BIO_new_mem_buf(pemCert, pemSize);
44     if (bio == nullptr) {
45         NETSTACK_LOGE("Failed to create BIO of PEM\n");
46         return nullptr;
47     }
48 
49     X509 *x509 = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
50     if (x509 == nullptr) {
51         NETSTACK_LOGE("Failed to convert PEM to X509\n");
52         BIO_free(bio);
53         bio = nullptr;
54         return nullptr;
55     }
56 
57     BIO_free(bio);
58     bio = nullptr;
59     return x509;
60 }
61 
DerToX509(const uint8_t * derCert,size_t derSize)62 X509 *DerToX509(const uint8_t *derCert, size_t derSize)
63 {
64     BIO *bio = BIO_new_mem_buf(derCert, derSize);
65     if (bio == nullptr) {
66         NETSTACK_LOGE("Failed to create BIO of DER\n");
67         return nullptr;
68     }
69 
70     X509 *x509 = d2i_X509_bio(bio, nullptr);
71     if (x509 == nullptr) {
72         NETSTACK_LOGE("Failed to convert DER to X509\n");
73         BIO_free(bio);
74         bio = nullptr;
75         return nullptr;
76     }
77 
78     BIO_free(bio);
79     bio = nullptr;
80     return x509;
81 }
82 
CertBlobToX509(const CertBlob * cert)83 X509 *CertBlobToX509(const CertBlob *cert)
84 {
85     X509 *x509 = nullptr;
86     do {
87         if (cert == nullptr) {
88             continue;
89         }
90         switch (cert->type) {
91             case CERT_TYPE_PEM:
92                 x509 = PemToX509(cert->data, cert->size);
93                 if (x509 == nullptr) {
94                     NETSTACK_LOGE("x509 of PEM cert is nullptr\n");
95                 }
96                 break;
97             case CERT_TYPE_DER:
98                 x509 = DerToX509(cert->data, cert->size);
99                 if (x509 == nullptr) {
100                     NETSTACK_LOGE("x509 of DER cert is nullptr\n");
101                 }
102                 break;
103             default:
104                 break;
105         }
106     } while (false);
107     return x509;
108 }
109 
VerifyCert(const CertBlob * cert)110 uint32_t VerifyCert(const CertBlob *cert)
111 {
112     uint32_t verifyResult = SSL_X509_V_ERR_UNSPECIFIED;
113     X509 *certX509 = nullptr;
114     X509_STORE *store = nullptr;
115     X509_STORE_CTX *ctx = nullptr;
116     do {
117         certX509 = CertBlobToX509(cert);
118         if (certX509 == nullptr) {
119             NETSTACK_LOGE("x509 of cert is nullptr\n");
120         }
121         store = X509_STORE_new();
122         if (store == nullptr) {
123             continue;
124         }
125         std::string userInstalledCaPath = GetUserInstalledCaPath();
126         if (X509_STORE_load_locations(store, nullptr, SslConstant::SYSPRECAPATH) != VERIFY_RESULT_SUCCESS) {
127             NETSTACK_LOGE("load SYSPRECAPATH store failed\n");
128         }
129         if (X509_STORE_load_locations(store, nullptr, userInstalledCaPath.c_str()) != VERIFY_RESULT_SUCCESS) {
130             NETSTACK_LOGI("load userInstalledCaPath store failed\n");
131         }
132         ctx = X509_STORE_CTX_new();
133         if (ctx == nullptr) {
134             continue;
135         }
136         X509_STORE_CTX_init(ctx, store, certX509, nullptr);
137         verifyResult = static_cast<uint32_t>(X509_verify_cert(ctx));
138         if (verifyResult != VERIFY_RESULT_SUCCESS) {
139             verifyResult = static_cast<uint32_t>(X509_STORE_CTX_get_error(ctx) + SSL_ERROR_CODE_BASE);
140             NETSTACK_LOGE("failed to verify certificate: %{public}s (%{public}d)\n",
141                           X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)), verifyResult);
142             break;
143         } else {
144             verifyResult = X509_V_OK;
145             NETSTACK_LOGI("certificate validation succeeded.\n");
146         }
147     } while (false);
148 
149     FreeResources(&certX509, nullptr, &store, &ctx);
150     return verifyResult;
151 }
152 
VerifyCert(const CertBlob * cert,const CertBlob * caCert)153 uint32_t VerifyCert(const CertBlob *cert, const CertBlob *caCert)
154 {
155     uint32_t verifyResult = SSL_X509_V_ERR_UNSPECIFIED;
156     X509 *certX509 = nullptr;
157     X509 *caX509 = nullptr;
158     X509_STORE *store = nullptr;
159     X509_STORE_CTX *ctx = nullptr;
160     do {
161         certX509 = CertBlobToX509(cert);
162         if (certX509 == nullptr) {
163             NETSTACK_LOGE("x509 of cert is nullptr\n");
164         }
165         caX509 = CertBlobToX509(caCert);
166         if (caX509 == nullptr) {
167             NETSTACK_LOGE("x509 of ca is nullptr\n");
168         }
169         store = X509_STORE_new();
170         if (store == nullptr) {
171             continue;
172         }
173         if (X509_STORE_add_cert(store, caX509) != VERIFY_RESULT_SUCCESS) {
174             NETSTACK_LOGE("add ca to store failed\n");
175         }
176         ctx = X509_STORE_CTX_new();
177         if (ctx == nullptr) {
178             continue;
179         }
180         X509_STORE_CTX_init(ctx, store, certX509, nullptr);
181         verifyResult = static_cast<uint32_t>(X509_verify_cert(ctx));
182         if (verifyResult != VERIFY_RESULT_SUCCESS) {
183             verifyResult = static_cast<uint32_t>(X509_STORE_CTX_get_error(ctx) + SSL_ERROR_CODE_BASE);
184             NETSTACK_LOGE("failed to verify certificate: %{public}s (%{public}d)\n",
185                           X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)), verifyResult);
186             break;
187         } else {
188             verifyResult = X509_V_OK;
189             NETSTACK_LOGI("certificate validation succeeded.\n");
190         }
191     } while (false);
192 
193     FreeResources(&certX509, &caX509, &store, &ctx);
194     return verifyResult;
195 }
196 
FreeResources(X509 ** certX509,X509 ** caX509,X509_STORE ** store,X509_STORE_CTX ** ctx)197 void FreeResources(X509 **certX509, X509 **caX509, X509_STORE **store, X509_STORE_CTX **ctx)
198 {
199     if (certX509 != nullptr) {
200         if (*certX509 != nullptr) {
201             X509_free(*certX509);
202             *certX509 = nullptr;
203         }
204     }
205     if (caX509 != nullptr) {
206         if (*caX509 != nullptr) {
207             X509_free(*caX509);
208             *caX509 = nullptr;
209         }
210     }
211     if (store != nullptr) {
212         if (*store != nullptr) {
213             X509_STORE_free(*store);
214             *store = nullptr;
215         }
216     }
217     if (ctx != nullptr) {
218         if (*ctx != nullptr) {
219             X509_STORE_CTX_free(*ctx);
220             *ctx = nullptr;
221         }
222     }
223 }
224 } // namespace Ssl
225 } // namespace NetStack
226 } // namespace OHOS