Remove allocations from Dns.* (dotnet/corefx#41061)
[mono-project.git] / mono / btls / btls-ssl-ctx.c
bloba768ee4c6ca6c96563482b20b3bf2ba079fb5d58
1 //
2 // btls-ssl-ctx.c
3 // MonoBtls
4 //
5 // Created by Martin Baulig on 4/11/16.
6 // Copyright © 2016 Xamarin. All rights reserved.
7 //
9 #include "btls-ssl-ctx.h"
10 #include "btls-x509-verify-param.h"
11 #include <openssl/bytestring.h>
12 #include <string.h>
14 struct MonoBtlsSslCtx {
15 CRYPTO_refcount_t references;
16 SSL_CTX *ctx;
17 BIO *bio;
18 BIO *debug_bio;
19 void *instance;
20 MonoBtlsVerifyFunc verify_func;
21 MonoBtlsSelectFunc select_func;
22 MonoBtlsServerNameFunc server_name_func;
25 #define debug_print(ptr,message) \
26 do { if (mono_btls_ssl_ctx_is_debug_enabled(ptr)) \
27 mono_btls_ssl_ctx_debug_printf (ptr, "%s:%d:%s(): " message, __FILE__, __LINE__, \
28 __func__); } while (0)
30 #define debug_printf(ptr,fmt, ...) \
31 do { if (mono_btls_ssl_ctx_is_debug_enabled(ptr)) \
32 mono_btls_ssl_ctx_debug_printf (ptr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, \
33 __func__, __VA_ARGS__); } while (0)
35 int
36 mono_btls_ssl_ctx_is_debug_enabled (MonoBtlsSslCtx *ctx)
38 return ctx->debug_bio != NULL;
41 int
42 mono_btls_ssl_ctx_debug_printf (MonoBtlsSslCtx *ctx, const char *format, ...)
44 va_list args;
45 int ret;
47 if (!ctx->debug_bio)
48 return 0;
50 va_start (args, format);
51 ret = mono_btls_debug_printf (ctx->debug_bio, format, args);
52 va_end (args);
53 return ret;
56 MonoBtlsSslCtx *
57 mono_btls_ssl_ctx_new (void)
59 MonoBtlsSslCtx *ctx;
61 ctx = OPENSSL_malloc (sizeof (MonoBtlsSslCtx));
62 if (!ctx)
63 return NULL;
65 memset (ctx, 0, sizeof (MonoBtlsSslCtx));
66 ctx->references = 1;
67 ctx->ctx = SSL_CTX_new (TLS_method ());
69 // enable the default ciphers but disable any RC4 based ciphers
70 // since they're insecure: RFC 7465 "Prohibiting RC4 Cipher Suites"
71 SSL_CTX_set_cipher_list (ctx->ctx, "DEFAULT:!RC4");
73 // disable SSLv2 and SSLv3 by default, they are deprecated
74 // and should generally not be used according to the openssl docs
75 SSL_CTX_set_options (ctx->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
77 return ctx;
80 MonoBtlsSslCtx *
81 mono_btls_ssl_ctx_up_ref (MonoBtlsSslCtx *ctx)
83 CRYPTO_refcount_inc (&ctx->references);
84 return ctx;
87 int
88 mono_btls_ssl_ctx_free (MonoBtlsSslCtx *ctx)
90 if (!CRYPTO_refcount_dec_and_test_zero (&ctx->references))
91 return 0;
92 SSL_CTX_free (ctx->ctx);
93 ctx->instance = NULL;
94 OPENSSL_free (ctx);
95 return 1;
98 SSL_CTX *
99 mono_btls_ssl_ctx_get_ctx (MonoBtlsSslCtx *ctx)
101 return ctx->ctx;
104 void
105 mono_btls_ssl_ctx_set_debug_bio (MonoBtlsSslCtx *ctx, BIO *debug_bio)
107 if (debug_bio)
108 ctx->debug_bio = BIO_up_ref(debug_bio);
109 else
110 ctx->debug_bio = NULL;
113 void
114 mono_btls_ssl_ctx_initialize (MonoBtlsSslCtx *ctx, void *instance)
116 ctx->instance = instance;
119 static int
120 cert_verify_callback (X509_STORE_CTX *storeCtx, void *arg)
122 MonoBtlsSslCtx *ptr = (MonoBtlsSslCtx*)arg;
123 int ret;
125 debug_printf (ptr, "cert_verify_callback(): %p\n", ptr->verify_func);
126 ret = X509_verify_cert (storeCtx);
127 debug_printf (ptr, "cert_verify_callback() #1: %d\n", ret);
129 if (ptr->verify_func)
130 ret = ptr->verify_func (ptr->instance, ret, storeCtx);
132 return ret;
135 void
136 mono_btls_ssl_ctx_set_cert_verify_callback (MonoBtlsSslCtx *ptr, MonoBtlsVerifyFunc func, int cert_required)
138 int mode;
140 ptr->verify_func = func;
141 SSL_CTX_set_cert_verify_callback (ptr->ctx, cert_verify_callback, ptr);
143 mode = SSL_VERIFY_PEER;
144 if (cert_required)
145 mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
147 SSL_CTX_set_verify (ptr->ctx, mode, NULL);
150 static int
151 cert_select_callback (SSL *ssl, void *arg)
153 MonoBtlsSslCtx *ptr = (MonoBtlsSslCtx*)arg;
154 STACK_OF(X509_NAME) *ca_list;
155 int *sizes = NULL;
156 void **cadata = NULL;
157 int count = 0;
158 int ret = 1;
159 int i;
161 debug_printf (ptr, "cert_select_callback(): %p\n", ptr->select_func);
163 // SSL_get_client_CA_list() may only be called during this callback.
164 ca_list = SSL_get_client_CA_list (ssl);
165 if (ca_list) {
166 count = (int)sk_X509_NAME_num (ca_list);
167 cadata = OPENSSL_malloc (sizeof (void *) * (count + 1));
168 sizes = OPENSSL_malloc (sizeof (int) * (count + 1));
169 if (!cadata || !sizes) {
170 ret = 0;
171 goto out;
173 for (i = 0; i < count; i++) {
174 X509_NAME *name = sk_X509_NAME_value (ca_list, i);
175 cadata[i] = name->bytes->data;
176 sizes[i] = (int)name->bytes->length;
180 debug_printf (ptr, "cert_select_callback() #1: %p\n", ca_list);
182 if (ptr->select_func)
183 ret = ptr->select_func (ptr->instance, count, sizes, cadata);
184 debug_printf (ptr, "cert_select_callback() #1: %d\n", ret);
186 out:
187 if (cadata)
188 OPENSSL_free (cadata);
189 if (sizes)
190 OPENSSL_free (sizes);
192 return ret;
195 void
196 mono_btls_ssl_ctx_set_cert_select_callback (MonoBtlsSslCtx *ptr, MonoBtlsSelectFunc func)
198 ptr->select_func = func;
199 SSL_CTX_set_cert_cb (ptr->ctx, cert_select_callback, ptr);
202 X509_STORE *
203 mono_btls_ssl_ctx_peek_store (MonoBtlsSslCtx *ctx)
205 return SSL_CTX_get_cert_store (ctx->ctx);
208 void
209 mono_btls_ssl_ctx_set_min_version (MonoBtlsSslCtx *ctx, int version)
211 SSL_CTX_set_min_version (ctx->ctx, version);
214 void
215 mono_btls_ssl_ctx_set_max_version (MonoBtlsSslCtx *ctx, int version)
217 SSL_CTX_set_max_version (ctx->ctx, version);
221 mono_btls_ssl_ctx_is_cipher_supported (MonoBtlsSslCtx *ctx, uint16_t value)
223 const SSL_CIPHER *cipher;
225 cipher = SSL_get_cipher_by_value (value);
226 return cipher != NULL;
230 mono_btls_ssl_ctx_set_ciphers (MonoBtlsSslCtx *ctx, int count, const uint16_t *data,
231 int allow_unsupported)
233 CBB cbb;
234 int i, ret = 0;
236 if (!CBB_init (&cbb, 64))
237 goto err;
239 /* Assemble a cipher string with the specified ciphers' names. */
240 for (i = 0; i < count; i++) {
241 const char *name;
242 const SSL_CIPHER *cipher = SSL_get_cipher_by_value (data [i]);
243 if (!cipher) {
244 debug_printf (ctx, "mono_btls_ssl_ctx_set_ciphers(): unknown cipher %02x", data [i]);
245 if (!allow_unsupported)
246 goto err;
247 continue;
249 name = SSL_CIPHER_get_name (cipher);
250 if (i > 0 && !CBB_add_u8 (&cbb, ':'))
251 goto err;
252 if (!CBB_add_bytes (&cbb, (const uint8_t *)name, strlen(name)))
253 goto err;
256 /* NUL-terminate the string. */
257 if (!CBB_add_u8 (&cbb, 0))
258 goto err;
260 ret = SSL_CTX_set_cipher_list (ctx->ctx, (const char *)CBB_data (&cbb));
262 err:
263 CBB_cleanup (&cbb);
264 return ret;
268 mono_btls_ssl_ctx_set_verify_param (MonoBtlsSslCtx *ctx, const MonoBtlsX509VerifyParam *param)
270 return SSL_CTX_set1_param (ctx->ctx, mono_btls_x509_verify_param_peek_param (param));
274 mono_btls_ssl_ctx_set_client_ca_list (MonoBtlsSslCtx *ctx, int count, int *sizes, const void **data)
276 STACK_OF(X509_NAME) *name_list;
277 int i;
279 name_list = sk_X509_NAME_new_null ();
280 if (!name_list)
281 return 0;
283 for (i = 0; i < count; i++) {
284 X509_NAME *name;
285 const unsigned char *ptr = (const unsigned char*)data[i];
287 name = d2i_X509_NAME (NULL, &ptr, sizes[i]);
288 if (!name) {
289 sk_X509_NAME_pop_free (name_list, X509_NAME_free);
290 return 0;
292 sk_X509_NAME_push (name_list, name);
295 // Takes ownership of the list.
296 SSL_CTX_set_client_CA_list (ctx->ctx, name_list);
297 return 1;
300 static int
301 server_name_callback (SSL *ssl, int *out_alert, void *arg)
303 MonoBtlsSslCtx *ctx = (MonoBtlsSslCtx *)arg;
305 if (ctx->server_name_func (ctx->instance) == 1)
306 return SSL_TLSEXT_ERR_OK;
308 *out_alert = SSL_AD_USER_CANCELLED;
309 return SSL_TLSEXT_ERR_ALERT_FATAL;
312 void
313 mono_btls_ssl_ctx_set_server_name_callback (MonoBtlsSslCtx *ptr, MonoBtlsServerNameFunc func)
315 ptr->server_name_func = func;
317 SSL_CTX_set_tlsext_servername_callback (ptr->ctx, server_name_callback);
318 SSL_CTX_set_tlsext_servername_arg (ptr->ctx, ptr);