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_CERT_REVOKED, "Certificate has been revoked."},
52 {SslErrorCode::SSL_X509_V_ERR_INVALID_CA, "Invalid certificate authority (CA)."},
53 {SslErrorCode::SSL_X509_V_ERR_CERT_UNTRUSTED, "Certificate is untrusted."},
54 {SslErrorCode::SSL_X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT, "self-signed certificate."},
55 {SslErrorCode::SSL_X509_V_ERR_INVALID_CALL, "invalid certificate verification context."}
56 };
57
CertContext(napi_env env,EventManager * manager)58 CertContext::CertContext(napi_env env, EventManager *manager)
59 : BaseContext(env, manager), certBlob_(nullptr), certBlobClient_(nullptr)
60 {
61 manager_ = new EventManager;
62 }
63
ParseParams(napi_value * params,size_t paramsCount)64 void CertContext::ParseParams(napi_value *params, size_t paramsCount)
65 {
66 bool valid = CheckParamsType(params, paramsCount);
67 if (valid) {
68 if (paramsCount == PARAM_JUST_CERT) {
69 certBlob_ = ParseCertBlobFromValue(GetEnv(), params[0]);
70 SetParseOK(certBlob_ != nullptr);
71 } else if (paramsCount == PARAM_CERT_AND_CACERT) {
72 certBlob_ = ParseCertBlobFromValue(GetEnv(), params[0]);
73 certBlobClient_ = ParseCertBlobFromValue(GetEnv(), params[1]);
74 SetParseOK(certBlob_ != nullptr && certBlobClient_ != nullptr);
75 }
76 } else {
77 SetErrorCode(PARSE_ERROR_CODE);
78 }
79 }
80
CheckParamsType(napi_value * params,size_t paramsCount)81 bool CertContext::CheckParamsType(napi_value *params, size_t paramsCount)
82 {
83 if (paramsCount == PARAM_JUST_CERT) {
84 return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_object;
85 } else if (paramsCount == PARAM_CERT_AND_CACERT) {
86 return NapiUtils::GetValueType(GetEnv(), params[0]) == napi_object &&
87 NapiUtils::GetValueType(GetEnv(), params[1]) == napi_object;
88 }
89 return false;
90 }
91
ParseCertBlobFromValue(napi_env env,napi_value value)92 CertBlob *CertContext::ParseCertBlobFromValue(napi_env env, napi_value value)
93 {
94 napi_value typeValue;
95 napi_value dataValue;
96 napi_get_named_property(env, value, "type", &typeValue);
97 napi_get_named_property(env, value, "data", &dataValue);
98 if (typeValue == nullptr || dataValue == nullptr) {
99 SetErrorCode(PARSE_ERROR_CODE);
100 return new CertBlob{CERT_TYPE_MAX, 0, nullptr};
101 }
102 return ParseCertBlobFromData(env, value, typeValue, dataValue);
103 }
104
ParseCertBlobFromData(napi_env env,napi_value value,napi_value typeValue,napi_value dataValue)105 CertBlob *CertContext::ParseCertBlobFromData(napi_env env, napi_value value, napi_value typeValue, napi_value dataValue)
106 {
107 size_t dataSize = 0;
108 uint32_t type;
109 uint32_t size = 0;
110 uint8_t *data = nullptr;
111 napi_get_value_uint32(env, typeValue, &type);
112 CertType certType = static_cast<CertType>(type);
113 if (certType == CERT_TYPE_PEM) {
114 NETSTACK_LOGD("CERT_TYPE_PEM\n");
115 napi_valuetype valueType;
116 napi_typeof(env, dataValue, &valueType);
117 if (valueType != napi_string) {
118 NETSTACK_LOGE("pem but not string\n");
119 return new CertBlob{CERT_TYPE_MAX, 0, nullptr};
120 }
121 napi_get_value_string_utf8(env, dataValue, nullptr, 0, &dataSize);
122 if (dataSize + 1 < SIZE_MAX / sizeof(uint8_t)) {
123 data = new uint8_t[dataSize + 1];
124 napi_get_value_string_utf8(env, dataValue, reinterpret_cast<char *>(data), dataSize + 1, &dataSize);
125 size = static_cast<uint32_t>(dataSize);
126 } else {
127 return new CertBlob{CERT_TYPE_MAX, 0, nullptr};
128 }
129 } else if (certType == CERT_TYPE_DER) {
130 NETSTACK_LOGD("CERT_TYPE_DER\n");
131 bool isArrayBuffer = false;
132 napi_is_buffer(env, dataValue, &isArrayBuffer);
133 if (!isArrayBuffer) {
134 NETSTACK_LOGE("der but bot arraybuffer\n");
135 return new CertBlob{CERT_TYPE_MAX, 0, nullptr};
136 }
137 void *dataArray = nullptr;
138 napi_get_arraybuffer_info(env, dataValue, &dataArray, &dataSize);
139 if (dataSize < SIZE_MAX / sizeof(uint8_t)) {
140 data = new uint8_t[dataSize];
141 std::copy(static_cast<uint8_t *>(dataArray), static_cast<uint8_t *>(dataArray) + dataSize, data);
142 size = static_cast<uint32_t>(dataSize);
143 } else {
144 return new CertBlob{CERT_TYPE_MAX, 0, nullptr};
145 }
146 } else {
147 return new CertBlob{CERT_TYPE_MAX, 0, nullptr};
148 }
149 return new CertBlob{static_cast<CertType>(type), static_cast<uint32_t>(size), static_cast<uint8_t *>(data)};
150 }
151
GetCertBlob()152 CertBlob *CertContext::GetCertBlob()
153 {
154 return certBlob_;
155 }
156
GetCertBlobClient()157 CertBlob *CertContext::GetCertBlobClient()
158 {
159 return certBlobClient_;
160 }
161
GetErrorCode() const162 int32_t CertContext::GetErrorCode() const
163 {
164 auto errorCode = BaseContext::GetErrorCode();
165 if (errorCode == PARSE_ERROR_CODE) {
166 return PARSE_ERROR_CODE;
167 }
168 #if HAS_NETMANAGER_BASE
169 const auto &errorCodeSet =
170 OHOS::NetManagerStandard::NetConnClient::IsAPIVersionSupported(CommonUtils::SdkVersion::TWELVE)
171 ? SslErrorCodeSetSinceAPI12
172 : SslErrorCodeSetBase;
173 #else
174 const auto &errorCodeSet = SslErrorCodeSetSinceAPI12;
175 #endif
176 if (errorCodeSet.find(errorCode) == errorCodeSet.end()) {
177 errorCode = SSL_X509_V_ERR_UNSPECIFIED;
178 }
179 return errorCode;
180 }
181
GetErrorMessage() const182 std::string CertContext::GetErrorMessage() const
183 {
184 auto err = BaseContext::GetErrorCode();
185 if (err == PARSE_ERROR_CODE) {
186 return PARSE_ERROR_MSG;
187 }
188
189 auto pos = SSL_ERR_MAP.find(err);
190 if (pos != SSL_ERR_MAP.end()) {
191 return pos->second;
192 }
193 return SSL_ERR_MAP.at(SslErrorCode::SSL_X509_V_ERR_CERT_UNTRUSTED);
194 }
195
~CertContext()196 CertContext::~CertContext()
197 {
198 if (certBlob_ != nullptr) {
199 if (certBlob_->data != nullptr) {
200 delete certBlob_->data;
201 certBlob_->data = nullptr;
202 }
203 delete certBlob_;
204 certBlob_ = nullptr;
205 }
206
207 if (certBlobClient_ != nullptr) {
208 if (certBlobClient_->data != nullptr) {
209 delete certBlobClient_->data;
210 certBlobClient_->data = nullptr;
211 }
212 delete certBlobClient_;
213 certBlobClient_ = nullptr;
214 }
215 if (manager_ != nullptr) {
216 delete manager_;
217 manager_ = nullptr;
218 }
219 NETSTACK_LOGD("CertContext is destructed by the destructor");
220 }
221 } // namespace OHOS::NetStack::Ssl
222