/[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.3 - (show annotations) (download) (as text)
Tue Nov 23 16:36:23 2010 UTC (8 years, 6 months ago) by pseudo
Branch: MAIN
Changes since 1.2: +2 -2 lines
File MIME type: text/x-chdr
Fixed a problem with sharing causing starttls to fail.
Moved STARTTLS early in the bot link process and synchronized the handshake.
Made it possible for ssl handshakes to complete even without data to be sent on the channel.
Fixed an ancient bug resulting in sending uninitialized strings when sharing bot addresses.
Enabled userfile sending over ssl.

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 2010/10/19 14:20:56 pseudo 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)) ? 0 : 1) : 0;
384 else
385 match = ssl_hostmatch(cn, data->host);
386 pos = X509_NAME_get_index_by_NID(subj, NID_commonName, pos);
387 }
388 }
389 }
390
391 if (ip)
392 ASN1_OCTET_STRING_free(ip);
393 return match;
394 }
395
396 /* Extract a human readable version of a X509_NAME and put the result
397 * into a nmalloc'd buffer.
398 * The X509_NAME structure is used for example in certificate subject
399 * and issuer names.
400 *
401 * You need to nfree() the returned pointer.
402 */
403 static char *ssl_printname(X509_NAME *name)
404 {
405 int len;
406 char *data, *buf;
407 BIO *bio = BIO_new(BIO_s_mem());
408
409 /* X509_NAME_oneline() is easier and shorter, but is deprecated and
410 the manual discourages it's usage, so let's not be lazy ;) */
411 X509_NAME_print_ex(bio, name, 0, XN_FLAG_ONELINE & ~XN_FLAG_SPC_EQ);
412 len = BIO_get_mem_data(bio, &data) + 1;
413 buf = nmalloc(len);
414 strncpyz(buf, data, len);
415 BIO_free(bio);
416 return buf;
417 }
418
419 /* Print the time from a ASN1_UTCTIME object in standard format i.e.
420 * Nov 21 23:59:00 1996 GMT and store it in a nmalloc'd buffer.
421 * The ASN1_UTCTIME structure is what's used for example with
422 * certificate validity dates.
423 *
424 * You need to nfree() the returned pointer.
425 */
426 static char *ssl_printtime(ASN1_UTCTIME *t)
427 {
428 int len;
429 char *data, *buf;
430 BIO *bio = BIO_new(BIO_s_mem());
431
432 ASN1_UTCTIME_print(bio, t);
433 len = BIO_get_mem_data(bio, &data) + 1;
434 buf = nmalloc(len);
435 strncpyz(buf, data, len);
436 BIO_free(bio);
437 return buf;
438 }
439
440 /* Print the value of an ASN1_INTEGER in hexadecimal format.
441 * A typical use for this is to display certificate serial numbers.
442 * As usual, we use a memory BIO.
443 *
444 * You need to nfree() the returned pointer.
445 */
446 static char *ssl_printnum(ASN1_INTEGER *i)
447 {
448 int len;
449 char *data, *buf;
450 BIO *bio = BIO_new(BIO_s_mem());
451
452 i2a_ASN1_INTEGER(bio, i);
453 len = BIO_get_mem_data(bio, &data) + 1;
454 buf = nmalloc(len);
455 strncpyz(buf, data, len);
456 BIO_free(bio);
457 return buf;
458 }
459
460 /* Show the user all relevant information about a certificate: subject,
461 * issuer, validity dates and fingerprints.
462 */
463 static void ssl_showcert(X509 *cert, int loglev)
464 {
465 char *buf, *from, *to;
466 X509_NAME *name;
467 unsigned int len;
468 unsigned char md[EVP_MAX_MD_SIZE];
469
470 /* Subject and issuer names */
471 if ((name = X509_get_subject_name(cert))) {
472 buf = ssl_printname(name);
473 putlog(loglev, "*", "TLS: certificate subject: %s", buf);
474 nfree(buf);
475 } else
476 putlog(loglev, "*", "TLS: cannot get subject name from certificate!");
477 if ((name = X509_get_issuer_name(cert))) {
478 buf = ssl_printname(name);
479 putlog(loglev, "*", "TLS: certificate issuer: %s", buf);
480 nfree(buf);
481 } else
482 putlog(loglev, "*", "TLS: cannot get issuer name from certificate!");
483
484 /* Fingerprints */
485 X509_digest(cert, EVP_md5(), md, &len); /* MD5 hash */
486 if (len <= sizeof(md)) {
487 buf = hex_to_string(md, len);
488 putlog(loglev, "*", "TLS: certificate MD5 Fingerprint: %s", buf);
489 OPENSSL_free(buf);
490 }
491 X509_digest(cert, EVP_sha1(), md, &len); /* SHA-1 hash */
492 if (len <= sizeof(md)) {
493 buf = hex_to_string(md, len);
494 putlog(loglev, "*", "TLS: certificate SHA1 Fingerprint: %s", buf);
495 OPENSSL_free(buf);
496 }
497
498 /* Validity time */
499 from = ssl_printtime(X509_get_notBefore(cert));
500 to = ssl_printtime(X509_get_notAfter(cert));
501 putlog(loglev, "*", "TLS: certificate valid from %s to %s", from, to);
502 nfree(from);
503 nfree(to);
504 }
505
506 /* Certificate validation callback
507 *
508 * Check if the certificate given is valid with respect to the
509 * ssl-verify config variable. This makes it possible to allow
510 * self-signed certificates and is also a convenient place to
511 * extract a certificate summary.
512 *
513 * Return value: 1 - validation passed, 0 - invalid cert
514 */
515 int ssl_verify(int ok, X509_STORE_CTX *ctx)
516 {
517 SSL *ssl;
518 X509 *cert;
519 ssl_appdata *data;
520 int err, depth;
521
522 /* get cert, callbacks, error codes, etc. */
523 depth = X509_STORE_CTX_get_error_depth(ctx);
524 cert = X509_STORE_CTX_get_current_cert(ctx);
525 ssl = X509_STORE_CTX_get_ex_data(ctx,
526 SSL_get_ex_data_X509_STORE_CTX_idx());
527 data = (ssl_appdata *) SSL_get_app_data(ssl);
528 err = X509_STORE_CTX_get_error(ctx);
529
530 /* OpenSSL won't explicitly generate this error; instead it will
531 * report missing certificates. Refer to SSL_CTX_set_verify(3)
532 * manual for details
533 */
534 if (depth > tls_maxdepth) {
535 ok = 0;
536 err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
537
538 /* depth 0 is actually the peer certificate. We do all custom
539 * verification here and leave the rest of the certificate chain
540 * to OpenSSL's built in procedures.
541 */
542 } else if (!depth) {
543 /* OpenSSL doesn't perform subject name verification. We need to do
544 * it ourselves. We check here for validity even if it's not requested
545 * in order to be able to warn the user.
546 */
547 if (!(data->flags & TLS_DEPTH0) && !ssl_verifycn(cert, data) &&
548 (data->verify & TLS_VERIFYCN)) {
549 putlog(data->loglevel, "*", "TLS: certificate validation failed. "
550 "Certificate subject does not match peer.");
551 return 0;
552 }
553 data->flags |= TLS_DEPTH0;
554 /* Allow exceptions for certain common verification errors, if the
555 * caller requested so. A lot of servers provide completely invalid
556 * certificates unuseful for any authentication.
557 */
558 if (!ok || data->verify)
559 if (((err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) &&
560 (data->verify & TLS_VERIFYISSUER)) ||
561 ((err == X509_V_ERR_CERT_REVOKED) &&
562 (data->verify & TLS_VERIFYREV)) ||
563 ((err == X509_V_ERR_CERT_NOT_YET_VALID) &&
564 (data->verify & TLS_VERIFYFROM)) ||
565 ((err == X509_V_ERR_CERT_HAS_EXPIRED) &&
566 (data->verify & TLS_VERIFYTO))) {
567 debug1("TLS: peer certificate warning: %s",
568 X509_verify_cert_error_string(err));
569 ok = 1;
570 }
571 }
572 if (ok || !data->verify)
573 return 1;
574 putlog(data->loglevel, "*",
575 "TLS: certificate validation failed at depth %d: %s",
576 depth, X509_verify_cert_error_string(err));
577 return 0;
578 }
579
580 /* SSL info callback, this is used to trace engine state changes
581 * and to check when the handshake is finished, so we can display
582 * some cipher and session information and process callbacks.
583 */
584 void ssl_info(SSL *ssl, int where, int ret)
585 {
586 int sock;
587 X509 *cert;
588 char buf[256];
589 ssl_appdata *data;
590 SSL_CIPHER *cipher;
591 int secret, processed;
592
593 /* We're doing non-blocking IO, so we check here if the handshake has
594 finished */
595 if (where & SSL_CB_HANDSHAKE_DONE) {
596 if (!(data = (ssl_appdata *) SSL_get_app_data(ssl)))
597 return;
598 /* Callback for completed handshake. Cheaper and more convenient than
599 using H_tls */
600 sock = SSL_get_fd(ssl);
601 if (data->cb)
602 data->cb(sock);
603 /* Call TLS binds. We allow scripts to take over or disable displaying of
604 certificate information. */
605 if (check_tcl_tls(sock))
606 return;
607
608 putlog(data->loglevel, "*", "TLS: handshake successful. Secure connection "
609 "established.");
610
611 if ((cert = SSL_get_peer_certificate(ssl)))
612 ssl_showcert(cert, data->loglevel);
613 else
614 putlog(data->loglevel, "*", "TLS: peer did not present a certificate");
615
616 /* Display cipher information */
617 cipher = SSL_get_current_cipher(ssl);
618 processed = SSL_CIPHER_get_bits(cipher, &secret);
619 putlog(data->loglevel, "*", "TLS: cipher used: %s %s; %d bits (%d secret)",
620 SSL_CIPHER_get_name(cipher), SSL_CIPHER_get_version(cipher),
621 processed, secret);
622 /* secret are the actually secret bits. If processed and secret differ,
623 the rest of the bits are fixed, i.e. for limited export ciphers */
624
625 /* More verbose information, for debugging only */
626 SSL_CIPHER_description(cipher, buf, sizeof buf);
627 debug1("TLS: cipher details: %s", buf);
628 }
629
630 /* Display the state of the engine for debugging purposes */
631 debug1("TLS: state change: %s", SSL_state_string_long(ssl));
632 }
633
634 /* Switch a socket to SSL communication
635 *
636 * Creates a SSL data structure for the connection;
637 * Sets up callbacks and initiates a SSL handshake with the peer;
638 * Reports error conditions and performs cleanup upon failure.
639 *
640 * flags: ssl flags, i.e connect or listen
641 * verify: peer certificate verification flags
642 * loglevel: is the level to output information about the connection
643 * and certificates.
644 * host: contains the dns name or ip address of the peer. Used for
645 * verification.
646 * cb: optional callback, this function will be called after the
647 * handshake completes.
648 *
649 * Return value: 0 on success, !=0 on failure.
650 */
651 int ssl_handshake(int sock, int flags, int verify, int loglevel, char *host,
652 IntFunc cb)
653 {
654 int i, err, ret;
655 ssl_appdata *data;
656 struct threaddata *td = threaddata();
657
658 debug0("TLS: attempting SSL negotiation...");
659 if (!ssl_ctx && ssl_init()) {
660 debug0("TLS: Failed. OpenSSL not initialized properly.");
661 return -1;
662 }
663 /* find the socket in the list */
664 i = findsock(sock);
665 if (i == -1) {
666 debug0("TLS: socket not in socklist");
667 return -2;
668 }
669 if (td->socklist[i].ssl) {
670 debug0("TLS: handshake not required - SSL session already established");
671 return 0;
672 }
673 td->socklist[i].ssl = SSL_new(ssl_ctx);
674 if (!td->socklist[i].ssl ||
675 !SSL_set_fd(td->socklist[i].ssl, td->socklist[i].sock)) {
676 debug1("TLS: cannot initiate SSL session - %s",
677 ERR_error_string(ERR_get_error(), 0));
678 return -3;
679 }
680
681 /* Prepare a ssl appdata struct for the verify callback */
682 data = nmalloc(sizeof(ssl_appdata));
683 egg_bzero(data, sizeof(ssl_appdata));
684 data->flags = flags & (TLS_LISTEN | TLS_CONNECT);
685 data->verify = flags & ~(TLS_LISTEN | TLS_CONNECT);
686 data->loglevel = loglevel;
687 data->cb = cb;
688 strncpyz(data->host, host ? host : "", sizeof(data->host));
689 SSL_set_app_data(td->socklist[i].ssl, data);
690 SSL_set_info_callback(td->socklist[i].ssl, (void *) ssl_info);
691 /* We set this +1 to be able to report extra long chains properly.
692 * Otherwise, OpenSSL will break the verification reporting about
693 * missing certificates instead. The rest of the fix is in
694 * ssl_verify()
695 */
696 SSL_set_verify_depth(td->socklist[i].ssl, tls_maxdepth + 1);
697
698 SSL_set_mode(td->socklist[i].ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
699 if (data->flags & TLS_CONNECT) {
700 SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER, ssl_verify);
701 ret = SSL_connect(td->socklist[i].ssl);
702 if (!ret)
703 debug0("TLS: connect handshake failed.");
704 } else {
705 if (data->flags & TLS_VERIFYPEER)
706 SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER |
707 SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify);
708 else
709 SSL_set_verify(td->socklist[i].ssl, SSL_VERIFY_PEER, ssl_verify);
710 ret = SSL_accept(td->socklist[i].ssl);
711 if (!ret)
712 debug0("TLS: accept handshake failed");
713 }
714
715 err = SSL_get_error(td->socklist[i].ssl, ret);
716 /* Normal condition for async I/O, similar to EAGAIN */
717 if (ret > 0 || err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
718 debug0("TLS: handshake in progress");
719 return 0;
720 }
721 if (ERR_peek_error())
722 debug0("TLS: handshake failed due to the following errors: ");
723 while ((err = ERR_get_error()))
724 debug1("TLS: %s", ERR_error_string(err, NULL));
725
726 /* Attempt failed, cleanup and abort */
727 SSL_shutdown(td->socklist[i].ssl);
728 SSL_free(td->socklist[i].ssl);
729 td->socklist[i].ssl = NULL;
730 nfree(data);
731 return -4;
732 }
733
734 /* Tcl functions */
735
736 /* Is the connection secure? */
737 static int tcl_istls STDVAR
738 {
739 int j;
740
741 BADARGS(2, 2, " idx");
742
743 j = findidx(atoi(argv[1]));
744 if (j < 0) {
745 Tcl_AppendResult(irp, "invalid idx", NULL);
746 return TCL_ERROR;
747 }
748 if (dcc[j].ssl)
749 Tcl_AppendResult(irp, "1", NULL);
750 else
751 Tcl_AppendResult(irp, "0", NULL);
752 return TCL_OK;
753 }
754
755 /* Perform a SSL handshake over an existing plain text
756 * connection.
757 */
758 static int tcl_starttls STDVAR
759 {
760 int j;
761 struct threaddata *td = threaddata();
762
763 BADARGS(2, 2, " idx");
764
765 j = findidx(atoi(argv[1]));
766 if (j < 0 || (dcc[j].type != &DCC_SCRIPT)) {
767 Tcl_AppendResult(irp, "invalid idx", NULL);
768 return TCL_ERROR;
769 }
770 if (dcc[j].ssl) {
771 Tcl_AppendResult(irp, "already started", NULL);
772 return TCL_ERROR;
773 }
774 /* Determine if we're playing a client or a server */
775 j = findsock(dcc[j].sock);
776 if (ssl_handshake(dcc[j].sock, (td->socklist[j].flags & SOCK_CONNECT) ?
777 TLS_CONNECT : TLS_LISTEN, tls_vfydcc, LOG_MISC, NULL, NULL))
778 Tcl_AppendResult(irp, "0", NULL);
779 else
780 Tcl_AppendResult(irp, "1", NULL);
781 return TCL_OK;
782 }
783
784 /* Get all relevant information about an established ssl connection.
785 * This includes certificate subject and issuer, serial number,
786 * expiry date, protocol version and cipher information.
787 * All data is presented as a flat list consisting of name-value pairs.
788 */
789 static int tcl_tlsstatus STDVAR
790 {
791 char *p;
792 int i, j;
793 X509 *cert;
794 SSL_CIPHER *cipher;
795 struct threaddata *td = threaddata();
796 Tcl_DString ds;
797
798 BADARGS(2, 2, " idx");
799
800 /* Allow it to be used for any connection, not just scripted
801 * ones. This makes it possible for a script to display the
802 * server certificate.
803 */
804 i = findanyidx(atoi(argv[1]));
805 if (i < 0) {
806 Tcl_AppendResult(irp, "invalid idx", NULL);
807 return TCL_ERROR;
808 }
809 j = findsock(dcc[i].sock);
810 if (!j || !dcc[i].ssl || !td->socklist[j].ssl) {
811 Tcl_AppendResult(irp, "not a TLS connection", NULL);
812 return TCL_ERROR;
813 }
814
815 Tcl_DStringInit(&ds);
816 /* Try to get a cert, clients aren't required to send a
817 * certificate, so this is optional
818 */
819 cert = SSL_get_peer_certificate(td->socklist[j].ssl);
820 /* The following information is certificate dependent */
821 if (cert) {
822 p = ssl_printname(X509_get_subject_name(cert));
823 Tcl_DStringAppendElement(&ds, "subject");
824 Tcl_DStringAppendElement(&ds, p);
825 nfree(p);
826 p = ssl_printname(X509_get_issuer_name(cert));
827 Tcl_DStringAppendElement(&ds, "issuer");
828 Tcl_DStringAppendElement(&ds, p);
829 nfree(p);
830 p = ssl_printtime(X509_get_notBefore(cert));
831 Tcl_DStringAppendElement(&ds, "notBefore");
832 Tcl_DStringAppendElement(&ds, p);
833 nfree(p);
834 p = ssl_printtime(X509_get_notAfter(cert));
835 Tcl_DStringAppendElement(&ds, "notAfter");
836 Tcl_DStringAppendElement(&ds, p);
837 nfree(p);
838 p = ssl_printnum(X509_get_serialNumber(cert));
839 Tcl_DStringAppendElement(&ds, "serial");
840 Tcl_DStringAppendElement(&ds, p);
841 nfree(p);
842 }
843 /* We should always have a cipher, but who knows? */
844 cipher = SSL_get_current_cipher(td->socklist[j].ssl);
845 if (cipher) { /* don't bother if there's none */
846 Tcl_DStringAppendElement(&ds, "protocol");
847 Tcl_DStringAppendElement(&ds, SSL_CIPHER_get_version(cipher));
848 Tcl_DStringAppendElement(&ds, "cipher");
849 Tcl_DStringAppendElement(&ds, SSL_CIPHER_get_name(cipher));
850 }
851
852 /* Done, get a Tcl list from this and return it to the caller */
853 Tcl_AppendResult(irp, Tcl_DStringValue(&ds), NULL);
854 Tcl_DStringFree(&ds);
855 return TCL_OK;
856 }
857
858 /* These will be added by tcl.c which is the established practice */
859 tcl_cmds tcltls_cmds[] = {
860 {"istls", tcl_istls},
861 {"starttls", tcl_starttls},
862 {"tlsstatus", tcl_tlsstatus},
863 {NULL, NULL}
864 };
865
866 #endif /* TLS */

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23