xref: /aosp_15_r20/external/tink/cc/subtle/pem_parser_boringssl.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2018 Google Inc.
2 //
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 "tink/subtle/pem_parser_boringssl.h"
17 
18 #include <memory>
19 #include <string>
20 #include <utility>
21 
22 #include "absl/memory/memory.h"
23 #include "absl/status/status.h"
24 #include "absl/strings/str_cat.h"
25 #include "absl/strings/string_view.h"
26 #include "openssl/bio.h"
27 #include "openssl/bn.h"
28 #include "openssl/ec.h"
29 #include "openssl/evp.h"
30 #include "openssl/pem.h"
31 #include "openssl/rsa.h"
32 #include "tink/internal/bn_util.h"
33 #include "tink/internal/ec_util.h"
34 #include "tink/internal/rsa_util.h"
35 #include "tink/internal/ssl_unique_ptr.h"
36 #include "tink/internal/ssl_util.h"
37 #include "tink/subtle/common_enums.h"
38 #include "tink/subtle/subtle_util_boringssl.h"
39 #include "tink/util/status.h"
40 #include "tink/util/statusor.h"
41 
42 namespace crypto {
43 namespace tink {
44 namespace subtle {
45 
46 namespace {
47 constexpr int kBsslOk = 1;
48 
49 // Verifies that the given RSA pointer `rsa_key` points to a valid RSA key.
VerifyRsaKey(const RSA * rsa_key)50 util::Status VerifyRsaKey(const RSA* rsa_key) {
51   if (rsa_key == nullptr) {
52     return util::Status(absl::StatusCode::kInvalidArgument,
53                         "Invalid RSA key format");
54   }
55   // Check the key parameters.
56   if (RSA_check_key(rsa_key) != kBsslOk) {
57     return util::Status(absl::StatusCode::kInvalidArgument,
58                         "Invalid RSA key format");
59   }
60   return util::OkStatus();
61 }
62 
63 // Verifies that the given ECDSA pointer `ecdsa_key` points to a valid ECDSA
64 // key.
VerifyEcdsaKey(const EC_KEY * ecdsa_key)65 util::Status VerifyEcdsaKey(const EC_KEY* ecdsa_key) {
66   if (ecdsa_key == nullptr) {
67     return util::Status(absl::StatusCode::kInvalidArgument,
68                         "Invalid ECDSA key format");
69   }
70   // Check the key parameters.
71   if (EC_KEY_check_key(ecdsa_key) != kBsslOk) {
72     return util::Status(absl::StatusCode::kInvalidArgument,
73                         "Invalid ECDSA key format");
74   }
75   return util::OkStatus();
76 }
77 
78 // Converts the public portion of a given SubtleUtilBoringSSL::EcKey,
79 // `subtle_ec_key`, into an OpenSSL EC key, `openssl_ec_key`.
EcKeyToSslEcPublicKey(const SubtleUtilBoringSSL::EcKey & subtle_ec_key,EC_KEY * openssl_ec_key)80 util::Status EcKeyToSslEcPublicKey(
81     const SubtleUtilBoringSSL::EcKey& subtle_ec_key, EC_KEY* openssl_ec_key) {
82   if (openssl_ec_key == nullptr) {
83     return util::Status(absl::StatusCode::kInvalidArgument,
84                         "`openssl_ec_key` arg cannot be NULL");
85   }
86 
87   util::StatusOr<internal::SslUniquePtr<EC_GROUP>> group =
88       internal::EcGroupFromCurveType(subtle_ec_key.curve);
89   if (!group.ok()) {
90     return group.status();
91   }
92 
93   util::StatusOr<internal::SslUniquePtr<EC_POINT>> ec_point =
94       internal::GetEcPoint(subtle_ec_key.curve, subtle_ec_key.pub_x,
95                            subtle_ec_key.pub_y);
96   if (!ec_point.ok()) {
97     return ec_point.status();
98   }
99 
100   // Set key's group and EC point.
101   if (!EC_KEY_set_group(openssl_ec_key, group->get())) {
102     return util::Status(
103         absl::StatusCode::kInternal,
104         absl::StrCat("Failed to set key group from EC group for curve ",
105                      EnumToString(subtle_ec_key.curve)));
106   }
107 
108   if (!EC_KEY_set_public_key(openssl_ec_key, ec_point->get())) {
109     return util::Status(absl::StatusCode::kInternal,
110                         "Failed to set public key");
111   }
112 
113   return util::OkStatus();
114 }
115 
116 // Converts a given SubtleUtilBoringSSL::EcKey, `subtle_ec_key`, into an OpenSSL
117 // EC key, `openssl_ec_key`.
EcKeyToSslEcPrivateKey(const SubtleUtilBoringSSL::EcKey & subtle_ec_key,EC_KEY * openssl_ec_key)118 util::Status EcKeyToSslEcPrivateKey(
119     const SubtleUtilBoringSSL::EcKey& subtle_ec_key, EC_KEY* openssl_ec_key) {
120   if (openssl_ec_key == nullptr) {
121     return util::Status(absl::StatusCode::kInvalidArgument,
122                         "`openssl_ec_key` arg cannot be NULL");
123   }
124   util::Status status = EcKeyToSslEcPublicKey(subtle_ec_key, openssl_ec_key);
125   if (!status.ok()) {
126     return status;
127   }
128 
129   util::StatusOr<internal::SslUniquePtr<BIGNUM>> x =
130       internal::StringToBignum(absl::string_view(
131           reinterpret_cast<const char*>(subtle_ec_key.priv.data()),
132           subtle_ec_key.priv.size()));
133   if (!x.ok()) {
134     return x.status();
135   }
136 
137   if (!EC_KEY_set_private_key(openssl_ec_key, x->get())) {
138     return util::Status(absl::StatusCode::kInvalidArgument,
139                         "Failed to set private key");
140   }
141   return VerifyEcdsaKey(openssl_ec_key);
142 }
143 
144 // Converts an OpenSSL BIO (i.e., basic IO stream), `bio`, into a string.
ConvertBioToString(BIO * bio)145 util::StatusOr<std::string> ConvertBioToString(BIO* bio) {
146   BUF_MEM* mem = nullptr;
147   BIO_get_mem_ptr(bio, &mem);
148   std::string pem_material;
149   if (mem->data && mem->length) {
150     pem_material.assign(mem->data, mem->length);
151   }
152   if (pem_material.empty()) {
153     return util::Status(absl::StatusCode::kInvalidArgument,
154                         "Failed to retrieve key material from BIO");
155   }
156   return pem_material;
157 }
158 
ScalarSizeInBytes(const EC_GROUP * group)159 size_t ScalarSizeInBytes(const EC_GROUP* group) {
160   return BN_num_bytes(EC_GROUP_get0_order(group));
161 }
162 
FieldElementSizeInBytes(const EC_GROUP * group)163 size_t FieldElementSizeInBytes(const EC_GROUP* group) {
164   unsigned degree_bits = EC_GROUP_get_degree(group);
165   return (degree_bits + 7) / 8;
166 }
167 
168 // We explicitly set a failing passphrase callback function to make sure no
169 // default callback routine is used.
FailingPassphraseCallback(char * buf,int buf_size,int rwflag,void * u)170 static int FailingPassphraseCallback(char* buf, int buf_size, int rwflag,
171                                      void* u) {
172   return -1;
173 }
174 
175 }  // namespace
176 
177 util::StatusOr<std::unique_ptr<internal::RsaPublicKey>>
ParseRsaPublicKey(absl::string_view pem_serialized_key)178 PemParser::ParseRsaPublicKey(absl::string_view pem_serialized_key) {
179   // Read the RSA key into EVP_PKEY.
180   internal::SslUniquePtr<BIO> rsa_key_bio(BIO_new(BIO_s_mem()));
181   BIO_write(rsa_key_bio.get(), pem_serialized_key.data(),
182             pem_serialized_key.size());
183 
184   internal::SslUniquePtr<EVP_PKEY> evp_rsa_key(
185       PEM_read_bio_PUBKEY(rsa_key_bio.get(), /*x=*/nullptr,
186                           &FailingPassphraseCallback, /*u=*/nullptr));
187 
188   if (evp_rsa_key == nullptr) {
189     return util::Status(absl::StatusCode::kInvalidArgument,
190                         "PEM Public Key parsing failed");
191   }
192   // No need to free bssl_rsa_key after use.
193   const RSA* bssl_rsa_key = EVP_PKEY_get0_RSA(evp_rsa_key.get());
194   util::Status verification_res = internal::RsaCheckPublicKey(bssl_rsa_key);
195   if (!verification_res.ok()) {
196     return verification_res;
197   }
198 
199   // Get the public key parameters.
200   const BIGNUM *n_bn, *e_bn, *d_bn;
201   RSA_get0_key(bssl_rsa_key, &n_bn, &e_bn, &d_bn);
202 
203   // Public key should not have d_bn set.
204   if (d_bn != nullptr) {
205     return util::Status(absl::StatusCode::kInvalidArgument,
206                         "Invalid RSA Public Key format");
207   }
208 
209   // We are only interested in e and n.
210   auto n_str = internal::BignumToString(n_bn, BN_num_bytes(n_bn));
211   auto e_str = internal::BignumToString(e_bn, BN_num_bytes(e_bn));
212   if (!n_str.ok()) {
213     return n_str.status();
214   }
215   if (!e_str.ok()) {
216     return e_str.status();
217   }
218   auto rsa_public_key = absl::make_unique<internal::RsaPublicKey>();
219   rsa_public_key->e = *std::move(e_str);
220   rsa_public_key->n = *std::move(n_str);
221 
222   return std::move(rsa_public_key);
223 }
224 
225 util::StatusOr<std::unique_ptr<internal::RsaPrivateKey>>
ParseRsaPrivateKey(absl::string_view pem_serialized_key)226 PemParser::ParseRsaPrivateKey(absl::string_view pem_serialized_key) {
227   // Read the private key into EVP_PKEY.
228   internal::SslUniquePtr<BIO> rsa_key_bio(BIO_new(BIO_s_mem()));
229   BIO_write(rsa_key_bio.get(), pem_serialized_key.data(),
230             pem_serialized_key.size());
231 
232   // BoringSSL APIs to parse the PEM data.
233   internal::SslUniquePtr<EVP_PKEY> evp_rsa_key(
234       PEM_read_bio_PrivateKey(rsa_key_bio.get(), /*x=*/nullptr,
235                               &FailingPassphraseCallback, /*u=*/nullptr));
236 
237   if (evp_rsa_key == nullptr) {
238     return util::Status(absl::StatusCode::kInvalidArgument,
239                         "PEM Private Key parsing failed");
240   }
241 
242   // No need to free bssl_rsa_key after use.
243   const RSA* bssl_rsa_key = EVP_PKEY_get0_RSA(evp_rsa_key.get());
244 
245   auto is_valid_key = VerifyRsaKey(bssl_rsa_key);
246   if (!is_valid_key.ok()) {
247     return is_valid_key;
248   }
249 
250   const BIGNUM *n_bn, *e_bn, *d_bn;
251   RSA_get0_key(bssl_rsa_key, &n_bn, &e_bn, &d_bn);
252 
253   // Save exponents.
254   auto rsa_private_key = absl::make_unique<internal::RsaPrivateKey>();
255   auto n_str = internal::BignumToString(n_bn, BN_num_bytes(n_bn));
256   auto e_str = internal::BignumToString(e_bn, BN_num_bytes(e_bn));
257   auto d_str = internal::BignumToSecretData(d_bn, BN_num_bytes(d_bn));
258   if (!n_str.ok()) {
259     return n_str.status();
260   }
261   if (!e_str.ok()) {
262     return e_str.status();
263   }
264   if (!d_str.ok()) {
265     return d_str.status();
266   }
267   rsa_private_key->n = *std::move(n_str);
268   rsa_private_key->e = *std::move(e_str);
269   rsa_private_key->d = *std::move(d_str);
270 
271   // Save factors.
272   const BIGNUM *p_bn, *q_bn;
273   RSA_get0_factors(bssl_rsa_key, &p_bn, &q_bn);
274   auto p_str = internal::BignumToSecretData(p_bn, BN_num_bytes(p_bn));
275   auto q_str = internal::BignumToSecretData(q_bn, BN_num_bytes(q_bn));
276   if (!p_str.ok()) {
277     return p_str.status();
278   }
279   if (!q_str.ok()) {
280     return q_str.status();
281   }
282   rsa_private_key->p = *std::move(p_str);
283   rsa_private_key->q = *std::move(q_str);
284 
285   // Save CRT parameters.
286   const BIGNUM *dp_bn, *dq_bn, *crt_bn;
287   RSA_get0_crt_params(bssl_rsa_key, &dp_bn, &dq_bn, &crt_bn);
288   auto dp_str = internal::BignumToSecretData(dp_bn, BN_num_bytes(dp_bn));
289   auto dq_str = internal::BignumToSecretData(dq_bn, BN_num_bytes(dq_bn));
290   auto crt_str = internal::BignumToSecretData(crt_bn, BN_num_bytes(crt_bn));
291   if (!dp_str.ok()) {
292     return dp_str.status();
293   }
294   if (!dq_str.ok()) {
295     return dq_str.status();
296   }
297   if (!crt_str.ok()) {
298     return crt_str.status();
299   }
300   rsa_private_key->dp = *std::move(dp_str);
301   rsa_private_key->dq = *std::move(dq_str);
302   rsa_private_key->crt = *std::move(crt_str);
303 
304   return std::move(rsa_private_key);
305 }
306 
WriteRsaPublicKey(const internal::RsaPublicKey & rsa_public_key)307 util::StatusOr<std::string> PemParser::WriteRsaPublicKey(
308     const internal::RsaPublicKey& rsa_public_key) {
309   auto rsa_statusor = internal::RsaPublicKeyToRsa(rsa_public_key);
310   if (!rsa_statusor.ok()) {
311     return rsa_statusor.status();
312   }
313 
314   internal::SslUniquePtr<RSA> rsa = *std::move(rsa_statusor);
315   internal::SslUniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
316   if (!PEM_write_bio_RSA_PUBKEY(bio.get(), rsa.get())) {
317     return util::Status(absl::StatusCode::kInvalidArgument,
318                         "Failed to write openssl RSA key to write bio");
319   }
320   return ConvertBioToString(bio.get());
321 }
322 
WriteRsaPrivateKey(const internal::RsaPrivateKey & rsa_private_key)323 util::StatusOr<std::string> PemParser::WriteRsaPrivateKey(
324     const internal::RsaPrivateKey& rsa_private_key) {
325   auto rsa_statusor = internal::RsaPrivateKeyToRsa(rsa_private_key);
326   if (!rsa_statusor.ok()) {
327     return rsa_statusor.status();
328   }
329 
330   internal::SslUniquePtr<RSA> rsa = *std::move(rsa_statusor);
331   internal::SslUniquePtr<EVP_PKEY> evp(EVP_PKEY_new());
332   EVP_PKEY_set1_RSA(evp.get(), rsa.get());
333 
334   internal::SslUniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
335   if (!PEM_write_bio_PrivateKey(bio.get(), evp.get(),
336                                 /*enc=*/nullptr, /*kstr=*/nullptr,
337                                 /*klen=*/0,
338                                 /*cb=*/nullptr, /*u=*/nullptr)) {
339     return util::Status(absl::StatusCode::kInvalidArgument,
340                         "Failed to write openssl RSA key to write bio");
341   }
342   return ConvertBioToString(bio.get());
343 }
344 
345 util::StatusOr<std::unique_ptr<SubtleUtilBoringSSL::EcKey>>
ParseEcPublicKey(absl::string_view pem_serialized_key)346 PemParser::ParseEcPublicKey(absl::string_view pem_serialized_key) {
347   // Read the ECDSA key into EVP_PKEY.
348   internal::SslUniquePtr<BIO> ecdsa_key_bio(BIO_new(BIO_s_mem()));
349   BIO_write(ecdsa_key_bio.get(), pem_serialized_key.data(),
350             pem_serialized_key.size());
351 
352   internal::SslUniquePtr<EVP_PKEY> evp_ecdsa_key(
353       PEM_read_bio_PUBKEY(ecdsa_key_bio.get(), /*x=*/nullptr,
354                           &FailingPassphraseCallback, /*u=*/nullptr));
355 
356   if (evp_ecdsa_key == nullptr) {
357     return util::Status(absl::StatusCode::kInvalidArgument,
358                         "PEM Public Key parsing failed");
359   }
360   // No need to free bssl_ecdsa_key after use.
361   const EC_KEY* bssl_ecdsa_key = EVP_PKEY_get0_EC_KEY(evp_ecdsa_key.get());
362   auto is_valid = VerifyEcdsaKey(bssl_ecdsa_key);
363   if (!is_valid.ok()) {
364     return is_valid;
365   }
366 
367   // Get the public key parameters.
368   const EC_POINT* public_point = EC_KEY_get0_public_key(bssl_ecdsa_key);
369   const EC_GROUP* ec_group = EC_KEY_get0_group(bssl_ecdsa_key);
370   internal::SslUniquePtr<BIGNUM> x_coordinate(BN_new());
371   internal::SslUniquePtr<BIGNUM> y_coordinate(BN_new());
372   EC_POINT_get_affine_coordinates(ec_group, public_point, x_coordinate.get(),
373                                   y_coordinate.get(), nullptr);
374 
375   // Convert public key parameters and construct Subtle ECKey
376   util::StatusOr<std::string> x_string = internal::BignumToString(
377       x_coordinate.get(), FieldElementSizeInBytes(ec_group));
378   if (!x_string.ok()) {
379     return x_string.status();
380   }
381   util::StatusOr<std::string> y_string = internal::BignumToString(
382       y_coordinate.get(), FieldElementSizeInBytes(ec_group));
383   if (!y_string.ok()) {
384     return y_string.status();
385   }
386   util::StatusOr<EllipticCurveType> curve =
387       internal::CurveTypeFromEcGroup(ec_group);
388   if (!curve.ok()) {
389     return curve.status();
390   }
391 
392   auto ecdsa_public_key = absl::make_unique<SubtleUtilBoringSSL::EcKey>();
393   ecdsa_public_key->pub_x = *std::move(x_string);
394   ecdsa_public_key->pub_y = *std::move(y_string);
395   ecdsa_public_key->curve = *std::move(curve);
396 
397   return std::move(ecdsa_public_key);
398 }
399 
400 util::StatusOr<std::unique_ptr<SubtleUtilBoringSSL::EcKey>>
ParseEcPrivateKey(absl::string_view pem_serialized_key)401 PemParser::ParseEcPrivateKey(absl::string_view pem_serialized_key) {
402   internal::SslUniquePtr<BIO> ecdsa_key_bio(BIO_new(BIO_s_mem()));
403   BIO_write(ecdsa_key_bio.get(), pem_serialized_key.data(),
404             pem_serialized_key.size());
405 
406   internal::SslUniquePtr<EVP_PKEY> evp_ecdsa_key(
407       PEM_read_bio_PrivateKey(ecdsa_key_bio.get(), /*x=*/nullptr,
408                               &FailingPassphraseCallback, /*u=*/nullptr));
409 
410   if (evp_ecdsa_key == nullptr) {
411     return util::Status(absl::StatusCode::kInvalidArgument,
412                         "PEM Private Key parsing failed");
413   }
414 
415   // No need to free bssl_ecdsa_key after use.
416   const EC_KEY* bssl_ecdsa_key = EVP_PKEY_get0_EC_KEY(evp_ecdsa_key.get());
417   util::Status verify_result = VerifyEcdsaKey(bssl_ecdsa_key);
418   if (!verify_result.ok()) {
419     return verify_result;
420   }
421 
422   internal::SslUniquePtr<BIGNUM> x_coordinate(BN_new());
423   internal::SslUniquePtr<BIGNUM> y_coordinate(BN_new());
424   const EC_POINT* public_point = EC_KEY_get0_public_key(bssl_ecdsa_key);
425   const EC_GROUP* ec_group = EC_KEY_get0_group(bssl_ecdsa_key);
426   EC_POINT_get_affine_coordinates(ec_group, public_point, x_coordinate.get(),
427                                   y_coordinate.get(), nullptr);
428 
429   const BIGNUM* priv_key = EC_KEY_get0_private_key(bssl_ecdsa_key);
430   util::StatusOr<util::SecretData> priv =
431       internal::BignumToSecretData(priv_key, ScalarSizeInBytes(ec_group));
432   if (!priv.ok()) {
433     return priv.status();
434   }
435   util::StatusOr<std::string> x_string = internal::BignumToString(
436       x_coordinate.get(), FieldElementSizeInBytes(ec_group));
437   if (!x_string.ok()) {
438     return x_string.status();
439   }
440   util::StatusOr<std::string> y_string = internal::BignumToString(
441       y_coordinate.get(), FieldElementSizeInBytes(ec_group));
442   if (!y_string.ok()) {
443     return y_string.status();
444   }
445   util::StatusOr<EllipticCurveType> curve =
446       internal::CurveTypeFromEcGroup(ec_group);
447   if (!curve.ok()) {
448     return curve.status();
449   }
450 
451   auto ecdsa_private_key = absl::make_unique<SubtleUtilBoringSSL::EcKey>();
452   ecdsa_private_key->pub_x = *std::move(x_string);
453   ecdsa_private_key->pub_y = *std::move(y_string);
454   ecdsa_private_key->priv = *std::move(priv);
455   ecdsa_private_key->curve = *std::move(curve);
456 
457   return std::move(ecdsa_private_key);
458 }
459 
WriteEcPublicKey(const SubtleUtilBoringSSL::EcKey & ec_key)460 util::StatusOr<std::string> PemParser::WriteEcPublicKey(
461     const SubtleUtilBoringSSL::EcKey& ec_key) {
462   internal::SslUniquePtr<EC_KEY> openssl_ec_key(EC_KEY_new());
463   util::Status status = EcKeyToSslEcPublicKey(ec_key, openssl_ec_key.get());
464   if (!status.ok()) {
465     return status;
466   }
467   internal::SslUniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
468   if (!PEM_write_bio_EC_PUBKEY(bio.get(), openssl_ec_key.get())) {
469     return util::Status(absl::StatusCode::kInvalidArgument,
470                         "Failed to write openssl EC key to write bio");
471   }
472   return ConvertBioToString(bio.get());
473 }
474 
WriteEcPrivateKey(const SubtleUtilBoringSSL::EcKey & ec_key)475 util::StatusOr<std::string> PemParser::WriteEcPrivateKey(
476     const SubtleUtilBoringSSL::EcKey& ec_key) {
477   internal::SslUniquePtr<EC_KEY> openssl_ec_key(EC_KEY_new());
478   util::Status status = EcKeyToSslEcPrivateKey(ec_key, openssl_ec_key.get());
479   if (!status.ok()) {
480     return status;
481   }
482   internal::SslUniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
483   if (!PEM_write_bio_ECPrivateKey(bio.get(), openssl_ec_key.get(),
484                                   /*enc=*/nullptr, /*kstr=*/nullptr, /*klen=*/0,
485                                   /*cb=*/nullptr, /*u=*/nullptr)) {
486     return util::Status(absl::StatusCode::kInvalidArgument,
487                         "Failed to write openssl EC key to write bio");
488   }
489   return ConvertBioToString(bio.get());
490 }
491 
492 }  // namespace subtle
493 }  // namespace tink
494 }  // namespace crypto
495