Botan 3.12.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 value.decode(data->m_extensions).verify_end();
140 }
141 }
142 attributes.verify_end();
143 } else if(attr_bits.is_set()) {
144 throw BER_Bad_Tag("PKCS10_Request: Unexpected tag for attributes", attr_bits.tagging());
145 }
146
147 cert_req_info.verify_end();
148
149 if(const auto* ext = data->m_extensions.get_extension_object_as<Cert_Extension::Subject_Alternative_Name>()) {
150 data->m_alt_name = ext->get_alt_name();
151 }
152
153 for(const auto& email : pkcs9_email) {
154 data->m_alt_name.add_email(email);
155 }
156
157 return data;
158}
159
160} // namespace
161
162void PKCS10_Request::force_decode() {
163 m_data.reset();
164
165 m_data = decode_pkcs10(signed_body());
166
167 auto key = this->subject_public_key();
168 if(!this->check_signature(*key)) {
169 throw Decoding_Error("PKCS #10 request: Bad signature detected");
170 }
171}
172
173const PKCS10_Data& PKCS10_Request::data() const {
174 if(m_data == nullptr) {
175 throw Decoding_Error("PKCS10_Request decoding failed");
176 }
177 return *m_data;
178}
179
180/*
181* Return the challenge password (if any)
182*/
184 return data().m_challenge;
185}
186
187/*
188* Return the name of the requestor
189*/
191 return data().m_subject_dn;
192}
193
194/*
195* Return the public key of the requestor
196*/
197const std::vector<uint8_t>& PKCS10_Request::raw_public_key() const {
198 return data().m_public_key_bits;
199}
200
201/*
202* Return the public key of the requestor
203*/
204std::unique_ptr<Public_Key> PKCS10_Request::subject_public_key() const {
206 return X509::load_key(source);
207}
208
209/*
210* Return the alternative names of the requestor
211*/
213 return data().m_alt_name;
214}
215
216/*
217* Return the X509v3 extensions
218*/
220 return data().m_extensions;
221}
222
223/*
224* Return the key constraints (if any)
225*/
227 if(const auto* ext = extensions().get_extension_object_as<Cert_Extension::Key_Usage>()) {
228 return ext->get_constraints();
229 } else {
231 }
232}
233
234/*
235* Return the extendend key constraints (if any)
236*/
237std::vector<OID> PKCS10_Request::ex_constraints() const {
238 if(const auto* ext = extensions().get_extension_object_as<Cert_Extension::Extended_Key_Usage>()) {
239 return ext->object_identifiers();
240 } else {
241 return {};
242 }
243}
244
245/*
246* Return is a CA certificate is requested
247*/
249 if(const auto* ext = extensions().get_extension_object_as<Cert_Extension::Basic_Constraints>()) {
250 return ext->is_ca();
251 } else {
252 return false;
253 }
254}
255
256/*
257* Return the requested path limit
258*/
259std::optional<size_t> PKCS10_Request::path_length_constraint() const {
260 if(const auto* ext = extensions().get_extension_object_as<Cert_Extension::Basic_Constraints>()) {
261 if(ext->is_ca()) {
262 return ext->path_length_constraint();
263 }
264 }
265
266 return std::nullopt;
267}
268
269} // namespace Botan
const std::string & value() const
Definition asn1_obj.h:365
static Limits DER()
Definition ber_dec.h:35
DER_Encoder & end_explicit()
Definition der_enc.cpp:195
DER_Encoder & start_explicit(uint16_t type_tag)
Definition der_enc.cpp:188
DER_Encoder & start_sequence()
Definition der_enc.h:67
DER_Encoder & raw_bytes(const uint8_t val[], size_t len)
Definition der_enc.cpp:202
DER_Encoder & end_cons()
Definition der_enc.cpp:173
std::vector< uint8_t > get_contents_unlocked()
Definition der_enc.cpp:148
DER_Encoder & encode(bool b)
Definition der_enc.cpp:245
static OID from_string(std::string_view str)
Definition asn1_oid.cpp:86
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:204
const X509_DN & subject_dn() const
Definition pkcs10.cpp:190
std::vector< OID > ex_constraints() const
Definition pkcs10.cpp:237
const std::vector< uint8_t > & raw_public_key() const
Definition pkcs10.cpp:197
Key_Constraints constraints() const
Definition pkcs10.cpp:226
bool is_CA() const
Definition pkcs10.cpp:248
const AlternativeName & subject_alt_name() const
Definition pkcs10.cpp:212
std::optional< size_t > path_length_constraint() const
Definition pkcs10.cpp:259
const Extensions & extensions() const
Definition pkcs10.cpp:219
std::string challenge_password() const
Definition pkcs10.cpp:183
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:237
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:153
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:177
std::unique_ptr< Public_Key > load_key(DataSource &source)
Definition x509_key.cpp:28