CCF
Loading...
Searching...
No Matches
public_key.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
6
7#include <openssl/evp.h>
8#include <stdexcept>
9#include <string>
10
11namespace ccf::crypto
12{
14 {
15 protected:
16 // The key is always owned by the PublicKey_OpenSSL instance
17 // even when passed to the constructor, and is disposed of
18 // by the PublicKey_OpenSSL destructor.
19 EVP_PKEY* key = nullptr;
20
21 public:
22 PublicKey_OpenSSL() = default;
23 PublicKey_OpenSSL(EVP_PKEY* key) : key(key) {}
25 {
26 OpenSSL::Unique_BIO mem(pem);
27 key = PEM_read_bio_PUBKEY(mem, nullptr, nullptr, nullptr);
28 if (key == nullptr)
29 {
30 throw std::runtime_error("could not parse PEM");
31 }
32 }
33
34 PublicKey_OpenSSL(std::span<const uint8_t> der)
35 {
36 OpenSSL::Unique_BIO buf(der);
37 key = d2i_PUBKEY_bio(buf, &key);
38 if (key == nullptr)
39 {
40 throw std::runtime_error("Could not read DER");
41 }
42 }
43
44 void check_is_cose_compatible(int cose_alg)
45 {
46 if (key == nullptr)
47 {
48 throw std::logic_error("Public key is not initialized");
49 }
50
51 const int key_type = EVP_PKEY_get_base_id(key);
52
53 if (key_type == EVP_PKEY_EC)
54 {
55 // Get the curve name
56 size_t gname_len = 0;
57 OpenSSL::CHECK1(EVP_PKEY_get_group_name(key, nullptr, 0, &gname_len));
58 std::string gname(gname_len + 1, '\0');
60 EVP_PKEY_get_group_name(key, gname.data(), gname.size(), &gname_len));
61 gname.resize(gname_len);
62
63 // Map curve to COSE algorithm
64 if (gname == SN_X9_62_prime256v1) // P-256
65 {
66 if (cose_alg != -7)
67 {
68 throw std::domain_error(fmt::format(
69 "secp256r1 key cannot be used with COSE algorithm {}", cose_alg));
70 }
71 }
72 else if (gname == SN_secp384r1) // P-384
73 {
74 if (cose_alg != -35)
75 {
76 throw std::domain_error(fmt::format(
77 "secp384r1 key cannot be used with COSE algorithm {}", cose_alg));
78 }
79 }
80 else if (gname == SN_secp521r1) // P-521
81 {
82 if (cose_alg != -36)
83 {
84 throw std::domain_error(fmt::format(
85 "secp521r1 key cannot be used with COSE algorithm {}", cose_alg));
86 }
87 }
88 else
89 {
90 throw std::domain_error(
91 fmt::format("Unsupported EC curve: {}", gname));
92 }
93 }
94 else if (key_type == EVP_PKEY_RSA || key_type == EVP_PKEY_RSA_PSS)
95 {
96 // It is RECOMMENDED although not required to match hash function and
97 // key sizes, so any of PS256(-37), PS384(-38), and PS512(-39) is
98 // acceptable.
99 //
100 // https://www.iana.org/assignments/cose/cose.xhtml
101 if (cose_alg != -37 && cose_alg != -38 && cose_alg != -39)
102 {
103 throw std::domain_error(
104 fmt::format("Incompatible cose algorithm {} for RSA", cose_alg));
105 }
106 }
107 else
108 {
109 throw std::domain_error(
110 fmt::format("Unsupported key type {}", key_type));
111 }
112 }
113
114 operator EVP_PKEY*() const
115 {
116 return key;
117 }
118
119 [[nodiscard]] std::vector<uint8_t> public_key_der() const
120 {
122 OpenSSL::CHECK1(i2d_PUBKEY_bio(buf, key));
123 BUF_MEM* bptr = nullptr;
124 BIO_get_mem_ptr(buf, &bptr);
125 return {bptr->data, bptr->data + bptr->length};
126 }
127
129 {
130 if (key != nullptr)
131 {
132 EVP_PKEY_free(key);
133 }
134 }
135 };
136}
Definition pem.h:18
Definition public_key.h:14
PublicKey_OpenSSL(const Pem &pem)
Definition public_key.h:24
virtual ~PublicKey_OpenSSL()
Definition public_key.h:128
void check_is_cose_compatible(int cose_alg)
Definition public_key.h:44
PublicKey_OpenSSL(EVP_PKEY *key)
Definition public_key.h:23
PublicKey_OpenSSL(std::span< const uint8_t > der)
Definition public_key.h:34
std::vector< uint8_t > public_key_der() const
Definition public_key.h:119
EVP_PKEY * key
Definition public_key.h:19
void CHECK1(int rc)
Throws if rc is not 1.
Definition openssl_wrappers.h:54
Definition base64.h:11
Definition openssl_wrappers.h:150