Blame nss/lib/ssl/sslsecur.c

Packit 40b132
/*
Packit 40b132
 * Various SSL functions.
Packit 40b132
 *
Packit 40b132
 * This Source Code Form is subject to the terms of the Mozilla Public
Packit 40b132
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit 40b132
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
Packit 40b132
#include "cert.h"
Packit 40b132
#include "secitem.h"
Packit 40b132
#include "keyhi.h"
Packit 40b132
#include "ssl.h"
Packit 40b132
#include "sslimpl.h"
Packit 40b132
#include "sslproto.h"
Packit 40b132
#include "secoid.h"	/* for SECOID_GetALgorithmTag */
Packit 40b132
#include "pk11func.h"	/* for PK11_GenerateRandom */
Packit 40b132
#include "nss.h"        /* for NSS_RegisterShutdown */
Packit 40b132
#include "prinit.h"     /* for PR_CallOnceWithArg */
Packit 40b132
Packit 40b132
#define MAX_BLOCK_CYPHER_SIZE	32
Packit 40b132
Packit 40b132
#define TEST_FOR_FAILURE	/* reminder */
Packit 40b132
#define SET_ERROR_CODE		/* reminder */
Packit 40b132
Packit 40b132
/* Returns a SECStatus: SECSuccess or SECFailure, NOT SECWouldBlock. 
Packit 40b132
 * 
Packit 40b132
 * Currently, the list of functions called through ss->handshake is:
Packit 40b132
 * 
Packit 40b132
 * In sslsocks.c:
Packit 40b132
 *  SocksGatherRecord
Packit 40b132
 *  SocksHandleReply	
Packit 40b132
 *  SocksStartGather
Packit 40b132
 *
Packit 40b132
 * In sslcon.c:
Packit 40b132
 *  ssl_GatherRecord1stHandshake
Packit 40b132
 *  ssl2_HandleClientSessionKeyMessage
Packit 40b132
 *  ssl2_HandleMessage
Packit 40b132
 *  ssl2_HandleVerifyMessage
Packit 40b132
 *  ssl2_BeginClientHandshake
Packit 40b132
 *  ssl2_BeginServerHandshake
Packit 40b132
 *  ssl2_HandleClientHelloMessage
Packit 40b132
 *  ssl2_HandleServerHelloMessage
Packit 40b132
 * 
Packit 40b132
 * The ss->handshake function returns SECWouldBlock under these conditions:
Packit 40b132
 * 1.	ssl_GatherRecord1stHandshake called ssl2_GatherData which read in 
Packit 40b132
 *	the beginning of an SSL v3 hello message and returned SECWouldBlock 
Packit 40b132
 *	to switch to SSL v3 handshake processing.
Packit 40b132
 *
Packit 40b132
 * 2.	ssl2_HandleClientHelloMessage discovered version 3.0 in the incoming
Packit 40b132
 *	v2 client hello msg, and called ssl3_HandleV2ClientHello which 
Packit 40b132
 *	returned SECWouldBlock.
Packit 40b132
 *
Packit 40b132
 * 3.   SECWouldBlock was returned by one of the callback functions, via
Packit 40b132
 *	one of these paths:
Packit 40b132
 * -	ssl2_HandleMessage() -> ssl2_HandleRequestCertificate() ->
Packit 40b132
 *	ss->getClientAuthData()
Packit 40b132
 *
Packit 40b132
 * -	ssl2_HandleServerHelloMessage() -> ss->handleBadCert()
Packit 40b132
 *
Packit 40b132
 * -	ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() -> 
Packit 40b132
 *	ssl3_HandleRecord() -> ssl3_HandleHandshake() -> 
Packit 40b132
 *	ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificate() -> 
Packit 40b132
 *	ss->handleBadCert()
Packit 40b132
 *
Packit 40b132
 * -	ssl_GatherRecord1stHandshake() -> ssl3_GatherCompleteHandshake() -> 
Packit 40b132
 *	ssl3_HandleRecord() -> ssl3_HandleHandshake() -> 
Packit 40b132
 *	ssl3_HandleHandshakeMessage() -> ssl3_HandleCertificateRequest() -> 
Packit 40b132
 *	ss->getClientAuthData()
Packit 40b132
 *
Packit 40b132
 * Called from: SSL_ForceHandshake	(below), 
Packit 40b132
 *              ssl_SecureRecv 		(below) and
Packit 40b132
 *              ssl_SecureSend		(below)
Packit 40b132
 *	  from: WaitForResponse 	in sslsocks.c
Packit 40b132
 *	        ssl_SocksRecv   	in sslsocks.c
Packit 40b132
 *              ssl_SocksSend   	in sslsocks.c
Packit 40b132
 *
Packit 40b132
 * Caller must hold the (write) handshakeLock.
Packit 40b132
 */
Packit 40b132
int 
Packit 40b132
ssl_Do1stHandshake(sslSocket *ss)
Packit 40b132
{
Packit 40b132
    int rv        = SECSuccess;
Packit 40b132
    int loopCount = 0;
Packit 40b132
Packit 40b132
    do {
Packit 40b132
	PORT_Assert(ss->opt.noLocks ||  ssl_Have1stHandshakeLock(ss) );
Packit 40b132
	PORT_Assert(ss->opt.noLocks || !ssl_HaveRecvBufLock(ss));
Packit 40b132
	PORT_Assert(ss->opt.noLocks || !ssl_HaveXmitBufLock(ss));
Packit 40b132
	PORT_Assert(ss->opt.noLocks || !ssl_HaveSSL3HandshakeLock(ss));
Packit 40b132
Packit 40b132
	if (ss->handshake == 0) {
Packit 40b132
	    /* Previous handshake finished. Switch to next one */
Packit 40b132
	    ss->handshake = ss->nextHandshake;
Packit 40b132
	    ss->nextHandshake = 0;
Packit 40b132
	}
Packit 40b132
	if (ss->handshake == 0) {
Packit 40b132
	    /* Previous handshake finished. Switch to security handshake */
Packit 40b132
	    ss->handshake = ss->securityHandshake;
Packit 40b132
	    ss->securityHandshake = 0;
Packit 40b132
	}
Packit 40b132
	if (ss->handshake == 0) {
Packit 40b132
	    /* for v3 this is done in ssl3_FinishHandshake */
Packit 40b132
	    if (!ss->firstHsDone && ss->version < SSL_LIBRARY_VERSION_3_0) {
Packit 40b132
		ssl_GetRecvBufLock(ss);
Packit 40b132
		ss->gs.recordLen = 0;
Packit 40b132
		ssl_FinishHandshake(ss);
Packit 40b132
		ssl_ReleaseRecvBufLock(ss);
Packit 40b132
	    }
Packit 40b132
	    break;
Packit 40b132
	}
Packit 40b132
	rv = (*ss->handshake)(ss);
Packit 40b132
	++loopCount;
Packit 40b132
    /* This code must continue to loop on SECWouldBlock, 
Packit 40b132
     * or any positive value.	See XXX_1 comments.
Packit 40b132
     */
Packit 40b132
    } while (rv != SECFailure);  	/* was (rv >= 0); XXX_1 */
Packit 40b132
Packit 40b132
    PORT_Assert(ss->opt.noLocks || !ssl_HaveRecvBufLock(ss));
Packit 40b132
    PORT_Assert(ss->opt.noLocks || !ssl_HaveXmitBufLock(ss));
Packit 40b132
    PORT_Assert(ss->opt.noLocks || !ssl_HaveSSL3HandshakeLock(ss));
Packit 40b132
Packit 40b132
    if (rv == SECWouldBlock) {
Packit 40b132
	PORT_SetError(PR_WOULD_BLOCK_ERROR);
Packit 40b132
	rv = SECFailure;
Packit 40b132
    }
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
void
Packit 40b132
ssl_FinishHandshake(sslSocket *ss)
Packit 40b132
{
Packit 40b132
    PORT_Assert( ss->opt.noLocks || ssl_Have1stHandshakeLock(ss) );
Packit 40b132
    PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) );
Packit 40b132
Packit 40b132
    SSL_TRC(3, ("%d: SSL[%d]: handshake is completed", SSL_GETPID(), ss->fd));
Packit 40b132
Packit 40b132
    ss->firstHsDone = PR_TRUE;
Packit 40b132
    ss->enoughFirstHsDone = PR_TRUE;
Packit 40b132
    ss->gs.writeOffset = 0;
Packit 40b132
    ss->gs.readOffset  = 0;
Packit 40b132
Packit 40b132
    if (ss->handshakeCallback) {
Packit 40b132
	(ss->handshakeCallback)(ss->fd, ss->handshakeCallbackData);
Packit 40b132
    }
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * Handshake function that blocks.  Used to force a
Packit 40b132
 * retry on a connection on the next read/write.
Packit 40b132
 */
