comparison src/lib-ssl-iostream/iostream-openssl-context.c @ 12616:bd23d4e10fa1

Added lib-ssl-iostream for handling SSL connections more easily.
author Timo Sirainen <tss@iki.fi>
date Mon, 31 Jan 2011 18:40:27 +0200
parents
children 733ac4aba089
comparison
equal deleted inserted replaced
12615:3dde816d945d 12616:bd23d4e10fa1
1 /* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
2
3 #include "lib.h"
4 #include "safe-memset.h"
5 #include "iostream-openssl.h"
6
7 #include <openssl/crypto.h>
8 #include <openssl/x509.h>
9 #include <openssl/pem.h>
10 #include <openssl/ssl.h>
11 #include <openssl/err.h>
12 #include <openssl/rand.h>
13
14 struct ssl_iostream_password_context {
15 const char *password;
16 const char *key_source;
17 };
18
19 static bool ssl_global_initialized = FALSE;
20 int dovecot_ssl_extdata_index;
21
22 static void ssl_iostream_init_global(void);
23
24 const char *ssl_iostream_error(void)
25 {
26 unsigned long err;
27 char *buf;
28 size_t err_size = 256;
29
30 err = ERR_get_error();
31 if (err == 0) {
32 if (errno != 0)
33 return strerror(errno);
34 return "Unknown error";
35 }
36 if (ERR_GET_REASON(err) == ERR_R_MALLOC_FAILURE)
37 i_fatal_status(FATAL_OUTOFMEM, "OpenSSL malloc() failed");
38
39 buf = t_malloc(err_size);
40 buf[err_size-1] = '\0';
41 ERR_error_string_n(err, buf, err_size-1);
42 return buf;
43 }
44
45 const char *ssl_iostream_key_load_error(void)
46 {
47 unsigned long err = ERR_peek_error();
48
49 if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
50 ERR_GET_REASON(err) == X509_R_KEY_VALUES_MISMATCH)
51 return "Key is for a different cert than ssl_cert";
52 else
53 return ssl_iostream_error();
54 }
55
56 static RSA *ssl_gen_rsa_key(SSL *ssl ATTR_UNUSED,
57 int is_export ATTR_UNUSED, int keylength)
58 {
59 return RSA_generate_key(keylength, RSA_F4, NULL, NULL);
60 }
61
62 static DH *ssl_tmp_dh_callback(SSL *ssl ATTR_UNUSED,
63 int is_export, int keylength)
64 {
65 struct ssl_iostream *ssl_io;
66
67 ssl_io = SSL_get_ex_data(ssl, dovecot_ssl_extdata_index);
68 /* Well, I'm not exactly sure why the logic in here is this.
69 It's the same as in Postfix, so it can't be too wrong. */
70 if (is_export && keylength == 512 && ssl_io->ctx->dh_512 != NULL)
71 return ssl_io->ctx->dh_512;
72 else
73 return ssl_io->ctx->dh_1024;
74 }
75
76 static int
77 pem_password_callback(char *buf, int size, int rwflag ATTR_UNUSED,
78 void *userdata)
79 {
80 struct ssl_iostream_password_context *ctx = userdata;
81
82 if (ctx->password == NULL) {
83 i_error("%s: SSL private key file is password protected, "
84 "but password isn't given", ctx->key_source);
85 return 0;
86 }
87
88 if (i_strocpy(buf, userdata, size) < 0) {
89 i_error("%s: SSL private key password is too long",
90 ctx->key_source);
91 return 0;
92 }
93 return strlen(buf);
94 }
95
96 int ssl_iostream_load_key(const struct ssl_iostream_settings *set,
97 const char *key_source, EVP_PKEY **pkey_r)
98 {
99 struct ssl_iostream_password_context ctx;
100 EVP_PKEY *pkey;
101 BIO *bio;
102 char *key;
103
104 key = t_strdup_noconst(set->key);
105 bio = BIO_new_mem_buf(key, strlen(key));
106 if (bio == NULL) {
107 i_error("BIO_new_mem_buf() failed: %s", ssl_iostream_error());
108 safe_memset(key, 0, strlen(key));
109 return -1;
110 }
111
112 ctx.password = set->key_password;
113 ctx.key_source = key_source;
114
115 pkey = PEM_read_bio_PrivateKey(bio, NULL, pem_password_callback, &ctx);
116 if (pkey == NULL) {
117 i_error("%s: Couldn't parse private SSL key: %s",
118 key_source, ssl_iostream_error());
119 }
120 BIO_free(bio);
121
122 safe_memset(key, 0, strlen(key));
123 *pkey_r = pkey;
124 return pkey == NULL ? -1 : 0;
125 }
126
127 static int
128 ssl_iostream_ctx_use_key(struct ssl_iostream_context *ctx,
129 const struct ssl_iostream_settings *set)
130 {
131 EVP_PKEY *pkey;
132 int ret = 0;
133
134 if (ssl_iostream_load_key(set, ctx->source, &pkey) < 0)
135 return -1;
136 if (!SSL_CTX_use_PrivateKey(ctx->ssl_ctx, pkey)) {
137 i_error("%s: Can't load SSL private key: %s",
138 ctx->source, ssl_iostream_key_load_error());
139 ret = -1;
140 }
141 EVP_PKEY_free(pkey);
142 return ret;
143 }
144
145 static bool is_pem_key(const char *cert)
146 {
147 return strstr(cert, "PRIVATE KEY---") != NULL;
148 }
149
150 const char *ssl_iostream_get_use_certificate_error(const char *cert)
151 {
152 unsigned long err;
153
154 err = ERR_peek_error();
155 if (ERR_GET_LIB(err) != ERR_LIB_PEM ||
156 ERR_GET_REASON(err) != PEM_R_NO_START_LINE)
157 return ssl_iostream_error();
158 else if (is_pem_key(cert)) {
159 return "The file contains a private key "
160 "(you've mixed ssl_cert and ssl_key settings)";
161 } else {
162 return "There is no certificate.";
163 }
164 }
165
166 static int ssl_ctx_use_certificate_chain(SSL_CTX *ctx, const char *cert)
167 {
168 /* mostly just copy&pasted from SSL_CTX_use_certificate_chain_file() */
169 BIO *in;
170 X509 *x;
171 int ret = 0;
172
173 in = BIO_new_mem_buf(t_strdup_noconst(cert), strlen(cert));
174 if (in == NULL)
175 i_fatal("BIO_new_mem_buf() failed");
176
177 x = PEM_read_bio_X509(in, NULL, NULL, NULL);
178 if (x == NULL)
179 goto end;
180
181 ret = SSL_CTX_use_certificate(ctx, x);
182 if (ERR_peek_error() != 0)
183 ret = 0;
184
185 if (ret != 0) {
186 /* If we could set up our certificate, now proceed to
187 * the CA certificates.
188 */
189 X509 *ca;
190 int r;
191 unsigned long err;
192
193 while ((ca = PEM_read_bio_X509(in,NULL,NULL,NULL)) != NULL) {
194 r = SSL_CTX_add_extra_chain_cert(ctx, ca);
195 if (!r) {
196 X509_free(ca);
197 ret = 0;
198 goto end;
199 }
200 }
201 /* When the while loop ends, it's usually just EOF. */
202 err = ERR_peek_last_error();
203 if (ERR_GET_LIB(err) == ERR_LIB_PEM && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)
204 ERR_clear_error();
205 else
206 ret = 0; /* some real error */
207 }
208
209 end:
210 if (x != NULL) X509_free(x);
211 BIO_free(in);
212 return ret;
213 }
214
215 static int load_ca(X509_STORE *store, const char *ca,
216 STACK_OF(X509_NAME) **xnames_r)
217 {
218 /* mostly just copy&pasted from X509_load_cert_crl_file() */
219 STACK_OF(X509_INFO) *inf;
220 STACK_OF(X509_NAME) *xnames;
221 X509_INFO *itmp;
222 X509_NAME *xname;
223 BIO *bio;
224 int i;
225
226 bio = BIO_new_mem_buf(t_strdup_noconst(ca), strlen(ca));
227 if (bio == NULL)
228 i_fatal("BIO_new_mem_buf() failed");
229 inf = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
230 BIO_free(bio);
231
232 if (inf == NULL)
233 return -1;
234
235 xnames = sk_X509_NAME_new_null();
236 if (xnames == NULL)
237 i_fatal("sk_X509_NAME_new_null() failed");
238 for(i = 0; i < sk_X509_INFO_num(inf); i++) {
239 itmp = sk_X509_INFO_value(inf, i);
240 if(itmp->x509) {
241 X509_STORE_add_cert(store, itmp->x509);
242 xname = X509_get_subject_name(itmp->x509);
243 if (xname != NULL)
244 xname = X509_NAME_dup(xname);
245 if (xname != NULL)
246 sk_X509_NAME_push(xnames, xname);
247 }
248 if(itmp->crl)
249 X509_STORE_add_crl(store, itmp->crl);
250 }
251 sk_X509_INFO_pop_free(inf, X509_INFO_free);
252 *xnames_r = xnames;
253 return 0;
254 }
255
256 static int
257 ssl_iostream_ctx_verify_remote_cert(struct ssl_iostream_context *ctx,
258 STACK_OF(X509_NAME) *ca_names)
259 {
260 #if OPENSSL_VERSION_NUMBER >= 0x00907000L
261 X509_STORE *store;
262
263 store = SSL_CTX_get_cert_store(ctx->ssl_ctx);
264 X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
265 X509_V_FLAG_CRL_CHECK_ALL);
266 #endif
267
268 SSL_CTX_set_client_CA_list(ctx->ssl_ctx, ca_names);
269 return 0;
270 }
271
272 static struct ssl_iostream_settings *
273 ssl_iostream_settings_dup(pool_t pool,
274 const struct ssl_iostream_settings *old_set)
275 {
276 struct ssl_iostream_settings *new_set;
277
278 new_set = p_new(pool, struct ssl_iostream_settings, 1);
279 new_set->cipher_list = p_strdup(pool, old_set->cipher_list);
280 new_set->cert = p_strdup(pool, old_set->cert);
281 new_set->key = p_strdup(pool, old_set->key);
282 new_set->key_password = p_strdup(pool, old_set->key_password);
283
284 new_set->verbose = old_set->verbose;
285 return new_set;
286 }
287
288 static int
289 ssl_iostream_context_set(struct ssl_iostream_context *ctx,
290 const struct ssl_iostream_settings *set)
291 {
292 X509_STORE *store;
293 STACK_OF(X509_NAME) *xnames = NULL;
294
295 ctx->set = ssl_iostream_settings_dup(ctx->pool, set);
296 if (set->cipher_list != NULL &&
297 !SSL_CTX_set_cipher_list(ctx->ssl_ctx, set->cipher_list)) {
298 i_error("%s: Can't set cipher list to '%s': %s",
299 ctx->source, set->cipher_list,
300 ssl_iostream_error());
301 return -1;
302 }
303
304 if (set->cert != NULL &&
305 ssl_ctx_use_certificate_chain(ctx->ssl_ctx, set->cert) < 0) {
306 i_error("%s: Can't load SSL certificate: %s", ctx->source,
307 ssl_iostream_get_use_certificate_error(set->cert));
308 }
309 if (set->key != NULL) {
310 if (ssl_iostream_ctx_use_key(ctx, set) < 0)
311 return -1;
312 }
313
314 /* set trusted CA certs */
315 if (!set->verify_remote_cert) {
316 /* no CA */
317 } else if (set->ca != NULL) {
318 store = SSL_CTX_get_cert_store(ctx->ssl_ctx);
319 if (load_ca(store, set->ca, &xnames) < 0) {
320 i_error("%s: Couldn't parse ssl_ca: %s", ctx->source,
321 ssl_iostream_error());
322 return -1;
323 }
324 if (ssl_iostream_ctx_verify_remote_cert(ctx, xnames) < 0)
325 return -1;
326 } else if (set->ca_dir != NULL) {
327 if (!SSL_CTX_load_verify_locations(ctx->ssl_ctx, NULL,
328 set->ca_dir)) {
329 i_error("%s: Can't load CA certs from directory %s: %s",
330 ctx->source, set->ca_dir, ssl_iostream_error());
331 return -1;
332 }
333 } else {
334 i_error("%s: Can't verify remote certs without CA",
335 ctx->source);
336 return -1;
337 }
338
339 if (set->cert_username_field != NULL) {
340 ctx->username_nid = OBJ_txt2nid(set->cert_username_field);
341 if (ctx->username_nid == NID_undef) {
342 i_error("%s: Invalid cert_username_field: %s",
343 ctx->source, set->cert_username_field);
344 }
345 }
346 return 0;
347 }
348
349 static int
350 ssl_iostream_context_init_common(struct ssl_iostream_context *ctx,
351 const char *source,
352 const struct ssl_iostream_settings *set)
353 {
354 ctx->pool = pool_alloconly_create("ssl iostream context", 4096);
355 ctx->source = p_strdup(ctx->pool, source);
356
357 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
358 if (SSL_CTX_need_tmp_RSA(ctx->ssl_ctx))
359 SSL_CTX_set_tmp_rsa_callback(ctx->ssl_ctx, ssl_gen_rsa_key);
360 SSL_CTX_set_tmp_dh_callback(ctx->ssl_ctx, ssl_tmp_dh_callback);
361
362 return ssl_iostream_context_set(ctx, set);
363 }
364
365 int ssl_iostream_context_init_client(const char *source,
366 const struct ssl_iostream_settings *set,
367 struct ssl_iostream_context **ctx_r)
368 {
369 struct ssl_iostream_context *ctx;
370 SSL_CTX *ssl_ctx;
371
372 ssl_iostream_init_global();
373 if ((ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
374 i_error("SSL_CTX_new() failed: %s", ssl_iostream_error());
375 return -1;
376 }
377
378 ctx = i_new(struct ssl_iostream_context, 1);
379 ctx->ssl_ctx = ssl_ctx;
380 ctx->client_ctx = TRUE;
381 if (ssl_iostream_context_init_common(ctx, source, set) < 0) {
382 ssl_iostream_context_deinit(&ctx);
383 return -1;
384 }
385 *ctx_r = ctx;
386 return 0;
387 }
388
389 int ssl_iostream_context_init_server(const char *source,
390 const struct ssl_iostream_settings *set,
391 struct ssl_iostream_context **ctx_r)
392 {
393 struct ssl_iostream_context *ctx;
394 SSL_CTX *ssl_ctx;
395
396 ssl_iostream_init_global();
397 if ((ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
398 i_error("SSL_CTX_new() failed: %s", ssl_iostream_error());
399 return -1;
400 }
401
402 ctx = i_new(struct ssl_iostream_context, 1);
403 ctx->ssl_ctx = ssl_ctx;
404 if (ssl_iostream_context_init_common(ctx, source, set) < 0) {
405 ssl_iostream_context_deinit(&ctx);
406 return -1;
407 }
408 *ctx_r = ctx;
409 return 0;
410 }
411
412 void ssl_iostream_context_deinit(struct ssl_iostream_context **_ctx)
413 {
414 struct ssl_iostream_context *ctx = *_ctx;
415
416 *_ctx = NULL;
417 SSL_CTX_free(ctx->ssl_ctx);
418 ssl_iostream_context_free_params(ctx);
419 pool_unref(&ctx->pool);
420 i_free(ctx);
421 }
422
423 static void ssl_iostream_deinit_global(void)
424 {
425 EVP_cleanup();
426 ERR_free_strings();
427 }
428
429 static void ssl_iostream_init_global(void)
430 {
431 static char dovecot[] = "dovecot";
432 unsigned char buf;
433
434 if (ssl_global_initialized)
435 return;
436
437 atexit(ssl_iostream_deinit_global);
438 ssl_global_initialized = TRUE;
439 SSL_library_init();
440 SSL_load_error_strings();
441
442 dovecot_ssl_extdata_index =
443 SSL_get_ex_new_index(0, dovecot, NULL, NULL, NULL);
444
445 /* PRNG initialization might want to use /dev/urandom, make sure it
446 does it before chrooting. We might not have enough entropy at
447 the first try, so this function may fail. It's still been
448 initialized though. */
449 (void)RAND_bytes(&buf, 1);
450 }