#include "device/fido/ed25519_public_key.h"
#include <utility>
#include "base/memory/raw_ptr_exclusion.h"
#include "components/cbor/writer.h"
#include "crypto/evp.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/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 {
std::unique_ptr<PublicKey> Ed25519PublicKey::ExtractFromCOSEKey(
int32_t algorithm,
base::span<const uint8_t> cbor_bytes,
const cbor::Value::MapValue& map) {
struct COSEKey {
RAW_PTR_EXCLUSION const int64_t* kty;
RAW_PTR_EXCLUSION const int64_t* crv;
RAW_PTR_EXCLUSION const std::vector<uint8_t>* key;
} cose_key;
static constexpr cbor_extract::StepOrByte<COSEKey> kSteps[] = {
ELEMENT(Is::kRequired, COSEKey, kty),
IntKey<COSEKey>(static_cast<int>(CoseKeyKey::kKty)),
ELEMENT(Is::kRequired, COSEKey, crv),
IntKey<COSEKey>(static_cast<int>(CoseKeyKey::kEllipticCurve)),
ELEMENT(Is::kRequired, COSEKey, key),
IntKey<COSEKey>(static_cast<int>(CoseKeyKey::kEllipticX)),
Stop<COSEKey>(),
};
if (!cbor_extract::Extract<COSEKey>(&cose_key, kSteps, map) ||
*cose_key.kty != static_cast<int64_t>(CoseKeyTypes::kOKP) ||
*cose_key.crv != static_cast<int64_t>(CoseCurves::kEd25519) ||
cose_key.key->size() != 32) {
return nullptr;
}
bssl::UniquePtr<EVP_PKEY> pkey(
EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, nullptr,
cose_key.key->data(), cose_key.key->size()));
if (!pkey) {
return nullptr;
}
std::vector<uint8_t> der = crypto::evp::PublicKeyToBytes(pkey.get());
return std::make_unique<PublicKey>(algorithm, cbor_bytes, std::move(der));
}
}