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
ProcessResult(uint32_t & verifyResult)110 void ProcessResult(uint32_t &verifyResult)
111 {
112 if (SslErrorCodeSet.find(verifyResult) == SslErrorCodeSet.end()) {
113 verifyResult = SSL_X509_V_ERR_UNSPECIFIED;
114 }
115 }
116
VerifyCert(const CertBlob * cert)117 uint32_t VerifyCert(const CertBlob *cert)
118 {
119 uint32_t verifyResult = SSL_X509_V_ERR_UNSPECIFIED;
120 X509 *certX509 = nullptr;
121 X509_STORE *store = nullptr;
122 X509_STORE_CTX *ctx = nullptr;
123 do {
124 certX509 = CertBlobToX509(cert);
125 if (certX509 == nullptr) {
126 NETSTACK_LOGE("x509 of cert is nullptr\n");
127 }
128 store = X509_STORE_new();
129 if (store == nullptr) {
130 continue;
131 }
132 std::string userInstalledCaPath = GetUserInstalledCaPath();
133 if (X509_STORE_load_locations(store, nullptr, SslConstant::SYSPRECAPATH) != VERIFY_RESULT_SUCCESS) {
134 NETSTACK_LOGE("load SYSPRECAPATH store failed\n");
135 }
136 if (X509_STORE_load_locations(store, nullptr, userInstalledCaPath.c_str()) != VERIFY_RESULT_SUCCESS) {
137 NETSTACK_LOGI("load userInstalledCaPath store failed\n");
138 }
139 ctx = X509_STORE_CTX_new();
140 if (ctx == nullptr) {
141 continue;
142 }
143 X509_STORE_CTX_init(ctx, store, certX509, nullptr);
144 verifyResult = static_cast<uint32_t>(X509_verify_cert(ctx));
145 if (verifyResult != VERIFY_RESULT_SUCCESS) {
146 verifyResult = static_cast<uint32_t>(X509_STORE_CTX_get_error(ctx) + SSL_ERROR_CODE_BASE);
147 ProcessResult(verifyResult);
148 NETSTACK_LOGE("failed to verify certificate: %{public}s (%{public}d)\n",
149 X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)), verifyResult);
150 break;
151 } else {
152 verifyResult = X509_V_OK;
153 NETSTACK_LOGI("certificate validation succeeded.\n");
154 }
155 } while (false);
156
157 FreeResources(&certX509, nullptr, &store, &ctx);
158 return verifyResult;
159 }
160
VerifyCert(const CertBlob * cert,const CertBlob * caCert)161 uint32_t VerifyCert(const CertBlob *cert, const CertBlob *caCert)
162 {
163 uint32_t verifyResult = SSL_X509_V_ERR_UNSPECIFIED;
164 X509 *certX509 = nullptr;
165 X509 *caX509 = nullptr;
166 X509_STORE *store = nullptr;
167 X509_STORE_CTX *ctx = nullptr;
168 do {
169 certX509 = CertBlobToX509(cert);
170 if (certX509 == nullptr) {
171 NETSTACK_LOGE("x509 of cert is nullptr\n");
172 }
173 caX509 = CertBlobToX509(caCert);
174 if (caX509 == nullptr) {
175 NETSTACK_LOGE("x509 of ca is nullptr\n");
176 }
177 store = X509_STORE_new();
178 if (store == nullptr) {
179 continue;
180 }
181 if (X509_STORE_add_cert(store, caX509) != VERIFY_RESULT_SUCCESS) {
182 NETSTACK_LOGE("add ca to store failed\n");
183 }
184 ctx = X509_STORE_CTX_new();
185 if (ctx == nullptr) {
186 continue;
187 }
188 X509_STORE_CTX_init(ctx, store, certX509, nullptr);
189 verifyResult = static_cast<uint32_t>(X509_verify_cert(ctx));
190 if (verifyResult != VERIFY_RESULT_SUCCESS) {
191 verifyResult = static_cast<uint32_t>(X509_STORE_CTX_get_error(ctx) + SSL_ERROR_CODE_BASE);
192 ProcessResult(verifyResult);
193 NETSTACK_LOGE("failed to verify certificate: %{public}s (%{public}d)\n",
194 X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)), verifyResult);
195 break;
196 } else {
197 verifyResult = X509_V_OK;
198 NETSTACK_LOGI("certificate validation succeeded.\n");
199 }
200 } while (false);
201
202 FreeResources(&certX509, &caX509, &store, &ctx);
203 return verifyResult;
204 }
205
FreeResources(X509 ** certX509,X509 ** caX509,X509_STORE ** store,X509_STORE_CTX ** ctx)206 void FreeResources(X509 **certX509, X509 **caX509, X509_STORE **store, X509_STORE_CTX **ctx)
207 {
208 if (certX509 != nullptr) {
209 if (*certX509 != nullptr) {
210 X509_free(*certX509);
211 *certX509 = nullptr;
212 }
213 }
214 if (caX509 != nullptr) {
215 if (*caX509 != nullptr) {
216 X509_free(*caX509);
217 *caX509 = nullptr;
218 }
219 }
220 if (store != nullptr) {
221 if (*store != nullptr) {
222 X509_STORE_free(*store);
223 *store = nullptr;
224 }
225 }
226 if (ctx != nullptr) {
227 if (*ctx != nullptr) {
228 X509_STORE_CTX_free(*ctx);
229 *ctx = nullptr;
230 }
231 }
232 }
233 } // namespace Ssl
234 } // namespace NetStack
235 } // namespace OHOS