Packit 40b132
static SECStatus
Packit 40b132
ssl3_AlwaysBlock(sslSocket *ss)
Packit 40b132
{
Packit 40b132
    PORT_SetError(PR_WOULD_BLOCK_ERROR);	/* perhaps redundant. */
Packit 40b132
    return SECWouldBlock;
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * set the initial handshake state machine to block
Packit 40b132
 */
Packit 40b132
void
Packit 40b132
ssl3_SetAlwaysBlock(sslSocket *ss)
Packit 40b132
{
Packit 40b132
    if (!ss->firstHsDone) {
Packit 40b132
	ss->handshake = ssl3_AlwaysBlock;
Packit 40b132
	ss->nextHandshake = 0;
Packit 40b132
    }
Packit 40b132
}
Packit 40b132
Packit 40b132
static SECStatus 
Packit 40b132
ssl_SetTimeout(PRFileDesc *fd, PRIntervalTime timeout)
Packit 40b132
{
Packit 40b132
    sslSocket *ss;
Packit 40b132
Packit 40b132
    ss = ssl_FindSocket(fd);
Packit 40b132
    if (!ss) {
Packit 40b132
	SSL_DBG(("%d: SSL[%d]: bad socket in SetTimeout", SSL_GETPID(), fd));
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
    SSL_LOCK_READER(ss);
Packit 40b132
    ss->rTimeout = timeout;
Packit 40b132
    if (ss->opt.fdx) {
Packit 40b132
        SSL_LOCK_WRITER(ss);
Packit 40b132
    }
Packit 40b132
    ss->wTimeout = timeout;
Packit 40b132
    if (ss->opt.fdx) {
Packit 40b132
        SSL_UNLOCK_WRITER(ss);
Packit 40b132
    }
Packit 40b132
    SSL_UNLOCK_READER(ss);
Packit 40b132
    return SECSuccess;
Packit 40b132
}
Packit 40b132
Packit 40b132
/* Acquires and releases HandshakeLock.
Packit 40b132
*/
Packit 40b132
SECStatus
Packit 40b132
SSL_ResetHandshake(PRFileDesc *s, PRBool asServer)
Packit 40b132
{
Packit 40b132
    sslSocket *ss;
Packit 40b132
    SECStatus status;
Packit 40b132
    PRNetAddr addr;
Packit 40b132
Packit 40b132
    ss = ssl_FindSocket(s);
Packit 40b132
    if (!ss) {
Packit 40b132
	SSL_DBG(("%d: SSL[%d]: bad socket in ResetHandshake", SSL_GETPID(), s));
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    /* Don't waste my time */
Packit 40b132
    if (!ss->opt.useSecurity)
Packit 40b132
	return SECSuccess;
Packit 40b132
Packit 40b132
    SSL_LOCK_READER(ss);
Packit 40b132
    SSL_LOCK_WRITER(ss);
Packit 40b132
Packit 40b132
    /* Reset handshake state */
Packit 40b132
    ssl_Get1stHandshakeLock(ss);
Packit 40b132
Packit 40b132
    ss->firstHsDone = PR_FALSE;
Packit 40b132
    ss->enoughFirstHsDone = PR_FALSE;
Packit 40b132
    if ( asServer ) {
Packit 40b132
	ss->handshake = ssl2_BeginServerHandshake;
Packit 40b132
	ss->handshaking = sslHandshakingAsServer;
Packit 40b132
    } else {
Packit 40b132
	ss->handshake = ssl2_BeginClientHandshake;
Packit 40b132
	ss->handshaking = sslHandshakingAsClient;
Packit 40b132
    }
Packit 40b132
    ss->nextHandshake       = 0;
Packit 40b132
    ss->securityHandshake   = 0;
Packit 40b132
Packit 40b132
    ssl_GetRecvBufLock(ss);
Packit 40b132
    status = ssl_InitGather(&ss->gs);
Packit 40b132
    ssl_ReleaseRecvBufLock(ss);
Packit 40b132
Packit 40b132
    ssl_GetSSL3HandshakeLock(ss);
Packit 40b132
    ss->ssl3.hs.canFalseStart = PR_FALSE;
Packit 40b132
    ss->ssl3.hs.restartTarget = NULL;
Packit 40b132
Packit 40b132
    /*
Packit 40b132
    ** Blow away old security state and get a fresh setup.
Packit 40b132
    */
Packit 40b132
    ssl_GetXmitBufLock(ss); 
Packit 40b132
    ssl_ResetSecurityInfo(&ss->sec, PR_TRUE);
Packit 40b132
    status = ssl_CreateSecurityInfo(ss);
Packit 40b132
    ssl_ReleaseXmitBufLock(ss); 
Packit 40b132
Packit 40b132
    ssl_ReleaseSSL3HandshakeLock(ss);
Packit 40b132
    ssl_Release1stHandshakeLock(ss);
Packit 40b132
Packit 40b132
    if (!ss->TCPconnected)
Packit 40b132
	ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr));
Packit 40b132
Packit 40b132
    SSL_UNLOCK_WRITER(ss);
Packit 40b132
    SSL_UNLOCK_READER(ss);
Packit 40b132
Packit 40b132
    return status;
Packit 40b132
}
Packit 40b132
Packit 40b132
/* For SSLv2, does nothing but return an error.
Packit 40b132
** For SSLv3, flushes SID cache entry (if requested),
Packit 40b132
** and then starts new client hello or hello request.
Packit 40b132
** Acquires and releases HandshakeLock.
Packit 40b132
*/
Packit 40b132
SECStatus
Packit 40b132
SSL_ReHandshake(PRFileDesc *fd, PRBool flushCache)
Packit 40b132
{
Packit 40b132
    sslSocket *ss;
Packit 40b132
    SECStatus  rv;
Packit 40b132
    
Packit 40b132
    ss = ssl_FindSocket(fd);
Packit 40b132
    if (!ss) {
Packit 40b132
	SSL_DBG(("%d: SSL[%d]: bad socket in RedoHandshake", SSL_GETPID(), fd));
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (!ss->opt.useSecurity)
Packit 40b132
	return SECSuccess;
Packit 40b132
    
Packit 40b132
    ssl_Get1stHandshakeLock(ss);
Packit 40b132
Packit 40b132
    /* SSL v2 protocol does not support subsequent handshakes. */
Packit 40b132
    if (ss->version < SSL_LIBRARY_VERSION_3_0) {
Packit 40b132
	PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
Packit 40b132
	rv = SECFailure;
Packit 40b132
    } else {
Packit 40b132
	ssl_GetSSL3HandshakeLock(ss);
Packit 40b132
	rv = ssl3_RedoHandshake(ss, flushCache); /* force full handshake. */
Packit 40b132
	ssl_ReleaseSSL3HandshakeLock(ss);
Packit 40b132
    }
Packit 40b132
Packit 40b132
    ssl_Release1stHandshakeLock(ss);
Packit 40b132
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
** Same as above, but with an I/O timeout.
Packit 40b132
 */
Packit 40b132
SSL_IMPORT SECStatus SSL_ReHandshakeWithTimeout(PRFileDesc *fd,
Packit 40b132
                                                PRBool flushCache,
Packit 40b132
                                                PRIntervalTime timeout)
Packit 40b132
{
Packit 40b132
    if (SECSuccess != ssl_SetTimeout(fd, timeout)) {
Packit 40b132
        return SECFailure;
Packit 40b132
    }
Packit 40b132
    return SSL_ReHandshake(fd, flushCache);
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus
Packit 40b132
SSL_RedoHandshake(PRFileDesc *fd)
Packit 40b132
{
Packit 40b132
    return SSL_ReHandshake(fd, PR_TRUE);
Packit 40b132
}
Packit 40b132
Packit 40b132
/* Register an application callback to be called when SSL handshake completes.
Packit 40b132
** Acquires and releases HandshakeLock.
Packit 40b132
*/
Packit 40b132
SECStatus
Packit 40b132
SSL_HandshakeCallback(PRFileDesc *fd, SSLHandshakeCallback cb,
Packit 40b132
		      void *client_data)
Packit 40b132
{
Packit 40b132
    sslSocket *ss;
Packit 40b132
    
Packit 40b132
    ss = ssl_FindSocket(fd);
Packit 40b132
    if (!ss) {
Packit 40b132
	SSL_DBG(("%d: SSL[%d]: bad socket in HandshakeCallback",
Packit 40b132
		 SSL_GETPID(), fd));
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (!ss->opt.useSecurity) {
Packit 40b132
	PORT_SetError(SEC_ERROR_INVALID_ARGS);
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    ssl_Get1stHandshakeLock(ss);
Packit 40b132
    ssl_GetSSL3HandshakeLock(ss);
Packit 40b132
Packit 40b132
    ss->handshakeCallback     = cb;
Packit 40b132
    ss->handshakeCallbackData = client_data;
Packit 40b132
Packit 40b132
    ssl_ReleaseSSL3HandshakeLock(ss);
Packit 40b132
    ssl_Release1stHandshakeLock(ss);
Packit 40b132
Packit 40b132
    return SECSuccess;
Packit 40b132
}
Packit 40b132
Packit 40b132
/* Register an application callback to be called when false start may happen.
Packit 40b132
** Acquires and releases HandshakeLock.
Packit 40b132
*/
Packit 40b132
SECStatus
Packit 40b132
SSL_SetCanFalseStartCallback(PRFileDesc *fd, SSLCanFalseStartCallback cb,
Packit 40b132
			     void *arg)
Packit 40b132
{
Packit 40b132
    sslSocket *ss;
Packit 40b132
Packit 40b132
    ss = ssl_FindSocket(fd);
Packit 40b132
    if (!ss) {
Packit 40b132
	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetCanFalseStartCallback",
Packit 40b132
		 SSL_GETPID(), fd));
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (!ss->opt.useSecurity) {
Packit 40b132
	PORT_SetError(SEC_ERROR_INVALID_ARGS);
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    ssl_Get1stHandshakeLock(ss);
Packit 40b132
    ssl_GetSSL3HandshakeLock(ss);
Packit 40b132
Packit 40b132
    ss->canFalseStartCallback     = cb;
Packit 40b132
    ss->canFalseStartCallbackData = arg;
Packit 40b132
Packit 40b132
    ssl_ReleaseSSL3HandshakeLock(ss);
Packit 40b132
    ssl_Release1stHandshakeLock(ss);
Packit 40b132
Packit 40b132
    return SECSuccess;
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus
Packit 40b132
SSL_RecommendedCanFalseStart(PRFileDesc *fd, PRBool *canFalseStart)
Packit 40b132
{
Packit 40b132
    sslSocket *ss;
Packit 40b132
Packit 40b132
    *canFalseStart = PR_FALSE;
Packit 40b132
    ss = ssl_FindSocket(fd);
Packit 40b132
    if (!ss) {
Packit 40b132
	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_RecommendedCanFalseStart",
Packit 40b132
		 SSL_GETPID(), fd));
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (!ss->ssl3.initialized) {
Packit 40b132
	PORT_SetError(SEC_ERROR_INVALID_ARGS);
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (ss->version < SSL_LIBRARY_VERSION_3_0) {
Packit 40b132
	PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    /* Require a forward-secret key exchange. */
Packit 40b132
    *canFalseStart = ss->ssl3.hs.kea_def->kea == kea_dhe_dss ||
Packit 40b132
		     ss->ssl3.hs.kea_def->kea == kea_dhe_rsa ||
Packit 40b132
		     ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa ||
Packit 40b132
		     ss->ssl3.hs.kea_def->kea == kea_ecdhe_rsa;
Packit 40b132
Packit 40b132
    return SECSuccess;
Packit 40b132
}
Packit 40b132
Packit 40b132
/* Try to make progress on an SSL handshake by attempting to read the 
Packit 40b132
** next handshake from the peer, and sending any responses.
Packit 40b132
** For non-blocking sockets, returns PR_ERROR_WOULD_BLOCK  if it cannot 
Packit 40b132
** read the next handshake from the underlying socket.
Packit 40b132
** For SSLv2, returns when handshake is complete or fatal error occurs.
Packit 40b132
** For SSLv3, returns when handshake is complete, or application data has
Packit 40b132
** arrived that must be taken by application before handshake can continue, 
Packit 40b132
** or a fatal error occurs.
Packit 40b132
** Application should use handshake completion callback to tell which. 
Packit 40b132
*/
Packit 40b132
SECStatus
Packit 40b132
SSL_ForceHandshake(PRFileDesc *fd)
Packit 40b132
{
Packit 40b132
    sslSocket *ss;
Packit 40b132
    SECStatus  rv = SECFailure;
Packit 40b132
Packit 40b132
    ss = ssl_FindSocket(fd);
Packit 40b132
    if (!ss) {
Packit 40b132
	SSL_DBG(("%d: SSL[%d]: bad socket in ForceHandshake",
Packit 40b132
		 SSL_GETPID(), fd));
Packit 40b132
	return rv;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    /* Don't waste my time */
Packit 40b132
    if (!ss->opt.useSecurity) 
Packit 40b132
    	return SECSuccess;
Packit 40b132
Packit 40b132
    if (!ssl_SocketIsBlocking(ss)) {
Packit 40b132
	ssl_GetXmitBufLock(ss);
Packit 40b132
	if (ss->pendingBuf.len != 0) {
Packit 40b132
	    int sent = ssl_SendSavedWriteData(ss);
Packit 40b132
	    if ((sent < 0) && (PORT_GetError() != PR_WOULD_BLOCK_ERROR)) {
Packit 40b132
		ssl_ReleaseXmitBufLock(ss);
Packit 40b132
		return SECFailure;
Packit 40b132
	    }
Packit 40b132
	}
Packit 40b132
	ssl_ReleaseXmitBufLock(ss);
Packit 40b132
    }
Packit 40b132
Packit 40b132
    ssl_Get1stHandshakeLock(ss);
Packit 40b132
Packit 40b132
    if (ss->version >= SSL_LIBRARY_VERSION_3_0) {
Packit 40b132
	int gatherResult;
Packit 40b132
Packit 40b132
    	ssl_GetRecvBufLock(ss);
Packit 40b132
	gatherResult = ssl3_GatherCompleteHandshake(ss, 0);
Packit 40b132
	ssl_ReleaseRecvBufLock(ss);
Packit 40b132
	if (gatherResult > 0) {
Packit 40b132
	    rv = SECSuccess;
Packit 40b132
	} else if (gatherResult == 0) {
Packit 40b132
	    PORT_SetError(PR_END_OF_FILE_ERROR);
Packit 40b132
	} else if (gatherResult == SECWouldBlock) {
Packit 40b132
	    PORT_SetError(PR_WOULD_BLOCK_ERROR);
Packit 40b132
	}
Packit 40b132
    } else if (!ss->firstHsDone) {
Packit 40b132
	rv = ssl_Do1stHandshake(ss);
Packit 40b132
    } else {
Packit 40b132
	/* tried to force handshake on an SSL 2 socket that has 
Packit 40b132
	** already completed the handshake. */
Packit 40b132
    	rv = SECSuccess;	/* just pretend we did it. */
Packit 40b132
    }
Packit 40b132
Packit 40b132
    ssl_Release1stHandshakeLock(ss);
Packit 40b132
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 ** Same as above, but with an I/O timeout.
Packit 40b132
 */
Packit 40b132
SSL_IMPORT SECStatus SSL_ForceHandshakeWithTimeout(PRFileDesc *fd,
Packit 40b132
                                                   PRIntervalTime timeout)
Packit 40b132
{
Packit 40b132
    if (SECSuccess != ssl_SetTimeout(fd, timeout)) {
Packit 40b132
        return SECFailure;
Packit 40b132
    }
Packit 40b132
    return SSL_ForceHandshake(fd);
Packit 40b132
}
Packit 40b132
Packit 40b132
Packit 40b132
/************************************************************************/
Packit 40b132
Packit 40b132
/*
Packit 40b132
** Grow a buffer to hold newLen bytes of data.
Packit 40b132
** Called for both recv buffers and xmit buffers.
Packit 40b132
** Caller must hold xmitBufLock or recvBufLock, as appropriate.
Packit 40b132
*/
Packit 40b132
SECStatus
Packit 40b132
sslBuffer_Grow(sslBuffer *b, unsigned int newLen)
Packit 40b132
{
Packit 40b132
    newLen = PR_MAX(newLen, MAX_FRAGMENT_LENGTH + 2048);
Packit 40b132
    if (newLen > b->space) {
Packit 40b132
	unsigned char *newBuf;
Packit 40b132
	if (b->buf) {
Packit 40b132
	    newBuf = (unsigned char *) PORT_Realloc(b->buf, newLen);
Packit 40b132
	} else {
Packit 40b132
	    newBuf = (unsigned char *) PORT_Alloc(newLen);
Packit 40b132
	}
Packit 40b132
	if (!newBuf) {
Packit 40b132
	    return SECFailure;
Packit 40b132
	}
Packit 40b132
	SSL_TRC(10, ("%d: SSL: grow buffer from %d to %d",
Packit 40b132
		     SSL_GETPID(), b->space, newLen));
Packit 40b132
	b->buf = newBuf;
Packit 40b132
	b->space = newLen;
Packit 40b132
    }
Packit 40b132
    return SECSuccess;
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus 
Packit 40b132
sslBuffer_Append(sslBuffer *b, const void * data, unsigned int len)
Packit 40b132
{
Packit 40b132
    unsigned int newLen = b->len + len;
Packit 40b132
    SECStatus rv;
Packit 40b132
Packit 40b132
    rv = sslBuffer_Grow(b, newLen);
Packit 40b132
    if (rv != SECSuccess)
Packit 40b132
    	return rv;
Packit 40b132
    PORT_Memcpy(b->buf + b->len, data, len);
Packit 40b132
    b->len += len;
Packit 40b132
    return SECSuccess;
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
** Save away write data that is trying to be written before the security
Packit 40b132
** handshake has been completed. When the handshake is completed, we will
Packit 40b132
** flush this data out.
Packit 40b132
** Caller must hold xmitBufLock
Packit 40b132
*/
Packit 40b132
SECStatus 
Packit 40b132
ssl_SaveWriteData(sslSocket *ss, const void *data, unsigned int len)
Packit 40b132
{
Packit 40b132
    SECStatus    rv;
Packit 40b132
Packit 40b132
    PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
Packit 40b132
    rv = sslBuffer_Append(&ss->pendingBuf, data, len);
Packit 40b132
    SSL_TRC(5, ("%d: SSL[%d]: saving %u bytes of data (%u total saved so far)",
Packit 40b132
		 SSL_GETPID(), ss->fd, len, ss->pendingBuf.len));
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
** Send saved write data. This will flush out data sent prior to a
Packit 40b132
** complete security handshake. Hopefully there won't be too much of it.
Packit 40b132
** Returns count of the bytes sent, NOT a SECStatus.
Packit 40b132
** Caller must hold xmitBufLock
Packit 40b132
*/
Packit 40b132
int 
Packit 40b132
ssl_SendSavedWriteData(sslSocket *ss)
Packit 40b132
{
Packit 40b132
    int rv	= 0;
Packit 40b132
Packit 40b132
    PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) );
Packit 40b132
    if (ss->pendingBuf.len != 0) {
Packit 40b132
	SSL_TRC(5, ("%d: SSL[%d]: sending %d bytes of saved data",
Packit 40b132
		     SSL_GETPID(), ss->fd, ss->pendingBuf.len));
Packit 40b132
	rv = ssl_DefSend(ss, ss->pendingBuf.buf, ss->pendingBuf.len, 0);
Packit 40b132
	if (rv < 0) {
Packit 40b132
	    return rv;
Packit 40b132
	} 
Packit 40b132
	ss->pendingBuf.len -= rv;
Packit 40b132
	if (ss->pendingBuf.len > 0 && rv > 0) {
Packit 40b132
	    /* UGH !! This shifts the whole buffer down by copying it */
Packit 40b132
	    PORT_Memmove(ss->pendingBuf.buf, ss->pendingBuf.buf + rv, 
Packit 40b132
	                 ss->pendingBuf.len);
Packit 40b132
    	}
Packit 40b132
    }
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
/************************************************************************/
Packit 40b132
Packit 40b132
/*
Packit 40b132
** Receive some application data on a socket.  Reads SSL records from the input
Packit 40b132
** stream, decrypts them and then copies them to the output buffer.
Packit 40b132
** Called from ssl_SecureRecv() below.
Packit 40b132
**
Packit 40b132
** Caller does NOT hold 1stHandshakeLock because that handshake is over.
Packit 40b132
** Caller doesn't call this until initial handshake is complete.
Packit 40b132
** For SSLv2, there is no subsequent handshake.
Packit 40b132
** For SSLv3, the call to ssl3_GatherAppDataRecord may encounter handshake
Packit 40b132
** messages from a subsequent handshake.
Packit 40b132
**
Packit 40b132
** This code is similar to, and easily confused with, 
Packit 40b132
**   ssl_GatherRecord1stHandshake() in sslcon.c
Packit 40b132
*/
Packit 40b132
static int 
Packit 40b132
DoRecv(sslSocket *ss, unsigned char *out, int len, int flags)
Packit 40b132
{
Packit 40b132
    int              rv;
Packit 40b132
    int              amount;
Packit 40b132
    int              available;
Packit 40b132
Packit 40b132
    /* ssl3_GatherAppDataRecord may call ssl_FinishHandshake, which needs the
Packit 40b132
     * 1stHandshakeLock. */
Packit 40b132
    ssl_Get1stHandshakeLock(ss);
Packit 40b132
    ssl_GetRecvBufLock(ss);
Packit 40b132
Packit 40b132
    available = ss->gs.writeOffset - ss->gs.readOffset;
Packit 40b132
    if (available == 0) {
Packit 40b132
	/* Get some more data */
Packit 40b132
	if (ss->version >= SSL_LIBRARY_VERSION_3_0) {
Packit 40b132
	    /* Wait for application data to arrive.  */
Packit 40b132
	    rv = ssl3_GatherAppDataRecord(ss, 0);
Packit 40b132
	} else {
Packit 40b132
	    /* See if we have a complete record */
Packit 40b132
	    rv = ssl2_GatherRecord(ss, 0);
Packit 40b132
	}
Packit 40b132
	if (rv <= 0) {
Packit 40b132
	    if (rv == 0) {
Packit 40b132
		/* EOF */
Packit 40b132
		SSL_TRC(10, ("%d: SSL[%d]: ssl_recv EOF",
Packit 40b132
			     SSL_GETPID(), ss->fd));
Packit 40b132
		goto done;
Packit 40b132
	    }
Packit 40b132
	    if ((rv != SECWouldBlock) && 
Packit 40b132
	        (PR_GetError() != PR_WOULD_BLOCK_ERROR)) {
Packit 40b132
		/* Some random error */
Packit 40b132
		goto done;
Packit 40b132
	    }
Packit 40b132
Packit 40b132
	    /*
Packit 40b132
	    ** Gather record is blocked waiting for more record data to
Packit 40b132
	    ** arrive. Try to process what we have already received
Packit 40b132
	    */
Packit 40b132
	} else {
Packit 40b132
	    /* Gather record has finished getting a complete record */
Packit 40b132
	}
Packit 40b132
Packit 40b132
	/* See if any clear data is now available */
Packit 40b132
	available = ss->gs.writeOffset - ss->gs.readOffset;
Packit 40b132
	if (available == 0) {
Packit 40b132
	    /*
Packit 40b132
	    ** No partial data is available. Force error code to
Packit 40b132
	    ** EWOULDBLOCK so that caller will try again later. Note
Packit 40b132
	    ** that the error code is probably EWOULDBLOCK already,
Packit 40b132
	    ** but if it isn't (for example, if we received a zero
Packit 40b132
	    ** length record) then this will force it to be correct.
Packit 40b132
	    */
Packit 40b132
	    PORT_SetError(PR_WOULD_BLOCK_ERROR);
Packit 40b132
	    rv = SECFailure;
Packit 40b132
	    goto done;
Packit 40b132
	}
Packit 40b132
	SSL_TRC(30, ("%d: SSL[%d]: partial data ready, available=%d",
Packit 40b132
		     SSL_GETPID(), ss->fd, available));
Packit 40b132
    }
Packit 40b132
Packit 40b132
    /* Dole out clear data to reader */
Packit 40b132
    amount = PR_MIN(len, available);
Packit 40b132
    PORT_Memcpy(out, ss->gs.buf.buf + ss->gs.readOffset, amount);
Packit 40b132
    if (!(flags & PR_MSG_PEEK)) {
Packit 40b132
	ss->gs.readOffset += amount;
Packit 40b132
    }
Packit 40b132
    PORT_Assert(ss->gs.readOffset <= ss->gs.writeOffset);
Packit 40b132
    rv = amount;
Packit 40b132
Packit 40b132
    SSL_TRC(30, ("%d: SSL[%d]: amount=%d available=%d",
Packit 40b132
		 SSL_GETPID(), ss->fd, amount, available));
Packit 40b132
    PRINT_BUF(4, (ss, "DoRecv receiving plaintext:", out, amount));
Packit 40b132
Packit 40b132
done:
Packit 40b132
    ssl_ReleaseRecvBufLock(ss);
Packit 40b132
    ssl_Release1stHandshakeLock(ss);
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
/************************************************************************/
Packit 40b132
Packit 40b132
/*
Packit 40b132
** Return SSLKEAType derived from cert's Public Key algorithm info.
Packit 40b132
*/
Packit 40b132
SSLKEAType
Packit 40b132
NSS_FindCertKEAType(CERTCertificate * cert)
Packit 40b132
{
Packit 40b132
  SSLKEAType keaType = kt_null; 
Packit 40b132
  int tag;
Packit 40b132
  
Packit 40b132
  if (!cert) goto loser;
Packit 40b132
  
Packit 40b132
  tag = SECOID_GetAlgorithmTag(&(cert->subjectPublicKeyInfo.algorithm));
Packit 40b132
  
Packit 40b132
  switch (tag) {
Packit 40b132
  case SEC_OID_X500_RSA_ENCRYPTION:
Packit 40b132
  case SEC_OID_PKCS1_RSA_ENCRYPTION:
Packit 40b132
    keaType = kt_rsa;
Packit 40b132
    break;
Packit 40b132
  case SEC_OID_ANSIX9_DSA_SIGNATURE: /* hah, signature, not a key? */
Packit 40b132
  case SEC_OID_X942_DIFFIE_HELMAN_KEY:
Packit 40b132
    keaType = kt_dh;
Packit 40b132
    break;
Packit 40b132
#ifndef NSS_DISABLE_ECC
Packit 40b132
  case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
Packit 40b132
    keaType = kt_ecdh;
Packit 40b132
    break;
Packit 40b132
#endif /* NSS_DISABLE_ECC */
Packit 40b132
  default:
Packit 40b132
    keaType = kt_null;
Packit 40b132
  }
Packit 40b132
  
Packit 40b132
 loser:
Packit 40b132
  
Packit 40b132
  return keaType;
Packit 40b132
}
Packit 40b132
Packit 40b132
static const PRCallOnceType pristineCallOnce;
Packit 40b132
static       PRCallOnceType setupServerCAListOnce;
Packit 40b132
Packit 40b132
static SECStatus serverCAListShutdown(void* appData, void* nssData)
Packit 40b132
{
Packit 40b132
    PORT_Assert(ssl3_server_ca_list);
Packit 40b132
    if (ssl3_server_ca_list) {
Packit 40b132
	CERT_FreeDistNames(ssl3_server_ca_list);
Packit 40b132
	ssl3_server_ca_list = NULL;
Packit 40b132
    }
Packit 40b132
    setupServerCAListOnce = pristineCallOnce;
Packit 40b132
    return SECSuccess;
Packit 40b132
}
Packit 40b132
Packit 40b132
static PRStatus serverCAListSetup(void *arg)
Packit 40b132
{
Packit 40b132
    CERTCertDBHandle *dbHandle = (CERTCertDBHandle *)arg;
Packit 40b132
    SECStatus rv = NSS_RegisterShutdown(serverCAListShutdown, NULL);
Packit 40b132
    PORT_Assert(SECSuccess == rv);
Packit 40b132
    if (SECSuccess == rv) {
Packit 40b132
	ssl3_server_ca_list = CERT_GetSSLCACerts(dbHandle);
Packit 40b132
	return PR_SUCCESS;
Packit 40b132
    }
Packit 40b132
    return PR_FAILURE;
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus
Packit 40b132
ssl_ConfigSecureServer(sslSocket *ss, CERTCertificate *cert,
Packit 40b132
                       const CERTCertificateList *certChain,
Packit 40b132
                       ssl3KeyPair *keyPair, SSLKEAType kea)
Packit 40b132
{
Packit 40b132
    CERTCertificateList *localCertChain = NULL;
Packit 40b132
    sslServerCerts  *sc = ss->serverCerts + kea;
Packit 40b132
Packit 40b132
    /* load the server certificate */
Packit 40b132
    if (sc->serverCert != NULL) {
Packit 40b132
	CERT_DestroyCertificate(sc->serverCert);
Packit 40b132
    	sc->serverCert = NULL;
Packit 40b132
        sc->serverKeyBits = 0;
Packit 40b132
    }
Packit 40b132
    /* load the server cert chain */
Packit 40b132
    if (sc->serverCertChain != NULL) {
Packit 40b132
	CERT_DestroyCertificateList(sc->serverCertChain);
Packit 40b132
    	sc->serverCertChain = NULL;
Packit 40b132
    }
Packit 40b132
    if (cert) {
Packit 40b132
        sc->serverCert = CERT_DupCertificate(cert);
Packit 40b132
        /* get the size of the cert's public key, and remember it */
Packit 40b132
        sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey);
Packit 40b132
        if (!certChain) {
Packit 40b132
            localCertChain =
Packit 40b132
                CERT_CertChainFromCert(sc->serverCert, certUsageSSLServer,
Packit 40b132
                                       PR_TRUE);
Packit 40b132
            if (!localCertChain)
Packit 40b132
                goto loser;
Packit 40b132
        }
Packit 40b132
        sc->serverCertChain = (certChain) ? CERT_DupCertList(certChain) :
Packit 40b132
                                            localCertChain;
Packit 40b132
        if (!sc->serverCertChain) {
Packit 40b132
            goto loser;
Packit 40b132
        }
Packit 40b132
        localCertChain = NULL;      /* consumed */
Packit 40b132
    }
Packit 40b132
Packit 40b132
    /* get keyPair */
Packit 40b132
    if (sc->serverKeyPair != NULL) {
Packit 40b132
        ssl3_FreeKeyPair(sc->serverKeyPair);
Packit 40b132
        sc->serverKeyPair = NULL;
Packit 40b132
    }
Packit 40b132
    if (keyPair) {
Packit 40b132
        SECKEY_CacheStaticFlags(keyPair->privKey);
Packit 40b132
        sc->serverKeyPair = ssl3_GetKeyPairRef(keyPair);
Packit 40b132
    }
Packit 40b132
    if (kea == kt_rsa && cert && sc->serverKeyBits > 512 &&
Packit 40b132
        !ss->opt.noStepDown && !ss->stepDownKeyPair) { 
Packit 40b132
        if (ssl3_CreateRSAStepDownKeys(ss) != SECSuccess) {
Packit 40b132
            goto loser;
Packit 40b132
        }
Packit 40b132
    }
Packit 40b132
    if (kea == ssl_kea_dh || kea == ssl_kea_rsa) {
Packit 40b132
        if (ssl3_SelectDHParams(ss) != SECSuccess) {
Packit 40b132
            goto loser;
Packit 40b132
        }
Packit 40b132
     }
Packit 40b132
    return SECSuccess;
Packit 40b132
Packit 40b132
loser:
Packit 40b132
    if (localCertChain) {
Packit 40b132
        CERT_DestroyCertificateList(localCertChain);
Packit 40b132
    }
Packit 40b132
    if (sc->serverCert != NULL) {
Packit 40b132
	CERT_DestroyCertificate(sc->serverCert);
Packit 40b132
	sc->serverCert = NULL;
Packit 40b132
    }
Packit 40b132
    if (sc->serverCertChain != NULL) {
Packit 40b132
	CERT_DestroyCertificateList(sc->serverCertChain);
Packit 40b132
	sc->serverCertChain = NULL;
Packit 40b132
    }
Packit 40b132
    if (sc->serverKeyPair != NULL) {
Packit 40b132
	ssl3_FreeKeyPair(sc->serverKeyPair);
Packit 40b132
	sc->serverKeyPair = NULL;
Packit 40b132
    }
Packit 40b132
    return SECFailure;
Packit 40b132
}
Packit 40b132
Packit 40b132
/* XXX need to protect the data that gets changed here.!! */
Packit 40b132
Packit 40b132
SECStatus
Packit 40b132
SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert,
Packit 40b132
		       SECKEYPrivateKey *key, SSL3KEAType kea)
Packit 40b132
{
Packit 40b132
Packit 40b132
    return SSL_ConfigSecureServerWithCertChain(fd, cert, NULL, key, kea);
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus
Packit 40b132
SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert,
Packit 40b132
                                    const CERTCertificateList *certChainOpt,
Packit 40b132
                                    SECKEYPrivateKey *key, SSL3KEAType kea)
Packit 40b132
{
Packit 40b132
    sslSocket *ss;
Packit 40b132
    SECKEYPublicKey *pubKey = NULL;
Packit 40b132
    ssl3KeyPair *keyPair = NULL;
Packit 40b132
    SECStatus rv = SECFailure;
Packit 40b132
Packit 40b132
    ss = ssl_FindSocket(fd);
Packit 40b132
    if (!ss) {
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    /* Both key and cert must have a value or be NULL */
Packit 40b132
    /* Passing a value of NULL will turn off key exchange algorithms that were
Packit 40b132
     * previously turned on */
Packit 40b132
    if (!cert != !key) {
Packit 40b132
	PORT_SetError(SEC_ERROR_INVALID_ARGS);
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    /* make sure the key exchange is recognized */
Packit 40b132
    if ((kea >= kt_kea_size) || (kea < kt_null)) {
Packit 40b132
	PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (kea != NSS_FindCertKEAType(cert)) {
Packit 40b132
    	PORT_SetError(SSL_ERROR_CERT_KEA_MISMATCH);
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (cert) {
Packit 40b132
    	/* get the size of the cert's public key, and remember it */
Packit 40b132
	pubKey = CERT_ExtractPublicKey(cert);
Packit 40b132
	if (!pubKey) 
Packit 40b132
            return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (key) {
Packit 40b132
	SECKEYPrivateKey * keyCopy	= NULL;
Packit 40b132
	CK_MECHANISM_TYPE  keyMech	= CKM_INVALID_MECHANISM;
Packit 40b132
Packit 40b132
	if (key->pkcs11Slot) {
Packit 40b132
	    PK11SlotInfo * bestSlot;
Packit 40b132
	    bestSlot = PK11_ReferenceSlot(key->pkcs11Slot);
Packit 40b132
	    if (bestSlot) {
Packit 40b132
		keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key);
Packit 40b132
		PK11_FreeSlot(bestSlot);
Packit 40b132
	    }
Packit 40b132
	}
Packit 40b132
	if (keyCopy == NULL)
Packit 40b132
	    keyMech = PK11_MapSignKeyType(key->keyType);
Packit 40b132
	if (keyMech != CKM_INVALID_MECHANISM) {
Packit 40b132
	    PK11SlotInfo * bestSlot;
Packit 40b132
	    /* XXX Maybe should be bestSlotMultiple? */
Packit 40b132
	    bestSlot = PK11_GetBestSlot(keyMech, NULL /* wincx */);
Packit 40b132
	    if (bestSlot) {
Packit 40b132
		keyCopy = PK11_CopyTokenPrivKeyToSessionPrivKey(bestSlot, key);
Packit 40b132
		PK11_FreeSlot(bestSlot);
Packit 40b132
	    }
Packit 40b132
	}
Packit 40b132
	if (keyCopy == NULL)
Packit 40b132
	    keyCopy = SECKEY_CopyPrivateKey(key);
Packit 40b132
	if (keyCopy == NULL)
Packit 40b132
	    goto loser;
Packit 40b132
        keyPair = ssl3_NewKeyPair(keyCopy, pubKey);
Packit 40b132
        if (keyPair == NULL) {
Packit 40b132
            SECKEY_DestroyPrivateKey(keyCopy);
Packit 40b132
            goto loser;
Packit 40b132
        }
Packit 40b132
	pubKey = NULL; /* adopted by serverKeyPair */
Packit 40b132
    }
Packit 40b132
    if (ssl_ConfigSecureServer(ss, cert, certChainOpt,
Packit 40b132
                               keyPair, kea) == SECFailure) {
Packit 40b132
        goto loser;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    /* Only do this once because it's global. */
Packit 40b132
    if (PR_SUCCESS == PR_CallOnceWithArg(&setupServerCAListOnce, 
Packit 40b132
                                         &serverCAListSetup,
Packit 40b132
                                         (void *)(ss->dbHandle))) {
Packit 40b132
        rv = SECSuccess;
Packit 40b132
    }
Packit 40b132
Packit 40b132
loser:
Packit 40b132
    if (keyPair) {
Packit 40b132
        ssl3_FreeKeyPair(keyPair);
Packit 40b132
    }
Packit 40b132
    if (pubKey) {
Packit 40b132
	SECKEY_DestroyPublicKey(pubKey); 
Packit 40b132
	pubKey = NULL;
Packit 40b132
    }
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
/************************************************************************/
Packit 40b132
Packit 40b132
SECStatus
Packit 40b132
ssl_CreateSecurityInfo(sslSocket *ss)
Packit 40b132
{
Packit 40b132
    SECStatus status;
Packit 40b132
Packit 40b132
    /* initialize sslv2 socket to send data in the clear. */
Packit 40b132
    ssl2_UseClearSendFunc(ss);
Packit 40b132
Packit 40b132
    ss->sec.blockSize  = 1;
Packit 40b132
    ss->sec.blockShift = 0;
Packit 40b132
Packit 40b132
    ssl_GetXmitBufLock(ss); 
Packit 40b132
    status = sslBuffer_Grow(&ss->sec.writeBuf, 4096);
Packit 40b132
    ssl_ReleaseXmitBufLock(ss); 
Packit 40b132
Packit 40b132
    return status;
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus
Packit 40b132
ssl_CopySecurityInfo(sslSocket *ss, sslSocket *os)
Packit 40b132
{
Packit 40b132
    ss->sec.send 		= os->sec.send;
Packit 40b132
    ss->sec.isServer 		= os->sec.isServer;
Packit 40b132
    ss->sec.keyBits    		= os->sec.keyBits;
Packit 40b132
    ss->sec.secretKeyBits 	= os->sec.secretKeyBits;
Packit 40b132
Packit 40b132
    ss->sec.peerCert   		= CERT_DupCertificate(os->sec.peerCert);
Packit 40b132
    if (os->sec.peerCert && !ss->sec.peerCert)
Packit 40b132
    	goto loser;
Packit 40b132
Packit 40b132
    ss->sec.cache      		= os->sec.cache;
Packit 40b132
    ss->sec.uncache    		= os->sec.uncache;
Packit 40b132
Packit 40b132
    /* we don't dup the connection info. */
Packit 40b132
Packit 40b132
    ss->sec.sendSequence 	= os->sec.sendSequence;
Packit 40b132
    ss->sec.rcvSequence 	= os->sec.rcvSequence;
Packit 40b132
Packit 40b132
    if (os->sec.hash && os->sec.hashcx) {
Packit 40b132
	ss->sec.hash 		= os->sec.hash;
Packit 40b132
	ss->sec.hashcx 		= os->sec.hash->clone(os->sec.hashcx);
Packit 40b132
	if (os->sec.hashcx && !ss->sec.hashcx)
Packit 40b132
	    goto loser;
Packit 40b132
    } else {
Packit 40b132
	ss->sec.hash 		= NULL;
Packit 40b132
	ss->sec.hashcx 		= NULL;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (SECITEM_CopyItem(0, &ss->sec.sendSecret, &os->sec.sendSecret))
Packit 40b132
    	goto loser;
Packit 40b132
    if (SECITEM_CopyItem(0, &ss->sec.rcvSecret,  &os->sec.rcvSecret))
Packit 40b132
    	goto loser;
Packit 40b132
Packit 40b132
    /* XXX following code is wrong if either cx != 0 */
Packit 40b132
    PORT_Assert(os->sec.readcx  == 0);
Packit 40b132
    PORT_Assert(os->sec.writecx == 0);
Packit 40b132
    ss->sec.readcx     		= os->sec.readcx;
Packit 40b132
    ss->sec.writecx    		= os->sec.writecx;
Packit 40b132
    ss->sec.destroy    		= 0;	
Packit 40b132
Packit 40b132
    ss->sec.enc        		= os->sec.enc;
Packit 40b132
    ss->sec.dec        		= os->sec.dec;
Packit 40b132
Packit 40b132
    ss->sec.blockShift 		= os->sec.blockShift;
Packit 40b132
    ss->sec.blockSize  		= os->sec.blockSize;
Packit 40b132
Packit 40b132
    return SECSuccess;
Packit 40b132
Packit 40b132
loser:
Packit 40b132
    return SECFailure;
Packit 40b132
}
Packit 40b132
Packit 40b132
/* Reset sec back to its initial state.
Packit 40b132
** Caller holds any relevant locks.
Packit 40b132
*/
Packit 40b132
void 
Packit 40b132
ssl_ResetSecurityInfo(sslSecurityInfo *sec, PRBool doMemset)
Packit 40b132
{
Packit 40b132
    /* Destroy MAC */
Packit 40b132
    if (sec->hash && sec->hashcx) {
Packit 40b132
	(*sec->hash->destroy)(sec->hashcx, PR_TRUE);
Packit 40b132
	sec->hashcx = NULL;
Packit 40b132
	sec->hash = NULL;
Packit 40b132
    }
Packit 40b132
    SECITEM_ZfreeItem(&sec->sendSecret, PR_FALSE);
Packit 40b132
    SECITEM_ZfreeItem(&sec->rcvSecret, PR_FALSE);
Packit 40b132
Packit 40b132
    /* Destroy ciphers */
Packit 40b132
    if (sec->destroy) {
Packit 40b132
	(*sec->destroy)(sec->readcx, PR_TRUE);
Packit 40b132
	(*sec->destroy)(sec->writecx, PR_TRUE);
Packit 40b132
	sec->readcx = NULL;
Packit 40b132
	sec->writecx = NULL;
Packit 40b132
    } else {
Packit 40b132
	PORT_Assert(sec->readcx == 0);
Packit 40b132
	PORT_Assert(sec->writecx == 0);
Packit 40b132
    }
Packit 40b132
    sec->readcx = 0;
Packit 40b132
    sec->writecx = 0;
Packit 40b132
Packit 40b132
    if (sec->localCert) {
Packit 40b132
	CERT_DestroyCertificate(sec->localCert);
Packit 40b132
	sec->localCert = NULL;
Packit 40b132
    }
Packit 40b132
    if (sec->peerCert) {
Packit 40b132
	CERT_DestroyCertificate(sec->peerCert);
Packit 40b132
	sec->peerCert = NULL;
Packit 40b132
    }
Packit 40b132
    if (sec->peerKey) {
Packit 40b132
	SECKEY_DestroyPublicKey(sec->peerKey);
Packit 40b132
	sec->peerKey = NULL;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    /* cleanup the ci */
Packit 40b132
    if (sec->ci.sid != NULL) {
Packit 40b132
	ssl_FreeSID(sec->ci.sid);
Packit 40b132
    }
Packit 40b132
    PORT_ZFree(sec->ci.sendBuf.buf, sec->ci.sendBuf.space);
Packit 40b132
    if (doMemset) {
Packit 40b132
        memset(&sec->ci, 0, sizeof sec->ci);
Packit 40b132
    }
Packit 40b132
    
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
** Called from SSL_ResetHandshake (above), and 
Packit 40b132
**        from ssl_FreeSocket     in sslsock.c
Packit 40b132
** Caller should hold relevant locks (e.g. XmitBufLock)
Packit 40b132
*/
Packit 40b132
void 
Packit 40b132
ssl_DestroySecurityInfo(sslSecurityInfo *sec)
Packit 40b132
{
Packit 40b132
    ssl_ResetSecurityInfo(sec, PR_FALSE);
Packit 40b132
Packit 40b132
    PORT_ZFree(sec->writeBuf.buf, sec->writeBuf.space);
Packit 40b132
    sec->writeBuf.buf = 0;
Packit 40b132
Packit 40b132
    memset(sec, 0, sizeof *sec);
Packit 40b132
}
Packit 40b132
Packit 40b132
/************************************************************************/
Packit 40b132
Packit 40b132
int 
Packit 40b132
ssl_SecureConnect(sslSocket *ss, const PRNetAddr *sa)
Packit 40b132
{
Packit 40b132
    PRFileDesc *osfd = ss->fd->lower;
Packit 40b132
    int rv;
Packit 40b132
Packit 40b132
    if ( ss->opt.handshakeAsServer ) {
Packit 40b132
	ss->securityHandshake = ssl2_BeginServerHandshake;
Packit 40b132
	ss->handshaking = sslHandshakingAsServer;
Packit 40b132
    } else {
Packit 40b132
	ss->securityHandshake = ssl2_BeginClientHandshake;
Packit 40b132
	ss->handshaking = sslHandshakingAsClient;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    /* connect to server */
Packit 40b132
    rv = osfd->methods->connect(osfd, sa, ss->cTimeout);
Packit 40b132
    if (rv == PR_SUCCESS) {
Packit 40b132
	ss->TCPconnected = 1;
Packit 40b132
    } else {
Packit 40b132
	int err = PR_GetError();
Packit 40b132
	SSL_DBG(("%d: SSL[%d]: connect failed, errno=%d",
Packit 40b132
		 SSL_GETPID(), ss->fd, err));
Packit 40b132
	if (err == PR_IS_CONNECTED_ERROR) {
Packit 40b132
	    ss->TCPconnected = 1;
Packit 40b132
	} 
Packit 40b132
    }
Packit 40b132
Packit 40b132
    SSL_TRC(5, ("%d: SSL[%d]: secure connect completed, rv == %d",
Packit 40b132
		SSL_GETPID(), ss->fd, rv));
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * The TLS 1.2 RFC 5246, Section 7.2.1 says:
Packit 40b132
 *
Packit 40b132
 *     Unless some other fatal alert has been transmitted, each party is
Packit 40b132
 *     required to send a close_notify alert before closing the write side
Packit 40b132
 *     of the connection.  The other party MUST respond with a close_notify
Packit 40b132
 *     alert of its own and close down the connection immediately,
Packit 40b132
 *     discarding any pending writes.  It is not required for the initiator
Packit 40b132
 *     of the close to wait for the responding close_notify alert before
Packit 40b132
 *     closing the read side of the connection.
Packit 40b132
 *
Packit 40b132
 * The second sentence requires that we send a close_notify alert when we
Packit 40b132
 * have received a close_notify alert.  In practice, all SSL implementations
Packit 40b132
 * close the socket immediately after sending a close_notify alert (which is
Packit 40b132
 * allowed by the third sentence), so responding with a close_notify alert
Packit 40b132
 * would result in a write failure with the ECONNRESET error.  This is why
Packit 40b132
 * we don't respond with a close_notify alert.
Packit 40b132
 *
Packit 40b132
 * Also, in the unlikely event that the TCP pipe is full and the peer stops
Packit 40b132
 * reading, the SSL3_SendAlert call in ssl_SecureClose and ssl_SecureShutdown
Packit 40b132
 * may block indefinitely in blocking mode, and may fail (without retrying)
Packit 40b132
 * in non-blocking mode.
Packit 40b132
 */
Packit 40b132
Packit 40b132
int
Packit 40b132
ssl_SecureClose(sslSocket *ss)
Packit 40b132
{
Packit 40b132
    int rv;
Packit 40b132
Packit 40b132
    if (ss->version >= SSL_LIBRARY_VERSION_3_0 	&&
Packit 40b132
	!(ss->shutdownHow & ssl_SHUTDOWN_SEND)	&&
Packit 40b132
    	ss->firstHsDone 			&& 
Packit 40b132
	!ss->recvdCloseNotify                   &&
Packit 40b132
	ss->ssl3.initialized) {
Packit 40b132
Packit 40b132
	/* We don't want the final alert to be Nagle delayed. */
Packit 40b132
	if (!ss->delayDisabled) {
Packit 40b132
	    ssl_EnableNagleDelay(ss, PR_FALSE);
Packit 40b132
	    ss->delayDisabled = 1;
Packit 40b132
	}
Packit 40b132
Packit 40b132
	(void) SSL3_SendAlert(ss, alert_warning, close_notify);
Packit 40b132
    }
Packit 40b132
    rv = ssl_DefClose(ss);
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
/* Caller handles all locking */
Packit 40b132
int
Packit 40b132
ssl_SecureShutdown(sslSocket *ss, int nsprHow)
Packit 40b132
{
Packit 40b132
    PRFileDesc *osfd = ss->fd->lower;
Packit 40b132
    int 	rv;
Packit 40b132
    PRIntn	sslHow	= nsprHow + 1;
Packit 40b132
Packit 40b132
    if ((unsigned)nsprHow > PR_SHUTDOWN_BOTH) {
Packit 40b132
	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
Packit 40b132
    	return PR_FAILURE;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if ((sslHow & ssl_SHUTDOWN_SEND) != 0 		&&
Packit 40b132
    	ss->version >= SSL_LIBRARY_VERSION_3_0		&&
Packit 40b132
	!(ss->shutdownHow & ssl_SHUTDOWN_SEND)		&&
Packit 40b132
	ss->firstHsDone 				&& 
Packit 40b132
	!ss->recvdCloseNotify                   	&&
Packit 40b132
	ss->ssl3.initialized) {
Packit 40b132
Packit 40b132
	(void) SSL3_SendAlert(ss, alert_warning, close_notify);
Packit 40b132
    }
Packit 40b132
Packit 40b132
    rv = osfd->methods->shutdown(osfd, nsprHow);
Packit 40b132
Packit 40b132
    ss->shutdownHow |= sslHow;
Packit 40b132
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
/************************************************************************/
Packit 40b132
Packit 40b132
Packit 40b132
int
Packit 40b132
ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags)
Packit 40b132
{
Packit 40b132
    sslSecurityInfo *sec;
Packit 40b132
    int              rv   = 0;
Packit 40b132
Packit 40b132
    sec = &ss->sec;
Packit 40b132
Packit 40b132
    if (ss->shutdownHow & ssl_SHUTDOWN_RCV) {
Packit 40b132
	PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR);
Packit 40b132
    	return PR_FAILURE;
Packit 40b132
    }
Packit 40b132
    if (flags & ~PR_MSG_PEEK) {
Packit 40b132
	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
Packit 40b132
    	return PR_FAILURE;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (!ssl_SocketIsBlocking(ss) && !ss->opt.fdx) {
Packit 40b132
	ssl_GetXmitBufLock(ss);
Packit 40b132
	if (ss->pendingBuf.len != 0) {
Packit 40b132
	    rv = ssl_SendSavedWriteData(ss);
Packit 40b132
	    if ((rv < 0) && (PORT_GetError() != PR_WOULD_BLOCK_ERROR)) {
Packit 40b132
		ssl_ReleaseXmitBufLock(ss);
Packit 40b132
		return SECFailure;
Packit 40b132
	    }
Packit 40b132
	}
Packit 40b132
	ssl_ReleaseXmitBufLock(ss);
Packit 40b132
    }
Packit 40b132
    
Packit 40b132
    rv = 0;
Packit 40b132
    /* If any of these is non-zero, the initial handshake is not done. */
Packit 40b132
    if (!ss->firstHsDone) {
Packit 40b132
	ssl_Get1stHandshakeLock(ss);
Packit 40b132
	if (ss->handshake || ss->nextHandshake || ss->securityHandshake) {
Packit 40b132
	    rv = ssl_Do1stHandshake(ss);
Packit 40b132
	}
Packit 40b132
	ssl_Release1stHandshakeLock(ss);
Packit 40b132
    }
Packit 40b132
    if (rv < 0) {
Packit 40b132
	return rv;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (len == 0) return 0;
Packit 40b132
Packit 40b132
    rv = DoRecv(ss, (unsigned char*) buf, len, flags);
Packit 40b132
    SSL_TRC(2, ("%d: SSL[%d]: recving %d bytes securely (errno=%d)",
Packit 40b132
		SSL_GETPID(), ss->fd, rv, PORT_GetError()));
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
int
Packit 40b132
ssl_SecureRead(sslSocket *ss, unsigned char *buf, int len)
Packit 40b132
{
Packit 40b132
    return ssl_SecureRecv(ss, buf, len, 0);
Packit 40b132
}
Packit 40b132
Packit 40b132
/* Caller holds the SSL Socket's write lock. SSL_LOCK_WRITER(ss) */
Packit 40b132
int
Packit 40b132
ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags)
Packit 40b132
{
Packit 40b132
    int rv = 0;
Packit 40b132
Packit 40b132
    SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes",
Packit 40b132
		SSL_GETPID(), ss->fd, len));
Packit 40b132
Packit 40b132
    if (ss->shutdownHow & ssl_SHUTDOWN_SEND) {
Packit 40b132
	PORT_SetError(PR_SOCKET_SHUTDOWN_ERROR);
Packit 40b132
    	rv = PR_FAILURE;
Packit 40b132
	goto done;
Packit 40b132
    }
Packit 40b132
    if (flags) {
Packit 40b132
	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
Packit 40b132
    	rv = PR_FAILURE;
Packit 40b132
	goto done;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    ssl_GetXmitBufLock(ss);
Packit 40b132
    if (ss->pendingBuf.len != 0) {
Packit 40b132
	PORT_Assert(ss->pendingBuf.len > 0);
Packit 40b132
	rv = ssl_SendSavedWriteData(ss);
Packit 40b132
	if (rv >= 0 && ss->pendingBuf.len != 0) {
Packit 40b132
	    PORT_Assert(ss->pendingBuf.len > 0);
Packit 40b132
	    PORT_SetError(PR_WOULD_BLOCK_ERROR);
Packit 40b132
	    rv = SECFailure;
Packit 40b132
	}
Packit 40b132
    }
Packit 40b132
    ssl_ReleaseXmitBufLock(ss);
Packit 40b132
    if (rv < 0) {
Packit 40b132
	goto done;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (len > 0) 
Packit 40b132
    	ss->writerThread = PR_GetCurrentThread();
Packit 40b132
    /* If any of these is non-zero, the initial handshake is not done. */
Packit 40b132
    if (!ss->firstHsDone) {
Packit 40b132
	PRBool falseStart = PR_FALSE;
Packit 40b132
	ssl_Get1stHandshakeLock(ss);
Packit 40b132
	if (ss->opt.enableFalseStart &&
Packit 40b132
	    ss->version >= SSL_LIBRARY_VERSION_3_0) {
Packit 40b132
	    ssl_GetSSL3HandshakeLock(ss);
Packit 40b132
	    falseStart = ss->ssl3.hs.canFalseStart;
Packit 40b132
	    ssl_ReleaseSSL3HandshakeLock(ss);
Packit 40b132
	}
Packit 40b132
	if (!falseStart &&
Packit 40b132
	    (ss->handshake || ss->nextHandshake || ss->securityHandshake)) {
Packit 40b132
	    rv = ssl_Do1stHandshake(ss);
Packit 40b132
	}
Packit 40b132
	ssl_Release1stHandshakeLock(ss);
Packit 40b132
    }
Packit 40b132
    if (rv < 0) {
Packit 40b132
    	ss->writerThread = NULL;
Packit 40b132
	goto done;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    /* Check for zero length writes after we do housekeeping so we make forward
Packit 40b132
     * progress.
Packit 40b132
     */
Packit 40b132
    if (len == 0) {
Packit 40b132
    	rv = 0;
Packit 40b132
	goto done;
Packit 40b132
    }
Packit 40b132
    PORT_Assert(buf != NULL);
Packit 40b132
    if (!buf) {
Packit 40b132
	PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
Packit 40b132
    	rv = PR_FAILURE;
Packit 40b132
	goto done;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    if (!ss->firstHsDone) {
Packit 40b132
	PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_3_0);
Packit 40b132
#ifdef DEBUG
Packit 40b132
	ssl_GetSSL3HandshakeLock(ss);
Packit 40b132
	PORT_Assert(ss->ssl3.hs.canFalseStart);
Packit 40b132
	ssl_ReleaseSSL3HandshakeLock(ss);
Packit 40b132
#endif
Packit 40b132
	SSL_TRC(3, ("%d: SSL[%d]: SecureSend: sending data due to false start",
Packit 40b132
		    SSL_GETPID(), ss->fd));
Packit 40b132
    }
Packit 40b132
Packit 40b132
    /* Send out the data using one of these functions:
Packit 40b132
     *	ssl2_SendClear, ssl2_SendStream, ssl2_SendBlock, 
Packit 40b132
     *  ssl3_SendApplicationData
Packit 40b132
     */
Packit 40b132
    ssl_GetXmitBufLock(ss);
Packit 40b132
    rv = (*ss->sec.send)(ss, buf, len, flags);
Packit 40b132
    ssl_ReleaseXmitBufLock(ss);
Packit 40b132
    ss->writerThread = NULL;
Packit 40b132
done:
Packit 40b132
    if (rv < 0) {
Packit 40b132
	SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count, error %d",
Packit 40b132
		    SSL_GETPID(), ss->fd, rv, PORT_GetError()));
Packit 40b132
    } else {
Packit 40b132
	SSL_TRC(2, ("%d: SSL[%d]: SecureSend: returning %d count",
Packit 40b132
		    SSL_GETPID(), ss->fd, rv));
Packit 40b132
    }
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
int
Packit 40b132
ssl_SecureWrite(sslSocket *ss, const unsigned char *buf, int len)
Packit 40b132
{
Packit 40b132
    return ssl_SecureSend(ss, buf, len, 0);
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus
Packit 40b132
SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f, void *arg)
Packit 40b132
{
Packit 40b132
    sslSocket *ss;
Packit 40b132
    
Packit 40b132
    ss = ssl_FindSocket(fd);
Packit 40b132
    if (!ss) {
Packit 40b132
	SSL_DBG(("%d: SSL[%d]: bad socket in SSLBadCertHook",
Packit 40b132
		 SSL_GETPID(), fd));
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    ss->handleBadCert = f;
Packit 40b132
    ss->badCertArg = arg;
Packit 40b132
Packit 40b132
    return SECSuccess;
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * Allow the application to pass the url or hostname into the SSL library
Packit 40b132
 * so that we can do some checking on it. It will be used for the value in
Packit 40b132
 * SNI extension of client hello message.
Packit 40b132
 */
Packit 40b132
SECStatus
Packit 40b132
SSL_SetURL(PRFileDesc *fd, const char *url)
Packit 40b132
{
Packit 40b132
    sslSocket *   ss = ssl_FindSocket(fd);
Packit 40b132
    SECStatus     rv = SECSuccess;
Packit 40b132
Packit 40b132
    if (!ss) {
Packit 40b132
	SSL_DBG(("%d: SSL[%d]: bad socket in SSLSetURL",
Packit 40b132
		 SSL_GETPID(), fd));
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
    ssl_Get1stHandshakeLock(ss);
Packit 40b132
    ssl_GetSSL3HandshakeLock(ss);
Packit 40b132
Packit 40b132
    if ( ss->url ) {
Packit 40b132
	PORT_Free((void *)ss->url);	/* CONST */
Packit 40b132
    }
Packit 40b132
Packit 40b132
    ss->url = (const char *)PORT_Strdup(url);
Packit 40b132
    if ( ss->url == NULL ) {
Packit 40b132
	rv = SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    ssl_ReleaseSSL3HandshakeLock(ss);
Packit 40b132
    ssl_Release1stHandshakeLock(ss);
Packit 40b132
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
 * Allow the application to pass the set of trust anchors
Packit 40b132
 */
Packit 40b132
SECStatus
Packit 40b132
SSL_SetTrustAnchors(PRFileDesc *fd, CERTCertList *certList)
Packit 40b132
{
Packit 40b132
    sslSocket *   ss = ssl_FindSocket(fd);
Packit 40b132
    CERTDistNames *names = NULL;
Packit 40b132
Packit 40b132
    if (!certList) {
Packit 40b132
        PORT_SetError(SEC_ERROR_INVALID_ARGS);
Packit 40b132
        return SECFailure;
Packit 40b132
    }
Packit 40b132
    if (!ss) {
Packit 40b132
	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetTrustAnchors",
Packit 40b132
		 SSL_GETPID(), fd));
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    names = CERT_DistNamesFromCertList(certList);
Packit 40b132
    if (names == NULL) {
Packit 40b132
        return SECFailure;
Packit 40b132
    }
Packit 40b132
    ssl_Get1stHandshakeLock(ss);
Packit 40b132
    ssl_GetSSL3HandshakeLock(ss);
Packit 40b132
    if (ss->ssl3.ca_list) {
Packit 40b132
        CERT_FreeDistNames(ss->ssl3.ca_list);
Packit 40b132
    }
Packit 40b132
    ss->ssl3.ca_list = names;
Packit 40b132
    ssl_ReleaseSSL3HandshakeLock(ss);
Packit 40b132
    ssl_Release1stHandshakeLock(ss);
Packit 40b132
Packit 40b132
    return SECSuccess;
Packit 40b132
}
Packit 40b132
Packit 40b132
/*
Packit 40b132
** Returns Negative number on error, zero or greater on success.
Packit 40b132
** Returns the amount of data immediately available to be read.
Packit 40b132
*/
Packit 40b132
int
Packit 40b132
SSL_DataPending(PRFileDesc *fd)
Packit 40b132
{
Packit 40b132
    sslSocket *ss;
Packit 40b132
    int        rv  = 0;
Packit 40b132
Packit 40b132
    ss = ssl_FindSocket(fd);
Packit 40b132
Packit 40b132
    if (ss && ss->opt.useSecurity) {
Packit 40b132
	ssl_GetRecvBufLock(ss);
Packit 40b132
	rv = ss->gs.writeOffset - ss->gs.readOffset;
Packit 40b132
	ssl_ReleaseRecvBufLock(ss);
Packit 40b132
    }
Packit 40b132
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus
Packit 40b132
SSL_InvalidateSession(PRFileDesc *fd)
Packit 40b132
{
Packit 40b132
    sslSocket *   ss = ssl_FindSocket(fd);
Packit 40b132
    SECStatus     rv = SECFailure;
Packit 40b132
Packit 40b132
    if (ss) {
Packit 40b132
	ssl_Get1stHandshakeLock(ss);
Packit 40b132
	ssl_GetSSL3HandshakeLock(ss);
Packit 40b132
Packit 40b132
	if (ss->sec.ci.sid && ss->sec.uncache) {
Packit 40b132
	    ss->sec.uncache(ss->sec.ci.sid);
Packit 40b132
	    rv = SECSuccess;
Packit 40b132
	}
Packit 40b132
Packit 40b132
	ssl_ReleaseSSL3HandshakeLock(ss);
Packit 40b132
	ssl_Release1stHandshakeLock(ss);
Packit 40b132
    }
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
SECItem *
Packit 40b132
SSL_GetSessionID(PRFileDesc *fd)
Packit 40b132
{
Packit 40b132
    sslSocket *    ss;
Packit 40b132
    SECItem *      item = NULL;
Packit 40b132
Packit 40b132
    ss = ssl_FindSocket(fd);
Packit 40b132
    if (ss) {
Packit 40b132
	ssl_Get1stHandshakeLock(ss);
Packit 40b132
	ssl_GetSSL3HandshakeLock(ss);
Packit 40b132
Packit 40b132
	if (ss->opt.useSecurity && ss->firstHsDone && ss->sec.ci.sid) {
Packit 40b132
	    item = (SECItem *)PORT_Alloc(sizeof(SECItem));
Packit 40b132
	    if (item) {
Packit 40b132
		sslSessionID * sid = ss->sec.ci.sid;
Packit 40b132
		if (sid->version < SSL_LIBRARY_VERSION_3_0) {
Packit 40b132
		    item->len = SSL2_SESSIONID_BYTES;
Packit 40b132
		    item->data = (unsigned char*)PORT_Alloc(item->len);
Packit 40b132
		    PORT_Memcpy(item->data, sid->u.ssl2.sessionID, item->len);
Packit 40b132
		} else {
Packit 40b132
		    item->len = sid->u.ssl3.sessionIDLength;
Packit 40b132
		    item->data = (unsigned char*)PORT_Alloc(item->len);
Packit 40b132
		    PORT_Memcpy(item->data, sid->u.ssl3.sessionID, item->len);
Packit 40b132
		}
Packit 40b132
	    }
Packit 40b132
	}
Packit 40b132
Packit 40b132
	ssl_ReleaseSSL3HandshakeLock(ss);
Packit 40b132
	ssl_Release1stHandshakeLock(ss);
Packit 40b132
    }
Packit 40b132
    return item;
Packit 40b132
}
Packit 40b132
Packit 40b132
SECStatus
Packit 40b132
SSL_CertDBHandleSet(PRFileDesc *fd, CERTCertDBHandle *dbHandle)
Packit 40b132
{
Packit 40b132
    sslSocket *    ss;
Packit 40b132
Packit 40b132
    ss = ssl_FindSocket(fd);
Packit 40b132
    if (!ss)
Packit 40b132
    	return SECFailure;
Packit 40b132
    if (!dbHandle) {
Packit 40b132
    	PORT_SetError(SEC_ERROR_INVALID_ARGS);
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
    ss->dbHandle = dbHandle;
Packit 40b132
    return SECSuccess;
Packit 40b132
}
Packit 40b132
Packit 40b132
/* DO NOT USE. This function was exported in ssl.def with the wrong signature;
Packit 40b132
 * this implementation exists to maintain link-time compatibility.
Packit 40b132
 */
Packit 40b132
int
Packit 40b132
SSL_RestartHandshakeAfterCertReq(sslSocket *         ss,
Packit 40b132
				CERTCertificate *    cert, 
Packit 40b132
				SECKEYPrivateKey *   key,
Packit 40b132
				CERTCertificateList *certChain)
Packit 40b132
{
Packit 40b132
    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
Packit 40b132
    return -1;
Packit 40b132
}
Packit 40b132
Packit 40b132
/* DO NOT USE. This function was exported in ssl.def with the wrong signature;
Packit 40b132
 * this implementation exists to maintain link-time compatibility.
Packit 40b132
 */
Packit 40b132
int
Packit 40b132
SSL_RestartHandshakeAfterServerCert(sslSocket * ss)
Packit 40b132
{
Packit 40b132
    PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
Packit 40b132
    return -1;
Packit 40b132
}
Packit 40b132
Packit 40b132
/* See documentation in ssl.h */
Packit 40b132
SECStatus
Packit 40b132
SSL_AuthCertificateComplete(PRFileDesc *fd, PRErrorCode error)
Packit 40b132
{
Packit 40b132
    SECStatus rv;
Packit 40b132
    sslSocket *ss = ssl_FindSocket(fd);
Packit 40b132
Packit 40b132
    if (!ss) {
Packit 40b132
	SSL_DBG(("%d: SSL[%d]: bad socket in SSL_AuthCertificateComplete",
Packit 40b132
		 SSL_GETPID(), fd));
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    ssl_Get1stHandshakeLock(ss);
Packit 40b132
Packit 40b132
    if (!ss->ssl3.initialized) {
Packit 40b132
	PORT_SetError(SEC_ERROR_INVALID_ARGS);
Packit 40b132
	rv = SECFailure;
Packit 40b132
    } else if (ss->version < SSL_LIBRARY_VERSION_3_0) {
Packit 40b132
	PORT_SetError(SSL_ERROR_FEATURE_NOT_SUPPORTED_FOR_SSL2);
Packit 40b132
	rv = SECFailure;
Packit 40b132
    } else {
Packit 40b132
	rv = ssl3_AuthCertificateComplete(ss, error);
Packit 40b132
    }
Packit 40b132
Packit 40b132
    ssl_Release1stHandshakeLock(ss);
Packit 40b132
Packit 40b132
    return rv;
Packit 40b132
}
Packit 40b132
Packit 40b132
/* For more info see ssl.h */
Packit 40b132
SECStatus 
Packit 40b132
SSL_SNISocketConfigHook(PRFileDesc *fd, SSLSNISocketConfig func,
Packit 40b132
                        void *arg)
Packit 40b132
{
Packit 40b132
    sslSocket *ss;
Packit 40b132
Packit 40b132
    ss = ssl_FindSocket(fd);
Packit 40b132
    if (!ss) {
Packit 40b132
	SSL_DBG(("%d: SSL[%d]: bad socket in SNISocketConfigHook",
Packit 40b132
		 SSL_GETPID(), fd));
Packit 40b132
	return SECFailure;
Packit 40b132
    }
Packit 40b132
Packit 40b132
    ss->sniSocketConfig = func;
Packit 40b132
    ss->sniSocketConfigArg = arg;
Packit 40b132
    return SECSuccess;
Packit 40b132
}