1 /* ========================================================================
2 * Copyright 2008-2009 Mark Crispin
3 * ========================================================================
7 * Program: SSL authentication/encryption module
11 * Date: 22 September 1998
12 * Last Edited: 8 November 2009
14 * Previous versions of this file were
16 * Copyright 1988-2008 University of Washington
18 * Licensed under the Apache License, Version 2.0 (the "License");
19 * you may not use this file except in compliance with the License.
20 * You may obtain a copy of the License at
22 * http://www.apache.org/licenses/LICENSE-2.0
26 #define crypt ssl_private_crypt
27 #define STRING OPENSSL_STRING
39 #define SSLBUFLEN 8192
42 * PCI auditing compliance, disable:
44 * anonymous D-H (no certificate
45 * export encryption ciphers (40 and 56 bits)
46 * low encryption cipher suites (40 and 56 bits, excluding export)
47 * null encryption (disabling implied by "ALL")
49 * UW imapd just disables low-grade and null ("ALL:!LOW"). This setting
50 * will break clients that attempt to use the newly-prohibited mechanisms.
52 * I question the value of disabling SSLv2, as opposed to disabling the SSL
53 * ports (e.g., 993 for IMAP, 995 for POP3) and using TLS exclusively.
56 #define SSLCIPHERLIST "ALL:!SSLv2:!ADH:!EXP:!LOW"
60 typedef struct ssl_stream
{
61 TCPSTREAM
*tcpstream
; /* TCP stream */
62 SSL_CTX
*context
; /* SSL context */
63 SSL
*con
; /* SSL connection */
64 int ictr
; /* input counter */
65 char *iptr
; /* input pointer */
66 char ibuf
[SSLBUFLEN
]; /* input buffer */
71 /* Function prototypes */
72 const SSL_METHOD
*ssl_connect_mthd(int flag
);
73 static SSLSTREAM
*ssl_start(TCPSTREAM
*tstream
,char *host
,unsigned long flags
);
74 static char *ssl_start_work (SSLSTREAM
*stream
,char *host
,unsigned long flags
);
75 static int ssl_open_verify (int ok
,X509_STORE_CTX
*ctx
);
76 static char *ssl_validate_cert (X509
*cert
,char *host
);
77 static long ssl_compare_hostnames (unsigned char *s
,unsigned char *pat
);
78 static char *ssl_getline_work (SSLSTREAM
*stream
,unsigned long *size
,
80 static long ssl_abort (SSLSTREAM
*stream
);
81 static RSA
*ssl_genkey (SSL
*con
,int export
,int keylength
);
84 /* Secure Sockets Layer network driver dispatch */
86 static struct ssl_driver ssldriver
= {
87 ssl_open
, /* open connection */
88 ssl_aopen
, /* open preauthenticated connection */
89 ssl_getline
, /* get a line */
90 ssl_getbuffer
, /* get a buffer */
91 ssl_soutr
, /* output pushed data */
92 ssl_sout
, /* output string */
93 ssl_close
, /* close connection */
94 ssl_host
, /* return host name */
95 ssl_remotehost
, /* return remote host name */
96 ssl_port
, /* return port number */
97 ssl_localhost
/* return local host name */
99 /* non-NIL if doing SSL primary I/O */
100 static SSLSTDIOSTREAM
*sslstdio
= NIL
;
101 static char *start_tls
= NIL
; /* non-NIL if start TLS requested */
103 /* One-time SSL initialization */
105 static int sslonceonly
= 0;
107 void ssl_onceonlyinit (void)
109 if (!sslonceonly
++) { /* only need to call it once */
111 char tmp
[MAILTMPLEN
];
113 /* if system doesn't have /dev/urandom */
114 if (stat ("/dev/urandom",&sbuf
)) {
115 strcpy(tmp
, "SSLXXXXXX");
116 while ((fd
= mkstemp(tmp
)) < 0) sleep (1);
117 unlink (tmp
); /* don't need the file */
118 fstat (fd
,&sbuf
); /* get information about the file */
119 close (fd
); /* flush descriptor */
120 /* not great but it'll have to do */
121 sprintf (tmp
+ strlen (tmp
),"%.80s%lx%.80s%lx%lx%lx%lx%lx",
122 tcp_serveraddr (),(unsigned long) tcp_serverport (),
123 tcp_clientaddr (),(unsigned long) tcp_clientport (),
124 (unsigned long) sbuf
.st_ino
,(unsigned long) time (0),
125 (unsigned long) gethostid (),(unsigned long) getpid ());
126 RAND_seed (tmp
,strlen (tmp
));
128 /* apply runtime linkage */
129 mail_parameters (NIL
,SET_SSLDRIVER
,(void *) &ssldriver
);
130 mail_parameters (NIL
,SET_SSLSTART
,(void *) ssl_start
);
131 SSL_library_init (); /* add all algorithms */
137 * contact service name
138 * contact port number
139 * Returns: SSL stream if success else NIL
142 SSLSTREAM
*ssl_open (char *host
,char *service
,unsigned long port
)
144 TCPSTREAM
*stream
= tcp_open (host
,service
,port
);
145 return stream
? ssl_start (stream
,host
,port
) : NIL
;
149 /* SSL authenticated open
152 * returned user name buffer
153 * Returns: SSL stream if success else NIL
156 SSLSTREAM
*ssl_aopen (NETMBX
*mb
,char *service
,char *usrbuf
)
158 return NIL
; /* don't use this mechanism with SSL */
161 /* ssl_connect_mthd: returns a context pointer to the connection to
164 const SSL_METHOD
*ssl_connect_mthd(int flag
)
166 if(flag
& NET_TRYTLS1
)
167 return TLSv1_client_method();
169 else if(flag
& NET_TRYTLS1_1
)
170 return TLSv1_1_client_method();
171 else if(flag
& NET_TRYTLS1_2
)
172 return TLSv1_2_client_method();
174 else if(flag
& NET_TRYDTLS1
)
175 return DTLSv1_client_method();
176 else return SSLv23_client_method();
179 /* Start SSL/TLS negotiations
180 * Accepts: open TCP stream of session
183 * Returns: SSL stream if success else NIL
186 static SSLSTREAM
*ssl_start (TCPSTREAM
*tstream
,char *host
,unsigned long flags
)
188 char *reason
,tmp
[MAILTMPLEN
];
189 sslfailure_t sf
= (sslfailure_t
) mail_parameters (NIL
,GET_SSLFAILURE
,NIL
);
190 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
191 void *data
= (*bn
) (BLOCK_SENSITIVE
,NIL
);
192 SSLSTREAM
*stream
= (SSLSTREAM
*) memset (fs_get (sizeof (SSLSTREAM
)),0,
194 stream
->tcpstream
= tstream
; /* bind TCP stream */
196 reason
= ssl_start_work (stream
,host
,flags
);
197 (*bn
) (BLOCK_NONSENSITIVE
,data
);
198 if (reason
) { /* failed? */
199 ssl_close (stream
); /* failed to do SSL */
200 stream
= NIL
; /* no stream returned */
201 switch (*reason
) { /* analyze reason */
202 case '*': /* certificate failure */
203 ++reason
; /* skip over certificate failure indication */
204 /* pass to error callback */
205 if (sf
) (*sf
) (host
,reason
,flags
);
206 else { /* no error callback, build error message */
207 sprintf (tmp
,"Certificate failure for %.80s: %.512s",host
,reason
);
210 case '\0': /* user answered no to certificate callback */
211 if (flags
& NET_TRYSSL
) /* return dummy stream to stop tryssl */
212 stream
= (SSLSTREAM
*) memset (fs_get (sizeof (SSLSTREAM
)),0,
215 default: /* non-certificate failure */
216 if (flags
& NET_TRYSSL
); /* no error output if tryssl */
217 /* pass to error callback */
218 else if (sf
) (*sf
) (host
,reason
,flags
);
219 else { /* no error callback, build error message */
220 sprintf (tmp
,"TLS/SSL failure for %.80s: %.512s",host
,reason
);
229 /* Start SSL/TLS negotiations worker routine
230 * Accepts: SSL stream
233 * Returns: NIL if success, else error reason
236 /* evil but I had no choice */
237 static char *ssl_last_error
= NIL
;
238 static char *ssl_last_host
= NIL
;
240 static char *ssl_start_work (SSLSTREAM
*stream
,char *host
,unsigned long flags
)
245 char *s
,*t
,*err
,tmp
[MAILTMPLEN
];
246 sslcertificatequery_t scq
=
247 (sslcertificatequery_t
) mail_parameters (NIL
,GET_SSLCERTIFICATEQUERY
,NIL
);
248 sslclientcert_t scc
=
249 (sslclientcert_t
) mail_parameters (NIL
,GET_SSLCLIENTCERT
,NIL
);
251 (sslclientkey_t
) mail_parameters (NIL
,GET_SSLCLIENTKEY
,NIL
);
252 if (ssl_last_error
) fs_give ((void **) &ssl_last_error
);
253 ssl_last_host
= host
;
254 if (!(stream
->context
= SSL_CTX_new (ssl_connect_mthd(flags
))))
255 return "SSL context failed";
256 SSL_CTX_set_options (stream
->context
,0);
257 /* disable certificate validation? */
258 if (flags
& NET_NOVALIDATECERT
)
259 SSL_CTX_set_verify (stream
->context
,SSL_VERIFY_NONE
,NIL
);
260 else SSL_CTX_set_verify (stream
->context
,SSL_VERIFY_PEER
,ssl_open_verify
);
261 /* set default paths to CAs... */
262 SSL_CTX_set_default_verify_paths (stream
->context
);
263 /* ...unless a non-standard path desired */
264 if (s
= (char *) mail_parameters (NIL
,GET_SSLCAPATH
,NIL
))
265 SSL_CTX_load_verify_locations (stream
->context
,NIL
,s
);
266 /* want to send client certificate? */
267 if (scc
&& (s
= (*scc
) ()) && (sl
= strlen (s
))) {
268 if (cert
= PEM_read_bio_X509 (bio
= BIO_new_mem_buf (s
,sl
),NIL
,NIL
,NIL
)) {
269 SSL_CTX_use_certificate (stream
->context
,cert
);
273 if (!cert
) return "SSL client certificate failed";
274 /* want to supply private key? */
275 if ((t
= (sck
? (*sck
) () : s
)) && (tl
= strlen (t
))) {
277 if (key
= PEM_read_bio_PrivateKey (bio
= BIO_new_mem_buf (t
,tl
),
279 SSL_CTX_use_PrivateKey (stream
->context
,key
);
283 memset (t
,0,tl
); /* erase key */
285 if (s
!= t
) memset (s
,0,sl
);/* erase certificate if different from key */
288 /* create connection */
289 if (!(stream
->con
= (SSL
*) SSL_new (stream
->context
)))
290 return "SSL connection failed";
291 bio
= BIO_new_socket (stream
->tcpstream
->tcpsi
,BIO_NOCLOSE
);
292 SSL_set_bio (stream
->con
,bio
,bio
);
293 SSL_set_connect_state (stream
->con
);
294 if (SSL_in_init (stream
->con
)) SSL_total_renegotiations (stream
->con
);
295 /* now negotiate SSL */
296 if (SSL_write (stream
->con
,"",0) < 0)
297 return ssl_last_error
? ssl_last_error
: "SSL negotiation failed";
298 /* need to validate host names? */
299 if (!(flags
& NET_NOVALIDATECERT
) &&
300 (err
= ssl_validate_cert (cert
= SSL_get_peer_certificate (stream
->con
),
302 /* application callback */
303 if (scq
) return (*scq
) (err
,host
,cert
? cert
->name
: "???") ? NIL
: "";
304 /* error message to return via mm_log() */
305 sprintf (tmp
,"*%.128s: %.255s",err
,cert
? cert
->name
: "???");
306 return ssl_last_error
= cpystr (tmp
);
311 /* SSL certificate verification callback
312 * Accepts: error flag
314 * Returns: error flag
317 static int ssl_open_verify (int ok
,X509_STORE_CTX
*ctx
)
319 char *err
,cert
[256],tmp
[MAILTMPLEN
];
320 sslcertificatequery_t scq
=
321 (sslcertificatequery_t
) mail_parameters (NIL
,GET_SSLCERTIFICATEQUERY
,NIL
);
322 if (!ok
) { /* in case failure */
323 err
= (char *) X509_verify_cert_error_string
324 (X509_STORE_CTX_get_error (ctx
));
325 X509_NAME_oneline (X509_get_subject_name
326 (X509_STORE_CTX_get_current_cert (ctx
)),cert
,255);
327 if (!scq
) { /* mm_log() error message if no callback */
328 sprintf (tmp
,"*%.128s: %.255s",err
,cert
);
329 ssl_last_error
= cpystr (tmp
);
331 /* ignore error if application says to */
332 else if ((*scq
) (err
,ssl_last_host
,cert
)) ok
= T
;
333 /* application wants punt */
334 else ssl_last_error
= cpystr ("");
340 /* SSL validate certificate
341 * Accepts: certificate
342 * host to validate against
343 * Returns: NIL if validated, else string of error message
346 static char *ssl_validate_cert (X509
*cert
,char *host
)
352 /* make sure have a certificate */
353 if (!cert
) ret
= "No certificate from server";
354 /* and that it has a name */
355 else if (!cert
->name
) ret
= "No name in certificate";
357 else if (s
= strstr (cert
->name
,"/CN=")) {
358 if (t
= strchr (s
+= 4,'/')) *t
= '\0';
359 /* host name matches pattern? */
360 ret
= ssl_compare_hostnames (host
,s
) ? NIL
:
361 "Server name does not match certificate";
362 if (t
) *t
= '/'; /* restore smashed delimiter */
363 /* if mismatch, see if in extensions */
364 if (ret
&& (ext
= X509_get_ext_d2i (cert
,NID_subject_alt_name
,NIL
,NIL
)) &&
365 (n
= sk_GENERAL_NAME_num (ext
)))
366 /* older versions of OpenSSL use "ia5" instead of dNSName */
367 for (i
= 0; ret
&& (i
< n
); i
++)
368 if ((name
= sk_GENERAL_NAME_value (ext
,i
)) &&
369 (name
->type
= GEN_DNS
) && (s
= name
->d
.ia5
->data
) &&
370 ssl_compare_hostnames (host
,s
)) ret
= NIL
;
372 else ret
= "Unable to locate common name in certificate";
376 /* Case-independent wildcard pattern match
377 * Accepts: base string
379 * Returns: T if pattern matches base, else NIL
382 static long ssl_compare_hostnames (unsigned char *s
,unsigned char *pat
)
386 case '*': /* wildcard */
387 if (pat
[1]) { /* there must be a pattern suffix */
388 /* there is, scan base against it */
389 do if (ssl_compare_hostnames (s
,pat
+1)) ret
= LONGT
;
390 while (!ret
&& (*s
!= '.') && *s
++);
393 case '\0': /* end of pattern */
394 if (!*s
) ret
= LONGT
; /* success if base is also at end */
396 default: /* non-wildcard, recurse if match */
397 if (!compare_uchar (*pat
,*s
)) ret
= ssl_compare_hostnames (s
+1,pat
+1);
404 * Accepts: SSL stream
405 * Returns: text line string or NIL if failure
408 char *ssl_getline (SSLSTREAM
*stream
)
410 unsigned long n
,contd
;
411 char *ret
= ssl_getline_work (stream
,&n
,&contd
);
412 if (ret
&& contd
) { /* got a line needing continuation? */
413 STRINGLIST
*stl
= mail_newstringlist ();
414 STRINGLIST
*stc
= stl
;
415 do { /* collect additional lines */
416 stc
->text
.data
= (unsigned char *) ret
;
418 stc
= stc
->next
= mail_newstringlist ();
419 ret
= ssl_getline_work (stream
,&n
,&contd
);
420 } while (ret
&& contd
);
421 if (ret
) { /* stash final part of line on list */
422 stc
->text
.data
= (unsigned char *) ret
;
424 /* determine how large a buffer we need */
425 for (n
= 0, stc
= stl
; stc
; stc
= stc
->next
) n
+= stc
->text
.size
;
426 ret
= fs_get (n
+ 1); /* copy parts into buffer */
427 for (n
= 0, stc
= stl
; stc
; n
+= stc
->text
.size
, stc
= stc
->next
)
428 memcpy (ret
+ n
,stc
->text
.data
,stc
->text
.size
);
431 mail_free_stringlist (&stl
);/* either way, done with list */
436 /* SSL receive line or partial line
437 * Accepts: SSL stream
438 * pointer to return size
439 * pointer to return continuation flag
440 * Returns: text line string, size and continuation flag, or NIL if failure
443 static char *ssl_getline_work (SSLSTREAM
*stream
,unsigned long *size
,
448 *contd
= NIL
; /* assume no continuation */
449 /* make sure have data */
450 if (!ssl_getdata (stream
)) return NIL
;
451 for (s
= stream
->iptr
, n
= 0, c
= '\0'; stream
->ictr
--; n
++, c
= d
) {
452 d
= *stream
->iptr
++; /* slurp another character */
453 if ((c
== '\015') && (d
== '\012')) {
454 ret
= (char *) fs_get (n
--);
455 memcpy (ret
,s
,*size
= n
); /* copy into a free storage string */
456 ret
[n
] = '\0'; /* tie off string with null */
460 /* copy partial string from buffer */
461 memcpy ((ret
= (char *) fs_get (n
)),s
,*size
= n
);
462 /* get more data from the net */
463 if (!ssl_getdata (stream
)) fs_give ((void **) &ret
);
464 /* special case of newline broken by buffer */
465 else if ((c
== '\015') && (*stream
->iptr
== '\012')) {
466 stream
->iptr
++; /* eat the line feed */
468 ret
[*size
= --n
] = '\0'; /* tie off string with null */
470 else *contd
= LONGT
; /* continuation needed */
474 /* SSL receive buffer
475 * Accepts: SSL stream
477 * buffer to read into
478 * Returns: T if success, NIL otherwise
481 long ssl_getbuffer (SSLSTREAM
*stream
,unsigned long size
,char *buffer
)
484 while (size
> 0) { /* until request satisfied */
485 if (!ssl_getdata (stream
)) return NIL
;
486 n
= min (size
,stream
->ictr
);/* number of bytes to transfer */
488 memcpy (buffer
,stream
->iptr
,n
);
489 buffer
+= n
; /* update pointer */
491 size
-= n
; /* update # of bytes to do */
494 buffer
[0] = '\0'; /* tie off string */
499 * Accepts: TCP/IP stream
500 * Returns: T if success, NIL otherwise
503 long ssl_getdata (SSLSTREAM
*stream
)
508 tcptimeout_t tmoh
= (tcptimeout_t
) mail_parameters (NIL
,GET_TIMEOUT
,NIL
);
509 long ttmo_read
= (long) mail_parameters (NIL
,GET_READTIMEOUT
,NIL
);
511 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
512 if (!stream
->con
|| ((sock
= SSL_get_fd (stream
->con
)) < 0)) return NIL
;
513 /* tcp_unix should have prevented this */
514 if (sock
>= FD_SETSIZE
) fatal ("unselectable socket in ssl_getdata()");
515 (*bn
) (BLOCK_TCPREAD
,NIL
);
516 while (stream
->ictr
< 1) { /* if nothing in the buffer */
517 time_t tl
= time (0); /* start of request */
519 int ti
= ttmo_read
? now
+ ttmo_read
: 0;
520 if (SSL_pending (stream
->con
)) i
= 1;
522 if (tcpdebug
) mm_log ("Reading SSL data",TCPDEBUG
);
524 FD_ZERO (&fds
); /* initialize selection vector */
525 FD_ZERO (&efds
); /* handle errors too */
526 FD_SET (sock
,&fds
); /* set bit in selection vector */
527 FD_SET (sock
,&efds
); /* set bit in error selection vector */
528 errno
= NIL
; /* block and read */
529 do { /* block under timeout */
530 tmo
.tv_sec
= ti
? ti
- now
: 0;
531 i
= select (sock
+1,&fds
,0,&efds
,ti
? &tmo
: 0);
532 now
= time (0); /* fake timeout if interrupt & time expired */
533 if ((i
< 0) && (errno
== EINTR
) && ti
&& (ti
<= now
)) i
= 0;
534 } while ((i
< 0) && (errno
== EINTR
));
536 if (i
) { /* non-timeout result from select? */
537 errno
= 0; /* just in case */
538 if (i
> 0) /* read what we can */
539 while (((i
= SSL_read (stream
->con
,stream
->ibuf
,SSLBUFLEN
)) < 0) &&
541 (SSL_get_error (stream
->con
,i
) == SSL_ERROR_WANT_READ
)));
542 if (i
<= 0) { /* error seen? */
544 char *s
,tmp
[MAILTMPLEN
];
545 if (i
) sprintf (s
= tmp
,"SSL data read I/O error %d SSL error %d",
546 errno
,SSL_get_error (stream
->con
,i
));
547 else s
= "SSL data read end of file";
550 return ssl_abort (stream
);
552 stream
->iptr
= stream
->ibuf
;/* point at TCP buffer */
553 stream
->ictr
= i
; /* set new byte count */
554 if (tcpdebug
) mm_log ("Successfully read SSL data",TCPDEBUG
);
556 /* timeout, punt unless told not to */
557 else if (!tmoh
|| !(*tmoh
) (now
- t
,now
- tl
, stream
->tcpstream
->host
)) {
558 if (tcpdebug
) mm_log ("SSL data read timeout",TCPDEBUG
);
559 return ssl_abort (stream
);
562 (*bn
) (BLOCK_NONE
,NIL
);
566 /* SSL send string as record
567 * Accepts: SSL stream
569 * Returns: T if success else NIL
572 long ssl_soutr (SSLSTREAM
*stream
,char *string
)
574 return ssl_sout (stream
,string
,(unsigned long) strlen (string
));
579 * Accepts: SSL stream
582 * Returns: T if success else NIL
585 long ssl_sout (SSLSTREAM
*stream
,char *string
,unsigned long size
)
588 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
589 if (!stream
->con
) return NIL
;
590 (*bn
) (BLOCK_TCPWRITE
,NIL
);
591 if (tcpdebug
) mm_log ("Writing to SSL",TCPDEBUG
);
592 /* until request satisfied */
593 for (i
= 0; size
> 0; string
+= i
,size
-= i
)
594 /* write as much as we can */
595 if ((i
= SSL_write (stream
->con
,string
,(int) min (SSLBUFLEN
,size
))) < 0) {
597 char tmp
[MAILTMPLEN
];
598 sprintf (tmp
,"SSL data write I/O error %d SSL error %d",
599 errno
,SSL_get_error (stream
->con
,i
));
600 mm_log (tmp
,TCPDEBUG
);
602 return ssl_abort (stream
);/* write failed */
604 if (tcpdebug
) mm_log ("successfully wrote to TCP",TCPDEBUG
);
605 (*bn
) (BLOCK_NONE
,NIL
);
606 return LONGT
; /* all done */
610 * Accepts: SSL stream
613 void ssl_close (SSLSTREAM
*stream
)
615 ssl_abort (stream
); /* nuke the stream */
616 fs_give ((void **) &stream
); /* flush the stream */
621 * Accepts: SSL stream
622 * Returns: NIL always
625 static long ssl_abort (SSLSTREAM
*stream
)
627 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
628 if (stream
->con
) { /* close SSL connection */
629 SSL_shutdown (stream
->con
);
630 SSL_free (stream
->con
);
633 if (stream
->context
) { /* clean up context */
634 SSL_CTX_free (stream
->context
);
635 stream
->context
= NIL
;
637 if (stream
->tcpstream
) { /* close TCP stream */
638 tcp_close (stream
->tcpstream
);
639 stream
->tcpstream
= NIL
;
641 (*bn
) (BLOCK_NONE
,NIL
);
646 * Accepts: SSL stream
647 * Returns: host name for this stream
650 char *ssl_host (SSLSTREAM
*stream
)
652 return stream
? tcp_host (stream
->tcpstream
) : "UNKNOWN";
656 /* SSL get remote host name
657 * Accepts: SSL stream
658 * Returns: host name for this stream
661 char *ssl_remotehost (SSLSTREAM
*stream
)
663 return tcp_remotehost (stream
->tcpstream
);
667 /* SSL return port for this stream
668 * Accepts: SSL stream
669 * Returns: port number for this stream
672 unsigned long ssl_port (SSLSTREAM
*stream
)
674 return tcp_port (stream
->tcpstream
);
678 /* SSL get local host name
679 * Accepts: SSL stream
680 * Returns: local host name
683 char *ssl_localhost (SSLSTREAM
*stream
)
685 return tcp_localhost (stream
->tcpstream
);
689 * Accepts: /etc/services service name
690 * Returns: cpystr'd error string if TLS failed, else NIL for success
693 char *ssl_start_tls (char *server
)
695 char tmp
[MAILTMPLEN
];
697 if (sslstdio
) return cpystr ("Already in an SSL session");
698 if (start_tls
) return cpystr ("TLS already started");
699 if (server
) { /* build specific certificate/key file name */
700 sprintf (tmp
,"%s/%s-%s.pem",SSL_CERT_DIRECTORY
,server
,tcp_serveraddr ());
701 if (stat (tmp
,&sbuf
)) { /* use non-specific name if no specific file */
702 sprintf (tmp
,"%s/%s.pem",SSL_CERT_DIRECTORY
,server
);
703 if (stat (tmp
,&sbuf
)) return cpystr ("Server certificate not installed");
705 start_tls
= server
; /* switch to STARTTLS mode */
710 /* Init server for SSL
711 * Accepts: server name
714 void ssl_server_init (char *server
)
716 char cert
[MAILTMPLEN
],key
[MAILTMPLEN
];
719 SSLSTREAM
*stream
= (SSLSTREAM
*) memset (fs_get (sizeof (SSLSTREAM
)),0,
721 ssl_onceonlyinit (); /* make sure algorithms added */
722 ERR_load_crypto_strings ();
723 SSL_load_error_strings ();
724 /* build specific certificate/key file names */
725 sprintf (cert
,"%s/%s-%s.pem",SSL_CERT_DIRECTORY
,server
,tcp_serveraddr ());
726 sprintf (key
,"%s/%s-%s.pem",SSL_KEY_DIRECTORY
,server
,tcp_serveraddr ());
727 /* use non-specific name if no specific cert */
728 if (stat (cert
,&sbuf
)) sprintf (cert
,"%s/%s.pem",SSL_CERT_DIRECTORY
,server
);
729 if (stat (key
,&sbuf
)) { /* use non-specific name if no specific key */
730 sprintf (key
,"%s/%s.pem",SSL_KEY_DIRECTORY
,server
);
731 /* use cert file as fallback for key */
732 if (stat (key
,&sbuf
)) strcpy (key
,cert
);
735 if (!(stream
->context
= SSL_CTX_new (start_tls
?
736 TLSv1_server_method () :
737 SSLv23_server_method ())))
738 syslog (LOG_ALERT
,"Unable to create SSL context, host=%.80s",
740 else { /* set context options */
741 SSL_CTX_set_options (stream
->context
,SSL_OP_ALL
);
742 /* set cipher list */
743 if (!SSL_CTX_set_cipher_list (stream
->context
,SSLCIPHERLIST
))
744 syslog (LOG_ALERT
,"Unable to set cipher list %.80s, host=%.80s",
745 SSLCIPHERLIST
,tcp_clienthost ());
746 /* load certificate */
747 else if (!SSL_CTX_use_certificate_chain_file (stream
->context
,cert
))
748 syslog (LOG_ALERT
,"Unable to load certificate from %.80s, host=%.80s",
749 cert
,tcp_clienthost ());
751 else if (!(SSL_CTX_use_RSAPrivateKey_file (stream
->context
,key
,
753 syslog (LOG_ALERT
,"Unable to load private key from %.80s, host=%.80s",
754 key
,tcp_clienthost ());
756 else { /* generate key if needed */
757 if (SSL_CTX_need_tmp_RSA (stream
->context
))
758 SSL_CTX_set_tmp_rsa_callback (stream
->context
,ssl_genkey
);
759 /* create new SSL connection */
760 if (!(stream
->con
= SSL_new (stream
->context
)))
761 syslog (LOG_ALERT
,"Unable to create SSL connection, host=%.80s",
763 else { /* set file descriptor */
764 SSL_set_fd (stream
->con
,0);
765 /* all OK if accepted */
766 if (SSL_accept (stream
->con
) < 0)
767 syslog (LOG_INFO
,"Unable to accept SSL connection, host=%.80s",
769 else { /* server set up */
770 sslstdio
= (SSLSTDIOSTREAM
*)
771 memset (fs_get (sizeof(SSLSTDIOSTREAM
)),0,sizeof (SSLSTDIOSTREAM
));
772 sslstdio
->sslstream
= stream
;
773 /* available space in output buffer */
774 sslstdio
->octr
= SSLBUFLEN
;
775 /* current output buffer pointer */
776 sslstdio
->optr
= sslstdio
->obuf
;
777 /* allow plaintext if disable value was 2 */
778 if ((long) mail_parameters (NIL
,GET_DISABLEPLAINTEXT
,NIL
) > 1)
779 mail_parameters (NIL
,SET_DISABLEPLAINTEXT
,NIL
);
780 /* unhide PLAIN SASL authenticator */
781 mail_parameters (NIL
,UNHIDE_AUTHENTICATOR
,"PLAIN");
782 mail_parameters (NIL
,UNHIDE_AUTHENTICATOR
,"LOGIN");
788 while (i
= ERR_get_error ()) /* SSL failure */
789 syslog (LOG_ERR
,"SSL error status: %.80s",ERR_error_string (i
,NIL
));
790 ssl_close (stream
); /* punt stream */
791 exit (1); /* punt this program too */
794 /* Generate one-time key for server
795 * Accepts: SSL connection
798 * Returns: generated key, always
801 static RSA
*ssl_genkey (SSL
*con
,int export
,int keylength
)
804 static RSA
*key
= NIL
;
805 if (!key
) { /* if don't have a key already */
807 if (!(key
= RSA_generate_key (export
? keylength
: 1024,RSA_F4
,NIL
,NIL
))) {
808 syslog (LOG_ALERT
,"Unable to generate temp key, host=%.80s",
810 while (i
= ERR_get_error ())
811 syslog (LOG_ALERT
,"SSL error status: %s",ERR_error_string (i
,NIL
));
818 /* Wait for stdin input
819 * Accepts: timeout in seconds
820 * Returns: T if have input on stdin, else NIL
823 long ssl_server_input_wait (long seconds
)
829 if (!sslstdio
) return server_input_wait (seconds
);
830 /* input available in buffer */
831 if (((stream
= sslstdio
->sslstream
)->ictr
> 0) ||
832 !stream
->con
|| ((sock
= SSL_get_fd (stream
->con
)) < 0)) return LONGT
;
833 /* sock ought to be 0 always */
834 if (sock
>= FD_SETSIZE
) fatal ("unselectable socket in ssl_getdata()");
835 /* input available from SSL */
836 if (SSL_pending (stream
->con
) &&
837 ((i
= SSL_read (stream
->con
,stream
->ibuf
,SSLBUFLEN
)) > 0)) {
838 stream
->iptr
= stream
->ibuf
;/* point at TCP buffer */
839 stream
->ictr
= i
; /* set new byte count */
842 FD_ZERO (&fds
); /* initialize selection vector */
843 FD_ZERO (&efd
); /* initialize selection vector */
844 FD_SET (sock
,&fds
); /* set bit in selection vector */
845 FD_SET (sock
,&efd
); /* set bit in selection vector */
846 tmo
.tv_sec
= seconds
; tmo
.tv_usec
= 0;
847 /* see if input available from the socket */
848 return select (sock
+1,&fds
,0,&efd
,&tmo
) ? LONGT
: NIL
;
851 #include "sslstdio.c"