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 if (rc != 1)
57 {
58 unsigned long ec = ERR_get_error();
59 throw std::runtime_error(fmt::format(
60 "OpenSSL error (rc={}, ec={}): {}", rc, ec, error_string(ec)));
61 }
62 }
63
65 inline void CHECKNULL(void* ptr)
66 {
67 if (ptr == nullptr)
68 {
69 throw std::runtime_error("OpenSSL error: missing object");
70 }
71 }
72
73 // Throws if values are not equal
74 inline void CHECKEQUAL(int expect, int actual)
75 {
76 if (expect != actual)
77 {
78 unsigned long ec = ERR_get_error();
79 throw std::runtime_error(fmt::format(
80 "OpenSSL error (rc={}, ec={}): {}", actual, ec, error_string(ec)));
81 }
82 }
83
84 // Throws if value is not positive
85 inline void CHECKPOSITIVE(int val)
86 {
87 if (val <= 0)
88 {
89 unsigned long ec = ERR_get_error();
90 throw std::runtime_error(fmt::format(
91 "OpenSSL error (rc={}, ec={}): {}", val, ec, error_string(ec)));
92 }
93 }
94
95 /*
96 * Unique pointer wrappers for SSL objects, with SSL' specific constructors
97 * and destructors. Some objects need special functionality, others are just
98 * wrappers around the same template interface Unique_SSL_OBJECT.
99 */
100
105 template <class T, T* (*CTOR)(), void (*DTOR)(T*)>
107 {
108 protected:
110 std::unique_ptr<T, void (*)(T*)> p;
111
112 public:
114 Unique_SSL_OBJECT() : p(CTOR(), DTOR)
115 {
116 CHECKNULL(p.get());
117 }
119 Unique_SSL_OBJECT(T* ptr, void (*dtor)(T*), bool check_null = true) :
120 p(ptr, dtor)
121 {
122 if (check_null)
123 {
124 CHECKNULL(p.get());
125 }
126 }
128 operator T*()
129 {
130 return p.get();
131 }
133 operator T*() const
134 {
135 return p.get();
136 }
138 void reset(T* other)
139 {
140 p.reset(other);
141 }
144 {
145 return p.release();
146 }
147 };
148
149 struct Unique_BIO : public Unique_SSL_OBJECT<BIO, nullptr, nullptr>
150 {
152 Unique_SSL_OBJECT(BIO_new(BIO_s_mem()), [](auto x) { BIO_free(x); })
153 {}
154 Unique_BIO(const void* buf, int len) :
155 Unique_SSL_OBJECT(BIO_new_mem_buf(buf, len), [](auto x) { BIO_free(x); })
156 {}
157 Unique_BIO(std::span<const uint8_t> s) :
159 BIO_new_mem_buf(s.data(), s.size()), [](auto x) { BIO_free(x); })
160 {}
161 Unique_BIO(const Pem& pem) :
163 BIO_new_mem_buf(pem.data(), -1), [](auto x) { BIO_free(x); })
164 {}
165 Unique_BIO(SSL_CTX* ctx) :
167 BIO_new_ssl_connect(ctx), [](auto x) { BIO_free_all(x); })
168 {}
169 };
170
171 struct Unique_SSL_CTX : public Unique_SSL_OBJECT<SSL_CTX, nullptr, nullptr>
172 {
173 Unique_SSL_CTX(const SSL_METHOD* m) :
174 Unique_SSL_OBJECT(SSL_CTX_new(m), SSL_CTX_free)
175 {}
176 };
177
178 struct Unique_SSL : public Unique_SSL_OBJECT<SSL, nullptr, nullptr>
179 {
180 Unique_SSL(SSL_CTX* ctx) : Unique_SSL_OBJECT(SSL_new(ctx), SSL_free) {}
181 };
182
184 : public Unique_SSL_OBJECT<EVP_PKEY, EVP_PKEY_new, EVP_PKEY_free>
185 {
187 Unique_PKEY(BIO* mem) :
189 PEM_read_bio_PUBKEY(mem, nullptr, nullptr, nullptr), EVP_PKEY_free)
190 {}
191
192 Unique_PKEY(EVP_PKEY* pkey) :
193 Unique_SSL_OBJECT(EVP_PKEY_dup(pkey), EVP_PKEY_free)
194 {}
195 };
196
198 : public Unique_SSL_OBJECT<EVP_PKEY_CTX, nullptr, nullptr>
199 {
200 Unique_EVP_PKEY_CTX(EVP_PKEY* key) :
201 Unique_SSL_OBJECT(EVP_PKEY_CTX_new(key, nullptr), EVP_PKEY_CTX_free)
202 {}
203 Unique_EVP_PKEY_CTX(int key_type = EVP_PKEY_EC) :
205 EVP_PKEY_CTX_new_id(key_type, nullptr), EVP_PKEY_CTX_free)
206 {}
207
208 Unique_EVP_PKEY_CTX(const std::string& name) :
210 EVP_PKEY_CTX_new_from_name(nullptr, name.c_str(), nullptr),
211 EVP_PKEY_CTX_free)
212 {}
213 };
214
216 : public Unique_SSL_OBJECT<EVP_MD_CTX, nullptr, nullptr>
217 {
218 Unique_EVP_MD_CTX() : Unique_SSL_OBJECT(EVP_MD_CTX_new(), EVP_MD_CTX_free)
219 {}
220 };
221
223 : public Unique_SSL_OBJECT<X509_REQ, X509_REQ_new, X509_REQ_free>
224 {
226 Unique_X509_REQ(BIO* mem) :
228 PEM_read_bio_X509_REQ(mem, nullptr, nullptr, nullptr), X509_REQ_free)
229 {}
230 };
231
233 : public Unique_SSL_OBJECT<X509_CRL, X509_CRL_new, X509_CRL_free>
234 {
236 Unique_X509_CRL(BIO* mem) :
238 PEM_read_bio_X509_CRL(mem, nullptr, nullptr, nullptr), X509_CRL_free)
239 {}
240 };
241
242 static const char pem_prefix[] = "-----BEGIN CERTIFICATE-----";
243 // -1 for the null terminator
244 static constexpr size_t pem_prefix_len = sizeof(pem_prefix) - 1;
245
246 // Check BIO starts with PEM prefix before attempting to read it as PEM
247 // because PEM_read_bio_X509 is permissive and will skip over non-PEM data,
248 // which may for example result in a DER containing nested PEM being read
249 // as the nested certificate.
250 inline X509* read_pem(BIO* mem)
251 {
252 std::vector<char> buf(pem_prefix_len);
253 auto read = BIO_read(mem, buf.data(), pem_prefix_len);
254 BIO_reset(mem);
255 if (
256 read != pem_prefix_len || std::memcmp(buf.data(), pem_prefix, read) != 0)
257 {
258 return nullptr;
259 }
260 return PEM_read_bio_X509(mem, nullptr, nullptr, nullptr);
261 };
262
263 struct Unique_X509 : public Unique_SSL_OBJECT<X509, X509_new, X509_free>
264 {
266 // p == nullptr is OK (e.g. wrong format)
267 Unique_X509(BIO* mem, bool pem, bool check_null = false) :
269 pem ? read_pem(mem) : d2i_X509_bio(mem, nullptr), X509_free, check_null)
270 {}
271 Unique_X509(X509* cert, bool check_null) :
272 Unique_SSL_OBJECT(cert, X509_free, check_null)
273 {}
274 };
275
277 : public Unique_SSL_OBJECT<X509_STORE, X509_STORE_new, X509_STORE_free>
278 {
280 };
281
283 X509_STORE_CTX,
284 X509_STORE_CTX_new,
285 X509_STORE_CTX_free>
286 {
288 };
289
291 EVP_CIPHER_CTX,
292 EVP_CIPHER_CTX_new,
293 EVP_CIPHER_CTX_free>
294 {
296 };
297
299 : public Unique_SSL_OBJECT<STACK_OF(X509), nullptr, nullptr>
300 {
303 sk_X509_new_null(), [](auto x) { sk_X509_pop_free(x, X509_free); })
304 {}
305 };
306
308 : public Unique_SSL_OBJECT<STACK_OF(X509_EXTENSION), nullptr, nullptr>
309 {
311 Unique_SSL_OBJECT(sk_X509_EXTENSION_new_null(), [](auto x) {
312 sk_X509_EXTENSION_pop_free(x, X509_EXTENSION_free);
313 })
314 {}
315 Unique_STACK_OF_X509_EXTENSIONS(STACK_OF(X509_EXTENSION) * exts) :
317 exts,
318 [](auto x) { sk_X509_EXTENSION_pop_free(x, X509_EXTENSION_free); },
319 /*check_null=*/false)
320 {}
321 };
322
324 : public Unique_SSL_OBJECT<ECDSA_SIG, ECDSA_SIG_new, ECDSA_SIG_free>
325 {
327 Unique_ECDSA_SIG(ECDSA_SIG* ecdsa_sig) :
328 Unique_SSL_OBJECT(ecdsa_sig, ECDSA_SIG_free)
329 {}
330 };
331
332 struct Unique_BIGNUM : public Unique_SSL_OBJECT<BIGNUM, BN_new, BN_free>
333 {
335
336 Unique_BIGNUM(const BIGNUM* n) : Unique_BIGNUM(BN_dup(n), BN_free) {}
337 };
338
340 : public Unique_SSL_OBJECT<ASN1_TIME, ASN1_TIME_new, ASN1_TIME_free>
341 {
343 Unique_X509_TIME(const std::string& s) :
344 Unique_SSL_OBJECT(ASN1_TIME_new(), ASN1_TIME_free, /*check_null=*/false)
345 {
346 auto t = ccf::ds::to_x509_time_string(s);
347 CHECK1(ASN1_TIME_set_string(*this, t.c_str()));
348 CHECK1(ASN1_TIME_normalize(*this));
349 }
350 Unique_X509_TIME(ASN1_TIME* t) :
351 Unique_SSL_OBJECT(t, ASN1_TIME_free, /*check_null=*/false)
352 {}
354 Unique_X509_TIME(ccf::ds::to_x509_time_string(t))
355 {}
356 };
357
359 : public Unique_SSL_OBJECT<BN_CTX, BN_CTX_new, BN_CTX_free>
360 {
362 };
363
364 struct Unique_EC_GROUP : public Unique_SSL_OBJECT<EC_GROUP, nullptr, nullptr>
365 {
368 EC_GROUP_new_by_curve_name(nid), EC_GROUP_free, /*check_null=*/true)
369 {}
370 };
371
372 struct Unique_EC_POINT : public Unique_SSL_OBJECT<EC_POINT, nullptr, nullptr>
373 {
374 Unique_EC_POINT(const EC_GROUP* group) :
375 Unique_SSL_OBJECT(EC_POINT_new(group), EC_POINT_free, /*check_null=*/true)
376 {}
377 Unique_EC_POINT(EC_POINT* point) :
378 Unique_SSL_OBJECT(point, EC_POINT_free, /*check_null=*/true)
379 {}
380 };
381
383 EVP_ENCODE_CTX,
384 EVP_ENCODE_CTX_new,
385 EVP_ENCODE_CTX_free>
386 {
388 };
389
391 : public Unique_SSL_OBJECT<EVP_PKEY, EVP_PKEY_new, EVP_PKEY_free>
392 {
393 Unique_EVP_PKEY() = default;
394 Unique_EVP_PKEY(EVP_PKEY* key) : Unique_SSL_OBJECT(key, EVP_PKEY_free) {}
395 };
396
398 : public Unique_SSL_OBJECT<X509_REQ, X509_REQ_new, X509_REQ_free>
399 {
402 d2i_X509_REQ_bio(mem, nullptr), X509_REQ_free)
403 {}
404 };
405}
Definition openssl_wrappers.h:107
std::unique_ptr< T, void(*)(T *)> p
Pointer owning storage.
Definition openssl_wrappers.h:110
T * release()
Release pointer, so it's freed elsewhere (CAUTION!)
Definition openssl_wrappers.h:143
Unique_SSL_OBJECT(T *ptr, void(*dtor)(T *), bool check_null=true)
C-tor with pointer created in base class.
Definition openssl_wrappers.h:119
void reset(T *other)
Reset pointer, free old if any.
Definition openssl_wrappers.h:138
Unique_SSL_OBJECT()
C-tor with new pointer via T's c-tor.
Definition openssl_wrappers.h:114
Definition pem.h:18
Definition openssl_wrappers.h:27
void CHECKNULL(void *ptr)
Throws if ptr is null.
Definition openssl_wrappers.h:65
void CHECKEQUAL(int expect, int actual)
Definition openssl_wrappers.h:74
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:250
void CHECK1(int rc)
Throws if rc is not 1.
Definition openssl_wrappers.h:54
void CHECKPOSITIVE(int val)
Definition openssl_wrappers.h:85
Definition app_interface.h:13
Definition dl_list.h:9
Definition openssl_wrappers.h:333
Unique_BIGNUM(const BIGNUM *n)
Definition openssl_wrappers.h:336
Definition openssl_wrappers.h:150
Unique_BIO(const void *buf, int len)
Definition openssl_wrappers.h:154
Unique_BIO(const Pem &pem)
Definition openssl_wrappers.h:161
Unique_BIO(std::span< const uint8_t > s)
Definition openssl_wrappers.h:157
Unique_BIO()
Definition openssl_wrappers.h:151
Unique_BIO(SSL_CTX *ctx)
Definition openssl_wrappers.h:165
Definition openssl_wrappers.h:360
Definition openssl_wrappers.h:325
Unique_ECDSA_SIG(ECDSA_SIG *ecdsa_sig)
Definition openssl_wrappers.h:327
Definition openssl_wrappers.h:365
Unique_EC_GROUP(int nid)
Definition openssl_wrappers.h:366
Definition openssl_wrappers.h:373
Unique_EC_POINT(EC_POINT *point)
Definition openssl_wrappers.h:377
Unique_EC_POINT(const EC_GROUP *group)
Definition openssl_wrappers.h:374
Definition openssl_wrappers.h:294
Definition openssl_wrappers.h:386
Definition openssl_wrappers.h:217
Unique_EVP_MD_CTX()
Definition openssl_wrappers.h:218
Definition openssl_wrappers.h:199
Unique_EVP_PKEY_CTX(const std::string &name)
Definition openssl_wrappers.h:208
Unique_EVP_PKEY_CTX(int key_type=EVP_PKEY_EC)
Definition openssl_wrappers.h:203
Unique_EVP_PKEY_CTX(EVP_PKEY *key)
Definition openssl_wrappers.h:200
Definition openssl_wrappers.h:392
Unique_EVP_PKEY(EVP_PKEY *key)
Definition openssl_wrappers.h:394
Definition openssl_wrappers.h:185
Unique_PKEY(BIO *mem)
Definition openssl_wrappers.h:187
Unique_PKEY(EVP_PKEY *pkey)
Definition openssl_wrappers.h:192
Definition openssl_wrappers.h:172
Unique_SSL_CTX(const SSL_METHOD *m)
Definition openssl_wrappers.h:173
Definition openssl_wrappers.h:179
Unique_SSL(SSL_CTX *ctx)
Definition openssl_wrappers.h:180
Unique_STACK_OF_X509_EXTENSIONS()
Definition openssl_wrappers.h:310
Unique_STACK_OF_X509_EXTENSIONS(STACK_OF(X509_EXTENSION) *exts)
Definition openssl_wrappers.h:315
Definition openssl_wrappers.h:300
Unique_STACK_OF_X509()
Definition openssl_wrappers.h:301
Definition openssl_wrappers.h:234
Unique_X509_CRL(BIO *mem)
Definition openssl_wrappers.h:236
Definition openssl_wrappers.h:399
Unique_X509_REQ_DER(BIO *mem)
Definition openssl_wrappers.h:400
Definition openssl_wrappers.h:224
Unique_X509_REQ(BIO *mem)
Definition openssl_wrappers.h:226
Definition openssl_wrappers.h:286
Definition openssl_wrappers.h:278
Definition openssl_wrappers.h:341
Unique_X509_TIME(ASN1_TIME *t)
Definition openssl_wrappers.h:350
Unique_X509_TIME(const std::string &s)
Definition openssl_wrappers.h:343
Unique_X509_TIME(const ccf::nonstd::SystemClock::time_point &t)
Definition openssl_wrappers.h:353
Definition openssl_wrappers.h:264
Unique_X509(BIO *mem, bool pem, bool check_null=false)
Definition openssl_wrappers.h:267
Unique_X509(X509 *cert, bool check_null)
Definition openssl_wrappers.h:271
std::chrono::time_point< SystemClock > time_point
Definition nonstd.h:231