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

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

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


Revision 1.3 - (hide 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 pseudo 1.1 /*
2     * tls.c -- handles:
3     * TLS support functions
4     * Certificate handling
5     * OpenSSL initialization and shutdown
6     *
7 pseudo 1.3 * $Id: tls.c,v 1.2 2010/10/19 14:20:56 pseudo Exp $
8 pseudo 1.1 */
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 pseudo 1.2 #ifdef HAVE_RAND_STATUS
81 pseudo 1.1 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 pseudo 1.2 #ifdef HAVE_RAND_STATUS
107 pseudo 1.1 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 pseudo 1.3 debug1("TLS: state change: %s", SSL_state_string_long(ssl));
632 pseudo 1.1 }
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