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 + -
显示快捷键?