/[cvs]/eggdrop1.8/src/tls.c
ViewVC logotype

Contents of /eggdrop1.8/src/tls.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2.2.3 - (show annotations) (download) (as text)
Sat Apr 19 17:41:59 2014 UTC (5 years, 1 month ago) by pseudo
Branch: gettext
Changes since 1.2.2.2: +3 -3 lines
File MIME type: text/x-chdr
Changed FILE * to gzFile when calling zlib funcs in compress.mod.

Fixed some compile time warnings.

Patch by: pseudo

1 /*
2 * tls.c -- handles:
3 * TLS support functions
4 * Certificate handling
5 * OpenSSL initialization and shutdown
6 *
7 * $Id: tls.c,v 1.2.2.2 2011/02/08 22:06:01 thommey Exp $
8 */
9 /*
10 * Written by Rumen Stoyanov <pseudo@egg6.net>
11 *
12 * Copyright (C) 2010 Eggheads Development Team
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29 #include "main.h"
30
31 #ifdef TLS
32
33 #include <openssl/err.h>
34 #include <openssl/rand.h>
35 #include <openssl/x509v3.h>
36
37 extern int tls_vfydcc;
38 extern struct dcc_t *dcc;
39
40 int tls_maxdepth = 9; /* Max certificate chain verification depth */
41 SSL_CTX *ssl_ctx = NULL; /* SSL context object */
42 char *tls_randfile = NULL; /* Random seed file for SSL */
43 char tls_capath[121] = ""; /* Path to trusted CA certificates */
44 char tls_cafile[121] = ""; /* File containing trusted CA certificates */
45 char tls_certfile[121] = ""; /* Our own digital certificate ;) */
46 char tls_keyfile[121] = ""; /* Private key for use with eggdrop */
47 char tls_ciphers[121] = ""; /* A list of ciphers for SSL to use */
48
49
50 /* Count allocated memory for SSL. This excludes memory allocated by OpenSSL's
51 * family of malloc functions.
52 */
53 int expmem_tls()
54 {
55 int i, tot;
56 struct threaddata *td = threaddata();
57
58 /* currently it's only the appdata structs allocated by ssl_handshake() */
59 for (i = 0, tot = 0; i < td->MAXSOCKS; i++)
60 if (!(td->socklist[i].flags & (SOCK_UNUSED | SOCK_TCL)))
61 if (td->socklist[i].ssl && SSL_get_app_data(td->socklist[i].ssl))
62 tot += sizeof(ssl_appdata);
63 return tot;
64 }
65
66 /* Seeds the PRNG
67 *
68 * Only does something if the system doesn't have enough entropy.
69 * If there is no random file, one will be created either at
70 * $RANDFILE if set or at $HOME/.rnd
71 *
72 * Return value: 0 on success, !=0 on failure.
73 */
74 static int ssl_seed(void)
75 {
76 char stackdata[1024];
77 static char rand_file[120];
78 FILE *fh;
79
80 #ifdef HAVE_RAND_STATUS
81 if (RAND_status())
82 return 0; /* Status OK */
83 #endif
84 /* If '/dev/urandom' is present, OpenSSL will use it by default.
85 * Otherwise we'll have to generate pseudorandom data ourselves,
86 * using system time, our process ID and some unitialized static
87 * storage.
88 */
89 if ((fh = fopen("/dev/urandom", "r"))) {
90 fclose(fh);
91 return 0;
92 }
93 if (RAND_file_name(rand_file, sizeof(rand_file)))
94 tls_randfile = rand_file;
95 else
96 return 1;
97 if (!RAND_load_file(rand_file, -1)) {
98 /* generate some pseudo random data */
99 unsigned int c;
100 c = time(NULL);
101 RAND_seed(&c, sizeof(c));
102 c = getpid();
103 RAND_seed(&c, sizeof(c));
104 RAND_seed(stackdata, sizeof(stackdata));
105 }
106 #ifdef HAVE_RAND_STATUS
107 if (!RAND_status())
108 return 2; /* pseudo random data still not ehough */
109 #endif
110 return 0;
111 }
112
113 /* Prepares and initializes SSL stuff
114 *
115 * Creates a context object, supporting SSLv2/v3 & TLSv1 protocols;
116 * Seeds the Pseudo Random Number Generator;
117 * Optionally loads a SSL certifate and a private key.
118 * Tell OpenSSL the location of certificate authority certs
119 *
120 * Return value: 0 on successful initialization, !=0 on failure
121 */
122 int ssl_init()
123 {
124 /* Load SSL and crypto error strings; register SSL algorithms */
125 SSL_load_error_strings();
126 SSL_library_init();
127
128 if (ssl_seed()) {
129 putlog(LOG_MISC, "*", _("TLS: unable to seed PRNG. Disabling SSL"));
130 ERR_free_strings();
131 return -2;
132 }
133 /* A TLS/SSL connection established with this method will understand all
134 supported protocols (SSLv2, SSLv3, and TLSv1) */
135 if (!(ssl_ctx = SSL_CTX_new(SSLv23_method()))) {
136 debug0(ERR_error_string(ERR_get_error(), NULL));
137 putlog(LOG_MISC, "*", _("TLS: unable to create context. Disabling SSL."));
138 ERR_free_strings();
139 return -1;
140 }
141 /* Load our own certificate and private key. Mandatory for acting as
142 server, because we don't support anonymous ciphers by default. */
143 if (SSL_CTX_use_certificate_chain_file(ssl_ctx, tls_certfile) != 1)
144 debug1(_("TLS: unable to load own certificate: %s"),
145 ERR_error_string(ERR_get_error(), NULL));
146 if (SSL_CTX_use_PrivateKey_file(ssl_ctx, tls_keyfile,
147 SSL_FILETYPE_PEM) != 1)
148 debug1(_("TLS: unable to load private key: %s"),
149 ERR_error_string(ERR_get_error(), NULL));
150 if ((tls_capath[0] || tls_cafile[0]) &&
151 !SSL_CTX_load_verify_locations(ssl_ctx, tls_cafile[0] ? tls_cafile : NULL,
152 tls_capath[0] ? tls_capath : NULL))
153 debug1(_("TLS: unable to set CA certificates location: %s"),
154 ERR_error_string(ERR_get_error(), NULL));
155 /* Let advanced users specify the list of allowed ssl ciphers */
156 if (tls_ciphers[0])
157 if (!SSL_CTX_set_cipher_list(ssl_ctx, tls_ciphers)) {
158 /* this replaces any preset ciphers so an invalid list is fatal */
159 putlog(LOG_MISC, "*", _("TLS: no valid ciphers found. Disabling SSL."));
160 ERR_free_strings();
161 SSL_CTX_free(ssl_ctx);
162 ssl_ctx = NULL;
163 return -3;
164 }
165
166 return 0;
167 }
168
169 /* Free the SSL CTX, clean up the mess */
170 void ssl_cleanup()
171 {
172 if (ssl_ctx) {
173 SSL_CTX_free(ssl_ctx);
174 ssl_ctx = NULL;
175 }
176 if (tls_randfile)
177 RAND_write_file(tls_randfile);
178 ERR_free_strings();
179 }
180
181 char *ssl_fpconv(char *in, char *out)
182 {
183 long len;
184 char *fp;
185 unsigned char *md5;
186
187 if (!in)
188 return NULL;
189
190 if ((md5 = string_to_hex(in, &len))) {
191 fp = hex_to_string(md5, len);
192 if (fp) {
193 out = user_realloc(out, strlen(fp) + 1);
194 strcpy(out, fp);
195 OPENSSL_free(md5);
196 OPENSSL_free(fp);
197 return out;
198 }
199 OPENSSL_free(md5);
200 }
201 return NULL;
202 }
203
204 /* Get the certificate, corresponding to the connection
205 * identified by sock.
206 *
207 * Return value: pointer to a X509 certificate or NULL if we couldn't
208 * look up the certificate.
209 */
210 static X509 *ssl_getcert(int sock)
211 {
212 int i;
213 struct threaddata *td = threaddata();
214
215 i = findsock(sock);
216 if (i == -1 || !td->socklist[i].ssl)
217 return NULL;
218 return SSL_get_peer_certificate(td->socklist[i].ssl);
219 }
220
221 /* Get the certificate fingerprint of the connection corresponding
222 * to the socket.
223 *
224 * Return value: ptr to the hexadecimal representation of the fingerprint
225 * or NULL if there's no certificate associated with the connection.
226 */
227 char *ssl_getfp(int sock)
228 {
229 char *p;
230 unsigned i;
231 X509 *cert;
232 static char fp[64];
233 unsigned char md[EVP_MAX_MD_SIZE];
234
235 if (!(cert = ssl_getcert(sock)))
236 return NULL;
237 if (!X509_digest(cert, EVP_sha1(), md, &i))
238 return NULL;
239 if (!(p = hex_to_string(md, i)))
240 return NULL;
241 strncpyz(fp, p, sizeof fp);
242 OPENSSL_free(p);
243 return fp;
244 }
245
246 /* Get the UID field from the certificate subject name.
247 * The certificate is looked up using the socket of the connection.
248 *
249 * Return value: Pointer to the uid string or NULL if not found
250 */
251 char *ssl_getuid(int sock)
252 {
253 int idx;
254 X509 *cert;
255 X509_NAME *subj;
256 ASN1_STRING *name;
257
258 if (!(cert = ssl_getcert(sock)))
259 return NULL;
260 /* Get the subject name */
261 if (!(subj = X509_get_subject_name(cert)))
262 return NULL;
263
264 /* Get the first UID */
265 idx = X509_NAME_get_index_by_NID(subj, NID_userId, -1);
266 if (idx == -1)
267 return NULL;
268 name = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subj, idx));
269 /* Extract the contents, assuming null-terminated ASCII string */
270 return (char *) ASN1_STRING_data(name);
271 }
272
273 /* Compare the peer's host with their Common Name or dnsName found in
274 * it's certificate. Only the first domain component of cn is allowed to
275 * be a wildcard '*'. The non-wildcard characters are compared ignoring
276 * case.
277 *
278 * Return value: 1 if cn matches host, 0 otherwise.
279 */
280 static int ssl_hostmatch(char *cn, char *host)
281 {
282 char *p, *q, *r;
283
284 if ((r = strchr(cn + 1, '.')) && r[-1] == '*' && strchr(r, '.')) {
285 for (p = cn, q = host; *p != '*'; p++, q++)
286 if (toupper(*p) != toupper(*q))
287 return 0;
288
289 if (!(p = strchr(host, '.')) || strcasecmp(p, r))
290 return 0;
291 return 1;
292 }
293
294 /* First domain component is not a wildcard and they aren't allowed
295 elsewhere, so just compare the strings. */
296 return strcasecmp(cn, host) ? 0 : 1;
297 }
298
299 /* Confirm the peer identity, by checking if the certificate subject
300 * matches the peer's DNS name or IP address. Matching is performed in
301 * accordance with RFC 2818:
302 *
303 * If the certificate has a subjectAltName extension, all names of type
304 * IPAddress or dnsName present there, will be compared to data->host,
305 * depending on it's contents.
306 * In case there's no subjectAltName extension, commonName (CN) parts
307 * of the certificate subject field will be used instead of IPAddress
308 * and dnsName entries. For IP addresses, common names must contain IPs
309 * in presentation format (1.2.3.4 or 2001:DB8:15:dead::)
310 * Finally, if no subjectAltName or common names are present, the
311 * certificate is considered to not match the peer.
312 *
313 * The structure of X509 certificates and all fields referenced above
314 * are described in RFC 5280.
315 *
316 * The certificate must be pointed by cert and the peer's host must be
317 * placed in data->host. The format is a regular DNS name or an IP in
318 * presentation format (see above).
319 *
320 * Return value: 1 if the certificate matches the peer, 0 otherwise.
321 */
322 static int ssl_verifycn(X509 *cert, ssl_appdata *data)
323 {
324 char *cn;
325 int crit = 0, match = 0;
326 ASN1_OCTET_STRING *ip;
327 GENERAL_NAMES *altname; /* SubjectAltName ::= GeneralNames */
328
329 ip = a2i_IPADDRESS(data->host); /* check if it's an IP or a hostname */
330 if ((altname = X509_get_ext_d2i(cert, NID_subject_alt_name, &crit, NULL))) {
331 GENERAL_NAME *gn;
332
333 /* Loop through the general names in altname and pick these
334 of type ip address or dns name */
335 while (!match && (gn = sk_GENERAL_NAME_pop(altname))) {
336 /* if the peer's host is an IP, we're only interested in
337 matching against iPAddress general names, otherwise
338 we'll only look for dnsName's */
339 if (ip) {
340 if (gn->type == GEN_IPADD)
341 match = !ASN1_STRING_cmp(gn->d.ip, ip);
342 } else if (gn->type == GEN_DNS) {
343 /* IA5string holds ASCII data */
344 cn = (char *) ASN1_STRING_data(gn->d.ia5);
345 match = ssl_hostmatch(cn, data->host);
346 }
347 }
348 sk_GENERAL_NAME_free(altname);
349 } else { /* no subjectAltName, try to match against the subject CNs */
350 X509_NAME *subj; /* certificate subject */
351
352 /* the following is just for information */
353 switch (crit) {
354 case 0:
355 debug0(_("TLS: X509 subjectAltName cannot be decoded"));
356 break;
357 case -1:
358 debug0(_("TLS: X509 has no subjectAltName extension"));
359 break;
360 case -2:
361 debug0(_("TLS: X509 has multiple subjectAltName extensions"));
362 }
363 /* no subject name either? A completely broken certificate :) */
364 if (!(subj = X509_get_subject_name(cert))) {
365 putlog(data->loglevel, "*", _("TLS: peer certificate has no subject: %s"),
366 data->host);
367 match = 0;
368 } else { /* we have a subject name, look at it */
369 int pos = -1;
370 ASN1_STRING *name;
371
372 /* Look for commonName attributes in the subject name */
373 pos = X509_NAME_get_index_by_NID(subj, NID_commonName, pos);
374 if (pos == -1) /* sorry */
375 putlog(data->loglevel, "*", _("TLS: Peer has no common names and "
376 "no subjectAltName extension. Verification failed."));
377 /* Loop through all common names which may be present in the subject
378 name until we find a match. */
379 while (!match && pos != -1) {
380 name = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(subj, pos));
381 cn = (char *) ASN1_STRING_data(name);
382 if (ip)
383 match = a2i_IPADDRESS(cn) ? (ASN1_STRING_cmp(ip, a2i_IPADDRESS(cn)) ?
384 0 : 1) : 0;
385 else
386 match = ssl_hostmatch(cn, data->host);
387 pos = X509_NAME_get_index_by_NID(subj, NID_commonName, pos);
388 }
389 }
390 }
391
392 if (ip)
393 ASN1_OCTET_STRING_free(ip);
394 return match;
395 }
396
397 /* Extract a human readable version of a X509_NAME and put the result
398 * into a nmalloc'd buffer.
399 * The X509_NAME structure is used for example in certificate subject
400 * and issuer names.
401 *
402 * You need to nfree() the returned pointer.
403 */
404 static char *ssl_printname(X509_NAME *name)
405 {
406 int len;
407 char *data, *buf;
408 BIO *bio = BIO_new(BIO_s_mem());
409
410 /* X509_NAME_oneline() is easier and shorter, but is deprecated and
411 the manual discourages it's usage, so let's not be lazy ;) */
412 X509_NAME_print_ex(bio, name, 0, XN_FLAG_ONELINE & ~XN_FLAG_SPC_EQ);
413 len = BIO_get_mem_data(bio, &data) + 1;
414 buf = nmalloc(len);
415 strncpyz(buf, data, len);
416 BIO_free(bio);
417 return buf;
418 }
419
420 /* Print the time from a ASN1_UTCTIME object in standard format i.e.
421 * Nov 21 23:59:00 1996 GMT and store it in a nmalloc'd buffer.
422 * The ASN1_UTCTIME structure is what's used for example with
423 * certificate validity dates.
424 *
425 * You need to nfree() the returned pointer.
426 */
427 static char *ssl_printtime(ASN1_UTCTIME *t)
428 {
429 int len;
430 char *data, *buf;
431 BIO *bio = BIO_new(BIO_s_mem());
432
433 ASN1_UTCTIME_print(bio, t);
434 len = BIO_get_mem_data(bio, &data) + 1;
435 buf = nmalloc(len);
436 strncpyz(buf, data, len);
437 BIO_free(bio);
438 return buf;
439 }
440
441 /* Print the value of an ASN1_INTEGER in hexadecimal format.
442 * A typical use for this is to display certificate serial numbers.
443 * As usual, we use a memory BIO.
444 *
445 * You need to nfree() the returned pointer.
446 */
447 static char *ssl_printnum(ASN1_INTEGER *i)
448 {
449 int len;
450 char *data, *buf;
451 BIO *bio = BIO_new(BIO_s_mem());
452
453 i2a_ASN1_INTEGER(bio, i);
454 len = BIO_get_mem_data(bio, &data) + 1;
455 buf = nmalloc(len);
456 strncpyz(buf, data, len);
457 BIO_free(bio);
458 return buf;
459 }
460
461 /* Show the user all relevant information about a certificate: subject,
462 * issuer, validity dates and fingerprints.
463 */
464 static void ssl_showcert(X509 *cert, int loglev)
465 {
466 char *buf, *from, *to;
467 X509_NAME *name;
468 unsigned int len;
469 unsigned char md[EVP_MAX_MD_SIZE];
470
471 /* Subject and issuer names */
472 if ((name = X509_get_subject_name(cert))) {
473 buf = ssl_printname(name);
474 putlog(loglev, "*", _("TLS: certificate subject: %s"), buf);
475 nfree(buf);
476 } else
477 putlog(loglev, "*", _("TLS: cannot get subject name from certificate!"));
478 if ((name = X509_get_issuer_name(cert))) {
479 buf = ssl_printname(name);
480 putlog(loglev, "*", _("TLS: certificate issuer: %s"), buf);
481 nfree(buf);
482 } else
483 putlog(loglev, "*", _("TLS: cannot get issuer name from certificate!"));
484
485 /* Fingerprints */
486 X509_digest(cert, EVP_md5(), md, &len); /* MD5 hash */
487 if (len <= sizeof(md)) {
488 buf = hex_to_string(md, len);
489 putlog(loglev, "*", _("TLS: certificate MD5 Fingerprint: %s"), buf);
490 OPENSSL_free(buf);
491 }
492 X509_digest(cert, EVP_sha1(), md, &len); /* SHA-1 hash */
493 if (len <= sizeof(md)) {
494 buf = hex_to_string(md, len);
495 putlog(loglev, "*", _("TLS: certificate SHA1 Fingerprint: %s"), buf);
496 OPENSSL_free(buf);
497 }
498
499 /* Validity time */
500 from = ssl_printtime(X509_get_notBefore(cert));
501 to = ssl_printtime(X509_get_notAfter(cert));
502 putlog(loglev, "*", _("TLS: certificate valid from %s to %s"), from, to);
503 nfree(from);
504 nfree(to);
505 }
506
507 /* Certificate validation callback
508 *
509 * Check if the certificate given is valid with respect to the
510 * ssl-verify config variable. This makes it possible to allow
511 * self-signed certificates and is also a convenient place to
512 * extract a certificate summary.
513 *
514 * Return value: 1 - validation passed, 0 - invalid cert
515 */
516 int ssl_verify(int ok, X509_STORE_CTX *ctx)
517 {
518 SSL *ssl;
519 X509 *cert;
520 ssl_appdata *data;
521 int err, depth;
522
523 /* get cert, callbacks, error codes, etc. */
524 depth = X509_STORE_CTX_get_error_depth(ctx);
525 cert = X509_STORE_CTX_get_current_cert(ctx);
526 ssl = X509_STORE_CTX_get_ex_data(ctx,
527 SSL_get_ex_data_X509_STORE_CTX_idx());
528 data = (ssl_appdata *) SSL_get_app_data(ssl);
529 err = X509_STORE_CTX_get_error(ctx);
530
531 /* OpenSSL won't explicitly generate this error; instead it will
532 * report missing certificates. Refer to SSL_CTX_set_verify(3)
533 * manual for details
534 */
535 if (depth > tls_maxdepth) {
536 ok = 0;
537 err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
538
539 /* depth 0 is actually the peer certificate. We do all custom
540 * verification here and leave the rest of the certificate chain
541 * to OpenSSL's built in procedures.
542 */
543 } else if (!depth) {
544 /* OpenSSL doesn't perform subject name verification. We need to do
545 * it ourselves. We check here for validity even if it's not requested
546 * in order to be able to warn the user.
547 */
548 if (!(data->flags & TLS_DEPTH0) && !ssl_verifycn(cert, data) &&
549 (data->verify & TLS_VERIFYCN)) {
550 putlog(data->loglevel, "*", _("TLS: certificate validation failed. "
551 "Certificate subject does not match peer."));
552 return 0;
553 }
554 data->flags |= TLS_DEPTH0;
555 /* Allow exceptions for certain common verification errors, if the
556 * caller requested so. A lot of servers provide completely invalid
557 * certificates unuseful for any authentication.
558 */
559 if (!ok || data->verify)
560 if (((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) &&
561 (data->verify & TLS_VERIFYISSUER)) ||
562 ((err == X509_V_ERR_CERT_REVOKED) &&
563 (data->verify & TLS_VERIFYREV)) ||
564 ((err == X509_V_ERR_CERT_NOT_YET_VALID) &&
565 (data->verify & TLS_VERIFYFROM)) ||
566 ((err == X509_V_ERR_CERT_HAS_EXPIRED) &&
567 (data->verify & TLS_VERIFYTO))) {
568 debug1(_("TLS: peer certificate warning: %s"),
569 X509_verify_cert_error_string(err));
570 ok = 1;
571 }
572 }
573 if (ok || !data->verify)
574 return 1;
575 putlog(data->loglevel, "*",
576 _("TLS: certificate validation failed at depth %d: %s"),
577 depth, X509_verify_cert_error_string(err));
578 return 0;
579 }
580
581 /* SSL info callback, this is used to trace engine state changes
582 * and to check when the handshake is finished, so we can display
583 * some cipher and session information and process callbacks.
584 */
585 void ssl_info(SSL *ssl, int where, int ret)
586 {
587 int sock;
588 X509 *cert;
589 char buf[256];
590 ssl_appdata *data;
591 const SSL_CIPHER *cipher;
592 int secret, processed;
593
594 /* We're doing non-blocking IO, so we check here if the handshake has
595 finished */
596 if (where & SSL_CB_HANDSHAKE_DONE) {
597 if (!(data = (ssl_appdata *) SSL_get_app_data(ssl)))
598 return;
599 /* Callback for completed handshake. Cheaper and more convenient than
600 using H_tls */
601 sock = SSL_get_fd(ssl);
602 if (data->cb)
603 data->cb(sock);
604 /* Call TLS binds. We allow scripts to take over or disable displaying of
605 certificate information. */
606 if (check_tcl_tls(sock))
607 return;
608
609 putlog(data->loglevel, "*", _("TLS: handshake successful. "
610 "Secure connection established."));
611
612 if ((cert = SSL_get_peer_certificate(ssl)))
613 ssl_showcert(cert, data->loglevel);
614 else
615 putlog(data->loglevel, "*", _("TLS: peer did not present a certificate"));
616
617 /* Display cipher information */
618 cipher = SSL_get_current_cipher(ssl);
619 processed = SSL_CIPHER_get_bits(cipher, &secret);
620 putlog(data->loglevel, "*", _("TLS: cipher used: %s %s; "
621 "%d bits (%d secret)"), SSL_CIPHER_get_name(cipher),
622 SSL_CIPHER_get_version(cipher), processed, secret);
623 /* secret are the actually secret bits. If processed and secret differ,
624 the rest of the bits are fixed, i.e. for limited export ciphers */
625
626 /* More verbose information, for debugging only */
627 SSL_CIPHER_description(cipher, buf, sizeof buf);
628 debug1(_("TLS: cipher details: %s"), buf);
629 }
630
631 /* Display the state of the engine for debugging purposes */
632 debug1("TLS: state change: %s", SSL_state_string_long(ssl));
633 }
634
635 /* Switch a socket to SSL communication
636 *
637 * Creates a SSL data structure for the connection;
638 * Sets up callbacks and initiates a SSL handshake with the peer;
639 * Reports error conditions and performs cleanup upon failure.
640 *
641 * flags: ssl flags, i.e connect or listen
642 * verify: peer certificate verification flags
643 * loglevel: is the level to output information about the connection
644 * and certificates.
645 * host: contains the dns name or ip address of the peer. Used for
646 * verification.
647 * cb: optional callback, this function will be called after the
648 * handshake completes.
649 *
650 * Return value: 0 on success, !=0 on failure.
651 */
652 int ssl_handshake(int sock, int flags, int verify, int loglevel, char *host,
653 IntFunc cb)
654 {
655 int i, err, ret;
656 ssl_appdata *data;
657 struct threaddata *td = threaddata();
658
659 debug0(_("TLS: attempting SSL negotiation..."));
660 if (!ssl_ctx && ssl_init()) {
661 debug0(_("TLS: Failed. OpenSSL not initialized properly."));
662 return -1;
663 }
664 /* find the socket in the list */
665 i = findsock(sock);
666 if (i == -1) {
667 debug0(_("TLS: socket not in socklist"));
668 return -2;
669 }
670 if (td->socklist[i].ssl) {
671 debug0(_("TLS: handshake not required - SSL session already established"));
672 return 0;
673 }
674 td->socklist[i].ssl = SSL_new(ssl_ctx);
675 if (!td->socklist[i].ssl ||
676 !SSL_set_fd(td->socklist[i].ssl, td->socklist[i].sock)) {
677 debug1(_("TLS: cannot initiate SSL session - %s"),
678 ERR_error_string(ERR_get_error(), 0));
679 return -3;
680 }
681
682 /* Prepare a ssl appdata struct for the verify callback */
683 data = nmalloc(sizeof(ssl_appdata));
684 egg_bzero(data, sizeof(ssl_appdata));
685 data->flags = flags & (TLS_LISTEN | TLS_CONNECT);
686 data->verify = flags & ~(TLS_LISTEN | TLS_CONNECT);
687 data->loglevel = loglevel;
688 data->cb = cb;
689 strncpyz(data->host, host ? host : "", sizeof(data->host));
690 SSL_set_app_data(td->socklist[i].ssl, data);
691 SSL_set_info_callback(td->socklist[i].ssl, (void *) ssl_info);
692 /* We set this +1 to be able to report extra long chains properly.
693 * Otherwise, OpenSSL will break the verification reporting about
694 * missing certificates instead. The rest of the fix is in
695 * ssl_verify()
696 */
697 SSL_set_verify_depth(td->socklist[i].ssl, tls_maxdepth + 1);
698
699 SSL_set_mode(td->socklist[i].ssl, SSL_MODE_ENABLE_PARTIAL_WRITE |
700 SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
701 if (data->flags & TLS_CONNECT) {
702 SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER, ssl_verify);
703 ret = SSL_connect(td->socklist[i].ssl);
704 if (!ret)
705 debug0(_("TLS: connect handshake failed."));
706 } else {
707 if (data->flags & TLS_VERIFYPEER)
708 SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER |
709 SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify);
710 else
711 SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER, ssl_verify);
712 ret = SSL_accept(td->socklist[i].ssl);
713 if (!ret)
714 debug0(_("TLS: accept handshake failed"));
715 }
716
717 err = SSL_get_error(td->socklist[i].ssl, ret);
718 /* Normal condition for async I/O, similar to EAGAIN */
719 if (ret > 0 || err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
720 debug0(_("TLS: handshake in progress"));
721 return 0;
722 }
723 if (ERR_peek_error())
724 debug0(_("TLS: handshake failed due to the following errors: "));
725 while ((err = ERR_get_error()))
726 debug1(_("TLS: %s"), ERR_error_string(err, NULL));
727
728 /* Attempt failed, cleanup and abort */
729 SSL_shutdown(td->socklist[i].ssl);
730 SSL_free(td->socklist[i].ssl);
731 td->socklist[i].ssl = NULL;
732 nfree(data);
733 return -4;
734 }
735
736 /* Tcl functions */
737
738 /* Is the connection secure? */
739 static int tcl_istls STDVAR
740 {
741 int j;
742
743 BADARGS(2, 2, " idx");
744
745 j = findidx(atoi(argv[1]));
746 if (j < 0) {
747 Tcl_AppendResult(irp, "invalid idx", NULL);
748 return TCL_ERROR;
749 }
750 if (dcc[j].ssl)
751 Tcl_AppendResult(irp, "1", NULL);
752 else
753 Tcl_AppendResult(irp, "0", NULL);
754 return TCL_OK;
755 }
756
757 /* Perform a SSL handshake over an existing plain text
758 * connection.
759 */
760 static int tcl_starttls STDVAR
761 {
762 int j;
763 struct threaddata *td = threaddata();
764
765 BADARGS(2, 2, " idx");
766
767 j = findidx(atoi(argv[1]));
768 if (j < 0 || (dcc[j].type != &DCC_SCRIPT)) {
769 Tcl_AppendResult(irp, "invalid idx", NULL);
770 return TCL_ERROR;
771 }
772 if (dcc[j].ssl) {
773 Tcl_AppendResult(irp, "already started", NULL);
774 return TCL_ERROR;
775 }
776 /* Determine if we're playing a client or a server */
777 j = findsock(dcc[j].sock);
778 if (ssl_handshake(dcc[j].sock, (td->socklist[j].flags & SOCK_CONNECT) ?
779 TLS_CONNECT : TLS_LISTEN, tls_vfydcc, LOG_MISC, NULL, NULL))
780 Tcl_AppendResult(irp, "0", NULL);
781 else
782 Tcl_AppendResult(irp, "1", NULL);
783 return TCL_OK;
784 }
785
786 /* Get all relevant information about an established ssl connection.
787 * This includes certificate subject and issuer, serial number,
788 * expiry date, protocol version and cipher information.
789 * All data is presented as a flat list consisting of name-value pairs.
790 */
791 static int tcl_tlsstatus STDVAR
792 {
793 char *p;
794 int i, j;
795 X509 *cert;
796 const SSL_CIPHER *cipher;
797 struct threaddata *td = threaddata();
798 Tcl_DString ds;
799
800 BADARGS(2, 2, " idx");
801
802 /* Allow it to be used for any connection, not just scripted
803 * ones. This makes it possible for a script to display the
804 * server certificate.
805 */
806 i = findanyidx(atoi(argv[1]));
807 if (i < 0) {
808 Tcl_AppendResult(irp, "invalid idx", NULL);
809 return TCL_ERROR;
810 }
811 j = findsock(dcc[i].sock);
812 if (!j || !dcc[i].ssl || !td->socklist[j].ssl) {
813 Tcl_AppendResult(irp, "not a TLS connection", NULL);
814 return TCL_ERROR;
815 }
816
817 Tcl_DStringInit(&ds);
818 /* Try to get a cert, clients aren't required to send a
819 * certificate, so this is optional
820 */
821 cert = SSL_get_peer_certificate(td->socklist[j].ssl);
822 /* The following information is certificate dependent */
823 if (cert) {
824 p = ssl_printname(X509_get_subject_name(cert));
825 Tcl_DStringAppendElement(&ds, "subject");
826 Tcl_DStringAppendElement(&ds, p);
827 nfree(p);
828 p = ssl_printname(X509_get_issuer_name(cert));
829 Tcl_DStringAppendElement(&ds, "issuer");
830 Tcl_DStringAppendElement(&ds, p);
831 nfree(p);
832 p = ssl_printtime(X509_get_notBefore(cert));
833 Tcl_DStringAppendElement(&ds, "notBefore");
834 Tcl_DStringAppendElement(&ds, p);
835 nfree(p);
836 p = ssl_printtime(X509_get_notAfter(cert));
837 Tcl_DStringAppendElement(&ds, "notAfter");
838 Tcl_DStringAppendElement(&ds, p);
839 nfree(p);
840 p = ssl_printnum(X509_get_serialNumber(cert));
841 Tcl_DStringAppendElement(&ds, "serial");
842 Tcl_DStringAppendElement(&ds, p);
843 nfree(p);
844 }
845 /* We should always have a cipher, but who knows? */
846 cipher = SSL_get_current_cipher(td->socklist[j].ssl);
847 if (cipher) { /* don't bother if there's none */
848 Tcl_DStringAppendElement(&ds, "protocol");
849 Tcl_DStringAppendElement(&ds, SSL_CIPHER_get_version(cipher));
850 Tcl_DStringAppendElement(&ds, "cipher");
851 Tcl_DStringAppendElement(&ds, SSL_CIPHER_get_name(cipher));
852 }
853
854 /* Done, get a Tcl list from this and return it to the caller */
855 Tcl_AppendResult(irp, Tcl_DStringValue(&ds), NULL);
856 Tcl_DStringFree(&ds);
857 return TCL_OK;
858 }
859
860 /* These will be added by tcl.c which is the established practice */
861 tcl_cmds tcltls_cmds[] = {
862 {"istls", tcl_istls},
863 {"starttls", tcl_starttls},
864 {"tlsstatus", tcl_tlsstatus},
865 {NULL, NULL}
866 };
867
868 #endif /* TLS */

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23