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