• 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 "cert_context.h"
17 
18 #include <map>
19 #include <node_api.h>
20 #include <openssl/ssl.h>
21 
22 #include "napi_utils.h"
23 #include "net_ssl_exec.h"
24 #include "netstack_common_utils.h"
25 #include "netstack_log.h"
26 #include "net_ssl_verify_cert.h"
27 #if HAS_NETMANAGER_BASE
28 #include "net_conn_client.h"
29 #endif // HAS_NETMANAGER_BASE
30 
31 static constexpr const int PARAM_JUST_CERT = 1;
32 
33 static constexpr const int PARAM_CERT_AND_CACERT = 2;
34 
35 namespace OHOS::NetStack::Ssl {
36 
37 static const std::map<int32_t, const char *> SSL_ERR_MAP = {
38     {SslErrorCode::SSL_NONE_ERR, "Verify success."},
39     {SslErrorCode::SSL_X509_V_ERR_UNSPECIFIED, "Unspecified error."},
40     {SslErrorCode::SSL_X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT, "Unable to get issuer certificate."},
41     {SslErrorCode::SSL_X509_V_ERR_UNABLE_TO_GET_CRL, "Unable to get certificate revocation list (CRL)."},
42     {SslErrorCode::SSL_X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE, "Unable to decrypt certificate signature."},
43     {SslErrorCode::SSL_X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE, "Unable to decrypt CRL signature."},
44     {SslErrorCode::SSL_X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY, "Unable to decode issuer public key."},
45     {SslErrorCode::SSL_X509_V_ERR_CERT_SIGNATURE_FAILURE, "Certificate signature failure."},
46     {SslErrorCode::SSL_X509_V_ERR_CRL_SIGNATURE_FAILURE, "CRL signature failure."},
47     {SslErrorCode::SSL_X509_V_ERR_CERT_NOT_YET_VALID, "Certificate is not yet valid."},
48     {SslErrorCode::SSL_X509_V_ERR_CERT_HAS_EXPIRED, "Certificate has expired."},
49     {SslErrorCode::SSL_X509_V_ERR_CRL_NOT_YET_VALID, "CRL is not yet valid."},
50     {SslErrorCode::SSL_X509_V_ERR_CRL_HAS_EXPIRED, "CRL has expired."},
51     {SslErrorCode::SSL_X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, "unable to get local issuer certificate."},
52     {SslErrorCode::SSL_X509_V_ERR_CERT_REVOKED, "Certificate has been revoked."},
53     {SslErrorCode::SSL_X509_V_ERR_INVALID_CA, "Invalid certificate authority (CA)."},
54     {SslErrorCode::SSL_X509_V_ERR_CERT_UNTRUSTED, "Certificate is untrusted."},
55     {SslErrorCode::SSL_X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, "self-signed certificate."},
56     {SslErrorCode::SSL_X509_V_ERR_INVALID_CALL, "invalid certificate verification context."}
57 };
58 
CertContext(napi_env env,const std::shared_ptr<EventManager> & manager)59 CertContext::CertContext(napi_env env, const std::shared_ptr<EventManager> &manager)
60     : BaseContext(env, manager), certBlob_(nullptr), certBlobClient_(nullptr) {}
61 
ParseParams(napi_value * params,size_t paramsCount)62 void CertContext::ParseParams(napi_value *params, size_t paramsCount)
63 {
64     bool valid = CheckParamsType(params, paramsCount);
65     if (valid) {
66         if (paramsCount == PARAM_JUST_CERT) {
67             certBlob_ = ParseCertBlobFromValue(GetEnv(), params[0]);
68             SetParseOK(certBlob_ != nullptr);
69         } else if (paramsCount == PARAM_CERT_AND_CACERT) {
70             certBlob_ = ParseCertBlobFromValue(GetEnv(), params[0]);
71             certBlobClient_ = ParseCertBlobFromValue(GetEnv(), params[1]);
72             SetParseOK(certBlob_ != nullptr && certBlobClient_ != nullptr);
73         }
74     } else {
75         SetErrorCode(PARSE_ERROR_CODE);
76     }
77 }
78 
CheckParamsType(napi_value * params,size_t paramsCount)79 bool CertContext::CheckParamsType(napi_value *params, size_t paramsCount)
80 {
81     if (paramsCount == PARAM_JUST_CERT) {
82         return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_object;
83     } else if (paramsCount == PARAM_CERT_AND_CACERT) {
84         return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_object &&
85                NapiUtils::GetValueType(GetEnv(), params[1]) == napi_object;
86     }
87     return false;
88 }
89 
ParseCertBlobFromValue(napi_env env,napi_value value)90 CertBlob *CertContext::ParseCertBlobFromValue(napi_env env, napi_value value)
91 {
92     napi_value typeValue;
93     napi_value dataValue;
94     napi_get_named_property(env, value, "type", &typeValue);
95     napi_get_named_property(env, value, "data", &dataValue);
96     if (typeValue == nullptr || dataValue == nullptr) {
97         SetErrorCode(PARSE_ERROR_CODE);
98         return new CertBlob{CERT_TYPE_MAX, 0, nullptr};
99     }
100     return ParseCertBlobFromData(env, value, typeValue, dataValue);
101 }
102 
ParseCertBlobFromData(napi_env env,napi_value value,napi_value typeValue,napi_value dataValue)103 CertBlob *CertContext::ParseCertBlobFromData(napi_env env, napi_value value, napi_value typeValue, napi_value dataValue)
104 {
105     size_t dataSize = 0;
106     uint32_t type;
107     uint32_t size = 0;
108     uint8_t *data = nullptr;
109     napi_get_value_uint32(env, typeValue, &type);
110     CertType certType = static_cast<CertType>(type);
111     if (certType == CERT_TYPE_PEM) {
112         NETSTACK_LOGD("CERT_TYPE_PEM\n");
113         napi_valuetype valueType;
114         napi_typeof(env, dataValue, &valueType);
115         if (valueType != napi_string) {
116             NETSTACK_LOGE("pem but not string\n");
117             return new CertBlob{CERT_TYPE_MAX, 0, nullptr};
118         }
119         napi_get_value_string_utf8(env, dataValue, nullptr, 0, &dataSize);
120         if (dataSize + 1 < SIZE_MAX / sizeof(uint8_t)) {
121             data = new uint8_t[dataSize + 1];
122             napi_get_value_string_utf8(env, dataValue, reinterpret_cast<char *>(data), dataSize + 1, &dataSize);
123             size = static_cast<uint32_t>(dataSize);
124         } else {
125             return new CertBlob{CERT_TYPE_MAX, 0, nullptr};
126         }
127     } else if (certType == CERT_TYPE_DER) {
128         NETSTACK_LOGD("CERT_TYPE_DER\n");
129         bool isArrayBuffer = false;
130         napi_is_buffer(env, dataValue, &isArrayBuffer);
131         if (!isArrayBuffer) {
132             NETSTACK_LOGE("der but bot arraybuffer\n");
133             return new CertBlob{CERT_TYPE_MAX, 0, nullptr};
134         }
135         void *dataArray = nullptr;
136         napi_get_arraybuffer_info(env, dataValue, &dataArray, &dataSize);
137         if (dataSize < SIZE_MAX / sizeof(uint8_t)) {
138             data = new uint8_t[dataSize];
139             std::copy(static_cast<uint8_t *>(dataArray), static_cast<uint8_t *>(dataArray) + dataSize, data);
140             size = static_cast<uint32_t>(dataSize);
141         } else {
142             return new CertBlob{CERT_TYPE_MAX, 0, nullptr};
143         }
144     } else {
145         return new CertBlob{CERT_TYPE_MAX, 0, nullptr};
146     }
147     return new CertBlob{static_cast<CertType>(type), static_cast<uint32_t>(size), static_cast<uint8_t *>(data)};
148 }
149 
GetCertBlob()150 CertBlob *CertContext::GetCertBlob()
151 {
152     return certBlob_;
153 }
154 
GetCertBlobClient()155 CertBlob *CertContext::GetCertBlobClient()
156 {
157     return certBlobClient_;
158 }
159 
GetErrorCode() const160 int32_t CertContext::GetErrorCode() const
161 {
162     auto errorCode = BaseContext::GetErrorCode();
163     if (errorCode == PARSE_ERROR_CODE) {
164         return PARSE_ERROR_CODE;
165     }
166 #if HAS_NETMANAGER_BASE
167     const auto &errorCodeSet =
168         OHOS::NetManagerStandard::NetConnClient::IsAPIVersionSupported(CommonUtils::SdkVersion::TWELVE)
169             ? SslErrorCodeSetSinceAPI12
170             : SslErrorCodeSetBase;
171 #else
172     const auto &errorCodeSet = SslErrorCodeSetSinceAPI12;
173 #endif
174     if (errorCodeSet.find(errorCode) == errorCodeSet.end()) {
175         errorCode = SSL_X509_V_ERR_UNSPECIFIED;
176     }
177     return errorCode;
178 }
179 
GetErrorMessage() const180 std::string CertContext::GetErrorMessage() const
181 {
182     auto err = BaseContext::GetErrorCode();
183     if (err == PARSE_ERROR_CODE) {
184         return PARSE_ERROR_MSG;
185     }
186 
187     auto pos = SSL_ERR_MAP.find(err);
188     if (pos != SSL_ERR_MAP.end()) {
189         return pos->second;
190     }
191     return SSL_ERR_MAP.at(SslErrorCode::SSL_X509_V_ERR_CERT_UNTRUSTED);
192 }
193 
~CertContext()194 CertContext::~CertContext()
195 {
196     if (certBlob_ != nullptr) {
197         if (certBlob_->data != nullptr) {
198             delete[] certBlob_->data;
199             certBlob_->data = nullptr;
200         }
201         delete certBlob_;
202         certBlob_ = nullptr;
203     }
204 
205     if (certBlobClient_ != nullptr) {
206         if (certBlobClient_->data != nullptr) {
207             delete[] certBlobClient_->data;
208             certBlobClient_->data = nullptr;
209         }
210         delete certBlobClient_;
211         certBlobClient_ = nullptr;
212     }
213     NETSTACK_LOGD("CertContext is destructed by the destructor");
214 }
215 } // namespace OHOS::NetStack::Ssl
216