1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "util/crypto/rsa_private_key.h"
6 
7 #include <stdint.h>
8 
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 
13 #include "openssl/bn.h"
14 #include "openssl/bytestring.h"
15 #include "openssl/evp.h"
16 #include "openssl/mem.h"
17 #include "openssl/rsa.h"
18 #include "util/crypto/openssl_util.h"
19 #include "util/osp_logging.h"
20 
21 namespace openscreen {
22 RSAPrivateKey::~RSAPrivateKey() = default;
23 
24 // static
Create(uint16_t num_bits)25 ErrorOr<RSAPrivateKey> RSAPrivateKey::Create(uint16_t num_bits) {
26   OpenSSLErrStackTracer err_tracer(CURRENT_LOCATION);
27 
28   bssl::UniquePtr<RSA> rsa_key(RSA_new());
29   bssl::UniquePtr<BIGNUM> exponent(BN_new());
30   if (!rsa_key.get() || !exponent.get() ||
31       !BN_set_word(exponent.get(), 65537L) ||
32       !RSA_generate_key_ex(rsa_key.get(), num_bits, exponent.get(), nullptr)) {
33     return Error::Code::kRSAKeyGenerationFailure;
34   }
35 
36   RSAPrivateKey result;
37   result.key_.reset(EVP_PKEY_new());
38   if (!result.key_ || !EVP_PKEY_set1_RSA(result.key_.get(), rsa_key.get())) {
39     return Error::Code::kEVPInitializationError;
40   }
41 
42   return result;
43 }
44 
45 // static
CreateFromPrivateKeyInfo(const std::vector<uint8_t> & input)46 ErrorOr<RSAPrivateKey> RSAPrivateKey::CreateFromPrivateKeyInfo(
47     const std::vector<uint8_t>& input) {
48   OpenSSLErrStackTracer err_tracer(CURRENT_LOCATION);
49 
50   CBS private_key_cbs;
51   CBS_init(&private_key_cbs, input.data(), input.size());
52   bssl::UniquePtr<EVP_PKEY> private_key(
53       EVP_parse_private_key(&private_key_cbs));
54   if (!private_key || CBS_len(&private_key_cbs) != 0 ||
55       EVP_PKEY_id(private_key.get()) != EVP_PKEY_RSA) {
56     return Error::Code::kEVPInitializationError;
57   }
58 
59   RSAPrivateKey result;
60   result.key_ = std::move(private_key);
61   return result;
62 }
63 
64 // static
CreateFromKey(EVP_PKEY * key)65 ErrorOr<RSAPrivateKey> RSAPrivateKey::CreateFromKey(EVP_PKEY* key) {
66   OpenSSLErrStackTracer err_tracer(CURRENT_LOCATION);
67   OSP_DCHECK(key);
68   if (EVP_PKEY_type(key->type) != EVP_PKEY_RSA) {
69     return Error::Code::kEVPInitializationError;
70   }
71 
72   RSAPrivateKey result;
73   result.key_ = bssl::UpRef(key);
74   return result;
75 }
76 
Copy() const77 ErrorOr<RSAPrivateKey> RSAPrivateKey::Copy() const {
78   OpenSSLErrStackTracer err_tracer(CURRENT_LOCATION);
79   RSAPrivateKey result;
80   bssl::UniquePtr<RSA> rsa(EVP_PKEY_get1_RSA(key_.get()));
81   if (!rsa) {
82     return Error::Code::kEVPInitializationError;
83   }
84 
85   result.key_.reset(EVP_PKEY_new());
86   if (!EVP_PKEY_set1_RSA(result.key_.get(), rsa.get())) {
87     return Error::Code::kEVPInitializationError;
88   }
89 
90   return result;
91 }
92 
ExportPrivateKey() const93 ErrorOr<std::vector<uint8_t>> RSAPrivateKey::ExportPrivateKey() const {
94   OpenSSLErrStackTracer err_tracer(CURRENT_LOCATION);
95   uint8_t* der;
96   size_t der_len;
97   bssl::ScopedCBB cbb;
98   if (!CBB_init(cbb.get(), 0) ||
99       !EVP_marshal_private_key(cbb.get(), key_.get()) ||
100       !CBB_finish(cbb.get(), &der, &der_len)) {
101     return Error::Code::kParseError;
102   }
103 
104   std::vector<uint8_t> output(der, der + der_len);
105   // The temporary buffer has to be freed after we properly copy out data.
106   OPENSSL_free(der);
107   return output;
108 }
109 
ExportPublicKey() const110 ErrorOr<std::vector<uint8_t>> RSAPrivateKey::ExportPublicKey() const {
111   OpenSSLErrStackTracer err_tracer(CURRENT_LOCATION);
112   uint8_t* der;
113   size_t der_len;
114   bssl::ScopedCBB cbb;
115   if (!CBB_init(cbb.get(), 0) ||
116       !EVP_marshal_public_key(cbb.get(), key_.get()) ||
117       !CBB_finish(cbb.get(), &der, &der_len)) {
118     return Error::Code::kParseError;
119   }
120 
121   std::vector<uint8_t> output(der, der + der_len);
122   // The temporary buffer has to be freed after we properly copy out data.
123   OPENSSL_free(der);
124   return output;
125 }
126 
127 RSAPrivateKey::RSAPrivateKey() = default;
128 
129 }  // namespace openscreen
130