tor-browser

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

libssl_internals.c (16668B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 /* This file contains functions for frobbing the internals of libssl */
      8 #include "libssl_internals.h"
      9 
     10 #include "nss.h"
     11 #include "pk11hpke.h"
     12 #include "pk11pub.h"
     13 #include "pk11priv.h"
     14 #include "tls13ech.h"
     15 #include "seccomon.h"
     16 #include "selfencrypt.h"
     17 #include "secmodti.h"
     18 #include "sslproto.h"
     19 
     20 SECStatus SSLInt_RemoveServerCertificates(PRFileDesc *fd) {
     21  if (!fd) {
     22    return SECFailure;
     23  }
     24  sslSocket *ss = ssl_FindSocket(fd);
     25  if (!ss) {
     26    return SECFailure;
     27  }
     28 
     29  PRCList *cursor;
     30  while (!PR_CLIST_IS_EMPTY(&ss->serverCerts)) {
     31    cursor = PR_LIST_TAIL(&ss->serverCerts);
     32    PR_REMOVE_LINK(cursor);
     33    ssl_FreeServerCert((sslServerCert *)cursor);
     34  }
     35  return SECSuccess;
     36 }
     37 
     38 SECStatus SSLInt_SetDCAdvertisedSigSchemes(PRFileDesc *fd,
     39                                           const SSLSignatureScheme *schemes,
     40                                           uint32_t num_sig_schemes) {
     41  if (!fd) {
     42    return SECFailure;
     43  }
     44  sslSocket *ss = ssl_FindSocket(fd);
     45  if (!ss) {
     46    return SECFailure;
     47  }
     48 
     49  // Alloc and copy, libssl will free.
     50  SSLSignatureScheme *dc_schemes =
     51      PORT_ZNewArray(SSLSignatureScheme, num_sig_schemes);
     52  if (!dc_schemes) {
     53    return SECFailure;
     54  }
     55  memcpy(dc_schemes, schemes, sizeof(SSLSignatureScheme) * num_sig_schemes);
     56 
     57  if (ss->xtnData.delegCredSigSchemesAdvertised) {
     58    PORT_Free(ss->xtnData.delegCredSigSchemesAdvertised);
     59  }
     60  ss->xtnData.delegCredSigSchemesAdvertised = dc_schemes;
     61  ss->xtnData.numDelegCredSigSchemesAdvertised = num_sig_schemes;
     62  return SECSuccess;
     63 }
     64 
     65 SECStatus SSLInt_TweakChannelInfoForDC(PRFileDesc *fd, PRBool changeAuthKeyBits,
     66                                       PRBool changeScheme) {
     67  if (!fd) {
     68    return SECFailure;
     69  }
     70  sslSocket *ss = ssl_FindSocket(fd);
     71  if (!ss) {
     72    return SECFailure;
     73  }
     74 
     75  // Just toggle so we'll always have a valid value.
     76  if (changeScheme) {
     77    ss->sec.signatureScheme = (ss->sec.signatureScheme == ssl_sig_ed25519)
     78                                  ? ssl_sig_ecdsa_secp256r1_sha256
     79                                  : ssl_sig_ed25519;
     80  }
     81  if (changeAuthKeyBits) {
     82    ss->sec.authKeyBits = ss->sec.authKeyBits ? ss->sec.authKeyBits * 2 : 384;
     83  }
     84 
     85  return SECSuccess;
     86 }
     87 
     88 SECStatus SSLInt_GetHandshakeRandoms(PRFileDesc *fd, SSL3Random client_random,
     89                                     SSL3Random server_random) {
     90  if (!fd) {
     91    return SECFailure;
     92  }
     93  sslSocket *ss = ssl_FindSocket(fd);
     94  if (!ss) {
     95    return SECFailure;
     96  }
     97 
     98  if (client_random) {
     99    memcpy(client_random, ss->ssl3.hs.client_random, sizeof(SSL3Random));
    100  }
    101  if (server_random) {
    102    memcpy(server_random, ss->ssl3.hs.server_random, sizeof(SSL3Random));
    103  }
    104  return SECSuccess;
    105 }
    106 
    107 SECStatus SSLInt_IncrementClientHandshakeVersion(PRFileDesc *fd) {
    108  sslSocket *ss = ssl_FindSocket(fd);
    109  if (!ss) {
    110    return SECFailure;
    111  }
    112 
    113  ++ss->clientHelloVersion;
    114 
    115  return SECSuccess;
    116 }
    117 
    118 /* Use this function to update the ClientRandom of a client's handshake state
    119 * after replacing its ClientHello message. We for example need to do this
    120 * when replacing an SSLv3 ClientHello with its SSLv2 equivalent. */
    121 SECStatus SSLInt_UpdateSSLv2ClientRandom(PRFileDesc *fd, uint8_t *rnd,
    122                                         size_t rnd_len, uint8_t *msg,
    123                                         size_t msg_len) {
    124  sslSocket *ss = ssl_FindSocket(fd);
    125  if (!ss) {
    126    return SECFailure;
    127  }
    128 
    129  ssl3_RestartHandshakeHashes(ss);
    130 
    131  // Ensure we don't overrun hs.client_random.
    132  rnd_len = PR_MIN(SSL3_RANDOM_LENGTH, rnd_len);
    133 
    134  // Zero the client_random.
    135  PORT_Memset(ss->ssl3.hs.client_random, 0, SSL3_RANDOM_LENGTH);
    136 
    137  // Copy over the challenge bytes.
    138  size_t offset = SSL3_RANDOM_LENGTH - rnd_len;
    139  PORT_Memcpy(ss->ssl3.hs.client_random + offset, rnd, rnd_len);
    140 
    141  // Rehash the SSLv2 client hello message.
    142  return ssl3_UpdateHandshakeHashes(ss, msg, msg_len);
    143 }
    144 
    145 PRBool SSLInt_ExtensionNegotiated(PRFileDesc *fd, PRUint16 ext) {
    146  sslSocket *ss = ssl_FindSocket(fd);
    147  return (PRBool)(ss && ssl3_ExtensionNegotiated(ss, ext));
    148 }
    149 
    150 // Tests should not use this function directly, because the keys may
    151 // still be in cache. Instead, use TlsConnectTestBase::ClearServerCache.
    152 void SSLInt_ClearSelfEncryptKey() { ssl_ResetSelfEncryptKeys(); }
    153 
    154 sslSelfEncryptKeys *ssl_GetSelfEncryptKeysInt();
    155 
    156 void SSLInt_SetSelfEncryptMacKey(PK11SymKey *key) {
    157  sslSelfEncryptKeys *keys = ssl_GetSelfEncryptKeysInt();
    158 
    159  PK11_FreeSymKey(keys->macKey);
    160  keys->macKey = key;
    161 }
    162 
    163 SECStatus SSLInt_SetMTU(PRFileDesc *fd, PRUint16 mtu) {
    164  sslSocket *ss = ssl_FindSocket(fd);
    165  if (!ss) {
    166    return SECFailure;
    167  }
    168  ss->ssl3.mtu = mtu;
    169  ss->ssl3.hs.rtRetries = 0; /* Avoid DTLS shrinking the MTU any more. */
    170  return SECSuccess;
    171 }
    172 
    173 PRInt32 SSLInt_CountCipherSpecs(PRFileDesc *fd) {
    174  PRCList *cur_p;
    175  PRInt32 ct = 0;
    176 
    177  sslSocket *ss = ssl_FindSocket(fd);
    178  if (!ss) {
    179    return -1;
    180  }
    181 
    182  for (cur_p = PR_NEXT_LINK(&ss->ssl3.hs.cipherSpecs);
    183       cur_p != &ss->ssl3.hs.cipherSpecs; cur_p = PR_NEXT_LINK(cur_p)) {
    184    ++ct;
    185  }
    186  return ct;
    187 }
    188 
    189 void SSLInt_PrintCipherSpecs(const char *label, PRFileDesc *fd) {
    190  PRCList *cur_p;
    191 
    192  sslSocket *ss = ssl_FindSocket(fd);
    193  if (!ss) {
    194    return;
    195  }
    196 
    197  fprintf(stderr, "Cipher specs for %s\n", label);
    198  for (cur_p = PR_NEXT_LINK(&ss->ssl3.hs.cipherSpecs);
    199       cur_p != &ss->ssl3.hs.cipherSpecs; cur_p = PR_NEXT_LINK(cur_p)) {
    200    ssl3CipherSpec *spec = (ssl3CipherSpec *)cur_p;
    201    fprintf(stderr, "  %s spec epoch=%d (%s) refct=%d\n", SPEC_DIR(spec),
    202            spec->epoch, spec->phase, spec->refCt);
    203  }
    204 }
    205 
    206 /* DTLS timers are separate from the time that the rest of the stack uses.
    207 * Force a timer expiry by backdating when all active timers were started.
    208 * We could set the remaining time to 0 but then backoff would not work properly
    209 * if we decide to test it. */
    210 SECStatus SSLInt_ShiftDtlsTimers(PRFileDesc *fd, PRIntervalTime shift) {
    211  size_t i;
    212  sslSocket *ss = ssl_FindSocket(fd);
    213  if (!ss) {
    214    return SECFailure;
    215  }
    216 
    217  for (i = 0; i < PR_ARRAY_SIZE(ss->ssl3.hs.timers); ++i) {
    218    if (ss->ssl3.hs.timers[i].cb) {
    219      ss->ssl3.hs.timers[i].started -= shift;
    220    }
    221  }
    222  return SECSuccess;
    223 }
    224 
    225 /* Instead of waiting the ACK timer to expire, we send the ack immediately*/
    226 SECStatus SSLInt_SendImmediateACK(PRFileDesc *fd) {
    227  sslSocket *ss = ssl_FindSocket(fd);
    228  if (!ss) {
    229    return SECFailure;
    230  }
    231  PORT_Assert(IS_DTLS(ss));
    232  dtls13_SendAck(ss);
    233  return SECSuccess;
    234 }
    235 
    236 #define CHECK_SECRET(secret)                  \
    237  if (ss->ssl3.hs.secret) {                   \
    238    fprintf(stderr, "%s != NULL\n", #secret); \
    239    return PR_FALSE;                          \
    240  }
    241 
    242 PRBool SSLInt_CheckSecretsDestroyed(PRFileDesc *fd) {
    243  sslSocket *ss = ssl_FindSocket(fd);
    244  if (!ss) {
    245    return PR_FALSE;
    246  }
    247 
    248  CHECK_SECRET(currentSecret);
    249  CHECK_SECRET(dheSecret);
    250  CHECK_SECRET(clientEarlyTrafficSecret);
    251  CHECK_SECRET(clientHsTrafficSecret);
    252  CHECK_SECRET(serverHsTrafficSecret);
    253 
    254  return PR_TRUE;
    255 }
    256 
    257 PRBool sslint_DamageTrafficSecret(PRFileDesc *fd, size_t offset) {
    258  unsigned char data[32] = {0};
    259  PK11SymKey **keyPtr;
    260  PK11SlotInfo *slot = PK11_GetInternalSlot();
    261  SECItem key_item = {siBuffer, data, sizeof(data)};
    262  sslSocket *ss = ssl_FindSocket(fd);
    263  if (!ss) {
    264    return PR_FALSE;
    265  }
    266  if (!slot) {
    267    return PR_FALSE;
    268  }
    269  keyPtr = (PK11SymKey **)((char *)&ss->ssl3.hs + offset);
    270  if (!*keyPtr) {
    271    return PR_FALSE;
    272  }
    273  PK11_FreeSymKey(*keyPtr);
    274  *keyPtr = PK11_ImportSymKey(slot, CKM_NSS_HKDF_SHA256, PK11_OriginUnwrap,
    275                              CKA_DERIVE, &key_item, NULL);
    276  PK11_FreeSlot(slot);
    277  if (!*keyPtr) {
    278    return PR_FALSE;
    279  }
    280 
    281  return PR_TRUE;
    282 }
    283 
    284 PRBool SSLInt_DamageClientHsTrafficSecret(PRFileDesc *fd) {
    285  return sslint_DamageTrafficSecret(
    286      fd, offsetof(SSL3HandshakeState, clientHsTrafficSecret));
    287 }
    288 
    289 PRBool SSLInt_DamageServerHsTrafficSecret(PRFileDesc *fd) {
    290  return sslint_DamageTrafficSecret(
    291      fd, offsetof(SSL3HandshakeState, serverHsTrafficSecret));
    292 }
    293 
    294 PRBool SSLInt_DamageEarlyTrafficSecret(PRFileDesc *fd) {
    295  return sslint_DamageTrafficSecret(
    296      fd, offsetof(SSL3HandshakeState, clientEarlyTrafficSecret));
    297 }
    298 
    299 SECStatus SSLInt_Set0RttAlpn(PRFileDesc *fd, PRUint8 *data, unsigned int len) {
    300  sslSocket *ss = ssl_FindSocket(fd);
    301  if (!ss) {
    302    return SECFailure;
    303  }
    304 
    305  ss->xtnData.nextProtoState = SSL_NEXT_PROTO_EARLY_VALUE;
    306  if (ss->xtnData.nextProto.data) {
    307    SECITEM_FreeItem(&ss->xtnData.nextProto, PR_FALSE);
    308  }
    309  if (!SECITEM_AllocItem(NULL, &ss->xtnData.nextProto, len)) {
    310    return SECFailure;
    311  }
    312  PORT_Memcpy(ss->xtnData.nextProto.data, data, len);
    313 
    314  return SECSuccess;
    315 }
    316 
    317 PRBool SSLInt_HasCertWithAuthType(PRFileDesc *fd, SSLAuthType authType) {
    318  sslSocket *ss = ssl_FindSocket(fd);
    319  if (!ss) {
    320    return PR_FALSE;
    321  }
    322 
    323  return (PRBool)(!!ssl_FindServerCert(ss, authType, NULL));
    324 }
    325 
    326 PRBool SSLInt_SendAlert(PRFileDesc *fd, uint8_t level, uint8_t type) {
    327  sslSocket *ss = ssl_FindSocket(fd);
    328  if (!ss) {
    329    return PR_FALSE;
    330  }
    331 
    332  SECStatus rv = SSL3_SendAlert(ss, level, type);
    333  if (rv != SECSuccess) return PR_FALSE;
    334 
    335  return PR_TRUE;
    336 }
    337 
    338 SECStatus SSLInt_AdvanceReadSeqNum(PRFileDesc *fd, PRUint64 to) {
    339  sslSocket *ss;
    340  ssl3CipherSpec *spec;
    341 
    342  ss = ssl_FindSocket(fd);
    343  if (!ss) {
    344    return SECFailure;
    345  }
    346  if (to > RECORD_SEQ_MAX) {
    347    PORT_SetError(SEC_ERROR_INVALID_ARGS);
    348    return SECFailure;
    349  }
    350  ssl_GetSpecWriteLock(ss);
    351  spec = ss->ssl3.crSpec;
    352  spec->nextSeqNum = to;
    353 
    354  /* For DTLS, we need to fix the record sequence number.  For this, we can just
    355   * scrub the entire structure on the assumption that the new sequence number
    356   * is far enough past the last received sequence number. */
    357  if (spec->nextSeqNum <=
    358      spec->recvdRecords.right + DTLS_RECVD_RECORDS_WINDOW) {
    359    PORT_SetError(SEC_ERROR_INVALID_ARGS);
    360    return SECFailure;
    361  }
    362  dtls_RecordSetRecvd(&spec->recvdRecords, spec->nextSeqNum - 1);
    363 
    364  ssl_ReleaseSpecWriteLock(ss);
    365  return SECSuccess;
    366 }
    367 
    368 SECStatus SSLInt_AdvanceWriteSeqNum(PRFileDesc *fd, PRUint64 to) {
    369  sslSocket *ss;
    370  ssl3CipherSpec *spec;
    371  PK11Context *pk11ctxt;
    372  const ssl3BulkCipherDef *cipher_def;
    373 
    374  ss = ssl_FindSocket(fd);
    375  if (!ss) {
    376    return SECFailure;
    377  }
    378  if (to >= RECORD_SEQ_MAX) {
    379    PORT_SetError(SEC_ERROR_INVALID_ARGS);
    380    return SECFailure;
    381  }
    382  ssl_GetSpecWriteLock(ss);
    383  spec = ss->ssl3.cwSpec;
    384  cipher_def = spec->cipherDef;
    385  spec->nextSeqNum = to;
    386  if (cipher_def->type != type_aead) {
    387    ssl_ReleaseSpecWriteLock(ss);
    388    return SECSuccess;
    389  }
    390  /* If we are using aead, we need to advance the counter in the
    391   * internal IV generator as well.
    392   * This could be in the token or software. */
    393  pk11ctxt = spec->cipherContext;
    394  /* If counter is in the token, we need to switch it to software,
    395   * since we don't have access to the internal state of the token. We do
    396   * that by turning on the simulated message interface, then setting up the
    397   * software IV generator */
    398  if (pk11ctxt->ivCounter == 0) {
    399    _PK11_ContextSetAEADSimulation(pk11ctxt);
    400    pk11ctxt->ivLen = cipher_def->iv_size + cipher_def->explicit_nonce_size;
    401    pk11ctxt->ivMaxCount = PR_UINT64(0xffffffffffffffff);
    402    if ((cipher_def->explicit_nonce_size == 0) ||
    403        (spec->version >= SSL_LIBRARY_VERSION_TLS_1_3)) {
    404      pk11ctxt->ivFixedBits =
    405          (pk11ctxt->ivLen - sizeof(sslSequenceNumber)) * BPB;
    406      pk11ctxt->ivGen = CKG_GENERATE_COUNTER_XOR;
    407    } else {
    408      pk11ctxt->ivFixedBits = cipher_def->iv_size * BPB;
    409      pk11ctxt->ivGen = CKG_GENERATE_COUNTER;
    410    }
    411    /* DTLS1.2 and below included the epoch in the fixed portion of the IV */
    412    if (IS_DTLS_1_OR_12(ss)) {
    413      pk11ctxt->ivFixedBits += 2 * BPB;
    414    }
    415  }
    416  /* now we can update the internal counter (either we are already using
    417   * the software IV generator, or we just switched to it above */
    418  pk11ctxt->ivCounter = to;
    419 
    420  ssl_ReleaseSpecWriteLock(ss);
    421  return SECSuccess;
    422 }
    423 
    424 /* The next two functions are responsible for replacing the epoch count with the
    425  one given as the parameter. Important: It does not modify any other data, i.e.
    426  keys. Used in ssl_keyupdate_unittests.cc,
    427  DTLSKeyUpdateClient_KeyUpdateMaxEpoch TV.
    428   */
    429 SECStatus SSLInt_AdvanceWriteEpochNum(PRFileDesc *fd, PRUint64 to) {
    430  sslSocket *ss;
    431  ss = ssl_FindSocket(fd);
    432  if (!ss) {
    433    return SECFailure;
    434  }
    435  // As currently the epoch is presented as a uint16, the max_epoch is the
    436  // maximum value of the type
    437  PRUint64 max_epoch = UINT16_MAX;
    438  if (to > max_epoch) {
    439    PORT_SetError(SEC_ERROR_INVALID_ARGS);
    440    return SECFailure;
    441  }
    442 
    443  ssl_GetSpecWriteLock(ss);
    444  ss->ssl3.cwSpec->epoch = to;
    445  ssl_ReleaseSpecWriteLock(ss);
    446  return SECSuccess;
    447 }
    448 
    449 SECStatus SSLInt_AdvanceReadEpochNum(PRFileDesc *fd, PRUint64 to) {
    450  sslSocket *ss;
    451  ss = ssl_FindSocket(fd);
    452  if (!ss) {
    453    return SECFailure;
    454  }
    455 
    456  PRUint64 max_epoch = UINT16_MAX;
    457  if (to > max_epoch) {
    458    PORT_SetError(SEC_ERROR_INVALID_ARGS);
    459    return SECFailure;
    460  }
    461 
    462  ssl_GetSpecReadLock(ss);
    463  ss->ssl3.crSpec->epoch = to;
    464  ssl_ReleaseSpecReadLock(ss);
    465  return SECSuccess;
    466 }
    467 
    468 SECStatus SSLInt_AdvanceWriteSeqByAWindow(PRFileDesc *fd, PRInt32 extra) {
    469  sslSocket *ss;
    470  sslSequenceNumber to;
    471 
    472  ss = ssl_FindSocket(fd);
    473  if (!ss) {
    474    return SECFailure;
    475  }
    476  ssl_GetSpecReadLock(ss);
    477  to = ss->ssl3.cwSpec->nextSeqNum + DTLS_RECVD_RECORDS_WINDOW + extra;
    478  ssl_ReleaseSpecReadLock(ss);
    479  return SSLInt_AdvanceWriteSeqNum(fd, to);
    480 }
    481 
    482 SECStatus SSLInt_AdvanceDtls13DecryptFailures(PRFileDesc *fd, PRUint64 to) {
    483  sslSocket *ss = ssl_FindSocket(fd);
    484  if (!ss) {
    485    return SECFailure;
    486  }
    487 
    488  ssl_GetSpecWriteLock(ss);
    489  ssl3CipherSpec *spec = ss->ssl3.crSpec;
    490  if (spec->cipherDef->type != type_aead) {
    491    ssl_ReleaseSpecWriteLock(ss);
    492    return SECFailure;
    493  }
    494 
    495  spec->deprotectionFailures = to;
    496  ssl_ReleaseSpecWriteLock(ss);
    497  return SECSuccess;
    498 }
    499 
    500 SSLKEAType SSLInt_GetKEAType(SSLNamedGroup group) {
    501  const sslNamedGroupDef *groupDef = ssl_LookupNamedGroup(group);
    502  if (!groupDef) return ssl_kea_null;
    503 
    504  return groupDef->keaType;
    505 }
    506 
    507 SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size) {
    508  sslSocket *ss;
    509 
    510  ss = ssl_FindSocket(fd);
    511  if (!ss) {
    512    return SECFailure;
    513  }
    514 
    515  /* This only works when resuming. */
    516  if (!ss->statelessResume) {
    517    PORT_SetError(SEC_INTERNAL_ONLY);
    518    return SECFailure;
    519  }
    520 
    521  /* Modifying both specs allows this to be used on either peer. */
    522  ssl_GetSpecWriteLock(ss);
    523  ss->ssl3.crSpec->earlyDataRemaining = size;
    524  ss->ssl3.cwSpec->earlyDataRemaining = size;
    525  ssl_ReleaseSpecWriteLock(ss);
    526 
    527  return SECSuccess;
    528 }
    529 
    530 SECStatus SSLInt_HasPendingHandshakeData(PRFileDesc *fd, PRBool *pending) {
    531  sslSocket *ss = ssl_FindSocket(fd);
    532  if (!ss) {
    533    return SECFailure;
    534  }
    535 
    536  ssl_GetSSL3HandshakeLock(ss);
    537  *pending = ss->ssl3.hs.msg_body.len > 0;
    538  ssl_ReleaseSSL3HandshakeLock(ss);
    539  return SECSuccess;
    540 }
    541 
    542 SECStatus SSLInt_SetRawEchConfigForRetry(PRFileDesc *fd, const uint8_t *buf,
    543                                         size_t len) {
    544  sslSocket *ss = ssl_FindSocket(fd);
    545  if (!ss) {
    546    return SECFailure;
    547  }
    548 
    549  sslEchConfig *cfg = (sslEchConfig *)PR_LIST_HEAD(&ss->echConfigs);
    550  SECITEM_FreeItem(&cfg->raw, PR_FALSE);
    551  SECITEM_AllocItem(NULL, &cfg->raw, len);
    552  PORT_Memcpy(cfg->raw.data, buf, len);
    553  return SECSuccess;
    554 }
    555 
    556 PRBool SSLInt_IsIp(PRUint8 *s, unsigned int len) { return tls13_IsIp(s, len); }
    557 
    558 SECStatus SSLInt_GetCertificateCompressionAlgorithm(
    559    PRFileDesc *fd, SSLCertificateCompressionAlgorithm *alg) {
    560  sslSocket *ss = ssl_FindSocket(fd);
    561  if (!ss) {
    562    return SECFailure; /* Code already set. */
    563  }
    564 
    565  PRBool algFound = PR_FALSE;
    566 
    567  if (!ssl_HaveXmitBufLock(ss)) {
    568    ssl_GetSSL3HandshakeLock(ss);
    569  }
    570 
    571  if (!ss->xtnData.compressionAlg) {
    572    if (!ssl_HaveXmitBufLock(ss)) {
    573      ssl_ReleaseSSL3HandshakeLock(ss);
    574    }
    575 
    576    PORT_SetError(SEC_ERROR_INVALID_ARGS);
    577    return SECFailure;
    578  }
    579  for (int i = 0; i < ss->ssl3.supportedCertCompressionAlgorithmsCount; i++) {
    580    if (ss->ssl3.supportedCertCompressionAlgorithms[i].id ==
    581        ss->xtnData.compressionAlg) {
    582      *alg = ss->ssl3.supportedCertCompressionAlgorithms[i];
    583      algFound = PR_TRUE;
    584      break;
    585    }
    586  }
    587 
    588  if (!ssl_HaveXmitBufLock(ss)) {
    589    ssl_ReleaseSSL3HandshakeLock(ss);
    590  }
    591 
    592  if (algFound) {
    593    return SECSuccess;
    594  }
    595  return SECFailure;
    596 }