// Copyright 2020 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "device/fido/rsa_public_key.h" #include #include "components/cbor/writer.h" #include "device/fido/cbor_extract.h" #include "device/fido/fido_constants.h" #include "third_party/boringssl/src/include/openssl/bn.h" #include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/evp.h" #include "third_party/boringssl/src/include/openssl/mem.h" #include "third_party/boringssl/src/include/openssl/obj.h" #include "third_party/boringssl/src/include/openssl/rsa.h" using device::cbor_extract::IntKey; using device::cbor_extract::Is; using device::cbor_extract::StepOrByte; using device::cbor_extract::Stop; namespace device { // static std::unique_ptr RSAPublicKey::ExtractFromCOSEKey( int32_t algorithm, base::span cbor_bytes, const cbor::Value::MapValue& map) { // See https://tools.ietf.org/html/rfc8230#section-4 struct COSEKey { const int64_t* kty; const std::vector* n; const std::vector* e; } cose_key; static constexpr cbor_extract::StepOrByte kSteps[] = { // clang-format off ELEMENT(Is::kRequired, COSEKey, kty), IntKey(static_cast(CoseKeyKey::kKty)), ELEMENT(Is::kRequired, COSEKey, n), IntKey(static_cast(CoseKeyKey::kRSAModulus)), ELEMENT(Is::kRequired, COSEKey, e), IntKey(static_cast(CoseKeyKey::kRSAPublicExponent)), Stop(), // clang-format on }; if (!cbor_extract::Extract(&cose_key, kSteps, map) || *cose_key.kty != static_cast(CoseKeyTypes::kRSA)) { return nullptr; } bssl::UniquePtr n_bn(BN_new()); bssl::UniquePtr e_bn(BN_new()); if (!BN_bin2bn(cose_key.n->data(), cose_key.n->size(), n_bn.get()) || !BN_bin2bn(cose_key.e->data(), cose_key.e->size(), e_bn.get())) { return nullptr; } bssl::UniquePtr rsa(RSA_new()); if (!RSA_set0_key(rsa.get(), n_bn.release(), e_bn.release(), /*d=*/nullptr)) { return nullptr; } bssl::UniquePtr pkey(EVP_PKEY_new()); CHECK(EVP_PKEY_assign_RSA(pkey.get(), rsa.release())); bssl::ScopedCBB cbb; uint8_t* der_bytes = nullptr; size_t der_bytes_len = 0; CHECK(CBB_init(cbb.get(), /* initial size */ 128) && EVP_marshal_public_key(cbb.get(), pkey.get()) && CBB_finish(cbb.get(), &der_bytes, &der_bytes_len)); std::vector der_bytes_vec(der_bytes, der_bytes + der_bytes_len); OPENSSL_free(der_bytes); return std::make_unique(algorithm, cbor_bytes, std::move(der_bytes_vec)); } } // namespace device