CCF
Loading...
Searching...
No Matches
openssl_wrappers.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
5#include "ccf/crypto/pem.h"
6
7#define FMT_HEADER_ONLY
8
10
11#include <chrono>
12#include <fmt/format.h>
13#include <memory>
14#include <openssl/asn1.h>
15#include <openssl/bn.h>
16#include <openssl/ec.h>
17#include <openssl/engine.h>
18#include <openssl/err.h>
19#include <openssl/evp.h>
20#include <openssl/pem.h>
21#include <openssl/rsa.h>
22#include <openssl/ssl.h>
23#include <openssl/x509.h>
24#include <openssl/x509v3.h>
25
27{
28 /*
29 * Generic OpenSSL error handling
30 */
31
33 inline std::string error_string(unsigned long ec)
34 {
35 // ERR_error_string doesn't really expect the code could actually be zero
36 // and uses the `static char buf[256]` which is NOT cleaned nor checked
37 // if it has changed. So we use ERR_error_string_n directly.
38 if (ec != 0u)
39 {
40 constexpr size_t max_error_size = 256;
41 std::string err(max_error_size, '\0');
42 ERR_load_crypto_strings();
43 SSL_load_error_strings();
44 ERR_error_string_n(ec, err.data(), err.size());
45 ERR_free_strings();
46 // Remove any trailing NULs before returning
47 err.resize(std::strlen(err.c_str()));
48 return err;
49 }
50 return "unknown error";
51 }
52
54 inline void CHECK1(int rc)
55 {
56 unsigned long ec = ERR_get_error();
57 if (rc != 1 && ec != 0)
58 {
59 throw std::runtime_error(
60 fmt::format("OpenSSL error: {}", error_string(ec)));
61 }
62 }
63
65 inline void CHECK0(int rc)
66 {
67 unsigned long ec = ERR_get_error();
68 if (rc == 0 && ec != 0)
69 {
70 throw std::runtime_error(
71 fmt::format("OpenSSL error: {}", error_string(ec)));
72 }
73 }
74
76 inline void CHECKNULL(void* ptr)
77 {
78 if (ptr == nullptr)
79 {
80 throw std::runtime_error("OpenSSL error: missing object");
81 }
82 }
83
84 // Throws if values are not equal
85 inline void CHECKEQUAL(int expect, int actual)
86 {
87 if (expect != actual)
88 {
89 unsigned long ec = ERR_get_error();
90 throw std::runtime_error(
91 fmt::format("OpenSSL error: {}", error_string(ec)));
92 }
93 }
94
95 // Throws if value is not positive
96 inline void CHECKPOSITIVE(int val)
97 {
98 if (val <= 0)
99 {
100 throw std::runtime_error("OpenSSL error: expected positive value");
101 }
102 }
103
104 /*
105 * Unique pointer wrappers for SSL objects, with SSL' specific constructors
106 * and destructors. Some objects need special functionality, others are just
107 * wrappers around the same template interface Unique_SSL_OBJECT.
108 */
109
114 template <class T, T* (*CTOR)(), void (*DTOR)(T*)>
116 {
117 protected:
119 std::unique_ptr<T, void (*)(T*)> p;
120
121 public:
123 Unique_SSL_OBJECT() : p(CTOR(), DTOR)
124 {
125 CHECKNULL(p.get());
126 }
128 Unique_SSL_OBJECT(T* ptr, void (*dtor)(T*), bool check_null = true) :
129 p(ptr, dtor)
130 {
131 if (check_null)
132 {
133 CHECKNULL(p.get());
134 }
135 }
137 operator T*()
138 {
139 return p.get();
140 }
142 operator T*() const
143 {
144 return p.get();
145 }
147 void reset(T* other)
148 {
149 p.reset(other);
150 }
153 {
154 return p.release();
155 }
156 };
157
158 struct Unique_BIO : public Unique_SSL_OBJECT<BIO, nullptr, nullptr>
159 {
161 Unique_SSL_OBJECT(BIO_new(BIO_s_mem()), [](auto x) { BIO_free(x); })
162 {}
163 Unique_BIO(const void* buf, int len) :
164 Unique_SSL_OBJECT(BIO_new_mem_buf(buf, len), [](auto x) { BIO_free(x); })
165 {}
166 Unique_BIO(std::span<const uint8_t> s) :
168 BIO_new_mem_buf(s.data(), s.size()), [](auto x) { BIO_free(x); })
169 {}
170 Unique_BIO(const Pem& pem) :
172 BIO_new_mem_buf(pem.data(), -1), [](auto x) { BIO_free(x); })
173 {}
174 Unique_BIO(SSL_CTX* ctx) :
176 BIO_new_ssl_connect(ctx), [](auto x) { BIO_free_all(x); })
177 {}
178 };
179
180 struct Unique_SSL_CTX : public Unique_SSL_OBJECT<SSL_CTX, nullptr, nullptr>
181 {
182 Unique_SSL_CTX(const SSL_METHOD* m) :
183 Unique_SSL_OBJECT(SSL_CTX_new(m), SSL_CTX_free)
184 {}
185 };
186
187 struct Unique_SSL : public Unique_SSL_OBJECT<SSL, nullptr, nullptr>
188 {
189 Unique_SSL(SSL_CTX* ctx) : Unique_SSL_OBJECT(SSL_new(ctx), SSL_free) {}
190 };
191
193 : public Unique_SSL_OBJECT<EVP_PKEY, EVP_PKEY_new, EVP_PKEY_free>
194 {
196 Unique_PKEY(BIO* mem) :
198 PEM_read_bio_PUBKEY(mem, nullptr, nullptr, nullptr), EVP_PKEY_free)
199 {}
200
201 Unique_PKEY(EVP_PKEY* pkey) :
202 Unique_SSL_OBJECT(EVP_PKEY_dup(pkey), EVP_PKEY_free)
203 {}
204 };
205
207 : public Unique_SSL_OBJECT<EVP_PKEY_CTX, nullptr, nullptr>
208 {
209 Unique_EVP_PKEY_CTX(EVP_PKEY* key) :
210 Unique_SSL_OBJECT(EVP_PKEY_CTX_new(key, nullptr), EVP_PKEY_CTX_free)
211 {}
212 Unique_EVP_PKEY_CTX(int key_type = EVP_PKEY_EC) :
214 EVP_PKEY_CTX_new_id(key_type, nullptr), EVP_PKEY_CTX_free)
215 {}
216
217 Unique_EVP_PKEY_CTX(const std::string& name) :
219 EVP_PKEY_CTX_new_from_name(nullptr, name.c_str(), nullptr),
220 EVP_PKEY_CTX_free)
221 {}
222 };
223
225 : public Unique_SSL_OBJECT<EVP_MD_CTX, nullptr, nullptr>
226 {
227 Unique_EVP_MD_CTX() : Unique_SSL_OBJECT(EVP_MD_CTX_new(), EVP_MD_CTX_free)
228 {}
229 };
230
232 : public Unique_SSL_OBJECT<X509_REQ, X509_REQ_new, X509_REQ_free>
233 {
235 Unique_X509_REQ(BIO* mem) :
237 PEM_read_bio_X509_REQ(mem, nullptr, nullptr, nullptr), X509_REQ_free)
238 {}
239 };
240
242 : public Unique_SSL_OBJECT<X509_CRL, X509_CRL_new, X509_CRL_free>
243 {
245 Unique_X509_CRL(BIO* mem) :
247 PEM_read_bio_X509_CRL(mem, nullptr, nullptr, nullptr), X509_CRL_free)
248 {}
249 };
250
251 static const char pem_prefix[] = "-----BEGIN CERTIFICATE-----";
252 // -1 for the null terminator
253 static constexpr size_t pem_prefix_len = sizeof(pem_prefix) - 1;
254
255 // Check BIO starts with PEM prefix before attempting to read it as PEM
256 // because PEM_read_bio_X509 is permissive and will skip over non-PEM data,
257 // which may for example result in a DER containing nested PEM being read
258 // as the nested certificate.
259 inline X509* read_pem(BIO* mem)
260 {
261 std::vector<char> buf(pem_prefix_len);
262 auto read = BIO_read(mem, buf.data(), pem_prefix_len);
263 BIO_reset(mem);
264 if (
265 read != pem_prefix_len || std::memcmp(buf.data(), pem_prefix, read) != 0)
266 {
267 return nullptr;
268 }
269 return PEM_read_bio_X509(mem, nullptr, nullptr, nullptr);
270 };
271
272 struct Unique_X509 : public Unique_SSL_OBJECT<X509, X509_new, X509_free>
273 {
275 // p == nullptr is OK (e.g. wrong format)
276 Unique_X509(BIO* mem, bool pem, bool check_null = false) :
278 pem ? read_pem(mem) : d2i_X509_bio(mem, nullptr), X509_free, check_null)
279 {}
280 Unique_X509(X509* cert, bool check_null) :
281 Unique_SSL_OBJECT(cert, X509_free, check_null)
282 {}
283 };
284
286 : public Unique_SSL_OBJECT<X509_STORE, X509_STORE_new, X509_STORE_free>
287 {
289 };
290
292 X509_STORE_CTX,
293 X509_STORE_CTX_new,
294 X509_STORE_CTX_free>
295 {
297 };
298
300 EVP_CIPHER_CTX,
301 EVP_CIPHER_CTX_new,
302 EVP_CIPHER_CTX_free>
303 {
305 };
306
308 : public Unique_SSL_OBJECT<STACK_OF(X509), nullptr, nullptr>
309 {
312 sk_X509_new_null(), [](auto x) { sk_X509_pop_free(x, X509_free); })
313 {}
314 };
315
317 : public Unique_SSL_OBJECT<STACK_OF(X509_EXTENSION), nullptr, nullptr>
318 {
320 Unique_SSL_OBJECT(sk_X509_EXTENSION_new_null(), [](auto x) {
321 sk_X509_EXTENSION_pop_free(x, X509_EXTENSION_free);
322 })
323 {}
324 Unique_STACK_OF_X509_EXTENSIONS(STACK_OF(X509_EXTENSION) * exts) :
326 exts,
327 [](auto x) { sk_X509_EXTENSION_pop_free(x, X509_EXTENSION_free); },
328 /*check_null=*/false)
329 {}
330 };
331
333 : public Unique_SSL_OBJECT<ECDSA_SIG, ECDSA_SIG_new, ECDSA_SIG_free>
334 {
336 Unique_ECDSA_SIG(ECDSA_SIG* ecdsa_sig) :
337 Unique_SSL_OBJECT(ecdsa_sig, ECDSA_SIG_free)
338 {}
339 };
340
341 struct Unique_BIGNUM : public Unique_SSL_OBJECT<BIGNUM, BN_new, BN_free>
342 {
344
345 Unique_BIGNUM(const BIGNUM* n) : Unique_BIGNUM(BN_dup(n), BN_free) {}
346 };
347
349 : public Unique_SSL_OBJECT<ASN1_TIME, ASN1_TIME_new, ASN1_TIME_free>
350 {
352 Unique_X509_TIME(const std::string& s) :
353 Unique_SSL_OBJECT(ASN1_TIME_new(), ASN1_TIME_free, /*check_null=*/false)
354 {
355 auto t = ccf::ds::to_x509_time_string(s);
356 CHECK1(ASN1_TIME_set_string(*this, t.c_str()));
357 CHECK1(ASN1_TIME_normalize(*this));
358 }
359 Unique_X509_TIME(ASN1_TIME* t) :
360 Unique_SSL_OBJECT(t, ASN1_TIME_free, /*check_null=*/false)
361 {}
362 Unique_X509_TIME(const std::chrono::system_clock::time_point& t) :
363 Unique_X509_TIME(ccf::ds::to_x509_time_string(t))
364 {}
365 };
366
368 : public Unique_SSL_OBJECT<BN_CTX, BN_CTX_new, BN_CTX_free>
369 {
371 };
372
373 struct Unique_EC_GROUP : public Unique_SSL_OBJECT<EC_GROUP, nullptr, nullptr>
374 {
377 EC_GROUP_new_by_curve_name(nid), EC_GROUP_free, /*check_null=*/true)
378 {}
379 };
380
381 struct Unique_EC_POINT : public Unique_SSL_OBJECT<EC_POINT, nullptr, nullptr>
382 {
383 Unique_EC_POINT(const EC_GROUP* group) :
384 Unique_SSL_OBJECT(EC_POINT_new(group), EC_POINT_free, /*check_null=*/true)
385 {}
386 Unique_EC_POINT(EC_POINT* point) :
387 Unique_SSL_OBJECT(point, EC_POINT_free, /*check_null=*/true)
388 {}
389 };
390
392 EVP_ENCODE_CTX,
393 EVP_ENCODE_CTX_new,
394 EVP_ENCODE_CTX_free>
395 {
397 };
398
400 : public Unique_SSL_OBJECT<EVP_PKEY, EVP_PKEY_new, EVP_PKEY_free>
401 {
402 Unique_EVP_PKEY() = default;
403 Unique_EVP_PKEY(EVP_PKEY* key) : Unique_SSL_OBJECT(key, EVP_PKEY_free) {}
404 };
405
407 : public Unique_SSL_OBJECT<X509_REQ, X509_REQ_new, X509_REQ_free>
408 {
411 d2i_X509_REQ_bio(mem, nullptr), X509_REQ_free)
412 {}
413 };
414}
Definition openssl_wrappers.h:116
std::unique_ptr< T, void(*)(T *)> p
Pointer owning storage.
Definition openssl_wrappers.h:119
T * release()
Release pointer, so it's freed elsewhere (CAUTION!)
Definition openssl_wrappers.h:152
Unique_SSL_OBJECT(T *ptr, void(*dtor)(T *), bool check_null=true)
C-tor with pointer created in base class.
Definition openssl_wrappers.h:128
void reset(T *other)
Reset pointer, free old if any.
Definition openssl_wrappers.h:147
Unique_SSL_OBJECT()
C-tor with new pointer via T's c-tor.
Definition openssl_wrappers.h:123
Definition pem.h:18
Definition openssl_wrappers.h:27
void CHECKNULL(void *ptr)
Throws if ptr is null.
Definition openssl_wrappers.h:76
void CHECK0(int rc)
Throws if rc is 0 and has error.
Definition openssl_wrappers.h:65
void CHECKEQUAL(int expect, int actual)
Definition openssl_wrappers.h:85
std::string error_string(unsigned long ec)
Returns the error string from an error code.
Definition openssl_wrappers.h:33
X509 * read_pem(BIO *mem)
Definition openssl_wrappers.h:259
void CHECK1(int rc)
Throws if rc is not 1 and has error.
Definition openssl_wrappers.h:54
void CHECKPOSITIVE(int val)
Definition openssl_wrappers.h:96
Definition app_interface.h:14
Definition dl_list.h:9
Definition openssl_wrappers.h:342
Unique_BIGNUM(const BIGNUM *n)
Definition openssl_wrappers.h:345
Definition openssl_wrappers.h:159
Unique_BIO(const void *buf, int len)
Definition openssl_wrappers.h:163
Unique_BIO(const Pem &pem)
Definition openssl_wrappers.h:170
Unique_BIO(std::span< const uint8_t > s)
Definition openssl_wrappers.h:166
Unique_BIO()
Definition openssl_wrappers.h:160
Unique_BIO(SSL_CTX *ctx)
Definition openssl_wrappers.h:174
Definition openssl_wrappers.h:369
Definition openssl_wrappers.h:334
Unique_ECDSA_SIG(ECDSA_SIG *ecdsa_sig)
Definition openssl_wrappers.h:336
Definition openssl_wrappers.h:374
Unique_EC_GROUP(int nid)
Definition openssl_wrappers.h:375
Definition openssl_wrappers.h:382
Unique_EC_POINT(EC_POINT *point)
Definition openssl_wrappers.h:386
Unique_EC_POINT(const EC_GROUP *group)
Definition openssl_wrappers.h:383
Definition openssl_wrappers.h:303
Definition openssl_wrappers.h:395
Definition openssl_wrappers.h:226
Unique_EVP_MD_CTX()
Definition openssl_wrappers.h:227
Definition openssl_wrappers.h:208
Unique_EVP_PKEY_CTX(const std::string &name)
Definition openssl_wrappers.h:217
Unique_EVP_PKEY_CTX(int key_type=EVP_PKEY_EC)
Definition openssl_wrappers.h:212
Unique_EVP_PKEY_CTX(EVP_PKEY *key)
Definition openssl_wrappers.h:209
Definition openssl_wrappers.h:401
Unique_EVP_PKEY(EVP_PKEY *key)
Definition openssl_wrappers.h:403
Definition openssl_wrappers.h:194
Unique_PKEY(BIO *mem)
Definition openssl_wrappers.h:196
Unique_PKEY(EVP_PKEY *pkey)
Definition openssl_wrappers.h:201
Definition openssl_wrappers.h:181
Unique_SSL_CTX(const SSL_METHOD *m)
Definition openssl_wrappers.h:182
Definition openssl_wrappers.h:188
Unique_SSL(SSL_CTX *ctx)
Definition openssl_wrappers.h:189
Unique_STACK_OF_X509_EXTENSIONS()
Definition openssl_wrappers.h:319
Unique_STACK_OF_X509_EXTENSIONS(STACK_OF(X509_EXTENSION) *exts)
Definition openssl_wrappers.h:324
Definition openssl_wrappers.h:309
Unique_STACK_OF_X509()
Definition openssl_wrappers.h:310
Definition openssl_wrappers.h:243
Unique_X509_CRL(BIO *mem)
Definition openssl_wrappers.h:245
Definition openssl_wrappers.h:408
Unique_X509_REQ_DER(BIO *mem)
Definition openssl_wrappers.h:409
Definition openssl_wrappers.h:233
Unique_X509_REQ(BIO *mem)
Definition openssl_wrappers.h:235
Definition openssl_wrappers.h:295
Definition openssl_wrappers.h:287
Definition openssl_wrappers.h:350
Unique_X509_TIME(ASN1_TIME *t)
Definition openssl_wrappers.h:359
Unique_X509_TIME(const std::string &s)
Definition openssl_wrappers.h:352
Unique_X509_TIME(const std::chrono::system_clock::time_point &t)
Definition openssl_wrappers.h:362
Definition openssl_wrappers.h:273
Unique_X509(BIO *mem, bool pem, bool check_null=false)
Definition openssl_wrappers.h:276
Unique_X509(X509 *cert, bool check_null)
Definition openssl_wrappers.h:280