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 "ccf/ds/logger.h"
7#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 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 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 SSL_set_connect_state(ssl);
75 else
76 SSL_set_accept_state(ssl);
77 }
78
79 virtual ~Context() = default;
80
81 virtual void set_bio(
82 void* cb_obj, BIO_callback_fn_ex send, BIO_callback_fn_ex recv)
83 {
84 // Read/Write BIOs will be used by TLS
85 BIO* rbio = BIO_new(BIO_s_mem());
86 BIO_set_mem_eof_return(rbio, -1);
87 BIO_set_callback_arg(rbio, (char*)cb_obj);
88 BIO_set_callback_ex(rbio, recv);
89 SSL_set0_rbio(ssl, rbio);
90
91 BIO* wbio = BIO_new(BIO_s_mem());
92 BIO_set_mem_eof_return(wbio, -1);
93 BIO_set_callback_arg(wbio, (char*)cb_obj);
94 BIO_set_callback_ex(wbio, send);
95 SSL_set0_wbio(ssl, wbio);
96 }
97
98 virtual int handshake()
99 {
100 if (SSL_is_init_finished(ssl))
101 return 0;
102
103 int rc = SSL_do_handshake(ssl);
104 // Success in OpenSSL is 1, MBed is 0
105 if (rc > 0)
106 {
107 LOG_TRACE_FMT("Context::handshake() : Success");
108 return 0;
109 }
110
111 // Want read/write needs special return
112 if (SSL_want_read(ssl))
113 {
114 return TLS_ERR_WANT_READ;
115 }
116 else if (SSL_want_write(ssl))
117 {
118 return TLS_ERR_WANT_WRITE;
119 }
120
121 // So does x509 validation
122 if (!peer_cert_ok())
123 {
124 return TLS_ERR_X509_VERIFY;
125 }
126
127 // Everything else falls here.
128 LOG_TRACE_FMT("Context::handshake() : Error code {}", rc);
129
130 // As an MBedTLS emulation, we return negative for errors.
131 return -SSL_get_error(ssl, rc);
132 }
133
134 virtual int read(uint8_t* buf, size_t len)
135 {
136 if (len == 0)
137 return 0;
138 size_t readbytes = 0;
139 int rc = SSL_read_ex(ssl, buf, len, &readbytes);
140 if (rc > 0)
141 {
142 return readbytes;
143 }
144 if (SSL_want_read(ssl))
145 {
146 return TLS_ERR_WANT_READ;
147 }
148
149 // Everything else falls here.
150 LOG_TRACE_FMT("Context::read() : Error code {}", rc);
151
152 // As an MBedTLS emulation, we return negative for errors.
153 return -SSL_get_error(ssl, rc);
154 }
155
156 virtual int write(const uint8_t* buf, size_t len)
157 {
158 if (len == 0)
159 return 0;
160 size_t written = 0;
161 int rc = SSL_write_ex(ssl, buf, len, &written);
162 if (rc > 0)
163 {
164 return written;
165 }
166 if (SSL_want_write(ssl))
167 {
168 return TLS_ERR_WANT_WRITE;
169 }
170
171 // Everything else falls here.
172 LOG_TRACE_FMT("Context::write() : Error code {}", rc);
173
174 // As an MBedTLS emulation, we return negative for errors.
175 return -SSL_get_error(ssl, rc);
176 }
177
178 virtual int close()
179 {
180 LOG_TRACE_FMT("Context::close() : Shutdown");
181 return SSL_shutdown(ssl);
182 }
183
184 virtual bool peer_cert_ok()
185 {
186 return SSL_get_verify_result(ssl) == X509_V_OK;
187 }
188
189 virtual std::string get_verify_error()
190 {
191 return X509_verify_cert_error_string(SSL_get_verify_result(ssl));
192 }
193
194 virtual std::string host()
195 {
196 return {};
197 }
198
199 virtual std::vector<uint8_t> peer_cert()
200 {
201 // CodeQL complains that we don't verify the peer certificate. We don't
202 // need to do that because it's been verified before and we use
203 // SSL_get_peer_certificate just to extract it from the context.
204
206 SSL_get_peer_certificate(ssl), /*check_null=*/false);
207 if (!cert)
208 {
209 LOG_TRACE_FMT("Empty peer cert");
210 return {};
211 }
213 if (!i2d_X509_bio(bio, cert))
214 {
215 LOG_TRACE_FMT("Can't convert X509 to DER");
216 return {};
217 }
218
219 // Get the total length of the DER representation
220 auto len = BIO_get_mem_data(bio, nullptr);
221 if (!len)
222 {
223 LOG_TRACE_FMT("Null X509 peer cert");
224 return {};
225 }
226
227 // Get the BIO memory pointer
228 BUF_MEM* ptr = nullptr;
229 if (!BIO_get_mem_ptr(bio, &ptr))
230 {
231 LOG_TRACE_FMT("Invalid X509 peer cert");
232 return {};
233 }
234
235 // Return its contents as a vector
236 auto ret = std::vector<uint8_t>(ptr->data, ptr->data + len);
237 return ret;
238 }
239 };
240}
Definition context.h:17
ccf::crypto::OpenSSL::Unique_SSL ssl
Definition context.h:20
virtual int handshake()
Definition context.h:98
virtual std::vector< uint8_t > peer_cert()
Definition context.h:199
virtual int read(uint8_t *buf, size_t len)
Definition context.h:134
virtual std::string get_verify_error()
Definition context.h:189
virtual ~Context()=default
virtual int write(const uint8_t *buf, size_t len)
Definition context.h:156
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:81
virtual std::string host()
Definition context.h:194
virtual int close()
Definition context.h:178
virtual bool peer_cert_ok()
Definition context.h:184
#define LOG_TRACE_FMT
Definition logger.h:356
Definition custom_protocol_subsystem_interface.h:18
Definition perf_client.h:12
Definition openssl_wrappers.h:161
Definition openssl_wrappers.h:184
Definition openssl_wrappers.h:191
Definition openssl_wrappers.h:277
#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