• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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