tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

sslcon.c (7089B)


      1 /*
      2 * Basic SSL handshake functions.
      3 *
      4 * This Source Code Form is subject to the terms of the Mozilla Public
      5 * License, v. 2.0. If a copy of the MPL was not distributed with this
      6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      7 
      8 #include "nssrenam.h"
      9 #include "cert.h"
     10 #include "secitem.h"
     11 #include "sechash.h"
     12 #include "cryptohi.h" /* for SGN_ funcs */
     13 #include "keyhi.h"    /* for SECKEY_ high level functions. */
     14 #include "ssl.h"
     15 #include "sslimpl.h"
     16 #include "sslproto.h"
     17 #include "ssl3prot.h"
     18 #include "sslerr.h"
     19 #include "pk11func.h"
     20 #include "prinit.h"
     21 
     22 /*
     23 ** Put a string tag in the library so that we can examine an executable
     24 ** and see what kind of security it supports.
     25 */
     26 const char *ssl_version = "SECURITY_VERSION:"
     27                          " +us"
     28                          " +export"
     29 #ifdef TRACE
     30                          " +trace"
     31 #endif
     32 #ifdef DEBUG
     33                          " +debug"
     34 #endif
     35    ;
     36 
     37 /***********************************************************************
     38 * Gathers in and handles records/messages until either the handshake is
     39 * complete or application data is available.
     40 *
     41 * Called from ssl_Do1stHandshake() via function pointer ss->handshake.
     42 * Caller must hold handshake lock.
     43 * This function acquires and releases the RecvBufLock.
     44 *
     45 * returns SECSuccess for success.
     46 * returns SECFailure on error, setting PR_WOULD_BLOCK_ERROR if only blocked.
     47 *
     48 * The gather functions called by ssl_GatherRecord1stHandshake are expected
     49 *  to return values interpreted as follows:
     50 *  1 : the function completed without error.
     51 *  0 : the function read EOF.
     52 * -1 : read error, or PR_WOULD_BLOCK_ERROR, or handleRecord error.
     53 *
     54 * This code is similar to, and easily confused with, DoRecv() in sslsecur.c
     55 *
     56 * This function is called from ssl_Do1stHandshake().
     57 * The following functions put ssl_GatherRecord1stHandshake into ss->handshake:
     58 *  ssl_BeginClientHandshake
     59 *  ssl3_RestartHandshakeAfterCertReq
     60 *  ssl3_RestartHandshakeAfterServerCert
     61 *  ssl_BeginServerHandshake
     62 */
     63 SECStatus
     64 ssl_GatherRecord1stHandshake(sslSocket *ss)
     65 {
     66    int rv;
     67 
     68    PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
     69 
     70    ssl_GetRecvBufLock(ss);
     71 
     72    /* Wait for handshake to complete, or application data to arrive.  */
     73    rv = ssl3_GatherCompleteHandshake(ss, 0);
     74    SSL_TRC(10, ("%d: SSL[%d]: handshake gathering, rv=%d",
     75                 SSL_GETPID(), ss->fd, rv));
     76 
     77    ssl_ReleaseRecvBufLock(ss);
     78 
     79    if (rv <= 0) {
     80        if (rv == 0) {
     81            /* EOF. Loser  */
     82            PORT_SetError(PR_END_OF_FILE_ERROR);
     83        }
     84        if (PORT_GetError() == PR_WOULD_BLOCK_ERROR) {
     85            SSL_TRC(10, ("%d: SSL[%d]: handshake blocked (need %d)",
     86                         SSL_GETPID(), ss->fd, ss->gs.remainder));
     87        }
     88        return SECFailure; /* rv is < 0 here. */
     89    }
     90 
     91    ss->handshake = NULL;
     92    return SECSuccess;
     93 }
     94 
     95 /* This function is called at the beginning of a handshake to ensure that at
     96 * least one SSL/TLS version is enabled. */
     97 static SECStatus
     98 ssl_CheckConfigSanity(sslSocket *ss)
     99 {
    100    if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) {
    101        SSL_DBG(("%d: SSL[%d]: Can't handshake! all versions disabled.",
    102                 SSL_GETPID(), ss->fd));
    103        PORT_SetError(SSL_ERROR_SSL_DISABLED);
    104        return SECFailure;
    105    }
    106    return SECSuccess;
    107 }
    108 
    109 /* Sends out the initial client Hello message on the connection.
    110 * Acquires and releases the socket's xmitBufLock.
    111 */
    112 SECStatus
    113 ssl_BeginClientHandshake(sslSocket *ss)
    114 {
    115    sslSessionID *sid = NULL;
    116    SECStatus rv;
    117 
    118    PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
    119 
    120    ss->sec.isServer = PR_FALSE;
    121 
    122    rv = ssl_CheckConfigSanity(ss);
    123    if (rv != SECSuccess)
    124        goto loser;
    125 
    126    /* Get peer name of server */
    127    rv = ssl_GetPeerInfo(ss);
    128    if (rv < 0) {
    129 #ifdef HPUX11
    130        /*
    131         * On some HP-UX B.11.00 systems, getpeername() occasionally
    132         * fails with ENOTCONN after a successful completion of
    133         * non-blocking connect.  I found that if we do a write()
    134         * and then retry getpeername(), it will work.
    135         */
    136        if (PR_GetError() == PR_NOT_CONNECTED_ERROR) {
    137            char dummy;
    138            (void)PR_Write(ss->fd->lower, &dummy, 0);
    139            rv = ssl_GetPeerInfo(ss);
    140            if (rv < 0) {
    141                goto loser;
    142            }
    143        }
    144 #else
    145        goto loser;
    146 #endif
    147    }
    148 
    149    SSL_TRC(3, ("%d: SSL[%d]: sending client-hello", SSL_GETPID(), ss->fd));
    150 
    151    /* If there's an sid set from an external cache, use it. */
    152    if (ss->sec.ci.sid && ss->sec.ci.sid->cached == in_external_cache) {
    153        sid = ss->sec.ci.sid;
    154        SSL_TRC(3, ("%d: SSL[%d]: using external token", SSL_GETPID(), ss->fd));
    155    } else if (!ss->opt.noCache) {
    156        /* Try to find server in our session-id cache */
    157        sid = ssl_LookupSID(ssl_Time(ss), &ss->sec.ci.peer,
    158                            ss->sec.ci.port, ss->peerID, ss->url);
    159    }
    160 
    161    if (sid) {
    162        if (sid->version >= ss->vrange.min && sid->version <= ss->vrange.max) {
    163            PORT_Assert(!ss->sec.localCert);
    164            ss->sec.localCert = CERT_DupCertificate(sid->localCert);
    165        } else {
    166            ssl_UncacheSessionID(ss);
    167            ssl_FreeSID(sid);
    168            sid = NULL;
    169        }
    170    }
    171    if (!sid) {
    172        sid = ssl3_NewSessionID(ss, PR_FALSE);
    173        if (!sid) {
    174            goto loser;
    175        }
    176        /* This session is a dummy, which we don't want to resume. */
    177        sid->u.ssl3.keys.resumable = PR_FALSE;
    178    }
    179    ss->sec.ci.sid = sid;
    180 
    181    ss->gs.state = GS_INIT;
    182    ss->handshake = ssl_GatherRecord1stHandshake;
    183 
    184    /* ssl3_SendClientHello will override this if it succeeds. */
    185    ss->version = SSL_LIBRARY_VERSION_3_0;
    186 
    187    ssl_GetSSL3HandshakeLock(ss);
    188    ssl_GetXmitBufLock(ss);
    189    rv = ssl3_SendClientHello(ss, client_hello_initial);
    190    ssl_ReleaseXmitBufLock(ss);
    191    ssl_ReleaseSSL3HandshakeLock(ss);
    192 
    193    return rv;
    194 
    195 loser:
    196    return SECFailure;
    197 }
    198 
    199 SECStatus
    200 ssl_BeginServerHandshake(sslSocket *ss)
    201 {
    202    SECStatus rv;
    203 
    204    ss->sec.isServer = PR_TRUE;
    205    ss->ssl3.hs.ws = wait_client_hello;
    206 
    207    rv = ssl_CheckConfigSanity(ss);
    208    if (rv != SECSuccess)
    209        goto loser;
    210 
    211    ss->handshake = ssl_GatherRecord1stHandshake;
    212    return SECSuccess;
    213 
    214 loser:
    215    return SECFailure;
    216 }
    217 
    218 /* This function doesn't really belong in this file.
    219 ** It's here to keep AIX compilers from optimizing it away,
    220 ** and not including it in the DSO.
    221 */
    222 
    223 #include "nss.h"
    224 extern const char __nss_ssl_version[];
    225 
    226 PRBool
    227 NSSSSL_VersionCheck(const char *importedVersion)
    228 {
    229 #define NSS_VERSION_VARIABLE __nss_ssl_version
    230 #include "verref.h"
    231 
    232    /*
    233     * This is the secret handshake algorithm.
    234     *
    235     * This release has a simple version compatibility
    236     * check algorithm.  This release is not backward
    237     * compatible with previous major releases.  It is
    238     * not compatible with future major, minor, or
    239     * patch releases.
    240     */
    241    return NSS_VersionCheck(importedVersion);
    242 }
    243 
    244 const char *
    245 NSSSSL_GetVersion(void)
    246 {
    247    return NSS_VERSION;
    248 }