CCF
Loading...
Searching...
No Matches
context.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/base64.h"
6#include "cert.h"
8#include "tls/tls.h"
9
10#include <memory>
11#include <openssl/bio.h>
12#include <openssl/ssl.h>
13
14namespace ccf::tls
15{
16 class Context
17 {
18 protected:
21
22 public:
24 cfg(client ? TLS_client_method() : TLS_server_method()),
25 ssl(cfg)
26 {
27 // Require at least TLS 1.2, support up to 1.3
28 SSL_CTX_set_min_proto_version(cfg, TLS1_2_VERSION);
29 SSL_set_min_proto_version(ssl, TLS1_2_VERSION);
30
31 // Disable renegotiation to avoid DoS
32 SSL_CTX_set_options(
33 cfg,
34 SSL_OP_CIPHER_SERVER_PREFERENCE |
35 SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
36 SSL_OP_NO_RENEGOTIATION);
37 SSL_set_options(
38 ssl,
39 SSL_OP_CIPHER_SERVER_PREFERENCE |
40 SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
41 SSL_OP_NO_RENEGOTIATION);
42
43 // Set cipher for TLS 1.2
44 const auto* const cipher_list =
45 "ECDHE-ECDSA-AES256-GCM-SHA384:"
46 "ECDHE-ECDSA-AES128-GCM-SHA256:"
47 "ECDHE-RSA-AES256-GCM-SHA384:"
48 "ECDHE-RSA-AES128-GCM-SHA256";
49 SSL_CTX_set_cipher_list(cfg, cipher_list);
50 SSL_set_cipher_list(ssl, cipher_list);
51
52 // Set cipher for TLS 1.3
53 const auto* const ciphersuites =
54 "TLS_AES_256_GCM_SHA384:"
55 "TLS_AES_128_GCM_SHA256";
56 SSL_CTX_set_ciphersuites(cfg, ciphersuites);
57 SSL_set_ciphersuites(ssl, ciphersuites);
58
59 // Restrict the curves to approved ones
60 SSL_CTX_set1_curves_list(cfg, "P-521:P-384:P-256");
61 SSL_set1_curves_list(ssl, "P-521:P-384:P-256");
62
63 // Allow buffer to be relocated between WANT_WRITE retries, and do partial
64 // writes if possible
65 SSL_CTX_set_mode(
66 cfg,
67 SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE);
68 SSL_set_mode(
69 ssl,
70 SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE);
71
72 // Initialise connection
73 if (client)
74 {
75 SSL_set_connect_state(ssl);
76 }
77 else
78 {
79 SSL_set_accept_state(ssl);
80 }
81 }
82
83 virtual ~Context() = default;
84
85 virtual void set_bio(
86 void* cb_obj, BIO_callback_fn_ex send, BIO_callback_fn_ex recv)
87 {
88 // Read/Write BIOs will be used by TLS
89 BIO* rbio = BIO_new(BIO_s_mem());
90 BIO_set_mem_eof_return(rbio, -1);
91 BIO_set_callback_arg(rbio, static_cast<char*>(cb_obj));
92 BIO_set_callback_ex(rbio, recv);
93 SSL_set0_rbio(ssl, rbio);
94
95 BIO* wbio = BIO_new(BIO_s_mem());
96 BIO_set_mem_eof_return(wbio, -1);
97 BIO_set_callback_arg(wbio, static_cast<char*>(cb_obj));
98 BIO_set_callback_ex(wbio, send);
99 SSL_set0_wbio(ssl, wbio);
100 }
101
102 virtual int handshake()
103 {
104 if (SSL_is_init_finished(ssl) != 0)
105 {
106 return 0;
107 }
108
109 int rc = SSL_do_handshake(ssl);
110 // Success in OpenSSL is 1, MBed is 0
111 if (rc > 0)
112 {
113 LOG_TRACE_FMT("Context::handshake() : Success");
114 return 0;
115 }
116
117 // Want read/write needs special return
118 if (SSL_want_read(ssl))
119 {
120 return TLS_ERR_WANT_READ;
121 }
122
123 if (SSL_want_write(ssl))
124 {
125 return TLS_ERR_WANT_WRITE;
126 }
127
128 // So does x509 validation
129 if (!peer_cert_ok())
130 {
131 return TLS_ERR_X509_VERIFY;
132 }
133
134 // Everything else falls here.
135 LOG_TRACE_FMT("Context::handshake() : Error code {}", rc);
136
137 // As an MBedTLS emulation, we return negative for errors.
138 return -SSL_get_error(ssl, rc);
139 }
140
141 virtual int read(uint8_t* buf, size_t len)
142 {
143 if (len == 0)
144 {
145 return 0;
146 }
147 size_t readbytes = 0;
148 int rc = SSL_read_ex(ssl, buf, len, &readbytes);
149 if (rc > 0)
150 {
151 return readbytes;
152 }
153 if (SSL_want_read(ssl))
154 {
155 return TLS_ERR_WANT_READ;
156 }
157
158 // Everything else falls here.
159 LOG_TRACE_FMT("Context::read() : Error code {}", rc);
160
161 // As an MBedTLS emulation, we return negative for errors.
162 return -SSL_get_error(ssl, rc);
163 }
164
165 virtual int write(const uint8_t* buf, size_t len)
166 {
167 if (len == 0)
168 {
169 return 0;
170 }
171 size_t written = 0;
172 int rc = SSL_write_ex(ssl, buf, len, &written);
173 if (rc > 0)
174 {
175 return written;
176 }
177 if (SSL_want_write(ssl))
178 {
179 return TLS_ERR_WANT_WRITE;
180 }
181
182 // Everything else falls here.
183 LOG_TRACE_FMT("Context::write() : Error code {}", rc);
184
185 // As an MBedTLS emulation, we return negative for errors.
186 return -SSL_get_error(ssl, rc);
187 }
188
189 virtual int close()
190 {
191 LOG_TRACE_FMT("Context::close() : Shutdown");
192 return SSL_shutdown(ssl);
193 }
194
195 virtual bool peer_cert_ok()
196 {
197 return SSL_get_verify_result(ssl) == X509_V_OK;
198 }
199
200 virtual std::string get_verify_error()
201 {
202 return X509_verify_cert_error_string(SSL_get_verify_result(ssl));
203 }
204
205 virtual std::string host()
206 {
207 return {};
208 }
209
210 virtual std::vector<uint8_t> peer_cert()
211 {
212 // CodeQL complains that we don't verify the peer certificate. We don't
213 // need to do that because it's been verified before and we use
214 // SSL_get_peer_certificate just to extract it from the context.
215
217 SSL_get_peer_certificate(ssl), /*check_null=*/false);
218 if (cert == nullptr)
219 {
220 LOG_TRACE_FMT("Empty peer cert");
221 return {};
222 }
224 if (i2d_X509_bio(bio, cert) == 0)
225 {
226 LOG_TRACE_FMT("Can't convert X509 to DER");
227 return {};
228 }
229
230 // Get the total length of the DER representation
231 auto len = BIO_get_mem_data(bio, nullptr);
232 if (len == 0)
233 {
234 LOG_TRACE_FMT("Null X509 peer cert");
235 return {};
236 }
237
238 // Get the BIO memory pointer
239 BUF_MEM* ptr = nullptr;
240 if (BIO_get_mem_ptr(bio, &ptr) == 0)
241 {
242 LOG_TRACE_FMT("Invalid X509 peer cert");
243 return {};
244 }
245
246 // Return its contents as a vector
247 auto ret = std::vector<uint8_t>(ptr->data, ptr->data + len);
248 return ret;
249 }
250 };
251}
Definition context.h:17
ccf::crypto::OpenSSL::Unique_SSL ssl
Definition context.h:20
virtual int handshake()
Definition context.h:102
virtual std::vector< uint8_t > peer_cert()
Definition context.h:210
virtual int read(uint8_t *buf, size_t len)
Definition context.h:141
virtual std::string get_verify_error()
Definition context.h:200
virtual ~Context()=default
virtual int write(const uint8_t *buf, size_t len)
Definition context.h:165
Context(bool client)
Definition context.h:23
ccf::crypto::OpenSSL::Unique_SSL_CTX cfg
Definition context.h:19
virtual void set_bio(void *cb_obj, BIO_callback_fn_ex send, BIO_callback_fn_ex recv)
Definition context.h:85
virtual std::string host()
Definition context.h:205
virtual int close()
Definition context.h:189
virtual bool peer_cert_ok()
Definition context.h:195
#define LOG_TRACE_FMT
Definition internal_logger.h:13
Definition custom_protocol_subsystem_interface.h:18
Definition perf_client.h:12
Definition openssl_wrappers.h:159
Definition openssl_wrappers.h:181
Definition openssl_wrappers.h:188
Definition openssl_wrappers.h:273
#define TLS_ERR_X509_VERIFY
Definition tls.h:24
#define TLS_ERR_WANT_WRITE
Definition tls.h:17
#define TLS_ERR_WANT_READ
Definition tls.h:16