blob: e31a7ed4b0d003a2948b7bc67ff52d8ce6f328c6 [file]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "crypto/cose.h"
#include <vector>
#include "base/check_op.h"
#include "base/notreached.h"
#include "components/cbor/values.h"
#include "components/cbor/writer.h"
#include "third_party/boringssl/src/include/openssl/base.h"
#include "third_party/boringssl/src/include/openssl/bn.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "third_party/boringssl/src/include/openssl/rsa.h"
namespace crypto {
namespace {
constexpr size_t kEcP256FieldElementLength = 32;
// Enumerates the keys in a COSE Key structure. See
// https://tools.ietf.org/html/rfc8152#section-7.1
enum class CoseKeyKey : int {
kAlg = 3,
kKty = 1,
kRSAModulus = -1,
kRSAPublicExponent = -2,
kEllipticCurve = -1,
kEllipticX = -2,
kEllipticY = -3,
};
// Enumerates COSE key types. See
// https://tools.ietf.org/html/rfc8152#section-13
enum class CoseKeyTypes : int {
kOKP = 1,
kEC2 = 2,
kRSA = 3,
};
// Enumerates COSE elliptic curves. See
// https://tools.ietf.org/html/rfc8152#section-13.1
enum class CoseCurves : int {
kP256 = 1,
kEd25519 = 6,
};
enum class CoseAlgorithmIdentifier : int {
kEs256 = -7,
kEdDSA = -8,
kRs256 = -257,
};
std::vector<uint8_t> RsaToCoseKey(const EVP_PKEY* key) {
// Extract the RSA key and its components (n and e).
const RSA* rsa_key = EVP_PKEY_get0_RSA(key);
CHECK(rsa_key);
const BIGNUM* n = RSA_get0_n(rsa_key); // modulus
const BIGNUM* e = RSA_get0_e(rsa_key); // public exponent
CHECK(n && e);
// Convert BIGNUM components to byte vectors.
std::vector<uint8_t> n_bytes(BN_num_bytes(n));
BN_bn2bin(n, n_bytes.data());
std::vector<uint8_t> e_bytes(BN_num_bytes(e));
BN_bn2bin(e, e_bytes.data());
// Construct the COSE_Key CBOR Map.
cbor::Value::MapValue map;
map.emplace(static_cast<int64_t>(CoseKeyKey::kAlg),
static_cast<int64_t>(CoseAlgorithmIdentifier::kRs256));
map.emplace(static_cast<int64_t>(CoseKeyKey::kKty),
static_cast<int64_t>(CoseKeyTypes::kRSA));
map.emplace(static_cast<int64_t>(CoseKeyKey::kRSAModulus),
std::move(n_bytes));
map.emplace(static_cast<int64_t>(CoseKeyKey::kRSAPublicExponent),
std::move(e_bytes));
std::optional<std::vector<uint8_t>> cbor_bytes =
cbor::Writer::Write(cbor::Value(std::move(map)));
CHECK(cbor_bytes);
return cbor_bytes.value();
}
std::vector<uint8_t> EcP256ToCoseKey(const keypair::PublicKey& key) {
// COSE's non-standard public key encoding is the x and y halves of the
// standard X9.62 uncompressed encoding: 04 || x || y.
std::vector<uint8_t> uncompressed = key.ToUncompressedX962Point();
CHECK_EQ(uncompressed.size(), 1 + 2 * kEcP256FieldElementLength);
auto [x, y] =
base::span(uncompressed).subspan(1u).split_at(kEcP256FieldElementLength);
cbor::Value::MapValue map;
map.emplace(static_cast<int64_t>(CoseKeyKey::kKty),
static_cast<int64_t>(CoseKeyTypes::kEC2));
map.emplace(static_cast<int64_t>(CoseKeyKey::kAlg),
static_cast<int64_t>(CoseAlgorithmIdentifier::kEs256));
map.emplace(static_cast<int64_t>(CoseKeyKey::kEllipticCurve),
static_cast<int64_t>(CoseCurves::kP256));
map.emplace(static_cast<int64_t>(CoseKeyKey::kEllipticX), std::move(x));
map.emplace(static_cast<int64_t>(CoseKeyKey::kEllipticY), std::move(y));
std::optional<std::vector<uint8_t>> cbor_bytes =
cbor::Writer::Write(cbor::Value(std::move(map)));
CHECK(cbor_bytes);
return cbor_bytes.value();
}
} // namespace
std::vector<uint8_t> PublicKeyToCoseKey(const keypair::PublicKey& key) {
if (key.IsRsa()) {
return RsaToCoseKey(key.key());
} else if (key.IsEcP256()) {
return EcP256ToCoseKey(key);
}
NOTREACHED();
}
} // namespace crypto