diff options
Diffstat (limited to 'vchat-tls.c')
-rwxr-xr-x | vchat-tls.c | 308 |
1 files changed, 106 insertions, 202 deletions
diff --git a/vchat-tls.c b/vchat-tls.c index 4131a23..205f0e0 100755 --- a/vchat-tls.c +++ b/vchat-tls.c | |||
@@ -20,6 +20,62 @@ | |||
20 | #include <string.h> | 20 | #include <string.h> |
21 | #include <assert.h> | 21 | #include <assert.h> |
22 | 22 | ||
23 | #include <readline/readline.h> | ||
24 | |||
25 | #include "vchat.h" | ||
26 | #include "vchat-tls.h" | ||
27 | |||
28 | const char *vchat_tls_version = "vchat-tls.c $Id$"; | ||
29 | const char *vchat_tls_version_external = "Unknown implementation; version unknown"; | ||
30 | |||
31 | void vc_cleanup_x509store(vc_x509store_t *store) | ||
32 | { | ||
33 | free(store->cafile); | ||
34 | free(store->capath); | ||
35 | free(store->crlfile); | ||
36 | free(store->certfile); | ||
37 | free(store->keyfile); | ||
38 | memset(store, 0, sizeof(vc_x509store_t)); | ||
39 | } | ||
40 | |||
41 | void vc_x509store_setflags(vc_x509store_t *store, int flags) { store->flags |= flags; } | ||
42 | void vc_x509store_clearflags(vc_x509store_t *store, int flags) { store->flags &= ~flags; } | ||
43 | void vc_x509store_set_pkeycb(vc_x509store_t *store, vc_askpass_cb_t callback) { store->askpass_callback = callback; } | ||
44 | |||
45 | void vc_x509store_setcafile(vc_x509store_t *store, char *file) | ||
46 | { | ||
47 | free(store->cafile); | ||
48 | store->cafile = ( file ? strdup(file) : 0 ); | ||
49 | store->flags |= VC_X509S_USE_CAFILE; | ||
50 | } | ||
51 | |||
52 | void vc_x509store_setcapath(vc_x509store_t *store, char *path) | ||
53 | { | ||
54 | free(store->capath); | ||
55 | store->capath = ( path ? strdup(path) : 0 ); | ||
56 | } | ||
57 | |||
58 | void vc_x509store_setcrlfile(vc_x509store_t *store, char *file) | ||
59 | { | ||
60 | free(store->crlfile); | ||
61 | store->crlfile = ( file ? strdup(file) : 0 ); | ||
62 | } | ||
63 | |||
64 | void vc_x509store_setkeyfile(vc_x509store_t *store, char *file) | ||
65 | { | ||
66 | free(store->keyfile); | ||
67 | store->keyfile = ( file ? strdup(file) : 0 ); | ||
68 | } | ||
69 | |||
70 | void vc_x509store_setcertfile(vc_x509store_t *store, char *file) | ||
71 | { | ||
72 | free(store->certfile); | ||
73 | store->certfile = ( file ? strdup(file) : 0 ); | ||
74 | store->flags |= VC_X509S_USE_CERTIFICATE; | ||
75 | } | ||
76 | |||
77 | //// OPENSSL SPECIFIC | ||
78 | |||
23 | #include <openssl/err.h> | 79 | #include <openssl/err.h> |
24 | #include <openssl/ssl.h> | 80 | #include <openssl/ssl.h> |
25 | #include <openssl/bio.h> | 81 | #include <openssl/bio.h> |
@@ -28,77 +84,53 @@ | |||
28 | #include <openssl/x509v3.h> | 84 | #include <openssl/x509v3.h> |
29 | #include <openssl/conf.h> | 85 | #include <openssl/conf.h> |
30 | 86 | ||
31 | #include <readline/readline.h> | 87 | void vchat_tls_get_version_external() |
88 | { | ||
89 | snprintf(tmpstr, sizeof(tmpstr), "OpenSSL %s with %s", SSLeay_version(SSLEAY_VERSION), SSLeay_version(SSLEAY_CFLAGS)); | ||
90 | vchat_tls_version_external = strdup(tmpstr); | ||
91 | } | ||
32 | 92 | ||
33 | #include "vchat.h" | 93 | /* Helpers to work with vc_x509store_t used by all tls libs */ |
34 | #include "vchat-tls.h" | 94 | void vc_init_x509store(vc_x509store_t *store) |
95 | { | ||
96 | static int sslinit; | ||
97 | if (!sslinit++) { | ||
98 | SSL_library_init (); | ||
99 | SSL_load_error_strings(); | ||
100 | } | ||
101 | memset(store, 0, sizeof(vc_x509store_t)); | ||
35 | 102 | ||
36 | const char *vchat_ssl_version = "vchat-tlsl.c $Id$"; | 103 | /* We want to make verifying the peer the default */ |
104 | store->flags |= VC_X509S_SSL_VERIFY_PEER; | ||
105 | } | ||
37 | 106 | ||
38 | /* connection BIO for openssl */ | 107 | /* connection BIO for openssl */ |
39 | static BIO *server_conn = NULL; | 108 | static BIO *server_conn = NULL; |
40 | 109 | ||
41 | typedef int (*vc_x509verify_cb_t)(int, X509_STORE_CTX *); | ||
42 | struct vc_x509store_t { | ||
43 | char *cafile; | ||
44 | char *capath; | ||
45 | char *crlfile; | ||
46 | vc_x509verify_cb_t callback; | ||
47 | vc_askpass_cb_t askpass_callback; | ||
48 | STACK_OF(X509) *certs; | ||
49 | STACK_OF(X509_CRL) *crls; | ||
50 | char *use_certfile; | ||
51 | STACK_OF(X509) *use_certs; | ||
52 | char *use_keyfile; | ||
53 | EVP_PKEY *use_key; | ||
54 | int flags; | ||
55 | }; | ||
56 | |||
57 | static SSL_CTX * vc_create_sslctx( vc_x509store_t *vc_store ); | 110 | static SSL_CTX * vc_create_sslctx( vc_x509store_t *vc_store ); |
58 | static int vc_verify_callback(int, X509_STORE_CTX *); | 111 | static int vc_verify_callback(int, X509_STORE_CTX *); |
59 | static X509_STORE * vc_x509store_create(vc_x509store_t *); | 112 | static X509_STORE * vc_x509store_create(vc_x509store_t *); |
60 | static void vc_x509store_clearflags(vc_x509store_t *, int); | ||
61 | static void vc_x509store_setcapath(vc_x509store_t *, char *); | ||
62 | static void vc_x509store_setcrlfile(vc_x509store_t *, char *); | ||
63 | static void vc_x509store_addcert(vc_x509store_t *, X509 *); | ||
64 | static void vc_x509store_setcb(vc_x509store_t *, vc_x509verify_cb_t); | ||
65 | |||
66 | #define VC_CTX_ERR_EXIT(se, cx) do { \ | ||
67 | snprintf(tmpstr, TMPSTRSIZE, "CREATE CTX: %s", \ | ||
68 | ERR_error_string (ERR_get_error (), NULL)); \ | ||
69 | writecf(FS_ERR, tmpstr); \ | ||
70 | if(se) X509_STORE_free(se); \ | ||
71 | if(cx) SSL_CTX_free(cx); \ | ||
72 | return(0); \ | ||
73 | } while(0) | ||
74 | |||
75 | #define VC_SETCERT_ERR_EXIT(se, cx, err) do { \ | ||
76 | snprintf(tmpstr, TMPSTRSIZE, "CREATE CTX: %s", err); \ | ||
77 | writecf(FS_ERR, tmpstr); \ | ||
78 | if(se) X509_STORE_free(se); \ | ||
79 | if(cx) SSL_CTX_free(cx); \ | ||
80 | return(NULL); \ | ||
81 | } while(0) | ||
82 | 113 | ||
83 | static SSL_CTX * vc_create_sslctx( vc_x509store_t *vc_store ) | 114 | static SSL_CTX * vc_create_sslctx( vc_x509store_t *vc_store ) |
84 | { | 115 | { |
85 | int i = 0; | 116 | int flags = 0; |
86 | int n = 0; | ||
87 | int flags = 0; | ||
88 | int r = 0; | ||
89 | SSL_CTX *ctx = NULL; | ||
90 | X509_STORE *store = NULL; | ||
91 | vc_x509verify_cb_t verify_callback = NULL; | ||
92 | 117 | ||
93 | /* Explicitly use TLSv1 (or maybe later) */ | 118 | /* Explicitly use TLSv1 (or maybe later) */ |
94 | if( !(ctx = SSL_CTX_new(TLS_client_method())) ) | 119 | SSL_CTX *ctx = SSL_CTX_new(TLS_client_method()); |
95 | VC_CTX_ERR_EXIT(store, ctx); | 120 | X509_STORE *store = vc_x509store_create(vc_store); |
96 | 121 | ||
97 | if( !(store = vc_x509store_create(vc_store)) ) | 122 | if (!ctx || !store) { |
98 | VC_CTX_ERR_EXIT(store, ctx); | 123 | snprintf(tmpstr, sizeof(tmpstr), "CREATE CTX: %s",ERR_error_string (ERR_get_error (), NULL)); |
124 | writecf(FS_ERR, tmpstr); | ||
125 | if (store) | ||
126 | X509_STORE_free(store); | ||
127 | if (ctx) | ||
128 | SSL_CTX_free(ctx); | ||
129 | return NULL; | ||
130 | } | ||
99 | 131 | ||
100 | SSL_CTX_set_cert_store(ctx, store); | 132 | SSL_CTX_set_cert_store(ctx, store); |
101 | store = NULL; | 133 | |
102 | /* Disable some insecure protocols explicitly */ | 134 | /* Disable some insecure protocols explicitly */ |
103 | SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); | 135 | SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); |
104 | if (getstroption(CF_CIPHERSUITE)) | 136 | if (getstroption(CF_CIPHERSUITE)) |
@@ -108,14 +140,10 @@ static SSL_CTX * vc_create_sslctx( vc_x509store_t *vc_store ) | |||
108 | 140 | ||
109 | SSL_CTX_set_verify_depth (ctx, getintoption(CF_VERIFYSSL)); | 141 | SSL_CTX_set_verify_depth (ctx, getintoption(CF_VERIFYSSL)); |
110 | 142 | ||
111 | if( !(verify_callback = vc_store->callback) ) | ||
112 | verify_callback = vc_verify_callback; | ||
113 | |||
114 | if( !(vc_store->flags & VC_X509S_SSL_VERIFY_MASK) ) { | 143 | if( !(vc_store->flags & VC_X509S_SSL_VERIFY_MASK) ) { |
115 | writecf(FS_DBG, tmpstr); | 144 | writecf(FS_DBG, tmpstr); |
116 | flags = SSL_VERIFY_NONE; | 145 | flags = SSL_VERIFY_NONE; |
117 | } | 146 | } else { |
118 | else { | ||
119 | if(vc_store->flags & VC_X509S_SSL_VERIFY_PEER) | 147 | if(vc_store->flags & VC_X509S_SSL_VERIFY_PEER) |
120 | flags |= SSL_VERIFY_PEER; | 148 | flags |= SSL_VERIFY_PEER; |
121 | if(vc_store->flags & VC_X509S_SSL_VERIFY_FAIL_IF_NO_PEER_CERT) | 149 | if(vc_store->flags & VC_X509S_SSL_VERIFY_FAIL_IF_NO_PEER_CERT) |
@@ -124,29 +152,25 @@ static SSL_CTX * vc_create_sslctx( vc_x509store_t *vc_store ) | |||
124 | flags |= SSL_VERIFY_CLIENT_ONCE; | 152 | flags |= SSL_VERIFY_CLIENT_ONCE; |
125 | } | 153 | } |
126 | 154 | ||
127 | SSL_CTX_set_verify(ctx, flags, verify_callback); | 155 | SSL_CTX_set_verify(ctx, flags, vc_verify_callback); |
128 | 156 | ||
129 | if(vc_store->flags & VC_X509S_USE_CERTIFICATE) { | 157 | if(vc_store->flags & VC_X509S_USE_CERTIFICATE) { |
130 | if(vc_store->use_certfile) | 158 | int r = 0; |
131 | SSL_CTX_use_certificate_chain_file(ctx, vc_store->use_certfile); | 159 | if(vc_store->certfile) |
132 | else { | 160 | SSL_CTX_use_certificate_chain_file(ctx, vc_store->certfile); |
133 | SSL_CTX_use_certificate(ctx, | ||
134 | sk_X509_value(vc_store->use_certs, 0)); | ||
135 | for(i=0,n=sk_X509_num(vc_store->use_certs); i<n; i++) | ||
136 | SSL_CTX_add_extra_chain_cert(ctx, | ||
137 | sk_X509_value(vc_store->use_certs, i)); | ||
138 | } | ||
139 | 161 | ||
140 | SSL_CTX_set_default_passwd_cb(ctx, vc_store->askpass_callback); | 162 | SSL_CTX_set_default_passwd_cb(ctx, vc_store->askpass_callback); |
141 | 163 | ||
142 | if(vc_store->use_keyfile) { | 164 | if(vc_store->keyfile) |
143 | r=SSL_CTX_use_PrivateKey_file(ctx, vc_store->use_keyfile, | 165 | r=SSL_CTX_use_PrivateKey_file(ctx, vc_store->keyfile, |
144 | SSL_FILETYPE_PEM); | 166 | SSL_FILETYPE_PEM); |
145 | } else if(vc_store->use_key) | ||
146 | r=SSL_CTX_use_PrivateKey(ctx, vc_store->use_key); | ||
147 | 167 | ||
148 | if( r!=1 || !SSL_CTX_check_private_key(ctx)) | 168 | if( r!=1 || !SSL_CTX_check_private_key(ctx)) { |
149 | VC_SETCERT_ERR_EXIT(store, ctx, "Load private key failed"); | 169 | snprintf(tmpstr, sizeof(tmpstr), "CREATE CTX: Load private key failed"); |
170 | writecf(FS_ERR, tmpstr); | ||
171 | SSL_CTX_free(ctx); | ||
172 | return NULL; | ||
173 | } | ||
150 | } | 174 | } |
151 | 175 | ||
152 | SSL_CTX_set_app_data(ctx, vc_store); | 176 | SSL_CTX_set_app_data(ctx, vc_store); |
@@ -298,29 +322,24 @@ all_errors: | |||
298 | 322 | ||
299 | X509_STORE *vc_x509store_create(vc_x509store_t *vc_store) | 323 | X509_STORE *vc_x509store_create(vc_x509store_t *vc_store) |
300 | { | 324 | { |
301 | int i = 0; | ||
302 | int n = 0; | ||
303 | X509_STORE *store = NULL; | 325 | X509_STORE *store = NULL; |
304 | X509_LOOKUP *lookup = NULL; | 326 | X509_LOOKUP *lookup = NULL; |
305 | 327 | ||
306 | store = X509_STORE_new(); | 328 | store = X509_STORE_new(); |
307 | 329 | ||
308 | if(vc_store->callback) | 330 | X509_STORE_set_verify_cb_func(store, vc_verify_callback); |
309 | X509_STORE_set_verify_cb_func(store, vc_store->callback); | ||
310 | else | ||
311 | X509_STORE_set_verify_cb_func(store, vc_verify_callback); | ||
312 | 331 | ||
313 | if( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) ) | 332 | if( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) ) |
314 | VC_STORE_ERR_EXIT(store); | 333 | VC_STORE_ERR_EXIT(store); |
315 | 334 | ||
316 | if(!vc_store->cafile) { | 335 | if (!vc_store->cafile) { |
317 | if( !(vc_store->flags & VC_X509S_NODEF_CAFILE) ) | 336 | if( !(vc_store->flags & VC_X509S_USE_CAFILE) ) |
318 | X509_LOOKUP_load_file(lookup, 0, X509_FILETYPE_DEFAULT); | 337 | X509_LOOKUP_load_file(lookup, 0, X509_FILETYPE_DEFAULT); |
319 | } else if( !X509_LOOKUP_load_file(lookup, vc_store->cafile, | 338 | } else if( !X509_LOOKUP_load_file(lookup, vc_store->cafile, |
320 | X509_FILETYPE_PEM) ) | 339 | X509_FILETYPE_PEM) ) |
321 | VC_STORE_ERR_EXIT(store); | 340 | VC_STORE_ERR_EXIT(store); |
322 | 341 | ||
323 | if(vc_store->crlfile) { | 342 | if (vc_store->crlfile) { |
324 | if( !X509_load_crl_file(lookup, vc_store->crlfile, | 343 | if( !X509_load_crl_file(lookup, vc_store->crlfile, |
325 | X509_FILETYPE_PEM) ) | 344 | X509_FILETYPE_PEM) ) |
326 | VC_STORE_ERR_EXIT(store); | 345 | VC_STORE_ERR_EXIT(store); |
@@ -329,25 +348,16 @@ X509_STORE *vc_x509store_create(vc_x509store_t *vc_store) | |||
329 | X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL ); | 348 | X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL ); |
330 | } | 349 | } |
331 | 350 | ||
332 | if( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir())) ) | 351 | if ( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir())) ) |
333 | VC_STORE_ERR_EXIT(store); | 352 | VC_STORE_ERR_EXIT(store); |
334 | 353 | ||
335 | if( !vc_store->capath ) { | 354 | if ( !vc_store->capath ) { |
336 | if( !(vc_store->flags & VC_X509S_NODEF_CAPATH) ) | 355 | if( !(vc_store->flags & VC_X509S_USE_CAPATH) ) |
337 | X509_LOOKUP_add_dir(lookup, 0, X509_FILETYPE_DEFAULT); | 356 | X509_LOOKUP_add_dir(lookup, 0, X509_FILETYPE_DEFAULT); |
338 | } else if( !X509_LOOKUP_add_dir(lookup, vc_store->capath, | 357 | } else if( !X509_LOOKUP_add_dir(lookup, vc_store->capath, |
339 | X509_FILETYPE_PEM) ) | 358 | X509_FILETYPE_PEM) ) |
340 | VC_STORE_ERR_EXIT(store); | 359 | VC_STORE_ERR_EXIT(store); |
341 | 360 | ||
342 | for( i=0, n=sk_X509_num(vc_store->certs); i<n; i++) | ||
343 | if( !X509_STORE_add_cert(store, sk_X509_value(vc_store->certs, i)) ) | ||
344 | VC_STORE_ERR_EXIT(store); | ||
345 | |||
346 | for( i=0, n=sk_X509_CRL_num(vc_store->crls); i<n; i++) | ||
347 | if( !X509_STORE_add_crl(store, | ||
348 | sk_X509_CRL_value(vc_store->crls, i)) ) | ||
349 | VC_STORE_ERR_EXIT(store); | ||
350 | |||
351 | return(store); | 361 | return(store); |
352 | } | 362 | } |
353 | 363 | ||
@@ -361,104 +371,6 @@ int vc_verify_callback(int ok, X509_STORE_CTX *store) | |||
361 | return (ok | getintoption(CF_IGNSSL)); | 371 | return (ok | getintoption(CF_IGNSSL)); |
362 | } | 372 | } |
363 | 373 | ||
364 | void vc_x509store_setflags(vc_x509store_t *store, int flags) | ||
365 | { | ||
366 | store->flags |= flags; | ||
367 | } | ||
368 | |||
369 | void vc_x509store_clearflags(vc_x509store_t *store, int flags) | ||
370 | { | ||
371 | store->flags &= ~flags; | ||
372 | } | ||
373 | |||
374 | void vc_x509store_setcb(vc_x509store_t *store, | ||
375 | vc_x509verify_cb_t callback) | ||
376 | { | ||
377 | store->callback = callback; | ||
378 | } | ||
379 | |||
380 | void vc_x509store_set_pkeycb(vc_x509store_t *store, | ||
381 | vc_askpass_cb_t callback) | ||
382 | { | ||
383 | store->askpass_callback = callback; | ||
384 | } | ||
385 | |||
386 | void vc_x509store_addcert(vc_x509store_t *store, X509 *cert) | ||
387 | { | ||
388 | sk_X509_push(store->certs, cert); | ||
389 | } | ||
390 | |||
391 | void vc_x509store_setcafile(vc_x509store_t *store, char *file) | ||
392 | { | ||
393 | free(store->cafile); | ||
394 | store->cafile = ( file ? strdup(file) : 0 ); | ||
395 | } | ||
396 | |||
397 | void vc_x509store_setcapath(vc_x509store_t *store, char *path) | ||
398 | { | ||
399 | free(store->capath); | ||
400 | store->capath = ( path ? strdup(path) : 0 ); | ||
401 | } | ||
402 | |||
403 | void vc_x509store_setcrlfile(vc_x509store_t *store, char *file) | ||
404 | { | ||
405 | free(store->crlfile); | ||
406 | store->crlfile = ( file ? strdup(file) : 0 ); | ||
407 | } | ||
408 | |||
409 | void vc_x509store_setkeyfile(vc_x509store_t *store, char *file) | ||
410 | { | ||
411 | free(store->use_keyfile); | ||
412 | store->use_keyfile = ( file ? strdup(file) : 0 ); | ||
413 | } | ||
414 | |||
415 | void vc_x509store_setcertfile(vc_x509store_t *store, char *file) | ||
416 | { | ||
417 | free(store->use_certfile); | ||
418 | store->use_certfile = ( file ? strdup(file) : 0 ); | ||
419 | } | ||
420 | |||
421 | vc_x509store_t *vc_init_x509store() | ||
422 | { | ||
423 | vc_x509store_t *s = malloc(sizeof(vc_x509store_t)); | ||
424 | if (s) { | ||
425 | |||
426 | static int sslinit; | ||
427 | if( !sslinit++ ) { | ||
428 | SSL_library_init (); | ||
429 | SSL_load_error_strings(); | ||
430 | } | ||
431 | |||
432 | s->cafile = NULL; | ||
433 | s->capath = NULL; | ||
434 | s->crlfile = NULL; | ||
435 | s->callback = NULL; | ||
436 | s->askpass_callback = NULL; | ||
437 | s->certs = sk_X509_new_null(); | ||
438 | s->crls = sk_X509_CRL_new_null(); | ||
439 | s->use_certfile = NULL; | ||
440 | s->use_certs = sk_X509_new_null(); | ||
441 | s->use_keyfile = NULL; | ||
442 | s->use_key = NULL; | ||
443 | s->flags = 0; | ||
444 | } | ||
445 | return s; | ||
446 | } | ||
447 | |||
448 | void vc_cleanup_x509store(vc_x509store_t *s) | ||
449 | { | ||
450 | free(s->cafile); | ||
451 | free(s->capath); | ||
452 | free(s->crlfile); | ||
453 | free(s->use_certfile); | ||
454 | free(s->use_keyfile); | ||
455 | free(s->use_key); | ||
456 | sk_X509_free(s->certs); | ||
457 | sk_X509_CRL_free(s->crls); | ||
458 | sk_X509_free(s->use_certs); | ||
459 | free(s); | ||
460 | } | ||
461 | |||
462 | ssize_t vc_tls_sendmessage(const void *buf, size_t size) { | 374 | ssize_t vc_tls_sendmessage(const void *buf, size_t size) { |
463 | return BIO_write(server_conn, buf, size); | 375 | return BIO_write(server_conn, buf, size); |
464 | } | 376 | } |
@@ -476,11 +388,3 @@ void vc_tls_cleanup() { | |||
476 | BIO_free_all( server_conn ); | 388 | BIO_free_all( server_conn ); |
477 | server_conn = NULL; | 389 | server_conn = NULL; |
478 | } | 390 | } |
479 | |||
480 | const char *vchat_ssl_version_external = "OpenSSL implementation; version unknown"; | ||
481 | void vchat_ssl_get_version_external() | ||
482 | { | ||
483 | char tmpstr[TMPSTRSIZE]; | ||
484 | snprintf(tmpstr, TMPSTRSIZE, "%s with %s", SSLeay_version(SSLEAY_VERSION), SSLeay_version(SSLEAY_CFLAGS)); | ||
485 | vchat_ssl_version_external = strdup(tmpstr); | ||
486 | } | ||