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 #endif /* OPENSSL_1_1_0 */
43 #define SSLBUFLEN 8192
46 * PCI auditing compliance, disable:
48 * anonymous D-H (no certificate
49 * export encryption ciphers (40 and 56 bits)
50 * low encryption cipher suites (40 and 56 bits, excluding export)
51 * null encryption (disabling implied by "ALL")
53 * UW imapd just disables low-grade and null ("ALL:!LOW"). This setting
54 * will break clients that attempt to use the newly-prohibited mechanisms.
56 * I question the value of disabling SSLv2, as opposed to disabling the SSL
57 * ports (e.g., 993 for IMAP, 995 for POP3) and using TLS exclusively.
60 #define SSLCIPHERLIST "ALL:!SSLv2:!ADH:!EXP:!LOW"
64 typedef struct ssl_stream
{
65 TCPSTREAM
*tcpstream
; /* TCP stream */
66 SSL_CTX
*context
; /* SSL context */
67 SSL
*con
; /* SSL connection */
68 int ictr
; /* input counter */
69 char *iptr
; /* input pointer */
70 char ibuf
[SSLBUFLEN
]; /* input buffer */
75 /* Function prototypes */
76 int ssl_disable_mask(int ssl_version
, int direction
);
77 const SSL_METHOD
*ssl_connect_mthd(int flag
, int *min
, int *max
);
78 static SSLSTREAM
*ssl_start(TCPSTREAM
*tstream
,char *host
,unsigned long flags
);
79 static char *ssl_start_work (SSLSTREAM
*stream
,char *host
,unsigned long flags
);
80 static int ssl_open_verify (int ok
,X509_STORE_CTX
*ctx
);
81 static char *ssl_validate_cert (X509
*cert
,char *host
);
82 static long ssl_compare_hostnames (unsigned char *s
,unsigned char *pat
);
83 static char *ssl_getline_work (SSLSTREAM
*stream
,unsigned long *size
,
85 static long ssl_abort (SSLSTREAM
*stream
);
88 #define SSL_CTX_TYPE SSL_CTX
90 #define SSL_CTX_TYPE SSL
91 #endif /* OPENSSL_1_1_0 */
93 static RSA
*ssl_genkey (SSL_CTX_TYPE
*con
,int export
,int keylength
);
96 /* Secure Sockets Layer network driver dispatch */
98 static struct ssl_driver ssldriver
= {
99 ssl_open
, /* open connection */
100 ssl_aopen
, /* open preauthenticated connection */
101 ssl_getline
, /* get a line */
102 ssl_getbuffer
, /* get a buffer */
103 ssl_soutr
, /* output pushed data */
104 ssl_sout
, /* output string */
105 ssl_close
, /* close connection */
106 ssl_host
, /* return host name */
107 ssl_remotehost
, /* return remote host name */
108 ssl_port
, /* return port number */
109 ssl_localhost
/* return local host name */
111 /* non-NIL if doing SSL primary I/O */
112 static SSLSTDIOSTREAM
*sslstdio
= NIL
;
113 static char *start_tls
= NIL
; /* non-NIL if start TLS requested */
115 /* One-time SSL initialization */
117 static int sslonceonly
= 0;
119 void ssl_onceonlyinit (void)
121 if (!sslonceonly
++) { /* only need to call it once */
123 char tmp
[MAILTMPLEN
];
125 /* if system doesn't have /dev/urandom */
126 if (stat ("/dev/urandom",&sbuf
)) {
127 strcpy(tmp
, "SSLXXXXXX");
128 while ((fd
= mkstemp(tmp
)) < 0) sleep (1);
129 unlink (tmp
); /* don't need the file */
130 fstat (fd
,&sbuf
); /* get information about the file */
131 close (fd
); /* flush descriptor */
132 /* not great but it'll have to do */
133 sprintf (tmp
+ strlen (tmp
),"%.80s%lx%.80s%lx%lx%lx%lx%lx",
134 tcp_serveraddr (),(unsigned long) tcp_serverport (),
135 tcp_clientaddr (),(unsigned long) tcp_clientport (),
136 (unsigned long) sbuf
.st_ino
,(unsigned long) time (0),
137 (unsigned long) gethostid (),(unsigned long) getpid ());
138 RAND_seed (tmp
,strlen (tmp
));
140 /* apply runtime linkage */
141 mail_parameters (NIL
,SET_SSLDRIVER
,(void *) &ssldriver
);
142 mail_parameters (NIL
,SET_SSLSTART
,(void *) ssl_start
);
144 OPENSSL_init_ssl(0, NULL
);
146 SSL_library_init (); /* add all algorithms */
147 #endif /* OPENSSL_1_1_0 */
153 * contact service name
154 * contact port number
155 * Returns: SSL stream if success else NIL
158 SSLSTREAM
*ssl_open (char *host
,char *service
,unsigned long port
)
160 TCPSTREAM
*stream
= tcp_open (host
,service
,port
);
161 return stream
? ssl_start (stream
,host
,port
) : NIL
;
165 /* SSL authenticated open
168 * returned user name buffer
169 * Returns: SSL stream if success else NIL
172 SSLSTREAM
*ssl_aopen (NETMBX
*mb
,char *service
,char *usrbuf
)
174 return NIL
; /* don't use this mechanism with SSL */
177 typedef struct ssl_disable_s
{
182 SSL_DISABLE_S ssl_disable
[] = {
183 {SSL2_VERSION
, SSL_OP_NO_SSLv2
},
184 {SSL3_VERSION
, SSL_OP_NO_SSLv3
},
185 {TLS1_VERSION
, SSL_OP_NO_TLSv1
},
186 {TLS1_1_VERSION
, SSL_OP_NO_TLSv1_1
},
187 {TLS1_2_VERSION
, SSL_OP_NO_TLSv1_2
},
188 #ifdef TLS1_3_VERSION
189 {TLS1_3_VERSION
, SSL_OP_NO_TLSv1_3
},
190 #endif /* TLS1_3_VERSION */
194 #define NUMBER_SSL_VERSIONS (sizeof(ssl_disable)/sizeof(ssl_disable[0]) - 1)
196 /* returns the mask to disable a specific version.
197 * If version not found, returns 0.
199 * Arguments: version, and direction.
200 * If direction is -1, returns mask to disable versions less than given version.
201 * If direction is +1, returns mask to disable versions bigger than given version.
203 int ssl_disable_mask(int ssl_version
, int direction
)
207 for(i
= 0; ssl_disable
[i
].version
!= 0
208 && ssl_disable
[i
].version
!= ssl_version
; i
++);
210 || i
== NUMBER_SSL_VERSIONS
- 1
211 || ssl_disable
[i
].version
== 0)
213 i
+= direction
; /* move in the direction */
214 for(; i
>= 0 && i
<= NUMBER_SSL_VERSIONS
- 1; i
+= direction
)
215 rv
|= ssl_disable
[i
].disable_code
;
220 /* ssl_connect_mthd: returns a context pointer to the connection to
223 const SSL_METHOD
*ssl_connect_mthd(int flag
, int *min
, int *max
)
227 client_request
= (flag
& NET_TRYTLS1
) ? TLS1_VERSION
228 : (flag
& NET_TRYTLS1_1
) ? TLS1_1_VERSION
229 : (flag
& NET_TRYTLS1_2
) ? TLS1_2_VERSION
230 #ifdef TLS1_3_VERSION
231 : (flag
& NET_TRYTLS1_3
) ? TLS1_3_VERSION
233 : (flag
& NET_TRYTLS1_3
) ? INT_MAX
237 *min
= *(int *) mail_parameters(NULL
, GET_ENCRYPTION_RANGE_MIN
, NULL
);
238 *max
= *(int *) mail_parameters(NULL
, GET_ENCRYPTION_RANGE_MAX
, NULL
);
241 * if no special request, negotiate the maximum the client is configured
244 if(client_request
== 0)
245 client_request
= *max
;
247 if(client_request
< *min
|| client_request
> *max
)
248 return NIL
; /* out of range? bail out */
250 #ifndef OPENSSL_1_1_0
251 if(client_request
== SSL3_VERSION
)
252 return SSLv3_client_method();
253 if(client_request
== TLS1_VERSION
)
254 return TLSv1_client_method();
255 else if(client_request
== TLS1_1_VERSION
)
256 return TLSv1_1_client_method();
257 else if(client_request
== TLS1_2_VERSION
)
258 return TLSv1_2_client_method();
259 #ifdef TLS1_3_VERSION /* this is only reachable if TLS1_3 support exists */
260 else if(client_request
== TLS1_3_VERSION
)
261 return TLS_client_method();
262 #endif /* TLS1_3_VERSION */
263 #endif /* ifndef OPENSSL_1_1_0 */
265 return SSLv23_client_method();
268 /* Start SSL/TLS negotiations
269 * Accepts: open TCP stream of session
272 * Returns: SSL stream if success else NIL
275 static SSLSTREAM
*ssl_start (TCPSTREAM
*tstream
,char *host
,unsigned long flags
)
277 char *reason
,tmp
[MAILTMPLEN
];
278 sslfailure_t sf
= (sslfailure_t
) mail_parameters (NIL
,GET_SSLFAILURE
,NIL
);
279 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
280 void *data
= (*bn
) (BLOCK_SENSITIVE
,NIL
);
281 SSLSTREAM
*stream
= (SSLSTREAM
*) memset (fs_get (sizeof (SSLSTREAM
)),0,
283 stream
->tcpstream
= tstream
; /* bind TCP stream */
285 reason
= ssl_start_work (stream
,host
,flags
);
286 (*bn
) (BLOCK_NONSENSITIVE
,data
);
287 if (reason
) { /* failed? */
288 ssl_close (stream
); /* failed to do SSL */
289 stream
= NIL
; /* no stream returned */
290 switch (*reason
) { /* analyze reason */
291 case '*': /* certificate failure */
292 ++reason
; /* skip over certificate failure indication */
293 /* pass to error callback */
294 if (sf
) (*sf
) (host
,reason
,flags
);
295 else { /* no error callback, build error message */
296 sprintf (tmp
,"Certificate failure for %.80s: %.512s",host
,reason
);
299 case '\0': /* user answered no to certificate callback */
300 if (flags
& NET_TRYSSL
) /* return dummy stream to stop tryssl */
301 stream
= (SSLSTREAM
*) memset (fs_get (sizeof (SSLSTREAM
)),0,
304 default: /* non-certificate failure */
305 if (flags
& NET_TRYSSL
); /* no error output if tryssl */
306 /* pass to error callback */
307 else if (sf
) (*sf
) (host
,reason
,flags
);
308 else { /* no error callback, build error message */
309 sprintf (tmp
,"TLS/SSL failure for %.80s: %.512s",host
,reason
);
318 /* Start SSL/TLS negotiations worker routine
319 * Accepts: SSL stream
322 * Returns: NIL if success, else error reason
325 /* evil but I had no choice */
326 static char *ssl_last_error
= NIL
;
327 static char *ssl_last_host
= NIL
;
329 static char *ssl_start_work (SSLSTREAM
*stream
,char *host
,unsigned long flags
)
335 char *s
,*t
,*err
,tmp
[MAILTMPLEN
], buf
[256];
336 sslcertificatequery_t scq
=
337 (sslcertificatequery_t
) mail_parameters (NIL
,GET_SSLCERTIFICATEQUERY
,NIL
);
338 sslclientcert_t scc
=
339 (sslclientcert_t
) mail_parameters (NIL
,GET_SSLCLIENTCERT
,NIL
);
341 (sslclientkey_t
) mail_parameters (NIL
,GET_SSLCLIENTKEY
,NIL
);
342 if (ssl_last_error
) fs_give ((void **) &ssl_last_error
);
343 ssl_last_host
= host
;
344 if (!(stream
->context
= SSL_CTX_new (ssl_connect_mthd(flags
, &min
, &max
))))
345 return "SSL context failed";
346 SSL_CTX_set_options (stream
->context
,0);
348 if(stream
->context
!= NIL
&&
349 ((min
!= 0 && SSL_CTX_set_min_proto_version(stream
->context
, min
) == 0) ||
350 (max
!= 0 && SSL_CTX_set_max_proto_version(stream
->context
, max
) == 0)))
351 return "SSL set protocol version Failed";
353 { int masklow
, maskhigh
;
354 masklow
= ssl_disable_mask(min
, -1);
355 maskhigh
= ssl_disable_mask(max
, 1);
356 SSL_CTX_set_options(stream
->context
, masklow
|maskhigh
);
358 #endif /* OPENSSL_1_1_0 */
359 /* disable certificate validation? */
360 if (flags
& NET_NOVALIDATECERT
)
361 SSL_CTX_set_verify (stream
->context
,SSL_VERIFY_NONE
,NIL
);
362 else SSL_CTX_set_verify (stream
->context
,SSL_VERIFY_PEER
,ssl_open_verify
);
363 /* set default paths to CAs... */
364 SSL_CTX_set_default_verify_paths (stream
->context
);
365 /* ...unless a non-standard path desired */
366 if ((s
= (char *) mail_parameters (NIL
,GET_SSLCAPATH
,NIL
)) != NULL
)
367 SSL_CTX_load_verify_locations (stream
->context
,NIL
,s
);
368 /* want to send client certificate? */
369 if (scc
&& (s
= (*scc
) ()) && (sl
= strlen (s
))) {
370 if ((cert
= PEM_read_bio_X509 (bio
= BIO_new_mem_buf (s
,sl
),NIL
,NIL
,NIL
)) != NULL
) {
371 SSL_CTX_use_certificate (stream
->context
,cert
);
375 if (!cert
) return "SSL client certificate failed";
376 /* want to supply private key? */
377 if ((t
= (sck
? (*sck
) () : s
)) && (tl
= strlen (t
))) {
379 if ((key
= PEM_read_bio_PrivateKey (bio
= BIO_new_mem_buf (t
,tl
),
380 NIL
,NIL
,"")) != NULL
) {
381 SSL_CTX_use_PrivateKey (stream
->context
,key
);
385 memset (t
,0,tl
); /* erase key */
387 if (s
!= t
) memset (s
,0,sl
);/* erase certificate if different from key */
390 /* create connection */
391 if (!(stream
->con
= (SSL
*) SSL_new (stream
->context
)))
392 return "SSL connection failed";
393 if (host
&& !SSL_set_tlsext_host_name(stream
->con
, host
)){
394 return "Server Name Identification (SNI) failed";
396 bio
= BIO_new_socket (stream
->tcpstream
->tcpsi
,BIO_NOCLOSE
);
397 SSL_set_bio (stream
->con
,bio
,bio
);
398 SSL_set_connect_state (stream
->con
);
399 if (SSL_in_init (stream
->con
)) SSL_total_renegotiations (stream
->con
);
400 /* now negotiate SSL */
401 if (SSL_write (stream
->con
,"",0) < 0)
402 return ssl_last_error
? ssl_last_error
: "SSL negotiation failed";
403 /* need to validate host names? */
404 if (!(flags
& NET_NOVALIDATECERT
) &&
405 (err
= ssl_validate_cert (cert
= SSL_get_peer_certificate (stream
->con
),
407 /* application callback */
408 X509_NAME_oneline (X509_get_subject_name(cert
), buf
, sizeof(buf
));
409 if (scq
) return (*scq
) (err
,host
,cert
? buf
: "???") ? NIL
: "";
410 /* error message to return via mm_log() */
411 sprintf (tmp
,"*%.128s: %.255s",err
,cert
? buf
: "???");
412 return ssl_last_error
= cpystr (tmp
);
417 /* SSL certificate verification callback
418 * Accepts: error flag
420 * Returns: error flag
423 static int ssl_open_verify (int ok
,X509_STORE_CTX
*ctx
)
425 char *err
,cert
[256],tmp
[MAILTMPLEN
];
426 sslcertificatequery_t scq
=
427 (sslcertificatequery_t
) mail_parameters (NIL
,GET_SSLCERTIFICATEQUERY
,NIL
);
428 if (!ok
) { /* in case failure */
429 err
= (char *) X509_verify_cert_error_string
430 (X509_STORE_CTX_get_error (ctx
));
431 X509_NAME_oneline (X509_get_subject_name
432 (X509_STORE_CTX_get_current_cert (ctx
)),cert
,255);
433 if (!scq
) { /* mm_log() error message if no callback */
434 sprintf (tmp
,"*%.128s: %.255s",err
,cert
);
435 ssl_last_error
= cpystr (tmp
);
437 /* ignore error if application says to */
438 else if ((*scq
) (err
,ssl_last_host
,cert
)) ok
= T
;
439 /* application wants punt */
440 else ssl_last_error
= cpystr ("");
446 /* SSL validate certificate
447 * Accepts: certificate
448 * host to validate against
449 * Returns: NIL if validated, else string of error message
452 static char *ssl_validate_cert (X509
*cert
,char *host
)
455 char *s
=NULL
,*t
,*ret
;
461 /* make sure have a certificate */
462 if (!cert
) ret
= "No certificate from server";
463 /* and that it has a name */
464 else if (!(cname
= X509_get_subject_name(cert
))) ret
= "No name in certificate";
467 if((e
= X509_NAME_get_entry(cname
, X509_NAME_entry_count(cname
)-1)) != NULL
){
468 X509_NAME_get_text_by_OBJ(cname
, X509_NAME_ENTRY_get_object(e
), buf
, sizeof(buf
));
474 /* host name matches pattern? */
475 ret
= ssl_compare_hostnames (host
,s
) ? NIL
:
476 "Server name does not match certificate";
477 /* if mismatch, see if in extensions */
478 if (ret
&& (ext
= X509_get_ext_d2i (cert
,NID_subject_alt_name
,NIL
,NIL
)) &&
479 (n
= sk_GENERAL_NAME_num (ext
)))
480 /* older versions of OpenSSL use "ia5" instead of dNSName */
481 for (i
= 0; ret
&& (i
< n
); i
++)
482 if ((name
= sk_GENERAL_NAME_value (ext
,i
)) &&
483 (name
->type
= GEN_DNS
) && (s
= name
->d
.ia5
->data
) &&
484 ssl_compare_hostnames (host
,s
)) ret
= NIL
;
486 else ret
= "Unable to locate common name in certificate";
490 /* Case-independent wildcard pattern match
491 * Accepts: base string
493 * Returns: T if pattern matches base, else NIL
496 static long ssl_compare_hostnames (unsigned char *s
,unsigned char *pat
)
500 case '*': /* wildcard */
501 if (pat
[1]) { /* there must be a pattern suffix */
502 /* there is, scan base against it */
503 do if (ssl_compare_hostnames (s
,pat
+1)) ret
= LONGT
;
504 while (!ret
&& (*s
!= '.') && *s
++);
507 case '\0': /* end of pattern */
508 if (!*s
) ret
= LONGT
; /* success if base is also at end */
510 default: /* non-wildcard, recurse if match */
511 if (!compare_uchar (*pat
,*s
)) ret
= ssl_compare_hostnames (s
+1,pat
+1);
518 * Accepts: SSL stream
519 * Returns: text line string or NIL if failure
522 char *ssl_getline (SSLSTREAM
*stream
)
524 unsigned long n
,contd
;
525 char *ret
= ssl_getline_work (stream
,&n
,&contd
);
526 if (ret
&& contd
) { /* got a line needing continuation? */
527 STRINGLIST
*stl
= mail_newstringlist ();
528 STRINGLIST
*stc
= stl
;
529 do { /* collect additional lines */
530 stc
->text
.data
= (unsigned char *) ret
;
532 stc
= stc
->next
= mail_newstringlist ();
533 ret
= ssl_getline_work (stream
,&n
,&contd
);
534 } while (ret
&& contd
);
535 if (ret
) { /* stash final part of line on list */
536 stc
->text
.data
= (unsigned char *) ret
;
538 /* determine how large a buffer we need */
539 for (n
= 0, stc
= stl
; stc
; stc
= stc
->next
) n
+= stc
->text
.size
;
540 ret
= fs_get (n
+ 1); /* copy parts into buffer */
541 for (n
= 0, stc
= stl
; stc
; n
+= stc
->text
.size
, stc
= stc
->next
)
542 memcpy (ret
+ n
,stc
->text
.data
,stc
->text
.size
);
545 mail_free_stringlist (&stl
);/* either way, done with list */
550 /* SSL receive line or partial line
551 * Accepts: SSL stream
552 * pointer to return size
553 * pointer to return continuation flag
554 * Returns: text line string, size and continuation flag, or NIL if failure
557 static char *ssl_getline_work (SSLSTREAM
*stream
,unsigned long *size
,
562 *contd
= NIL
; /* assume no continuation */
563 /* make sure have data */
564 if (!ssl_getdata (stream
)) return NIL
;
565 for (s
= stream
->iptr
, n
= 0, c
= '\0'; stream
->ictr
--; n
++, c
= d
) {
566 d
= *stream
->iptr
++; /* slurp another character */
567 if ((c
== '\015') && (d
== '\012')) {
568 ret
= (char *) fs_get (n
--);
569 memcpy (ret
,s
,*size
= n
); /* copy into a free storage string */
570 ret
[n
] = '\0'; /* tie off string with null */
574 /* copy partial string from buffer */
575 memcpy ((ret
= (char *) fs_get (n
)),s
,*size
= n
);
576 /* get more data from the net */
577 if (!ssl_getdata (stream
)) fs_give ((void **) &ret
);
578 /* special case of newline broken by buffer */
579 else if ((c
== '\015') && (*stream
->iptr
== '\012')) {
580 stream
->iptr
++; /* eat the line feed */
582 ret
[*size
= --n
] = '\0'; /* tie off string with null */
584 else *contd
= LONGT
; /* continuation needed */
588 /* SSL receive buffer
589 * Accepts: SSL stream
591 * buffer to read into
592 * Returns: T if success, NIL otherwise
595 long ssl_getbuffer (SSLSTREAM
*stream
,unsigned long size
,char *buffer
)
598 while (size
> 0) { /* until request satisfied */
599 if (!ssl_getdata (stream
)) return NIL
;
600 n
= min (size
,stream
->ictr
);/* number of bytes to transfer */
602 memcpy (buffer
,stream
->iptr
,n
);
603 buffer
+= n
; /* update pointer */
605 size
-= n
; /* update # of bytes to do */
608 buffer
[0] = '\0'; /* tie off string */
613 * Accepts: TCP/IP stream
614 * Returns: T if success, NIL otherwise
617 long ssl_getdata (SSLSTREAM
*stream
)
622 tcptimeout_t tmoh
= (tcptimeout_t
) mail_parameters (NIL
,GET_TIMEOUT
,NIL
);
623 long ttmo_read
= (long) mail_parameters (NIL
,GET_READTIMEOUT
,NIL
);
625 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
626 if (!stream
->con
|| ((sock
= SSL_get_fd (stream
->con
)) < 0)) return NIL
;
627 /* tcp_unix should have prevented this */
628 if (sock
>= FD_SETSIZE
) fatal ("unselectable socket in ssl_getdata()");
629 (*bn
) (BLOCK_TCPREAD
,NIL
);
630 while (stream
->ictr
< 1) { /* if nothing in the buffer */
631 time_t tl
= time (0); /* start of request */
633 int ti
= ttmo_read
? now
+ ttmo_read
: 0;
634 if (SSL_pending (stream
->con
)) i
= 1;
636 if (tcpdebug
) mm_log ("Reading SSL data",TCPDEBUG
);
638 FD_ZERO (&fds
); /* initialize selection vector */
639 FD_ZERO (&efds
); /* handle errors too */
640 FD_SET (sock
,&fds
); /* set bit in selection vector */
641 FD_SET (sock
,&efds
); /* set bit in error selection vector */
642 errno
= NIL
; /* block and read */
643 do { /* block under timeout */
644 tmo
.tv_sec
= ti
? ti
- now
: 0;
645 i
= select (sock
+1,&fds
,0,&efds
,ti
? &tmo
: 0);
646 now
= time (0); /* fake timeout if interrupt & time expired */
647 if ((i
< 0) && (errno
== EINTR
) && ti
&& (ti
<= now
)) i
= 0;
648 } while ((i
< 0) && (errno
== EINTR
));
650 if (i
) { /* non-timeout result from select? */
651 errno
= 0; /* just in case */
652 if (i
> 0) /* read what we can */
653 while (((i
= SSL_read (stream
->con
,stream
->ibuf
,SSLBUFLEN
)) < 0) &&
655 (SSL_get_error (stream
->con
,i
) == SSL_ERROR_WANT_READ
)));
656 if (i
<= 0) { /* error seen? */
658 char *s
,tmp
[MAILTMPLEN
];
659 if (i
) sprintf (s
= tmp
,"SSL data read I/O error %d SSL error %d",
660 errno
,SSL_get_error (stream
->con
,i
));
661 else s
= "SSL data read end of file";
664 return ssl_abort (stream
);
666 stream
->iptr
= stream
->ibuf
;/* point at TCP buffer */
667 stream
->ictr
= i
; /* set new byte count */
668 if (tcpdebug
) mm_log ("Successfully read SSL data",TCPDEBUG
);
670 /* timeout, punt unless told not to */
671 else if (!tmoh
|| !(*tmoh
) (now
- t
,now
- tl
, stream
->tcpstream
->host
)) {
672 if (tcpdebug
) mm_log ("SSL data read timeout",TCPDEBUG
);
673 return ssl_abort (stream
);
676 (*bn
) (BLOCK_NONE
,NIL
);
680 /* SSL send string as record
681 * Accepts: SSL stream
683 * Returns: T if success else NIL
686 long ssl_soutr (SSLSTREAM
*stream
,char *string
)
688 return ssl_sout (stream
,string
,(unsigned long) strlen (string
));
693 * Accepts: SSL stream
696 * Returns: T if success else NIL
699 long ssl_sout (SSLSTREAM
*stream
,char *string
,unsigned long size
)
702 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
703 if (!stream
->con
) return NIL
;
704 (*bn
) (BLOCK_TCPWRITE
,NIL
);
705 if (tcpdebug
) mm_log ("Writing to SSL",TCPDEBUG
);
706 /* until request satisfied */
707 for (i
= 0; size
> 0; string
+= i
,size
-= i
)
708 /* write as much as we can */
709 if ((i
= SSL_write (stream
->con
,string
,(int) min (SSLBUFLEN
,size
))) < 0) {
711 char tmp
[MAILTMPLEN
];
712 sprintf (tmp
,"SSL data write I/O error %d SSL error %d",
713 errno
,SSL_get_error (stream
->con
,i
));
714 mm_log (tmp
,TCPDEBUG
);
716 return ssl_abort (stream
);/* write failed */
718 if (tcpdebug
) mm_log ("successfully wrote to TCP",TCPDEBUG
);
719 (*bn
) (BLOCK_NONE
,NIL
);
720 return LONGT
; /* all done */
724 * Accepts: SSL stream
727 void ssl_close (SSLSTREAM
*stream
)
729 ssl_abort (stream
); /* nuke the stream */
730 fs_give ((void **) &stream
); /* flush the stream */
735 * Accepts: SSL stream
736 * Returns: NIL always
739 static long ssl_abort (SSLSTREAM
*stream
)
741 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
742 if (stream
->con
) { /* close SSL connection */
743 SSL_shutdown (stream
->con
);
744 SSL_free (stream
->con
);
747 if (stream
->context
) { /* clean up context */
748 SSL_CTX_free (stream
->context
);
749 stream
->context
= NIL
;
751 if (stream
->tcpstream
) { /* close TCP stream */
752 tcp_close (stream
->tcpstream
);
753 stream
->tcpstream
= NIL
;
755 (*bn
) (BLOCK_NONE
,NIL
);
760 * Accepts: SSL stream
761 * Returns: host name for this stream
764 char *ssl_host (SSLSTREAM
*stream
)
766 return stream
? tcp_host (stream
->tcpstream
) : "UNKNOWN";
770 /* SSL get remote host name
771 * Accepts: SSL stream
772 * Returns: host name for this stream
775 char *ssl_remotehost (SSLSTREAM
*stream
)
777 return tcp_remotehost (stream
->tcpstream
);
781 /* SSL return port for this stream
782 * Accepts: SSL stream
783 * Returns: port number for this stream
786 unsigned long ssl_port (SSLSTREAM
*stream
)
788 return tcp_port (stream
->tcpstream
);
792 /* SSL get local host name
793 * Accepts: SSL stream
794 * Returns: local host name
797 char *ssl_localhost (SSLSTREAM
*stream
)
799 return tcp_localhost (stream
->tcpstream
);
803 * Accepts: /etc/services service name
804 * Returns: cpystr'd error string if TLS failed, else NIL for success
807 char *ssl_start_tls (char *server
)
809 char tmp
[MAILTMPLEN
];
811 if (sslstdio
) return cpystr ("Already in an SSL session");
812 if (start_tls
) return cpystr ("TLS already started");
813 if (server
) { /* build specific certificate/key file name */
814 sprintf (tmp
,"%s/%s-%s.pem",SSL_CERT_DIRECTORY
,server
,tcp_serveraddr ());
815 if (stat (tmp
,&sbuf
)) { /* use non-specific name if no specific file */
816 sprintf (tmp
,"%s/%s.pem",SSL_CERT_DIRECTORY
,server
);
817 if (stat (tmp
,&sbuf
)) return cpystr ("Server certificate not installed");
819 start_tls
= server
; /* switch to STARTTLS mode */
824 /* Init server for SSL
825 * Accepts: server name
828 void ssl_server_init (char *server
)
830 char cert
[MAILTMPLEN
],key
[MAILTMPLEN
];
833 SSLSTREAM
*stream
= (SSLSTREAM
*) memset (fs_get (sizeof (SSLSTREAM
)),0,
835 ssl_onceonlyinit (); /* make sure algorithms added */
837 OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS
, NULL
);
838 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|OPENSSL_INIT_LOAD_CRYPTO_STRINGS
, NULL
);
840 ERR_load_crypto_strings ();
841 SSL_load_error_strings ();
842 #endif /* OPENSSL_1_1_0 */
843 /* build specific certificate/key file names */
844 sprintf (cert
,"%s/%s-%s.pem",SSL_CERT_DIRECTORY
,server
,tcp_serveraddr ());
845 sprintf (key
,"%s/%s-%s.pem",SSL_KEY_DIRECTORY
,server
,tcp_serveraddr ());
846 /* use non-specific name if no specific cert */
847 if (stat (cert
,&sbuf
)) sprintf (cert
,"%s/%s.pem",SSL_CERT_DIRECTORY
,server
);
848 if (stat (key
,&sbuf
)) { /* use non-specific name if no specific key */
849 sprintf (key
,"%s/%s.pem",SSL_KEY_DIRECTORY
,server
);
850 /* use cert file as fallback for key */
851 if (stat (key
,&sbuf
)) strcpy (key
,cert
);
855 if (!(stream
->context
= SSL_CTX_new (start_tls
?
856 TLS_server_method () :
857 SSLv23_server_method ())))
859 if (!(stream
->context
= SSL_CTX_new (start_tls
?
860 TLSv1_server_method () :
861 SSLv23_server_method ())))
862 #endif /* OPENSSL_1_1_0 */
863 syslog (LOG_ALERT
,"Unable to create SSL context, host=%.80s",
865 else { /* set context options */
866 SSL_CTX_set_options (stream
->context
,SSL_OP_ALL
);
867 /* set cipher list */
868 if (!SSL_CTX_set_cipher_list (stream
->context
,SSLCIPHERLIST
))
869 syslog (LOG_ALERT
,"Unable to set cipher list %.80s, host=%.80s",
870 SSLCIPHERLIST
,tcp_clienthost ());
871 /* load certificate */
872 else if (!SSL_CTX_use_certificate_chain_file (stream
->context
,cert
))
873 syslog (LOG_ALERT
,"Unable to load certificate from %.80s, host=%.80s",
874 cert
,tcp_clienthost ());
876 else if (!(SSL_CTX_use_RSAPrivateKey_file (stream
->context
,key
,
878 syslog (LOG_ALERT
,"Unable to load private key from %.80s, host=%.80s",
879 key
,tcp_clienthost ());
881 else { /* generate key if needed */
884 ssl_genkey(stream
->context
, 0, 0);
886 if (SSL_CTX_need_tmp_RSA (stream
->context
))
887 SSL_CTX_set_tmp_rsa_callback (stream
->context
,ssl_genkey
);
888 #endif /* OPENSSL_1_1_0 */
889 /* create new SSL connection */
890 if (!(stream
->con
= SSL_new (stream
->context
)))
891 syslog (LOG_ALERT
,"Unable to create SSL connection, host=%.80s",
893 else { /* set file descriptor */
894 SSL_set_fd (stream
->con
,0);
895 /* all OK if accepted */
896 if (SSL_accept (stream
->con
) < 0)
897 syslog (LOG_INFO
,"Unable to accept SSL connection, host=%.80s",
899 else { /* server set up */
900 sslstdio
= (SSLSTDIOSTREAM
*)
901 memset (fs_get (sizeof(SSLSTDIOSTREAM
)),0,sizeof (SSLSTDIOSTREAM
));
902 sslstdio
->sslstream
= stream
;
903 /* available space in output buffer */
904 sslstdio
->octr
= SSLBUFLEN
;
905 /* current output buffer pointer */
906 sslstdio
->optr
= sslstdio
->obuf
;
907 /* allow plaintext if disable value was 2 */
908 if ((long) mail_parameters (NIL
,GET_DISABLEPLAINTEXT
,NIL
) > 1)
909 mail_parameters (NIL
,SET_DISABLEPLAINTEXT
,NIL
);
910 /* unhide PLAIN SASL authenticator */
911 mail_parameters (NIL
,UNHIDE_AUTHENTICATOR
,"PLAIN");
912 mail_parameters (NIL
,UNHIDE_AUTHENTICATOR
,"LOGIN");
918 while ((i
= ERR_get_error ()) != 0L) /* SSL failure */
919 syslog (LOG_ERR
,"SSL error status: %.80s",ERR_error_string (i
,NIL
));
920 ssl_close (stream
); /* punt stream */
921 exit (1); /* punt this program too */
924 /* Generate one-time key for server
925 * Accepts: SSL connection
928 * Returns: generated key, always
931 static RSA
*ssl_genkey (SSL_CTX_TYPE
*con
,int export
,int keylength
)
934 static RSA
*key
= NIL
;
935 if (!key
) { /* if don't have a key already */
938 BIGNUM
*e
= BN_new();
939 if (!RSA_generate_key_ex (key
, export
? keylength
: 1024, e
,NIL
)) {
941 if (!(key
= RSA_generate_key (export
? keylength
: 1024,RSA_F4
,NIL
,NIL
))) {
942 #endif /* OPENSSL_1_1_0 */
943 syslog (LOG_ALERT
,"Unable to generate temp key, host=%.80s",
945 while ((i
= ERR_get_error ()) != 0L)
946 syslog (LOG_ALERT
,"SSL error status: %s",ERR_error_string (i
,NIL
));
952 #endif /* OPENSSL_1_1_0 */
957 /* Wait for stdin input
958 * Accepts: timeout in seconds
959 * Returns: T if have input on stdin, else NIL
962 long ssl_server_input_wait (long seconds
)
968 if (!sslstdio
) return server_input_wait (seconds
);
969 /* input available in buffer */
970 if (((stream
= sslstdio
->sslstream
)->ictr
> 0) ||
971 !stream
->con
|| ((sock
= SSL_get_fd (stream
->con
)) < 0)) return LONGT
;
972 /* sock ought to be 0 always */
973 if (sock
>= FD_SETSIZE
) fatal ("unselectable socket in ssl_getdata()");
974 /* input available from SSL */
975 if (SSL_pending (stream
->con
) &&
976 ((i
= SSL_read (stream
->con
,stream
->ibuf
,SSLBUFLEN
)) > 0)) {
977 stream
->iptr
= stream
->ibuf
;/* point at TCP buffer */
978 stream
->ictr
= i
; /* set new byte count */
981 FD_ZERO (&fds
); /* initialize selection vector */
982 FD_ZERO (&efd
); /* initialize selection vector */
983 FD_SET (sock
,&fds
); /* set bit in selection vector */
984 FD_SET (sock
,&efd
); /* set bit in selection vector */
985 tmo
.tv_sec
= seconds
; tmo
.tv_usec
= 0;
986 /* see if input available from the socket */
987 return select (sock
+1,&fds
,0,&efd
,&tmo
) ? LONGT
: NIL
;
990 #include "sslstdio.c"