tor-browser

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

sslauth.c (9425B)


      1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 #include "cert.h"
      6 #include "secitem.h"
      7 #include "ssl.h"
      8 #include "sslimpl.h"
      9 #include "sslproto.h"
     10 #include "pk11func.h"
     11 #include "ocsp.h"
     12 
     13 /* NEED LOCKS IN HERE.  */
     14 CERTCertificate *
     15 SSL_PeerCertificate(PRFileDesc *fd)
     16 {
     17    sslSocket *ss;
     18 
     19    ss = ssl_FindSocket(fd);
     20    if (!ss) {
     21        SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate",
     22                 SSL_GETPID(), fd));
     23        return 0;
     24    }
     25    if (ss->opt.useSecurity && ss->sec.peerCert) {
     26        return CERT_DupCertificate(ss->sec.peerCert);
     27    }
     28    return 0;
     29 }
     30 
     31 /* NEED LOCKS IN HERE.  */
     32 SECStatus
     33 SSLExp_PeerCertificateChainDER(PRFileDesc *fd, SECItemArray **out)
     34 {
     35    sslSocket *ss;
     36    ssl3CertNode *cur;
     37    SECItemArray *chain;
     38    unsigned int count;
     39    unsigned int index;
     40    SECStatus rv;
     41 
     42    ss = ssl_FindSocket(fd);
     43    if (!ss) {
     44        SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChainDER",
     45                 SSL_GETPID(), fd));
     46        return SECFailure;
     47    }
     48    if (!ss->opt.useSecurity || !ss->sec.peerCert) {
     49        PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
     50        return SECFailure;
     51    }
     52 
     53    count = 1; // for ss->sec.peerCert
     54    for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) {
     55        ++count;
     56    }
     57 
     58    chain = SECITEM_AllocArray(NULL, NULL, count);
     59    if (chain == NULL) {
     60        return SECFailure; /* error code set in SECITEM_AllocArray */
     61    }
     62 
     63    index = 0;
     64    rv = SECITEM_CopyItem(NULL, &chain->items[index++], &ss->sec.peerCert->derCert);
     65    if (rv != SECSuccess) {
     66        goto loser; /* error code set in SECITEM_CopyItem */
     67    }
     68 
     69    for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) {
     70        rv = SECITEM_CopyItem(NULL, &chain->items[index++], cur->derCert);
     71        if (rv != SECSuccess) {
     72            goto loser; /* error code set in SECITEM_CopyItem */
     73        }
     74    }
     75 
     76    *out = chain;
     77    return SECSuccess;
     78 
     79 loser:
     80    SECITEM_FreeArray(chain, PR_TRUE);
     81    return SECFailure;
     82 }
     83 
     84 /* NEED LOCKS IN HERE.  */
     85 CERTCertList *
     86 SSL_PeerCertificateChain(PRFileDesc *fd)
     87 {
     88    sslSocket *ss;
     89    CERTCertList *chain = NULL;
     90    CERTCertificate *cert;
     91    ssl3CertNode *cur;
     92 
     93    ss = ssl_FindSocket(fd);
     94    if (!ss) {
     95        SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificateChain",
     96                 SSL_GETPID(), fd));
     97        return NULL;
     98    }
     99    if (!ss->opt.useSecurity || !ss->sec.peerCert) {
    100        PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
    101        return NULL;
    102    }
    103    chain = CERT_NewCertList();
    104    if (!chain) {
    105        return NULL;
    106    }
    107    cert = CERT_DupCertificate(ss->sec.peerCert);
    108    if (CERT_AddCertToListTail(chain, cert) != SECSuccess) {
    109        goto loser;
    110    }
    111    for (cur = ss->ssl3.peerCertChain; cur; cur = cur->next) {
    112        cert = CERT_NewTempCertificate(ss->dbHandle, cur->derCert,
    113                                       NULL, PR_FALSE, PR_TRUE);
    114        if (!cert || CERT_AddCertToListTail(chain, cert) != SECSuccess) {
    115            goto loser;
    116        }
    117    }
    118    return chain;
    119 
    120 loser:
    121    CERT_DestroyCertList(chain);
    122    return NULL;
    123 }
    124 
    125 /* NEED LOCKS IN HERE.  */
    126 CERTCertificate *
    127 SSL_LocalCertificate(PRFileDesc *fd)
    128 {
    129    sslSocket *ss;
    130 
    131    ss = ssl_FindSocket(fd);
    132    if (!ss) {
    133        SSL_DBG(("%d: SSL[%d]: bad socket in PeerCertificate",
    134                 SSL_GETPID(), fd));
    135        return NULL;
    136    }
    137    if (ss->opt.useSecurity) {
    138        if (ss->sec.localCert) {
    139            return CERT_DupCertificate(ss->sec.localCert);
    140        }
    141        if (ss->sec.ci.sid && ss->sec.ci.sid->localCert) {
    142            return CERT_DupCertificate(ss->sec.ci.sid->localCert);
    143        }
    144    }
    145    return NULL;
    146 }
    147 
    148 /* NEED LOCKS IN HERE.  */
    149 SECStatus
    150 SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1,
    151                   char **ip, char **sp)
    152 {
    153    sslSocket *ss;
    154 
    155    ss = ssl_FindSocket(fd);
    156    if (!ss) {
    157        SSL_DBG(("%d: SSL[%d]: bad socket in SecurityStatus",
    158                 SSL_GETPID(), fd));
    159        return SECFailure;
    160    }
    161 
    162    if (cp)
    163        *cp = 0;
    164    if (kp0)
    165        *kp0 = 0;
    166    if (kp1)
    167        *kp1 = 0;
    168    if (ip)
    169        *ip = 0;
    170    if (sp)
    171        *sp = 0;
    172    if (op) {
    173        *op = SSL_SECURITY_STATUS_OFF;
    174    }
    175 
    176    if (ss->opt.useSecurity && ss->enoughFirstHsDone) {
    177        const ssl3BulkCipherDef *bulkCipherDef;
    178        PRBool isDes = PR_FALSE;
    179 
    180        bulkCipherDef = ssl_GetBulkCipherDef(ss->ssl3.hs.suite_def);
    181        if (cp) {
    182            *cp = PORT_Strdup(bulkCipherDef->short_name);
    183        }
    184        if (PORT_Strstr(bulkCipherDef->short_name, "DES")) {
    185            isDes = PR_TRUE;
    186        }
    187 
    188        if (kp0) {
    189            *kp0 = bulkCipherDef->key_size * 8;
    190            if (isDes)
    191                *kp0 = (*kp0 * 7) / 8;
    192        }
    193        if (kp1) {
    194            *kp1 = bulkCipherDef->secret_key_size * 8;
    195            if (isDes)
    196                *kp1 = (*kp1 * 7) / 8;
    197        }
    198        if (op) {
    199            if (bulkCipherDef->key_size == 0) {
    200                *op = SSL_SECURITY_STATUS_OFF;
    201            } else if (bulkCipherDef->secret_key_size * 8 < 90) {
    202                *op = SSL_SECURITY_STATUS_ON_LOW;
    203            } else {
    204                *op = SSL_SECURITY_STATUS_ON_HIGH;
    205            }
    206        }
    207 
    208        if (ip || sp) {
    209            CERTCertificate *cert;
    210 
    211            cert = ss->sec.peerCert;
    212            if (cert) {
    213                if (ip) {
    214                    *ip = CERT_NameToAscii(&cert->issuer);
    215                }
    216                if (sp) {
    217                    *sp = CERT_NameToAscii(&cert->subject);
    218                }
    219            } else {
    220                if (ip) {
    221                    *ip = PORT_Strdup("no certificate");
    222                }
    223                if (sp) {
    224                    *sp = PORT_Strdup("no certificate");
    225                }
    226            }
    227        }
    228    }
    229 
    230    return SECSuccess;
    231 }
    232 
    233 /************************************************************************/
    234 
    235 /* NEED LOCKS IN HERE.  */
    236 SECStatus
    237 SSL_AuthCertificateHook(PRFileDesc *s, SSLAuthCertificate func, void *arg)
    238 {
    239    sslSocket *ss;
    240 
    241    ss = ssl_FindSocket(s);
    242    if (!ss) {
    243        SSL_DBG(("%d: SSL[%d]: bad socket in AuthCertificateHook",
    244                 SSL_GETPID(), s));
    245        return SECFailure;
    246    }
    247 
    248    ss->authCertificate = func;
    249    ss->authCertificateArg = arg;
    250 
    251    return SECSuccess;
    252 }
    253 
    254 /* NEED LOCKS IN HERE.  */
    255 SECStatus
    256 SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func,
    257                          void *arg)
    258 {
    259    sslSocket *ss;
    260 
    261    ss = ssl_FindSocket(s);
    262    if (!ss) {
    263        SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
    264                 SSL_GETPID(), s));
    265        return SECFailure;
    266    }
    267 
    268    ss->getClientAuthData = func;
    269    ss->getClientAuthDataArg = arg;
    270    return SECSuccess;
    271 }
    272 
    273 /* NEED LOCKS IN HERE.  */
    274 SECStatus
    275 SSL_SetPKCS11PinArg(PRFileDesc *s, void *arg)
    276 {
    277    sslSocket *ss;
    278 
    279    ss = ssl_FindSocket(s);
    280    if (!ss) {
    281        SSL_DBG(("%d: SSL[%d]: bad socket in GetClientAuthDataHook",
    282                 SSL_GETPID(), s));
    283        return SECFailure;
    284    }
    285 
    286    ss->pkcs11PinArg = arg;
    287    return SECSuccess;
    288 }
    289 
    290 /* This is the "default" authCert callback function.  It is called when a
    291 * certificate message is received from the peer and the local application
    292 * has not registered an authCert callback function.
    293 */
    294 SECStatus
    295 SSL_AuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, PRBool isServer)
    296 {
    297    SECStatus rv;
    298    CERTCertDBHandle *handle;
    299    sslSocket *ss;
    300    SECCertUsage certUsage;
    301    const char *hostname = NULL;
    302    SECItemArray *certStatusArray;
    303 
    304    ss = ssl_FindSocket(fd);
    305    PORT_Assert(ss != NULL);
    306    if (!ss) {
    307        return SECFailure;
    308    }
    309 
    310    handle = (CERTCertDBHandle *)arg;
    311    certStatusArray = &ss->sec.ci.sid->peerCertStatus;
    312 
    313    PRTime now = ssl_Time(ss);
    314    if (certStatusArray->len) {
    315        PORT_SetError(0);
    316        if (CERT_CacheOCSPResponseFromSideChannel(handle, ss->sec.peerCert, now,
    317                                                  &certStatusArray->items[0],
    318                                                  ss->pkcs11PinArg) !=
    319            SECSuccess) {
    320            PORT_Assert(PR_GetError() != 0);
    321        }
    322    }
    323 
    324    /* this may seem backwards, but isn't. */
    325    certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
    326 
    327    /* Calling SSL_PeerCertificateChain here ensures that all certs from the
    328     * peer's presented chain are in the database for path finding.
    329     */
    330    CERTCertList *peerChain = SSL_PeerCertificateChain(fd);
    331 
    332    rv = CERT_VerifyCert(handle, ss->sec.peerCert, checkSig, certUsage,
    333                         now, ss->pkcs11PinArg, NULL);
    334 
    335    CERT_DestroyCertList(peerChain);
    336 
    337    if (rv != SECSuccess || isServer)
    338        return rv;
    339 
    340    /* cert is OK.  This is the client side of an SSL connection.
    341     * Now check the name field in the cert against the desired hostname.
    342     * NB: This is our only defense against Man-In-The-Middle (MITM) attacks!
    343     */
    344    hostname = ss->url;
    345    if (hostname && hostname[0])
    346        rv = CERT_VerifyCertName(ss->sec.peerCert, hostname);
    347    else
    348        rv = SECFailure;
    349    if (rv != SECSuccess)
    350        PORT_SetError(SSL_ERROR_BAD_CERT_DOMAIN);
    351 
    352    return rv;
    353 }