Merge pull request #3686 from lambdageek/dev-format-printf
[mono.git] / mono / btls / btls-ssl-ctx.c
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 int
35 mono_btls_ssl_ctx_is_debug_enabled (MonoBtlsSslCtx *ctx)
36 {
37         return ctx->debug_bio != NULL;
38 }
39
40 int
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 MonoBtlsSslCtx *
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         return ctx;
68 }
69
70 MonoBtlsSslCtx *
71 mono_btls_ssl_ctx_up_ref (MonoBtlsSslCtx *ctx)
72 {
73         CRYPTO_refcount_inc (&ctx->references);
74         return ctx;
75 }
76
77 int
78 mono_btls_ssl_ctx_free (MonoBtlsSslCtx *ctx)
79 {
80         if (!CRYPTO_refcount_dec_and_test_zero (&ctx->references))
81                 return 0;
82         SSL_CTX_free (ctx->ctx);
83         ctx->instance = NULL;
84         OPENSSL_free (ctx);
85         return 1;
86 }
87
88 SSL_CTX *
89 mono_btls_ssl_ctx_get_ctx (MonoBtlsSslCtx *ctx)
90 {
91         return ctx->ctx;
92 }
93
94 void
95 mono_btls_ssl_ctx_set_debug_bio (MonoBtlsSslCtx *ctx, BIO *debug_bio)
96 {
97         if (debug_bio)
98                 ctx->debug_bio = BIO_up_ref(debug_bio);
99         else
100                 ctx->debug_bio = NULL;
101 }
102
103 void
104 mono_btls_ssl_ctx_initialize (MonoBtlsSslCtx *ctx, void *instance)
105 {
106         ctx->instance = instance;
107 }
108
109 static int
110 cert_verify_callback (X509_STORE_CTX *storeCtx, void *arg)
111 {
112         MonoBtlsSslCtx *ptr = (MonoBtlsSslCtx*)arg;
113         int ret;
114
115         debug_printf (ptr, "cert_verify_callback(): %p\n", ptr->verify_func);
116         ret = X509_verify_cert (storeCtx);
117         debug_printf (ptr, "cert_verify_callback() #1: %d\n", ret);
118
119         if (ptr->verify_func)
120                 ret = ptr->verify_func (ptr->instance, ret, storeCtx);
121
122         return ret;
123 }
124
125 void
126 mono_btls_ssl_ctx_set_cert_verify_callback (MonoBtlsSslCtx *ptr, MonoBtlsVerifyFunc func, int cert_required)
127 {
128         int mode;
129
130         ptr->verify_func = func;
131         SSL_CTX_set_cert_verify_callback (ptr->ctx, cert_verify_callback, ptr);
132
133         mode = SSL_VERIFY_PEER;
134         if (cert_required)
135                 mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
136
137         SSL_CTX_set_verify (ptr->ctx, mode, NULL);
138 }
139
140 static int
141 cert_select_callback (SSL *ssl, void *arg)
142 {
143         MonoBtlsSslCtx *ptr = (MonoBtlsSslCtx*)arg;
144         int ret = 1;
145
146         debug_printf (ptr, "cert_select_callback(): %p\n", ptr->select_func);
147         if (ptr->select_func)
148                 ret = ptr->select_func (ptr->instance);
149         debug_printf (ptr, "cert_select_callback() #1: %d\n", ret);
150
151         return ret;
152 }
153
154 void
155 mono_btls_ssl_ctx_set_cert_select_callback (MonoBtlsSslCtx *ptr, MonoBtlsSelectFunc func)
156 {
157         ptr->select_func = func;
158         SSL_CTX_set_cert_cb (ptr->ctx, cert_select_callback, ptr);
159 }
160
161 X509_STORE *
162 mono_btls_ssl_ctx_peek_store (MonoBtlsSslCtx *ctx)
163 {
164         return SSL_CTX_get_cert_store (ctx->ctx);
165 }
166
167 void
168 mono_btls_ssl_ctx_set_min_version (MonoBtlsSslCtx *ctx, int version)
169 {
170         SSL_CTX_set_min_version (ctx->ctx, version);
171 }
172
173 void
174 mono_btls_ssl_ctx_set_max_version (MonoBtlsSslCtx *ctx, int version)
175 {
176         SSL_CTX_set_max_version (ctx->ctx, version);
177 }
178
179 int
180 mono_btls_ssl_ctx_is_cipher_supported (MonoBtlsSslCtx *ctx, uint16_t value)
181 {
182         const SSL_CIPHER *cipher;
183
184         cipher = SSL_get_cipher_by_value (value);
185         return cipher != NULL;
186 }
187
188 int
189 mono_btls_ssl_ctx_set_ciphers (MonoBtlsSslCtx *ctx, int count, const uint16_t *data,
190                                    int allow_unsupported)
191 {
192         STACK_OF(SSL_CIPHER) *ciphers = NULL;
193         struct ssl_cipher_preference_list_st *pref_list = NULL;
194         uint8_t *in_group_flags = NULL;
195         int i;
196
197         ciphers = sk_SSL_CIPHER_new_null ();
198         if (!ciphers)
199                 goto err;
200
201         for (i = 0; i < count; i++) {
202                 const SSL_CIPHER *cipher = SSL_get_cipher_by_value (data [i]);
203                 if (!cipher) {
204                         debug_printf (ctx, "mono_btls_ssl_ctx_set_ciphers(): unknown cipher %02x", data [i]);
205                         if (!allow_unsupported)
206                                 goto err;
207                         continue;
208                 }
209                 if (!sk_SSL_CIPHER_push (ciphers, cipher))
210                          goto err;
211         }
212
213         pref_list = OPENSSL_malloc (sizeof (struct ssl_cipher_preference_list_st));
214         if (!pref_list)
215                 goto err;
216
217         memset (pref_list, 0, sizeof (struct ssl_cipher_preference_list_st));
218         pref_list->ciphers = sk_SSL_CIPHER_dup (ciphers);
219         if (!pref_list->ciphers)
220                 goto err;
221         pref_list->in_group_flags = OPENSSL_malloc (sk_SSL_CIPHER_num (ciphers));
222         if (!pref_list->in_group_flags)
223                 goto err;
224
225         if (ctx->ctx->cipher_list)
226                 ssl_cipher_preference_list_free (ctx->ctx->cipher_list);
227         if (ctx->ctx->cipher_list_by_id)
228                 sk_SSL_CIPHER_free (ctx->ctx->cipher_list_by_id);
229         if (ctx->ctx->cipher_list_tls10) {
230                 ssl_cipher_preference_list_free (ctx->ctx->cipher_list_tls10);
231                 ctx->ctx->cipher_list_tls10 = NULL;
232         }
233         if (ctx->ctx->cipher_list_tls11) {
234                 ssl_cipher_preference_list_free (ctx->ctx->cipher_list_tls11);
235                 ctx->ctx->cipher_list_tls11 = NULL;
236         }
237
238         ctx->ctx->cipher_list = pref_list;
239         ctx->ctx->cipher_list_by_id = ciphers;
240
241         return (int)sk_SSL_CIPHER_num (ciphers);
242
243 err:
244         sk_SSL_CIPHER_free (ciphers);
245         OPENSSL_free (pref_list);
246         OPENSSL_free (in_group_flags);
247         return 0;
248 }
249
250 int
251 mono_btls_ssl_ctx_set_verify_param (MonoBtlsSslCtx *ctx, const MonoBtlsX509VerifyParam *param)
252 {
253         return SSL_CTX_set1_param (ctx->ctx, mono_btls_x509_verify_param_peek_param (param));
254 }
255