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
9#include <chrono>
10#include <ds/x509_time_fmt.h>
11#include <fmt/format.h>
12#include <memory>
13#include <openssl/asn1.h>
14#include <openssl/bn.h>
15#include <openssl/ec.h>
16#include <openssl/engine.h>
17#include <openssl/err.h>
18#include <openssl/evp.h>
19#include <openssl/pem.h>
20#include <openssl/rsa.h>
21#include <openssl/ssl.h>
22#include <openssl/x509.h>
23#include <openssl/x509v3.h>
24
25#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
26# include <openssl/evp.h>
27#endif
28
29namespace ccf::crypto
30{
31 namespace OpenSSL
32 {
33 /*
34 * Generic OpenSSL error handling
35 */
36
38 inline std::string error_string(int ec)
39 {
40 // ERR_error_string doesn't really expect the code could actually be zero
41 // and uses the `static char buf[256]` which is NOT cleaned nor checked
42 // if it has changed. So we use ERR_error_string_n directly.
43 if (ec)
44 {
45 std::string err(256, '\0');
46 ERR_error_string_n((unsigned long)ec, err.data(), err.size());
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(const std::vector<uint8_t>& d) :
171 BIO_new_mem_buf(d.data(), d.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#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
205 Unique_PKEY(EVP_PKEY* pkey) :
206 Unique_SSL_OBJECT(EVP_PKEY_dup(pkey), EVP_PKEY_free)
207 {}
208#endif
209 };
210
212 : public Unique_SSL_OBJECT<EVP_PKEY_CTX, nullptr, nullptr>
213 {
214 Unique_EVP_PKEY_CTX(EVP_PKEY* key) :
215 Unique_SSL_OBJECT(EVP_PKEY_CTX_new(key, NULL), EVP_PKEY_CTX_free)
216 {}
217 Unique_EVP_PKEY_CTX(int key_type = EVP_PKEY_EC) :
219 EVP_PKEY_CTX_new_id(key_type, NULL), EVP_PKEY_CTX_free)
220 {}
221
222#if defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3
223 Unique_EVP_PKEY_CTX(const std::string& name) :
225 EVP_PKEY_CTX_new_from_name(NULL, name.c_str(), NULL),
226 EVP_PKEY_CTX_free)
227 {}
228#endif
229 };
230
232 : public Unique_SSL_OBJECT<EVP_MD_CTX, nullptr, nullptr>
233 {
234 Unique_EVP_MD_CTX() : Unique_SSL_OBJECT(EVP_MD_CTX_new(), EVP_MD_CTX_free)
235 {}
236 };
237
239 : public Unique_SSL_OBJECT<X509_REQ, X509_REQ_new, X509_REQ_free>
240 {
242 Unique_X509_REQ(BIO* mem) :
244 PEM_read_bio_X509_REQ(mem, NULL, NULL, NULL), X509_REQ_free)
245 {}
246 };
247
249 : public Unique_SSL_OBJECT<X509_CRL, X509_CRL_new, X509_CRL_free>
250 {
252 Unique_X509_CRL(BIO* mem) :
254 PEM_read_bio_X509_CRL(mem, NULL, NULL, NULL), X509_CRL_free)
255 {}
256 };
257
258 static const char pem_prefix[] = "-----BEGIN CERTIFICATE-----\n";
259 // -1 for the null terminator
260 static constexpr size_t pem_prefix_len = sizeof(pem_prefix) - 1;
261
262 // Check BIO starts with PEM prefix before attempting to read it as PEM
263 // because PEM_read_bio_X509 is permissive and will skip over non-PEM data,
264 // which may for example result in a DER containing nested PEM being read
265 // as the nested certificate.
266 inline X509* read_pem(BIO* mem)
267 {
268 std::vector<char> buf(pem_prefix_len);
269 auto read = BIO_read(mem, buf.data(), pem_prefix_len);
270 BIO_reset(mem);
271 if (
272 read != pem_prefix_len ||
273 std::memcmp(buf.data(), pem_prefix, read) != 0)
274 {
275 return nullptr;
276 }
277 return PEM_read_bio_X509(mem, NULL, NULL, NULL);
278 };
279
280 struct Unique_X509 : public Unique_SSL_OBJECT<X509, X509_new, X509_free>
281 {
283 // p == nullptr is OK (e.g. wrong format)
284 Unique_X509(BIO* mem, bool pem, bool check_null = false) :
286 pem ? read_pem(mem) : d2i_X509_bio(mem, NULL), X509_free, check_null)
287 {}
288 Unique_X509(X509* cert, bool check_null) :
289 Unique_SSL_OBJECT(cert, X509_free, check_null)
290 {}
291 };
292
294 : public Unique_SSL_OBJECT<X509_STORE, X509_STORE_new, X509_STORE_free>
295 {
297 };
298
300 X509_STORE_CTX,
301 X509_STORE_CTX_new,
302 X509_STORE_CTX_free>
303 {
305 };
306
308 EVP_CIPHER_CTX,
309 EVP_CIPHER_CTX_new,
310 EVP_CIPHER_CTX_free>
311 {
313 };
314
316 : public Unique_SSL_OBJECT<STACK_OF(X509), nullptr, nullptr>
317 {
320 sk_X509_new_null(), [](auto x) { sk_X509_pop_free(x, X509_free); })
321 {}
322 };
323
325 : public Unique_SSL_OBJECT<STACK_OF(X509_EXTENSION), nullptr, nullptr>
326 {
328 Unique_SSL_OBJECT(sk_X509_EXTENSION_new_null(), [](auto x) {
329 sk_X509_EXTENSION_pop_free(x, X509_EXTENSION_free);
330 })
331 {}
332 Unique_STACK_OF_X509_EXTENSIONS(STACK_OF(X509_EXTENSION) * exts) :
334 exts,
335 [](auto x) { sk_X509_EXTENSION_pop_free(x, X509_EXTENSION_free); },
336 /*check_null=*/false)
337 {}
338 };
339
341 : public Unique_SSL_OBJECT<ECDSA_SIG, ECDSA_SIG_new, ECDSA_SIG_free>
342 {
344 Unique_ECDSA_SIG(ECDSA_SIG* ecdsa_sig) :
345 Unique_SSL_OBJECT(ecdsa_sig, ECDSA_SIG_free)
346 {}
347 };
348
349 struct Unique_BIGNUM : public Unique_SSL_OBJECT<BIGNUM, BN_new, BN_free>
350 {
352
353 Unique_BIGNUM(const BIGNUM* n) : Unique_BIGNUM(BN_dup(n), BN_free) {}
354 };
355
357 : public Unique_SSL_OBJECT<ASN1_TIME, ASN1_TIME_new, ASN1_TIME_free>
358 {
360 Unique_X509_TIME(const std::string& s) :
361 Unique_SSL_OBJECT(ASN1_TIME_new(), ASN1_TIME_free, /*check_null=*/false)
362 {
363 auto t = ::ds::to_x509_time_string(s);
364 CHECK1(ASN1_TIME_set_string(*this, t.c_str()));
365 CHECK1(ASN1_TIME_normalize(*this));
366 }
367 Unique_X509_TIME(ASN1_TIME* t) :
368 Unique_SSL_OBJECT(t, ASN1_TIME_free, /*check_null=*/false)
369 {}
370 Unique_X509_TIME(const std::chrono::system_clock::time_point& t) :
371 Unique_X509_TIME(::ds::to_x509_time_string(t))
372 {}
373 };
374
376 : public Unique_SSL_OBJECT<BN_CTX, BN_CTX_new, BN_CTX_free>
377 {
379 };
380
382 : public Unique_SSL_OBJECT<EC_GROUP, nullptr, nullptr>
383 {
386 EC_GROUP_new_by_curve_name(nid), EC_GROUP_free, /*check_null=*/true)
387 {}
388 };
389
391 : public Unique_SSL_OBJECT<EC_POINT, nullptr, nullptr>
392 {
393 Unique_EC_POINT(const EC_GROUP* group) :
395 EC_POINT_new(group), EC_POINT_free, /*check_null=*/true)
396 {}
397 Unique_EC_POINT(EC_POINT* point) :
398 Unique_SSL_OBJECT(point, EC_POINT_free, /*check_null=*/true)
399 {}
400 };
401
402#if !(defined(OPENSSL_VERSION_MAJOR) && OPENSSL_VERSION_MAJOR >= 3)
403 struct Unique_EC_KEY : public Unique_SSL_OBJECT<EC_KEY, nullptr, nullptr>
404 {
405 Unique_EC_KEY(int nid) :
407 EC_KEY_new_by_curve_name(nid), EC_KEY_free, /*check_null=*/true)
408 {}
409 Unique_EC_KEY(EC_KEY* key) :
410 Unique_SSL_OBJECT(key, EC_KEY_free, /*check_null=*/true)
411 {}
412 };
413
414 struct Unique_RSA : public Unique_SSL_OBJECT<RSA, RSA_new, RSA_free>
415 {
417 };
418#endif
419
421 EVP_ENCODE_CTX,
422 EVP_ENCODE_CTX_new,
423 EVP_ENCODE_CTX_free>
424 {
426 };
427 }
428}
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
std::string error_string(int ec)
Returns the error string from an error code.
Definition openssl_wrappers.h:38
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
X509 * read_pem(BIO *mem)
Definition openssl_wrappers.h:266
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:9
Definition dl_list.h:9
Definition openssl_wrappers.h:350
Unique_BIGNUM(const BIGNUM *n)
Definition openssl_wrappers.h:353
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(const std::vector< uint8_t > &d)
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:377
Definition openssl_wrappers.h:342
Unique_ECDSA_SIG(ECDSA_SIG *ecdsa_sig)
Definition openssl_wrappers.h:344
Definition openssl_wrappers.h:383
Unique_EC_GROUP(int nid)
Definition openssl_wrappers.h:384
Definition openssl_wrappers.h:404
Unique_EC_KEY(EC_KEY *key)
Definition openssl_wrappers.h:409
Unique_EC_KEY(int nid)
Definition openssl_wrappers.h:405
Definition openssl_wrappers.h:392
Unique_EC_POINT(EC_POINT *point)
Definition openssl_wrappers.h:397
Unique_EC_POINT(const EC_GROUP *group)
Definition openssl_wrappers.h:393
Definition openssl_wrappers.h:311
Definition openssl_wrappers.h:424
Definition openssl_wrappers.h:233
Unique_EVP_MD_CTX()
Definition openssl_wrappers.h:234
Definition openssl_wrappers.h:213
Unique_EVP_PKEY_CTX(int key_type=EVP_PKEY_EC)
Definition openssl_wrappers.h:217
Unique_EVP_PKEY_CTX(EVP_PKEY *key)
Definition openssl_wrappers.h:214
Definition openssl_wrappers.h:197
Unique_PKEY(BIO *mem)
Definition openssl_wrappers.h:199
Definition openssl_wrappers.h:415
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:327
Unique_STACK_OF_X509_EXTENSIONS(STACK_OF(X509_EXTENSION) *exts)
Definition openssl_wrappers.h:332
Definition openssl_wrappers.h:317
Unique_STACK_OF_X509()
Definition openssl_wrappers.h:318
Definition openssl_wrappers.h:250
Unique_X509_CRL(BIO *mem)
Definition openssl_wrappers.h:252
Definition openssl_wrappers.h:240
Unique_X509_REQ(BIO *mem)
Definition openssl_wrappers.h:242
Definition openssl_wrappers.h:303
Definition openssl_wrappers.h:295
Definition openssl_wrappers.h:358
Unique_X509_TIME(ASN1_TIME *t)
Definition openssl_wrappers.h:367
Unique_X509_TIME(const std::string &s)
Definition openssl_wrappers.h:360
Unique_X509_TIME(const std::chrono::system_clock::time_point &t)
Definition openssl_wrappers.h:370
Definition openssl_wrappers.h:281
Unique_X509(BIO *mem, bool pem, bool check_null=false)
Definition openssl_wrappers.h:284
Unique_X509(X509 *cert, bool check_null)
Definition openssl_wrappers.h:288