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