1 /* ========================================================================
2 * Copyright 2018 Eduardo Chappa
3 * Copyright 2008-2009 Mark Crispin
4 * ========================================================================
8 * Program: SSL authentication/encryption module for Windows 9x and NT
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
26 #ifdef ENABLE_WINDOWS_LIBRESSL
27 #define crypt ssl_private_crypt
28 #define STRING OPENSSL_STRING
37 #ifndef TLS_client_method
38 #ifdef TLSv1_2_client_method
39 #define TLS_client_method TLSv1_2_client_method
40 #elif defined(TLSv1_1_client_method)
41 #define TLS_client_method TLSv1_1_client_method
43 #define TLS_client_method TLSv1_client_method
44 #endif /* TLSv1_2_client_method */
45 #endif /* TLS_client_method */
49 #ifdef TLSv1_client_method
50 #undef TLSv1_client_method
51 #endif /* TLSv1_client_method */
52 #ifdef TLSv1_1_client_method
53 #undef TLSv1_1_client_method
54 #endif /* TLSv1_1_client_method */
55 #ifdef TLSv1_2_client_method
56 #undef TLSv1_2_client_method
57 #endif /* TLSv1_2_client_method */
58 #ifdef DTLSv1_client_method
59 #undef DTLSv1_client_method
60 #endif /* DTLSv1_client_method */
61 #ifdef DTLSv1_2_client_method
62 #undef DTLSv1_2_client_method
63 #endif /* DTLSv1_2_client_method */
64 #define TLSv1_client_method TLS_client_method
65 #define TLSv1_1_client_method TLS_client_method
66 #define TLSv1_2_client_method TLS_client_method
67 #define DTLSv1_client_method DTLS_client_method
68 #define DTLSv1_2_client_method DTLS_client_method
69 #endif /* OPENSSL_1_1_0 */
70 #ifndef DTLSv1_2_client_method
71 #define DTLSv1_2_client_method DTLSv1_client_method
72 #endif /* DTLSv1_2_client_method */
76 #define SSLBUFLEN 8192
79 * PCI auditing compliance, disable:
81 * anonymous D-H (no certificate
82 * export encryption ciphers (40 and 56 bits)
83 * low encryption cipher suites (40 and 56 bits, excluding export)
84 * null encryption (disabling implied by "ALL")
86 * UW imapd just disables low-grade and null ("ALL:!LOW"). This setting
87 * will break clients that attempt to use the newly-prohibited mechanisms.
89 * I question the value of disabling SSLv2, as opposed to disabling the SSL
90 * ports (e.g., 993 for IMAP, 995 for POP3) and using TLS exclusively.
93 #define SSLCIPHERLIST "ALL:!SSLv2:!ADH:!EXP:!LOW"
97 typedef struct ssl_stream
{
98 TCPSTREAM
*tcpstream
; /* TCP stream */
99 SSL_CTX
*context
; /* SSL context */
100 SSL
*con
; /* SSL connection */
101 int ictr
; /* input counter */
102 char *iptr
; /* input pointer */
103 char ibuf
[SSLBUFLEN
]; /* input buffer */
108 /* Function prototypes */
109 const SSL_METHOD
*ssl_connect_mthd(int flag
);
110 static SSLSTREAM
*ssl_start(TCPSTREAM
*tstream
,char *host
,unsigned long flags
);
111 static char *ssl_start_work (SSLSTREAM
*stream
,char *host
,unsigned long flags
);
112 static int ssl_open_verify (int ok
,X509_STORE_CTX
*ctx
);
113 static char *ssl_validate_cert (X509
*cert
,char *host
);
114 static long ssl_compare_hostnames (unsigned char *s
,unsigned char *pat
);
115 static char *ssl_getline_work (SSLSTREAM
*stream
,unsigned long *size
,
117 static long ssl_abort (SSLSTREAM
*stream
);
120 #define SSL_CTX_TYPE SSL_CTX
122 #define SSL_CTX_TYPE SSL
123 #endif /* OPENSSL_1_1_0 */
125 static RSA
*ssl_genkey (SSL_CTX_TYPE
*con
,int export
,int keylength
);
128 /* Secure Sockets Layer network driver dispatch */
130 static struct ssl_driver ssldriver
= {
131 ssl_open
, /* open connection */
132 ssl_aopen
, /* open preauthenticated connection */
133 ssl_getline
, /* get a line */
134 ssl_getbuffer
, /* get a buffer */
135 ssl_soutr
, /* output pushed data */
136 ssl_sout
, /* output string */
137 ssl_close
, /* close connection */
138 ssl_host
, /* return host name */
139 ssl_remotehost
, /* return remote host name */
140 ssl_port
, /* return port number */
141 ssl_localhost
/* return local host name */
143 /* non-NIL if doing SSL primary I/O */
144 static SSLSTDIOSTREAM
*sslstdio
= NIL
;
145 static char *start_tls
= NIL
; /* non-NIL if start TLS requested */
147 /* One-time SSL initialization */
149 static int sslonceonly
= 0;
151 void ssl_onceonlyinit (void)
153 if (!sslonceonly
++) { /* only need to call it once */
155 char tmp
[MAILTMPLEN
];
157 /* if system doesn't have /dev/urandom */
158 if (stat ("/dev/urandom",&sbuf
)) {
159 strcpy(tmp
, "SSLXXXXXX");
161 unlink (tmp
); /* don't need the file */
162 fstat (fd
,&sbuf
); /* get information about the file */
163 close (fd
); /* flush descriptor */
164 /* not great but it'll have to do */
165 sprintf (tmp
+ strlen (tmp
),"%.80s%lx%.80s%lx%lx%lx%lx%lx",
166 tcp_serveraddr (),(unsigned long) tcp_serverport (),
167 tcp_clientaddr (),(unsigned long) tcp_clientport (),
168 (unsigned long) sbuf
.st_ino
,(unsigned long) time (0),
169 (unsigned long) gethostid (),(unsigned long) getpid ());
170 RAND_seed (tmp
,strlen (tmp
));
172 /* apply runtime linkage */
173 mail_parameters (NIL
,SET_SSLDRIVER
,(void *) &ssldriver
);
174 mail_parameters (NIL
,SET_SSLSTART
,(void *) ssl_start
);
176 OPENSSL_init_ssl(0, NULL
);
178 SSL_library_init (); /* add all algorithms */
179 #endif /* OPENSSL_1_1_0 */
185 * contact service name
186 * contact port number
187 * Returns: SSL stream if success else NIL
190 SSLSTREAM
*ssl_open (char *host
,char *service
,unsigned long port
)
192 TCPSTREAM
*stream
= tcp_open (host
,service
,port
);
193 return stream
? ssl_start (stream
,host
,port
) : NIL
;
197 /* SSL authenticated open
200 * returned user name buffer
201 * Returns: SSL stream if success else NIL
204 SSLSTREAM
*ssl_aopen (NETMBX
*mb
,char *service
,char *usrbuf
)
206 return NIL
; /* don't use this mechanism with SSL */
209 /* ssl_connect_mthd: returns a context pointer to the connection to
212 const SSL_METHOD
*ssl_connect_mthd(int flag
)
214 if (flag
& NET_TRYTLS1
)
215 #ifndef OPENSSL_NO_TLS1_METHOD
216 return TLSv1_client_method();
218 return TLS_client_method();
219 #endif /* OPENSSL_NO_TLS1_METHOD */
221 else if(flag
& NET_TRYTLS1_1
)
222 #ifndef OPENSSL_NO_TLS1_1_METHOD
223 return TLSv1_1_client_method();
225 return TLS_client_method();
226 #endif /* OPENSSL_NO_TLS1_1_METHOD */
228 else if(flag
& NET_TRYTLS1_2
)
229 #ifndef OPENSSL_NO_TLS1_2_METHOD
230 return TLSv1_2_client_method();
232 return TLS_client_method();
233 #endif /* OPENSSL_NO_TLS1_2_METHOD */
235 else if(flag
& NET_TRYTLS1_3
)
236 return TLS_client_method();
238 else if(flag
& NET_TRYDTLS1
)
239 #ifndef OPENSSL_NO_DTLS1_METHOD
240 return DTLSv1_client_method();
242 return DTLS_client_method();
243 #endif /* OPENSSL_NO_DTLS1_METHOD */
245 else if(flag
& NET_TRYDTLS1_2
)
246 #ifndef OPENSSL_NO_DTLS1_METHOD
247 return DTLSv1_2_client_method();
249 return DTLS_client_method();
250 #endif /* OPENSSL_NO_DTLS1_METHOD */
252 else return SSLv23_client_method();
255 /* Start SSL/TLS negotiations
256 * Accepts: open TCP stream of session
259 * Returns: SSL stream if success else NIL
262 static SSLSTREAM
*ssl_start (TCPSTREAM
*tstream
,char *host
,unsigned long flags
)
264 char *reason
,tmp
[MAILTMPLEN
];
265 sslfailure_t sf
= (sslfailure_t
) mail_parameters (NIL
,GET_SSLFAILURE
,NIL
);
266 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
267 void *data
= (*bn
) (BLOCK_SENSITIVE
,NIL
);
268 SSLSTREAM
*stream
= (SSLSTREAM
*) memset (fs_get (sizeof (SSLSTREAM
)),0,
270 stream
->tcpstream
= tstream
; /* bind TCP stream */
272 reason
= ssl_start_work (stream
,host
,flags
);
273 (*bn
) (BLOCK_NONSENSITIVE
,data
);
274 if (reason
) { /* failed? */
275 ssl_close (stream
); /* failed to do SSL */
276 stream
= NIL
; /* no stream returned */
277 switch (*reason
) { /* analyze reason */
278 case '*': /* certificate failure */
279 ++reason
; /* skip over certificate failure indication */
280 /* pass to error callback */
281 if (sf
) (*sf
) (host
,reason
,flags
);
282 else { /* no error callback, build error message */
283 sprintf (tmp
,"Certificate failure for %.80s: %.512s",host
,reason
);
286 case '\0': /* user answered no to certificate callback */
287 if (flags
& NET_TRYSSL
) /* return dummy stream to stop tryssl */
288 stream
= (SSLSTREAM
*) memset (fs_get (sizeof (SSLSTREAM
)),0,
291 default: /* non-certificate failure */
292 if (flags
& NET_TRYSSL
); /* no error output if tryssl */
293 /* pass to error callback */
294 else if (sf
) (*sf
) (host
,reason
,flags
);
295 else { /* no error callback, build error message */
296 sprintf (tmp
,"TLS/SSL failure for %.80s: %.512s",host
,reason
);
305 /* Start SSL/TLS negotiations worker routine
306 * Accepts: SSL stream
309 * Returns: NIL if success, else error reason
312 /* evil but I had no choice */
313 static char *ssl_last_error
= NIL
;
314 static char *ssl_last_host
= NIL
;
316 static char *ssl_start_work (SSLSTREAM
*stream
,char *host
,unsigned long flags
)
321 char *s
,*t
,*err
,tmp
[MAILTMPLEN
], buf
[256];
322 sslcertificatequery_t scq
=
323 (sslcertificatequery_t
) mail_parameters (NIL
,GET_SSLCERTIFICATEQUERY
,NIL
);
324 sslclientcert_t scc
=
325 (sslclientcert_t
) mail_parameters (NIL
,GET_SSLCLIENTCERT
,NIL
);
327 (sslclientkey_t
) mail_parameters (NIL
,GET_SSLCLIENTKEY
,NIL
);
328 if (ssl_last_error
) fs_give ((void **) &ssl_last_error
);
329 ssl_last_host
= host
;
330 if (!(stream
->context
= SSL_CTX_new (ssl_connect_mthd(flags
))))
331 return "SSL context failed";
332 SSL_CTX_set_options (stream
->context
,0);
333 /* disable certificate validation? */
334 if (flags
& NET_NOVALIDATECERT
)
335 SSL_CTX_set_verify (stream
->context
,SSL_VERIFY_NONE
,NIL
);
336 else SSL_CTX_set_verify (stream
->context
,SSL_VERIFY_PEER
,ssl_open_verify
);
337 /* set default paths to CAs... */
338 SSL_CTX_set_default_verify_paths (stream
->context
);
339 /* ...unless a non-standard path desired */
340 if ((s
= (char *) mail_parameters (NIL
,GET_SSLCAPATH
,NIL
)) != NULL
)
341 SSL_CTX_load_verify_locations (stream
->context
,NIL
,s
);
342 /* want to send client certificate? */
343 if (scc
&& (s
= (*scc
) ()) && (sl
= strlen (s
))) {
344 if ((cert
= PEM_read_bio_X509 (bio
= BIO_new_mem_buf (s
,sl
),NIL
,NIL
,NIL
)) != NULL
) {
345 SSL_CTX_use_certificate (stream
->context
,cert
);
349 if (!cert
) return "SSL client certificate failed";
350 /* want to supply private key? */
351 if ((t
= (sck
? (*sck
) () : s
)) && (tl
= strlen (t
))) {
353 if ((key
= PEM_read_bio_PrivateKey (bio
= BIO_new_mem_buf (t
,tl
),
354 NIL
,NIL
,"")) != NULL
) {
355 SSL_CTX_use_PrivateKey (stream
->context
,key
);
359 memset (t
,0,tl
); /* erase key */
361 if (s
!= t
) memset (s
,0,sl
);/* erase certificate if different from key */
364 /* create connection */
365 if (!(stream
->con
= (SSL
*) SSL_new (stream
->context
)))
366 return "SSL connection failed";
367 bio
= BIO_new_socket (stream
->tcpstream
->tcpsi
,BIO_NOCLOSE
);
368 SSL_set_bio (stream
->con
,bio
,bio
);
369 SSL_set_connect_state (stream
->con
);
370 if (SSL_in_init (stream
->con
)) SSL_total_renegotiations (stream
->con
);
371 /* now negotiate SSL */
372 if (SSL_write (stream
->con
,"",0) < 0)
373 return ssl_last_error
? ssl_last_error
: "SSL negotiation failed";
374 /* need to validate host names? */
375 if (!(flags
& NET_NOVALIDATECERT
) &&
376 (err
= ssl_validate_cert (cert
= SSL_get_peer_certificate (stream
->con
),
378 /* application callback */
379 X509_NAME_oneline (X509_get_subject_name(cert
), buf
, sizeof(buf
));
380 if (scq
) return (*scq
) (err
,host
,cert
? buf
: "???") ? NIL
: "";
381 /* error message to return via mm_log() */
382 sprintf (tmp
,"*%.128s: %.255s",err
,cert
? buf
: "???");
383 return ssl_last_error
= cpystr (tmp
);
388 /* SSL certificate verification callback
389 * Accepts: error flag
391 * Returns: error flag
394 static int ssl_open_verify (int ok
,X509_STORE_CTX
*ctx
)
396 char *err
,cert
[256],tmp
[MAILTMPLEN
];
397 sslcertificatequery_t scq
=
398 (sslcertificatequery_t
) mail_parameters (NIL
,GET_SSLCERTIFICATEQUERY
,NIL
);
399 if (!ok
) { /* in case failure */
400 err
= (char *) X509_verify_cert_error_string
401 (X509_STORE_CTX_get_error (ctx
));
402 X509_NAME_oneline (X509_get_subject_name
403 (X509_STORE_CTX_get_current_cert (ctx
)),cert
,255);
404 if (!scq
) { /* mm_log() error message if no callback */
405 sprintf (tmp
,"*%.128s: %.255s",err
,cert
);
406 ssl_last_error
= cpystr (tmp
);
408 /* ignore error if application says to */
409 else if ((*scq
) (err
,ssl_last_host
,cert
)) ok
= T
;
410 /* application wants punt */
411 else ssl_last_error
= cpystr ("");
417 /* SSL validate certificate
418 * Accepts: certificate
419 * host to validate against
420 * Returns: NIL if validated, else string of error message
423 static char *ssl_validate_cert (X509
*cert
,char *host
)
426 char *s
=NULL
,*t
,*ret
;
432 /* make sure have a certificate */
433 if (!cert
) ret
= "No certificate from server";
434 /* and that it has a name */
435 else if (!(cname
= X509_get_subject_name(cert
))) ret
= "No name in certificate";
438 if((e
= X509_NAME_get_entry(cname
, X509_NAME_entry_count(cname
)-1)) != NULL
){
439 X509_NAME_get_text_by_OBJ(cname
, X509_NAME_ENTRY_get_object(e
), buf
, sizeof(buf
));
445 /* host name matches pattern? */
446 ret
= ssl_compare_hostnames (host
,s
) ? NIL
:
447 "Server name does not match certificate";
448 /* if mismatch, see if in extensions */
449 if (ret
&& (ext
= X509_get_ext_d2i (cert
,NID_subject_alt_name
,NIL
,NIL
)) &&
450 (n
= sk_GENERAL_NAME_num (ext
)))
451 /* older versions of OpenSSL use "ia5" instead of dNSName */
452 for (i
= 0; ret
&& (i
< n
); i
++)
453 if ((name
= sk_GENERAL_NAME_value (ext
,i
)) &&
454 (name
->type
= GEN_DNS
) && (s
= name
->d
.ia5
->data
) &&
455 ssl_compare_hostnames (host
,s
)) ret
= NIL
;
457 else ret
= "Unable to locate common name in certificate";
461 /* Case-independent wildcard pattern match
462 * Accepts: base string
464 * Returns: T if pattern matches base, else NIL
467 static long ssl_compare_hostnames (unsigned char *s
,unsigned char *pat
)
471 case '*': /* wildcard */
472 if (pat
[1]) { /* there must be a pattern suffix */
473 /* there is, scan base against it */
474 do if (ssl_compare_hostnames (s
,pat
+1)) ret
= LONGT
;
475 while (!ret
&& (*s
!= '.') && *s
++);
478 case '\0': /* end of pattern */
479 if (!*s
) ret
= LONGT
; /* success if base is also at end */
481 default: /* non-wildcard, recurse if match */
482 if (!compare_uchar (*pat
,*s
)) ret
= ssl_compare_hostnames (s
+1,pat
+1);
489 * Accepts: SSL stream
490 * Returns: text line string or NIL if failure
493 char *ssl_getline (SSLSTREAM
*stream
)
495 unsigned long n
,contd
;
496 char *ret
= ssl_getline_work (stream
,&n
,&contd
);
497 if (ret
&& contd
) { /* got a line needing continuation? */
498 STRINGLIST
*stl
= mail_newstringlist ();
499 STRINGLIST
*stc
= stl
;
500 do { /* collect additional lines */
501 stc
->text
.data
= (unsigned char *) ret
;
503 stc
= stc
->next
= mail_newstringlist ();
504 ret
= ssl_getline_work (stream
,&n
,&contd
);
505 } while (ret
&& contd
);
506 if (ret
) { /* stash final part of line on list */
507 stc
->text
.data
= (unsigned char *) ret
;
509 /* determine how large a buffer we need */
510 for (n
= 0, stc
= stl
; stc
; stc
= stc
->next
) n
+= stc
->text
.size
;
511 ret
= fs_get (n
+ 1); /* copy parts into buffer */
512 for (n
= 0, stc
= stl
; stc
; n
+= stc
->text
.size
, stc
= stc
->next
)
513 memcpy (ret
+ n
,stc
->text
.data
,stc
->text
.size
);
516 mail_free_stringlist (&stl
);/* either way, done with list */
521 /* SSL receive line or partial line
522 * Accepts: SSL stream
523 * pointer to return size
524 * pointer to return continuation flag
525 * Returns: text line string, size and continuation flag, or NIL if failure
528 static char *ssl_getline_work (SSLSTREAM
*stream
,unsigned long *size
,
533 *contd
= NIL
; /* assume no continuation */
534 /* make sure have data */
535 if (!ssl_getdata (stream
)) return NIL
;
536 for (s
= stream
->iptr
, n
= 0, c
= '\0'; stream
->ictr
--; n
++, c
= d
) {
537 d
= *stream
->iptr
++; /* slurp another character */
538 if ((c
== '\015') && (d
== '\012')) {
539 ret
= (char *) fs_get (n
--);
540 memcpy (ret
,s
,*size
= n
); /* copy into a free storage string */
541 ret
[n
] = '\0'; /* tie off string with null */
545 /* copy partial string from buffer */
546 memcpy ((ret
= (char *) fs_get (n
)),s
,*size
= n
);
547 /* get more data from the net */
548 if (!ssl_getdata (stream
)) fs_give ((void **) &ret
);
549 /* special case of newline broken by buffer */
550 else if ((c
== '\015') && (*stream
->iptr
== '\012')) {
551 stream
->iptr
++; /* eat the line feed */
553 ret
[*size
= --n
] = '\0'; /* tie off string with null */
555 else *contd
= LONGT
; /* continuation needed */
559 /* SSL receive buffer
560 * Accepts: SSL stream
562 * buffer to read into
563 * Returns: T if success, NIL otherwise
566 long ssl_getbuffer (SSLSTREAM
*stream
,unsigned long size
,char *buffer
)
569 while (size
> 0) { /* until request satisfied */
570 if (!ssl_getdata (stream
)) return NIL
;
571 n
= min (size
,stream
->ictr
);/* number of bytes to transfer */
573 memcpy (buffer
,stream
->iptr
,n
);
574 buffer
+= n
; /* update pointer */
576 size
-= n
; /* update # of bytes to do */
579 buffer
[0] = '\0'; /* tie off string */
584 * Accepts: TCP/IP stream
585 * Returns: T if success, NIL otherwise
590 #endif /* FD_SETSIZE */
591 #define FD_SETSIZE 16384
593 long ssl_getdata (SSLSTREAM
*stream
)
598 tcptimeout_t tmoh
= (tcptimeout_t
) mail_parameters (NIL
,GET_TIMEOUT
,NIL
);
599 long ttmo_read
= (long) mail_parameters (NIL
,GET_READTIMEOUT
,NIL
);
601 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
602 if (!stream
->con
|| ((sock
= SSL_get_fd (stream
->con
)) < 0)) return NIL
;
603 /* tcp_unix should have prevented this */
604 if (sock
>= FD_SETSIZE
) fatal ("unselectable socket in ssl_getdata()");
605 (*bn
) (BLOCK_TCPREAD
,NIL
);
606 while (stream
->ictr
< 1) { /* if nothing in the buffer */
607 time_t tl
= time (0); /* start of request */
609 int ti
= ttmo_read
? now
+ ttmo_read
: 0;
610 if (SSL_pending (stream
->con
)) i
= 1;
612 if (tcpdebug
) mm_log ("Reading SSL data",TCPDEBUG
);
614 FD_ZERO (&fds
); /* initialize selection vector */
615 FD_ZERO (&efds
); /* handle errors too */
616 FD_SET (sock
,&fds
); /* set bit in selection vector */
617 FD_SET (sock
,&efds
); /* set bit in error selection vector */
618 errno
= NIL
; /* block and read */
619 do { /* block under timeout */
620 tmo
.tv_sec
= ti
? ti
- now
: 0;
621 i
= select (sock
+1,&fds
,0,&efds
,ti
? &tmo
: 0);
622 now
= time (0); /* fake timeout if interrupt & time expired */
623 if ((i
< 0) && (errno
== EINTR
) && ti
&& (ti
<= now
)) i
= 0;
624 } while ((i
< 0) && (errno
== EINTR
));
626 if (i
) { /* non-timeout result from select? */
627 errno
= 0; /* just in case */
628 if (i
> 0) /* read what we can */
629 while (((i
= SSL_read (stream
->con
,stream
->ibuf
,SSLBUFLEN
)) < 0) &&
631 (SSL_get_error (stream
->con
,i
) == SSL_ERROR_WANT_READ
)));
632 if (i
<= 0) { /* error seen? */
634 char *s
,tmp
[MAILTMPLEN
];
635 if (i
) sprintf (s
= tmp
,"SSL data read I/O error %d SSL error %d",
636 errno
,SSL_get_error (stream
->con
,i
));
637 else s
= "SSL data read end of file";
640 return ssl_abort (stream
);
642 stream
->iptr
= stream
->ibuf
;/* point at TCP buffer */
643 stream
->ictr
= i
; /* set new byte count */
644 if (tcpdebug
) mm_log ("Successfully read SSL data",TCPDEBUG
);
646 /* timeout, punt unless told not to */
647 else if (!tmoh
|| !(*tmoh
) (now
- t
,now
- tl
, stream
->tcpstream
->host
)) {
648 if (tcpdebug
) mm_log ("SSL data read timeout",TCPDEBUG
);
649 return ssl_abort (stream
);
652 (*bn
) (BLOCK_NONE
,NIL
);
656 /* SSL send string as record
657 * Accepts: SSL stream
659 * Returns: T if success else NIL
662 long ssl_soutr (SSLSTREAM
*stream
,char *string
)
664 return ssl_sout (stream
,string
,(unsigned long) strlen (string
));
669 * Accepts: SSL stream
672 * Returns: T if success else NIL
675 long ssl_sout (SSLSTREAM
*stream
,char *string
,unsigned long size
)
678 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
679 if (!stream
->con
) return NIL
;
680 (*bn
) (BLOCK_TCPWRITE
,NIL
);
681 if (tcpdebug
) mm_log ("Writing to SSL",TCPDEBUG
);
682 /* until request satisfied */
683 for (i
= 0; size
> 0; string
+= i
,size
-= i
)
684 /* write as much as we can */
685 if ((i
= SSL_write (stream
->con
,string
,(int) min (SSLBUFLEN
,size
))) < 0) {
687 char tmp
[MAILTMPLEN
];
688 sprintf (tmp
,"SSL data write I/O error %d SSL error %d",
689 errno
,SSL_get_error (stream
->con
,i
));
690 mm_log (tmp
,TCPDEBUG
);
692 return ssl_abort (stream
);/* write failed */
694 if (tcpdebug
) mm_log ("successfully wrote to TCP",TCPDEBUG
);
695 (*bn
) (BLOCK_NONE
,NIL
);
696 return LONGT
; /* all done */
700 * Accepts: SSL stream
703 void ssl_close (SSLSTREAM
*stream
)
705 ssl_abort (stream
); /* nuke the stream */
706 fs_give ((void **) &stream
); /* flush the stream */
711 * Accepts: SSL stream
712 * Returns: NIL always
715 static long ssl_abort (SSLSTREAM
*stream
)
717 blocknotify_t bn
= (blocknotify_t
) mail_parameters (NIL
,GET_BLOCKNOTIFY
,NIL
);
718 if (stream
->con
) { /* close SSL connection */
719 SSL_shutdown (stream
->con
);
720 SSL_free (stream
->con
);
723 if (stream
->context
) { /* clean up context */
724 SSL_CTX_free (stream
->context
);
725 stream
->context
= NIL
;
727 if (stream
->tcpstream
) { /* close TCP stream */
728 tcp_close (stream
->tcpstream
);
729 stream
->tcpstream
= NIL
;
731 (*bn
) (BLOCK_NONE
,NIL
);
736 * Accepts: SSL stream
737 * Returns: host name for this stream
740 char *ssl_host (SSLSTREAM
*stream
)
742 return stream
? tcp_host (stream
->tcpstream
) : "UNKNOWN";
746 /* SSL get remote host name
747 * Accepts: SSL stream
748 * Returns: host name for this stream
751 char *ssl_remotehost (SSLSTREAM
*stream
)
753 return tcp_remotehost (stream
->tcpstream
);
757 /* SSL return port for this stream
758 * Accepts: SSL stream
759 * Returns: port number for this stream
762 unsigned long ssl_port (SSLSTREAM
*stream
)
764 return tcp_port (stream
->tcpstream
);
768 /* SSL get local host name
769 * Accepts: SSL stream
770 * Returns: local host name
773 char *ssl_localhost (SSLSTREAM
*stream
)
775 return tcp_localhost (stream
->tcpstream
);
778 #ifdef SSL_CERT_DIRECTORY
779 #undef SSL_CERT_DIRECTORY
780 #endif /* SSL_CERT_DIRECTORY */
781 #define SSL_CERT_DIRECTORY "C:\\\\libressl\\ssl\\certs"
783 #ifdef SSL_KEY_DIRECTORY
784 #undef SSL_KEY_DIRECTORY
785 #endif /* SSL_KEY_DIRECTORY */
786 #define SSL_KEY_DIRECTORY "C:\\\\libressl\\ssl\\private"
790 * Accepts: /etc/services service name
791 * Returns: cpystr'd error string if TLS failed, else NIL for success
793 char *ssl_start_tls (char *server
)
795 char tmp
[MAILTMPLEN
];
797 if (sslstdio
) return cpystr ("Already in an SSL session");
798 if (start_tls
) return cpystr ("TLS already started");
799 if (server
) { /* build specific certificate/key file name */
800 sprintf (tmp
,"%s\\%s-%s.pem",SSL_CERT_DIRECTORY
,server
,tcp_serveraddr ());
801 if (stat (tmp
,&sbuf
)) { /* use non-specific name if no specific file */
802 sprintf (tmp
,"%s\\%s.pem",SSL_CERT_DIRECTORY
,server
);
803 if (stat (tmp
,&sbuf
)) return cpystr ("Server certificate not installed");
805 start_tls
= server
; /* switch to STARTTLS mode */
810 /* Init server for SSL
811 * Accepts: server name
814 void ssl_server_init (char *server
)
816 char cert
[MAILTMPLEN
],key
[MAILTMPLEN
];
819 SSLSTREAM
*stream
= (SSLSTREAM
*) memset (fs_get (sizeof (SSLSTREAM
)),0,
821 ssl_onceonlyinit (); /* make sure algorithms added */
823 OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS
, NULL
);
824 OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|OPENSSL_INIT_LOAD_CRYPTO_STRINGS
, NULL
);
826 ERR_load_crypto_strings ();
827 SSL_load_error_strings ();
828 #endif /* OPENSSL_1_1_0 */
829 /* build specific certificate/key file names */
830 sprintf (cert
,"%s\\%s-%s.pem",SSL_CERT_DIRECTORY
,server
,tcp_serveraddr ());
831 sprintf (key
,"%s\\%s-%s.pem",SSL_KEY_DIRECTORY
,server
,tcp_serveraddr ());
832 /* use non-specific name if no specific cert */
833 if (stat (cert
,&sbuf
)) sprintf (cert
,"%s\\%s.pem",SSL_CERT_DIRECTORY
,server
);
834 if (stat (key
,&sbuf
)) { /* use non-specific name if no specific key */
835 sprintf (key
,"%s\\%s.pem",SSL_KEY_DIRECTORY
,server
);
836 /* use cert file as fallback for key */
837 if (stat (key
,&sbuf
)) strcpy (key
,cert
);
841 if (!(stream
->context
= SSL_CTX_new (start_tls
?
842 TLS_server_method () :
843 SSLv23_server_method ())))
845 if (!(stream
->context
= SSL_CTX_new (start_tls
?
846 TLSv1_server_method () :
847 SSLv23_server_method ())))
848 #endif /* OPENSSL_1_1_0 */
849 syslog (LOG_ALERT
,"Unable to create SSL context, host=%.80s",
851 else { /* set context options */
852 SSL_CTX_set_options (stream
->context
,SSL_OP_ALL
);
853 /* set cipher list */
854 if (!SSL_CTX_set_cipher_list (stream
->context
,SSLCIPHERLIST
))
855 syslog (LOG_ALERT
,"Unable to set cipher list %.80s, host=%.80s",
856 SSLCIPHERLIST
,tcp_clienthost ());
857 /* load certificate */
858 else if (!SSL_CTX_use_certificate_chain_file (stream
->context
,cert
))
859 syslog (LOG_ALERT
,"Unable to load certificate from %.80s, host=%.80s",
860 cert
,tcp_clienthost ());
862 else if (!(SSL_CTX_use_RSAPrivateKey_file (stream
->context
,key
,
864 syslog (LOG_ALERT
,"Unable to load private key from %.80s, host=%.80s",
865 key
,tcp_clienthost ());
867 else { /* generate key if needed */
870 ssl_genkey(stream
->context
, 0, 0);
872 if (SSL_CTX_need_tmp_RSA (stream
->context
))
873 SSL_CTX_set_tmp_rsa_callback (stream
->context
,ssl_genkey
);
874 #endif /* OPENSSL_1_1_0 */
875 /* create new SSL connection */
876 if (!(stream
->con
= SSL_new (stream
->context
)))
877 syslog (LOG_ALERT
,"Unable to create SSL connection, host=%.80s",
879 else { /* set file descriptor */
880 SSL_set_fd (stream
->con
,0);
881 /* all OK if accepted */
882 if (SSL_accept (stream
->con
) < 0)
883 syslog (LOG_INFO
,"Unable to accept SSL connection, host=%.80s",
885 else { /* server set up */
886 sslstdio
= (SSLSTDIOSTREAM
*)
887 memset (fs_get (sizeof(SSLSTDIOSTREAM
)),0,sizeof (SSLSTDIOSTREAM
));
888 sslstdio
->sslstream
= stream
;
889 /* available space in output buffer */
890 sslstdio
->octr
= SSLBUFLEN
;
891 /* current output buffer pointer */
892 sslstdio
->optr
= sslstdio
->obuf
;
893 /* allow plaintext if disable value was 2 */
894 if ((long) mail_parameters (NIL
,GET_DISABLEPLAINTEXT
,NIL
) > 1)
895 mail_parameters (NIL
,SET_DISABLEPLAINTEXT
,NIL
);
896 /* unhide PLAIN SASL authenticator */
897 mail_parameters (NIL
,UNHIDE_AUTHENTICATOR
,"PLAIN");
898 mail_parameters (NIL
,UNHIDE_AUTHENTICATOR
,"LOGIN");
904 while ((i
= ERR_get_error ()) != 0L) /* SSL failure */
905 syslog (LOG_ERR
,"SSL error status: %.80s",ERR_error_string (i
,NIL
));
906 ssl_close (stream
); /* punt stream */
907 exit (1); /* punt this program too */
910 /* Generate one-time key for server
911 * Accepts: SSL connection
914 * Returns: generated key, always
917 static RSA
*ssl_genkey (SSL_CTX_TYPE
*con
,int export
,int keylength
)
920 static RSA
*key
= NIL
;
921 if (!key
) { /* if don't have a key already */
924 BIGNUM
*e
= BN_new();
925 if (!RSA_generate_key_ex (key
, export
? keylength
: 1024, e
,NIL
)) {
927 if (!(key
= RSA_generate_key (export
? keylength
: 1024,RSA_F4
,NIL
,NIL
))) {
928 #endif /* OPENSSL_1_1_0 */
929 syslog (LOG_ALERT
,"Unable to generate temp key, host=%.80s",
931 while ((i
= ERR_get_error ()) != 0L)
932 syslog (LOG_ALERT
,"SSL error status: %s",ERR_error_string (i
,NIL
));
938 #endif /* OPENSSL_1_1_0 */
943 /* Wait for stdin input
944 * Accepts: timeout in seconds
945 * Returns: T if have input on stdin, else NIL
948 long ssl_server_input_wait (long seconds
)
954 if (!sslstdio
) return server_input_wait (seconds
);
955 /* input available in buffer */
956 if (((stream
= sslstdio
->sslstream
)->ictr
> 0) ||
957 !stream
->con
|| ((sock
= SSL_get_fd (stream
->con
)) < 0)) return LONGT
;
958 /* sock ought to be 0 always */
959 if (sock
>= FD_SETSIZE
) fatal ("unselectable socket in ssl_getdata()");
960 /* input available from SSL */
961 if (SSL_pending (stream
->con
) &&
962 ((i
= SSL_read (stream
->con
,stream
->ibuf
,SSLBUFLEN
)) > 0)) {
963 stream
->iptr
= stream
->ibuf
;/* point at TCP buffer */
964 stream
->ictr
= i
; /* set new byte count */
967 FD_ZERO (&fds
); /* initialize selection vector */
968 FD_ZERO (&efd
); /* initialize selection vector */
969 FD_SET (sock
,&fds
); /* set bit in selection vector */
970 FD_SET (sock
,&efd
); /* set bit in selection vector */
971 tmo
.tv_sec
= seconds
; tmo
.tv_usec
= 0;
972 /* see if input available from the socket */
973 return select (sock
+1,&fds
,0,&efd
,&tmo
) ? LONGT
: NIL
;
976 #include "sslstdio.c"
977 #else /* ENABLE_WINDOWS_LIBRESSL */
978 #define SECURITY_WIN32
980 #include <schannel.h>
983 #define SSLBUFLEN 8192
988 typedef struct ssl_stream
{
989 TCPSTREAM
*tcpstream
; /* TCP stream */
990 CredHandle cred
; /* SSL credentials */
991 CtxtHandle context
; /* SSL context */
992 /* stream encryption sizes */
993 SecPkgContext_StreamSizes sizes
;
995 int ictr
; /* input counter */
996 char *iptr
; /* input pointer */
997 int iextractr
; /* extra input counter */
998 char *iextraptr
; /* extra input pointer */
999 char *ibuf
; /* input buffer */
1000 char *obuf
; /* output buffer */
1006 /* Function prototypes */
1008 static SSLSTREAM
*ssl_start(TCPSTREAM
*tstream
,char *host
,unsigned long flags
);
1009 static char *ssl_analyze_status (SECURITY_STATUS err
,char *buf
);
1010 static char *ssl_getline_work (SSLSTREAM
*stream
,unsigned long *size
,
1012 static long ssl_abort (SSLSTREAM
*stream
);
1014 /* Secure Sockets Layer network driver dispatch */
1016 static struct ssl_driver ssldriver
= {
1017 ssl_open
, /* open connection */
1018 ssl_aopen
, /* open preauthenticated connection */
1019 ssl_getline
, /* get a line */
1020 ssl_getbuffer
, /* get a buffer */
1021 ssl_soutr
, /* output pushed data */
1022 ssl_sout
, /* output string */
1023 ssl_close
, /* close connection */
1024 ssl_host
, /* return host name */
1025 ssl_remotehost
, /* return remote host name */
1026 ssl_port
, /* return port number */
1027 ssl_localhost
/* return local host name */
1030 /* security function table */
1031 static SecurityFunctionTable
*sft
= NIL
;
1032 static unsigned long ssltsz
= 0;/* SSL maximum token length */
1035 /* Define crypt32.dll stuff here in case a pre-IE5 Win9x system */
1037 typedef DWORD (CALLBACK
*CNTS
) (DWORD
,PCERT_NAME_BLOB
,DWORD
,LPSTR
,DWORD
);
1038 typedef BOOL (CALLBACK
*CGCC
) (HCERTCHAINENGINE
,PCCERT_CONTEXT
,LPFILETIME
,
1039 HCERTSTORE
,PCERT_CHAIN_PARA
,DWORD
,LPVOID
,
1040 PCCERT_CHAIN_CONTEXT
*);
1041 typedef BOOL (CALLBACK
*CVCCP
) (LPCSTR
,PCCERT_CHAIN_CONTEXT
,
1042 PCERT_CHAIN_POLICY_PARA
,
1043 PCERT_CHAIN_POLICY_STATUS
);
1044 typedef VOID (CALLBACK
*CFCC
) (PCCERT_CHAIN_CONTEXT
);
1045 typedef BOOL (CALLBACK
*CFCCX
) (PCCERT_CONTEXT
);
1047 static CNTS certNameToStr
= NIL
;
1048 static CGCC certGetCertificateChain
= NIL
;
1049 static CVCCP certVerifyCertificateChainPolicy
= NIL
;
1050 static CFCC certFreeCertificateChain
= NIL
;
1051 static CFCCX certFreeCertificateContext
= NIL
;
1053 /* One-time SSL initialization */
1055 static int sslonceonly
= 0;
1057 void ssl_onceonlyinit (void)
1059 if (!sslonceonly
++) { /* only need to call it once */
1065 /* get security library */
1066 if (((lib
= LoadLibrary ("schannel.dll")) ||
1067 (lib
= LoadLibrary ("security.dll"))) &&
1068 (pi
= GetProcAddress (lib
,SECURITY_ENTRYPOINT
)) &&
1069 (sft
= (SecurityFunctionTable
*) pi ()) &&
1070 !(sft
->EnumerateSecurityPackages (&np
,&pp
))) {
1071 /* look for an SSL package */
1072 for (i
= 0; (i
< (int) np
); i
++) if (!strcmp (pp
[i
].Name
,UNISP_NAME
)) {
1073 /* note maximum token size and name */
1074 ssltsz
= pp
[i
].cbMaxToken
;
1075 /* apply runtime linkage */
1076 mail_parameters (NIL
,SET_SSLDRIVER
,(void *) &ssldriver
);
1077 mail_parameters (NIL
,SET_SSLSTART
,(void *) ssl_start
);
1078 if ((lib
= LoadLibrary ("crypt32.dll")) &&
1079 (certGetCertificateChain
= (CGCC
)
1080 GetProcAddress (lib
,"CertGetCertificateChain")) &&
1081 (certVerifyCertificateChainPolicy
= (CVCCP
)
1082 GetProcAddress (lib
,"CertVerifyCertificateChainPolicy")) &&
1083 (certFreeCertificateChain
= (CFCC
)
1084 GetProcAddress (lib
,"CertFreeCertificateChain")) &&
1085 (certFreeCertificateContext
= (CFCCX
)
1086 GetProcAddress (lib
,"CertFreeCertificateContext")))
1087 certNameToStr
= (CNTS
) GetProcAddress (lib
,"CertNameToStrA");
1088 return; /* all done */
1095 * Accepts: host name
1096 * contact service name
1097 * contact port number
1098 * Returns: SSL stream if success else NIL
1101 SSLSTREAM
*ssl_open (char *host
,char *service
,unsigned long port
)
1103 TCPSTREAM
*stream
= tcp_open (host
,service
,port
);
1104 return stream
? ssl_start (stream
,host
,port
) : NIL
;
1108 /* SSL authenticated open
1109 * Accepts: host name
1111 * returned user name buffer
1112 * Returns: SSL stream if success else NIL
1115 SSLSTREAM
*ssl_aopen (NETMBX
*mb
,char *service
,char *usrbuf
)
1117 return NIL
; /* don't use this mechanism with SSL */
1120 /* Start SSL/TLS negotiations
1121 * Accepts: open TCP stream of session
1124 * Returns: SSL stream if success else NIL
1127 static SSLSTREAM
*ssl_start (TCPSTREAM
*tstream
,char *host
,unsigned long flags
)
1132 SecBuffer ibuf
[2],obuf
[1];
1133 SecBufferDesc ibufs
,obufs
;
1134 SCHANNEL_CRED tlscred
;
1135 CERT_CONTEXT
*cert
= NIL
;
1136 CERT_CHAIN_PARA chparam
;
1137 CERT_CHAIN_CONTEXT
*chain
;
1138 SSL_EXTRA_CERT_CHAIN_POLICY_PARA policy
;
1139 CERT_CHAIN_POLICY_PARA polparam
;
1140 CERT_CHAIN_POLICY_STATUS status
;
1141 char tmp
[MAILTMPLEN
],certname
[256];
1143 ULONG req
= ISC_REQ_REPLAY_DETECT
| ISC_REQ_SEQUENCE_DETECT
|
1144 ISC_REQ_CONFIDENTIALITY
| ISC_REQ_USE_SESSION_KEY
|
1145 ISC_REQ_ALLOCATE_MEMORY
| ISC_REQ_STREAM
| ISC_REQ_EXTENDED_ERROR
|
1146 ISC_REQ_MANUAL_CRED_VALIDATION
;
1148 szOID_PKIX_KP_SERVER_AUTH
,
1149 szOID_SERVER_GATED_CRYPTO
,
1153 char *buf
= (char *) fs_get (ssltsz
);
1154 unsigned long size
= 0;
1155 sslcertificatequery_t scq
=
1156 (sslcertificatequery_t
) mail_parameters (NIL
,GET_SSLCERTIFICATEQUERY
,NIL
);
1157 sslfailure_t sf
= (sslfailure_t
) mail_parameters (NIL
,GET_SSLFAILURE
,NIL
);
1158 SSLSTREAM
*stream
= (SSLSTREAM
*) memset (fs_get (sizeof (SSLSTREAM
)),0,
1159 sizeof (SSLSTREAM
));
1160 stream
->tcpstream
= tstream
; /* bind TCP stream */
1161 /* initialize TLS credential */
1162 memset (&tlscred
,0,sizeof (SCHANNEL_CRED
));
1163 tlscred
.dwVersion
= SCHANNEL_CRED_VERSION
;
1164 tlscred
.grbitEnabledProtocols
= SP_PROT_TLS1
;
1166 /* acquire credentials */
1167 if (sft
->AcquireCredentialsHandle
1168 (NIL
,UNISP_NAME
,SECPKG_CRED_OUTBOUND
,NIL
,(flags
& NET_TLSCLIENT
) ?
1169 &tlscred
: NIL
,NIL
,NIL
,&stream
->cred
,&t
)
1170 != SEC_E_OK
) reason
= "Acquire credentials handle failed";
1171 else while (!reason
) { /* negotiate security context */
1172 /* initialize buffers */
1173 ibuf
[0].cbBuffer
= size
; ibuf
[0].pvBuffer
= buf
;
1174 ibuf
[1].cbBuffer
= 0; ibuf
[1].pvBuffer
= NIL
;
1175 obuf
[0].cbBuffer
= 0; obuf
[0].pvBuffer
= NIL
;
1176 ibuf
[0].BufferType
= obuf
[0].BufferType
= SECBUFFER_TOKEN
;
1177 ibuf
[1].BufferType
= SECBUFFER_EMPTY
;
1178 /* initialize buffer descriptors */
1179 ibufs
.ulVersion
= obufs
.ulVersion
= SECBUFFER_VERSION
;
1180 ibufs
.cBuffers
= 2; obufs
.cBuffers
= 1;
1181 ibufs
.pBuffers
= ibuf
; obufs
.pBuffers
= obuf
;
1182 /* negotiate security */
1183 e
= sft
->InitializeSecurityContext
1184 (&stream
->cred
,size
? &stream
->context
: NIL
,host
,req
,0,
1185 SECURITY_NETWORK_DREP
,size
? &ibufs
:NIL
,0,&stream
->context
,&obufs
,&a
,&t
);
1186 /* have an output buffer we need to send? */
1187 if (obuf
[0].pvBuffer
&& obuf
[0].cbBuffer
) {
1188 if (!tcp_sout (stream
->tcpstream
,obuf
[0].pvBuffer
,obuf
[0].cbBuffer
))
1189 reason
= "Unexpected TCP output disconnect";
1190 /* free the buffer */
1191 sft
->FreeContextBuffer (obuf
[0].pvBuffer
);
1193 if (!reason
) switch (e
) { /* negotiation state */
1194 case SEC_I_INCOMPLETE_CREDENTIALS
:
1195 break; /* server wants client auth */
1196 case SEC_I_CONTINUE_NEEDED
:
1197 if (size
) { /* continue, read any data? */
1198 /* yes, anything regurgiated back to us? */
1199 if (ibuf
[1].BufferType
== SECBUFFER_EXTRA
) {
1200 /* yes, set this as the new data */
1201 memmove (buf
,buf
+ size
- ibuf
[1].cbBuffer
,ibuf
[1].cbBuffer
);
1202 size
= ibuf
[1].cbBuffer
;
1205 size
= 0; /* otherwise, read more stuff from server */
1207 case SEC_E_INCOMPLETE_MESSAGE
:
1208 /* need to read more data from server */
1209 if (!tcp_getdata (stream
->tcpstream
))
1210 reason
= "Unexpected TCP input disconnect";
1212 memcpy (buf
+size
,stream
->tcpstream
->iptr
,stream
->tcpstream
->ictr
);
1213 size
+= stream
->tcpstream
->ictr
;
1214 /* empty it from TCP's buffers */
1215 stream
->tcpstream
->iptr
+= stream
->tcpstream
->ictr
;
1216 stream
->tcpstream
->ictr
= 0;
1220 case SEC_E_OK
: /* success, any data to be regurgitated? */
1221 if (ibuf
[1].BufferType
== SECBUFFER_EXTRA
) {
1222 /* yes, set this as the new data */
1223 memmove (stream
->tcpstream
->iptr
= stream
->tcpstream
->ibuf
,
1224 buf
+ size
- ibuf
[1].cbBuffer
,ibuf
[1].cbBuffer
);
1225 stream
->tcpstream
->ictr
= ibuf
[1].cbBuffer
;
1227 if (certNameToStr
&& !(flags
& NET_NOVALIDATECERT
)) {
1228 /* need validation, make wchar of host */
1229 if (!((size
= MultiByteToWideChar (CP_ACP
,0,host
,-1,NIL
,0)) &&
1230 (whost
= (PWSTR
) fs_get (size
*sizeof (WCHAR
))) &&
1231 MultiByteToWideChar (CP_ACP
,0,host
,-1,whost
,size
)))
1232 fatal ("Can't make wchar of host name!");
1233 /* get certificate */
1234 if ((sft
->QueryContextAttributes
1235 (&stream
->context
,SECPKG_ATTR_REMOTE_CERT_CONTEXT
,&cert
) !=
1236 SEC_E_OK
) || !cert
) {
1237 reason
= "*Unable to get certificate";
1238 strcpy (certname
,"<no certificate>");
1240 else { /* get certificate subject name */
1241 (*certNameToStr
) (X509_ASN_ENCODING
| PKCS_7_ASN_ENCODING
,
1242 &cert
->pCertInfo
->Subject
,CERT_X500_NAME_STR
,
1244 /* build certificate chain */
1245 memset (&chparam
,0,sizeof (chparam
));
1246 chparam
.cbSize
= sizeof (chparam
);
1247 chparam
.RequestedUsage
.dwType
= USAGE_MATCH_TYPE_OR
;
1248 chparam
.RequestedUsage
.Usage
.rgpszUsageIdentifier
= usage
;
1249 chparam
.RequestedUsage
.Usage
.cUsageIdentifier
=
1250 sizeof (usage
) / sizeof (LPSTR
);
1251 if (!(*certGetCertificateChain
)
1252 (NIL
,cert
,NIL
,cert
->hCertStore
,&chparam
,NIL
,NIL
,&chain
))
1253 reason
= ssl_analyze_status (GetLastError (),tmp
);
1254 else { /* validate certificate chain */
1255 memset (&policy
,0,sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA
));
1256 policy
.cbStruct
= sizeof (SSL_EXTRA_CERT_CHAIN_POLICY_PARA
);
1257 policy
.dwAuthType
= AUTHTYPE_SERVER
;
1258 policy
.fdwChecks
= NIL
;
1259 policy
.pwszServerName
= whost
;
1260 memset (&polparam
,0,sizeof (polparam
));
1261 polparam
.cbSize
= sizeof (polparam
);
1262 polparam
.pvExtraPolicyPara
= &policy
;
1263 memset (&status
,0,sizeof (status
));
1264 status
.cbSize
= sizeof (status
);
1265 if (!(*certVerifyCertificateChainPolicy
)
1266 (CERT_CHAIN_POLICY_SSL
,chain
,&polparam
,&status
))
1267 reason
= ssl_analyze_status (GetLastError (),tmp
);
1268 else if (status
.dwError
)
1269 reason
= ssl_analyze_status (status
.dwError
,tmp
);
1270 (*certFreeCertificateChain
) (chain
);
1272 (*certFreeCertificateContext
) (cert
);
1274 if (whost
) fs_give ((void **) &whost
);
1276 if (reason
) { /* got an error? */
1277 /* application callback */
1278 if (scq
) reason
= (*scq
) ((*reason
== '*') ? reason
+ 1 : reason
,
1279 host
,certname
) ? NIL
: "";
1280 else if (*certname
) { /* error message to return via mm_log() */
1281 sprintf (buf
,"*%.128s: %.255s",
1282 (*reason
== '*') ? reason
+ 1 : reason
,certname
);
1288 (reason
= ssl_analyze_status
1289 (sft
->QueryContextAttributes
1290 (&stream
->context
,SECPKG_ATTR_STREAM_SIZES
,&stream
->sizes
),buf
)))
1291 break; /* error in certificate or getting sizes */
1292 fs_give ((void **) &buf
); /* flush temporary buffer */
1293 /* make maximum-sized buffers */
1294 stream
->bufsize
= stream
->sizes
.cbHeader
+
1295 stream
->sizes
.cbMaximumMessage
+ stream
->sizes
.cbTrailer
;
1296 if (stream
->sizes
.cbMaximumMessage
< SSLBUFLEN
)
1297 fatal ("cbMaximumMessage is less than SSLBUFLEN!");
1298 else if (stream
->sizes
.cbMaximumMessage
< 16384) {
1299 sprintf (tmp
,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384",
1300 (long) stream
->sizes
.cbMaximumMessage
);
1303 stream
->ibuf
= (char *) fs_get (stream
->bufsize
);
1304 stream
->obuf
= (char *) fs_get (stream
->bufsize
);
1307 reason
= ssl_analyze_status (e
,buf
);
1310 ssl_close (stream
); /* failed to do SSL */
1311 stream
= NIL
; /* no stream returned */
1312 switch (*reason
) { /* analyze reason */
1313 case '*': /* certificate failure */
1314 ++reason
; /* skip over certificate failure indication */
1315 /* pass to error callback */
1316 if (sf
) (*sf
) (host
,reason
,flags
);
1317 else { /* no error callback, build error message */
1318 sprintf (tmp
,"Certificate failure for %.80s: %.512s",host
,reason
);
1321 case '\0': /* user answered no to certificate callback */
1322 if (flags
& NET_TRYSSL
) /* return dummy stream to stop tryssl */
1323 stream
= (SSLSTREAM
*) memset (fs_get (sizeof (SSLSTREAM
)),0,
1324 sizeof (SSLSTREAM
));
1326 default: /* non-certificate failure */
1327 if (flags
& NET_TRYSSL
); /* no error output if tryssl */
1328 /* pass to error callback */
1329 else if (sf
) (*sf
) (host
,reason
,flags
);
1330 else { /* no error callback, build error message */
1331 sprintf (tmp
,"TLS/SSL failure for %.80s: %.512s",host
,reason
);
1336 fs_give ((void **) &buf
); /* flush temporary buffer */
1340 /* Generate error text from SSL error code
1341 * Accepts: SSL status
1343 * Returns: text if error status, else NIL
1346 static char *ssl_analyze_status (SECURITY_STATUS err
,char *buf
)
1349 case SEC_E_OK
: /* no error */
1350 case SEC_I_CONTINUE_NEEDED
:
1351 case SEC_I_INCOMPLETE_CREDENTIALS
:
1352 case SEC_E_INCOMPLETE_MESSAGE
:
1354 case SEC_E_NO_AUTHENTICATING_AUTHORITY
:
1355 mm_log ("unexpected SEC_E_NO_AUTHENTICATING_AUTHORITY",NIL
);
1356 return "*No authority could be contacted for authentication";
1357 case SEC_E_WRONG_PRINCIPAL
:
1358 mm_log ("unexpected SEC_E_WRONG_PRINCIPAL",NIL
);
1359 case CERT_E_CN_NO_MATCH
:
1360 return "*Server name does not match certificate";
1361 case SEC_E_UNTRUSTED_ROOT
:
1362 mm_log ("unexpected SEC_E_UNTRUSTED_ROOT",NIL
);
1363 case CERT_E_UNTRUSTEDROOT
:
1364 return "*Self-signed certificate or untrusted authority";
1365 case SEC_E_CERT_EXPIRED
:
1366 mm_log ("unexpected SEC_E_CERT_EXPIRED",NIL
);
1367 case CERT_E_EXPIRED
:
1368 return "*Certificate has expired";
1369 case CERT_E_REVOKED
:
1370 return "*Certificate revoked";
1371 case SEC_E_INVALID_TOKEN
:
1372 return "Invalid token, probably not an SSL server";
1373 case SEC_E_UNSUPPORTED_FUNCTION
:
1374 return "SSL not supported on this machine - upgrade your system software";
1376 sprintf (buf
,"Unexpected SSPI or certificate error %lx - report this",err
);
1381 * Accepts: SSL stream
1382 * Returns: text line string or NIL if failure
1385 char *ssl_getline (SSLSTREAM
*stream
)
1387 unsigned long n
,contd
;
1388 char *ret
= ssl_getline_work (stream
,&n
,&contd
);
1389 if (ret
&& contd
) { /* got a line needing continuation? */
1390 STRINGLIST
*stl
= mail_newstringlist ();
1391 STRINGLIST
*stc
= stl
;
1392 do { /* collect additional lines */
1393 stc
->text
.data
= (unsigned char *) ret
;
1395 stc
= stc
->next
= mail_newstringlist ();
1396 ret
= ssl_getline_work (stream
,&n
,&contd
);
1397 } while (ret
&& contd
);
1398 if (ret
) { /* stash final part of line on list */
1399 stc
->text
.data
= (unsigned char *) ret
;
1401 /* determine how large a buffer we need */
1402 for (n
= 0, stc
= stl
; stc
; stc
= stc
->next
) n
+= stc
->text
.size
;
1403 ret
= fs_get (n
+ 1); /* copy parts into buffer */
1404 for (n
= 0, stc
= stl
; stc
; n
+= stc
->text
.size
, stc
= stc
->next
)
1405 memcpy (ret
+ n
,stc
->text
.data
,stc
->text
.size
);
1408 mail_free_stringlist (&stl
);/* either way, done with list */
1413 /* SSL receive line or partial line
1414 * Accepts: SSL stream
1415 * pointer to return size
1416 * pointer to return continuation flag
1417 * Returns: text line string, size and continuation flag, or NIL if failure
1420 static char *ssl_getline_work (SSLSTREAM
*stream
,unsigned long *size
,
1425 *contd
= NIL
; /* assume no continuation */
1426 /* make sure have data */
1427 if (!ssl_getdata (stream
)) return NIL
;
1428 for (s
= stream
->iptr
, n
= 0, c
= '\0'; stream
->ictr
--; n
++, c
= d
) {
1429 d
= *stream
->iptr
++; /* slurp another character */
1430 if ((c
== '\015') && (d
== '\012')) {
1431 ret
= (char *) fs_get (n
--);
1432 memcpy (ret
,s
,*size
= n
); /* copy into a free storage string */
1433 ret
[n
] = '\0'; /* tie off string with null */
1437 /* copy partial string from buffer */
1438 memcpy ((ret
= (char *) fs_get (n
)),s
,*size
= n
);
1439 /* get more data from the net */
1440 if (!ssl_getdata (stream
)) fs_give ((void **) &ret
);
1441 /* special case of newline broken by buffer */
1442 else if ((c
== '\015') && (*stream
->iptr
== '\012')) {
1443 stream
->iptr
++; /* eat the line feed */
1445 ret
[*size
= --n
] = '\0'; /* tie off string with null */
1447 else *contd
= LONGT
; /* continuation needed */
1451 /* SSL receive buffer
1452 * Accepts: SSL stream
1454 * buffer to read into
1455 * Returns: T if success, NIL otherwise
1458 long ssl_getbuffer (SSLSTREAM
*stream
,unsigned long size
,char *buffer
)
1461 while (size
> 0) { /* until request satisfied */
1462 if (!ssl_getdata (stream
)) return NIL
;
1463 n
= min (size
,stream
->ictr
);/* number of bytes to transfer */
1465 memcpy (buffer
,stream
->iptr
,n
);
1466 buffer
+= n
; /* update pointer */
1468 size
-= n
; /* update # of bytes to do */
1471 buffer
[0] = '\0'; /* tie off string */
1476 * Accepts: TCP/IP stream
1477 * Returns: T if success, NIL otherwise
1480 long ssl_getdata (SSLSTREAM
*stream
)
1482 while (stream
->ictr
< 1) { /* decrypted buffer empty? */
1483 SECURITY_STATUS status
;
1487 size_t n
= 0; /* initially no bytes to decrypt */
1488 if (!stream
->tcpstream
) return NIL
;
1489 do { /* yes, make sure have data from TCP */
1490 if (stream
->iextractr
) { /* have previous unread data? */
1491 memcpy (stream
->ibuf
+ n
,stream
->iextraptr
,stream
->iextractr
);
1492 n
+= stream
->iextractr
; /* update number of bytes read */
1493 stream
->iextractr
= 0; /* no more extra data */
1495 else { /* read from TCP */
1496 if (!tcp_getdata (stream
->tcpstream
)) return ssl_abort (stream
);
1497 /* maximum amount of data to copy */
1498 if (!(i
= min (stream
->bufsize
- n
,stream
->tcpstream
->ictr
)))
1499 fatal ("incomplete SecBuffer exceeds maximum buffer size");
1501 memcpy (stream
->ibuf
+ n
,stream
->tcpstream
->iptr
,i
);
1502 stream
->tcpstream
->iptr
+= i
;
1503 stream
->tcpstream
->ictr
-= i
;
1504 n
+= i
; /* update number of bytes to decrypt */
1506 buf
[0].cbBuffer
= n
; /* first SecBuffer gets data */
1507 buf
[0].pvBuffer
= stream
->ibuf
;
1508 buf
[0].BufferType
= SECBUFFER_DATA
;
1509 /* subsequent ones are for spares */
1510 buf
[1].BufferType
= buf
[2].BufferType
= buf
[3].BufferType
=
1512 msg
.ulVersion
= SECBUFFER_VERSION
;
1513 msg
.cBuffers
= 4; /* number of SecBuffers */
1514 msg
.pBuffers
= buf
; /* first SecBuffer */
1516 } while ((status
= ((DECRYPT_MESSAGE_FN
) sft
->Reserved4
)
1517 (&stream
->context
,&msg
,0,NIL
)) == SEC_E_INCOMPLETE_MESSAGE
);
1519 case SEC_E_OK
: /* won */
1520 case SEC_I_RENEGOTIATE
: /* won but lost it after this buffer */
1521 /* hunt for a buffer */
1522 for (i
= 0; (i
< 4) && (buf
[i
].BufferType
!= SECBUFFER_DATA
) ; i
++);
1523 if (i
< 4) { /* found a buffer? */
1524 /* yes, set up pointer and counter */
1525 stream
->iptr
= buf
[i
].pvBuffer
;
1526 stream
->ictr
= buf
[i
].cbBuffer
;
1527 /* any unprocessed data? */
1528 while (++i
< 4) if (buf
[i
].BufferType
== SECBUFFER_EXTRA
) {
1529 /* yes, note for next time around */
1530 stream
->iextraptr
= buf
[i
].pvBuffer
;
1531 stream
->iextractr
= buf
[i
].cbBuffer
;
1535 default: /* anything else means we've lost */
1536 return ssl_abort (stream
);
1542 /* SSL send string as record
1543 * Accepts: SSL stream
1545 * Returns: T if success else NIL
1548 long ssl_soutr (SSLSTREAM
*stream
,char *string
)
1550 return ssl_sout (stream
,string
,(unsigned long) strlen (string
));
1555 * Accepts: SSL stream
1558 * Returns: T if success else NIL
1561 long ssl_sout (SSLSTREAM
*stream
,char *string
,unsigned long size
)
1567 if (!stream
->tcpstream
) return NIL
;
1568 /* until request satisfied */
1569 for (s
= stream
->ibuf
,n
= 0; size
;) {
1571 buf
[0].BufferType
= SECBUFFER_STREAM_HEADER
;
1572 memset (buf
[0].pvBuffer
= stream
->obuf
,0,
1573 buf
[0].cbBuffer
= stream
->sizes
.cbHeader
);
1574 /* message (up to maximum size) */
1575 buf
[1].BufferType
= SECBUFFER_DATA
;
1576 memcpy (buf
[1].pvBuffer
= stream
->obuf
+ stream
->sizes
.cbHeader
,string
,
1577 buf
[1].cbBuffer
= min (size
,SSLBUFLEN
));
1579 buf
[2].BufferType
= SECBUFFER_STREAM_TRAILER
;
1580 memset (buf
[2].pvBuffer
= ((char *) buf
[1].pvBuffer
) + buf
[1].cbBuffer
,0,
1581 buf
[2].cbBuffer
= stream
->sizes
.cbTrailer
);
1583 buf
[3].BufferType
= SECBUFFER_EMPTY
;
1584 msg
.ulVersion
= SECBUFFER_VERSION
;
1585 msg
.cBuffers
= 4; /* number of SecBuffers */
1586 msg
.pBuffers
= buf
; /* first SecBuffer */
1587 string
+= buf
[1].cbBuffer
;
1588 size
-= buf
[1].cbBuffer
; /* this many bytes processed */
1589 /* encrypt and send message */
1590 if ((((ENCRYPT_MESSAGE_FN
) sft
->Reserved3
)
1591 (&stream
->context
,0,&msg
,NIL
) != SEC_E_OK
) ||
1592 !tcp_sout (stream
->tcpstream
,stream
->obuf
,
1593 buf
[0].cbBuffer
+ buf
[1].cbBuffer
+ buf
[2].cbBuffer
))
1594 return ssl_abort (stream
);/* encryption or sending failed */
1600 * Accepts: SSL stream
1603 void ssl_close (SSLSTREAM
*stream
)
1605 ssl_abort (stream
); /* nuke the stream */
1606 fs_give ((void **) &stream
); /* flush the stream */
1611 * Accepts: SSL stream
1612 * Returns: NIL always
1615 static long ssl_abort (SSLSTREAM
*stream
)
1617 if (stream
->tcpstream
) { /* close TCP stream */
1618 sft
->DeleteSecurityContext (&stream
->context
);
1619 sft
->FreeCredentialHandle (&stream
->cred
);
1620 tcp_close (stream
->tcpstream
);
1621 stream
->tcpstream
= NIL
;
1623 if (stream
->ibuf
) fs_give ((void **) &stream
->ibuf
);
1624 if (stream
->obuf
) fs_give ((void **) &stream
->obuf
);
1628 /* SSL get host name
1629 * Accepts: SSL stream
1630 * Returns: host name for this stream
1633 char *ssl_host (SSLSTREAM
*stream
)
1635 return stream
? tcp_host (stream
->tcpstream
) : "UNKNOWN";
1639 /* SSL get remote host name
1640 * Accepts: SSL stream
1641 * Returns: host name for this stream
1644 char *ssl_remotehost (SSLSTREAM
*stream
)
1646 return tcp_remotehost (stream
->tcpstream
);
1650 /* SSL return port for this stream
1651 * Accepts: SSL stream
1652 * Returns: port number for this stream
1655 unsigned long ssl_port (SSLSTREAM
*stream
)
1657 return tcp_port (stream
->tcpstream
);
1661 /* SSL get local host name
1662 * Accepts: SSL stream
1663 * Returns: local host name
1666 char *ssl_localhost (SSLSTREAM
*stream
)
1668 return tcp_localhost (stream
->tcpstream
);
1671 #include "ssl_none.c" /* currently no server support */
1673 #endif /* ENABLE_WINDOWS_LIBRESSL */