Botan 3.13.0
Crypto and TLS for C&
pkcs10.cpp
Go to the documentation of this file.
1/*
2* PKCS #10
3* (C) 1999-2007,2017 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/pkcs10.h>
9
10#include <botan/ber_dec.h>
11#include <botan/der_enc.h>
12#include <botan/pem.h>
13#include <botan/pubkey.h>
14#include <botan/x509_ext.h>
15#include <botan/x509_key.h>
16#include <botan/x509cert.h>
17
18namespace Botan {
19
20class PKCS10_Data final {
21 public:
22 X509_DN m_subject_dn;
23 std::vector<uint8_t> m_public_key_bits;
24 AlternativeName m_alt_name;
25 std::string m_challenge;
26 Extensions m_extensions;
27};
28
29std::string PKCS10_Request::PEM_label() const {
30 return "CERTIFICATE REQUEST";
31}
32
33std::vector<std::string> PKCS10_Request::alternate_PEM_labels() const {
34 return {"NEW CERTIFICATE REQUEST"};
35}
36
40
41PKCS10_Request::PKCS10_Request(const std::vector<uint8_t>& vec) {
42 DataSource_Memory src(vec.data(), vec.size());
43 load_data(src);
44}
45
46#if defined(BOTAN_TARGET_OS_HAS_FILESYSTEM)
47PKCS10_Request::PKCS10_Request(std::string_view fsname) {
48 DataSource_Stream src(fsname, true);
49 load_data(src);
50}
51#endif
52
53//static
55 const X509_DN& subject_dn,
57 std::string_view hash_fn,
59 std::string_view padding_scheme,
60 std::string_view challenge) {
61 auto signer = choose_sig_format(key, rng, hash_fn, padding_scheme);
62 const AlgorithmIdentifier sig_algo = signer->algorithm_identifier();
63
64 const size_t PKCS10_VERSION = 0;
65
66 DER_Encoder tbs_req;
67
68 tbs_req.start_sequence()
69 .encode(PKCS10_VERSION)
73
74 if(!challenge.empty()) {
75 std::vector<uint8_t> value;
76 DER_Encoder(value).encode(ASN1_String(challenge));
77 tbs_req.encode(Attribute("PKCS9.ChallengePassword", value));
78 }
79
80 std::vector<uint8_t> extension_req;
82 tbs_req.encode(Attribute("PKCS9.ExtensionRequest", extension_req));
83
84 // end the start_explicit above
85 tbs_req.end_explicit().end_cons();
86
87 const std::vector<uint8_t> req = X509_Object::make_signed(*signer, rng, sig_algo, tbs_req.get_contents_unlocked());
88
89 return PKCS10_Request(req);
90}
91
92/*
93* Decode the CertificateRequestInfo
94*/
95namespace {
96
97std::unique_ptr<PKCS10_Data> decode_pkcs10(const std::vector<uint8_t>& body) {
98 auto data = std::make_unique<PKCS10_Data>();
99
100 BER_Decoder cert_req_info(body, BER_Decoder::Limits::DER());
101
102 size_t version = 0;
103 cert_req_info.decode(version);
104 if(version != 0) {
105 throw Decoding_Error("Unknown version code in PKCS #10 request: " + std::to_string(version));
106 }
107
108 cert_req_info.decode(data->m_subject_dn);
109
110 const BER_Object public_key = cert_req_info.get_next_object();
111 if(!public_key.is_a(ASN1_Type::Sequence, ASN1_Class::Constructed)) {
112 throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for public key", public_key.tagging());
113 }
114
115 data->m_public_key_bits = ASN1::put_in_sequence(public_key.bits(), public_key.length());
116
117 const BER_Object attr_bits = cert_req_info.get_next_object();
118
119 std::set<std::string> pkcs9_email;
120
122 BER_Decoder attributes(attr_bits, cert_req_info.limits());
123 while(attributes.more_items()) {
124 Attribute attr;
125 attributes.decode(attr);
126
127 const OID& oid = attr.object_identifier();
128 BER_Decoder value(attr.get_parameters(), cert_req_info.limits());
129
130 if(oid == OID::from_string("PKCS9.EmailAddress")) {
131 ASN1_String email;
132 value.decode(email);
133 pkcs9_email.insert(email.value());
134 } else if(oid == OID::from_string("PKCS9.ChallengePassword")) {
135 ASN1_String challenge_password;
136 value.decode(challenge_password);
137 data->m_challenge = challenge_password.value();
138 } else if(oid == OID::from_string("PKCS9.ExtensionRequest")) {
139 data->m_extensions.decode_from(value, Extension_Context::Certificate);
140 value.verify_end();
141 }
142 }
143 attributes.verify_end();
144 } else if(attr_bits.is_set()) {
145 throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes", attr_bits.tagging());
146 }
147
148 cert_req_info.verify_end();
149
150 if(const auto* ext = data->m_extensions.get_extension_object_as<Cert_Extension::Subject_Alternative_Name>()) {
151 data->m_alt_name = ext->get_alt_name();
152 }
153
154 for(const auto& email : pkcs9_email) {
155 data->m_alt_name.add_email(email);
156 }
157
158 return data;
159}
160
161} // namespace
162
163void PKCS10_Request::force_decode() {
164 m_data.reset();
165
166 m_data = decode_pkcs10(signed_body());
167
168 auto key = this->subject_public_key();
169 if(!this->check_signature(*key)) {
170 throw Decoding_Error("PKCS #10 request: Bad signature detected");
171 }
172}
173
174const PKCS10_Data& PKCS10_Request::data() const {
175 if(m_data == nullptr) {
176 throw Decoding_Error("PKCS10_Request decoding failed");
177 }
178 return *m_data;
179}
180
181/*
182* Return the challenge password (if any)
183*/
185 return data().m_challenge;
186}
187
188/*
189* Return the name of the requestor
190*/
192 return data().m_subject_dn;
193}
194
195/*
196* Return the public key of the requestor
197*/
198const std::vector<uint8_t>& PKCS10_Request::raw_public_key() const {
199 return data().m_public_key_bits;
200}
201
202/*
203* Return the public key of the requestor
204*/
205std::unique_ptr<Public_Key> PKCS10_Request::subject_public_key() const {
207 return X509::load_key(source);
208}
209
210/*
211* Return the alternative names of the requestor
212*/
214 return data().m_alt_name;
215}
216
217/*
218* Return the X509v3 extensions
219*/
221 return data().m_extensions;
222}
223
224/*
225* Return the key constraints (if any)
226*/
228 if(const auto* ext = extensions().get_extension_object_as<Cert_Extension::Key_Usage>()) {
229 return ext->get_constraints();
230 } else {
232 }
233}
234
235/*
236* Return the extendend key constraints (if any)
237*/
238std::vector<OID> PKCS10_Request::ex_constraints() const {
239 if(const auto* ext = extensions().get_extension_object_as<Cert_Extension::Extended_Key_Usage>()) {
240 return ext->object_identifiers();
241 } else {
242 return {};
243 }
244}
245
246/*
247* Return is a CA certificate is requested
248*/
250 if(const auto* ext = extensions().get_extension_object_as<Cert_Extension::Basic_Constraints>()) {
251 return ext->is_ca();
252 } else {
253 return false;
254 }
255}
256
257/*
258* Return the requested path limit
259*/
260std::optional<size_t> PKCS10_Request::path_length_constraint() const {
261 if(const auto* ext = extensions().get_extension_object_as<Cert_Extension::Basic_Constraints>()) {
262 if(ext->is_ca()) {
263 return ext->path_length_constraint();
264 }
265 }
266
267 return std::nullopt;
268}
269
270} // namespace Botan
const std::string & value() const
Definition asn1_obj.h:590
static Limits DER()
Definition ber_dec.h:42
DER_Encoder & end_explicit()
Definition der_enc.cpp:230
DER_Encoder & start_explicit(uint16_t type_tag)
Definition der_enc.cpp:223
DER_Encoder & start_sequence()
Definition der_enc.h:86
DER_Encoder & raw_bytes(const uint8_t val[], size_t len)
Definition der_enc.cpp:237
DER_Encoder & end_cons()
Definition der_enc.cpp:208
std::vector< uint8_t > get_contents_unlocked()
Definition der_enc.cpp:175
DER_Encoder & encode(bool b)
Definition der_enc.cpp:313
static OID from_string(std::string_view str)
Definition asn1_oid.cpp:80
PKCS10_Request(DataSource &source)
Definition pkcs10.cpp:37
static PKCS10_Request create(const Private_Key &key, const X509_DN &subject_dn, const Extensions &extensions, std::string_view hash_fn, RandomNumberGenerator &rng, std::string_view padding_scheme="", std::string_view challenge="")
Definition pkcs10.cpp:54
std::unique_ptr< Public_Key > subject_public_key() const
Definition pkcs10.cpp:205
const X509_DN & subject_dn() const
Definition pkcs10.cpp:191
std::vector< OID > ex_constraints() const
Definition pkcs10.cpp:238
const std::vector< uint8_t > & raw_public_key() const
Definition pkcs10.cpp:198
Key_Constraints constraints() const
Definition pkcs10.cpp:227
bool is_CA() const
Definition pkcs10.cpp:249
const AlternativeName & subject_alt_name() const
Definition pkcs10.cpp:213
std::optional< size_t > path_length_constraint() const
Definition pkcs10.cpp:260
const Extensions & extensions() const
Definition pkcs10.cpp:220
std::string challenge_password() const
Definition pkcs10.cpp:184
std::vector< uint8_t > subject_public_key() const
Definition pk_keys.cpp:63
const std::vector< uint8_t > & signed_body() const
Definition x509_obj.cpp:66
virtual std::vector< std::string > alternate_PEM_labels() const
Definition x509_obj.h:102
static std::unique_ptr< PK_Signer > choose_sig_format(const Private_Key &key, RandomNumberGenerator &rng, std::string_view hash_fn, std::string_view padding_algo)
Definition x509_obj.cpp:240
static std::vector< uint8_t > make_signed(PK_Signer &signer, RandomNumberGenerator &rng, const AlgorithmIdentifier &alg_id, std::span< const uint8_t > tbs)
Definition x509_obj.cpp:156
void load_data(DataSource &src)
Definition x509_obj.cpp:24
virtual std::string PEM_label() const =0
bool check_signature(const Public_Key &key) const
Definition x509_obj.cpp:125
std::vector< uint8_t > put_in_sequence(const std::vector< uint8_t > &contents)
Definition asn1_obj.cpp:208
std::unique_ptr< Public_Key > load_key(DataSource &source)
Definition x509_key.cpp:28