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 //
8 
9 #include <btls-ssl-ctx.h>
10 #include <btls-x509-verify-param.h>
11 
12 struct MonoBtlsSslCtx {
13 	CRYPTO_refcount_t references;
14 	SSL_CTX *ctx;
15 	BIO *bio;
16 	BIO *debug_bio;
17 	void *instance;
18 	MonoBtlsVerifyFunc verify_func;
19 	MonoBtlsSelectFunc select_func;
20 };
21 
22 #define debug_print(ptr,message) \
23 do { if (mono_btls_ssl_ctx_is_debug_enabled(ptr)) \
24 mono_btls_ssl_ctx_debug_printf (ptr, "%s:%d:%s(): " message, __FILE__, __LINE__, \
25 	__func__); } while (0)
26 
27 #define debug_printf(ptr,fmt, ...) \
28 do { if (mono_btls_ssl_ctx_is_debug_enabled(ptr)) \
29 mono_btls_ssl_ctx_debug_printf (ptr, "%s:%d:%s(): " fmt, __FILE__, __LINE__, \
30 	__func__, __VA_ARGS__); } while (0)
31 
32 void ssl_cipher_preference_list_free (struct ssl_cipher_preference_list_st *cipher_list);
33 
34 MONO_API int
mono_btls_ssl_ctx_is_debug_enabled(MonoBtlsSslCtx * ctx)35 mono_btls_ssl_ctx_is_debug_enabled (MonoBtlsSslCtx *ctx)
36 {
37 	return ctx->debug_bio != NULL;
38 }
39 
40 MONO_API int
mono_btls_ssl_ctx_debug_printf(MonoBtlsSslCtx * ctx,const char * format,...)41 mono_btls_ssl_ctx_debug_printf (MonoBtlsSslCtx *ctx, const char *format, ...)
42 {
43 	va_list args;
44 	int ret;
45 
46 	if (!ctx->debug_bio)
47 		return 0;
48 
49 	va_start (args, format);
50 	ret = mono_btls_debug_printf (ctx->debug_bio, format, args);
51 	va_end (args);
52 	return ret;
53 }
54 
55 MONO_API MonoBtlsSslCtx *
mono_btls_ssl_ctx_new(void)56 mono_btls_ssl_ctx_new (void)
57 {
58 	MonoBtlsSslCtx *ctx;
59 
60 	ctx = OPENSSL_malloc (sizeof (MonoBtlsSslCtx));
61 	if (!ctx)
62 		return NULL;
63 
64 	memset (ctx, 0, sizeof (MonoBtlsSslCtx));
65 	ctx->references = 1;
66 	ctx->ctx = SSL_CTX_new (TLS_method ());
67 
68 	// enable the default ciphers but disable any RC4 based ciphers
69 	// since they're insecure: RFC 7465 "Prohibiting RC4 Cipher Suites"
70 	SSL_CTX_set_cipher_list (ctx->ctx, "DEFAULT:!RC4");
71 
72 	// disable SSLv2 and SSLv3 by default, they are deprecated
73 	// and should generally not be used according to the openssl docs
74 	SSL_CTX_set_options (ctx->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
75 
76 	return ctx;
77 }
78 
79 MONO_API MonoBtlsSslCtx *
mono_btls_ssl_ctx_up_ref(MonoBtlsSslCtx * ctx)80 mono_btls_ssl_ctx_up_ref (MonoBtlsSslCtx *ctx)
81 {
82 	CRYPTO_refcount_inc (&ctx->references);
83 	return ctx;
84 }
85 
86 MONO_API int
mono_btls_ssl_ctx_free(MonoBtlsSslCtx * ctx)87 mono_btls_ssl_ctx_free (MonoBtlsSslCtx *ctx)
88 {
89 	if (!CRYPTO_refcount_dec_and_test_zero (&ctx->references))
90 		return 0;
91 	SSL_CTX_free (ctx->ctx);
92 	ctx->instance = NULL;
93 	OPENSSL_free (ctx);
94 	return 1;
95 }
96 
97 MONO_API SSL_CTX *
mono_btls_ssl_ctx_get_ctx(MonoBtlsSslCtx * ctx)98 mono_btls_ssl_ctx_get_ctx (MonoBtlsSslCtx *ctx)
99 {
100 	return ctx->ctx;
101 }
102 
103 MONO_API void
mono_btls_ssl_ctx_set_debug_bio(MonoBtlsSslCtx * ctx,BIO * debug_bio)104 mono_btls_ssl_ctx_set_debug_bio (MonoBtlsSslCtx *ctx, BIO *debug_bio)
105 {
106 	if (debug_bio)
107 		ctx->debug_bio = BIO_up_ref(debug_bio);
108 	else
109 		ctx->debug_bio = NULL;
110 }
111 
112 MONO_API void
mono_btls_ssl_ctx_initialize(MonoBtlsSslCtx * ctx,void * instance)113 mono_btls_ssl_ctx_initialize (MonoBtlsSslCtx *ctx, void *instance)
114 {
115 	ctx->instance = instance;
116 }
117 
118 static int
cert_verify_callback(X509_STORE_CTX * storeCtx,void * arg)119 cert_verify_callback (X509_STORE_CTX *storeCtx, void *arg)
120 {
121 	MonoBtlsSslCtx *ptr = (MonoBtlsSslCtx*)arg;
122 	int ret;
123 
124 	debug_printf (ptr, "cert_verify_callback(): %p\n", ptr->verify_func);
125 	ret = X509_verify_cert (storeCtx);
126 	debug_printf (ptr, "cert_verify_callback() #1: %d\n", ret);
127 
128 	if (ptr->verify_func)
129 		ret = ptr->verify_func (ptr->instance, ret, storeCtx);
130 
131 	return ret;
132 }
133 
134 MONO_API void
mono_btls_ssl_ctx_set_cert_verify_callback(MonoBtlsSslCtx * ptr,MonoBtlsVerifyFunc func,int cert_required)135 mono_btls_ssl_ctx_set_cert_verify_callback (MonoBtlsSslCtx *ptr, MonoBtlsVerifyFunc func, int cert_required)
136 {
137 	int mode;
138 
139 	ptr->verify_func = func;
140 	SSL_CTX_set_cert_verify_callback (ptr->ctx, cert_verify_callback, ptr);
141 
142 	mode = SSL_VERIFY_PEER;
143 	if (cert_required)
144 		mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
145 
146 	SSL_CTX_set_verify (ptr->ctx, mode, NULL);
147 }
148 
149 static int
cert_select_callback(SSL * ssl,void * arg)150 cert_select_callback (SSL *ssl, void *arg)
151 {
152 	MonoBtlsSslCtx *ptr = (MonoBtlsSslCtx*)arg;
153 	int ret = 1;
154 
155 	debug_printf (ptr, "cert_select_callback(): %p\n", ptr->select_func);
156 	if (ptr->select_func)
157 		ret = ptr->select_func (ptr->instance);
158 	debug_printf (ptr, "cert_select_callback() #1: %d\n", ret);
159 
160 	return ret;
161 }
162 
163 MONO_API void
mono_btls_ssl_ctx_set_cert_select_callback(MonoBtlsSslCtx * ptr,MonoBtlsSelectFunc func)164 mono_btls_ssl_ctx_set_cert_select_callback (MonoBtlsSslCtx *ptr, MonoBtlsSelectFunc func)
165 {
166 	ptr->select_func = func;
167 	SSL_CTX_set_cert_cb (ptr->ctx, cert_select_callback, ptr);
168 }
169 
170 MONO_API X509_STORE *
mono_btls_ssl_ctx_peek_store(MonoBtlsSslCtx * ctx)171 mono_btls_ssl_ctx_peek_store (MonoBtlsSslCtx *ctx)
172 {
173 	return SSL_CTX_get_cert_store (ctx->ctx);
174 }
175 
176 MONO_API void
mono_btls_ssl_ctx_set_min_version(MonoBtlsSslCtx * ctx,int version)177 mono_btls_ssl_ctx_set_min_version (MonoBtlsSslCtx *ctx, int version)
178 {
179 	SSL_CTX_set_min_version (ctx->ctx, version);
180 }
181 
182 MONO_API void
mono_btls_ssl_ctx_set_max_version(MonoBtlsSslCtx * ctx,int version)183 mono_btls_ssl_ctx_set_max_version (MonoBtlsSslCtx *ctx, int version)
184 {
185 	SSL_CTX_set_max_version (ctx->ctx, version);
186 }
187 
188 MONO_API int
mono_btls_ssl_ctx_is_cipher_supported(MonoBtlsSslCtx * ctx,uint16_t value)189 mono_btls_ssl_ctx_is_cipher_supported (MonoBtlsSslCtx *ctx, uint16_t value)
190 {
191 	const SSL_CIPHER *cipher;
192 
193 	cipher = SSL_get_cipher_by_value (value);
194 	return cipher != NULL;
195 }
196 
197 MONO_API int
mono_btls_ssl_ctx_set_ciphers(MonoBtlsSslCtx * ctx,int count,const uint16_t * data,int allow_unsupported)198 mono_btls_ssl_ctx_set_ciphers (MonoBtlsSslCtx *ctx, int count, const uint16_t *data,
199 				   int allow_unsupported)
200 {
201 	STACK_OF(SSL_CIPHER) *ciphers = NULL;
202 	struct ssl_cipher_preference_list_st *pref_list = NULL;
203 	uint8_t *in_group_flags = NULL;
204 	int i;
205 
206 	ciphers = sk_SSL_CIPHER_new_null ();
207 	if (!ciphers)
208 		goto err;
209 
210 	for (i = 0; i < count; i++) {
211 		const SSL_CIPHER *cipher = SSL_get_cipher_by_value (data [i]);
212 		if (!cipher) {
213 			debug_printf (ctx, "mono_btls_ssl_ctx_set_ciphers(): unknown cipher %02x", data [i]);
214 			if (!allow_unsupported)
215 				goto err;
216 			continue;
217 		}
218 		if (!sk_SSL_CIPHER_push (ciphers, cipher))
219 			 goto err;
220 	}
221 
222 	pref_list = OPENSSL_malloc (sizeof (struct ssl_cipher_preference_list_st));
223 	if (!pref_list)
224 		goto err;
225 
226 	memset (pref_list, 0, sizeof (struct ssl_cipher_preference_list_st));
227 	pref_list->ciphers = sk_SSL_CIPHER_dup (ciphers);
228 	if (!pref_list->ciphers)
229 		goto err;
230 	pref_list->in_group_flags = OPENSSL_malloc (sk_SSL_CIPHER_num (ciphers));
231 	if (!pref_list->in_group_flags)
232 		goto err;
233 
234 	if (ctx->ctx->cipher_list)
235 		ssl_cipher_preference_list_free (ctx->ctx->cipher_list);
236 	if (ctx->ctx->cipher_list_by_id)
237 		sk_SSL_CIPHER_free (ctx->ctx->cipher_list_by_id);
238 	if (ctx->ctx->cipher_list_tls10) {
239 		ssl_cipher_preference_list_free (ctx->ctx->cipher_list_tls10);
240 		ctx->ctx->cipher_list_tls10 = NULL;
241 	}
242 	if (ctx->ctx->cipher_list_tls11) {
243 		ssl_cipher_preference_list_free (ctx->ctx->cipher_list_tls11);
244 		ctx->ctx->cipher_list_tls11 = NULL;
245 	}
246 
247 	ctx->ctx->cipher_list = pref_list;
248 	ctx->ctx->cipher_list_by_id = ciphers;
249 
250 	return (int)sk_SSL_CIPHER_num (ciphers);
251 
252 err:
253 	sk_SSL_CIPHER_free (ciphers);
254 	OPENSSL_free (pref_list);
255 	OPENSSL_free (in_group_flags);
256 	return 0;
257 }
258 
259 MONO_API int
mono_btls_ssl_ctx_set_verify_param(MonoBtlsSslCtx * ctx,const MonoBtlsX509VerifyParam * param)260 mono_btls_ssl_ctx_set_verify_param (MonoBtlsSslCtx *ctx, const MonoBtlsX509VerifyParam *param)
261 {
262 	return SSL_CTX_set1_param (ctx->ctx, mono_btls_x509_verify_param_peek_param (param));
263 }
264 
265