5 // Created by Martin Baulig on 4/11/16.
6 // Copyright © 2016 Xamarin. All rights reserved.
9 #include "btls-ssl-ctx.h"
10 #include "btls-x509-verify-param.h"
11 #include <openssl/bytestring.h>
14 struct MonoBtlsSslCtx
{
15 CRYPTO_refcount_t references
;
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)
36 mono_btls_ssl_ctx_is_debug_enabled (MonoBtlsSslCtx
*ctx
)
38 return ctx
->debug_bio
!= NULL
;
42 mono_btls_ssl_ctx_debug_printf (MonoBtlsSslCtx
*ctx
, const char *format
, ...)
50 va_start (args
, format
);
51 ret
= mono_btls_debug_printf (ctx
->debug_bio
, format
, args
);
57 mono_btls_ssl_ctx_new (void)
61 ctx
= OPENSSL_malloc (sizeof (MonoBtlsSslCtx
));
65 memset (ctx
, 0, sizeof (MonoBtlsSslCtx
));
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
);
81 mono_btls_ssl_ctx_up_ref (MonoBtlsSslCtx
*ctx
)
83 CRYPTO_refcount_inc (&ctx
->references
);
88 mono_btls_ssl_ctx_free (MonoBtlsSslCtx
*ctx
)
90 if (!CRYPTO_refcount_dec_and_test_zero (&ctx
->references
))
92 SSL_CTX_free (ctx
->ctx
);
99 mono_btls_ssl_ctx_get_ctx (MonoBtlsSslCtx
*ctx
)
105 mono_btls_ssl_ctx_set_debug_bio (MonoBtlsSslCtx
*ctx
, BIO
*debug_bio
)
108 ctx
->debug_bio
= BIO_up_ref(debug_bio
);
110 ctx
->debug_bio
= NULL
;
114 mono_btls_ssl_ctx_initialize (MonoBtlsSslCtx
*ctx
, void *instance
)
116 ctx
->instance
= instance
;
120 cert_verify_callback (X509_STORE_CTX
*storeCtx
, void *arg
)
122 MonoBtlsSslCtx
*ptr
= (MonoBtlsSslCtx
*)arg
;
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
);
136 mono_btls_ssl_ctx_set_cert_verify_callback (MonoBtlsSslCtx
*ptr
, MonoBtlsVerifyFunc func
, int cert_required
)
140 ptr
->verify_func
= func
;
141 SSL_CTX_set_cert_verify_callback (ptr
->ctx
, cert_verify_callback
, ptr
);
143 mode
= SSL_VERIFY_PEER
;
145 mode
|= SSL_VERIFY_FAIL_IF_NO_PEER_CERT
;
147 SSL_CTX_set_verify (ptr
->ctx
, mode
, NULL
);
151 cert_select_callback (SSL
*ssl
, void *arg
)
153 MonoBtlsSslCtx
*ptr
= (MonoBtlsSslCtx
*)arg
;
154 STACK_OF(X509_NAME
) *ca_list
;
156 void **cadata
= NULL
;
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
);
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
) {
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
);
188 OPENSSL_free (cadata
);
190 OPENSSL_free (sizes
);
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
);
203 mono_btls_ssl_ctx_peek_store (MonoBtlsSslCtx
*ctx
)
205 return SSL_CTX_get_cert_store (ctx
->ctx
);
209 mono_btls_ssl_ctx_set_min_version (MonoBtlsSslCtx
*ctx
, int version
)
211 SSL_CTX_set_min_version (ctx
->ctx
, version
);
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
)
236 if (!CBB_init (&cbb
, 64))
239 /* Assemble a cipher string with the specified ciphers' names. */
240 for (i
= 0; i
< count
; i
++) {
242 const SSL_CIPHER
*cipher
= SSL_get_cipher_by_value (data
[i
]);
244 debug_printf (ctx
, "mono_btls_ssl_ctx_set_ciphers(): unknown cipher %02x", data
[i
]);
245 if (!allow_unsupported
)
249 name
= SSL_CIPHER_get_name (cipher
);
250 if (i
> 0 && !CBB_add_u8 (&cbb
, ':'))
252 if (!CBB_add_bytes (&cbb
, (const uint8_t *)name
, strlen(name
)))
256 /* NUL-terminate the string. */
257 if (!CBB_add_u8 (&cbb
, 0))
260 ret
= SSL_CTX_set_cipher_list (ctx
->ctx
, (const char *)CBB_data (&cbb
));
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
;
279 name_list
= sk_X509_NAME_new_null ();
283 for (i
= 0; i
< count
; i
++) {
285 const unsigned char *ptr
= (const unsigned char*)data
[i
];
287 name
= d2i_X509_NAME (NULL
, &ptr
, sizes
[i
]);
289 sk_X509_NAME_pop_free (name_list
, X509_NAME_free
);
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
);
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
;
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
);
322 mono_btls_ssl_ctx_get_servername (MonoBtlsSslCtx
*ptr
)
324 return SSL_get_servername (ptr
->ctx
, TLSEXT_NAMETYPE_host_name
);