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 "openssl_utils.h"
17 
18 #include <mutex>
19 #include <openssl/pem.h>
20 #include "log.h"
21 
22 namespace OHOS {
23 namespace Security {
24 namespace CodeSign {
GetOpensslErrorMessage()25 void GetOpensslErrorMessage()
26 {
27     unsigned long retOpenssl;
28     char errOpenssl[OPENSSL_ERR_MESSAGE_MAX_LEN];
29     while ((retOpenssl = ERR_get_error()) != 0) {
30         // error string is written no more than OPENSSL_ERR_MESSAGE_MAX_LEN in errOpenssl
31         ERR_error_string_n(retOpenssl, errOpenssl, OPENSSL_ERR_MESSAGE_MAX_LEN);
32         LOG_ERROR("openssl err: %{public}lu, message: %{public}s", retOpenssl, errOpenssl);
33     }
34 }
35 
LoadCertFromBuffer(const uint8_t * buffer,const uint32_t size)36 X509 *LoadCertFromBuffer(const uint8_t *buffer, const uint32_t size)
37 {
38     BIO *mem = BIO_new_mem_buf(buffer, size);
39     if (mem == nullptr) {
40         LOG_ERROR("Fail to create bio for cert.");
41         return nullptr;
42     }
43     X509 *cert = d2i_X509_bio(mem, nullptr);
44     if (cert == nullptr) {
45         ERR_LOG_WITH_OPEN_SSL_MSG("Certificate is invalid.");
46     }
47     BIO_free(mem);
48     return cert;
49 }
50 
ConvertCertToPEMString(const ByteBuffer & certBuffer,std::string & pemString)51 bool ConvertCertToPEMString(const ByteBuffer &certBuffer, std::string &pemString)
52 {
53     X509 *cert = LoadCertFromBuffer(certBuffer.GetBuffer(), certBuffer.GetSize());
54     if (cert == nullptr) {
55         return false;
56     }
57     BIO *mem = BIO_new(BIO_s_mem());
58     if (mem == nullptr) {
59         X509_free(cert);
60         return false;
61     }
62     bool ret = false;
63     do {
64         if (!PEM_write_bio_X509(mem, cert)) {
65             ERR_LOG_WITH_OPEN_SSL_MSG("convert to pem failed.");
66             break;
67         }
68         uint8_t *outData = nullptr;
69         int32_t len = BIO_get_mem_data(mem, &outData);
70         if (len < 0) {
71             break;
72         }
73         pemString = std::string(reinterpret_cast<char *>(outData), len);
74         ret = true;
75     } while (0);
76     BIO_free(mem);
77     X509_free(cert);
78     return ret;
79 }
80 
STACK_OF(X509)81 STACK_OF(X509) *MakeStackOfCerts(const std::vector<ByteBuffer> &certChain)
82 {
83     STACK_OF(X509)* certs = sk_X509_new_null();
84     if (certs == nullptr) {
85         return nullptr;
86     }
87 
88     for (const ByteBuffer &cert: certChain) {
89         X509 *tmp = LoadCertFromBuffer(cert.GetBuffer(), cert.GetSize());
90 
91         if ((tmp == nullptr) || (!sk_X509_push(certs, tmp))) {
92             // including each cert in certs and stack of certs
93             sk_X509_pop_free(certs, X509_free);
94             certs = nullptr;
95             ERR_LOG_WITH_OPEN_SSL_MSG("Push cert failed.");
96             break;
97         }
98     }
99     return certs;
100 }
101 
CreateNIDFromOID(const std::string & oid,const std::string & shortName,const std::string & longName)102 int CreateNIDFromOID(const std::string &oid, const std::string &shortName,
103     const std::string &longName)
104 {
105     static std::mutex oidLock;
106     std::lock_guard<std::mutex> lock(oidLock);
107     int nid = OBJ_txt2nid(oid.c_str());
108     if (nid == NID_undef) {
109         nid = OBJ_create(oid.c_str(), shortName.c_str(), longName.c_str());
110     }
111     return nid;
112 }
113 }
114 }
115 }
116