From d026dc35c2e755f25b6b6783e30ad57b0771736c Mon Sep 17 00:00:00 2001 From: jiawen Date: Tue, 6 Sep 2022 15:00:34 +0800 Subject: [PATCH] =?UTF-8?q?tlssocket=20=E5=91=A8=E8=BE=B9=E5=AE=9E?= =?UTF-8?q?=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: jiawen Change-Id: I7d4d9f4b18bf6c0ed9fa45eb42ecae166fb5c739 --- .../native/tls_socket/src/tls_certificate.cpp | 325 ++++++++++++++++++ .../tls_socket/src/tls_configuration.cpp | 186 ++++++++++ .../native/tls_socket/src/tls_context.cpp | 228 ++++++++++++ frameworks/native/tls_socket/src/tls_key.cpp | 269 +++++++++++++++ 4 files changed, 1008 insertions(+) create mode 100644 frameworks/native/tls_socket/src/tls_certificate.cpp create mode 100644 frameworks/native/tls_socket/src/tls_configuration.cpp create mode 100644 frameworks/native/tls_socket/src/tls_context.cpp create mode 100644 frameworks/native/tls_socket/src/tls_key.cpp diff --git a/frameworks/native/tls_socket/src/tls_certificate.cpp b/frameworks/native/tls_socket/src/tls_certificate.cpp new file mode 100644 index 000000000..c702ed34c --- /dev/null +++ b/frameworks/native/tls_socket/src/tls_certificate.cpp @@ -0,0 +1,325 @@ +/* +* Copyright (c) 2022 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "tls_certificate.h" + +#include + +#include +#include +#include +#include + +#include "netstack_log.h" + +namespace OHOS { +namespace NetStack { + +namespace { +constexpr const char *BIO_FILE_FLAG = "r"; +constexpr const char *FILE_OPEN_FLAG = "rb"; +constexpr const char *CERT_VERSION_FLAG = "V"; +constexpr int FILE_READ_CERT_LEN = 4096; +} // namespace + +TLSCertificate::TLSCertificate(const TLSCertificate &certificate) = default; + +TLSCertificate::TLSCertificate(const std::string &data, EncodingFormat format, CertType certType) +{ + if (data.empty()) { + NETSTACK_LOGE("TlsCertificate::TlsCertificate data is empty"); + return; + } + switch (format) { + case PEM: + if (!CertificateFromPem(data, certType)) { + NETSTACK_LOGE("return CertificateFromPem(data, certs) is false"); + } + break; + case DER: + if (!CertificateFromDer(data, certType)) { + NETSTACK_LOGE("return CertificateFromDer(data, certs) is false"); + } + break; + default: + NETSTACK_LOGE("%{public}u is not supported, only support PEM =0 and DER = 1", format); + } +} + +TLSCertificate::TLSCertificate(const std::string &data, CertType certType) +{ + if (data.empty()) { + NETSTACK_LOGE("TlsCertificate::TlsCertificate(const std::string &data, CertType certType) data is empty"); + return; + } + if (!CertificateFromData(data, certType)) { + NETSTACK_LOGE("return CertificatesFromPem(data, certs) is false"); + } +} + +TLSCertificate &TLSCertificate::operator= (const TLSCertificate &other) +{ + if (other.x509_ != nullptr) { + x509_ = X509_new(); + x509_ = other.x509_; + } + version_ = other.version_; + serialNumber_ = other.serialNumber_; + notValidBefore_ = other.notValidBefore_; + notValidAfter_ = other.notValidBefore_; + signatureAlgorithm_ = other.signatureAlgorithm_; + localCertString_ = other.localCertString_; + caCertString_ = other.caCertString_; + return *this; +} + +bool TLSCertificate::CertificateFromData(const std::string &data, CertType certType) +{ + if (data.empty()) { + NETSTACK_LOGE("TlsCertificate::CertificateFromData: data is empty"); + return false; + } + BIO *bio = BIO_new_mem_buf(data.c_str(), -1); + if (!bio) { + NETSTACK_LOGE("TlsCertificate(const std::string &data, CertType certType) ---"); + return false; + } + X509 *x509 = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr); + BIO_free(bio); + + if (!x509) { + NETSTACK_LOGE("--- TlsCertificate::CertificateFromData: x509 is null ---"); + return false; + } + + x509_ = X509_dup(x509); + if (!AnalysisCertificate(certType, x509)) { + NETSTACK_LOGE("TlsCertificate::CertificateFromData: AnalysisCertificate is false"); + X509_free(x509); + return false; + } + X509_free(x509); + return true; +} + +bool TLSCertificate::CertificateFromPem(const std::string &data, CertType certType) +{ + BIO *bio = BIO_new_file((data.c_str()), BIO_FILE_FLAG); + if (!bio) { + NETSTACK_LOGE("bio new file fail errno = %{public}d reason = %{public}s \n", errno, strerror(errno)); + return false; + } + X509 *x509 = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr); + BIO_free(bio); + + if (!x509) { + NETSTACK_LOGE("--- TlsCertificate::CertificateFromPem: x509 is null ---"); + return false; + } + + x509_ = X509_dup(x509); + if (!AnalysisCertificate(certType, x509)) { + NETSTACK_LOGE("TlsCertificate::CertificateFromPem: AnalysisCertificate is false"); + X509_free(x509); + return false; + } + X509_free(x509); + return true; +} + +bool TLSCertificate::CertificateFromDer(const std::string &data, CertType certType) +{ + FILE *fp = nullptr; + fp = fopen(data.c_str(), FILE_OPEN_FLAG); + if (!fp) { + NETSTACK_LOGE("TlsCertificate::CertificateFromDer: Couldn't open %{public}s file for reading", data.c_str()); + return false; + } + unsigned char cert[FILE_READ_CERT_LEN] = {}; + long certLen = fread(cert, 1, FILE_READ_CERT_LEN, fp); + fclose(fp); + const auto *cert_data = reinterpret_cast(cert); + X509 *x509 = d2i_X509(nullptr, &cert_data, certLen); + if (!x509) { + NETSTACK_LOGE("TlsCertificate::CertificateFromDer: x509 is null"); + return false; + } + x509_ = X509_dup(x509); + if (!AnalysisCertificate(certType, x509)) { + NETSTACK_LOGE("TlsCertificate::CertificateFromDer: AnalysisCertificate is false"); + X509_free(x509); + return false; + } + X509_free(x509); + return true; +} + +bool TLSCertificate::AnalysisCertificate(CertType certType, X509 *x509) +{ + if (certType == CA_CERT) { + if (!CaCertToString(x509)) { + NETSTACK_LOGE("TlsCertificate::AnalysisCertificate: CaCertToString is false"); + return false; + } + } + if (certType == LOCAL_CERT) { + if (!LocalCertToString(x509)) { + NETSTACK_LOGE("TlsCertificate::AnalysisCertificate: LocalCertToString is false"); + return false; + } + } + if (!SetX509Version(x509)) { + NETSTACK_LOGE("TlsCertificate::AnalysisCertificate: SetX509Version is false"); + return false; + } + if (!SetSerialNumber(x509)) { + NETSTACK_LOGE("TlsCertificate::AnalysisCertificate: SetSerialNumber is false"); + return false; + } + if (!SetNotValidTime(x509)) { + NETSTACK_LOGE("TlsCertificate::AnalysisCertificate: SetNotValidTime is false"); + return false; + } + if (!SetSignatureAlgorithm(x509)) { + NETSTACK_LOGE("TlsCertificate::AnalysisCertificate: SetSignatureAlgorithm is false"); + return false; + } + return true; +} + +bool TLSCertificate::CaCertToString(X509 *x509) +{ + if (!x509) { + NETSTACK_LOGE("TlsCertificate::CaCertToString: x509 is null"); + return false; + } + BIO *bio = BIO_new(BIO_s_mem()); + X509_print(bio, x509); + char data[FILE_READ_CERT_LEN] = {}; + if (!BIO_read(bio, data, FILE_READ_CERT_LEN)) { + NETSTACK_LOGI("CaCertToString is BIO_read false"); + } + caCertString_ = std::string(data); + BIO_free(bio); + return true; +} + +bool TLSCertificate::LocalCertToString(X509 *x509) +{ + if (!x509) { + NETSTACK_LOGE("TlsCertificate::LocalCertToString: x509 is null"); + return false; + } + BIO *bio = BIO_new(BIO_s_mem()); + X509_print(bio, x509); + char data[FILE_READ_CERT_LEN] = {}; + if (!BIO_read(bio, data, FILE_READ_CERT_LEN)) { + NETSTACK_LOGE("LocalCertToString BIO_read is false"); + } + localCertString_ = std::string(data); + NETSTACK_LOGI("TlsCertificate::LocalCertToString cert is %{public}s", localCertString_.c_str()); + BIO_free(bio); + return true; +} + +bool TLSCertificate::SetX509Version(X509 *x509) +{ + if (!x509) { + NETSTACK_LOGE("TlsCertificate::SetX509Version: x509 is null"); + return false; + } + auto ver = X509_get_version(x509) + 1; + version_ = CERT_VERSION_FLAG + std::to_string(ver); + NETSTACK_LOGI("tls version_ %{public}s", version_.c_str()); + return true; +} + +bool TLSCertificate::SetSerialNumber(X509 *x509) +{ + if (!x509) { + NETSTACK_LOGE("TlsCertificate::SetSerialNumber: x509 is null"); + return false; + } + ASN1_INTEGER *serial = X509_get_serialNumber(x509); + if (!serial->length) { + NETSTACK_LOGE("X509_get_serialNumber length error"); + return false; + } + BIGNUM *bn = ASN1_INTEGER_to_BN(serial, nullptr); + if (!bn) { + NETSTACK_LOGE("TlsCertificate::SetSerialNumber: unable to convert ASN1INTEGER to BN"); + return false; + } + serialNumber_ = BN_bn2hex(bn); + BN_free(bn); + return true; +} + +bool TLSCertificate::SetNotValidTime(X509 *x509) +{ + if (!x509) { + NETSTACK_LOGE("TlsCertificate::SetNotValidTime: x509 is null"); + return false; + } + ASN1_TIME *before = X509_get_notBefore(x509); + if (!before) { + NETSTACK_LOGE("TlsCertificate::SetNotValidTime: before is null"); + return false; + } + tm tmBefore = {0}; + if (!ASN1_TIME_to_tm(before, &tmBefore)) { + NETSTACK_LOGE("TlsCertificate::SetNotValidTime: ASN1_TIME_to_tm before is false"); + return false; + } + notValidBefore_ = asctime(&tmBefore); + + ASN1_TIME *after = X509_get_notAfter(x509); + if (!after) { + NETSTACK_LOGE("TlsCertificate::SetNotValidTime: after is null"); + return false; + } + tm tmAfter; + if (!ASN1_TIME_to_tm(after, &tmAfter)) { + NETSTACK_LOGE("TlsCertificate::SetNotValidTime: ASN1_TIME_to_tm before is false"); + return false; + } + notValidAfter_ = asctime(&tmAfter); + return true; +} + +bool TLSCertificate::SetSignatureAlgorithm(X509 *x509) +{ + int signNid = X509_get_signature_nid(x509); + const char* sign = OBJ_nid2sn(signNid); + signatureAlgorithm_ = sign; + NETSTACK_LOGD("TlsCertificate::SetSignatureAlgorithm OBJ_nid2sn = %{public}s", signatureAlgorithm_.c_str()); + return true; +} + +std::string TLSCertificate::GetSignatureAlgorithm() const +{ + return signatureAlgorithm_; +} +std::string TLSCertificate::GetLocalCertString() const +{ + NETSTACK_LOGD("TlsCertificate::GetLocalCertString cert is %{public}s", localCertString_.c_str()); + return localCertString_; +} + +Handle TLSCertificate::handle() const +{ + return Handle(x509_); +} +} } // namespace OHOS::NetStack diff --git a/frameworks/native/tls_socket/src/tls_configuration.cpp b/frameworks/native/tls_socket/src/tls_configuration.cpp new file mode 100644 index 000000000..448f2034e --- /dev/null +++ b/frameworks/native/tls_socket/src/tls_configuration.cpp @@ -0,0 +1,186 @@ +/* +* Copyright (c) 2022 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "tls_configuration.h" + +#include +#include "tls.h" +#include "tls_key.h" +#include "netstack_log.h" + +namespace OHOS { +namespace NetStack { + +namespace { +constexpr const char *TLS_1_3 = "TlsV1_3"; +constexpr const char *TLS_1_2 = "TlsV1_2"; +} // namespace + +TLSConfiguration::TLSConfiguration(const TLSConfiguration &other) +{ + privateKey_ = other.privateKey_; +} + +const TLSKey& TLSConfiguration::PrivateKey() const +{ + return privateKey_; +} + +TLSConfiguration &TLSConfiguration::operator=(const TLSConfiguration &other) +{ + privateKey_= other.privateKey_; + localCertificate_ = other.localCertificate_; + caCertificate_ = other.caCertificate_; + minProtocol_ = other.minProtocol_; + maxProtocol_ = other.maxProtocol_; + cipherSuite_ = other.cipherSuite_; + return *this; +} + +void TLSConfiguration::SetLocalCertificate(const TLSCertificate &certificate) +{ + localCertificate_ = certificate; +} + +void TLSConfiguration::SetCaCertificate(const TLSCertificate &certificate) +{ + caCertificate_ = certificate; +} + +void TLSConfiguration::SetPrivateKey(const TLSKey &key) +{ + privateKey_ = key; +} + +void TLSConfiguration::SetPrivateKey(const std::string &key, const std::string &passwd) +{ +// TLSKey pkey(key, ALGORITHM_RSA, PEM, PRIVATE_KEY, passwd); + TLSKey pkey(key, ALGORITHM_RSA, passwd); + privateKey_ = pkey; +} + +void TLSConfiguration::SetLocalCertificate(const std::string &certificate) +{ +// TLSCertificate local(certificate, PEM, LOCAL_CERT); + TLSCertificate local(certificate, LOCAL_CERT); + localCertificate_ = local; +} + +void TLSConfiguration::SetCaCertificate(const std::vector &certificate) +{ + caCertificateChain_ = certificate; +} + +void TLSConfiguration::SetProtocol(const std::string &Protocol) +{ + if (Protocol == TLS_1_3) { + minProtocol_ = TLS_V1_3; + maxProtocol_ = TLS_V1_3; + } + if (Protocol == TLS_1_2) { + minProtocol_ = TLS_V1_2; + maxProtocol_ = TLS_V1_2; + } +} + +void TLSConfiguration::SetProtocol(const std::vector &Protocol) +{ + bool isTls1_3 = false; + bool isTls1_2 = false; + for (const auto &p : Protocol) { + if (p == TLS_1_3) { + maxProtocol_ = TLS_V1_3; + isTls1_3 = true; + } + if (p == TLS_1_2) { + minProtocol_ = TLS_V1_2; + isTls1_2 = true; + } + } + if (!isTls1_3) { + maxProtocol_ = TLS_V1_2; + } + if (!isTls1_2) { + minProtocol_ = TLS_V1_3; + } +} + +TLSProtocol TLSConfiguration::GetMinProtocol() const +{ + return minProtocol_; +} + +TLSProtocol TLSConfiguration::GetMaxProtocol() const +{ + return maxProtocol_; +} + +TLSProtocol TLSConfiguration::GetProtocol() const +{ + return protocol_; +} + +std::string TLSConfiguration::GetCipherSuite() const +{ + return cipherSuite_; +} + +std::vector TLSConfiguration::GetCipherSuiteVec() const +{ + return cipherSuiteVec_; +} + +std::string TLSConfiguration::GetCertificate() const +{ + return localCertificate_.GetLocalCertString(); +} + +void TLSConfiguration::SetCipherSuite(const std::string &cipherSuite) +{ + cipherSuite_ = cipherSuite; +} + +void TLSConfiguration::SetSignatureAlgorithms(const std::string &signatureAlgorithms) +{ + signatureAlgorithms_ = signatureAlgorithms; +} + +void TLSConfiguration::SetUseRemoteCipherPrefer(bool useRemoteCipherPrefer) +{ + useRemoteCipherPrefer_ = useRemoteCipherPrefer; +} + +bool TLSConfiguration::GetUseRemoteCipherPrefer() const +{ + return useRemoteCipherPrefer_; +} + +std::vector TLSConfiguration::GetCaCertificate() const +{ + return caCertificateChain_; +} + +TLSCertificate TLSConfiguration::GetLocalCertificate() const +{ + return localCertificate_; +} + +TLSKey TLSConfiguration::GetPrivateKey() const +{ + return privateKey_; +} + +TLSConfiguration::TLSConfiguration() = default; +} } // namespace OHOS::NetStack diff --git a/frameworks/native/tls_socket/src/tls_context.cpp b/frameworks/native/tls_socket/src/tls_context.cpp new file mode 100644 index 000000000..1e06c7509 --- /dev/null +++ b/frameworks/native/tls_socket/src/tls_context.cpp @@ -0,0 +1,228 @@ +/* +* Copyright (c) 2022 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "tls_context.h" +#include +#include + +#include +#include +#include "openssl/evp.h" + +#include "netstack_log.h" + +namespace OHOS { +namespace NetStack { + +std::unique_ptr TLSContext::CreateConfiguration(TlsMode mode, + const TLSConfiguration &configuration, + bool allowRootCertOnDemandLoading) +{ + auto tlsContext = std::make_unique(); + if (!InitTlsContext(tlsContext.get(), mode, configuration, allowRootCertOnDemandLoading)) { + return nullptr; + } + return tlsContext; +} + +void InitEnv() +{ + SSL_library_init(); + OpenSSL_add_all_algorithms(); + SSL_load_error_strings(); +} + +void TLSContext::SetCipherList(TLSContext *tlsContext, const TLSConfiguration &configuration) +{ + NETSTACK_LOGD("GetCipherSuite = %{public}s", configuration.GetCipherSuite().c_str()); + if (SSL_CTX_set_cipher_list(tlsContext->ctx_, configuration.GetCipherSuite().c_str()) <= 0) { + NETSTACK_LOGE("Error setting the cipher list"); + } +} + +void TLSContext::GetCiphers(TLSContext *tlsContext) +{ + std::vector cipherSuiteVec; + STACK_OF(SSL_CIPHER)* sk = SSL_CTX_get_ciphers(tlsContext->ctx_); + CipherSuite cipherSuite; + for (int i = 0; i < sk_SSL_CIPHER_num(sk); i++) { + const SSL_CIPHER* c = sk_SSL_CIPHER_value(sk, i); + cipherSuite.cipherId_ = SSL_CIPHER_get_id(c); + cipherSuite.cipherName_ = SSL_CIPHER_get_name(c); + cipherSuiteVec.push_back(cipherSuite); + NETSTACK_LOGD("SSL_CIPHER_get_id = %{public}lu, SSL_CIPHER_get_name = %{public}s", + cipherSuite.cipherId_, cipherSuite.cipherName_.c_str()); + } +} + +void TLSContext::UseRemoteCipher(TLSContext *tlsContext) +{ + if (tlsContext->tlsConfiguration_.GetUseRemoteCipherPrefer()) { + SSL_CTX_set_options(tlsContext->ctx_, SSL_OP_CIPHER_SERVER_PREFERENCE); + } + NETSTACK_LOGI("SSL_CTX_get_options = %{public}lx", SSL_CTX_get_options(tlsContext->ctx_)); +} + +void TLSContext::SetMinAndMaxProtocol(TLSContext *tlsContext) +{ + const long anyVersion = TLS_ANY_VERSION; + long minVersion = anyVersion; + long maxVersion = anyVersion; + + switch (tlsContext->tlsConfiguration_.GetMinProtocol()) { + case TLS_V1_2: + minVersion = TLS1_2_VERSION; + break; + case TLS_V1_3: + minVersion = TLS1_3_VERSION; + break; + case UNKNOW_PROTOCOL: + break; + } + + switch (tlsContext->tlsConfiguration_.GetMaxProtocol()) { + case TLS_V1_2: + maxVersion = TLS1_2_VERSION; + break; + case TLS_V1_3: + maxVersion = TLS1_3_VERSION; + break; + case UNKNOW_PROTOCOL: + break; + } + + if (minVersion != anyVersion && !SSL_CTX_set_min_proto_version(tlsContext->ctx_, minVersion)) { + NETSTACK_LOGE("Error while setting the minimal protocol version"); + return; + } + + if (maxVersion != anyVersion && !SSL_CTX_set_max_proto_version(tlsContext->ctx_, maxVersion)) { + NETSTACK_LOGE("Error while setting the maximum protocol version"); + return; + } + + NETSTACK_LOGD("minProtocol = %{public}lx, maxProtocol = %{public}lx", + SSL_CTX_get_min_proto_version(tlsContext->ctx_), SSL_CTX_get_max_proto_version(tlsContext->ctx_)); +} + +bool TLSContext::SetCaAndVerify(TLSContext *tlsContext, const TLSConfiguration &configuration) +{ + for (const auto &cert : configuration.GetCaCertificate()) { + TLSCertificate ca(cert, CA_CERT); + if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(tlsContext->ctx_), (X509 *)ca.handle())) { + return false; + } + } + return true; +} + +bool TLSContext::SetLocalCertificate(TLSContext *tlsContext, const TLSConfiguration &configuration) +{ + X509_print_fp(stdout, (X509*)configuration.GetLocalCertificate().handle()); + if (!SSL_CTX_use_certificate(tlsContext->ctx_, (X509 *)configuration.GetLocalCertificate().handle())) { + NETSTACK_LOGE("Error loading local certificate"); + return false; + } + return true; +} + +bool TLSContext::SetKeyAndCheck(TLSContext *tlsContext, const TLSConfiguration &configuration) +{ + if (configuration.GetPrivateKey().Algorithm() == OPAQUE) { + tlsContext->pkey_ = reinterpret_cast(configuration.GetPrivateKey().handle()); + } else { + tlsContext->pkey_ = EVP_PKEY_new(); + if (configuration.GetPrivateKey().Algorithm() == ALGORITHM_RSA) { + EVP_PKEY_set1_RSA(tlsContext->pkey_, + reinterpret_cast(configuration.GetPrivateKey().handle())); + } else if (tlsContext->tlsConfiguration_.GetPrivateKey().Algorithm() == ALGORITHM_DSA) { + EVP_PKEY_set1_DSA(tlsContext->pkey_, + reinterpret_cast(configuration.GetPrivateKey().handle())); + } + } + + if (configuration.GetPrivateKey().Algorithm() == OPAQUE) { + tlsContext->pkey_ = nullptr; + } + auto pkey_ = tlsContext->pkey_; + if (!SSL_CTX_use_PrivateKey(tlsContext->ctx_, pkey_)) { + NETSTACK_LOGE("SSL_CTX_use_PrivateKey is error"); + return false; + } + + if (!configuration.GetPrivateKey().GetPasswd().empty()) { + std::string password = tlsContext->tlsConfiguration_.GetPrivateKey().GetPasswd(); + NETSTACK_LOGI("tlsContext->tlsConfiguration_.privateKey_.GetPasswd()%{public}s", password.c_str()); + const char *pass = password.c_str(); + SSL_CTX_set_default_passwd_cb_userdata(tlsContext->ctx_, (void*)pass); + } + + const char *passwd = static_cast(SSL_CTX_get_default_passwd_cb_userdata(tlsContext->ctx_)); + NETSTACK_LOGI("pass = %{public}s", passwd); + + // Check if the certificate matches the private key. + if (!SSL_CTX_check_private_key(tlsContext->ctx_)) { + NETSTACK_LOGE("Check if the certificate matches the private key is error"); + return false; + } + return true; +} + +void TLSContext::SetVerify(TLSContext *tlsContext) +{ + SSL_CTX_set_verify(tlsContext->ctx_, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, nullptr); +} + +bool TLSContext::InitTlsContext(TLSContext *tlsContext, + TlsMode mode, + const TLSConfiguration &configuration, + bool allowRootCertOnDemandLoading) +{ + InitEnv(); + tlsContext->tlsConfiguration_ = configuration; + tlsContext->ctx_ = SSL_CTX_new(TLS_client_method()); + if (tlsContext->ctx_ == nullptr) { + ERR_print_errors_fp(stdout); + NETSTACK_LOGE("tlsContext->ctx_ is nullptr"); + return false; + } + + SetCipherList(tlsContext, configuration); + GetCiphers(tlsContext); + UseRemoteCipher(tlsContext); + SetMinAndMaxProtocol(tlsContext); + SetVerify(tlsContext); + if (!SetCaAndVerify(tlsContext, configuration)) { + return false; + } + if (!SetLocalCertificate(tlsContext, configuration)) { + return false; + } + if (!SetKeyAndCheck(tlsContext, configuration)) { + return false; + } + return true; +} +SSL *TLSContext::CreateSsl() +{ + ctxSsl_ = SSL_new(ctx_); + return ctxSsl_; +} + +void TLSContext::CloseCtx() +{ + SSL_CTX_free(ctx_); +} +} } // namespace OHOS::NetStack diff --git a/frameworks/native/tls_socket/src/tls_key.cpp b/frameworks/native/tls_socket/src/tls_key.cpp new file mode 100644 index 000000000..a4add526d --- /dev/null +++ b/frameworks/native/tls_socket/src/tls_key.cpp @@ -0,0 +1,269 @@ +/* +* Copyright (c) 2022 Huawei Device Co., Ltd. +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "tls_key.h" + +#include "netstack_log.h" + +namespace OHOS { +namespace NetStack { + +namespace { +constexpr int FILE_READ_Key_LEN = 4096; +constexpr const char *FILE_OPEN_FLAG = "rb"; +} // namespace + +TLSKey::TLSKey(const std::string &fileName, + KeyAlgorithm algorithm, + EncodingFormat encoding, + KeyType type, + const std::string &passPhrase) +{ + if (encoding == DER) { + DecodeDer(type, algorithm, fileName, passPhrase); + } else { + DecodePem(type, algorithm, fileName, passPhrase); + } +} + +TLSKey::TLSKey(const std::string &data, KeyAlgorithm algorithm, const std::string &passPhrase) +{ + if (data.empty()) { + NETSTACK_LOGE("TlsKey::TlsKey(const std::string &data, const std::string &passPhrase) data is empty"); + return; + } + DecodeData(data, algorithm, passPhrase); +} + +TLSKey &TLSKey::operator= (const TLSKey &other) +{ + if (other.rsa_ != nullptr) { + rsa_ = RSA_new(); + rsa_ = other.rsa_; + } + if (other.dsa_ != nullptr) { + dsa_ = DSA_new(); + dsa_ = other.dsa_; + } + if (other.dh_ != nullptr) { + dh_ = DH_new(); + dh_ = other.dh_; + } + if (other.genericKey_ != nullptr) { + genericKey_ = EVP_PKEY_new(); + genericKey_ = other.genericKey_; + } + keyIsNull_ = other.keyIsNull_; + keyType_ = other.keyType_; + keyAlgorithm_ = other.keyAlgorithm_; + passwd_ = other.passwd_; + return *this; +} + +void TLSKey::DecodeData(const std::string &data, KeyAlgorithm algorithm, const std::string &passPhrase) +{ + if (data.empty()) { + NETSTACK_LOGE("TlsKey::DecodeData data is empty"); + return; + } + keyAlgorithm_ = algorithm; + passwd_ = passPhrase; + BIO *bio = BIO_new_mem_buf(data.c_str(), -1); + if (!bio) { + NETSTACK_LOGE("TlsKey::DecodeData bio is null"); + return; + } + NETSTACK_LOGI("--- TlsKey::DecodeData rsa"); + RSA_print_fp(stdout,rsa_,11); + rsa_ = PEM_read_bio_RSAPrivateKey(bio, nullptr, nullptr, nullptr); + + if (rsa_) { + keyIsNull_ = false; + } +} + +void TLSKey::DecodeDer(KeyType type, + KeyAlgorithm algorithm, + const std::string &fileName, + const std::string &passPhrase) +{ + if (fileName.empty()) { + NETSTACK_LOGI("TlsKey::DecodeDer filename is empty"); + return; + } + keyType_ = type; + keyAlgorithm_ = algorithm; + passwd_ = passPhrase; + FILE *fp = nullptr; + fp = fopen(static_cast(fileName.c_str()), FILE_OPEN_FLAG); + if (!fp) { + NETSTACK_LOGE("TlsKey::DecodeDer: Couldn't open %{public}s file for reading", fileName.c_str()); + return; + } + char keyDer[FILE_READ_Key_LEN] = {}; + long keyLen = fread(keyDer, 1, FILE_READ_Key_LEN, fp); + (void)fclose(fp); + + const unsigned char *key_data = reinterpret_cast(keyDer); + if (type == PUBLIC_KEY) { + rsa_ = d2i_RSA_PUBKEY(nullptr, &key_data, keyLen); + } else { + rsa_ = d2i_RSAPrivateKey(nullptr, &key_data, keyLen); + } + if (!rsa_) { + NETSTACK_LOGE("TlsKey::DecodeDer rsa_ is null"); + return; + } + keyIsNull_ = false; +} + +void TLSKey::DecodePem(KeyType type, + KeyAlgorithm algorithm, + const std::string &fileName, + const std::string &passPhrase) +{ + if (fileName.empty()) { + NETSTACK_LOGE("TlsKey::DecodePem filename is empty"); + return; + } + keyType_ = type; + keyAlgorithm_ = algorithm; + FILE *fp = nullptr; + fp = fopen(static_cast(fileName.c_str()), FILE_OPEN_FLAG); + + if (!fp) { + NETSTACK_LOGE("TlsKey::DecodePem: Couldn't open %{public}s file for reading", fileName.c_str()); + return; + } + char privateKey[FILE_READ_Key_LEN] = {}; + if (!fread(privateKey, 1, FILE_READ_Key_LEN, fp)) { + NETSTACK_LOGE("TlsKey::DecodePem file read false"); + } + (void)fclose(fp); + const char *privateKeyData = static_cast(privateKey); + BIO *bio = BIO_new_mem_buf(privateKeyData, -1); + if (!bio) { + NETSTACK_LOGE("TlsKey::DecodePem: bio is null"); + return; + } + passwd_ = passPhrase; + switch (algorithm) { + case ALGORITHM_RSA: + rsa_ = (type == PUBLIC_KEY) + ? PEM_read_bio_RSA_PUBKEY(bio, nullptr, nullptr, nullptr) + : PEM_read_bio_RSAPrivateKey(bio, nullptr, nullptr, nullptr); + if (rsa_) { + keyIsNull_ = false; + } + break; + case ALGORITHM_DSA: + dsa_ = (type == PUBLIC_KEY) + ? PEM_read_bio_DSA_PUBKEY(bio, nullptr, nullptr, nullptr) + : PEM_read_bio_DSAPrivateKey(bio, nullptr, nullptr, nullptr); + if (dsa_) { + keyIsNull_ = false; + } + break; + case ALGORITHM_DH: { + EVP_PKEY *result = (type == PUBLIC_KEY) + ? PEM_read_bio_PUBKEY(bio, nullptr, nullptr, nullptr) + : PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr); + if (result) { + dh_ = EVP_PKEY_get1_DH(result); + } + if (dh_) { + keyIsNull_ = false; + } + EVP_PKEY_free(result); + break; + } + case ALGORITHM_EC: + ec_ = (type == PUBLIC_KEY) + ? PEM_read_bio_EC_PUBKEY(bio, nullptr, nullptr, nullptr) + : PEM_read_bio_ECPrivateKey(bio, nullptr, nullptr, nullptr); + if (ec_) { + keyIsNull_ = false; + } + break; + default: + NETSTACK_LOGE("TlsKey::DecodePem algorithm = %{public}d", algorithm); + } + BIO_free(bio); +} + +void TLSKey::Clear(bool deep) +{ + keyIsNull_ = true; + const auto algo = Algorithm(); + if (algo == ALGORITHM_RSA && rsa_) { + if (deep) { + RSA_free(rsa_); + } + rsa_ = nullptr; + } + if (algo == ALGORITHM_DSA && dsa_) { + if (deep) { + DSA_free(dsa_); + } + dsa_ = nullptr; + } + if (algo == ALGORITHM_DH && dh_) { + if (deep) { + DH_free(dh_); + } + dh_ = nullptr; + } + if (algo == ALGORITHM_EC && ec_) { + if (deep) { + EC_KEY_free(ec_); + } + ec_ = nullptr; + } + if (algo == OPAQUE && opaque_) { + if (deep) { + EVP_PKEY_free(opaque_); + } + opaque_ = nullptr; + } +} + +KeyAlgorithm TLSKey::Algorithm() const +{ + return keyAlgorithm_; +} + +Handle TLSKey::handle() const +{ + switch (keyAlgorithm_) { + case OPAQUE: + return Handle(OPAQUE); + case ALGORITHM_RSA: + return Handle(rsa_); + case ALGORITHM_DSA: + return Handle(dsa_); + case ALGORITHM_DH: + return Handle(dh_); + case ALGORITHM_EC: + return Handle(ec_); + default: + return Handle(nullptr); + } +} + +const std::string &TLSKey::GetPasswd() const +{ + return passwd_; +} +} } // namespace OHOS::NetStack -- Gitee