diff options
Diffstat (limited to 'security/nss/lib/ssl/sslcon.c')
-rw-r--r-- | security/nss/lib/ssl/sslcon.c | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/security/nss/lib/ssl/sslcon.c b/security/nss/lib/ssl/sslcon.c new file mode 100644 index 000000000..448170640 --- /dev/null +++ b/security/nss/lib/ssl/sslcon.c @@ -0,0 +1,264 @@ +/* + * Basic SSL handshake functions. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nssrenam.h" +#include "cert.h" +#include "secitem.h" +#include "sechash.h" +#include "cryptohi.h" /* for SGN_ funcs */ +#include "keyhi.h" /* for SECKEY_ high level functions. */ +#include "ssl.h" +#include "sslimpl.h" +#include "sslproto.h" +#include "ssl3prot.h" +#include "sslerr.h" +#include "pk11func.h" +#include "prinit.h" +#include "prtime.h" /* for PR_Now() */ + +/* +** Put a string tag in the library so that we can examine an executable +** and see what kind of security it supports. +*/ +const char *ssl_version = "SECURITY_VERSION:" + " +us" + " +export" +#ifdef TRACE + " +trace" +#endif +#ifdef DEBUG + " +debug" +#endif + ; + +/*********************************************************************** + * Gathers in and handles records/messages until either the handshake is + * complete or application data is available. + * + * Called from ssl_Do1stHandshake() via function pointer ss->handshake. + * Caller must hold handshake lock. + * This function acquires and releases the RecvBufLock. + * + * returns SECSuccess for success. + * returns SECWouldBlock when that value is returned by + * ssl3_GatherCompleteHandshake(). + * returns SECFailure on all other errors. + * + * The gather functions called by ssl_GatherRecord1stHandshake are expected + * to return values interpreted as follows: + * 1 : the function completed without error. + * 0 : the function read EOF. + * -1 : read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error. + * -2 : the function wants ssl_GatherRecord1stHandshake to be called again + * immediately, by ssl_Do1stHandshake. + * + * This code is similar to, and easily confused with, DoRecv() in sslsecur.c + * + * This function is called from ssl_Do1stHandshake(). + * The following functions put ssl_GatherRecord1stHandshake into ss->handshake: + * ssl_BeginClientHandshake + * ssl3_RestartHandshakeAfterCertReq + * ssl3_RestartHandshakeAfterServerCert + * ssl_BeginServerHandshake + */ +SECStatus +ssl_GatherRecord1stHandshake(sslSocket *ss) +{ + int rv; + + PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); + + ssl_GetRecvBufLock(ss); + + /* Wait for handshake to complete, or application data to arrive. */ + rv = ssl3_GatherCompleteHandshake(ss, 0); + SSL_TRC(10, ("%d: SSL[%d]: handshake gathering, rv=%d", + SSL_GETPID(), ss->fd, rv)); + + ssl_ReleaseRecvBufLock(ss); + + if (rv <= 0) { + if (rv == SECWouldBlock) { + /* Progress is blocked waiting for callback completion. */ + SSL_TRC(10, ("%d: SSL[%d]: handshake blocked (need %d)", + SSL_GETPID(), ss->fd, ss->gs.remainder)); + return SECWouldBlock; + } + if (rv == 0) { + /* EOF. Loser */ + PORT_SetError(PR_END_OF_FILE_ERROR); + } + return SECFailure; /* rv is < 0 here. */ + } + + ss->handshake = NULL; + return SECSuccess; +} + +/* This function is called at the beginning of a handshake to ensure that at + * least one SSL/TLS version is enabled. */ +static SECStatus +ssl_CheckConfigSanity(sslSocket *ss) +{ + if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) { + SSL_DBG(("%d: SSL[%d]: Can't handshake! all versions disabled.", + SSL_GETPID(), ss->fd)); + PORT_SetError(SSL_ERROR_SSL_DISABLED); + return SECFailure; + } + return SECSuccess; +} + +/* Sends out the initial client Hello message on the connection. + * Acquires and releases the socket's xmitBufLock. + */ +SECStatus +ssl_BeginClientHandshake(sslSocket *ss) +{ + sslSessionID *sid; + SECStatus rv; + + PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); + + ss->sec.isServer = PR_FALSE; + ssl_ChooseSessionIDProcs(&ss->sec); + + rv = ssl_CheckConfigSanity(ss); + if (rv != SECSuccess) + goto loser; + + /* Get peer name of server */ + rv = ssl_GetPeerInfo(ss); + if (rv < 0) { +#ifdef HPUX11 + /* + * On some HP-UX B.11.00 systems, getpeername() occasionally + * fails with ENOTCONN after a successful completion of + * non-blocking connect. I found that if we do a write() + * and then retry getpeername(), it will work. + */ + if (PR_GetError() == PR_NOT_CONNECTED_ERROR) { + char dummy; + (void)PR_Write(ss->fd->lower, &dummy, 0); + rv = ssl_GetPeerInfo(ss); + if (rv < 0) { + goto loser; + } + } +#else + goto loser; +#endif + } + + SSL_TRC(3, ("%d: SSL[%d]: sending client-hello", SSL_GETPID(), ss->fd)); + + /* Try to find server in our session-id cache */ + if (ss->opt.noCache) { + sid = NULL; + } else { + sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, + ss->url); + } + if (sid) { + if (sid->version >= ss->vrange.min && sid->version <= ss->vrange.max) { + PORT_Assert(!ss->sec.localCert); + ss->sec.localCert = CERT_DupCertificate(sid->localCert); + } else { + ss->sec.uncache(sid); + ssl_FreeSID(sid); + sid = NULL; + } + } + if (!sid) { + sid = PORT_ZNew(sslSessionID); + if (!sid) { + goto loser; + } + sid->references = 1; + sid->cached = never_cached; + sid->addr = ss->sec.ci.peer; + sid->port = ss->sec.ci.port; + if (ss->peerID != NULL) { + sid->peerID = PORT_Strdup(ss->peerID); + } + if (ss->url != NULL) { + sid->urlSvrName = PORT_Strdup(ss->url); + } + } + ss->sec.ci.sid = sid; + + PORT_Assert(sid != NULL); + + ss->gs.state = GS_INIT; + ss->handshake = ssl_GatherRecord1stHandshake; + + /* ssl3_SendClientHello will override this if it succeeds. */ + ss->version = SSL_LIBRARY_VERSION_3_0; + + ssl_GetSSL3HandshakeLock(ss); + ssl_GetXmitBufLock(ss); + rv = ssl3_SendClientHello(ss, client_hello_initial); + ssl_ReleaseXmitBufLock(ss); + ssl_ReleaseSSL3HandshakeLock(ss); + + return rv; + +loser: + return SECFailure; +} + +SECStatus +ssl_BeginServerHandshake(sslSocket *ss) +{ + SECStatus rv; + + ss->sec.isServer = PR_TRUE; + ss->ssl3.hs.ws = wait_client_hello; + ssl_ChooseSessionIDProcs(&ss->sec); + + rv = ssl_CheckConfigSanity(ss); + if (rv != SECSuccess) + goto loser; + + ss->handshake = ssl_GatherRecord1stHandshake; + return SECSuccess; + +loser: + return SECFailure; +} + +/* This function doesn't really belong in this file. +** It's here to keep AIX compilers from optimizing it away, +** and not including it in the DSO. +*/ + +#include "nss.h" +extern const char __nss_ssl_version[]; + +PRBool +NSSSSL_VersionCheck(const char *importedVersion) +{ +#define NSS_VERSION_VARIABLE __nss_ssl_version +#include "verref.h" + + /* + * This is the secret handshake algorithm. + * + * This release has a simple version compatibility + * check algorithm. This release is not backward + * compatible with previous major releases. It is + * not compatible with future major, minor, or + * patch releases. + */ + return NSS_VersionCheck(importedVersion); +} + +const char * +NSSSSL_GetVersion(void) +{ + return NSS_VERSION; +} |