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