summaryrefslogtreecommitdiff
path: root/vchat-ssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'vchat-ssl.c')
-rwxr-xr-xvchat-ssl.c475
1 files changed, 0 insertions, 475 deletions
diff --git a/vchat-ssl.c b/vchat-ssl.c
deleted file mode 100755
index adef70d..0000000
--- a/vchat-ssl.c
+++ /dev/null
@@ -1,475 +0,0 @@
1/*
2 * vchat-client - alpha version
3 * vchat-ssl.c - handling of SSL connection and X509 certificate
4 * verification
5 *
6 * Copyright (C) 2007 Thorsten Schroeder <ths@berlin.ccc.de>
7 *
8 * This program is free software. It can be redistributed and/or modified,
9 * provided that this copyright notice is kept intact. This program is
10 * distributed in the hope that it will be useful, but without any warranty;
11 * without even the implied warranty of merchantability or fitness for a
12 * particular purpose. In no event shall the copyright holder be liable for
13 * any direct, indirect, incidental or special damages arising in any way out
14 * of the use of this software.
15 *
16 */
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <assert.h>
22
23#include <openssl/err.h>
24#include <openssl/ssl.h>
25#include <openssl/bio.h>
26#include <openssl/evp.h>
27#include <openssl/x509.h>
28#include <openssl/x509v3.h>
29#include <openssl/conf.h>
30
31#include <readline/readline.h>
32
33#include "vchat.h"
34#include "vchat-ssl.h"
35
36const char *vchat_ssl_version = "vchat-ssl.c $Id$";
37
38typedef int (*vc_x509verify_cb_t)(int, X509_STORE_CTX *);
39struct vc_x509store_t {
40 char *cafile;
41 char *capath;
42 char *crlfile;
43 vc_x509verify_cb_t callback;
44 vc_askpass_cb_t askpass_callback;
45 STACK_OF(X509) *certs;
46 STACK_OF(X509_CRL) *crls;
47 char *use_certfile;
48 STACK_OF(X509) *use_certs;
49 char *use_keyfile;
50 EVP_PKEY *use_key;
51 int flags;
52};
53
54static void vc_cleanup_x509store(vc_x509store_t *); // Should not be static but is unused
55static SSL_CTX * vc_create_sslctx( vc_x509store_t *vc_store );
56static int vc_verify_callback(int, X509_STORE_CTX *);
57static X509_STORE * vc_x509store_create(vc_x509store_t *);
58static void vc_x509store_clearflags(vc_x509store_t *, int);
59static void vc_x509store_setcafile(vc_x509store_t *, char *);
60static void vc_x509store_setcapath(vc_x509store_t *, char *);
61static void vc_x509store_setcrlfile(vc_x509store_t *, char *);
62static void vc_x509store_addcert(vc_x509store_t *, X509 *);
63static void vc_x509store_setcb(vc_x509store_t *, vc_x509verify_cb_t);
64
65#define VC_CTX_ERR_EXIT(se, cx) do { \
66 snprintf(tmpstr, TMPSTRSIZE, "CREATE CTX: %s", \
67 ERR_error_string (ERR_get_error (), NULL)); \
68 writecf(FS_ERR, tmpstr); \
69 if(se) X509_STORE_free(se); \
70 if(cx) SSL_CTX_free(cx); \
71 return(0); \
72 } while(0)
73
74#define VC_SETCERT_ERR_EXIT(se, cx, err) do { \
75 snprintf(tmpstr, TMPSTRSIZE, "CREATE CTX: %s", err); \
76 writecf(FS_ERR, tmpstr); \
77 if(se) X509_STORE_free(se); \
78 if(cx) SSL_CTX_free(cx); \
79 return(NULL); \
80 } while(0)
81
82static SSL_CTX * vc_create_sslctx( vc_x509store_t *vc_store )
83{
84 int i = 0;
85 int n = 0;
86 int flags = 0;
87 int r = 0;
88 SSL_CTX *ctx = NULL;
89 X509_STORE *store = NULL;
90 vc_x509verify_cb_t verify_callback = NULL;
91
92 /* Explicitly use TLSv1 (or maybe later) */
93 if( !(ctx = SSL_CTX_new(SSLv23_client_method())) )
94 VC_CTX_ERR_EXIT(store, ctx);
95
96 if( !(store = vc_x509store_create(vc_store)) )
97 VC_CTX_ERR_EXIT(store, ctx);
98
99 SSL_CTX_set_cert_store(ctx, store);
100 store = NULL;
101 /* Disable some insecure protocols explicitly */
102 SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3);
103 if (getstroption(CF_CIPHERSUITE))
104 SSL_CTX_set_cipher_list(ctx, getstroption(CF_CIPHERSUITE));
105 else
106 SSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA");
107
108 SSL_CTX_set_verify_depth (ctx, getintoption(CF_VERIFYSSL));
109
110 if( !(verify_callback = vc_store->callback) )
111 verify_callback = vc_verify_callback;
112
113 if( !(vc_store->flags & VC_X509S_SSL_VERIFY_MASK) ) {
114 writecf(FS_DBG, tmpstr);
115 flags = SSL_VERIFY_NONE;
116 }
117 else {
118 if(vc_store->flags & VC_X509S_SSL_VERIFY_PEER)
119 flags |= SSL_VERIFY_PEER;
120 if(vc_store->flags & VC_X509S_SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
121 flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
122 if(vc_store->flags & VC_X509S_SSL_VERIFY_CLIENT_ONCE)
123 flags |= SSL_VERIFY_CLIENT_ONCE;
124 }
125
126 SSL_CTX_set_verify(ctx, flags, verify_callback);
127
128 if(vc_store->flags & VC_X509S_USE_CERTIFICATE) {
129 if(vc_store->use_certfile)
130 SSL_CTX_use_certificate_chain_file(ctx, vc_store->use_certfile);
131 else {
132 SSL_CTX_use_certificate(ctx,
133 sk_X509_value(vc_store->use_certs, 0));
134 for(i=0,n=sk_X509_num(vc_store->use_certs); i<n; i++)
135 SSL_CTX_add_extra_chain_cert(ctx,
136 sk_X509_value(vc_store->use_certs, i));
137 }
138
139 SSL_CTX_set_default_passwd_cb(ctx, vc_store->askpass_callback);
140
141 if(vc_store->use_keyfile) {
142 r=SSL_CTX_use_PrivateKey_file(ctx, vc_store->use_keyfile,
143 SSL_FILETYPE_PEM);
144 } else if(vc_store->use_key)
145 r=SSL_CTX_use_PrivateKey(ctx, vc_store->use_key);
146
147 if( r!=1 || !SSL_CTX_check_private_key(ctx))
148 VC_SETCERT_ERR_EXIT(store, ctx, "Load private key failed");
149 }
150
151 SSL_CTX_set_app_data(ctx, vc_store);
152 return(ctx);
153}
154
155int vc_connect_ssl( BIO **conn, vc_x509store_t *vc_store )
156{
157 SSL_CTX * ctx = vc_create_sslctx(vc_store);
158 X509 *peercert = NULL;
159 BIO *ssl_conn = NULL;
160 const SSL *sslp = NULL;
161 const SSL_CIPHER * cipher = NULL;
162
163 /* To display and check server fingerprint */
164 char fingerprint[EVP_MAX_MD_SIZE*4];
165 unsigned char fingerprint_bin[EVP_MAX_MD_SIZE];
166 unsigned int fingerprint_len;
167
168 FILE *fingerprint_file = NULL;
169 char * fp = fingerprint;
170
171 long result, j;
172
173 if( !ctx )
174 return 1;
175
176 ssl_conn = BIO_new_ssl(ctx, 1);
177 SSL_CTX_free(ctx);
178
179 if( !ssl_conn )
180 goto ssl_error;
181
182 BIO_push( ssl_conn, *conn );
183 *conn = ssl_conn;
184 fflush(stdout);
185
186 if( BIO_do_handshake( *conn ) <= 0 )
187 goto ssl_error;
188
189 /* Show information about cipher used */
190 /* Get cipher object */
191 BIO_get_ssl(ssl_conn, &sslp);
192 if (sslp)
193 cipher = SSL_get_current_cipher(sslp);
194 if (cipher) {
195 char cipher_desc[TMPSTRSIZE];
196 snprintf(tmpstr, TMPSTRSIZE, "[SSL CIPHER ] %s", SSL_CIPHER_description(cipher, cipher_desc, TMPSTRSIZE));
197 writecf(FS_SERV, tmpstr);
198 } else {
199 snprintf(tmpstr, TMPSTRSIZE, "[SSL ERROR ] Cipher not known / SSL object can't be queried!");
200 writecf(FS_ERR, tmpstr);
201 }
202
203 /* Accept being connected, _if_ verification passed */
204 if (!sslp)
205 goto ssl_error;
206
207 peercert = SSL_get_peer_certificate(sslp);
208 if (!peercert)
209 goto ssl_error;
210
211 /* show basic information about peer cert */
212 snprintf(tmpstr, TMPSTRSIZE, "[SSL SUBJECT ] %s", X509_NAME_oneline(X509_get_subject_name(peercert),0,0));
213 writecf(FS_SERV, tmpstr);
214 snprintf(tmpstr, TMPSTRSIZE, "[SSL ISSUER ] %s", X509_NAME_oneline(X509_get_issuer_name(peercert),0,0));
215 writecf(FS_SERV, tmpstr);
216
217 /* calculate fingerprint */
218 if (!X509_digest(peercert,EVP_sha1(),fingerprint_bin,&fingerprint_len))
219 goto ssl_error;
220
221 assert ( ( fingerprint_len > 1 ) && (fingerprint_len <= EVP_MAX_MD_SIZE ));
222 for (j=0; j<(int)fingerprint_len; j++)
223 fp += sprintf(fp, "%02X:", fingerprint_bin[j]);
224 assert ( fp > fingerprint );
225 fp[-1] = 0;
226 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] %s (from server)", fingerprint);
227 writecf(FS_SERV, tmpstr);
228
229 /* we don't need the peercert anymore */
230 X509_free(peercert);
231
232 /* verify fingerprint */
233 if (getintoption(CF_PINFINGER)) {
234
235 fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "r");
236 if (fingerprint_file) {
237
238 /* Read fingerprint from file */
239 char old_fingerprint[EVP_MAX_MD_SIZE*4];
240 char * r = fgets(old_fingerprint, sizeof(old_fingerprint), fingerprint_file);
241 fclose(fingerprint_file);
242
243 if (r) {
244 /* chomp */
245 char *nl = strchr(r, '\n');
246 if (nl) *nl = 0;
247
248 /* verify fingerprint matches stored version */
249 if (!strcmp(fingerprint, old_fingerprint))
250 return 0;
251 }
252
253 snprintf(tmpstr, TMPSTRSIZE, "[SSL FINGERPRINT ] %s (from %s)", r ? old_fingerprint : "<FILE READ ERROR>", getstroption(CF_FINGERPRINT));
254 writecf(FS_ERR, tmpstr);
255 writecf(FS_ERR, "[SSL CONNECT ERROR] Fingerprint mismatch! Server cert updated?");
256 return 1;
257 }
258
259 fingerprint_file = fopen(tilde_expand(getstroption(CF_FINGERPRINT)), "w");
260 if (!fingerprint_file) {
261 snprintf (tmpstr, TMPSTRSIZE, "[WARNING] Can't write fingerprint file, %s.", strerror(errno));
262 writecf(FS_ERR, tmpstr);
263 } else {
264 fputs(fingerprint, fingerprint_file);
265 fclose(fingerprint_file);
266 writecf(FS_SERV, "Stored fingerprint.");
267 }
268 return 0;
269 }
270
271 /* If verify of x509 chain was requested, do the check here */
272 result = SSL_get_verify_result(sslp);
273
274 if (result == X509_V_OK)
275 return 0;
276
277 if (getintoption(CF_IGNSSL)) {
278 writecf(FS_ERR, "[SSL VERIFY ERROR ] FAILURE IGNORED!!!");
279 return 0;
280 }
281
282ssl_error:
283 snprintf(tmpstr, TMPSTRSIZE, "[SSL CONNECT ERROR] %s", ERR_error_string (ERR_get_error (), NULL));
284 writecf(FS_ERR, tmpstr);
285
286 return 1;
287}
288
289#define VC_STORE_ERR_EXIT(s) do { \
290 fprintf(stderr, "[E] SSL_STORE: %s\n", ERR_error_string (ERR_get_error (), NULL)); \
291 if(s) X509_STORE_free(s); \
292 return(0); \
293 } while(0)
294
295X509_STORE *vc_x509store_create(vc_x509store_t *vc_store)
296{
297 int i = 0;
298 int n = 0;
299 X509_STORE *store = NULL;
300 X509_LOOKUP *lookup = NULL;
301
302 store = X509_STORE_new();
303
304 if(vc_store->callback)
305 X509_STORE_set_verify_cb_func(store, vc_store->callback);
306 else
307 X509_STORE_set_verify_cb_func(store, vc_verify_callback);
308
309 if( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) )
310 VC_STORE_ERR_EXIT(store);
311
312 if(!vc_store->cafile) {
313 if( !(vc_store->flags & VC_X509S_NODEF_CAFILE) )
314 X509_LOOKUP_load_file(lookup, 0, X509_FILETYPE_DEFAULT);
315 } else if( !X509_LOOKUP_load_file(lookup, vc_store->cafile,
316 X509_FILETYPE_PEM) )
317 VC_STORE_ERR_EXIT(store);
318
319 if(vc_store->crlfile) {
320 if( !X509_load_crl_file(lookup, vc_store->crlfile,
321 X509_FILETYPE_PEM) )
322 VC_STORE_ERR_EXIT(store);
323
324 X509_STORE_set_flags( store,
325 X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL );
326 }
327
328 if( !(lookup = X509_STORE_add_lookup(store, X509_LOOKUP_hash_dir())) )
329 VC_STORE_ERR_EXIT(store);
330
331 if( !vc_store->capath ) {
332 if( !(vc_store->flags & VC_X509S_NODEF_CAPATH) )
333 X509_LOOKUP_add_dir(lookup, 0, X509_FILETYPE_DEFAULT);
334 } else if( !X509_LOOKUP_add_dir(lookup, vc_store->capath,
335 X509_FILETYPE_PEM) )
336 VC_STORE_ERR_EXIT(store);
337
338 for( i=0, n=sk_X509_num(vc_store->certs); i<n; i++)
339 if( !X509_STORE_add_cert(store, sk_X509_value(vc_store->certs, i)) )
340 VC_STORE_ERR_EXIT(store);
341
342 for( i=0, n=sk_X509_CRL_num(vc_store->crls); i<n; i++)
343 if( !X509_STORE_add_crl(store,
344 sk_X509_CRL_value(vc_store->crls, i)) )
345 VC_STORE_ERR_EXIT(store);
346
347 return(store);
348}
349
350int vc_verify_callback(int ok, X509_STORE_CTX *store)
351{
352 if(!ok) {
353 snprintf(tmpstr, TMPSTRSIZE, "[SSL VERIFY ERROR ] %s",
354 X509_verify_cert_error_string(X509_STORE_CTX_get_error(store)));
355 writecf(FS_ERR, tmpstr);
356 }
357 return (ok | getintoption(CF_IGNSSL));
358}
359
360void vc_x509store_setflags(vc_x509store_t *store, int flags)
361{
362 store->flags |= flags;
363}
364
365void vc_x509store_clearflags(vc_x509store_t *store, int flags)
366{
367 store->flags &= ~flags;
368}
369
370void vc_x509store_setcb(vc_x509store_t *store,
371 vc_x509verify_cb_t callback)
372{
373 store->callback = callback;
374}
375
376void vc_x509store_set_pkeycb(vc_x509store_t *store,
377 vc_askpass_cb_t callback)
378{
379 store->askpass_callback = callback;
380}
381
382void vc_x509store_addcert(vc_x509store_t *store, X509 *cert)
383{
384 sk_X509_push(store->certs, cert);
385}
386
387void vc_x509store_setcafile(vc_x509store_t *store, char *file)
388{
389 free(store->cafile);
390 store->cafile = ( file ? strdup(file) : 0 );
391}
392
393void vc_x509store_setcapath(vc_x509store_t *store, char *path)
394{
395 free(store->capath);
396 store->capath = ( path ? strdup(path) : 0 );
397}
398
399void vc_x509store_setcrlfile(vc_x509store_t *store, char *file)
400{
401 free(store->crlfile);
402 store->crlfile = ( file ? strdup(file) : 0 );
403}
404
405void vc_x509store_setkeyfile(vc_x509store_t *store, char *file)
406{
407 free(store->use_keyfile);
408 store->use_keyfile = ( file ? strdup(file) : 0 );
409}
410
411void vc_x509store_setcertfile(vc_x509store_t *store, char *file)
412{
413 free(store->use_certfile);
414 store->use_certfile = ( file ? strdup(file) : 0 );
415}
416
417#if 0
418int vc_tls_read()
419{
420
421}
422
423int vc_tls_read()
424{
425
426}
427#endif
428
429vc_x509store_t *vc_init_x509store()
430{
431 vc_x509store_t *s = malloc(sizeof(vc_x509store_t));
432 if (s) {
433
434 static int sslinit;
435 if( !sslinit++ ) {
436 SSL_library_init ();
437 SSL_load_error_strings();
438 }
439
440 s->cafile = NULL;
441 s->capath = NULL;
442 s->crlfile = NULL;
443 s->callback = NULL;
444 s->askpass_callback = NULL;
445 s->certs = sk_X509_new_null();
446 s->crls = sk_X509_CRL_new_null();
447 s->use_certfile = NULL;
448 s->use_certs = sk_X509_new_null();
449 s->use_keyfile = NULL;
450 s->use_key = NULL;
451 s->flags = 0;
452 }
453 return s;
454}
455
456void vc_cleanup_x509store(vc_x509store_t *s)
457{
458 free(s->cafile);
459 free(s->capath);
460 free(s->crlfile);
461 free(s->use_certfile);
462 free(s->use_keyfile);
463 free(s->use_key);
464 sk_X509_free(s->certs);
465 sk_X509_CRL_free(s->crls);
466 sk_X509_free(s->use_certs);
467}
468
469const char *vchat_ssl_version_external = "OpenSSL implementation; version unknown";
470void vchat_ssl_get_version_external()
471{
472 char tmpstr[TMPSTRSIZE];
473 snprintf(tmpstr, TMPSTRSIZE, "%s with %s", SSLeay_version(SSLEAY_VERSION), SSLeay_version(SSLEAY_CFLAGS));
474 vchat_ssl_version_external = strdup(tmpstr);
475}