| /* |
| * 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 = NULL; |
| SECStatus rv; |
| |
| PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss)); |
| |
| ss->sec.isServer = PR_FALSE; |
| |
| 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)); |
| |
| /* If there's an sid set from an external cache, use it. */ |
| if (ss->sec.ci.sid && ss->sec.ci.sid->cached == in_external_cache) { |
| sid = ss->sec.ci.sid; |
| SSL_TRC(3, ("%d: SSL[%d]: using external token", SSL_GETPID(), ss->fd)); |
| } else if (!ss->opt.noCache) { |
| /* Try to find server in our session-id cache */ |
| 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 { |
| ssl_UncacheSessionID(ss); |
| 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; |
| |
| 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; |
| } |