diff options
Diffstat (limited to 'imap/src/osdep/nt/ssl_old.c')
-rw-r--r-- | imap/src/osdep/nt/ssl_old.c | 619 |
1 files changed, 0 insertions, 619 deletions
diff --git a/imap/src/osdep/nt/ssl_old.c b/imap/src/osdep/nt/ssl_old.c deleted file mode 100644 index 73a360d..0000000 --- a/imap/src/osdep/nt/ssl_old.c +++ /dev/null @@ -1,619 +0,0 @@ -/* ======================================================================== - * Copyright 2008-2009 Mark Crispin - * ======================================================================== - */ - -/* - * Program: SSL authentication/encryption module for Windows 9x and NT - * - * Author: Mark Crispin - * - * Date: 22 September 1998 - * Last Edited: 9 November 2009 - * - * Previous versions of this file were - * - * Copyright 1988-2008 University of Washington - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - */ - -#define SECURITY_WIN32 -#include <sspi.h> -#include <wincrypt.h> -ALGIDDEF -#include <schnlsp.h> -#include <issperr.h> - - /* in case a binary runs on Windows 2000 */ -#ifndef ISC_REQ_MANUAL_CRED_VALIDATION -#define ISC_REQ_MANUAL_CRED_VALIDATION 0x00080000 -#endif -#ifndef SEC_E_UNTRUSTED_ROOT -#define SEC_E_UNTRUSTED_ROOT ((HRESULT) 0x80090325L) -#endif -#ifndef SEC_E_CERT_EXPIRED -#define SEC_E_CERT_EXPIRED ((HRESULT) 0x80090328L) -#endif - - -#define SSLBUFLEN 8192 - - -/* SSL I/O stream */ - -typedef struct ssl_stream { - TCPSTREAM *tcpstream; /* TCP stream */ - CredHandle cred; /* SSL credentials */ - CtxtHandle context; /* SSL context */ - /* stream encryption sizes */ - SecPkgContext_StreamSizes sizes; - size_t bufsize; - int ictr; /* input counter */ - char *iptr; /* input pointer */ - int iextractr; /* extra input counter */ - char *iextraptr; /* extra input pointer */ - char *ibuf; /* input buffer */ - char *obuf; /* output buffer */ -} SSLSTREAM; - -#include "sslio.h" - - -/* Function prototypes */ - -static SSLSTREAM *ssl_start(TCPSTREAM *tstream,char *host,unsigned long flags); -static char *ssl_analyze_status (SECURITY_STATUS err,char *buf); -static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size, - long *contd); -static long ssl_abort (SSLSTREAM *stream); - -/* Secure Sockets Layer network driver dispatch */ - -static struct ssl_driver ssldriver = { - ssl_open, /* open connection */ - ssl_aopen, /* open preauthenticated connection */ - ssl_getline, /* get a line */ - ssl_getbuffer, /* get a buffer */ - ssl_soutr, /* output pushed data */ - ssl_sout, /* output string */ - ssl_close, /* close connection */ - ssl_host, /* return host name */ - ssl_remotehost, /* return remote host name */ - ssl_port, /* return port number */ - ssl_localhost /* return local host name */ -}; - - /* security function table */ -static SecurityFunctionTable *sft = NIL; -static unsigned long ssltsz = 0;/* SSL maximum token length */ - -/* One-time SSL initialization */ - -static int sslonceonly = 0; - -void ssl_onceonlyinit (void) -{ - if (!sslonceonly++) { /* only need to call it once */ - HINSTANCE lib; - FARPROC pi; - ULONG np; - SecPkgInfo *pp; - int i; - /* get security library */ - if (((lib = LoadLibrary ("schannel.dll")) || - (lib = LoadLibrary ("security.dll"))) && - (pi = GetProcAddress (lib,SECURITY_ENTRYPOINT)) && - (sft = (SecurityFunctionTable *) pi ()) && - !(sft->EnumerateSecurityPackages (&np,&pp))) { - /* look for an SSL package */ - for (i = 0; (i < (int) np); i++) if (!strcmp (pp[i].Name,UNISP_NAME)) { - /* note maximum token size and name */ - ssltsz = pp[i].cbMaxToken; - /* apply runtime linkage */ - mail_parameters (NIL,SET_SSLDRIVER,(void *) &ssldriver); - mail_parameters (NIL,SET_SSLSTART,(void *) ssl_start); - return; /* all done */ - } - } - } -} - -/* SSL open - * Accepts: host name - * contact service name - * contact port number - * Returns: SSL stream if success else NIL - */ - -SSLSTREAM *ssl_open (char *host,char *service,unsigned long port) -{ - TCPSTREAM *stream = tcp_open (host,service,port); - return stream ? ssl_start (stream,host,port) : NIL; -} - - -/* SSL authenticated open - * Accepts: host name - * service name - * returned user name buffer - * Returns: SSL stream if success else NIL - */ - -SSLSTREAM *ssl_aopen (NETMBX *mb,char *service,char *usrbuf) -{ - return NIL; /* don't use this mechanism with SSL */ -} - -/* Start SSL/TLS negotiations - * Accepts: open TCP stream of session - * user's host name - * flags - * Returns: SSL stream if success else NIL - */ - -static SSLSTREAM *ssl_start (TCPSTREAM *tstream,char *host,unsigned long flags) -{ - SECURITY_STATUS e; - ULONG a; - TimeStamp t; - SecBuffer ibuf[2],obuf[1]; - SecBufferDesc ibufs,obufs; - char tmp[MAILTMPLEN]; - char *reason = NIL; - ULONG req = ISC_REQ_REPLAY_DETECT | ISC_REQ_SEQUENCE_DETECT | - ISC_REQ_CONFIDENTIALITY | ISC_REQ_USE_SESSION_KEY | - ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM | ISC_REQ_EXTENDED_ERROR + - ((flags & NET_NOVALIDATECERT) ? ISC_REQ_MANUAL_CRED_VALIDATION : - ISC_REQ_MUTUAL_AUTH); - SCHANNEL_CRED tlscred; - char *buf = (char *) fs_get (ssltsz); - unsigned long size = 0; - sslfailure_t sf = (sslfailure_t) mail_parameters (NIL,GET_SSLFAILURE,NIL); - SSLSTREAM *stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, - sizeof (SSLSTREAM)); - stream->tcpstream = tstream; /* bind TCP stream */ - /* initialize TLS credential */ - memset (&tlscred,0,sizeof (SCHANNEL_CRED)); - tlscred.dwVersion = SCHANNEL_CRED_VERSION; - tlscred.grbitEnabledProtocols = SP_PROT_TLS1; - - /* acquire credentials */ - if (sft->AcquireCredentialsHandle - (NIL,UNISP_NAME,SECPKG_CRED_OUTBOUND,NIL,(flags & NET_TLSCLIENT) ? - &tlscred : NIL,NIL,NIL,&stream->cred,&t) - != SEC_E_OK) reason = "Acquire credentials handle failed"; - else while (!reason) { /* negotiate security context */ - /* initialize buffers */ - ibuf[0].cbBuffer = size; ibuf[0].pvBuffer = buf; - ibuf[1].cbBuffer = 0; ibuf[1].pvBuffer = NIL; - obuf[0].cbBuffer = 0; obuf[0].pvBuffer = NIL; - ibuf[0].BufferType = obuf[0].BufferType = SECBUFFER_TOKEN; - ibuf[1].BufferType = SECBUFFER_EMPTY; - /* initialize buffer descriptors */ - ibufs.ulVersion = obufs.ulVersion = SECBUFFER_VERSION; - ibufs.cBuffers = 2; obufs.cBuffers = 1; - ibufs.pBuffers = ibuf; obufs.pBuffers = obuf; - /* negotiate security */ - e = sft->InitializeSecurityContext - (&stream->cred,size ? &stream->context : NIL,host,req,0, - SECURITY_NETWORK_DREP,size? &ibufs:NIL,0,&stream->context,&obufs,&a,&t); - /* have an output buffer we need to send? */ - if (obuf[0].pvBuffer && obuf[0].cbBuffer) { - if (!tcp_sout (stream->tcpstream,obuf[0].pvBuffer,obuf[0].cbBuffer)) - reason = "Unexpected TCP output disconnect"; - /* free the buffer */ - sft->FreeContextBuffer (obuf[0].pvBuffer); - } - if (!reason) switch (e) { /* negotiation state */ - case SEC_I_INCOMPLETE_CREDENTIALS: - break; /* server wants client auth */ - case SEC_I_CONTINUE_NEEDED: - if (size) { /* continue, read any data? */ - /* yes, anything regurgiated back to us? */ - if (ibuf[1].BufferType == SECBUFFER_EXTRA) { - /* yes, set this as the new data */ - memmove (buf,buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); - size = ibuf[1].cbBuffer; - break; - } - size = 0; /* otherwise, read more stuff from server */ - } - case SEC_E_INCOMPLETE_MESSAGE: - /* need to read more data from server */ - if (!tcp_getdata (stream->tcpstream)) - reason = "Unexpected TCP input disconnect"; - else { - memcpy (buf+size,stream->tcpstream->iptr,stream->tcpstream->ictr); - size += stream->tcpstream->ictr; - /* empty it from TCP's buffers */ - stream->tcpstream->iptr += stream->tcpstream->ictr; - stream->tcpstream->ictr = 0; - } - break; - - case SEC_E_OK: /* success, any data to be regurgitated? */ - if (ibuf[1].BufferType == SECBUFFER_EXTRA) { - /* yes, set this as the new data */ - memmove (stream->tcpstream->iptr = stream->tcpstream->ibuf, - buf + size - ibuf[1].cbBuffer,ibuf[1].cbBuffer); - stream->tcpstream->ictr = ibuf[1].cbBuffer; - } - if (reason = ssl_analyze_status - (sft->QueryContextAttributes - (&stream->context,SECPKG_ATTR_STREAM_SIZES,&stream->sizes),buf)) - break; /* error getting sizes */ - fs_give ((void **) &buf); /* flush temporary buffer */ - /* make maximum-sized buffers */ - stream->bufsize = stream->sizes.cbHeader + - stream->sizes.cbMaximumMessage + stream->sizes.cbTrailer; - if (stream->sizes.cbMaximumMessage < SSLBUFLEN) - fatal ("cbMaximumMessage is less than SSLBUFLEN!"); - else if (stream->sizes.cbMaximumMessage < 16384) { - sprintf (tmp,"WINDOWS BUG: cbMaximumMessage = %ld, should be 16384", - (long) stream->sizes.cbMaximumMessage); - mm_log (tmp,NIL); - } - stream->ibuf = (char *) fs_get (stream->bufsize); - stream->obuf = (char *) fs_get (stream->bufsize); - return stream; - default: - reason = ssl_analyze_status (e,buf); - } - } - ssl_close (stream); /* failed to do SSL */ - stream = NIL; /* no stream returned */ - fs_give ((void **) &buf); /* flush temporary buffer */ - switch (*reason) { /* analyze reason */ - case '*': /* certificate failure */ - ++reason; /* skip over certificate failure indication */ - /* pass to error callback */ - if (sf) (*sf) (host,reason,flags); - else { /* no error callback, build error message */ - sprintf (tmp,"Certificate failure for %.80s: %.512s",host,reason); - mm_log (tmp,ERROR); - } - case '\0': /* user answered no to certificate callback */ - if (flags & NET_TRYSSL) /* return dummy stream to stop tryssl */ - stream = (SSLSTREAM *) memset (fs_get (sizeof (SSLSTREAM)),0, - sizeof (SSLSTREAM)); - break; - default: /* non-certificate failure */ - if (flags & NET_TRYSSL); /* no error output if tryssl */ - /* pass to error callback */ - else if (sf) (*sf) (host,reason,flags); - else { /* no error callback, build error message */ - sprintf (tmp,"TLS/SSL failure for %.80s: %.512s",host,reason); - mm_log (tmp,ERROR); - } - break; - } - return stream; -} - -/* Generate error text from SSL error code - * Accepts: SSL status - * scratch buffer - * Returns: text if error status, else NIL - */ - -static char *ssl_analyze_status (SECURITY_STATUS err,char *buf) -{ - switch (err) { - case SEC_E_OK: /* no error */ - case SEC_I_CONTINUE_NEEDED: - case SEC_I_INCOMPLETE_CREDENTIALS: - case SEC_E_INCOMPLETE_MESSAGE: - return NIL; - case SEC_E_NO_AUTHENTICATING_AUTHORITY: - return "*No authority could be contacted for authentication"; - case SEC_E_WRONG_PRINCIPAL: - return "*Server name does not match certificate"; - case SEC_E_UNTRUSTED_ROOT: - return "*Self-signed certificate or untrusted authority"; - case SEC_E_CERT_EXPIRED: - return "*Certificate has expired"; - case SEC_E_INVALID_TOKEN: - return "Invalid token, probably not an SSL server"; - case SEC_E_UNSUPPORTED_FUNCTION: - return "SSL not supported on this machine - upgrade your system software"; - } - sprintf (buf,"Unexpected SChannel error %lx - report this",err); - return buf; -} - -/* SSL receive line - * Accepts: SSL stream - * Returns: text line string or NIL if failure - */ - -char *ssl_getline (SSLSTREAM *stream) -{ - unsigned long n,contd; - char *ret = ssl_getline_work (stream,&n,&contd); - if (ret && contd) { /* got a line needing continuation? */ - STRINGLIST *stl = mail_newstringlist (); - STRINGLIST *stc = stl; - do { /* collect additional lines */ - stc->text.data = (unsigned char *) ret; - stc->text.size = n; - stc = stc->next = mail_newstringlist (); - ret = ssl_getline_work (stream,&n,&contd); - } while (ret && contd); - if (ret) { /* stash final part of line on list */ - stc->text.data = (unsigned char *) ret; - stc->text.size = n; - /* determine how large a buffer we need */ - for (n = 0, stc = stl; stc; stc = stc->next) n += stc->text.size; - ret = fs_get (n + 1); /* copy parts into buffer */ - for (n = 0, stc = stl; stc; n += stc->text.size, stc = stc->next) - memcpy (ret + n,stc->text.data,stc->text.size); - ret[n] = '\0'; - } - mail_free_stringlist (&stl);/* either way, done with list */ - } - return ret; -} - -/* SSL receive line or partial line - * Accepts: SSL stream - * pointer to return size - * pointer to return continuation flag - * Returns: text line string, size and continuation flag, or NIL if failure - */ - -static char *ssl_getline_work (SSLSTREAM *stream,unsigned long *size, - long *contd) -{ - unsigned long n; - char *s,*ret,c,d; - *contd = NIL; /* assume no continuation */ - /* make sure have data */ - if (!ssl_getdata (stream)) return NIL; - for (s = stream->iptr, n = 0, c = '\0'; stream->ictr--; n++, c = d) { - d = *stream->iptr++; /* slurp another character */ - if ((c == '\015') && (d == '\012')) { - ret = (char *) fs_get (n--); - memcpy (ret,s,*size = n); /* copy into a free storage string */ - ret[n] = '\0'; /* tie off string with null */ - return ret; - } - } - /* copy partial string from buffer */ - memcpy ((ret = (char *) fs_get (n)),s,*size = n); - /* get more data from the net */ - if (!ssl_getdata (stream)) fs_give ((void **) &ret); - /* special case of newline broken by buffer */ - else if ((c == '\015') && (*stream->iptr == '\012')) { - stream->iptr++; /* eat the line feed */ - stream->ictr--; - ret[*size = --n] = '\0'; /* tie off string with null */ - } - else *contd = LONGT; /* continuation needed */ - return ret; -} - -/* SSL receive buffer - * Accepts: SSL stream - * size in bytes - * buffer to read into - * Returns: T if success, NIL otherwise - */ - -long ssl_getbuffer (SSLSTREAM *stream,unsigned long size,char *buffer) -{ - unsigned long n; - while (size > 0) { /* until request satisfied */ - if (!ssl_getdata (stream)) return NIL; - n = min (size,stream->ictr);/* number of bytes to transfer */ - /* do the copy */ - memcpy (buffer,stream->iptr,n); - buffer += n; /* update pointer */ - stream->iptr += n; - size -= n; /* update # of bytes to do */ - stream->ictr -= n; - } - buffer[0] = '\0'; /* tie off string */ - return T; -} - -/* SSL receive data - * Accepts: TCP/IP stream - * Returns: T if success, NIL otherwise - */ - -long ssl_getdata (SSLSTREAM *stream) -{ - while (stream->ictr < 1) { /* decrypted buffer empty? */ - SECURITY_STATUS status; - SecBuffer buf[4]; - SecBufferDesc msg; - size_t i; - size_t n = 0; /* initially no bytes to decrypt */ - if (!stream->tcpstream) return NIL; - do { /* yes, make sure have data from TCP */ - if (stream->iextractr) { /* have previous unread data? */ - memcpy (stream->ibuf + n,stream->iextraptr,stream->iextractr); - n += stream->iextractr; /* update number of bytes read */ - stream->iextractr = 0; /* no more extra data */ - } - else { /* read from TCP */ - if (!tcp_getdata (stream->tcpstream)) return ssl_abort (stream); - /* maximum amount of data to copy */ - if (!(i = min (stream->bufsize - n,stream->tcpstream->ictr))) - fatal ("incomplete SecBuffer exceeds maximum buffer size"); - /* do the copy */ - memcpy (stream->ibuf + n,stream->tcpstream->iptr,i); - stream->tcpstream->iptr += i; - stream->tcpstream->ictr -= i; - n += i; /* update number of bytes to decrypt */ - } - buf[0].cbBuffer = n; /* first SecBuffer gets data */ - buf[0].pvBuffer = stream->ibuf; - buf[0].BufferType = SECBUFFER_DATA; - /* subsequent ones are for spares */ - buf[1].BufferType = buf[2].BufferType = buf[3].BufferType = - SECBUFFER_EMPTY; - msg.ulVersion = SECBUFFER_VERSION; - msg.cBuffers = 4; /* number of SecBuffers */ - msg.pBuffers = buf; /* first SecBuffer */ - - } while ((status = ((DECRYPT_MESSAGE_FN) sft->Reserved4) - (&stream->context,&msg,0,NIL)) == SEC_E_INCOMPLETE_MESSAGE); - switch (status) { - case SEC_E_OK: /* won */ - case SEC_I_RENEGOTIATE: /* won but lost it after this buffer */ - /* hunt for a buffer */ - for (i = 0; (i < 4) && (buf[i].BufferType != SECBUFFER_DATA) ; i++); - if (i < 4) { /* found a buffer? */ - /* yes, set up pointer and counter */ - stream->iptr = buf[i].pvBuffer; - stream->ictr = buf[i].cbBuffer; - /* any unprocessed data? */ - while (++i < 4) if (buf[i].BufferType == SECBUFFER_EXTRA) { - /* yes, note for next time around */ - stream->iextraptr = buf[i].pvBuffer; - stream->iextractr = buf[i].cbBuffer; - } - } - break; - default: /* anything else means we've lost */ - return ssl_abort (stream); - } - } - return LONGT; -} - -/* SSL send string as record - * Accepts: SSL stream - * string pointer - * Returns: T if success else NIL - */ - -long ssl_soutr (SSLSTREAM *stream,char *string) -{ - return ssl_sout (stream,string,(unsigned long) strlen (string)); -} - - -/* SSL send string - * Accepts: SSL stream - * string pointer - * byte count - * Returns: T if success else NIL - */ - -long ssl_sout (SSLSTREAM *stream,char *string,unsigned long size) -{ - SecBuffer buf[4]; - SecBufferDesc msg; - char *s = stream->ibuf; - size_t n = 0; - while (size) { /* until satisfied request */ - /* header */ - buf[0].BufferType = SECBUFFER_STREAM_HEADER; - memset (buf[0].pvBuffer = stream->obuf,0, - buf[0].cbBuffer = stream->sizes.cbHeader); - /* message (up to maximum size) */ - buf[1].BufferType = SECBUFFER_DATA; - memcpy (buf[1].pvBuffer = stream->obuf + stream->sizes.cbHeader,string, - buf[1].cbBuffer = min (size,SSLBUFLEN)); - /* trailer */ - buf[2].BufferType = SECBUFFER_STREAM_TRAILER; - memset (buf[2].pvBuffer = ((char *) buf[1].pvBuffer) + buf[1].cbBuffer,0, - buf[2].cbBuffer = stream->sizes.cbTrailer); - /* spare */ - buf[3].BufferType = SECBUFFER_EMPTY; - msg.ulVersion = SECBUFFER_VERSION; - msg.cBuffers = 4; /* number of SecBuffers */ - msg.pBuffers = buf; /* first SecBuffer */ - string += buf[1].cbBuffer; - size -= buf[1].cbBuffer; /* this many bytes processed */ - /* encrypt and send message */ - if ((((ENCRYPT_MESSAGE_FN) sft->Reserved3) - (&stream->context,0,&msg,NIL) != SEC_E_OK) || - !tcp_sout (stream->tcpstream,stream->obuf, - buf[0].cbBuffer + buf[1].cbBuffer + buf[2].cbBuffer)) - return ssl_abort (stream);/* encryption or sending failed */ - } - return LONGT; -} - -/* SSL close - * Accepts: SSL stream - */ - -void ssl_close (SSLSTREAM *stream) -{ - ssl_abort (stream); /* nuke the stream */ - fs_give ((void **) &stream); /* flush the stream */ -} - - -/* SSL abort stream - * Accepts: SSL stream - * Returns: NIL always - */ - -static long ssl_abort (SSLSTREAM *stream) -{ - if (stream->tcpstream) { /* close TCP stream */ - sft->DeleteSecurityContext (&stream->context); - sft->FreeCredentialHandle (&stream->cred); - tcp_close (stream->tcpstream); - stream->tcpstream = NIL; - } - if (stream->ibuf) fs_give ((void **) &stream->ibuf); - if (stream->obuf) fs_give ((void **) &stream->obuf); - return NIL; -} - -/* SSL get host name - * Accepts: SSL stream - * Returns: host name for this stream - */ - -char *ssl_host (SSLSTREAM *stream) -{ - return stream ? tcp_host (stream->tcpstream) : "UNKNOWN"; -} - - -/* SSL get remote host name - * Accepts: SSL stream - * Returns: host name for this stream - */ - -char *ssl_remotehost (SSLSTREAM *stream) -{ - return tcp_remotehost (stream->tcpstream); -} - - -/* SSL return port for this stream - * Accepts: SSL stream - * Returns: port number for this stream - */ - -unsigned long ssl_port (SSLSTREAM *stream) -{ - return tcp_port (stream->tcpstream); -} - - -/* SSL get local host name - * Accepts: SSL stream - * Returns: local host name - */ - -char *ssl_localhost (SSLSTREAM *stream) -{ - return tcp_localhost (stream->tcpstream); -} - -#include "ssl_none.c" /* currently no server support */ |