1  /*
2   * Copyright (c) 2021 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  #include "pkg_algo_sign.h"
16  #include <openssl/bio.h>
17  #include <openssl/bn.h>
18  #include <openssl/ec.h>
19  #include <openssl/ecdsa.h>
20  #include <openssl/evp.h>
21  #include <openssl/obj_mac.h>
22  #include <openssl/pem.h>
23  #include <openssl/rsa.h>
24  #include <openssl/sha.h>
25  #include "openssl_util.h"
26  #include "pkg_algorithm.h"
27  #include "pkg_utils.h"
28  
29  using namespace Updater;
30  
31  namespace Hpackage {
32  #ifndef BIO_FP_READ
33  constexpr uint32_t BIO_FP_READ = 0x02;
34  #endif
SignBuffer(const PkgBuffer & buffer,std::vector<uint8_t> & sign,size_t & signLen) const35  int32_t SignAlgorithmRsa::SignBuffer(const PkgBuffer &buffer, std::vector<uint8_t> &sign, size_t &signLen) const
36  {
37      if (buffer.buffer == nullptr) {
38          PKG_LOGE("Param null!");
39          return PKG_INVALID_PARAM;
40      }
41      BIO *in = BIO_new(BIO_s_file());
42      if (in == nullptr) {
43          PKG_LOGE("Failed to new BIO");
44          return PKG_INVALID_PARAM;
45      }
46  
47      int32_t ret = BIO_ctrl(in, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_READ, const_cast<char*>(keyName_.c_str()));
48      if (ret != 1) {
49          PKG_LOGE("Failed to BIO_read_filename ret %d %s", ret, keyName_.c_str());
50          BIO_free(in);
51          return PKG_INVALID_PARAM;
52      }
53  
54      RSA *rsa = PEM_read_bio_RSAPrivateKey(in, nullptr, nullptr, nullptr);
55      BIO_free(in);
56      if (rsa == nullptr) {
57          PKG_LOGE("Failed to PEM_read_bio_RSAPrivateKey ");
58          return PKG_INVALID_SIGNATURE;
59      }
60  
61      // Adjust key size
62      uint32_t size = static_cast<uint32_t>(RSA_size(rsa));
63      sign.resize(size);
64      ret = 0;
65      if (digestMethod_ == PKG_DIGEST_TYPE_SHA256) {
66          ret = RSA_sign(NID_sha256, buffer.buffer, buffer.length, sign.data(), &size, rsa);
67      } else if (digestMethod_ == PKG_DIGEST_TYPE_SHA384) {
68          ret = RSA_sign(NID_sha384, buffer.buffer, buffer.length, sign.data(), &size, rsa);
69      }
70      signLen = size;
71      RSA_free(rsa);
72      return ((ret == 1) ? PKG_SUCCESS : PKG_INVALID_SIGNATURE);
73  }
74  
SignBuffer(const PkgBuffer & buffer,std::vector<uint8_t> & sign,size_t & signLen) const75  int32_t SignAlgorithmEcc::SignBuffer(const PkgBuffer &buffer, std::vector<uint8_t> &sign, size_t &signLen) const
76  {
77      if (buffer.buffer == nullptr) {
78          PKG_LOGE("Param null!");
79          return PKG_INVALID_PARAM;
80      }
81      BIO *in = BIO_new(BIO_s_file());
82      if (in == nullptr) {
83          PKG_LOGE("Failed to new BIO ");
84          return PKG_INVALID_PARAM;
85      }
86  
87      int ret = BIO_ctrl(in, BIO_C_SET_FILENAME, BIO_CLOSE | BIO_FP_READ, const_cast<char*>(keyName_.c_str()));
88      if (ret != 1) {
89          PKG_LOGE("Failed to BIO_read_filename ret %d %s", ret, keyName_.c_str());
90          BIO_free(in);
91          return PKG_INVALID_PARAM;
92      }
93  
94      EC_KEY *ecKey = PEM_read_bio_ECPrivateKey(in, nullptr, nullptr, nullptr);
95      BIO_free(in);
96      if (ecKey == nullptr) {
97          PKG_LOGE("Failed to PEM_read_bio_ECPrivateKey %s", keyName_.c_str());
98          return PKG_INVALID_PARAM;
99      }
100  
101      // Adjust key size
102      uint32_t size = static_cast<uint32_t>(ECDSA_size(ecKey));
103      sign.resize(size + sizeof(uint32_t));
104      ret = ECDSA_sign(0, buffer.buffer, buffer.length, sign.data() + sizeof(uint32_t), &size, ecKey);
105      WriteLE32(sign.data(), size);
106      signLen = size + sizeof(uint32_t);
107      EC_KEY_free(ecKey);
108      return ((ret == 1) ? PKG_SUCCESS : PKG_INVALID_SIGNATURE);
109  }
110  
GetPubkey() const111  X509 *SignAlgorithm::GetPubkey() const
112  {
113      BIO *certbio = BIO_new_file(keyName_.c_str(), "r");
114      if (certbio == nullptr) {
115          PKG_LOGE("Failed to create BIO");
116          return nullptr;
117      }
118      X509 *rcert = PEM_read_bio_X509(certbio, nullptr, nullptr, nullptr);
119      if (rcert == nullptr) {
120          PKG_LOGE("Failed to read x509 certificate");
121          BIO_free(certbio);
122          return nullptr;
123      }
124      BIO_free(certbio);
125      return rcert;
126  }
127  
VerifyDigest(const std::vector<uint8_t> & digest,const std::vector<uint8_t> & signature)128  int32_t SignAlgorithm::VerifyDigest(const std::vector<uint8_t> &digest, const std::vector<uint8_t> &signature)
129  {
130      X509 *rcert = GetPubkey();
131      if (rcert == nullptr) {
132          PKG_LOGE("get pubkey fail");
133          return PKG_INVALID_SIGNATURE;
134      }
135      EVP_PKEY *pubKey = X509_get_pubkey(rcert);
136      if (pubKey == nullptr) {
137          X509_free(rcert);
138          PKG_LOGE("get pubkey from cert fail");
139          return PKG_INVALID_SIGNATURE;
140      }
141      int nid = EVP_MD_type(EVP_sha256());
142      int ret = VerifyDigestByPubKey(pubKey, nid, digest, signature);
143      if (ret != 0) {
144          EVP_PKEY_free(pubKey);
145          X509_free(rcert);
146          PKG_LOGE("Failed to verify digest by pubKey");
147          return PKG_INVALID_SIGNATURE;
148      }
149      EVP_PKEY_free(pubKey);
150      X509_free(rcert);
151      return 0;
152  }
153  
GetSignAlgorithm(const std::string & path,uint8_t signMethod,uint8_t type)154  SignAlgorithm::SignAlgorithmPtr PkgAlgorithmFactory::GetSignAlgorithm(const std::string &path,
155      uint8_t signMethod, uint8_t type)
156  {
157      switch (signMethod) {
158          case PKG_SIGN_METHOD_RSA:
159              return std::make_shared<SignAlgorithmRsa>(path, type);
160          case PKG_SIGN_METHOD_ECDSA:
161              return std::make_shared<SignAlgorithmEcc>(path, type);
162          default:
163              break;
164      }
165      return nullptr;
166  }
167  
GetVerifyAlgorithm(const std::string & path,uint8_t type)168  SignAlgorithm::SignAlgorithmPtr PkgAlgorithmFactory::GetVerifyAlgorithm(const std::string &path, uint8_t type)
169  {
170      return std::make_shared<VerifyAlgorithm>(path, type);
171  }
172  } // namespace Hpackage
173