1 /* ========================================================================
2 * Copyright 2019 Eduardo Chappa
3 * Copyright 2008-2009 Mark Crispin
4 * ========================================================================
8 * Program: SSL authentication/encryption module
10 * Author: Mark Crispin
12 * Date: 22 September 1998
13 * Last Edited: 8 November 2009
15 * Previous versions of this file were
17 * Copyright 1988-2008 University of Washington
19 * Licensed under the Apache License, Version 2.0 (the "License");
20 * you may not use this file except in compliance with the License.
21 * You may obtain a copy of the License at
23 * http://www.apache.org/licenses/LICENSE-2.0
27 #define crypt ssl_private_crypt
28 #define STRING OPENSSL_STRING
40 #endif /* OPENSSL_1_1_0 */
44 #define SSLBUFLEN 8192
47 * PCI auditing compliance, disable:
49 * anonymous D-H (no certificate
50 * export encryption ciphers (40 and 56 bits)
51 * low encryption cipher suites (40 and 56 bits, excluding export)
52 * null encryption (disabling implied by "ALL")
54 * UW imapd just disables low-grade and null ("ALL:!LOW"). This setting
55 * will break clients that attempt to use the newly-prohibited mechanisms.
57 * I question the value of disabling SSLv2, as opposed to disabling the SSL
58 * ports (e.g., 993 for IMAP, 995 for POP3) and using TLS exclusively.
61 #define SSLCIPHERLIST "ALL:!SSLv2:!ADH:!EXP:!LOW"
65 typedef struct ssl_stream
{
66 TCPSTREAM
*tcpstream
; /* TCP stream */
67 SSL_CTX
*context
; /* SSL context */
68 SSL
*con
; /* SSL connection */
69 int ictr
; /* input counter */
70 char *iptr
; /* input pointer */
71 char ibuf
[SSLBUFLEN
]; /* input buffer */
76 /* Function prototypes */
77 int ssl_disable_mask(int ssl_version
, int direction
);
78 const SSL_METHOD
*ssl_connect_mthd(int flag
, int *min
, int *max
);
79 static SSLSTREAM
*ssl_start(TCPSTREAM
*tstream
,char *host
,unsigned long flags
);
80 static char *ssl_start_work (SSLSTREAM
*stream
,char *host
,unsigned long flags
);
81 static int ssl_open_verify (int ok
,X509_STORE_CTX
*ctx
);
82 static char *ssl_validate_cert (X509
*cert
,char *host
);
83 static long ssl_compare_hostnames (unsigned char *s
,unsigned char *pat
);
84 static char *ssl_getline_work (SSLSTREAM
*stream
,unsigned long *size
,
86 static long ssl_abort (SSLSTREAM
*stream
);
89 #define SSL_CTX_TYPE SSL_CTX
91 #define SSL_CTX_TYPE SSL
92 #endif /* OPENSSL_1_1_0 */
94 static RSA
*ssl_genkey (SSL_CTX_TYPE
*con
,int export
,int keylength
);
96 typedef struct ssl_versions_s
{
102 pith_ssl_encryption_version(char *s
)
104 SSL_VERSIONS_S ssl_versions
[] = {
106 { "ssl3", SSL3_VERSION
},
107 { "tls1", TLS1_VERSION
},
108 { "tls1_1", TLS1_1_VERSION
},
109 { "tls1_2", TLS1_2_VERSION
},
110 #ifdef TLS1_3_VERSION
111 { "tls1_3", TLS1_3_VERSION
},
112 #endif /* TLS1_3_VERSION */
113 { "no_max", 0 }, /* set this last in the list */
118 if (s
== NULL
|| *s
== '\0')
121 for (i
= 0; ssl_versions
[i
].name
!= NULL
; i
++)
122 if (strcmp(ssl_versions
[i
].name
, s
) == 0)
125 if (strcmp(s
, "no_max") == 0) i
--;
127 return ssl_versions
[i
].name
!= NULL
? ssl_versions
[i
].version
: -1;
132 /* Secure Sockets Layer network driver dispatch */
134 static struct ssl_driver ssldriver
= {
135 ssl_open
, /* open connection */
136 ssl_aopen
, /* open preauthenticated connection */
137 ssl_getline
, /* get a line */
138 ssl_getbuffer
, /* get a buffer */
139 ssl_soutr
, /* output pushed data */
140 ssl_sout
, /* output string */
141 ssl_close
, /* close connection */
142 ssl_host
, /* return host name */
143 ssl_remotehost
, /* return remote host name */
144 ssl_port
, /* return port number */
145 ssl_localhost
, /* return local host name */
146 ssl_getsize
/* return needed number of bytes */
148 /* non-NIL if doing SSL primary I/O */
149 static SSLSTDIOSTREAM
*sslstdio
= NIL
;
150 static char *start_tls
= NIL
; /* non-NIL if start TLS requested */
152 /* One-time SSL initialization */
154 static int sslonceonly
= 0;
156 void ssl_onceonlyinit (void)
158 if (!sslonceonly
++) { /* only need to call it once */
160 char tmp
[MAILTMPLEN
];
162 /* if system doesn't have /dev/urandom */
163 if (stat ("/dev/urandom",&sbuf
)) {
164 strcpy(tmp
, "SSLXXXXXX");
165 while ((fd
= mkstemp(tmp
)) < 0) sleep (1);
166 fstat (fd
,&sbuf
); /* get information about the file */
167 close (fd
); /* flush descriptor */
168 unlink (tmp
); /* don't need the file */
169 /* not great but it'll have to do */
170 sprintf (tmp
+ strlen (tmp
),"%.80s%lx%.80s%lx%lx%lx%lx%lx",
171 tcp_serveraddr (),(unsigned long) tcp_serverport (),
172 tcp_clientaddr (),(unsigned long) tcp_clientport (),
173 (unsigned long) sbuf
.st_ino
,(unsigned long) time (0),
174 (unsigned long) gethostid (),(unsigned long) getpid ());
175 RAND_seed (tmp
,strlen (tmp
));
177 /* apply runtime linkage */
178 mail_parameters (NIL
,SET_SSLDRIVER
,(void *) &ssldriver
);
179 mail_parameters (NIL
,SET_SSLSTART
,(void *) ssl_start
);
181 OPENSSL_init_ssl(0, NULL
);
183 SSL_library_init (); /* add all algorithms */
184 #endif /* OPENSSL_1_1_0 */
190 * contact service name
191 * contact port number
192 * Returns: SSL stream if success else NIL
195 SSLSTREAM
*ssl_open (char *host
,char *service
,unsigned long port
)
197 TCPSTREAM
*stream
= tcp_open (host
,service
,port
);
198 return stream
? ssl_start (stream
,host
,port
) : NIL
;
202 /* SSL authenticated open
205 * returned user name buffer
206 * Returns: SSL stream if success else NIL
209 SSLSTREAM
*ssl_aopen (NETMBX
*mb
,char *service
,char *usrbuf
)
211 return NIL
; /* don't use this mechanism with SSL */
214 typedef struct ssl_disable_s
{
219 SSL_DISABLE_S ssl_disable
[] = {
220 {SSL2_VERSION
, SSL_OP_NO_SSLv2
},
221 {SSL3_VERSION
, SSL_OP_NO_SSLv3
},
222 {TLS1_VERSION
, SSL_OP_NO_TLSv1
},
223 {TLS1_1_VERSION
, SSL_OP_NO_TLSv1_1
},
224 {TLS1_2_VERSION
, SSL_OP_NO_TLSv1_2
},
225 #ifdef TLS1_3_VERSION
226 {TLS1_3_VERSION
, SSL_OP_NO_TLSv1_3
},
227 #endif /* TLS1_3_VERSION */
231 #define NUMBER_SSL_VERSIONS (sizeof(ssl_disable)/sizeof(ssl_disable[0]) - 1)
233 /* returns the mask to disable a specific version.
234 * If version not found, returns 0.
236 * Arguments: version, and direction.
237 * If direction is -1, returns mask to disable versions less than given version.
238 * If direction is +1, returns mask to disable versions bigger than given version.
240 int ssl_disable_mask(int ssl_version
, int direction
)
244 for(i
= 0; ssl_disable
[i
].version
!= 0
245 && ssl_disable
[i
].version
!= ssl_version
; i
++);
247 || i
== NUMBER_SSL_VERSIONS
- 1
248 || ssl_disable
[i
].version
== 0)
250 i
+= direction
; /* move in the direction */
251 for(; i
>= 0 && i
<= NUMBER_SSL_VERSIONS
- 1; i
+= direction
)
252 rv
|= ssl_disable
[i
].disable_code
;
257 /* ssl_connect_mthd: returns a context pointer to the connection to
260 const SSL_METHOD
*ssl_connect_mthd(int flag
, int *min
, int *max
)
263 client_request
= (flag
& NET_TRYTLS1
) ? TLS1_VERSION
264 : (flag
& NET_TRYTLS1_1
) ? TLS1_1_VERSION
265 : (flag
& NET_TRYTLS1_2
) ? TLS1_2_VERSION
266 #ifdef TLS1_3_VERSION
267 : (flag
& NET_TRYTLS1_3
) ? TLS1_3_VERSION
269 : (flag
& NET_TRYTLS1_3
) ? -2
273 *min
= *(int *) mail_parameters(NULL
, GET_ENCRYPTION_RANGE_MIN
, NULL
);
274 *max
= *(int *) mail_parameters(NULL
, GET_ENCRYPTION_RANGE_MAX
, NULL
);
277 * if no special request, negotiate the maximum the client is configured
280 if(client_request
== 0)
281 client_request
= *max
;
283 if(client_request
< *min
|| client_request
> *max
)
284 return NIL
; /* out of range? bail out */
286 /* Some Linux distributors seem to believe that it is ok to disable some of
287 * these methods for their users, so we have to test that every requested
288 * method has actually been compiled in into their openssl/libressl library.
291 #ifndef OPENSSL_1_1_0
292 if(client_request
== SSL3_VERSION
)
293 #ifndef OPENSSL_NO_SSL3_METHOD
294 return SSLv3_client_method();
297 #endif /* OPENSSL_NO_SSL3_METHOD */
298 else if(client_request
== TLS1_VERSION
)
299 #ifndef OPENSSL_NO_TLS1_METHOD
300 return TLSv1_client_method();
303 #endif /* OPENSSL_NO_TLS1_METHOD */
304 else if(client_request
== TLS1_1_VERSION
)
305 #ifndef OPENSSL_NO_TLS1_1_METHOD
306 return TLSv1_1_client_method();
309 #endif /* OPENSSL_NO_TLS1_1_METHOD */
310 else if(client_request
== TLS1_2_VERSION
)
311 #ifndef OPENSSL_NO_TLS1_2_METHOD
312 return TLSv1_2_client_method();
315 #endif /* OPENSSL_NO_TLS1_2_METHOD */
316 #ifdef TLS1_3_VERSION /* this is only reachable if TLS1_3 support exists */
317 else if(client_request
== TLS1_3_VERSION
)
318 #ifndef OPENSSL_NO_TLS1_3_METHOD
319 return TLS_client_method();
322 #endif /* #ifndef OPENSSL_NO_TLS1_2_METHOD */
323 #endif /* TLS1_3_VERSION */
324 #endif /* ifndef OPENSSL_1_1_0 */
326 return SSLv23_client_method();
329 /* Start SSL/TLS negotiations
330 * Accepts: open TCP stream of session
333 * Returns: SSL stream if success else NIL
336 static SSLSTREAM
*ssl_start (TCPSTREAM
*tstream
,char *host
,unsigned long flags
)
338 char *reason
,tmp
[MAILTMPLEN
];
339 sslfailure_t sf
= (sslfailure_t
) mail_parameters (NIL
,GET_SSLFAILURE
,NIL
);
340 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
341 void *data
= (*bn
) (BLOCK_SENSITIVE
,NIL
);
342 SSLSTREAM
*stream
= (SSLSTREAM
*) memset (fs_get (sizeof (SSLSTREAM
)),0,
344 stream
->tcpstream
= tstream
; /* bind TCP stream */
346 reason
= ssl_start_work (stream
,host
,flags
);
347 (*bn
) (BLOCK_NONSENSITIVE
,data
);
348 if (reason
) { /* failed? */
349 ssl_close (stream
); /* failed to do SSL */
350 stream
= NIL
; /* no stream returned */
351 switch (*reason
) { /* analyze reason */
352 case '*': /* certificate failure */
353 ++reason
; /* skip over certificate failure indication */
354 /* pass to error callback */
355 if (sf
) (*sf
) (host
,reason
,flags
);
356 else { /* no error callback, build error message */
357 sprintf (tmp
,"Certificate failure for %.80s: %.512s",host
,reason
);
360 case '\0': /* user answered no to certificate callback */
361 if (flags
& NET_TRYSSL
) /* return dummy stream to stop tryssl */
362 stream
= (SSLSTREAM
*) memset (fs_get (sizeof (SSLSTREAM
)),0,
365 default: /* non-certificate failure */
366 if (flags
& NET_TRYSSL
); /* no error output if tryssl */
367 /* pass to error callback */
368 else if (sf
) (*sf
) (host
,reason
,flags
);
369 else { /* no error callback, build error message */
370 sprintf (tmp
,"TLS/SSL failure for %.80s: %.512s",host
,reason
);
379 /* Start SSL/TLS negotiations worker routine
380 * Accepts: SSL stream
383 * Returns: NIL if success, else error reason
386 /* evil but I had no choice */
387 static char *ssl_last_error
= NIL
;
388 static char *ssl_last_host
= NIL
;
390 static char *ssl_start_work (SSLSTREAM
*stream
,char *host
,unsigned long flags
)
396 int masklow
, maskhigh
;
397 char *s
,*t
,*err
,tmp
[MAILTMPLEN
], buf
[256];
398 sslcertificatequery_t scq
=
399 (sslcertificatequery_t
) mail_parameters (NIL
,GET_SSLCERTIFICATEQUERY
,NIL
);
400 sslclientcert_t scc
=
401 (sslclientcert_t
) mail_parameters (NIL
,GET_SSLCLIENTCERT
,NIL
);
403 (sslclientkey_t
) mail_parameters (NIL
,GET_SSLCLIENTKEY
,NIL
);
404 if (ssl_last_error
) fs_give ((void **) &ssl_last_error
);
405 ssl_last_host
= host
;
406 if (!(stream
->context
= SSL_CTX_new (ssl_connect_mthd(flags
, &min
, &max
))))
407 return "SSL context failed";
408 SSL_CTX_set_options (stream
->context
,0);
409 masklow
= ssl_disable_mask(min
, -1);
410 maskhigh
= ssl_disable_mask(max
, 1);
411 SSL_CTX_set_options(stream
->context
, masklow
|maskhigh
);
412 /* disable certificate validation? */
413 if (flags
& NET_NOVALIDATECERT
)
414 SSL_CTX_set_verify (stream
->context
,SSL_VERIFY_NONE
,NIL
);
415 else SSL_CTX_set_verify (stream
->context
,SSL_VERIFY_PEER
,ssl_open_verify
);
416 /* set default paths to CAs... */
417 SSL_CTX_set_default_verify_paths (stream
->context
);
418 /* ...unless a non-standard path desired */
419 if ((s
= (char *) mail_parameters (NIL
,GET_SSLCAPATH
,NIL
)) != NULL
)
420 SSL_CTX_load_verify_locations (stream
->context
,NIL
,s
);
421 /* want to send client certificate? */
422 if (scc
&& (s
= (*scc
) ()) && (sl
= strlen (s
))) {
423 if ((cert
= PEM_read_bio_X509 (bio
= BIO_new_mem_buf (s
,sl
),NIL
,NIL
,NIL
)) != NULL
) {
424 SSL_CTX_use_certificate (stream
->context
,cert
);
428 if (!cert
) return "SSL client certificate failed";
429 /* want to supply private key? */
430 if ((t
= (sck
? (*sck
) () : s
)) && (tl
= strlen (t
))) {
432 if ((key
= PEM_read_bio_PrivateKey (bio
= BIO_new_mem_buf (t
,tl
),
433 NIL
,NIL
,"")) != NULL
) {
434 SSL_CTX_use_PrivateKey (stream
->context
,key
);
438 memset (t
,0,tl
); /* erase key */
440 if (s
!= t
) memset (s
,0,sl
);/* erase certificate if different from key */
443 /* create connection */
444 if (!(stream
->con
= (SSL
*) SSL_new (stream
->context
)))
445 return "SSL connection failed";
446 if (host
&& !SSL_set_tlsext_host_name(stream
->con
, host
)){
447 return "Server Name Identification (SNI) failed";
449 bio
= BIO_new_socket (stream
->tcpstream
->tcpsi
,BIO_NOCLOSE
);
450 SSL_set_bio (stream
->con
,bio
,bio
);
451 SSL_set_connect_state (stream
->con
);
452 if (SSL_in_init (stream
->con
)) SSL_total_renegotiations (stream
->con
);
453 /* now negotiate SSL */
454 if (SSL_write (stream
->con
,"",0) < 0)
455 return ssl_last_error
? ssl_last_error
: "SSL negotiation failed";
456 /* need to validate host names? */
457 if (!(flags
& NET_NOVALIDATECERT
) &&
458 (err
= ssl_validate_cert (cert
= SSL_get_peer_certificate (stream
->con
),
460 /* application callback */
461 X509_NAME_oneline (X509_get_subject_name(cert
), buf
, sizeof(buf
));
462 if (scq
) return (*scq
) (err
,host
,cert
? buf
: "???") ? NIL
: "";
463 /* error message to return via mm_log() */
464 sprintf (tmp
,"*%.128s: %.255s",err
,cert
? buf
: "???");
465 return ssl_last_error
= cpystr (tmp
);
470 /* SSL certificate verification callback
471 * Accepts: error flag
473 * Returns: error flag
476 static int ssl_open_verify (int ok
,X509_STORE_CTX
*ctx
)
478 char *err
,cert
[256],tmp
[MAILTMPLEN
];
479 sslcertificatequery_t scq
=
480 (sslcertificatequery_t
) mail_parameters (NIL
,GET_SSLCERTIFICATEQUERY
,NIL
);
481 if (!ok
) { /* in case failure */
482 err
= (char *) X509_verify_cert_error_string
483 (X509_STORE_CTX_get_error (ctx
));
484 X509_NAME_oneline (X509_get_subject_name
485 (X509_STORE_CTX_get_current_cert (ctx
)),cert
,255);
486 if (!scq
) { /* mm_log() error message if no callback */
487 sprintf (tmp
,"*%.128s: %.255s",err
,cert
);
488 ssl_last_error
= cpystr (tmp
);
490 /* ignore error if application says to */
491 else if ((*scq
) (err
,ssl_last_host
,cert
)) ok
= T
;
492 /* application wants punt */
493 else ssl_last_error
= cpystr ("");
499 /* SSL validate certificate
500 * Accepts: certificate
501 * host to validate against
502 * Returns: NIL if validated, else string of error message
505 static char *ssl_validate_cert (X509
*cert
,char *host
)
508 char *s
=NULL
,*t
,*ret
= NIL
;
514 /* make sure have a certificate */
515 if (!cert
) return "No certificate from server";
516 /* Method 1: locate CN */
517 #ifndef OPENSSL_1_1_0
518 if (cert
->name
== NIL
)
519 ret
= "No name in certificate";
520 else if ((s
= strstr (cert
->name
,"/CN=")) != NIL
) {
521 m
++; /* count that we tried this method */
522 if (t
= strchr (s
+= 4,'/')) *t
= '\0';
523 /* host name matches pattern? */
524 ret
= ssl_compare_hostnames (host
,s
) ? NIL
:
525 "Server name does not match certificate";
526 if (t
) *t
= '/'; /* restore smashed delimiter */
527 /* if mismatch, see if in extensions */
528 if (ret
&& (ext
= X509_get_ext_d2i (cert
,NID_subject_alt_name
,NIL
,NIL
)) &&
529 (n
= sk_GENERAL_NAME_num (ext
)))
530 /* older versions of OpenSSL use "ia5" instead of dNSName */
531 for (i
= 0; ret
&& (i
< n
); i
++)
532 if ((name
= sk_GENERAL_NAME_value (ext
,i
)) &&
533 (name
->type
= GEN_DNS
) && (s
= name
->d
.ia5
->data
) &&
534 ssl_compare_hostnames (host
,s
)) ret
= NIL
;
536 #endif /* OPENSSL_1_1_0 */
537 /* Method 2, use cname */
538 if(m
== 0 || ret
!= NIL
){
539 cname
= X509_get_subject_name(cert
);
540 for(j
= 0, ret
= NIL
; j
< X509_NAME_entry_count(cname
) && ret
== NIL
; j
++){
541 if((e
= X509_NAME_get_entry(cname
, j
)) != NULL
){
542 X509_NAME_get_text_by_OBJ(cname
, X509_NAME_ENTRY_get_object(e
), buf
, sizeof(buf
));
547 /* host name matches pattern? */
548 ret
= ssl_compare_hostnames (host
,s
) ? NIL
:
549 "Server name does not match certificate";
550 /* if mismatch, see if in extensions */
551 if (ret
&& (ext
= X509_get_ext_d2i (cert
,NID_subject_alt_name
,NIL
,NIL
)) &&
552 (n
= sk_GENERAL_NAME_num (ext
)))
553 /* older versions of OpenSSL use "ia5" instead of dNSName */
554 for (i
= 0; ret
&& (i
< n
); i
++)
555 if ((name
= sk_GENERAL_NAME_value (ext
,i
)) &&
556 (name
->type
= GEN_DNS
) && (s
= name
->d
.ia5
->data
) &&
557 ssl_compare_hostnames (host
,s
)) ret
= NIL
;
563 #ifndef OPENSSL_1_1_0
565 #endif /* OPENSSL_1_1_0 */
566 && !X509_get_subject_name(cert
))
567 ret
= "No name in certificate";
569 if (ret
== NIL
&& s
== NIL
)
570 ret
= "Unable to locate common name in certificate";
575 /* Case-independent wildcard pattern match
576 * Accepts: base string
578 * Returns: T if pattern matches base, else NIL
581 static long ssl_compare_hostnames (unsigned char *s
,unsigned char *pat
)
585 case '*': /* wildcard */
586 if (pat
[1]) { /* there must be a pattern suffix */
587 /* there is, scan base against it */
588 do if (ssl_compare_hostnames (s
,pat
+1)) ret
= LONGT
;
589 while (!ret
&& (*s
!= '.') && *s
++);
592 case '\0': /* end of pattern */
593 if (!*s
) ret
= LONGT
; /* success if base is also at end */
595 default: /* non-wildcard, recurse if match */
596 if (!compare_uchar (*pat
,*s
)) ret
= ssl_compare_hostnames (s
+1,pat
+1);
603 * Accepts: SSL stream
604 * Returns: text line string or NIL if failure
607 char *ssl_getline (SSLSTREAM
*stream
)
609 unsigned long n
,contd
;
610 char *ret
= ssl_getline_work (stream
,&n
,&contd
);
611 if (ret
&& contd
) { /* got a line needing continuation? */
612 STRINGLIST
*stl
= mail_newstringlist ();
613 STRINGLIST
*stc
= stl
;
614 do { /* collect additional lines */
615 stc
->text
.data
= (unsigned char *) ret
;
617 stc
= stc
->next
= mail_newstringlist ();
618 ret
= ssl_getline_work (stream
,&n
,&contd
);
619 } while (ret
&& contd
);
620 if (ret
) { /* stash final part of line on list */
621 stc
->text
.data
= (unsigned char *) ret
;
623 /* determine how large a buffer we need */
624 for (n
= 0, stc
= stl
; stc
; stc
= stc
->next
) n
+= stc
->text
.size
;
625 ret
= fs_get (n
+ 1); /* copy parts into buffer */
626 for (n
= 0, stc
= stl
; stc
; n
+= stc
->text
.size
, stc
= stc
->next
)
627 memcpy (ret
+ n
,stc
->text
.data
,stc
->text
.size
);
630 mail_free_stringlist (&stl
);/* either way, done with list */
635 char *ssl_getsize (SSLSTREAM
*stream
, unsigned long size
)
638 unsigned long got
= 0L, need
= size
, n
;
641 if(!ssl_getdata (stream
)) return ret
; /* return what we have */
642 n
= stream
->ictr
< need
? stream
->ictr
: need
;
643 fs_resize((void **) &ret
, (got
+ n
+ 1)*sizeof(char));
644 memcpy(ret
+ got
, stream
->iptr
, n
);
654 /* SSL receive line or partial line
655 * Accepts: SSL stream
656 * pointer to return size
657 * pointer to return continuation flag
658 * Returns: text line string, size and continuation flag, or NIL if failure
661 static char *ssl_getline_work (SSLSTREAM
*stream
,unsigned long *size
,
666 *contd
= NIL
; /* assume no continuation */
667 /* make sure have data */
668 if (!ssl_getdata (stream
)) return NIL
;
669 for (s
= stream
->iptr
, n
= 0, c
= '\0'; stream
->ictr
--; n
++, c
= d
) {
670 d
= *stream
->iptr
++; /* slurp another character */
671 if ((c
== '\015') && (d
== '\012')) {
672 ret
= (char *) fs_get (n
--);
673 memcpy (ret
,s
,*size
= n
); /* copy into a free storage string */
674 ret
[n
] = '\0'; /* tie off string with null */
678 /* copy partial string from buffer */
679 memcpy ((ret
= (char *) fs_get (n
)),s
,*size
= n
);
680 /* get more data from the net */
681 if (!ssl_getdata (stream
)) fs_give ((void **) &ret
);
682 /* special case of newline broken by buffer */
683 else if ((c
== '\015') && (*stream
->iptr
== '\012')) {
684 stream
->iptr
++; /* eat the line feed */
686 ret
[*size
= --n
] = '\0'; /* tie off string with null */
688 else *contd
= LONGT
; /* continuation needed */
692 /* SSL receive buffer
693 * Accepts: SSL stream
695 * buffer to read into
696 * Returns: T if success, NIL otherwise
699 long ssl_getbuffer (SSLSTREAM
*stream
,unsigned long size
,char *buffer
)
702 while (size
> 0) { /* until request satisfied */
703 if (!ssl_getdata (stream
)) return NIL
;
704 n
= min (size
,stream
->ictr
);/* number of bytes to transfer */
706 memcpy (buffer
,stream
->iptr
,n
);
707 buffer
+= n
; /* update pointer */
709 size
-= n
; /* update # of bytes to do */
712 buffer
[0] = '\0'; /* tie off string */
717 * Accepts: TCP/IP stream
718 * Returns: T if success, NIL otherwise
721 long ssl_getdata (SSLSTREAM
*stream
)
726 tcptimeout_t tmoh
= (tcptimeout_t
) mail_parameters (NIL
,GET_TIMEOUT
,NIL
);
727 long ttmo_read
= (long) mail_parameters (NIL
,GET_READTIMEOUT
,NIL
);
729 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
730 if (!stream
->con
|| ((sock
= SSL_get_fd (stream
->con
)) < 0)) return NIL
;
731 /* tcp_unix should have prevented this */
732 if (sock
>= FD_SETSIZE
) fatal ("unselectable socket in ssl_getdata()");
733 (*bn
) (BLOCK_TCPREAD
,NIL
);
734 while (stream
->ictr
< 1) { /* if nothing in the buffer */
735 time_t tl
= time (0); /* start of request */
737 int ti
= ttmo_read
? now
+ ttmo_read
: 0;
738 if (SSL_pending (stream
->con
)) i
= 1;
740 if (tcpdebug
) mm_log ("Reading SSL data",TCPDEBUG
);
742 FD_ZERO (&fds
); /* initialize selection vector */
743 FD_ZERO (&efds
); /* handle errors too */
744 FD_SET (sock
,&fds
); /* set bit in selection vector */
745 FD_SET (sock
,&efds
); /* set bit in error selection vector */
746 errno
= NIL
; /* block and read */
747 do { /* block under timeout */
748 tmo
.tv_sec
= ti
? ti
- now
: 0;
749 i
= select (sock
+1,&fds
,0,&efds
,ti
? &tmo
: 0);
750 now
= time (0); /* fake timeout if interrupt & time expired */
751 if ((i
< 0) && (errno
== EINTR
) && ti
&& (ti
<= now
)) i
= 0;
752 } while ((i
< 0) && (errno
== EINTR
));
754 if (i
) { /* non-timeout result from select? */
755 errno
= 0; /* just in case */
756 if (i
> 0) /* read what we can */
757 while (((i
= SSL_read (stream
->con
,stream
->ibuf
,SSLBUFLEN
)) < 0) &&
759 (SSL_get_error (stream
->con
,i
) == SSL_ERROR_WANT_READ
)));
760 if (i
<= 0) { /* error seen? */
762 char *s
,tmp
[MAILTMPLEN
];
763 if (i
) sprintf (s
= tmp
,"SSL data read I/O error %d SSL error %d",
764 errno
,SSL_get_error (stream
->con
,i
));
765 else s
= "SSL data read end of file";
768 return ssl_abort (stream
);
770 stream
->iptr
= stream
->ibuf
;/* point at TCP buffer */
771 stream
->ictr
= i
; /* set new byte count */
772 if (tcpdebug
) mm_log ("Successfully read SSL data",TCPDEBUG
);
774 /* timeout, punt unless told not to */
775 else if (!tmoh
|| !(*tmoh
) (now
- t
,now
- tl
, stream
->tcpstream
->host
)) {
776 if (tcpdebug
) mm_log ("SSL data read timeout",TCPDEBUG
);
777 return ssl_abort (stream
);
780 (*bn
) (BLOCK_NONE
,NIL
);
784 /* SSL send string as record
785 * Accepts: SSL stream
787 * Returns: T if success else NIL
790 long ssl_soutr (SSLSTREAM
*stream
,char *string
)
792 return ssl_sout (stream
,string
,(unsigned long) strlen (string
));
797 * Accepts: SSL stream
800 * Returns: T if success else NIL
803 long ssl_sout (SSLSTREAM
*stream
,char *string
,unsigned long size
)
806 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
807 if (!stream
->con
) return NIL
;
808 (*bn
) (BLOCK_TCPWRITE
,NIL
);
809 if (tcpdebug
) mm_log ("Writing to SSL",TCPDEBUG
);
810 /* until request satisfied */
811 for (i
= 0; size
> 0; string
+= i
,size
-= i
)
812 /* write as much as we can */
813 if ((i
= SSL_write (stream
->con
,string
,(int) min (SSLBUFLEN
,size
))) < 0) {
815 char tmp
[MAILTMPLEN
];
816 sprintf (tmp
,"SSL data write I/O error %d SSL error %d",
817 errno
,SSL_get_error (stream
->con
,i
));
818 mm_log (tmp
,TCPDEBUG
);
820 return ssl_abort (stream
);/* write failed */
822 if (tcpdebug
) mm_log ("successfully wrote to TCP",TCPDEBUG
);
823 (*bn
) (BLOCK_NONE
,NIL
);
824 return LONGT
; /* all done */
828 * Accepts: SSL stream
831 void ssl_close (SSLSTREAM
*stream
)
833 ssl_abort (stream
); /* nuke the stream */
834 fs_give ((void **) &stream
); /* flush the stream */
839 * Accepts: SSL stream
840 * Returns: NIL always
843 static long ssl_abort (SSLSTREAM
*stream
)
845 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
846 if (stream
->con
) { /* close SSL connection */
847 SSL_shutdown (stream
->con
);
848 SSL_free (stream
->con
);
851 if (stream
->context
) { /* clean up context */
852 SSL_CTX_free (stream
->context
);
853 stream
->context
= NIL
;
855 if (stream
->tcpstream
) { /* close TCP stream */
856 tcp_close (stream
->tcpstream
);
857 stream
->tcpstream
= NIL
;
859 (*bn
) (BLOCK_NONE
,NIL
);
864 * Accepts: SSL stream
865 * Returns: host name for this stream
868 char *ssl_host (SSLSTREAM
*stream
)
870 return stream
? tcp_host (stream
->tcpstream
) : "UNKNOWN";
874 /* SSL get remote host name
875 * Accepts: SSL stream
876 * Returns: host name for this stream
879 char *ssl_remotehost (SSLSTREAM
*stream
)
881 return tcp_remotehost (stream
->tcpstream
);
885 /* SSL return port for this stream
886 * Accepts: SSL stream
887 * Returns: port number for this stream
890 unsigned long ssl_port (SSLSTREAM
*stream
)
892 return tcp_port (stream
->tcpstream
);
896 /* SSL get local host name
897 * Accepts: SSL stream
898 * Returns: local host name
901 char *ssl_localhost (SSLSTREAM
*stream
)
903 return tcp_localhost (stream
->tcpstream
);
907 * Accepts: /etc/services service name
908 * Returns: cpystr'd error string if TLS failed, else NIL for success
911 char *ssl_start_tls (char *server
)
913 char tmp
[MAILTMPLEN
];
915 if (sslstdio
) return cpystr ("Already in an SSL session");
916 if (start_tls
) return cpystr ("TLS already started");
917 if (server
) { /* build specific certificate/key file name */
918 sprintf (tmp
,"%s/%s-%s.pem",SSL_CERT_DIRECTORY
,server
,tcp_serveraddr ());
919 if (stat (tmp
,&sbuf
)) { /* use non-specific name if no specific file */
920 sprintf (tmp
,"%s/%s.pem",SSL_CERT_DIRECTORY
,server
);
921 if (stat (tmp
,&sbuf
)) return cpystr ("Server certificate not installed");
923 start_tls
= server
; /* switch to STARTTLS mode */
928 /* Init server for SSL
929 * Accepts: server name
932 void ssl_server_init (char *server
)
934 char cert
[MAILTMPLEN
],key
[MAILTMPLEN
];
937 SSLSTREAM
*stream
= (SSLSTREAM
*) memset (fs_get (sizeof (SSLSTREAM
)),0,
939 ssl_onceonlyinit (); /* make sure algorithms added */
941 OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS
, NULL
);
942 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|OPENSSL_INIT_LOAD_CRYPTO_STRINGS
, NULL
);
944 ERR_load_crypto_strings ();
945 SSL_load_error_strings ();
946 #endif /* OPENSSL_1_1_0 */
947 /* build specific certificate/key file names */
948 sprintf (cert
,"%s/%s-%s.pem",SSL_CERT_DIRECTORY
,server
,tcp_serveraddr ());
949 sprintf (key
,"%s/%s-%s.pem",SSL_KEY_DIRECTORY
,server
,tcp_serveraddr ());
950 /* use non-specific name if no specific cert */
951 if (stat (cert
,&sbuf
)) sprintf (cert
,"%s/%s.pem",SSL_CERT_DIRECTORY
,server
);
952 if (stat (key
,&sbuf
)) { /* use non-specific name if no specific key */
953 sprintf (key
,"%s/%s.pem",SSL_KEY_DIRECTORY
,server
);
954 /* use cert file as fallback for key */
955 if (stat (key
,&sbuf
)) strcpy (key
,cert
);
959 if (!(stream
->context
= SSL_CTX_new (start_tls
?
960 TLS_server_method () :
961 SSLv23_server_method ())))
963 if (!(stream
->context
= SSL_CTX_new (start_tls
?
964 TLSv1_server_method () :
965 SSLv23_server_method ())))
966 #endif /* OPENSSL_1_1_0 */
967 syslog (LOG_ALERT
,"Unable to create SSL context, host=%.80s",
969 else { /* set context options */
970 SSL_CTX_set_options (stream
->context
,SSL_OP_ALL
);
971 /* set cipher list */
972 if (!SSL_CTX_set_cipher_list (stream
->context
,SSLCIPHERLIST
))
973 syslog (LOG_ALERT
,"Unable to set cipher list %.80s, host=%.80s",
974 SSLCIPHERLIST
,tcp_clienthost ());
975 /* load certificate */
976 else if (!SSL_CTX_use_certificate_chain_file (stream
->context
,cert
))
977 syslog (LOG_ALERT
,"Unable to load certificate from %.80s, host=%.80s",
978 cert
,tcp_clienthost ());
980 else if (!(SSL_CTX_use_RSAPrivateKey_file (stream
->context
,key
,
982 syslog (LOG_ALERT
,"Unable to load private key from %.80s, host=%.80s",
983 key
,tcp_clienthost ());
985 else { /* generate key if needed */
988 ssl_genkey(stream
->context
, 0, 0);
990 if (SSL_CTX_need_tmp_RSA (stream
->context
))
991 SSL_CTX_set_tmp_rsa_callback (stream
->context
,ssl_genkey
);
992 #endif /* OPENSSL_1_1_0 */
993 /* create new SSL connection */
994 if (!(stream
->con
= SSL_new (stream
->context
)))
995 syslog (LOG_ALERT
,"Unable to create SSL connection, host=%.80s",
997 else { /* set file descriptor */
998 SSL_set_fd (stream
->con
,0);
999 /* all OK if accepted */
1000 if (SSL_accept (stream
->con
) < 0)
1001 syslog (LOG_INFO
,"Unable to accept SSL connection, host=%.80s",
1003 else { /* server set up */
1004 sslstdio
= (SSLSTDIOSTREAM
*)
1005 memset (fs_get (sizeof(SSLSTDIOSTREAM
)),0,sizeof (SSLSTDIOSTREAM
));
1006 sslstdio
->sslstream
= stream
;
1007 /* available space in output buffer */
1008 sslstdio
->octr
= SSLBUFLEN
;
1009 /* current output buffer pointer */
1010 sslstdio
->optr
= sslstdio
->obuf
;
1011 /* allow plaintext if disable value was 2 */
1012 if ((long) mail_parameters (NIL
,GET_DISABLEPLAINTEXT
,NIL
) > 1)
1013 mail_parameters (NIL
,SET_DISABLEPLAINTEXT
,NIL
);
1014 /* unhide PLAIN SASL authenticator */
1015 mail_parameters (NIL
,UNHIDE_AUTHENTICATOR
,"PLAIN");
1016 mail_parameters (NIL
,UNHIDE_AUTHENTICATOR
,"LOGIN");
1022 while ((i
= ERR_get_error ()) != 0L) /* SSL failure */
1023 syslog (LOG_ERR
,"SSL error status: %.80s",ERR_error_string (i
,NIL
));
1024 ssl_close (stream
); /* punt stream */
1025 exit (1); /* punt this program too */
1028 /* Generate one-time key for server
1029 * Accepts: SSL connection
1032 * Returns: generated key, always
1035 static RSA
*ssl_genkey (SSL_CTX_TYPE
*con
,int export
,int keylength
)
1038 static RSA
*key
= NIL
;
1039 if (!key
) { /* if don't have a key already */
1041 #ifdef OPENSSL_1_1_0
1042 BIGNUM
*e
= BN_new();
1043 if (!RSA_generate_key_ex (key
, export
? keylength
: 1024, e
,NIL
)) {
1045 if (!(key
= RSA_generate_key (export
? keylength
: 1024,RSA_F4
,NIL
,NIL
))) {
1046 #endif /* OPENSSL_1_1_0 */
1047 syslog (LOG_ALERT
,"Unable to generate temp key, host=%.80s",
1049 while ((i
= ERR_get_error ()) != 0L)
1050 syslog (LOG_ALERT
,"SSL error status: %s",ERR_error_string (i
,NIL
));
1053 #ifdef OPENSSL_1_1_0
1056 #endif /* OPENSSL_1_1_0 */
1061 /* Wait for stdin input
1062 * Accepts: timeout in seconds
1063 * Returns: T if have input on stdin, else NIL
1066 long ssl_server_input_wait (long seconds
)
1072 if (!sslstdio
) return server_input_wait (seconds
);
1073 /* input available in buffer */
1074 if (((stream
= sslstdio
->sslstream
)->ictr
> 0) ||
1075 !stream
->con
|| ((sock
= SSL_get_fd (stream
->con
)) < 0)) return LONGT
;
1076 /* sock ought to be 0 always */
1077 if (sock
>= FD_SETSIZE
) fatal ("unselectable socket in ssl_getdata()");
1078 /* input available from SSL */
1079 if (SSL_pending (stream
->con
) &&
1080 ((i
= SSL_read (stream
->con
,stream
->ibuf
,SSLBUFLEN
)) > 0)) {
1081 stream
->iptr
= stream
->ibuf
;/* point at TCP buffer */
1082 stream
->ictr
= i
; /* set new byte count */
1085 FD_ZERO (&fds
); /* initialize selection vector */
1086 FD_ZERO (&efd
); /* initialize selection vector */
1087 FD_SET (sock
,&fds
); /* set bit in selection vector */
1088 FD_SET (sock
,&efd
); /* set bit in selection vector */
1089 tmo
.tv_sec
= seconds
; tmo
.tv_usec
= 0;
1090 /* see if input available from the socket */
1091 return select (sock
+1,&fds
,0,&efd
,&tmo
) ? LONGT
: NIL
;
1094 #include "sslstdio.c"