sslsecur.c

来自「支持SSL v2/v3, TLS, PKCS #5, PKCS #7, PKCS」· C语言 代码 · 共 1,378 行 · 第 1/3 页

C
1,378
字号
/* * Various SSL functions. * * The contents of this file are subject to the Mozilla Public * License Version 1.1 (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.mozilla.org/MPL/ *  * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. *  * The Original Code is the Netscape security libraries. *  * The Initial Developer of the Original Code is Netscape * Communications Corporation.  Portions created by Netscape are  * Copyright (C) 1994-2000 Netscape Communications Corporation.  All * Rights Reserved. *  * Contributor(s): *  * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the * "GPL"), in which case the provisions of the GPL are applicable  * instead of those above.  If you wish to allow use of your  * version of this file only under the terms of the GPL and not to * allow others to use your version of this file under the MPL, * indicate your decision by deleting the provisions above and * replace them with the notice and other provisions required by * the GPL.  If you do not delete the provisions above, a recipient * may use your version of this file under either the MPL or the * GPL. * * $Id: sslsecur.c,v 1.2 2000/09/07 19:01:48 nelsonb%netscape.com Exp $ */#include "cert.h"#include "secitem.h"#include "keyhi.h"#include "ssl.h"#include "sslimpl.h"#include "sslproto.h"#include "secoid.h"	/* for SECOID_GetALgorithmTag */#include "pk11func.h"	/* for PK11_GenerateRandom */#if defined(_WINDOWS)#include "winsock.h"	/* for MSG_PEEK */#elif defined(XP_MAC)#include "macsocket.h"#else#include <sys/socket.h> /* for MSG_PEEK */#endif#define MAX_BLOCK_CYPHER_SIZE	32#define TEST_FOR_FAILURE	/* reminder */#define SET_ERROR_CODE		/* reminder *//* Returns a SECStatus: SECSuccess or SECFailure, NOT SECWouldBlock.  *  * Currently, the list of functions called through ss->handshake is: *  * In sslsocks.c: *  SocksGatherRecord *  SocksHandleReply	 *  SocksStartGather * * In sslcon.c: *  ssl_GatherRecord1stHandshake *  ssl2_HandleClientSessionKeyMessage *  ssl2_HandleMessage *  ssl2_HandleVerifyMessage *  ssl2_BeginClientHandshake *  ssl2_BeginServerHandshake *  ssl2_HandleClientHelloMessage *  ssl2_HandleServerHelloMessage *  * The ss->handshake function returns SECWouldBlock under these conditions: * 1.	ssl_GatherRecord1stHandshake called ssl2_GatherData which read in  *	the beginning of an SSL v3 hello message and returned SECWouldBlock  *	to switch to SSL v3 handshake processing. * * 2.	ssl2_HandleClientHelloMessage discovered version 3.0 in the incoming *	v2 client hello msg, and called ssl3_HandleV2ClientHello which  *	returned SECWouldBlock. * * 3.   SECWouldBlock was returned by one of the callback functions, via *	one of these paths: * -	ssl2_HandleMessage() -> ssl2_HandleRequestCertificate() -> ss->getClientAuthData() * * -	ssl2_HandleServerHelloMessage() -> ss->handleBadCert() * * -	ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() ->  *	ssl3_HandleRecord() -> ssl3_HandleHandshake() ->  *	ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificate() ->  *	ss->handleBadCert() * * -	ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() ->  *	ssl3_HandleRecord() -> ssl3_HandleHandshake() ->  *	ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificateRequest() ->  *	ss->getClientAuthData() * * Called from: SSL_ForceHandshake	(below),  *              ssl_SecureRecv 		(below) and *              ssl_SecureSend		(below) *	  from: WaitForResponse 	in sslsocks.c *	        ssl_SocksRecv   	in sslsocks.c *              ssl_SocksSend   	in sslsocks.c * * Caller must hold the (write) handshakeLock. */int ssl_Do1stHandshake(sslSocket *ss){    int rv        = SECSuccess;    int loopCount = 0;    PORT_Assert(ss->gather != 0);    do {	PORT_Assert( ssl_Have1stHandshakeLock(ss) );	PORT_Assert( !ssl_HaveRecvBufLock(ss)   );	PORT_Assert( !ssl_HaveXmitBufLock(ss)   );	if (ss->handshake == 0) {	    /* Previous handshake finished. Switch to next one */	    ss->handshake = ss->nextHandshake;	    ss->nextHandshake = 0;	}	if (ss->handshake == 0) {	    /* Previous handshake finished. Switch to security handshake */	    ss->handshake = ss->securityHandshake;	    ss->securityHandshake = 0;	}	if (ss->handshake == 0) {	    ssl_GetRecvBufLock(ss);	    ss->gather->recordLen = 0;	    ssl_ReleaseRecvBufLock(ss);	    SSL_TRC(3, ("%d: SSL[%d]: handshake is completed",			SSL_GETPID(), ss->fd));            /* call handshake callback for ssl v2 */	    /* for v3 this is done in ssl3_HandleFinished() */	    if ((ss->sec != NULL) &&               /* used SSL */	        (ss->handshakeCallback != NULL) && /* has callback */		(!ss->connected) &&                /* only first time */		(ss->version < SSL_LIBRARY_VERSION_3_0)) {  /* not ssl3 */		ss->connected       = PR_TRUE;		(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);	    }	    ss->connected           = PR_TRUE;	    ss->gather->writeOffset = 0;	    ss->gather->readOffset  = 0;	    break;	}	rv = (*ss->handshake)(ss);	++loopCount;    /* This code must continue to loop on SECWouldBlock,      * or any positive value.	See XXX_1 comments.     */    } while (rv != SECFailure);  	/* was (rv >= 0); XXX_1 */    PORT_Assert( !ssl_HaveRecvBufLock(ss)   );    PORT_Assert( !ssl_HaveXmitBufLock(ss)   );    if (rv == SECWouldBlock) {	PORT_SetError(PR_WOULD_BLOCK_ERROR);	rv = SECFailure;    }    return rv;}/* * Handshake function that blocks.  Used to force a * retry on a connection on the next read/write. */#ifdef macintoshstatic SECStatus#elsestatic int#endifAlwaysBlock(sslSocket *ss){    PORT_SetError(PR_WOULD_BLOCK_ERROR);	/* perhaps redundant. */    return SECWouldBlock;}/* * set the initial handshake state machine to block */voidssl_SetAlwaysBlock(sslSocket *ss){    if (!ss->connected) {	ss->handshake = AlwaysBlock;	ss->nextHandshake = 0;    }}/* Acquires and releases HandshakeLock.*/SECStatusSSL_ResetHandshake(PRFileDesc *s, PRBool asServer){    sslSocket *ss;    SECStatus rv;    ss = ssl_FindSocket(s);    if (!ss) {	SSL_DBG(("%d: SSL[%d]: bad socket in ResetHandshake", SSL_GETPID(), s));	return SECFailure;    }    /* Don't waste my time */    if (!ss->useSecurity)	return SECSuccess;    SSL_LOCK_READER(ss);    SSL_LOCK_WRITER(ss);    /* Reset handshake state */    ssl_Get1stHandshakeLock(ss);    ssl_GetSSL3HandshakeLock(ss);    ss->connected = PR_FALSE;    ss->handshake = asServer ? ssl2_BeginServerHandshake	                     : ssl2_BeginClientHandshake;    ss->nextHandshake       = 0;    ss->securityHandshake   = 0;    ssl_GetRecvBufLock(ss);    ss->gather->state       = GS_INIT;    ss->gather->writeOffset = 0;    ss->gather->readOffset  = 0;    ssl_ReleaseRecvBufLock(ss);    /*    ** Blow away old security state and get a fresh setup. This way if    ** ssl was used to connect to the first point in communication, ssl    ** can be used for the next layer.    */    if (ss->sec) {	ssl_DestroySecurityInfo(ss->sec);	ss->sec = 0;    }    rv = ssl_CreateSecurityInfo(ss);    ssl_ReleaseSSL3HandshakeLock(ss);    ssl_Release1stHandshakeLock(ss);    SSL_UNLOCK_WRITER(ss);    SSL_UNLOCK_READER(ss);    return rv;}/* For SSLv2, does nothing but return an error.** For SSLv3, flushes SID cache entry (if requested),** and then starts new client hello or hello request.** Acquires and releases HandshakeLock.*/intSSL_ReHandshake(PRFileDesc *fd, PRBool flushCache){    sslSocket *ss;    int        rv;        ss = ssl_FindSocket(fd);    if (!ss) {	SSL_DBG(("%d: SSL[%d]: bad socket in RedoHandshake", SSL_GETPID(), fd));	PORT_SetError(PR_BAD_DESCRIPTOR_ERROR);	return SECFailure;    }    if (!ss->useSecurity)	return SECSuccess;        ssl_Get1stHandshakeLock(ss);    /* SSL v2 protocol does not support subsequent handshakes. */    if (ss->version < SSL_LIBRARY_VERSION_3_0) {	PORT_SetError(SEC_ERROR_INVALID_ARGS);	rv = SECFailure;    } else {	ssl_GetSSL3HandshakeLock(ss);	rv = ssl3_RedoHandshake(ss, flushCache); /* force full handshake. */	ssl_ReleaseSSL3HandshakeLock(ss);    }    ssl_Release1stHandshakeLock(ss);    return rv;}intSSL_RedoHandshake(PRFileDesc *fd){    return SSL_ReHandshake(fd, PR_TRUE);}/* Register an application callback to be called when SSL handshake completes.** Acquires and releases HandshakeLock.*/intSSL_HandshakeCallback(PRFileDesc *fd, SSLHandshakeCallback cb,		      void *client_data){    sslSocket *ss;        ss = ssl_FindSocket(fd);    if (!ss) {	SSL_DBG(("%d: SSL[%d]: bad socket in HandshakeCallback",		 SSL_GETPID(), fd));	PORT_SetError(PR_BAD_DESCRIPTOR_ERROR);	return SECFailure;    }    if (!ss->useSecurity) {	PORT_SetError(SEC_ERROR_INVALID_ARGS);	return SECFailure;    }    ssl_Get1stHandshakeLock(ss);    ssl_GetSSL3HandshakeLock(ss);    PORT_Assert(ss->sec);    ss->handshakeCallback     = cb;    ss->handshakeCallbackData = client_data;    ssl_ReleaseSSL3HandshakeLock(ss);    ssl_Release1stHandshakeLock(ss);    return SECSuccess;}/* Try to make progress on an SSL handshake by attempting to read the ** next handshake from the peer, and sending any responses.** For non-blocking sockets, returns PR_ERROR_WOULD_BLOCK  if it cannot ** read the next handshake from the underlying socket.** For SSLv2, returns when handshake is complete or fatal error occurs.** For SSLv3, returns when handshake is complete, or application data has** arrived that must be taken by application before handshake can continue, ** or a fatal error occurs.** Application should use handshake completion callback to tell which. */intSSL_ForceHandshake(PRFileDesc *fd){    sslSocket *ss;    int        rv;    ss = ssl_FindSocket(fd);    if (!ss) {	SSL_DBG(("%d: SSL[%d]: bad socket in ForceHandshake",		 SSL_GETPID(), fd));	return SECFailure;    }    /* Don't waste my time */    if (!ss->useSecurity)     	return 0;    ssl_Get1stHandshakeLock(ss);    if (ss->version >= SSL_LIBRARY_VERSION_3_0) {    	ssl_GetRecvBufLock(ss);	rv = ssl3_GatherCompleteHandshake(ss, 0);	ssl_ReleaseRecvBufLock(ss);	if (rv == 0) {	    PORT_SetError(PR_END_OF_FILE_ERROR);	    rv = SECFailure;	} else if (rv == SECWouldBlock) {	    PORT_SetError(PR_WOULD_BLOCK_ERROR);	    rv = SECFailure;	}    } else if (!ss->connected) {	rv = ssl_Do1stHandshake(ss);    } else {	/* tried to force handshake on a connected SSL 2 socket. */    	rv = SECSuccess;	/* just pretend we did it. */    }    ssl_Release1stHandshakeLock(ss);    if (rv > 0)     	rv = SECSuccess;    return rv;}/************************************************************************//*** Grow a buffer to hold newLen bytes of data.** Called for both recv buffers and xmit buffers.** Caller must hold xmitBufLock or recvBufLock, as appropriate.*/SECStatussslBuffer_Grow(sslBuffer *b, unsigned int newLen){    if (newLen > b->space) {	if (b->buf) {	    b->buf = (unsigned char *) PORT_Realloc(b->buf, newLen);	} else {	    b->buf = (unsigned char *) PORT_Alloc(newLen);	}	if (!b->buf) {	    return SECFailure;	}	SSL_TRC(10, ("%d: SSL: grow buffer from %d to %d",		     SSL_GETPID(), b->space, newLen));	b->space = newLen;    }    return SECSuccess;}/*** Save away write data that is trying to be written before the security** handshake has been completed. When the handshake is completed, we will** flush this data out.** Caller must hold xmitBufLock*/SECStatus ssl_SaveWriteData(sslSocket *ss, sslBuffer *buf, const void *data,                       unsigned int len){    unsigned int newlen;    SECStatus    rv;    PORT_Assert( ssl_HaveXmitBufLock(ss) );    newlen = buf->len + len;    if (newlen > buf->space) {	rv = sslBuffer_Grow(buf, newlen);	if (rv) {	    return rv;	}    }    SSL_TRC(5, ("%d: SSL[%d]: saving %d bytes of data (%d total saved so far)",		 SSL_GETPID(), ss->fd, len, newlen));    PORT_Memcpy(buf->buf + buf->len, data, len);    buf->len = newlen;    return SECSuccess;}/*** Send saved write data. This will flush out data sent prior to a** complete security handshake. Hopefully there won't be too much of it.** Returns count of the bytes sent, NOT a SECStatus.** Caller must hold xmitBufLock*/int ssl_SendSavedWriteData(sslSocket *ss, sslBuffer *buf, sslSendFunc send){    int rv	= 0;    int len	= buf->len;    PORT_Assert( ssl_HaveXmitBufLock(ss) );    if (len != 0) {	SSL_TRC(5, ("%d: SSL[%d]: sending %d bytes of saved data",		     SSL_GETPID(), ss->fd, len));	rv = (*send)(ss, buf->buf, len, 0);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?