Source code

Revision control

Copy as Markdown

Other Tools

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* SSL3 Protocol
*
* 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/. */
/* TODO(ekr): Implement HelloVerifyRequest on server side. OK for now. */
#include "cert.h"
#include "ssl.h"
#include "cryptohi.h" /* for DSAU_ stuff */
#include "keyhi.h"
#include "secder.h"
#include "secitem.h"
#include "sechash.h"
#include "sslimpl.h"
#include "sslproto.h"
#include "sslerr.h"
#include "ssl3ext.h"
#include "ssl3exthandle.h"
#include "tls13ech.h"
#include "tls13exthandle.h"
#include "tls13psk.h"
#include "tls13subcerts.h"
#include "prtime.h"
#include "prinrval.h"
#include "prerror.h"
#include "pratom.h"
#include "prthread.h"
#include "nss.h"
#include "nssoptions.h"
#include "pk11func.h"
#include "secmod.h"
#include "blapi.h"
#include <limits.h>
#include <stdio.h>
static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec,
PK11SlotInfo *serverKeySlot);
static SECStatus ssl3_ComputeMasterSecret(sslSocket *ss, PK11SymKey *pms,
PK11SymKey **msp);
static SECStatus ssl3_DeriveConnectionKeys(sslSocket *ss,
PK11SymKey *masterSecret);
static SECStatus ssl3_HandshakeFailure(sslSocket *ss);
static SECStatus ssl3_SendCertificate(sslSocket *ss);
static SECStatus ssl3_SendCertificateRequest(sslSocket *ss);
static SECStatus ssl3_SendNextProto(sslSocket *ss);
static SECStatus ssl3_SendFinished(sslSocket *ss, PRInt32 flags);
static SECStatus ssl3_SendServerHelloDone(sslSocket *ss);
static SECStatus ssl3_SendServerKeyExchange(sslSocket *ss);
static SECStatus ssl3_HandleClientHelloPart2(sslSocket *ss,
SECItem *suites,
sslSessionID *sid,
const PRUint8 *msg,
unsigned int len);
static SECStatus ssl3_HandleServerHelloPart2(sslSocket *ss,
const SECItem *sidBytes,
int *retErrCode);
static SECStatus ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss,
PRUint8 *b,
PRUint32 length);
static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags);
static CK_MECHANISM_TYPE ssl3_GetHashMechanismByHashType(SSLHashType hashType);
static CK_MECHANISM_TYPE ssl3_GetMgfMechanismByHashType(SSLHashType hash);
PRBool ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme);
PRBool ssl_IsRsaeSignatureScheme(SSLSignatureScheme scheme);
PRBool ssl_IsRsaPkcs1SignatureScheme(SSLSignatureScheme scheme);
PRBool ssl_IsDsaSignatureScheme(SSLSignatureScheme scheme);
static SECStatus ssl3_UpdateDefaultHandshakeHashes(sslSocket *ss,
const unsigned char *b,
unsigned int l);
const PRUint32 kSSLSigSchemePolicy =
NSS_USE_ALG_IN_SSL_KX | NSS_USE_ALG_IN_ANY_SIGNATURE;
const PRUint8 ssl_hello_retry_random[] = {
0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E,
0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C
};
PR_STATIC_ASSERT(PR_ARRAY_SIZE(ssl_hello_retry_random) == SSL3_RANDOM_LENGTH);
/* This list of SSL3 cipher suites is sorted in descending order of
* precedence (desirability). It only includes cipher suites we implement.
* This table is modified by SSL3_SetPolicy(). The ordering of cipher suites
* in this table must match the ordering in SSL_ImplementedCiphers (sslenum.c)
*
* Important: See bug 946147 before enabling, reordering, or adding any cipher
* suites to this list.
*/
/* clang-format off */
static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = {
/* cipher_suite policy enabled isPresent */
/* Special TLS 1.3 suites. */
{ TLS_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE },
{ TLS_CHACHA20_POLY1305_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE },
{ TLS_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE },
{ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE},
/* TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA is out of order to work around
*/
{ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256,SSL_ALLOWED,PR_TRUE, PR_FALSE},
{ TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_DHE_DSS_WITH_RC4_128_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDH_ECDSA_WITH_RC4_128_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDH_RSA_WITH_RC4_128_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
/* RSA */
{ TLS_RSA_WITH_AES_128_GCM_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_RSA_WITH_AES_256_GCM_SHA384, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_RSA_WITH_AES_128_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_RSA_WITH_AES_128_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_RSA_WITH_AES_256_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_RSA_WITH_AES_256_CBC_SHA256, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_RSA_WITH_SEED_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_RSA_WITH_RC4_128_SHA, SSL_ALLOWED, PR_TRUE, PR_FALSE},
{ TLS_RSA_WITH_RC4_128_MD5, SSL_ALLOWED, PR_TRUE, PR_FALSE},
/* 56-bit DES "domestic" cipher suites */
{ TLS_DHE_RSA_WITH_DES_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_DHE_DSS_WITH_DES_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_RSA_WITH_DES_CBC_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
/* ciphersuites with no encryption */
{ TLS_ECDHE_ECDSA_WITH_NULL_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDHE_RSA_WITH_NULL_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDH_RSA_WITH_NULL_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_ECDH_ECDSA_WITH_NULL_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_RSA_WITH_NULL_SHA, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_RSA_WITH_NULL_SHA256, SSL_ALLOWED, PR_FALSE, PR_FALSE},
{ TLS_RSA_WITH_NULL_MD5, SSL_ALLOWED, PR_FALSE, PR_FALSE},
};
/* clang-format on */
/* This is the default supported set of signature schemes. The order of the
* hashes here is all that is important, since that will (sometimes) determine
* which hash we use. The key pair (i.e., cert) is the primary thing that
* determines what we use and this doesn't affect how we select key pairs. The
* order of signature types is based on the same rules for ordering we use for
* cipher suites just for consistency.
*/
static const SSLSignatureScheme defaultSignatureSchemes[] = {
ssl_sig_ecdsa_secp256r1_sha256,
ssl_sig_ecdsa_secp384r1_sha384,
ssl_sig_ecdsa_secp521r1_sha512,
ssl_sig_ecdsa_sha1,
ssl_sig_rsa_pss_rsae_sha256,
ssl_sig_rsa_pss_rsae_sha384,
ssl_sig_rsa_pss_rsae_sha512,
ssl_sig_rsa_pkcs1_sha256,
ssl_sig_rsa_pkcs1_sha384,
ssl_sig_rsa_pkcs1_sha512,
ssl_sig_rsa_pkcs1_sha1,
ssl_sig_dsa_sha256,
ssl_sig_dsa_sha384,
ssl_sig_dsa_sha512,
ssl_sig_dsa_sha1
};
PR_STATIC_ASSERT(PR_ARRAY_SIZE(defaultSignatureSchemes) <=
MAX_SIGNATURE_SCHEMES);
/* Verify that SSL_ImplementedCiphers and cipherSuites are in consistent order.
*/
#ifdef DEBUG
void
ssl3_CheckCipherSuiteOrderConsistency()
{
unsigned int i;
PORT_Assert(SSL_NumImplementedCiphers == PR_ARRAY_SIZE(cipherSuites));
for (i = 0; i < PR_ARRAY_SIZE(cipherSuites); ++i) {
PORT_Assert(SSL_ImplementedCiphers[i] == cipherSuites[i].cipher_suite);
}
}
#endif
static const /*SSL3ClientCertificateType */ PRUint8 certificate_types[] = {
ct_RSA_sign,
ct_ECDSA_sign,
ct_DSS_sign,
};
static SSL3Statistics ssl3stats;
static const ssl3KEADef kea_defs[] = {
/* indexed by SSL3KeyExchangeAlgorithm */
/* kea exchKeyType signKeyType authKeyType ephemeral oid */
{ kea_null, ssl_kea_null, nullKey, ssl_auth_null, PR_FALSE, 0 },
{ kea_rsa, ssl_kea_rsa, nullKey, ssl_auth_rsa_decrypt, PR_FALSE, SEC_OID_TLS_RSA },
{ kea_dh_dss, ssl_kea_dh, dsaKey, ssl_auth_dsa, PR_FALSE, SEC_OID_TLS_DH_DSS },
{ kea_dh_rsa, ssl_kea_dh, rsaKey, ssl_auth_rsa_sign, PR_FALSE, SEC_OID_TLS_DH_RSA },
{ kea_dhe_dss, ssl_kea_dh, dsaKey, ssl_auth_dsa, PR_TRUE, SEC_OID_TLS_DHE_DSS },
{ kea_dhe_rsa, ssl_kea_dh, rsaKey, ssl_auth_rsa_sign, PR_TRUE, SEC_OID_TLS_DHE_RSA },
{ kea_dh_anon, ssl_kea_dh, nullKey, ssl_auth_null, PR_TRUE, SEC_OID_TLS_DH_ANON },
{ kea_ecdh_ecdsa, ssl_kea_ecdh, nullKey, ssl_auth_ecdh_ecdsa, PR_FALSE, SEC_OID_TLS_ECDH_ECDSA },
{ kea_ecdhe_ecdsa, ssl_kea_ecdh, ecKey, ssl_auth_ecdsa, PR_TRUE, SEC_OID_TLS_ECDHE_ECDSA },
{ kea_ecdh_rsa, ssl_kea_ecdh, nullKey, ssl_auth_ecdh_rsa, PR_FALSE, SEC_OID_TLS_ECDH_RSA },
{ kea_ecdhe_rsa, ssl_kea_ecdh, rsaKey, ssl_auth_rsa_sign, PR_TRUE, SEC_OID_TLS_ECDHE_RSA },
{ kea_ecdh_anon, ssl_kea_ecdh, nullKey, ssl_auth_null, PR_TRUE, SEC_OID_TLS_ECDH_ANON },
{ kea_ecdhe_psk, ssl_kea_ecdh_psk, nullKey, ssl_auth_psk, PR_TRUE, SEC_OID_TLS_ECDHE_PSK },
{ kea_dhe_psk, ssl_kea_dh_psk, nullKey, ssl_auth_psk, PR_TRUE, SEC_OID_TLS_DHE_PSK },
{ kea_tls13_any, ssl_kea_tls13_any, nullKey, ssl_auth_tls13_any, PR_TRUE, SEC_OID_TLS13_KEA_ANY },
};
/* must use ssl_LookupCipherSuiteDef to access */
static const ssl3CipherSuiteDef cipher_suite_defs[] = {
/* cipher_suite bulk_cipher_alg mac_alg key_exchange_alg prf_hash */
/* Note that the prf_hash_alg is the hash function used by the PRF, see sslimpl.h. */
{ TLS_NULL_WITH_NULL_NULL, cipher_null, ssl_mac_null, kea_null, ssl_hash_none },
{ TLS_RSA_WITH_NULL_MD5, cipher_null, ssl_mac_md5, kea_rsa, ssl_hash_none },
{ TLS_RSA_WITH_NULL_SHA, cipher_null, ssl_mac_sha, kea_rsa, ssl_hash_none },
{ TLS_RSA_WITH_NULL_SHA256, cipher_null, ssl_hmac_sha256, kea_rsa, ssl_hash_sha256 },
{ TLS_RSA_WITH_RC4_128_MD5, cipher_rc4, ssl_mac_md5, kea_rsa, ssl_hash_none },
{ TLS_RSA_WITH_RC4_128_SHA, cipher_rc4, ssl_mac_sha, kea_rsa, ssl_hash_none },
{ TLS_RSA_WITH_DES_CBC_SHA, cipher_des, ssl_mac_sha, kea_rsa, ssl_hash_none },
{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, ssl_mac_sha, kea_rsa, ssl_hash_none },
{ TLS_DHE_DSS_WITH_DES_CBC_SHA, cipher_des, ssl_mac_sha, kea_dhe_dss, ssl_hash_none },
{ TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA,
cipher_3des, ssl_mac_sha, kea_dhe_dss, ssl_hash_none },
{ TLS_DHE_DSS_WITH_RC4_128_SHA, cipher_rc4, ssl_mac_sha, kea_dhe_dss, ssl_hash_none },
{ TLS_DHE_RSA_WITH_DES_CBC_SHA, cipher_des, ssl_mac_sha, kea_dhe_rsa, ssl_hash_none },
{ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
cipher_3des, ssl_mac_sha, kea_dhe_rsa, ssl_hash_none },
/* New TLS cipher suites */
{ TLS_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, ssl_mac_sha, kea_rsa, ssl_hash_none },
{ TLS_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, ssl_hmac_sha256, kea_rsa, ssl_hash_sha256 },
{ TLS_DHE_DSS_WITH_AES_128_CBC_SHA, cipher_aes_128, ssl_mac_sha, kea_dhe_dss, ssl_hash_none },
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, ssl_mac_sha, kea_dhe_rsa, ssl_hash_none },
{ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, ssl_hmac_sha256, kea_dhe_rsa, ssl_hash_sha256 },
{ TLS_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, ssl_mac_sha, kea_rsa, ssl_hash_none },
{ TLS_RSA_WITH_AES_256_CBC_SHA256, cipher_aes_256, ssl_hmac_sha256, kea_rsa, ssl_hash_sha256 },
{ TLS_DHE_DSS_WITH_AES_256_CBC_SHA, cipher_aes_256, ssl_mac_sha, kea_dhe_dss, ssl_hash_none },
{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, ssl_mac_sha, kea_dhe_rsa, ssl_hash_none },
{ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, cipher_aes_256, ssl_hmac_sha256, kea_dhe_rsa, ssl_hash_sha256 },
{ TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, ssl_mac_aead, kea_dhe_rsa, ssl_hash_sha384 },
{ TLS_RSA_WITH_SEED_CBC_SHA, cipher_seed, ssl_mac_sha, kea_rsa, ssl_hash_none },
{ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, cipher_camellia_128, ssl_mac_sha, kea_rsa, ssl_hash_none },
{ TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA,
cipher_camellia_128, ssl_mac_sha, kea_dhe_dss, ssl_hash_none },
{ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,
cipher_camellia_128, ssl_mac_sha, kea_dhe_rsa, ssl_hash_none },
{ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, cipher_camellia_256, ssl_mac_sha, kea_rsa, ssl_hash_none },
{ TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA,
cipher_camellia_256, ssl_mac_sha, kea_dhe_dss, ssl_hash_none },
{ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,
cipher_camellia_256, ssl_mac_sha, kea_dhe_rsa, ssl_hash_none },
{ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, ssl_mac_aead, kea_dhe_rsa, ssl_hash_sha256 },
{ TLS_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, ssl_mac_aead, kea_rsa, ssl_hash_sha256 },
{ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, ssl_mac_aead, kea_ecdhe_rsa, ssl_hash_sha256 },
{ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, ssl_mac_aead, kea_ecdhe_ecdsa, ssl_hash_sha256 },
{ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, ssl_mac_aead, kea_ecdhe_ecdsa, ssl_hash_sha384 },
{ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, ssl_mac_aead, kea_ecdhe_rsa, ssl_hash_sha384 },
{ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, cipher_aes_256, ssl_hmac_sha384, kea_ecdhe_ecdsa, ssl_hash_sha384 },
{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, cipher_aes_256, ssl_hmac_sha384, kea_ecdhe_rsa, ssl_hash_sha384 },
{ TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, ssl_mac_aead, kea_dhe_dss, ssl_hash_sha256 },
{ TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, cipher_aes_128, ssl_hmac_sha256, kea_dhe_dss, ssl_hash_sha256 },
{ TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, cipher_aes_256, ssl_hmac_sha256, kea_dhe_dss, ssl_hash_sha256 },
{ TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, ssl_mac_aead, kea_dhe_dss, ssl_hash_sha384 },
{ TLS_RSA_WITH_AES_256_GCM_SHA384, cipher_aes_256_gcm, ssl_mac_aead, kea_rsa, ssl_hash_sha384 },
{ TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, ssl_mac_aead, kea_dhe_rsa, ssl_hash_sha256 },
{ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, ssl_mac_aead, kea_ecdhe_rsa, ssl_hash_sha256 },
{ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, cipher_chacha20, ssl_mac_aead, kea_ecdhe_ecdsa, ssl_hash_sha256 },
{ TLS_ECDH_ECDSA_WITH_NULL_SHA, cipher_null, ssl_mac_sha, kea_ecdh_ecdsa, ssl_hash_none },
{ TLS_ECDH_ECDSA_WITH_RC4_128_SHA, cipher_rc4, ssl_mac_sha, kea_ecdh_ecdsa, ssl_hash_none },
{ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, ssl_mac_sha, kea_ecdh_ecdsa, ssl_hash_none },
{ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, ssl_mac_sha, kea_ecdh_ecdsa, ssl_hash_none },
{ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, ssl_mac_sha, kea_ecdh_ecdsa, ssl_hash_none },
{ TLS_ECDHE_ECDSA_WITH_NULL_SHA, cipher_null, ssl_mac_sha, kea_ecdhe_ecdsa, ssl_hash_none },
{ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, cipher_rc4, ssl_mac_sha, kea_ecdhe_ecdsa, ssl_hash_none },
{ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, ssl_mac_sha, kea_ecdhe_ecdsa, ssl_hash_none },
{ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, ssl_mac_sha, kea_ecdhe_ecdsa, ssl_hash_none },
{ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, ssl_hmac_sha256, kea_ecdhe_ecdsa, ssl_hash_sha256 },
{ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, ssl_mac_sha, kea_ecdhe_ecdsa, ssl_hash_none },
{ TLS_ECDH_RSA_WITH_NULL_SHA, cipher_null, ssl_mac_sha, kea_ecdh_rsa, ssl_hash_none },
{ TLS_ECDH_RSA_WITH_RC4_128_SHA, cipher_rc4, ssl_mac_sha, kea_ecdh_rsa, ssl_hash_none },
{ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, ssl_mac_sha, kea_ecdh_rsa, ssl_hash_none },
{ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, ssl_mac_sha, kea_ecdh_rsa, ssl_hash_none },
{ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, ssl_mac_sha, kea_ecdh_rsa, ssl_hash_none },
{ TLS_ECDHE_RSA_WITH_NULL_SHA, cipher_null, ssl_mac_sha, kea_ecdhe_rsa, ssl_hash_none },
{ TLS_ECDHE_RSA_WITH_RC4_128_SHA, cipher_rc4, ssl_mac_sha, kea_ecdhe_rsa, ssl_hash_none },
{ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, ssl_mac_sha, kea_ecdhe_rsa, ssl_hash_none },
{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, ssl_mac_sha, kea_ecdhe_rsa, ssl_hash_none },
{ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, cipher_aes_128, ssl_hmac_sha256, kea_ecdhe_rsa, ssl_hash_sha256 },
{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, ssl_mac_sha, kea_ecdhe_rsa, ssl_hash_none },
{ TLS_AES_128_GCM_SHA256, cipher_aes_128_gcm, ssl_mac_aead, kea_tls13_any, ssl_hash_sha256 },
{ TLS_CHACHA20_POLY1305_SHA256, cipher_chacha20, ssl_mac_aead, kea_tls13_any, ssl_hash_sha256 },
{ TLS_AES_256_GCM_SHA384, cipher_aes_256_gcm, ssl_mac_aead, kea_tls13_any, ssl_hash_sha384 },
};
static const CK_MECHANISM_TYPE auth_alg_defs[] = {
CKM_INVALID_MECHANISM, /* ssl_auth_null */
CKM_RSA_PKCS, /* ssl_auth_rsa_decrypt */
CKM_DSA, /* ? _SHA1 */ /* ssl_auth_dsa */
CKM_INVALID_MECHANISM, /* ssl_auth_kea (unused) */
CKM_ECDSA, /* ssl_auth_ecdsa */
CKM_ECDH1_DERIVE, /* ssl_auth_ecdh_rsa */
CKM_ECDH1_DERIVE, /* ssl_auth_ecdh_ecdsa */
CKM_RSA_PKCS, /* ssl_auth_rsa_sign */
CKM_RSA_PKCS_PSS, /* ssl_auth_rsa_pss */
CKM_HKDF_DATA, /* ssl_auth_psk (just check for HKDF) */
CKM_INVALID_MECHANISM /* ssl_auth_tls13_any */
};
PR_STATIC_ASSERT(PR_ARRAY_SIZE(auth_alg_defs) == ssl_auth_size);
static const CK_MECHANISM_TYPE kea_alg_defs[] = {
CKM_INVALID_MECHANISM, /* ssl_kea_null */
CKM_RSA_PKCS, /* ssl_kea_rsa */
CKM_DH_PKCS_DERIVE, /* ssl_kea_dh */
CKM_INVALID_MECHANISM, /* ssl_kea_fortezza (unused) */
CKM_ECDH1_DERIVE, /* ssl_kea_ecdh */
CKM_ECDH1_DERIVE, /* ssl_kea_ecdh_psk */
CKM_DH_PKCS_DERIVE, /* ssl_kea_dh_psk */
CKM_INVALID_MECHANISM, /* ssl_kea_tls13_any */
CKM_INVALID_MECHANISM, /* ssl_kea_ecdh_hybrid */
CKM_INVALID_MECHANISM, /* ssl_kea_ecdh_hybrid_psk */
};
PR_STATIC_ASSERT(PR_ARRAY_SIZE(kea_alg_defs) == ssl_kea_size);
typedef struct SSLCipher2MechStr {
SSLCipherAlgorithm calg;
CK_MECHANISM_TYPE cmech;
} SSLCipher2Mech;
/* indexed by type SSLCipherAlgorithm */
static const SSLCipher2Mech alg2Mech[] = {
/* calg, cmech */
{ ssl_calg_null, CKM_INVALID_MECHANISM },
{ ssl_calg_rc4, CKM_RC4 },
{ ssl_calg_rc2, CKM_RC2_CBC },
{ ssl_calg_des, CKM_DES_CBC },
{ ssl_calg_3des, CKM_DES3_CBC },
{ ssl_calg_idea, CKM_IDEA_CBC },
{ ssl_calg_fortezza, CKM_SKIPJACK_CBC64 },
{ ssl_calg_aes, CKM_AES_CBC },
{ ssl_calg_camellia, CKM_CAMELLIA_CBC },
{ ssl_calg_seed, CKM_SEED_CBC },
{ ssl_calg_aes_gcm, CKM_AES_GCM },
{ ssl_calg_chacha20, CKM_CHACHA20_POLY1305 },
};
const PRUint8 tls12_downgrade_random[] = { 0x44, 0x4F, 0x57, 0x4E,
0x47, 0x52, 0x44, 0x01 };
const PRUint8 tls1_downgrade_random[] = { 0x44, 0x4F, 0x57, 0x4E,
0x47, 0x52, 0x44, 0x00 };
PR_STATIC_ASSERT(sizeof(tls12_downgrade_random) ==
sizeof(tls1_downgrade_random));
/* The ECCWrappedKeyInfo structure defines how various pieces of
* information are laid out within wrappedSymmetricWrappingkey
* for ECDH key exchange. Since wrappedSymmetricWrappingkey is
* a 512-byte buffer (see sslimpl.h), the variable length field
* in ECCWrappedKeyInfo can be at most (512 - 8) = 504 bytes.
*
* XXX For now, NSS only supports named elliptic curves of size 571 bits
* or smaller. The public value will fit within 145 bytes and EC params
* will fit within 12 bytes. We'll need to revisit this when NSS
* supports arbitrary curves.
*/
#define MAX_EC_WRAPPED_KEY_BUFLEN 504
typedef struct ECCWrappedKeyInfoStr {
PRUint16 size; /* EC public key size in bits */
PRUint16 encodedParamLen; /* length (in bytes) of DER encoded EC params */
PRUint16 pubValueLen; /* length (in bytes) of EC public value */
PRUint16 wrappedKeyLen; /* length (in bytes) of the wrapped key */
PRUint8 var[MAX_EC_WRAPPED_KEY_BUFLEN]; /* this buffer contains the */
/* EC public-key params, the EC public value and the wrapped key */
} ECCWrappedKeyInfo;
CK_MECHANISM_TYPE
ssl3_Alg2Mech(SSLCipherAlgorithm calg)
{
PORT_Assert(alg2Mech[calg].calg == calg);
return alg2Mech[calg].cmech;
}
#if defined(TRACE)
static char *
ssl3_DecodeHandshakeType(int msgType)
{
char *rv;
static char line[40];
switch (msgType) {
case ssl_hs_hello_request:
rv = "hello_request (0)";
break;
case ssl_hs_client_hello:
rv = "client_hello (1)";
break;
case ssl_hs_server_hello:
rv = "server_hello (2)";
break;
case ssl_hs_hello_verify_request:
rv = "hello_verify_request (3)";
break;
case ssl_hs_new_session_ticket:
rv = "new_session_ticket (4)";
break;
case ssl_hs_end_of_early_data:
rv = "end_of_early_data (5)";
break;
case ssl_hs_hello_retry_request:
rv = "hello_retry_request (6)";
break;
case ssl_hs_encrypted_extensions:
rv = "encrypted_extensions (8)";
break;
case ssl_hs_certificate:
rv = "certificate (11)";
break;
case ssl_hs_server_key_exchange:
rv = "server_key_exchange (12)";
break;
case ssl_hs_certificate_request:
rv = "certificate_request (13)";
break;
case ssl_hs_server_hello_done:
rv = "server_hello_done (14)";
break;
case ssl_hs_certificate_verify:
rv = "certificate_verify (15)";
break;
case ssl_hs_client_key_exchange:
rv = "client_key_exchange (16)";
break;
case ssl_hs_finished:
rv = "finished (20)";
break;
case ssl_hs_certificate_status:
rv = "certificate_status (22)";
break;
case ssl_hs_key_update:
rv = "key_update (24)";
break;
case ssl_hs_compressed_certificate:
rv = "compressed certificate (25)";
break;
default:
snprintf(line, sizeof(line), "*UNKNOWN* handshake type! (%d)", msgType);
rv = line;
}
return rv;
}
static char *
ssl3_DecodeContentType(int msgType)
{
char *rv;
static char line[40];
switch (msgType) {
case ssl_ct_change_cipher_spec:
rv = "change_cipher_spec (20)";
break;
case ssl_ct_alert:
rv = "alert (21)";
break;
case ssl_ct_handshake:
rv = "handshake (22)";
break;
case ssl_ct_application_data:
rv = "application_data (23)";
break;
case ssl_ct_ack:
rv = "ack (26)";
break;
default:
snprintf(line, sizeof(line), "*UNKNOWN* record type! (%d)", msgType);
rv = line;
}
return rv;
}
#endif
PRBool
ssl_HaveRecvBufLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
return PZ_InMonitor(ss->recvBufLock);
} else {
return PR_TRUE;
}
}
PRBool
ssl_HaveXmitBufLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
return PZ_InMonitor(ss->xmitBufLock);
} else {
return PR_TRUE;
}
}
PRBool
ssl_Have1stHandshakeLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
return PZ_InMonitor(ss->firstHandshakeLock);
} else {
return PR_TRUE;
}
}
PRBool
ssl_HaveSSL3HandshakeLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
return PZ_InMonitor(ss->ssl3HandshakeLock);
} else {
return PR_TRUE;
}
}
PRBool
ssl_HaveSpecWriteLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
return NSSRWLock_HaveWriteLock(ss->specLock);
} else {
return PR_TRUE;
}
}
/* firstHandshakeLock -> recvBufLock */
void
ssl_Get1stHandshakeLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
PORT_Assert(PZ_InMonitor(ss->firstHandshakeLock) ||
!ssl_HaveRecvBufLock(ss));
PZ_EnterMonitor(ss->firstHandshakeLock);
}
}
void
ssl_Release1stHandshakeLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
PZ_ExitMonitor(ss->firstHandshakeLock);
}
}
void
ssl_GetSSL3HandshakeLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
PORT_Assert(!ssl_HaveXmitBufLock(ss));
PZ_EnterMonitor(ss->ssl3HandshakeLock);
}
}
void
ssl_ReleaseSSL3HandshakeLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
PZ_ExitMonitor(ss->ssl3HandshakeLock);
}
}
void
ssl_GetSpecReadLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
NSSRWLock_LockRead(ss->specLock);
}
}
void
ssl_ReleaseSpecReadLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
NSSRWLock_UnlockRead(ss->specLock);
}
}
/* NSSRWLock_HaveReadLock is not exported so there's no
* ssl_HaveSpecReadLock. */
void
ssl_GetSpecWriteLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
NSSRWLock_LockWrite(ss->specLock);
}
}
void
ssl_ReleaseSpecWriteLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
NSSRWLock_UnlockWrite(ss->specLock);
}
}
/* recvBufLock -> ssl3HandshakeLock -> xmitBufLock */
void
ssl_GetRecvBufLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
PORT_Assert(!ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(!ssl_HaveXmitBufLock(ss));
PZ_EnterMonitor(ss->recvBufLock);
}
}
void
ssl_ReleaseRecvBufLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
PZ_ExitMonitor(ss->recvBufLock);
}
}
/* xmitBufLock -> specLock */
void
ssl_GetXmitBufLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
PZ_EnterMonitor(ss->xmitBufLock);
}
}
void
ssl_ReleaseXmitBufLock(sslSocket *ss)
{
if (!ss->opt.noLocks) {
PZ_ExitMonitor(ss->xmitBufLock);
}
}
SSL3Statistics *
SSL_GetStatistics(void)
{
return &ssl3stats;
}
typedef struct tooLongStr {
#if defined(IS_LITTLE_ENDIAN)
PRInt32 low;
PRInt32 high;
#else
PRInt32 high;
PRInt32 low;
#endif
} tooLong;
void
SSL_AtomicIncrementLong(long *x)
{
if ((sizeof *x) == sizeof(PRInt32)) {
PR_ATOMIC_INCREMENT((PRInt32 *)x);
} else {
tooLong *tl = (tooLong *)x;
if (PR_ATOMIC_INCREMENT(&tl->low) == 0)
PR_ATOMIC_INCREMENT(&tl->high);
}
}
PRBool
ssl3_CipherSuiteAllowedForVersionRange(ssl3CipherSuite cipherSuite,
const SSLVersionRange *vrange)
{
switch (cipherSuite) {
case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
case TLS_RSA_WITH_AES_256_CBC_SHA256:
case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
case TLS_RSA_WITH_AES_128_CBC_SHA256:
case TLS_RSA_WITH_AES_128_GCM_SHA256:
case TLS_RSA_WITH_AES_256_GCM_SHA384:
case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
case TLS_RSA_WITH_NULL_SHA256:
case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
case TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256:
case TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
case TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256:
return vrange->max >= SSL_LIBRARY_VERSION_TLS_1_2 &&
vrange->min < SSL_LIBRARY_VERSION_TLS_1_3;
/* RFC 4492: ECC cipher suites need TLS extensions to negotiate curves and
* point formats.*/
case TLS_ECDH_ECDSA_WITH_NULL_SHA:
case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
case TLS_ECDH_RSA_WITH_NULL_SHA:
case TLS_ECDH_RSA_WITH_RC4_128_SHA:
case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
case TLS_ECDHE_RSA_WITH_NULL_SHA:
case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
return vrange->max >= SSL_LIBRARY_VERSION_TLS_1_0 &&
vrange->min < SSL_LIBRARY_VERSION_TLS_1_3;
case TLS_AES_128_GCM_SHA256:
case TLS_AES_256_GCM_SHA384:
case TLS_CHACHA20_POLY1305_SHA256:
return vrange->max >= SSL_LIBRARY_VERSION_TLS_1_3;
default:
return vrange->min < SSL_LIBRARY_VERSION_TLS_1_3;
}
}
/* return pointer to ssl3CipherSuiteDef for suite, or NULL */
/* XXX This does a linear search. A binary search would be better. */
const ssl3CipherSuiteDef *
ssl_LookupCipherSuiteDef(ssl3CipherSuite suite)
{
int cipher_suite_def_len =
sizeof(cipher_suite_defs) / sizeof(cipher_suite_defs[0]);
int i;
for (i = 0; i < cipher_suite_def_len; i++) {
if (cipher_suite_defs[i].cipher_suite == suite)
return &cipher_suite_defs[i];
}
PORT_Assert(PR_FALSE); /* We should never get here. */
PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
return NULL;
}
/* Find the cipher configuration struct associate with suite */
/* XXX This does a linear search. A binary search would be better. */
static ssl3CipherSuiteCfg *
ssl_LookupCipherSuiteCfgMutable(ssl3CipherSuite suite,
ssl3CipherSuiteCfg *suites)
{
int i;
for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
if (suites[i].cipher_suite == suite)
return &suites[i];
}
/* return NULL and let the caller handle it. */
PORT_SetError(SSL_ERROR_UNKNOWN_CIPHER_SUITE);
return NULL;
}
const ssl3CipherSuiteCfg *
ssl_LookupCipherSuiteCfg(ssl3CipherSuite suite, const ssl3CipherSuiteCfg *suites)
{
return ssl_LookupCipherSuiteCfgMutable(suite,
CONST_CAST(ssl3CipherSuiteCfg, suites));
}
static PRBool
ssl_NamedGroupTypeEnabled(const sslSocket *ss, SSLKEAType keaType)
{
unsigned int i;
for (i = 0; i < SSL_NAMED_GROUP_COUNT; ++i) {
if (ss->namedGroupPreferences[i] &&
ss->namedGroupPreferences[i]->keaType == keaType) {
return PR_TRUE;
}
}
return PR_FALSE;
}
static PRBool
ssl_KEAEnabled(const sslSocket *ss, SSLKEAType keaType)
{
switch (keaType) {
case ssl_kea_rsa:
return PR_TRUE;
case ssl_kea_dh:
case ssl_kea_dh_psk: {
if (ss->sec.isServer && !ss->opt.enableServerDhe) {
return PR_FALSE;
}
if (ss->sec.isServer) {
/* If the server requires named FFDHE groups, then the client
* must have included an FFDHE group. peerSupportsFfdheGroups
* is set to true in ssl_HandleSupportedGroupsXtn(). */
if (ss->opt.requireDHENamedGroups &&
!ss->xtnData.peerSupportsFfdheGroups) {
return PR_FALSE;
}
/* We can use the weak DH group if all of these are true:
* 1. We don't require named groups.
* 2. The peer doesn't support named groups.
* 3. This isn't TLS 1.3.
* 4. The weak group is enabled. */
if (!ss->opt.requireDHENamedGroups &&
!ss->xtnData.peerSupportsFfdheGroups &&
ss->version < SSL_LIBRARY_VERSION_TLS_1_3 &&
ss->ssl3.dheWeakGroupEnabled) {
return PR_TRUE;
}
} else {
if (ss->vrange.min < SSL_LIBRARY_VERSION_TLS_1_3 &&
!ss->opt.requireDHENamedGroups) {
/* The client enables DHE cipher suites even if no DHE groups
* are enabled. Only if this isn't TLS 1.3 and named groups
* are not required. */
return PR_TRUE;
}
}
return ssl_NamedGroupTypeEnabled(ss, ssl_kea_dh);
}
case ssl_kea_ecdh:
case ssl_kea_ecdh_psk:
return ssl_NamedGroupTypeEnabled(ss, ssl_kea_ecdh);
case ssl_kea_ecdh_hybrid:
case ssl_kea_ecdh_hybrid_psk:
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
return PR_FALSE;
}
return ssl_NamedGroupTypeEnabled(ss, ssl_kea_ecdh_hybrid);
case ssl_kea_tls13_any:
return PR_TRUE;
case ssl_kea_fortezza:
default:
PORT_Assert(0);
}
return PR_FALSE;
}
static PRBool
ssl_HasCert(const sslSocket *ss, PRUint16 maxVersion, SSLAuthType authType)
{
PRCList *cursor;
if (authType == ssl_auth_null || authType == ssl_auth_psk || authType == ssl_auth_tls13_any) {
return PR_TRUE;
}
for (cursor = PR_NEXT_LINK(&ss->serverCerts);
cursor != &ss->serverCerts;
cursor = PR_NEXT_LINK(cursor)) {
sslServerCert *cert = (sslServerCert *)cursor;
if (!cert->serverKeyPair ||
!cert->serverKeyPair->privKey ||
!cert->serverCertChain ||
!SSL_CERT_IS(cert, authType)) {
continue;
}
/* When called from ssl3_config_match_init(), all the EC curves will be
* enabled, so this will essentially do nothing (unless we implement
* curve configuration). However, once we have seen the
* supported_groups extension and this is called from config_match(),
* this will filter out certificates with an unsupported curve.
*
* If we might negotiate TLS 1.3, skip this test as group configuration
* doesn't affect choices in TLS 1.3.
*/
if (maxVersion < SSL_LIBRARY_VERSION_TLS_1_3 &&
(authType == ssl_auth_ecdsa ||
authType == ssl_auth_ecdh_ecdsa ||
authType == ssl_auth_ecdh_rsa) &&
!ssl_NamedGroupEnabled(ss, cert->namedCurve)) {
continue;
}
return PR_TRUE;
}
if (authType == ssl_auth_rsa_sign) {
return ssl_HasCert(ss, maxVersion, ssl_auth_rsa_pss);
}
return PR_FALSE;
}
/* return true if the scheme is allowed by policy, This prevents
* failures later when our actual signatures are rejected by
* policy by either ssl code, or lower level NSS code */
static PRBool
ssl_SchemePolicyOK(SSLSignatureScheme scheme, PRUint32 require)
{
/* Hash policy. */
PRUint32 policy;
SECOidTag hashOID = ssl3_HashTypeToOID(ssl_SignatureSchemeToHashType(scheme));
SECOidTag sigOID;
/* policy bits needed to enable a SignatureScheme */
SECStatus rv = NSS_GetAlgorithmPolicy(hashOID, &policy);
if (rv == SECSuccess &&
(policy & require) != require) {
return PR_FALSE;
}
/* ssl_SignatureSchemeToAuthType reports rsa for rsa_pss_rsae, but we
* actually implement pss signatures when we sign, so just use RSA_PSS
* for all RSA PSS Siganture schemes */
if (ssl_IsRsaPssSignatureScheme(scheme)) {
sigOID = SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
} else {
sigOID = ssl3_AuthTypeToOID(ssl_SignatureSchemeToAuthType(scheme));
}
/* Signature Policy. */
rv = NSS_GetAlgorithmPolicy(sigOID, &policy);
if (rv == SECSuccess &&
(policy & require) != require) {
return PR_FALSE;
}
return PR_TRUE;
}
/* Check that a signature scheme is accepted.
* Both by policy and by having a token that supports it. */
static PRBool
ssl_SignatureSchemeAccepted(PRUint16 minVersion,
SSLSignatureScheme scheme,
PRBool forCert)
{
/* Disable RSA-PSS schemes if there are no tokens to verify them. */
if (ssl_IsRsaPssSignatureScheme(scheme)) {
if (!PK11_TokenExists(auth_alg_defs[ssl_auth_rsa_pss])) {
return PR_FALSE;
}
} else if (!forCert && ssl_IsRsaPkcs1SignatureScheme(scheme)) {
/* Disable PKCS#1 signatures if we are limited to TLS 1.3.
* We still need to advertise PKCS#1 signatures in CH and CR
* for certificate signatures.
*/
if (minVersion >= SSL_LIBRARY_VERSION_TLS_1_3) {
return PR_FALSE;
}
} else if (ssl_IsDsaSignatureScheme(scheme)) {
/* DSA: not in TLS 1.3, and check policy. */
if (minVersion >= SSL_LIBRARY_VERSION_TLS_1_3) {
return PR_FALSE;
}
}
return ssl_SchemePolicyOK(scheme, kSSLSigSchemePolicy);
}
static SECStatus
ssl_CheckSignatureSchemes(sslSocket *ss)
{
if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_2) {
return SECSuccess;
}
/* If this is a server using TLS 1.3, we just need to have one signature
* scheme for which we have a usable certificate.
*
* Note: Certificates for earlier TLS versions are checked along with the
* cipher suite in ssl3_config_match_init. */
if (ss->sec.isServer && ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) {
PRBool foundCert = PR_FALSE;
for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
SSLAuthType authType =
ssl_SignatureSchemeToAuthType(ss->ssl3.signatureSchemes[i]);
if (ssl_HasCert(ss, ss->vrange.max, authType)) {
foundCert = PR_TRUE;
break;
}
}
if (!foundCert) {
PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
return SECFailure;
}
}
/* Ensure that there is a signature scheme that can be accepted.*/
for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
if (ssl_SignatureSchemeAccepted(ss->vrange.min,
ss->ssl3.signatureSchemes[i],
PR_FALSE /* forCert */)) {
return SECSuccess;
}
}
PORT_SetError(SSL_ERROR_NO_SUPPORTED_SIGNATURE_ALGORITHM);
return SECFailure;
}
/* For a server, check that a signature scheme that can be used with the
* provided authType is both enabled and usable. */
static PRBool
ssl_HasSignatureScheme(const sslSocket *ss, SSLAuthType authType)
{
PORT_Assert(ss->sec.isServer);
PORT_Assert(ss->ssl3.hs.preliminaryInfo & ssl_preinfo_version);
PORT_Assert(authType != ssl_auth_null);
PORT_Assert(authType != ssl_auth_tls13_any);
if (ss->version < SSL_LIBRARY_VERSION_TLS_1_2 ||
authType == ssl_auth_rsa_decrypt ||
authType == ssl_auth_ecdh_rsa ||
authType == ssl_auth_ecdh_ecdsa) {
return PR_TRUE;
}
for (unsigned int i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
SSLSignatureScheme scheme = ss->ssl3.signatureSchemes[i];
SSLAuthType schemeAuthType = ssl_SignatureSchemeToAuthType(scheme);
PRBool acceptable = authType == schemeAuthType ||
(schemeAuthType == ssl_auth_rsa_pss &&
authType == ssl_auth_rsa_sign);
if (acceptable && ssl_SignatureSchemeAccepted(ss->version, scheme, PR_FALSE /* forCert */)) {
return PR_TRUE;
}
}
return PR_FALSE;
}
/* Initialize the suite->isPresent value for config_match
* Returns count of enabled ciphers supported by extant tokens,
* regardless of policy or user preference.
* If this returns zero, the user cannot do SSL v3.
*/
unsigned int
ssl3_config_match_init(sslSocket *ss)
{
ssl3CipherSuiteCfg *suite;
const ssl3CipherSuiteDef *cipher_def;
SSLCipherAlgorithm cipher_alg;
CK_MECHANISM_TYPE cipher_mech;
SSLAuthType authType;
SSLKEAType keaType;
unsigned int i;
unsigned int numPresent = 0;
unsigned int numEnabled = 0;
PORT_Assert(ss);
if (!ss) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return 0;
}
if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) {
return 0;
}
if (ss->sec.isServer && ss->psk &&
PR_CLIST_IS_EMPTY(&ss->serverCerts) &&
(ss->opt.requestCertificate || ss->opt.requireCertificate)) {
/* PSK and certificate auth cannot be combined. */
PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
return 0;
}
if (ssl_CheckSignatureSchemes(ss) != SECSuccess) {
return 0; /* Code already set. */
}
ssl_FilterSupportedGroups(ss);
for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
suite = &ss->cipherSuites[i];
if (suite->enabled) {
++numEnabled;
/* We need the cipher defs to see if we have a token that can handle
* this cipher. It isn't part of the static definition.
*/
cipher_def = ssl_LookupCipherSuiteDef(suite->cipher_suite);
if (!cipher_def) {
suite->isPresent = PR_FALSE;
continue;
}
cipher_alg = ssl_GetBulkCipherDef(cipher_def)->calg;
cipher_mech = ssl3_Alg2Mech(cipher_alg);
/* Mark the suites that are backed by real tokens, certs and keys */
suite->isPresent = PR_TRUE;
authType = kea_defs[cipher_def->key_exchange_alg].authKeyType;
if (authType != ssl_auth_null && authType != ssl_auth_tls13_any) {
if (ss->sec.isServer &&
!(ssl_HasCert(ss, ss->vrange.max, authType) &&
ssl_HasSignatureScheme(ss, authType))) {
suite->isPresent = PR_FALSE;
} else if (!PK11_TokenExists(auth_alg_defs[authType])) {
suite->isPresent = PR_FALSE;
}
}
keaType = kea_defs[cipher_def->key_exchange_alg].exchKeyType;
if (keaType != ssl_kea_null &&
keaType != ssl_kea_tls13_any &&
!PK11_TokenExists(kea_alg_defs[keaType])) {
suite->isPresent = PR_FALSE;
}
if (cipher_alg != ssl_calg_null &&
!PK11_TokenExists(cipher_mech)) {
suite->isPresent = PR_FALSE;
}
if (suite->isPresent) {
++numPresent;
}
}
}
PORT_AssertArg(numPresent > 0 || numEnabled == 0);
if (numPresent == 0) {
PORT_SetError(SSL_ERROR_NO_CIPHERS_SUPPORTED);
}
return numPresent;
}
/* Return PR_TRUE if suite is usable. This if the suite is permitted by policy,
* enabled, has a certificate (as needed), has a viable key agreement method, is
* usable with the negotiated TLS version, and is otherwise usable. */
PRBool
ssl3_config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy,
const SSLVersionRange *vrange, const sslSocket *ss)
{
const ssl3CipherSuiteDef *cipher_def;
const ssl3KEADef *kea_def;
if (!suite) {
PORT_Assert(suite);
return PR_FALSE;
}
PORT_Assert(policy != SSL_NOT_ALLOWED);
if (policy == SSL_NOT_ALLOWED)
return PR_FALSE;
if (!suite->enabled || !suite->isPresent)
return PR_FALSE;
if ((suite->policy == SSL_NOT_ALLOWED) ||
(suite->policy > policy))
return PR_FALSE;
PORT_Assert(ss != NULL);
cipher_def = ssl_LookupCipherSuiteDef(suite->cipher_suite);
PORT_Assert(cipher_def != NULL);
kea_def = &kea_defs[cipher_def->key_exchange_alg];
PORT_Assert(kea_def != NULL);
if (!ssl_KEAEnabled(ss, kea_def->exchKeyType)) {
return PR_FALSE;
}
if (ss->sec.isServer && !ssl_HasCert(ss, vrange->max, kea_def->authKeyType)) {
return PR_FALSE;
}
/* If a PSK is selected, disable suites that use a different hash than
* the PSK. We advertise non-PSK-compatible suites in the CH, as we could
* fallback to certificate auth. The client handler will check hash
* compatibility before committing to use the PSK. */
if (ss->xtnData.selectedPsk) {
if (ss->xtnData.selectedPsk->hash != cipher_def->prf_hash) {
return PR_FALSE;
}
}
return ssl3_CipherSuiteAllowedForVersionRange(suite->cipher_suite, vrange);
}
/* For TLS 1.3, when resuming, check for a ciphersuite that is both compatible
* with the identified ciphersuite and enabled. */
static PRBool
tls13_ResumptionCompatible(sslSocket *ss, ssl3CipherSuite suite)
{
SSLVersionRange vrange = { SSL_LIBRARY_VERSION_TLS_1_3,
SSL_LIBRARY_VERSION_TLS_1_3 };
SSLHashType hash = tls13_GetHashForCipherSuite(suite);
for (unsigned int i = 0; i < PR_ARRAY_SIZE(cipher_suite_defs); i++) {
if (cipher_suite_defs[i].prf_hash == hash) {
const ssl3CipherSuiteCfg *suiteCfg =
ssl_LookupCipherSuiteCfg(cipher_suite_defs[i].cipher_suite,
ss->cipherSuites);
if (suite && ssl3_config_match(suiteCfg, ss->ssl3.policy, &vrange, ss)) {
return PR_TRUE;
}
}
}
return PR_FALSE;
}
/*
* Null compression, mac and encryption functions
*/
SECStatus
Null_Cipher(void *ctx, unsigned char *output, unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
if (inputLen > maxOutputLen) {
*outputLen = 0; /* Match PK11_CipherOp in setting outputLen */
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
*outputLen = inputLen;
if (inputLen > 0 && input != output) {
PORT_Memcpy(output, input, inputLen);
}
return SECSuccess;
}
/* Wrapper around PK11_CipherOp to avoid undefined behavior due to incompatible
* function pointer type cast
*/
static SECStatus
SSLCipher_PK11_CipherOp(void *ctx, unsigned char *output, unsigned int *outputLen, unsigned int maxOutputLen,
const unsigned char *input, unsigned int inputLen)
{
PK11Context *pctx = ctx;
PORT_Assert(maxOutputLen <= INT_MAX);
int signedOutputLen = maxOutputLen;
SECStatus rv = PK11_CipherOp(pctx, output, &signedOutputLen, maxOutputLen, input, inputLen);
PORT_Assert(signedOutputLen >= 0);
*outputLen = signedOutputLen;
return rv;
}
/*
* SSL3 Utility functions
*/
static void
ssl_SetSpecVersions(sslSocket *ss, ssl3CipherSpec *spec)
{
spec->version = ss->version;
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
tls13_SetSpecRecordVersion(ss, spec);
} else if (IS_DTLS(ss)) {
spec->recordVersion = dtls_TLSVersionToDTLSVersion(ss->version);
} else {
spec->recordVersion = ss->version;
}
}
/* allowLargerPeerVersion controls whether the function will select the
* highest enabled SSL version or fail when peerVersion is greater than the
* highest enabled version.
*
* If allowLargerPeerVersion is true, peerVersion is the peer's highest
* enabled version rather than the peer's selected version.
*/
SECStatus
ssl3_NegotiateVersion(sslSocket *ss, SSL3ProtocolVersion peerVersion,
PRBool allowLargerPeerVersion)
{
SSL3ProtocolVersion negotiated;
/* Prevent negotiating to a lower version in response to a TLS 1.3 HRR. */
if (ss->ssl3.hs.helloRetry) {
PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
return SECFailure;
}
if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) {
PORT_SetError(SSL_ERROR_SSL_DISABLED);
return SECFailure;
}
if (peerVersion < ss->vrange.min ||
(peerVersion > ss->vrange.max && !allowLargerPeerVersion)) {
PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
return SECFailure;
}
negotiated = PR_MIN(peerVersion, ss->vrange.max);
PORT_Assert(ssl3_VersionIsSupported(ss->protocolVariant, negotiated));
if (ss->firstHsDone && ss->version != negotiated) {
PORT_SetError(SSL_ERROR_UNSUPPORTED_VERSION);
return SECFailure;
}
ss->version = negotiated;
return SECSuccess;
}
/* Used by the client when the server produces a version number.
* This reads, validates, and normalizes the value. */
SECStatus
ssl_ClientReadVersion(sslSocket *ss, PRUint8 **b, unsigned int *len,
SSL3ProtocolVersion *version)
{
SSL3ProtocolVersion v;
PRUint32 temp;
SECStatus rv;
rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 2, b, len);
if (rv != SECSuccess) {
return SECFailure; /* alert has been sent */
}
v = (SSL3ProtocolVersion)temp;
if (IS_DTLS(ss)) {
v = dtls_DTLSVersionToTLSVersion(v);
/* Check for failure. */
if (!v || v > SSL_LIBRARY_VERSION_MAX_SUPPORTED) {
SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
return SECFailure;
}
}
/* You can't negotiate TLS 1.3 this way. */
if (v >= SSL_LIBRARY_VERSION_TLS_1_3) {
SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
return SECFailure;
}
*version = v;
return SECSuccess;
}
SECStatus
ssl3_GetNewRandom(SSL3Random random)
{
SECStatus rv;
rv = PK11_GenerateRandom(random, SSL3_RANDOM_LENGTH);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE);
}
return rv;
}
/* this only implements TLS 1.2 and earlier signatures */
static SECStatus
ssl3_SignHashesWithPrivKey(SSL3Hashes *hash, SECKEYPrivateKey *key,
SSLSignatureScheme scheme, PRBool isTls, SECItem *buf)
{
SECStatus rv = SECFailure;
PRBool doDerEncode = PR_FALSE;
PRBool useRsaPss = ssl_IsRsaPssSignatureScheme(scheme);
SECItem hashItem;
buf->data = NULL;
switch (SECKEY_GetPrivateKeyType(key)) {
case rsaKey:
hashItem.data = hash->u.raw;
hashItem.len = hash->len;
break;
case dsaKey:
doDerEncode = isTls;
/* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash.
* In that case, we use just the SHA1 part. */
if (hash->hashAlg == ssl_hash_none) {
hashItem.data = hash->u.s.sha;
hashItem.len = sizeof(hash->u.s.sha);
} else {
hashItem.data = hash->u.raw;
hashItem.len = hash->len;
}
break;
case ecKey:
doDerEncode = PR_TRUE;
/* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash.
* In that case, we use just the SHA1 part. */
if (hash->hashAlg == ssl_hash_none) {
hashItem.data = hash->u.s.sha;
hashItem.len = sizeof(hash->u.s.sha);
} else {
hashItem.data = hash->u.raw;
hashItem.len = hash->len;
}
break;
default:
PORT_SetError(SEC_ERROR_INVALID_KEY);
goto done;
}
PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len));
if (useRsaPss || hash->hashAlg == ssl_hash_none) {
CK_MECHANISM_TYPE mech = PK11_MapSignKeyType(key->keyType);
int signatureLen = PK11_SignatureLen(key);
PRInt32 optval;
SECItem *params = NULL;
CK_RSA_PKCS_PSS_PARAMS pssParams;
SECItem pssParamsItem = { siBuffer,
(unsigned char *)&pssParams,
sizeof(pssParams) };
if (signatureLen <= 0) {
PORT_SetError(SEC_ERROR_INVALID_KEY);
goto done;
}
/* since we are calling PK11_SignWithMechanism directly, we need to
* check the key policy ourselves (which is already checked in
* SGN_Digest) */
rv = NSS_OptionGet(NSS_KEY_SIZE_POLICY_FLAGS, &optval);
if ((rv == SECSuccess) &&
((optval & NSS_KEY_SIZE_POLICY_SIGN_FLAG) == NSS_KEY_SIZE_POLICY_SIGN_FLAG)) {
rv = SECKEY_EnforceKeySize(key->keyType, SECKEY_PrivateKeyStrengthInBits(key),
SEC_ERROR_SIGNATURE_ALGORITHM_DISABLED);
if (rv != SECSuccess) {
goto done; /* error code already set */
}
}
buf->len = (unsigned)signatureLen;
buf->data = (unsigned char *)PORT_Alloc(signatureLen);
if (!buf->data)
goto done; /* error code was set. */
if (useRsaPss) {
pssParams.hashAlg = ssl3_GetHashMechanismByHashType(hash->hashAlg);
pssParams.mgf = ssl3_GetMgfMechanismByHashType(hash->hashAlg);
pssParams.sLen = hashItem.len;
params = &pssParamsItem;
mech = CKM_RSA_PKCS_PSS;
}
rv = PK11_SignWithMechanism(key, mech, params, buf, &hashItem);
} else {
SECOidTag hashOID = ssl3_HashTypeToOID(hash->hashAlg);
rv = SGN_Digest(key, hashOID, buf, &hashItem);
}
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
} else if (doDerEncode) {
SECItem derSig = { siBuffer, NULL, 0 };
/* This also works for an ECDSA signature */
rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
if (rv == SECSuccess) {
PORT_Free(buf->data); /* discard unencoded signature. */
*buf = derSig; /* give caller encoded signature. */
} else if (derSig.data) {
PORT_Free(derSig.data);
}
}
PRINT_BUF(60, (NULL, "signed hashes", (unsigned char *)buf->data, buf->len));
done:
if (rv != SECSuccess && buf->data) {
PORT_Free(buf->data);
buf->data = NULL;
}
return rv;
}
/* Called by ssl3_SendServerKeyExchange and ssl3_SendCertificateVerify */
SECStatus
ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash, SECKEYPrivateKey *key,
SECItem *buf)
{
SECStatus rv = SECFailure;
PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0);
SSLSignatureScheme scheme = ss->ssl3.hs.signatureScheme;
rv = ssl3_SignHashesWithPrivKey(hash, key, scheme, isTLS, buf);
if (rv != SECSuccess) {
return SECFailure;
}
if (ss->sec.isServer) {
ss->sec.signatureScheme = scheme;
ss->sec.authType = ssl_SignatureSchemeToAuthType(scheme);
}
return SECSuccess;
}
/* Called from ssl3_VerifySignedHashes */
/* this only implements TLS 1.2 and earlier signatures */
static SECStatus
ssl_VerifySignedHashesWithPubKey(sslSocket *ss, SECKEYPublicKey *key,
SSLSignatureScheme scheme,
SSL3Hashes *hash, SECItem *buf)
{
SECItem *signature = NULL;
SECStatus rv = SECFailure;
SECItem hashItem;
SECOidTag encAlg;
SECOidTag hashAlg;
void *pwArg = ss->pkcs11PinArg;
PRBool isRsaPssScheme = ssl_IsRsaPssSignatureScheme(scheme);
PRINT_BUF(60, (NULL, "check signed hashes", buf->data, buf->len));
hashAlg = ssl3_HashTypeToOID(hash->hashAlg);
switch (SECKEY_GetPublicKeyType(key)) {
case rsaKey:
encAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
hashItem.data = hash->u.raw;
hashItem.len = hash->len;
if (scheme == ssl_sig_none) {
scheme = ssl_sig_rsa_pkcs1_sha1md5;
}
break;
case dsaKey:
encAlg = SEC_OID_ANSIX9_DSA_SIGNATURE;
/* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash.
* In that case, we use just the SHA1 part. */
if (hash->hashAlg == ssl_hash_none) {
hashItem.data = hash->u.s.sha;
hashItem.len = sizeof(hash->u.s.sha);
} else {
hashItem.data = hash->u.raw;
hashItem.len = hash->len;
}
/* Allow DER encoded DSA signatures in SSL 3.0 */
if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0 ||
buf->len != SECKEY_SignatureLen(key)) {
signature = DSAU_DecodeDerSigToLen(buf, SECKEY_SignatureLen(key));
if (!signature) {
PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
goto loser;
}
buf = signature;
}
if (scheme == ssl_sig_none) {
scheme = ssl_sig_dsa_sha1;
}
break;
case ecKey:
encAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
/* ssl_hash_none is used to specify the MD5/SHA1 concatenated hash.
* In that case, we use just the SHA1 part.
* ECDSA signatures always encode the integers r and s using ASN.1
* (unlike DSA where ASN.1 encoding is used with TLS but not with
* SSL3). So we can use VFY_VerifyDigestDirect for ECDSA.
*/
if (hash->hashAlg == ssl_hash_none) {
hashAlg = SEC_OID_SHA1;
hashItem.data = hash->u.s.sha;
hashItem.len = sizeof(hash->u.s.sha);
} else {
hashItem.data = hash->u.raw;
hashItem.len = hash->len;
}
if (scheme == ssl_sig_none) {
scheme = ssl_sig_ecdsa_sha1;
}
break;
default:
PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
goto loser;
}
PRINT_BUF(60, (NULL, "hash(es) to be verified",
hashItem.data, hashItem.len));
if (isRsaPssScheme ||
hashAlg == SEC_OID_UNKNOWN ||
SECKEY_GetPublicKeyType(key) == dsaKey) {
/* VFY_VerifyDigestDirect requires DSA signatures to be DER-encoded.
* DSA signatures are DER-encoded in TLS but not in SSL3 and the code
* above always removes the DER encoding of DSA signatures when
* present. Thus DSA signatures are always verified with PK11_Verify.
*/
CK_MECHANISM_TYPE mech = PK11_MapSignKeyType(key->keyType);
SECItem *params = NULL;
CK_RSA_PKCS_PSS_PARAMS pssParams;
SECItem pssParamsItem = { siBuffer,
(unsigned char *)&pssParams,
sizeof(pssParams) };
if (isRsaPssScheme) {
pssParams.hashAlg = ssl3_GetHashMechanismByHashType(hash->hashAlg);
pssParams.mgf = ssl3_GetMgfMechanismByHashType(hash->hashAlg);
pssParams.sLen = hashItem.len;
params = &pssParamsItem;
mech = CKM_RSA_PKCS_PSS;
}
rv = PK11_VerifyWithMechanism(key, mech, params, buf, &hashItem, pwArg);
} else {
rv = VFY_VerifyDigestDirect(&hashItem, key, buf, encAlg, hashAlg,
pwArg);
}
if (signature) {
SECITEM_FreeItem(signature, PR_TRUE);
}
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE);
}
if (!ss->sec.isServer) {
ss->sec.signatureScheme = scheme;
ss->sec.authType = ssl_SignatureSchemeToAuthType(scheme);
}
loser:
#ifdef UNSAFE_FUZZER_MODE
rv = SECSuccess;
PORT_SetError(0);
#endif
return rv;
}
/* Called from ssl3_HandleServerKeyExchange, ssl3_HandleCertificateVerify */
SECStatus
ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme, SSL3Hashes *hash,
SECItem *buf)
{
SECKEYPublicKey *pubKey =
SECKEY_ExtractPublicKey(&ss->sec.peerCert->subjectPublicKeyInfo);
if (pubKey == NULL) {
ssl_MapLowLevelError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
return SECFailure;
}
SECStatus rv = ssl_VerifySignedHashesWithPubKey(ss, pubKey, scheme,
hash, buf);
SECKEY_DestroyPublicKey(pubKey);
return rv;
}
/* Caller must set hiLevel error code. */
/* Called from ssl3_ComputeDHKeyHash
* which are called from ssl3_HandleServerKeyExchange.
*
* hashAlg: ssl_hash_none indicates the pre-1.2, MD5/SHA1 combination hash.
*/
SECStatus
ssl3_ComputeCommonKeyHash(SSLHashType hashAlg,
PRUint8 *hashBuf, unsigned int bufLen,
SSL3Hashes *hashes)
{
SECStatus rv;
SECOidTag hashOID;
PRUint32 policy;
if (hashAlg == ssl_hash_none) {
if ((NSS_GetAlgorithmPolicy(SEC_OID_SHA1, &policy) == SECSuccess) &&
!(policy & NSS_USE_ALG_IN_SSL_KX)) {
ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
return SECFailure;
}
rv = PK11_HashBuf(SEC_OID_MD5, hashes->u.s.md5, hashBuf, bufLen);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
return rv;
}
rv = PK11_HashBuf(SEC_OID_SHA1, hashes->u.s.sha, hashBuf, bufLen);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return rv;
}
hashes->len = MD5_LENGTH + SHA1_LENGTH;
} else {
hashOID = ssl3_HashTypeToOID(hashAlg);
if ((NSS_GetAlgorithmPolicy(hashOID, &policy) == SECSuccess) &&
!(policy & NSS_USE_ALG_IN_SSL_KX)) {
ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
return SECFailure;
}
hashes->len = HASH_ResultLenByOidTag(hashOID);
if (hashes->len == 0 || hashes->len > sizeof(hashes->u.raw)) {
ssl_MapLowLevelError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM);
return SECFailure;
}
rv = PK11_HashBuf(hashOID, hashes->u.raw, hashBuf, bufLen);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
return rv;
}
}
hashes->hashAlg = hashAlg;
return SECSuccess;
}
/* Caller must set hiLevel error code. */
/* Called from ssl3_HandleServerKeyExchange. */
static SECStatus
ssl3_ComputeDHKeyHash(sslSocket *ss, SSLHashType hashAlg, SSL3Hashes *hashes,
SECItem dh_p, SECItem dh_g, SECItem dh_Ys, PRBool padY)
{
sslBuffer buf = SSL_BUFFER_EMPTY;
SECStatus rv;
unsigned int yLen;
unsigned int i;
PORT_Assert(dh_p.data);
PORT_Assert(dh_g.data);
PORT_Assert(dh_Ys.data);
rv = sslBuffer_Append(&buf, ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH);
if (rv != SECSuccess) {
goto loser;
}
rv = sslBuffer_Append(&buf, ss->ssl3.hs.server_random, SSL3_RANDOM_LENGTH);
if (rv != SECSuccess) {
goto loser;
}
/* p */
rv = sslBuffer_AppendVariable(&buf, dh_p.data, dh_p.len, 2);
if (rv != SECSuccess) {
goto loser;
}
/* g */
rv = sslBuffer_AppendVariable(&buf, dh_g.data, dh_g.len, 2);
if (rv != SECSuccess) {
goto loser;
}
/* y - complicated by padding */
yLen = padY ? dh_p.len : dh_Ys.len;
rv = sslBuffer_AppendNumber(&buf, yLen, 2);
if (rv != SECSuccess) {
goto loser;
}
/* If we're padding Y, dh_Ys can't be longer than dh_p. */
PORT_Assert(!padY || dh_p.len >= dh_Ys.len);
for (i = dh_Ys.len; i < yLen; ++i) {
rv = sslBuffer_AppendNumber(&buf, 0, 1);
if (rv != SECSuccess) {
goto loser;
}
}
rv = sslBuffer_Append(&buf, dh_Ys.data, dh_Ys.len);
if (rv != SECSuccess) {
goto loser;
}
rv = ssl3_ComputeCommonKeyHash(hashAlg, SSL_BUFFER_BASE(&buf),
SSL_BUFFER_LEN(&buf), hashes);
if (rv != SECSuccess) {
goto loser;
}
PRINT_BUF(95, (NULL, "DHkey hash: ", SSL_BUFFER_BASE(&buf),
SSL_BUFFER_LEN(&buf)));
if (hashAlg == ssl_hash_none) {
PRINT_BUF(95, (NULL, "DHkey hash: MD5 result",
hashes->u.s.md5, MD5_LENGTH));
PRINT_BUF(95, (NULL, "DHkey hash: SHA1 result",
hashes->u.s.sha, SHA1_LENGTH));
} else {
PRINT_BUF(95, (NULL, "DHkey hash: result",
hashes->u.raw, hashes->len));
}
sslBuffer_Clear(&buf);
return SECSuccess;
loser:
sslBuffer_Clear(&buf);
return SECFailure;
}
static SECStatus
ssl3_SetupPendingCipherSpec(sslSocket *ss, SSLSecretDirection direction,
const ssl3CipherSuiteDef *suiteDef,
ssl3CipherSpec **specp)
{
ssl3CipherSpec *spec;
const ssl3CipherSpec *prev;
prev = (direction == ssl_secret_write) ? ss->ssl3.cwSpec : ss->ssl3.crSpec;
if (prev->epoch == PR_UINT16_MAX) {
PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
return SECFailure;
}
spec = ssl_CreateCipherSpec(ss, direction);
if (!spec) {
return SECFailure;
}
spec->cipherDef = ssl_GetBulkCipherDef(suiteDef);
spec->macDef = ssl_GetMacDef(ss, suiteDef);
spec->epoch = prev->epoch + 1;
spec->nextSeqNum = 0;
if (IS_DTLS(ss) && direction == ssl_secret_read) {
dtls_InitRecvdRecords(&spec->recvdRecords);
}
ssl_SetSpecVersions(ss, spec);
ssl_SaveCipherSpec(ss, spec);
*specp = spec;
return SECSuccess;
}
/* Fill in the pending cipher spec with info from the selected ciphersuite.
** This is as much initialization as we can do without having key material.
** Called from ssl3_HandleServerHello(), ssl3_SendServerHello()
** Caller must hold the ssl3 handshake lock.
** Acquires & releases SpecWriteLock.
*/
SECStatus
ssl3_SetupBothPendingCipherSpecs(sslSocket *ss)
{
ssl3CipherSuite suite = ss->ssl3.hs.cipher_suite;
SSL3KeyExchangeAlgorithm kea;
const ssl3CipherSuiteDef *suiteDef;
SECStatus rv;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
ssl_GetSpecWriteLock(ss); /*******************************/
/* This hack provides maximal interoperability with SSL 3 servers. */
if (ss->ssl3.cwSpec->macDef->mac == ssl_mac_null) {
/* SSL records are not being MACed. */
ss->ssl3.cwSpec->version = ss->version;
}
SSL_TRC(3, ("%d: SSL3[%d]: Set XXX Pending Cipher Suite to 0x%04x",
SSL_GETPID(), ss->fd, suite));
suiteDef = ssl_LookupCipherSuiteDef(suite);
if (suiteDef == NULL) {
goto loser;
}
if (IS_DTLS(ss)) {
/* Double-check that we did not pick an RC4 suite */
PORT_Assert(suiteDef->bulk_cipher_alg != cipher_rc4);
}
ss->ssl3.hs.suite_def = suiteDef;
kea = suiteDef->key_exchange_alg;
ss->ssl3.hs.kea_def = &kea_defs[kea];
PORT_Assert(ss->ssl3.hs.kea_def->kea == kea);
rv = ssl3_SetupPendingCipherSpec(ss, ssl_secret_read, suiteDef,
&ss->ssl3.prSpec);
if (rv != SECSuccess) {
goto loser;
}
rv = ssl3_SetupPendingCipherSpec(ss, ssl_secret_write, suiteDef,
&ss->ssl3.pwSpec);
if (rv != SECSuccess) {
goto loser;
}
if (ssl3_ExtensionNegotiated(ss, ssl_record_size_limit_xtn)) {
ss->ssl3.prSpec->recordSizeLimit = PR_MIN(MAX_FRAGMENT_LENGTH,
ss->opt.recordSizeLimit);
ss->ssl3.pwSpec->recordSizeLimit = PR_MIN(MAX_FRAGMENT_LENGTH,
ss->xtnData.recordSizeLimit);
}
ssl_ReleaseSpecWriteLock(ss); /*******************************/
return SECSuccess;
loser:
ssl_ReleaseSpecWriteLock(ss);
return SECFailure;
}
/* ssl3_BuildRecordPseudoHeader writes the SSL/TLS pseudo-header (the data which
* is included in the MAC or AEAD additional data) to |buf|. See
* AEAD additional data.
*
* TLS pseudo-header includes the record's version field, SSL's doesn't. Which
* pseudo-header definition to use should be decided based on the version of
* the protocol that was negotiated when the cipher spec became current, NOT
* based on the version value in the record itself, and the decision is passed
* to this function as the |includesVersion| argument. But, the |version|
* argument should be the record's version value.
*/
static SECStatus
ssl3_BuildRecordPseudoHeader(DTLSEpoch epoch,
sslSequenceNumber seqNum,
SSLContentType ct,
PRBool includesVersion,
SSL3ProtocolVersion version,
PRBool isDTLS,
int length,
sslBuffer *buf, SSL3ProtocolVersion v)
{
SECStatus rv;
if (isDTLS && v < SSL_LIBRARY_VERSION_TLS_1_3) {
rv = sslBuffer_AppendNumber(buf, epoch, 2);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(buf, seqNum, 6);
} else {
rv = sslBuffer_AppendNumber(buf, seqNum, 8);
}
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(buf, ct, 1);
if (rv != SECSuccess) {
return SECFailure;
}
/* SSL3 MAC doesn't include the record's version field. */
if (includesVersion) {
/* TLS MAC and AEAD additional data include version. */
rv = sslBuffer_AppendNumber(buf, version, 2);
if (rv != SECSuccess) {
return SECFailure;
}
}
rv = sslBuffer_AppendNumber(buf, length, 2);
if (rv != SECSuccess) {
return SECFailure;
}
return SECSuccess;
}
/* Initialize encryption and MAC contexts for pending spec.
* Master Secret already is derived.
* Caller holds Spec write lock.
*/
static SECStatus
ssl3_InitPendingContexts(sslSocket *ss, ssl3CipherSpec *spec)
{
CK_MECHANISM_TYPE encMechanism;
CK_ATTRIBUTE_TYPE encMode;
SECItem macParam;
CK_ULONG macLength;
SECItem iv;
SSLCipherAlgorithm calg;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
calg = spec->cipherDef->calg;
PORT_Assert(alg2Mech[calg].calg == calg);
if (spec->cipherDef->type != type_aead) {
macLength = spec->macDef->mac_size;
/*
** Now setup the MAC contexts,
** crypto contexts are setup below.
*/
macParam.data = (unsigned char *)&macLength;
macParam.len = sizeof(macLength);
macParam.type = siBuffer;
spec->keyMaterial.macContext = PK11_CreateContextBySymKey(
spec->macDef->mmech, CKA_SIGN, spec->keyMaterial.macKey, &macParam);
if (!spec->keyMaterial.macContext) {
ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
return SECFailure;
}
}
/*
** Now setup the crypto contexts.
*/
if (calg == ssl_calg_null) {
spec->cipher = Null_Cipher;
return SECSuccess;
}
encMechanism = ssl3_Alg2Mech(calg);
encMode = (spec->direction == ssl_secret_write) ? CKA_ENCRYPT : CKA_DECRYPT;
if (spec->cipherDef->type == type_aead) {
encMode |= CKA_NSS_MESSAGE;
iv.data = NULL;
iv.len = 0;
} else {
spec->cipher = SSLCipher_PK11_CipherOp;
iv.data = spec->keyMaterial.iv;
iv.len = spec->cipherDef->iv_size;
}
/*
* build the context
*/
spec->cipherContext = PK11_CreateContextBySymKey(encMechanism, encMode,
spec->keyMaterial.key,
&iv);
if (!spec->cipherContext) {
ssl_MapLowLevelError(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE);
return SECFailure;
}
return SECSuccess;
}
/* Complete the initialization of all keys, ciphers, MACs and their contexts
* for the pending Cipher Spec.
* Called from: ssl3_SendClientKeyExchange (for Full handshake)
* ssl3_HandleRSAClientKeyExchange (for Full handshake)
* ssl3_HandleServerHello (for session restart)
* ssl3_HandleClientHello (for session restart)
* Sets error code, but caller probably should override to disambiguate.
*
* If |secret| is a master secret from a previous connection is reused, |derive|
* is PR_FALSE. If the secret is a pre-master secret, then |derive| is PR_TRUE
* and the master secret is derived from |secret|.
*/
SECStatus
ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret, PRBool derive)
{
PK11SymKey *masterSecret;
ssl3CipherSpec *pwSpec;
ssl3CipherSpec *prSpec;
SECStatus rv;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(secret);
ssl_GetSpecWriteLock(ss); /**************************************/
PORT_Assert(ss->ssl3.pwSpec);
PORT_Assert(ss->ssl3.cwSpec->epoch == ss->ssl3.crSpec->epoch);
prSpec = ss->ssl3.prSpec;
pwSpec = ss->ssl3.pwSpec;
if (ss->ssl3.cwSpec->epoch == PR_UINT16_MAX) {
/* The problem here is that we have rehandshaked too many
* times (you are not allowed to wrap the epoch). The
* spec says you should be discarding the connection
* and start over, so not much we can do here. */
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
if (derive) {
rv = ssl3_ComputeMasterSecret(ss, secret, &masterSecret);
if (rv != SECSuccess) {
goto loser;
}
} else {
masterSecret = secret;
}
PORT_Assert(masterSecret);
rv = ssl3_DeriveConnectionKeys(ss, masterSecret);
if (rv != SECSuccess) {
if (derive) {
/* masterSecret was created here. */
PK11_FreeSymKey(masterSecret);
}
goto loser;
}
/* Both cipher specs maintain a reference to the master secret, since each
* is managed and freed independently. */
prSpec->masterSecret = masterSecret;
pwSpec->masterSecret = PK11_ReferenceSymKey(masterSecret);
rv = ssl3_InitPendingContexts(ss, ss->ssl3.prSpec);
if (rv != SECSuccess) {
goto loser;
}
rv = ssl3_InitPendingContexts(ss, ss->ssl3.pwSpec);
if (rv != SECSuccess) {
goto loser;
}
ssl_ReleaseSpecWriteLock(ss); /******************************/
return SECSuccess;
loser:
ssl_ReleaseSpecWriteLock(ss); /******************************/
ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
return SECFailure;
}
/*
* 60 bytes is 3 times the maximum length MAC size that is supported.
*/
static const unsigned char mac_pad_1[60] = {
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36
};
static const unsigned char mac_pad_2[60] = {
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c,
0x5c, 0x5c, 0x5c, 0x5c
};
/* Called from: ssl3_SendRecord()
** Caller must already hold the SpecReadLock. (wish we could assert that!)
*/
static SECStatus
ssl3_ComputeRecordMAC(
ssl3CipherSpec *spec,
const unsigned char *header,
unsigned int headerLen,
const PRUint8 *input,
int inputLen,
unsigned char *outbuf,
unsigned int *outLen)
{
PK11Context *context;
int macSize = spec->macDef->mac_size;
SECStatus rv;
PRINT_BUF(95, (NULL, "frag hash1: header", header, headerLen));
PRINT_BUF(95, (NULL, "frag hash1: input", input, inputLen));
if (spec->macDef->mac == ssl_mac_null) {
*outLen = 0;
return SECSuccess;
}
context = spec->keyMaterial.macContext;
rv = PK11_DigestBegin(context);
rv |= PK11_DigestOp(context, header, headerLen);
rv |= PK11_DigestOp(context, input, inputLen);
rv |= PK11_DigestFinal(context, outbuf, outLen, macSize);
PORT_Assert(rv != SECSuccess || *outLen == (unsigned)macSize);
PRINT_BUF(95, (NULL, "frag hash2: result", outbuf, *outLen));
if (rv != SECSuccess) {
rv = SECFailure;
ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
}
return rv;
}
/* Called from: ssl3_HandleRecord()
* Caller must already hold the SpecReadLock. (wish we could assert that!)
*
* On entry:
* originalLen >= inputLen >= MAC size
*/
static SECStatus
ssl3_ComputeRecordMACConstantTime(
ssl3CipherSpec *spec,
const unsigned char *header,
unsigned int headerLen,
const PRUint8 *input,
int inputLen,
int originalLen,
unsigned char *outbuf,
unsigned int *outLen)
{
CK_MECHANISM_TYPE macType;
CK_NSS_MAC_CONSTANT_TIME_PARAMS params;
SECItem param, inputItem, outputItem;
int macSize = spec->macDef->mac_size;
SECStatus rv;
PORT_Assert(inputLen >= spec->macDef->mac_size);
PORT_Assert(originalLen >= inputLen);
if (spec->macDef->mac == ssl_mac_null) {
*outLen = 0;
return SECSuccess;
}
macType = CKM_NSS_HMAC_CONSTANT_TIME;
if (spec->version == SSL_LIBRARY_VERSION_3_0) {
macType = CKM_NSS_SSL3_MAC_CONSTANT_TIME;
}
params.macAlg = spec->macDef->mmech;
params.ulBodyTotalLen = originalLen;
params.pHeader = (unsigned char *)header; /* const cast */
params.ulHeaderLen = headerLen;
param.data = (unsigned char *)&params;
param.len = sizeof(params);
param.type = 0;
inputItem.data = (unsigned char *)input;
inputItem.len = inputLen;
inputItem.type = 0;
outputItem.data = outbuf;
outputItem.len = *outLen;
outputItem.type = 0;
rv = PK11_SignWithSymKey(spec->keyMaterial.macKey, macType, &param,
&outputItem, &inputItem);
if (rv != SECSuccess) {
if (PORT_GetError() == SEC_ERROR_INVALID_ALGORITHM) {
/* ssl3_ComputeRecordMAC() expects the MAC to have been removed
* from the input length already. */
return ssl3_ComputeRecordMAC(spec, header, headerLen,
input, inputLen - macSize,
outbuf, outLen);
}
*outLen = 0;
rv = SECFailure;
ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
return rv;
}
PORT_Assert(outputItem.len == (unsigned)macSize);
*outLen = outputItem.len;
return rv;
}
static PRBool
ssl3_ClientAuthTokenPresent(sslSessionID *sid)
{
PK11SlotInfo *slot = NULL;
PRBool isPresent = PR_TRUE;
/* we only care if we are doing client auth */
if (!sid || !sid->u.ssl3.clAuthValid) {
return PR_TRUE;
}
/* get the slot */
slot = SECMOD_LookupSlot(sid->u.ssl3.clAuthModuleID,
sid->u.ssl3.clAuthSlotID);
if (slot == NULL ||
!PK11_IsPresent(slot) ||
sid->u.ssl3.clAuthSeries != PK11_GetSlotSeries(slot) ||
sid->u.ssl3.clAuthSlotID != PK11_GetSlotID(slot) ||
sid->u.ssl3.clAuthModuleID != PK11_GetModuleID(slot) ||
(PK11_NeedLogin(slot) && !PK11_IsLoggedIn(slot, NULL))) {
isPresent = PR_FALSE;
}
if (slot) {
PK11_FreeSlot(slot);
}
return isPresent;
}
/* Caller must hold the spec read lock. */
SECStatus
ssl3_MACEncryptRecord(ssl3CipherSpec *cwSpec,
PRBool isServer,
PRBool isDTLS,
SSLContentType ct,
const PRUint8 *pIn,
PRUint32 contentLen,
sslBuffer *wrBuf)
{
SECStatus rv;
PRUint32 macLen = 0;
PRUint32 fragLen;
PRUint32 p1Len, p2Len, oddLen = 0;
unsigned int ivLen = 0;
unsigned char pseudoHeaderBuf[13];
sslBuffer pseudoHeader = SSL_BUFFER(pseudoHeaderBuf);
unsigned int len;
if (cwSpec->cipherDef->type == type_block &&
cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
/* Prepend the per-record explicit IV using technique 2b from
* RFC 4346 section 6.2.3.2: The IV is a cryptographically
* strong random number XORed with the CBC residue from the previous
* record.
*/
ivLen = cwSpec->cipherDef->iv_size;
if (ivLen > SSL_BUFFER_SPACE(wrBuf)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rv = PK11_GenerateRandom(SSL_BUFFER_NEXT(wrBuf), ivLen);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE);
return rv;
}
rv = cwSpec->cipher(cwSpec->cipherContext,
SSL_BUFFER_NEXT(wrBuf), /* output */
&len, /* outlen */
ivLen, /* max outlen */
SSL_BUFFER_NEXT(wrBuf), /* input */
ivLen); /* input len */
if (rv != SECSuccess || len != ivLen) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
rv = sslBuffer_Skip(wrBuf, len, NULL);
PORT_Assert(rv == SECSuccess); /* Can't fail. */
}
rv = ssl3_BuildRecordPseudoHeader(
cwSpec->epoch, cwSpec->nextSeqNum, ct,
cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_0, cwSpec->recordVersion,
isDTLS, contentLen, &pseudoHeader, cwSpec->version);
PORT_Assert(rv == SECSuccess);
if (cwSpec->cipherDef->type == type_aead) {
const unsigned int nonceLen = cwSpec->cipherDef->explicit_nonce_size;
const unsigned int tagLen = cwSpec->cipherDef->tag_size;
unsigned int ivOffset = 0;
CK_GENERATOR_FUNCTION gen;
/* ivOut includes the iv and the nonce and is the internal iv/nonce
* for the AEAD function. On Encrypt, this is an in/out parameter */
unsigned char ivOut[MAX_IV_LENGTH];
ivLen = cwSpec->cipherDef->iv_size;
PORT_Assert((ivLen + nonceLen) <= MAX_IV_LENGTH);
PORT_Assert((ivLen + nonceLen) >= sizeof(sslSequenceNumber));
if (nonceLen + contentLen + tagLen > SSL_BUFFER_SPACE(wrBuf)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if (nonceLen == 0) {
ivOffset = ivLen - sizeof(sslSequenceNumber);
gen = CKG_GENERATE_COUNTER_XOR;
} else {
ivOffset = ivLen;
gen = CKG_GENERATE_COUNTER;
}
ivOffset = tls13_SetupAeadIv(isDTLS, cwSpec->version, ivOut, cwSpec->keyMaterial.iv,
ivOffset, ivLen, cwSpec->epoch);
rv = tls13_AEAD(cwSpec->cipherContext,
PR_FALSE,
gen, ivOffset * BPB, /* iv generator params */
ivOut, /* iv in */
ivOut, /* iv out */
ivLen + nonceLen, /* full iv length */
NULL, 0, /* nonce is generated*/
SSL_BUFFER_BASE(&pseudoHeader), /* aad */
SSL_BUFFER_LEN(&pseudoHeader), /* aadlen */
SSL_BUFFER_NEXT(wrBuf) + nonceLen, /* output */
&len, /* out len */
SSL_BUFFER_SPACE(wrBuf) - nonceLen, /* max out */
tagLen,
pIn, contentLen); /* input */
if (rv != SECSuccess) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
len += nonceLen; /* include the nonce at the beginning */
/* copy out the generated iv if we are using explict nonces */
if (nonceLen) {
PORT_Memcpy(SSL_BUFFER_NEXT(wrBuf), ivOut + ivLen, nonceLen);
}
rv = sslBuffer_Skip(wrBuf, len, NULL);
PORT_Assert(rv == SECSuccess); /* Can't fail. */
} else {
int blockSize = cwSpec->cipherDef->block_size;
/*
* Add the MAC
*/
rv = ssl3_ComputeRecordMAC(cwSpec, SSL_BUFFER_BASE(&pseudoHeader),
SSL_BUFFER_LEN(&pseudoHeader),
pIn, contentLen,
SSL_BUFFER_NEXT(wrBuf) + contentLen, &macLen);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE);
return SECFailure;
}
p1Len = contentLen;
p2Len = macLen;
fragLen = contentLen + macLen; /* needs to be encrypted */
PORT_Assert(fragLen <= MAX_FRAGMENT_LENGTH + 1024);
/*
* Pad the text (if we're doing a block cipher)
* then Encrypt it
*/
if (cwSpec->cipherDef->type == type_block) {
unsigned char *pBuf;
int padding_length;
int i;
oddLen = contentLen % blockSize;
/* Assume blockSize is a power of two */
padding_length = blockSize - 1 - ((fragLen) & (blockSize - 1));
fragLen += padding_length + 1;
PORT_Assert((fragLen % blockSize) == 0);
/* Pad according to TLS rules (also acceptable to SSL3). */
pBuf = SSL_BUFFER_NEXT(wrBuf) + fragLen - 1;
for (i = padding_length + 1; i > 0; --i) {
*pBuf-- = padding_length;
}
/* now, if contentLen is not a multiple of block size, fix it */
p2Len = fragLen - p1Len;
}
if (p1Len < 256) {
oddLen = p1Len;
p1Len = 0;
} else {
p1Len -= oddLen;
}
if (oddLen) {
p2Len += oddLen;
PORT_Assert((blockSize < 2) ||
(p2Len % blockSize) == 0);
memmove(SSL_BUFFER_NEXT(wrBuf) + p1Len, pIn + p1Len, oddLen);
}
if (p1Len > 0) {
unsigned int cipherBytesPart1 = 0;
rv = cwSpec->cipher(cwSpec->cipherContext,
SSL_BUFFER_NEXT(wrBuf), /* output */
&cipherBytesPart1, /* actual outlen */
p1Len, /* max outlen */
pIn,
p1Len); /* input, and inputlen */
PORT_Assert(rv == SECSuccess && cipherBytesPart1 == p1Len);
if (rv != SECSuccess || cipherBytesPart1 != p1Len) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
rv = sslBuffer_Skip(wrBuf, p1Len, NULL);
PORT_Assert(rv == SECSuccess);
}
if (p2Len > 0) {
unsigned int cipherBytesPart2 = 0;
rv = cwSpec->cipher(cwSpec->cipherContext,
SSL_BUFFER_NEXT(wrBuf),
&cipherBytesPart2, /* output and actual outLen */
p2Len, /* max outlen */
SSL_BUFFER_NEXT(wrBuf),
p2Len); /* input and inputLen*/
PORT_Assert(rv == SECSuccess && cipherBytesPart2 == p2Len);
if (rv != SECSuccess || cipherBytesPart2 != p2Len) {
PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE);
return SECFailure;
}
rv = sslBuffer_Skip(wrBuf, p2Len, NULL);
PORT_Assert(rv == SECSuccess);
}
}
return SECSuccess;
}
/* Note: though this can report failure, it shouldn't. */
SECStatus
ssl_InsertRecordHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
SSLContentType contentType, sslBuffer *wrBuf,
PRBool *needsLength)
{
SECStatus rv;
#ifndef UNSAFE_FUZZER_MODE
if (cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
cwSpec->epoch > TrafficKeyClearText) {
if (IS_DTLS(ss)) {
return dtls13_InsertCipherTextHeader(ss, cwSpec, wrBuf,
needsLength);
}
contentType = ssl_ct_application_data;
}
#endif
rv = sslBuffer_AppendNumber(wrBuf, contentType, 1);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(wrBuf, cwSpec->recordVersion, 2);
if (rv != SECSuccess) {
return SECFailure;
}
if (IS_DTLS(ss)) {
rv = sslBuffer_AppendNumber(wrBuf, cwSpec->epoch, 2);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(wrBuf, cwSpec->nextSeqNum, 6);
if (rv != SECSuccess) {
return SECFailure;
}
}
*needsLength = PR_TRUE;
return SECSuccess;
}
SECStatus
ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSLContentType ct,
const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf)
{
PRBool needsLength;
unsigned int lenOffset;
SECStatus rv;
PORT_Assert(cwSpec->direction == ssl_secret_write);
PORT_Assert(SSL_BUFFER_LEN(wrBuf) == 0);
PORT_Assert(cwSpec->cipherDef->max_records <= RECORD_SEQ_MAX);
if (cwSpec->nextSeqNum >= cwSpec->cipherDef->max_records) {
SSL_TRC(3, ("%d: SSL[-]: write sequence number at limit 0x%0llx",
SSL_GETPID(), cwSpec->nextSeqNum));
PORT_SetError(SSL_ERROR_TOO_MANY_RECORDS);
return SECFailure;
}
rv = ssl_InsertRecordHeader(ss, cwSpec, ct, wrBuf, &needsLength);
if (rv != SECSuccess) {
return SECFailure;
}
if (needsLength) {
rv = sslBuffer_Skip(wrBuf, 2, &lenOffset);
if (rv != SECSuccess) {
return SECFailure;
}
}
#ifdef UNSAFE_FUZZER_MODE
{
unsigned int len;
rv = Null_Cipher(NULL, SSL_BUFFER_NEXT(wrBuf), &len,
SSL_BUFFER_SPACE(wrBuf), pIn, contentLen);
if (rv != SECSuccess) {
return SECFailure; /* error was set */
}
rv = sslBuffer_Skip(wrBuf, len, NULL);
PORT_Assert(rv == SECSuccess); /* Can't fail. */
}
#else
if (cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
PRUint8 *cipherText = SSL_BUFFER_NEXT(wrBuf);
unsigned int bufLen = SSL_BUFFER_LEN(wrBuf);
rv = tls13_ProtectRecord(ss, cwSpec, ct, pIn, contentLen, wrBuf);
if (rv != SECSuccess) {
return SECFailure;
}
if (IS_DTLS(ss)) {
bufLen = SSL_BUFFER_LEN(wrBuf) - bufLen;
rv = dtls13_MaskSequenceNumber(ss, cwSpec,
SSL_BUFFER_BASE(wrBuf),
cipherText, bufLen);
}
} else {
rv = ssl3_MACEncryptRecord(cwSpec, ss->sec.isServer, IS_DTLS(ss), ct,
pIn, contentLen, wrBuf);
}
#endif
if (rv != SECSuccess) {
return SECFailure; /* error was set */
}
if (needsLength) {
/* Insert the length. */
rv = sslBuffer_InsertLength(wrBuf, lenOffset, 2);
if (rv != SECSuccess) {
PORT_Assert(0); /* Can't fail. */
return SECFailure;
}
}
++cwSpec->nextSeqNum;
return SECSuccess;
}
SECStatus
ssl_ProtectNextRecord(sslSocket *ss, ssl3CipherSpec *spec, SSLContentType ct,
const PRUint8 *pIn, unsigned int nIn,
unsigned int *written)
{
sslBuffer *wrBuf = &ss->sec.writeBuf;
unsigned int contentLen;
unsigned int spaceNeeded;
SECStatus rv;
contentLen = PR_MIN(nIn, spec->recordSizeLimit);
spaceNeeded = contentLen + SSL3_BUFFER_FUDGE;
if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_1 &&
spec->cipherDef->type == type_block) {
spaceNeeded += spec->cipherDef->iv_size;
}
if (spaceNeeded > SSL_BUFFER_SPACE(wrBuf)) {
rv = sslBuffer_Grow(wrBuf, spaceNeeded);
if (rv != SECSuccess) {
SSL_DBG(("%d: SSL3[%d]: failed to expand write buffer to %d",
SSL_GETPID(), ss->fd, spaceNeeded));
return SECFailure;
}
}
rv = ssl_ProtectRecord(ss, spec, ct, pIn, contentLen, wrBuf);
if (rv != SECSuccess) {
return SECFailure;
}
PRINT_BUF(50, (ss, "send (encrypted) record data:",
SSL_BUFFER_BASE(wrBuf), SSL_BUFFER_LEN(wrBuf)));
*written = contentLen;
return SECSuccess;
}
/* Process the plain text before sending it.
* Returns the number of bytes of plaintext that were successfully sent
* plus the number of bytes of plaintext that were copied into the
* output (write) buffer.
* Returns -1 on an error. PR_WOULD_BLOCK_ERROR is set if the error is blocking
* and not terminal.
*
* Notes on the use of the private ssl flags:
* (no private SSL flags)
* Attempt to make and send SSL records for all plaintext
* If non-blocking and a send gets WOULD_BLOCK,
* or if the pending (ciphertext) buffer is not empty,
* then buffer remaining bytes of ciphertext into pending buf,
* and continue to do that for all succssive records until all
* bytes are used.
* ssl_SEND_FLAG_FORCE_INTO_BUFFER
* As above, except this suppresses all write attempts, and forces
* all ciphertext into the pending ciphertext buffer.
* ssl_SEND_FLAG_USE_EPOCH (for DTLS)
* Forces the use of the provided epoch
*/
PRInt32
ssl3_SendRecord(sslSocket *ss,
ssl3CipherSpec *cwSpec, /* non-NULL for DTLS retransmits */
SSLContentType ct,
const PRUint8 *pIn, /* input buffer */
PRInt32 nIn, /* bytes of input */
PRInt32 flags)
{
sslBuffer *wrBuf = &ss->sec.writeBuf;
ssl3CipherSpec *spec;
SECStatus rv;
PRInt32 totalSent = 0;
SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d",
SSL_GETPID(), ss->fd, ssl3_DecodeContentType(ct),
nIn));
PRINT_BUF(50, (ss, "Send record (plain text)", pIn, nIn));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert(SSL_BUFFER_LEN(wrBuf) == 0);
if (ss->ssl3.fatalAlertSent) {
SSL_TRC(3, ("%d: SSL3[%d] Suppress write, fatal alert already sent",
SSL_GETPID(), ss->fd));
if (ct != ssl_ct_alert) {
/* If we are sending an alert, then we already have an
* error, so don't overwrite. */
PORT_SetError(SSL_ERROR_HANDSHAKE_FAILED);
}
return -1;
}
/* check for Token Presence */
if (!ssl3_ClientAuthTokenPresent(ss->sec.ci.sid)) {
PORT_SetError(SSL_ERROR_TOKEN_INSERTION_REMOVAL);
return -1;
}
if (ss->recordWriteCallback) {
PRUint16 epoch;
ssl_GetSpecReadLock(ss);
epoch = ss->ssl3.cwSpec->epoch;
ssl_ReleaseSpecReadLock(ss);
rv = ss->recordWriteCallback(ss->fd, epoch, ct, pIn, nIn,
ss->recordWriteCallbackArg);
if (rv != SECSuccess) {
return -1;
}
return nIn;
}
if (cwSpec) {
/* cwSpec can only be set for retransmissions of the DTLS handshake. */
PORT_Assert(IS_DTLS(ss) &&
(ct == ssl_ct_handshake ||
ct == ssl_ct_change_cipher_spec));
spec = cwSpec;
} else {
spec = ss->ssl3.cwSpec;
}
while (nIn > 0) {
unsigned int written = 0;
PRInt32 sent;
ssl_GetSpecReadLock(ss);
rv = ssl_ProtectNextRecord(ss, spec, ct, pIn, nIn, &written);
ssl_ReleaseSpecReadLock(ss);
if (rv != SECSuccess) {
goto loser;
}
PORT_Assert(written > 0);
/* DTLS should not fragment non-application data here. */
if (IS_DTLS(ss) && ct != ssl_ct_application_data) {
PORT_Assert(written == nIn);
}
pIn += written;
nIn -= written;
PORT_Assert(nIn >= 0);
/* If there's still some previously saved ciphertext,
* or the caller doesn't want us to send the data yet,
* then add all our new ciphertext to the amount previously saved.
*/
if ((ss->pendingBuf.len > 0) ||
(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) {
rv = ssl_SaveWriteData(ss, SSL_BUFFER_BASE(wrBuf),
SSL_BUFFER_LEN(wrBuf));
if (rv != SECSuccess) {
/* presumably a memory error, SEC_ERROR_NO_MEMORY */
goto loser;
}
if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) {
ss->handshakeBegun = 1;
sent = ssl_SendSavedWriteData(ss);
if (sent < 0 && PR_GetError() != PR_WOULD_BLOCK_ERROR) {
ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE);
goto loser;
}
if (ss->pendingBuf.len) {
flags |= ssl_SEND_FLAG_FORCE_INTO_BUFFER;
}
}
} else {
PORT_Assert(SSL_BUFFER_LEN(wrBuf) > 0);
ss->handshakeBegun = 1;
sent = ssl_DefSend(ss, SSL_BUFFER_BASE(wrBuf),
SSL_BUFFER_LEN(wrBuf),
flags & ~ssl_SEND_FLAG_MASK);
if (sent < 0) {
if (PORT_GetError() != PR_WOULD_BLOCK_ERROR) {
ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE);
goto loser;
}
/* we got PR_WOULD_BLOCK_ERROR, which means none was sent. */
sent = 0;
}
if (SSL_BUFFER_LEN(wrBuf) > (unsigned int)sent) {
if (IS_DTLS(ss)) {
/* DTLS just says no in this case. No buffering */
PORT_SetError(PR_WOULD_BLOCK_ERROR);
goto loser;
}
/* now take all the remaining unsent new ciphertext and
* append it to the buffer of previously unsent ciphertext.
*/
rv = ssl_SaveWriteData(ss, SSL_BUFFER_BASE(wrBuf) + sent,
SSL_BUFFER_LEN(wrBuf) - sent);
if (rv != SECSuccess) {
/* presumably a memory error, SEC_ERROR_NO_MEMORY */
goto loser;
}
}
}
wrBuf->len = 0;
totalSent += written;
}
return totalSent;
loser:
/* Don't leave bits of buffer lying around. */
wrBuf->len = 0;
return -1;
}
#define SSL3_PENDING_HIGH_WATER 1024
/* Attempt to send the content of "in" in an SSL application_data record.
* Returns "len" or -1 on failure.
*/
int
ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in,
PRInt32 len, PRInt32 flags)
{
PRInt32 totalSent = 0;
PRInt32 discarded = 0;
PRBool splitNeeded = PR_FALSE;
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
/* These flags for internal use only */
PORT_Assert(!(flags & ssl_SEND_FLAG_NO_RETRANSMIT));
if (len < 0 || !in) {
PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
return -1;
}
if (ss->pendingBuf.len > SSL3_PENDING_HIGH_WATER &&
!ssl_SocketIsBlocking(ss)) {
PORT_Assert(!ssl_SocketIsBlocking(ss));
PORT_SetError(PR_WOULD_BLOCK_ERROR);
return -1;
}
if (ss->appDataBuffered && len) {
PORT_Assert(in[0] == (unsigned char)(ss->appDataBuffered));
if (in[0] != (unsigned char)(ss->appDataBuffered)) {
PORT_SetError(PR_INVALID_ARGUMENT_ERROR);
return -1;
}
in++;
len--;
discarded = 1;
}
/* We will split the first byte of the record into its own record, as
* explained in the documentation for SSL_CBC_RANDOM_IV in ssl.h.
*/
if (len > 1 && ss->opt.cbcRandomIV &&
ss->version < SSL_LIBRARY_VERSION_TLS_1_1 &&
ss->ssl3.cwSpec->cipherDef->type == type_block /* CBC */) {
splitNeeded = PR_TRUE;
}
while (len > totalSent) {
PRInt32 sent, toSend;
if (totalSent > 0) {
/*
* The thread yield is intended to give the reader thread a
* chance to get some cycles while the writer thread is in
* the middle of a large application data write. (See
* Bugzilla bug 127740, comment #1.)
*/
ssl_ReleaseXmitBufLock(ss);
PR_Sleep(PR_INTERVAL_NO_WAIT); /* PR_Yield(); */
ssl_GetXmitBufLock(ss);
}
if (splitNeeded) {
toSend = 1;
splitNeeded = PR_FALSE;
} else {
toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH);
}
/*
* Note that the 0 epoch is OK because flags will never require
* its use, as guaranteed by the PORT_Assert above.
*/
sent = ssl3_SendRecord(ss, NULL, ssl_ct_application_data,
in + totalSent, toSend, flags);
if (sent < 0) {
if (totalSent > 0 && PR_GetError() == PR_WOULD_BLOCK_ERROR) {
PORT_Assert(ss->lastWriteBlocked);
break;
}
return -1; /* error code set by ssl3_SendRecord */
}
totalSent += sent;
if (ss->pendingBuf.len) {
/* must be a non-blocking socket */
PORT_Assert(!ssl_SocketIsBlocking(ss));
PORT_Assert(ss->lastWriteBlocked);
break;
}
}
if (ss->pendingBuf.len) {
/* Must be non-blocking. */
PORT_Assert(!ssl_SocketIsBlocking(ss));
if (totalSent > 0) {
ss->appDataBuffered = 0x100 | in[totalSent - 1];
}
totalSent = totalSent + discarded - 1;
if (totalSent <= 0) {
PORT_SetError(PR_WOULD_BLOCK_ERROR);
totalSent = SECFailure;
}
return totalSent;
}
ss->appDataBuffered = 0;
return totalSent + discarded;
}
/* Attempt to send buffered handshake messages.
* Always set sendBuf.len to 0, even when returning SECFailure.
*
* Depending on whether we are doing DTLS or not, this either calls
*
* - ssl3_FlushHandshakeMessages if non-DTLS
* - dtls_FlushHandshakeMessages if DTLS
*
* Called from SSL3_SendAlert(), ssl3_SendChangeCipherSpecs(),
* ssl3_AppendHandshake(), ssl3_SendClientHello(),
* ssl3_SendHelloRequest(), ssl3_SendServerHelloDone(),
* ssl3_SendFinished(),
*/
SECStatus
ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags)
{
if (IS_DTLS(ss)) {
return dtls_FlushHandshakeMessages(ss, flags);
}
return ssl3_FlushHandshakeMessages(ss, flags);
}
/* Attempt to send the content of sendBuf buffer in an SSL handshake record.
* Always set sendBuf.len to 0, even when returning SECFailure.
*
* Called from ssl3_FlushHandshake
*/
static SECStatus
ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags)
{
static const PRInt32 allowedFlags = ssl_SEND_FLAG_FORCE_INTO_BUFFER;
PRInt32 count = -1;
SECStatus rv;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len)
return SECSuccess;
/* only these flags are allowed */
PORT_Assert(!(flags & ~allowedFlags));
if ((flags & ~allowedFlags) != 0) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
count = ssl3_SendRecord(ss, NULL, ssl_ct_handshake,
ss->sec.ci.sendBuf.buf,
ss->sec.ci.sendBuf.len, flags);
if (count < 0) {
int err = PORT_GetError();
PORT_Assert(err != PR_WOULD_BLOCK_ERROR);
if (err == PR_WOULD_BLOCK_ERROR) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
}
rv = SECFailure;
} else if ((unsigned int)count < ss->sec.ci.sendBuf.len) {
/* short write should never happen */
PORT_Assert((unsigned int)count >= ss->sec.ci.sendBuf.len);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
rv = SECFailure;
} else {
rv = SECSuccess;
}
/* Whether we succeeded or failed, toss the old handshake data. */
ss->sec.ci.sendBuf.len = 0;
return rv;
}
/*
* Called from ssl3_HandleAlert and from ssl3_HandleCertificate when
* the remote client sends a negative response to our certificate request.
* Returns SECFailure if the application has required client auth.
* SECSuccess otherwise.
*/
SECStatus
ssl3_HandleNoCertificate(sslSocket *ss)
{
ssl3_CleanupPeerCerts(ss);
/* If the server has required client-auth blindly but doesn't
* actually look at the certificate it won't know that no
* certificate was presented so we shutdown the socket to ensure
* an error. We only do this if we haven't already completed the
* first handshake because if we're redoing the handshake we
* know the server is paying attention to the certificate.
*/
if ((ss->opt.requireCertificate == SSL_REQUIRE_ALWAYS) ||
(!ss->firstHsDone &&
(ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE))) {
PRFileDesc *lower;
ssl_UncacheSessionID(ss);
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
SSL3_SendAlert(ss, alert_fatal, certificate_required);
} else {
SSL3_SendAlert(ss, alert_fatal, bad_certificate);
}
lower = ss->fd->lower;
#ifdef _WIN32
lower->methods->shutdown(lower, PR_SHUTDOWN_SEND);
#else
lower->methods->shutdown(lower, PR_SHUTDOWN_BOTH);
#endif
PORT_SetError(SSL_ERROR_NO_CERTIFICATE);
return SECFailure;
}
return SECSuccess;
}
/************************************************************************
* Alerts
*/
/*
** Acquires both handshake and XmitBuf locks.
** Called from: ssl3_IllegalParameter <-
** ssl3_HandshakeFailure <-
** ssl3_HandleAlert <- ssl3_HandleRecord.
** ssl3_HandleChangeCipherSpecs <- ssl3_HandleRecord
** ssl3_ConsumeHandshakeVariable <-
** ssl3_HandleHelloRequest <-
** ssl3_HandleServerHello <-
** ssl3_HandleServerKeyExchange <-
** ssl3_HandleCertificateRequest <-
** ssl3_HandleServerHelloDone <-
** ssl3_HandleClientHello <-
** ssl3_HandleV2ClientHello <-
** ssl3_HandleCertificateVerify <-
** ssl3_HandleClientKeyExchange <-
** ssl3_HandleCertificate <-
** ssl3_HandleFinished <-
** ssl3_HandleHandshakeMessage <-
** ssl3_HandlePostHelloHandshakeMessage <-
** ssl3_HandleRecord <-
**
*/
SECStatus
SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc)
{
PRUint8 bytes[2];
SECStatus rv;
PRBool needHsLock = !ssl_HaveSSL3HandshakeLock(ss);
/* Check that if I need the HS lock I also need the Xmit lock */
PORT_Assert(!needHsLock || !ssl_HaveXmitBufLock(ss));
SSL_TRC(3, ("%d: SSL3[%d]: send alert record, level=%d desc=%d",
SSL_GETPID(), ss->fd, level, desc));
bytes[0] = level;
bytes[1] = desc;
if (needHsLock) {
ssl_GetSSL3HandshakeLock(ss);
}
if (level == alert_fatal) {
if (ss->sec.ci.sid) {
ssl_UncacheSessionID(ss);
}
}
rv = tls13_SetAlertCipherSpec(ss);
if (rv != SECSuccess) {
if (needHsLock) {
ssl_ReleaseSSL3HandshakeLock(ss);
}
return rv;
}
ssl_GetXmitBufLock(ss);
rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
if (rv == SECSuccess) {
PRInt32 sent;
sent = ssl3_SendRecord(ss, NULL, ssl_ct_alert, bytes, 2,
(desc == no_certificate) ? ssl_SEND_FLAG_FORCE_INTO_BUFFER : 0);
rv = (sent >= 0) ? SECSuccess : (SECStatus)sent;
}
if (level == alert_fatal) {
ss->ssl3.fatalAlertSent = PR_TRUE;
}
ssl_ReleaseXmitBufLock(ss);
if (needHsLock) {
ssl_ReleaseSSL3HandshakeLock(ss);
}
if (rv == SECSuccess && ss->alertSentCallback) {
SSLAlert alert = { level, desc };
ss->alertSentCallback(ss->fd, ss->alertSentCallbackArg, &alert);
}
return rv; /* error set by ssl3_FlushHandshake or ssl3_SendRecord */
}
/*
* Send illegal_parameter alert. Set generic error number.
*/
static SECStatus
ssl3_IllegalParameter(sslSocket *ss)
{
(void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT
: SSL_ERROR_BAD_SERVER);
return SECFailure;
}
/*
* Send handshake_Failure alert. Set generic error number.
*/
static SECStatus
ssl3_HandshakeFailure(sslSocket *ss)
{
(void)SSL3_SendAlert(ss, alert_fatal, handshake_failure);
PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT
: SSL_ERROR_BAD_SERVER);
return SECFailure;
}
void
ssl3_SendAlertForCertError(sslSocket *ss, PRErrorCode errCode)
{
SSL3AlertDescription desc = bad_certificate;
PRBool isTLS = ss->version >= SSL_LIBRARY_VERSION_3_1_TLS;
switch (errCode) {
case SEC_ERROR_LIBRARY_FAILURE:
desc = unsupported_certificate;
break;
case SEC_ERROR_EXPIRED_CERTIFICATE:
desc = certificate_expired;
break;
case SEC_ERROR_REVOKED_CERTIFICATE:
desc = certificate_revoked;
break;
case SEC_ERROR_INADEQUATE_KEY_USAGE:
case SEC_ERROR_INADEQUATE_CERT_TYPE:
desc = certificate_unknown;
break;
case SEC_ERROR_UNTRUSTED_CERT:
desc = isTLS ? access_denied : certificate_unknown;
break;
case SEC_ERROR_UNKNOWN_ISSUER:
case SEC_ERROR_UNTRUSTED_ISSUER:
desc = isTLS ? unknown_ca : certificate_unknown;
break;
case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
desc = isTLS ? unknown_ca : certificate_expired;
break;
case SEC_ERROR_CERT_NOT_IN_NAME_SPACE:
case SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID:
case SEC_ERROR_CA_CERT_INVALID:
case SEC_ERROR_BAD_SIGNATURE:
default:
desc = bad_certificate;
break;
}
SSL_DBG(("%d: SSL3[%d]: peer certificate is no good: error=%d",
SSL_GETPID(), ss->fd, errCode));
(void)SSL3_SendAlert(ss, alert_fatal, desc);
}
/*
* Send decode_error alert. Set generic error number.
*/
SECStatus
ssl3_DecodeError(sslSocket *ss)
{
(void)SSL3_SendAlert(ss, alert_fatal,
ss->version > SSL_LIBRARY_VERSION_3_0 ? decode_error
: illegal_parameter);
PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT
: SSL_ERROR_BAD_SERVER);
return SECFailure;
}
/* Called from ssl3_HandleRecord.
** Caller must hold both RecvBuf and Handshake locks.
*/
static SECStatus
ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf)
{
SSL3AlertLevel level;
SSL3AlertDescription desc;
int error;
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
SSL_TRC(3, ("%d: SSL3[%d]: handle alert record", SSL_GETPID(), ss->fd));
if (buf->len != 2) {
(void)ssl3_DecodeError(ss);
PORT_SetError(SSL_ERROR_RX_MALFORMED_ALERT);
return SECFailure;
}
level = (SSL3AlertLevel)buf->buf[0];
desc = (SSL3AlertDescription)buf->buf[1];
buf->len = 0;
SSL_TRC(5, ("%d: SSL3[%d] received alert, level = %d, description = %d",
SSL_GETPID(), ss->fd, level, desc));
if (ss->alertReceivedCallback) {
SSLAlert alert = { level, desc };
ss->alertReceivedCallback(ss->fd, ss->alertReceivedCallbackArg, &alert);
}
switch (desc) {
case close_notify:
ss->recvdCloseNotify = 1;
error = SSL_ERROR_CLOSE_NOTIFY_ALERT;
break;
case unexpected_message:
error = SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT;
break;
case bad_record_mac:
error = SSL_ERROR_BAD_MAC_ALERT;
break;
case decryption_failed_RESERVED:
error = SSL_ERROR_DECRYPTION_FAILED_ALERT;
break;
case record_overflow:
error = SSL_ERROR_RECORD_OVERFLOW_ALERT;
break;
case decompression_failure:
error = SSL_ERROR_DECOMPRESSION_FAILURE_ALERT;
break;
case handshake_failure:
error = SSL_ERROR_HANDSHAKE_FAILURE_ALERT;
break;
case no_certificate:
error = SSL_ERROR_NO_CERTIFICATE;
break;
case certificate_required:
error = SSL_ERROR_RX_CERTIFICATE_REQUIRED_ALERT;
break;
case bad_certificate:
error = SSL_ERROR_BAD_CERT_ALERT;
break;
case unsupported_certificate:
error = SSL_ERROR_UNSUPPORTED_CERT_ALERT;
break;
case certificate_revoked:
error = SSL_ERROR_REVOKED_CERT_ALERT;
break;
case certificate_expired:
error = SSL_ERROR_EXPIRED_CERT_ALERT;
break;
case certificate_unknown:
error = SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT;
break;
case illegal_parameter:
error = SSL_ERROR_ILLEGAL_PARAMETER_ALERT;
break;
case inappropriate_fallback:
error = SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT;
break;
/* All alerts below are TLS only. */
case unknown_ca:
error = SSL_ERROR_UNKNOWN_CA_ALERT;
break;
case access_denied:
error = SSL_ERROR_ACCESS_DENIED_ALERT;
break;
case decode_error:
error = SSL_ERROR_DECODE_ERROR_ALERT;
break;
case decrypt_error:
error = SSL_ERROR_DECRYPT_ERROR_ALERT;
break;
case export_restriction:
error = SSL_ERROR_EXPORT_RESTRICTION_ALERT;
break;
case protocol_version:
error = SSL_ERROR_PROTOCOL_VERSION_ALERT;
break;
case insufficient_security:
error = SSL_ERROR_INSUFFICIENT_SECURITY_ALERT;
break;
case internal_error:
error = SSL_ERROR_INTERNAL_ERROR_ALERT;
break;
case user_canceled:
error = SSL_ERROR_USER_CANCELED_ALERT;
break;
case no_renegotiation:
error = SSL_ERROR_NO_RENEGOTIATION_ALERT;
break;
/* Alerts for TLS client hello extensions */
case missing_extension:
error = SSL_ERROR_MISSING_EXTENSION_ALERT;
break;
case unsupported_extension:
error = SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT;
break;
case certificate_unobtainable:
error = SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT;
break;
case unrecognized_name:
error = SSL_ERROR_UNRECOGNIZED_NAME_ALERT;
break;
case bad_certificate_status_response:
error = SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT;
break;
case bad_certificate_hash_value:
error = SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT;
break;
case no_application_protocol:
error = SSL_ERROR_NEXT_PROTOCOL_NO_PROTOCOL;
break;
case ech_required:
error = SSL_ERROR_ECH_REQUIRED_ALERT;
break;
default:
error = SSL_ERROR_RX_UNKNOWN_ALERT;
break;
}
if ((ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) &&
(ss->ssl3.hs.ws != wait_server_hello)) {
/* TLS 1.3 requires all but "end of data" alerts to be
* treated as fatal. */
switch (desc) {
case close_notify:
case user_canceled:
break;
default:
level = alert_fatal;
}
}
if (level == alert_fatal) {
ssl_UncacheSessionID(ss);
if ((ss->ssl3.hs.ws == wait_server_hello) &&
(desc == handshake_failure)) {
/* XXX This is a hack. We're assuming that any handshake failure
* XXX on the client hello is a failure to match ciphers.
*/
error = SSL_ERROR_NO_CYPHER_OVERLAP;
}
PORT_SetError(error);
return SECFailure;
}
if ((desc == no_certificate) && (ss->ssl3.hs.ws == wait_client_cert)) {
/* I'm a server. I've requested a client cert. He hasn't got one. */
SECStatus rv;
PORT_Assert(ss->sec.isServer);
ss->ssl3.hs.ws = wait_client_key;
rv = ssl3_HandleNoCertificate(ss);
return rv;
}
return SECSuccess;
}
/*
* Change Cipher Specs
* Called from ssl3_HandleServerHelloDone,
* ssl3_HandleClientHello,
* and ssl3_HandleFinished
*
* Acquires and releases spec write lock, to protect switching the current
* and pending write spec pointers.
*/
SECStatus
ssl3_SendChangeCipherSpecsInt(sslSocket *ss)
{
PRUint8 change = change_cipher_spec_choice;
SECStatus rv;
SSL_TRC(3, ("%d: SSL3[%d]: send change_cipher_spec record",
SSL_GETPID(), ss->fd));
rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
if (rv != SECSuccess) {
return SECFailure; /* error code set by ssl3_FlushHandshake */
}
if (!IS_DTLS(ss)) {
PRInt32 sent;
sent = ssl3_SendRecord(ss, NULL, ssl_ct_change_cipher_spec,
&change, 1, ssl_SEND_FLAG_FORCE_INTO_BUFFER);
if (sent < 0) {
return SECFailure; /* error code set by ssl3_SendRecord */
}
} else {
rv = dtls_QueueMessage(ss, ssl_ct_change_cipher_spec, &change, 1);
if (rv != SECSuccess) {
return SECFailure;
}
}
return SECSuccess;
}
static SECStatus
ssl3_SendChangeCipherSpecs(sslSocket *ss)
{
SECStatus rv;
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
rv = ssl3_SendChangeCipherSpecsInt(ss);
if (rv != SECSuccess) {
return rv; /* Error code set. */
}
/* swap the pending and current write specs. */
ssl_GetSpecWriteLock(ss); /**************************************/
ssl_CipherSpecRelease(ss->ssl3.cwSpec);
ss->ssl3.cwSpec = ss->ssl3.pwSpec;
ss->ssl3.pwSpec = NULL;
SSL_TRC(3, ("%d: SSL3[%d] Set Current Write Cipher Suite to Pending",
SSL_GETPID(), ss->fd));
/* With DTLS, we need to set a holddown timer in case the final
* message got lost */
if (IS_DTLS(ss) && ss->ssl3.crSpec->epoch == ss->ssl3.cwSpec->epoch) {
rv = dtls_StartHolddownTimer(ss);
}
ssl_ReleaseSpecWriteLock(ss); /**************************************/
return rv;
}
/* Called from ssl3_HandleRecord.
** Caller must hold both RecvBuf and Handshake locks.
*
* Acquires and releases spec write lock, to protect switching the current
* and pending write spec pointers.
*/
static SECStatus
ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf)
{
SSL3WaitState ws = ss->ssl3.hs.ws;
SSL3ChangeCipherSpecChoice change;
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
SSL_TRC(3, ("%d: SSL3[%d]: handle change_cipher_spec record",
SSL_GETPID(), ss->fd));
/* For DTLS: Ignore this if we aren't expecting it. Don't kill a connection
* as a result of receiving trash.
* For TLS: Maybe ignore, but only after checking format. */
if (ws != wait_change_cipher && IS_DTLS(ss)) {
/* Ignore this because it's out of order. */
SSL_TRC(3, ("%d: SSL3[%d]: discard out of order "
"DTLS change_cipher_spec",
SSL_GETPID(), ss->fd));
buf->len = 0;
return SECSuccess;
}
/* Handshake messages should not span ChangeCipherSpec. */
if (ss->ssl3.hs.header_bytes) {
(void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER);
return SECFailure;
}
if (buf->len != 1) {
(void)ssl3_DecodeError(ss);
PORT_SetError(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER);
return SECFailure;
}
change = (SSL3ChangeCipherSpecChoice)buf->buf[0];
if (change != change_cipher_spec_choice) {
/* illegal_parameter is correct here for both SSL3 and TLS. */
(void)ssl3_IllegalParameter(ss);
PORT_SetError(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER);
return SECFailure;
}
buf->len = 0;
if (ws != wait_change_cipher) {
/* Ignore a CCS for TLS 1.3. This only happens if the server sends a
* HelloRetryRequest. In other cases, the CCS will fail decryption and
* will be discarded by ssl3_HandleRecord(). */
if (ws == wait_server_hello &&
ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
ss->ssl3.hs.helloRetry) {
PORT_Assert(!ss->sec.isServer);
return SECSuccess;
}
/* Note: For a server, we can't test ss->ssl3.hs.helloRetry or
* ss->version because the server might be stateless (and so it won't
* have set either value yet). Set a flag so that at least we will
* guarantee that the server will treat any ClientHello properly. */
if (ws == wait_client_hello &&
ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3 &&
!ss->ssl3.hs.receivedCcs) {
PORT_Assert(ss->sec.isServer);
ss->ssl3.hs.receivedCcs = PR_TRUE;
return SECSuccess;
}
(void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER);
return SECFailure;
}
SSL_TRC(3, ("%d: SSL3[%d] Set Current Read Cipher Suite to Pending",
SSL_GETPID(), ss->fd));
ssl_GetSpecWriteLock(ss); /*************************************/
PORT_Assert(ss->ssl3.prSpec);
ssl_CipherSpecRelease(ss->ssl3.crSpec);
ss->ssl3.crSpec = ss->ssl3.prSpec;
ss->ssl3.prSpec = NULL;
ssl_ReleaseSpecWriteLock(ss); /*************************************/
ss->ssl3.hs.ws = wait_finished;
return SECSuccess;
}
static CK_MECHANISM_TYPE
ssl3_GetMgfMechanismByHashType(SSLHashType hash)
{
switch (hash) {
case ssl_hash_sha256:
return CKG_MGF1_SHA256;
case ssl_hash_sha384:
return CKG_MGF1_SHA384;
case ssl_hash_sha512:
return CKG_MGF1_SHA512;
default:
PORT_Assert(0);
}
return CKG_MGF1_SHA256;
}
/* Function valid for >= TLS 1.2, only. */
static CK_MECHANISM_TYPE
ssl3_GetHashMechanismByHashType(SSLHashType hashType)
{
switch (hashType) {
case ssl_hash_sha512:
return CKM_SHA512;
case ssl_hash_sha384:
return CKM_SHA384;
case ssl_hash_sha256:
case ssl_hash_none:
/* ssl_hash_none is for pre-1.2 suites, which use SHA-256. */
return CKM_SHA256;
case ssl_hash_sha1:
return CKM_SHA_1;
default:
PORT_Assert(0);
}
return CKM_SHA256;
}
/* Function valid for >= TLS 1.2, only. */
static CK_MECHANISM_TYPE
ssl3_GetPrfHashMechanism(sslSocket *ss)
{
return ssl3_GetHashMechanismByHashType(ss->ssl3.hs.suite_def->prf_hash);
}
static SSLHashType
ssl3_GetSuitePrfHash(sslSocket *ss)
{
/* ssl_hash_none is for pre-1.2 suites, which use SHA-256. */
if (ss->ssl3.hs.suite_def->prf_hash == ssl_hash_none) {
return ssl_hash_sha256;
}
return ss->ssl3.hs.suite_def->prf_hash;
}
/* This method completes the derivation of the MS from the PMS.
**
** 1. Derive the MS, if possible, else return an error.
**
** 2. Check the version if |pms_version| is non-zero and if wrong,
** return an error.
**
** 3. If |msp| is nonzero, return MS in |*msp|.
** Called from:
** ssl3_ComputeMasterSecretInt
** tls_ComputeExtendedMasterSecretInt
*/
static SECStatus
ssl3_ComputeMasterSecretFinish(sslSocket *ss,
CK_MECHANISM_TYPE master_derive,
CK_MECHANISM_TYPE key_derive,
CK_VERSION *pms_version,
SECItem *params, CK_FLAGS keyFlags,
PK11SymKey *pms, PK11SymKey **msp)
{
PK11SymKey *ms = NULL;
ms = PK11_DeriveWithFlags(pms, master_derive,
params, key_derive,
CKA_DERIVE, 0, keyFlags);
if (!ms) {
ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
return SECFailure;
}
if (pms_version && ss->opt.detectRollBack) {
SSL3ProtocolVersion client_version;
client_version = pms_version->major << 8 | pms_version->minor;
if (IS_DTLS(ss)) {
client_version = dtls_DTLSVersionToTLSVersion(client_version);
}
if (client_version != ss->clientHelloVersion) {
/* Destroy MS. Version roll-back detected. */
PK11_FreeSymKey(ms);
ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
return SECFailure;
}
}
if (msp) {
*msp = ms;
} else {
PK11_FreeSymKey(ms);
}
return SECSuccess;
}
/* Compute the ordinary (pre draft-ietf-tls-session-hash) master
** secret and return it in |*msp|.
**
** Called from: ssl3_ComputeMasterSecret
*/
static SECStatus
ssl3_ComputeMasterSecretInt(sslSocket *ss, PK11SymKey *pms,
PK11SymKey **msp)
{
PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0);
PRBool isTLS12 = (PRBool)(ss->version >= SSL_LIBRARY_VERSION_TLS_1_2);
/*
* Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH
* which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size
* data into a 48-byte value, and does not expect to return the version.
*/
PRBool isDH = (PRBool)((ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_dh) ||
(ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh) ||
(ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh_hybrid));
CK_MECHANISM_TYPE master_derive;
CK_MECHANISM_TYPE key_derive;
SECItem params;
CK_FLAGS keyFlags;
CK_VERSION pms_version;
CK_VERSION *pms_version_ptr = NULL;
/* master_params may be used as a CK_SSL3_MASTER_KEY_DERIVE_PARAMS */
CK_TLS12_MASTER_KEY_DERIVE_PARAMS master_params;
unsigned int master_params_len;
/* if we are using TLS and we aren't using the extended master secret,
* and SEC_OID_TLS_REQUIRE_EMS policy is true, fail. The caller will
* send an alert (eventually). In the RSA Server case, the alert
* won't happen until Finish time because the upper level code
* can't tell a difference between this failure and an RSA decrypt
* failure, so it will proceed with a faux key */
if (isTLS) {
PRUint32 policy;
SECStatus rv;
/* first fetch the policy for this algorithm */
rv = NSS_GetAlgorithmPolicy(SEC_OID_TLS_REQUIRE_EMS, &policy);
/* we only look at the policy if we can fetch it. */
if ((rv == SECSuccess) && (policy & NSS_USE_ALG_IN_SSL_KX)) {
/* just set the error, we don't want to map any errors
* set by NSS_GetAlgorithmPolicy here */
PORT_SetError(SSL_ERROR_MISSING_EXTENDED_MASTER_SECRET);
return SECFailure;
}
}
if (isTLS12) {
if (isDH)
master_derive = CKM_TLS12_MASTER_KEY_DERIVE_DH;
else
master_derive = CKM_TLS12_MASTER_KEY_DERIVE;
key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE;
keyFlags = CKF_SIGN | CKF_VERIFY;
} else if (isTLS) {
if (isDH)
master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH;
else
master_derive = CKM_TLS_MASTER_KEY_DERIVE;
key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
keyFlags = CKF_SIGN | CKF_VERIFY;
} else {
if (isDH)
master_derive = CKM_SSL3_MASTER_KEY_DERIVE_DH;
else
master_derive = CKM_SSL3_MASTER_KEY_DERIVE;
key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE;
keyFlags = 0;
}
if (!isDH) {
pms_version_ptr = &pms_version;
}
master_params.pVersion = pms_version_ptr;
master_params.RandomInfo.pClientRandom = ss->ssl3.hs.client_random;
master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
master_params.RandomInfo.pServerRandom = ss->ssl3.hs.server_random;
master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
if (isTLS12) {
master_params.prfHashMechanism = ssl3_GetPrfHashMechanism(ss);
master_params_len = sizeof(CK_TLS12_MASTER_KEY_DERIVE_PARAMS);
} else {
/* prfHashMechanism is not relevant with this PRF */
master_params_len = sizeof(CK_SSL3_MASTER_KEY_DERIVE_PARAMS);
}
params.data = (unsigned char *)&master_params;
params.len = master_params_len;
return ssl3_ComputeMasterSecretFinish(ss, master_derive, key_derive,
pms_version_ptr, &params,
keyFlags, pms, msp);
}
/* Compute the draft-ietf-tls-session-hash master
** secret and return it in |*msp|.
**
** Called from: ssl3_ComputeMasterSecret
*/
static SECStatus
tls_ComputeExtendedMasterSecretInt(sslSocket *ss, PK11SymKey *pms,
PK11SymKey **msp)
{
ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
CK_TLS12_EXTENDED_MASTER_KEY_DERIVE_PARAMS extended_master_params;
SSL3Hashes hashes;
/*
* Determine whether to use the DH/ECDH or RSA derivation modes.
*/
/*
* TODO(ekr@rtfm.com): Verify that the slot can handle this key expansion
* mode. Bug 1198298 */
PRBool isDH = (PRBool)((ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_dh) ||
(ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh) ||
(ss->ssl3.hs.kea_def->exchKeyType == ssl_kea_ecdh_hybrid));
CK_MECHANISM_TYPE master_derive;
CK_MECHANISM_TYPE key_derive;
SECItem params;
const CK_FLAGS keyFlags = CKF_SIGN | CKF_VERIFY;
CK_VERSION pms_version;
CK_VERSION *pms_version_ptr = NULL;
SECStatus rv;
rv = ssl3_ComputeHandshakeHashes(ss, pwSpec, &hashes, 0);
if (rv != SECSuccess) {
PORT_Assert(0); /* Should never fail */
ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
return SECFailure;
}
if (isDH) {
master_derive = CKM_TLS12_EXTENDED_MASTER_KEY_DERIVE_DH;
} else {
master_derive = CKM_TLS12_EXTENDED_MASTER_KEY_DERIVE;
pms_version_ptr = &pms_version;
}
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_2) {
/* TLS 1.2+ */
extended_master_params.prfHashMechanism = ssl3_GetPrfHashMechanism(ss);
key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE;
} else {
/* TLS < 1.2 */
extended_master_params.prfHashMechanism = CKM_TLS_PRF;
key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
}
extended_master_params.pVersion = pms_version_ptr;
extended_master_params.pSessionHash = hashes.u.raw;
extended_master_params.ulSessionHashLen = hashes.len;
params.data = (unsigned char *)&extended_master_params;
params.len = sizeof extended_master_params;
return ssl3_ComputeMasterSecretFinish(ss, master_derive, key_derive,
pms_version_ptr, &params,
keyFlags, pms, msp);
}
/* Wrapper method to compute the master secret and return it in |*msp|.
**
** Called from ssl3_ComputeMasterSecret
*/
static SECStatus
ssl3_ComputeMasterSecret(sslSocket *ss, PK11SymKey *pms,
PK11SymKey **msp)
{
PORT_Assert(pms != NULL);
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
if (ssl3_ExtensionNegotiated(ss, ssl_extended_master_secret_xtn)) {
return tls_ComputeExtendedMasterSecretInt(ss, pms, msp);
} else {
return ssl3_ComputeMasterSecretInt(ss, pms, msp);
}
}
/*
* Derive encryption and MAC Keys (and IVs) from master secret
* Sets a useful error code when returning SECFailure.
*
* Called only from ssl3_InitPendingCipherSpec(),
* which in turn is called from
* ssl3_SendRSAClientKeyExchange (for Full handshake)
* ssl3_SendDHClientKeyExchange (for Full handshake)
* ssl3_HandleClientKeyExchange (for Full handshake)
* ssl3_HandleServerHello (for session restart)
* ssl3_HandleClientHello (for session restart)
* Caller MUST hold the specWriteLock, and SSL3HandshakeLock.
* ssl3_InitPendingCipherSpec does that.
*
*/
static SECStatus
ssl3_DeriveConnectionKeys(sslSocket *ss, PK11SymKey *masterSecret)
{
ssl3CipherSpec *pwSpec = ss->ssl3.pwSpec;
ssl3CipherSpec *prSpec = ss->ssl3.prSpec;
ssl3CipherSpec *clientSpec;
ssl3CipherSpec *serverSpec;
PRBool isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0);
PRBool isTLS12 =
(PRBool)(isTLS && ss->version >= SSL_LIBRARY_VERSION_TLS_1_2);
const ssl3BulkCipherDef *cipher_def = pwSpec->cipherDef;
PK11SlotInfo *slot = NULL;
PK11SymKey *derivedKeyHandle = NULL;
void *pwArg = ss->pkcs11PinArg;
int keySize;
CK_TLS12_KEY_MAT_PARAMS key_material_params; /* may be used as a
* CK_SSL3_KEY_MAT_PARAMS */
unsigned int key_material_params_len;
CK_SSL3_KEY_MAT_OUT returnedKeys;
CK_MECHANISM_TYPE key_derive;
CK_MECHANISM_TYPE bulk_mechanism;
SSLCipherAlgorithm calg;
SECItem params;
PRBool skipKeysAndIVs = (PRBool)(cipher_def->calg == ssl_calg_null);
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSpecWriteLock(ss));
PORT_Assert(masterSecret);
/* These functions operate in terms of who is writing specs. */
if (ss->sec.isServer) {
clientSpec = prSpec;
serverSpec = pwSpec;
} else {
clientSpec = pwSpec;
serverSpec = prSpec;
}
/*
* generate the key material
*/
if (cipher_def->type == type_block &&
ss->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
/* Block ciphers in >= TLS 1.1 use a per-record, explicit IV. */
key_material_params.ulIVSizeInBits = 0;
PORT_Memset(clientSpec->keyMaterial.iv, 0, cipher_def->iv_size);
PORT_Memset(serverSpec->keyMaterial.iv, 0, cipher_def->iv_size);
}
key_material_params.bIsExport = PR_FALSE;
key_material_params.RandomInfo.pClientRandom = ss->ssl3.hs.client_random;
key_material_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
key_material_params.RandomInfo.pServerRandom = ss->ssl3.hs.server_random;
key_material_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
key_material_params.pReturnedKeyMaterial = &returnedKeys;
if (skipKeysAndIVs) {
keySize = 0;
returnedKeys.pIVClient = NULL;
returnedKeys.pIVServer = NULL;
key_material_params.ulKeySizeInBits = 0;
key_material_params.ulIVSizeInBits = 0;
} else {
keySize = cipher_def->key_size;
returnedKeys.pIVClient = clientSpec->keyMaterial.iv;
returnedKeys.pIVServer = serverSpec->keyMaterial.iv;
key_material_params.ulKeySizeInBits = cipher_def->secret_key_size * BPB;
key_material_params.ulIVSizeInBits = cipher_def->iv_size * BPB;
}
key_material_params.ulMacSizeInBits = pwSpec->macDef->mac_size * BPB;
calg = cipher_def->calg;
bulk_mechanism = ssl3_Alg2Mech(calg);
if (isTLS12) {
key_derive = CKM_TLS12_KEY_AND_MAC_DERIVE;
key_material_params.prfHashMechanism = ssl3_GetPrfHashMechanism(ss);
key_material_params_len = sizeof(CK_TLS12_KEY_MAT_PARAMS);
} else if (isTLS) {
key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
key_material_params_len = sizeof(CK_SSL3_KEY_MAT_PARAMS);
} else {
key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE;
key_material_params_len = sizeof(CK_SSL3_KEY_MAT_PARAMS);
}
params.data = (unsigned char *)&key_material_params;
params.len = key_material_params_len;
/* CKM_SSL3_KEY_AND_MAC_DERIVE is defined to set ENCRYPT, DECRYPT, and
* DERIVE by DEFAULT */
derivedKeyHandle = PK11_Derive(masterSecret, key_derive, &params,
bulk_mechanism, CKA_ENCRYPT, keySize);
if (!derivedKeyHandle) {
ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
return SECFailure;
}
/* we really should use the actual mac'ing mechanism here, but we
* don't because these types are used to map keytype anyway and both
* mac's map to the same keytype.
*/
slot = PK11_GetSlotFromKey(derivedKeyHandle);
PK11_FreeSlot(slot); /* slot is held until the key is freed */
clientSpec->keyMaterial.macKey =
PK11_SymKeyFromHandle(slot, derivedKeyHandle, PK11_OriginDerive,
CKM_SSL3_SHA1_MAC, returnedKeys.hClientMacSecret,
PR_TRUE, pwArg);
if (clientSpec->keyMaterial.macKey == NULL) {
goto loser; /* loser sets err */
}
serverSpec->keyMaterial.macKey =
PK11_SymKeyFromHandle(slot, derivedKeyHandle, PK11_OriginDerive,
CKM_SSL3_SHA1_MAC, returnedKeys.hServerMacSecret,
PR_TRUE, pwArg);
if (serverSpec->keyMaterial.macKey == NULL) {
goto loser; /* loser sets err */
}
if (!skipKeysAndIVs) {
clientSpec->keyMaterial.key =
PK11_SymKeyFromHandle(slot, derivedKeyHandle, PK11_OriginDerive,
bulk_mechanism, returnedKeys.hClientKey,
PR_TRUE, pwArg);
if (clientSpec->keyMaterial.key == NULL) {
goto loser; /* loser sets err */
}
serverSpec->keyMaterial.key =
PK11_SymKeyFromHandle(slot, derivedKeyHandle, PK11_OriginDerive,
bulk_mechanism, returnedKeys.hServerKey,
PR_TRUE, pwArg);
if (serverSpec->keyMaterial.key == NULL) {
goto loser; /* loser sets err */
}
}
PK11_FreeSymKey(derivedKeyHandle);
return SECSuccess;
loser:
PK11_FreeSymKey(derivedKeyHandle);
ssl_MapLowLevelError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
return SECFailure;
}
void
ssl3_CoalesceEchHandshakeHashes(sslSocket *ss)
{
/* |sha| contains the CHOuter transcript, which is the singular
* transcript if not doing ECH. If the server responded with 1.2,
* contexts are not yet initialized. */
if (ss->ssl3.hs.echAccepted) {
if (ss->ssl3.hs.sha) {
PORT_Assert(ss->ssl3.hs.shaEchInner);
PK11_DestroyContext(ss->ssl3.hs.sha, PR_TRUE);
ss->ssl3.hs.sha = ss->ssl3.hs.shaEchInner;
ss->ssl3.hs.shaEchInner = NULL;
}
} else {
if (ss->ssl3.hs.shaEchInner) {
PK11_DestroyContext(ss->ssl3.hs.shaEchInner, PR_TRUE);
ss->ssl3.hs.shaEchInner = NULL;
}
}
}
/* ssl3_InitHandshakeHashes creates handshake hash contexts and hashes in
* buffered messages in ss->ssl3.hs.messages. Called from
* ssl3_NegotiateCipherSuite(), tls13_HandleClientHelloPart2(),
* and ssl3_HandleServerHello. */
SECStatus
ssl3_InitHandshakeHashes(sslSocket *ss)
{
SSL_TRC(30, ("%d: SSL3[%d]: start handshake hashes", SSL_GETPID(), ss->fd));
PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_unknown);
if (ss->version == SSL_LIBRARY_VERSION_TLS_1_2) {
ss->ssl3.hs.hashType = handshake_hash_record;
} else {
PORT_Assert(!ss->ssl3.hs.md5 && !ss->ssl3.hs.sha);
/*
* note: We should probably lookup an SSL3 slot for these
* handshake hashes in hopes that we wind up with the same slots
* that the master secret will wind up in ...
*/
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
/* determine the hash from the prf */
const SECOidData *hash_oid =
SECOID_FindOIDByMechanism(ssl3_GetPrfHashMechanism(ss));
/* Get the PKCS #11 mechanism for the Hash from the cipher suite (prf_hash)
* Convert that to the OidTag. We can then use that OidTag to create our
* PK11Context */
PORT_Assert(hash_oid != NULL);
if (hash_oid == NULL) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
return SECFailure;
}
ss->ssl3.hs.sha = PK11_CreateDigestContext(hash_oid->offset);
if (ss->ssl3.hs.sha == NULL) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return SECFailure;
}
ss->ssl3.hs.hashType = handshake_hash_single;
if (PK11_DigestBegin(ss->ssl3.hs.sha) != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
return SECFailure;
}
/* Transcript hash used on ECH client. */
if (!ss->sec.isServer && ss->ssl3.hs.echHpkeCtx) {
ss->ssl3.hs.shaEchInner = PK11_CreateDigestContext(hash_oid->offset);
if (ss->ssl3.hs.shaEchInner == NULL) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return SECFailure;
}
if (PK11_DigestBegin(ss->ssl3.hs.shaEchInner) != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
return SECFailure;
}
}
} else {
/* Both ss->ssl3.hs.md5 and ss->ssl3.hs.sha should be NULL or
* created successfully. */
ss->ssl3.hs.md5 = PK11_CreateDigestContext(SEC_OID_MD5);
if (ss->ssl3.hs.md5 == NULL) {
ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
return SECFailure;
}
ss->ssl3.hs.sha = PK11_CreateDigestContext(SEC_OID_SHA1);
if (ss->ssl3.hs.sha == NULL) {
PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE);
ss->ssl3.hs.md5 = NULL;
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return SECFailure;
}
ss->ssl3.hs.hashType = handshake_hash_combo;
if (PK11_DigestBegin(ss->ssl3.hs.md5) != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
return SECFailure;
}
if (PK11_DigestBegin(ss->ssl3.hs.sha) != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return SECFailure;
}
}
}
if (ss->ssl3.hs.hashType != handshake_hash_record &&
ss->ssl3.hs.messages.len > 0) {
/* When doing ECH, ssl3_UpdateHandshakeHashes will store outer messages
* into the both the outer and inner transcripts.
* ssl3_UpdateDefaultHandshakeHashes uses the default context which is
* the outer when doing client ECH. For ECH shared-mode or backend
* servers only the hs.messages buffer is used. */
if (ssl3_UpdateDefaultHandshakeHashes(ss, ss->ssl3.hs.messages.buf,
ss->ssl3.hs.messages.len) != SECSuccess) {
return SECFailure;
}
/* When doing ECH, deriving the accept_confirmation value requires all
* messages up to and including the ServerHello
* (see draft-ietf-tls-esni-14, Section 7.2).
*
* Don't free the transcript buffer until confirmation calculation. */
if (!ss->ssl3.hs.echHpkeCtx && !ss->opt.enableTls13BackendEch) {
sslBuffer_Clear(&ss->ssl3.hs.messages);
}
}
if (ss->ssl3.hs.shaEchInner &&
ss->ssl3.hs.echInnerMessages.len > 0) {
if (PK11_DigestOp(ss->ssl3.hs.shaEchInner, ss->ssl3.hs.echInnerMessages.buf,
ss->ssl3.hs.echInnerMessages.len) != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
return SECFailure;
}
if (!ss->ssl3.hs.echHpkeCtx) {
sslBuffer_Clear(&ss->ssl3.hs.echInnerMessages);
}
}
return SECSuccess;
}
void
ssl3_RestartHandshakeHashes(sslSocket *ss)
{
SSL_TRC(30, ("%d: SSL3[%d]: reset handshake hashes",
SSL_GETPID(), ss->fd));
ss->ssl3.hs.hashType = handshake_hash_unknown;
ss->ssl3.hs.messages.len = 0;
ss->ssl3.hs.echInnerMessages.len = 0;
if (ss->ssl3.hs.md5) {
PK11_DestroyContext(ss->ssl3.hs.md5, PR_TRUE);
ss->ssl3.hs.md5 = NULL;
}
if (ss->ssl3.hs.sha) {
PK11_DestroyContext(ss->ssl3.hs.sha, PR_TRUE);
ss->ssl3.hs.sha = NULL;
}
if (ss->ssl3.hs.shaEchInner) {
PK11_DestroyContext(ss->ssl3.hs.shaEchInner, PR_TRUE);
ss->ssl3.hs.shaEchInner = NULL;
}
if (ss->ssl3.hs.shaPostHandshake) {
PK11_DestroyContext(ss->ssl3.hs.shaPostHandshake, PR_TRUE);
ss->ssl3.hs.shaPostHandshake = NULL;
}
}
/* Add the provided bytes to the handshake hash context. When doing
* TLS 1.3 ECH, |target| may be provided to specify only the inner/outer
* transcript, else the input is added to both contexts. This happens
* only on the client. On the server, only the default context is used. */
SECStatus
ssl3_UpdateHandshakeHashesInt(sslSocket *ss, const unsigned char *b,
unsigned int l, sslBuffer *target)
{
SECStatus rv = SECSuccess;
PRBool explicit = (target != NULL);
PRBool appendToEchInner = !ss->sec.isServer &&
ss->ssl3.hs.echHpkeCtx &&
!explicit;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(target != &ss->ssl3.hs.echInnerMessages ||
!ss->sec.isServer);
if (target == NULL) {
/* Default context. */
target = &ss->ssl3.hs.messages;
}
/* With TLS 1.3, and versions TLS.1.1 and older, we keep the hash(es)
* always up to date. However, we must initially buffer the handshake
* messages, until we know what to do.
* If ss->ssl3.hs.hashType != handshake_hash_unknown,
* it means we know what to do. We calculate (hash our input),
* and we stop appending to the buffer.
*
* With TLS 1.2, we always append all handshake messages,
* and never update the hash, because the hash function we must use for
* certificate_verify might be different from the hash function we use
* when signing other handshake hashes. */
if (ss->ssl3.hs.hashType == handshake_hash_unknown ||
ss->ssl3.hs.hashType == handshake_hash_record) {
rv = sslBuffer_Append(target, b, l);
if (rv != SECSuccess) {
return SECFailure;
}
if (appendToEchInner) {
return sslBuffer_Append(&ss->ssl3.hs.echInnerMessages, b, l);
}
return SECSuccess;
}
PRINT_BUF(90, (ss, "handshake hash input:", b, l));
if (ss->ssl3.hs.hashType == handshake_hash_single) {
PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
if (target == &ss->ssl3.hs.messages) {
rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
return rv;
}
}
if (ss->ssl3.hs.shaEchInner &&
(target == &ss->ssl3.hs.echInnerMessages || !explicit)) {
rv = PK11_DigestOp(ss->ssl3.hs.shaEchInner, b, l);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
return rv;
}
}
} else if (ss->ssl3.hs.hashType == handshake_hash_combo) {
rv = PK11_DigestOp(ss->ssl3.hs.md5, b, l);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
return rv;
}
rv = PK11_DigestOp(ss->ssl3.hs.sha, b, l);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
return rv;
}
}
return rv;
}
static SECStatus
ssl3_UpdateDefaultHandshakeHashes(sslSocket *ss, const unsigned char *b,
unsigned int l)
{
return ssl3_UpdateHandshakeHashesInt(ss, b, l,
&ss->ssl3.hs.messages);
}
static SECStatus
ssl3_UpdateInnerHandshakeHashes(sslSocket *ss, const unsigned char *b,
unsigned int l)
{
return ssl3_UpdateHandshakeHashesInt(ss, b, l,
&ss->ssl3.hs.echInnerMessages);
}
/*
* Handshake messages
*/
/* Called from ssl3_InitHandshakeHashes()
** ssl3_AppendHandshake()
** ssl3_HandleV2ClientHello()
** ssl3_HandleHandshakeMessage()
** Caller must hold the ssl3Handshake lock.
*/
SECStatus
ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l)
{
return ssl3_UpdateHandshakeHashesInt(ss, b, l, NULL);
}
SECStatus
ssl3_UpdatePostHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l)
{
SECStatus rv = SECSuccess;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PRINT_BUF(90, (ss, "post handshake hash input:", b, l));
PORT_Assert(ss->ssl3.hs.hashType == handshake_hash_single);
PORT_Assert(ss->version >= SSL_LIBRARY_VERSION_TLS_1_3);
rv = PK11_DigestOp(ss->ssl3.hs.shaPostHandshake, b, l);
if (rv != SECSuccess) {
PORT_SetError(SSL_ERROR_DIGEST_FAILURE);
}
return rv;
}
/* The next two functions serve to append the handshake header.
The first one additionally writes to seqNumberBuffer
the sequence number of the message we are generating.
This function is used when generating the keyUpdate message in dtls13_enqueueKeyUpdateMessage.
*/
SECStatus
ssl3_AppendHandshakeHeaderAndStashSeqNum(sslSocket *ss, SSLHandshakeType t, PRUint32 length, PRUint64 *sendMessageSeqOut)
{
PORT_Assert(t != ssl_hs_client_hello);
SECStatus rv;
/* If we already have a message in place, we need to enqueue it.
* This empties the buffer. This is a convenient place to call
* dtls_StageHandshakeMessage to mark the message boundary.
*/
if (IS_DTLS(ss)) {
rv = dtls_StageHandshakeMessage(ss);
if (rv != SECSuccess) {
return rv;
}
}
SSL_TRC(30, ("%d: SSL3[%d]: append handshake header: type %s",
SSL_GETPID(), ss->fd, ssl3_DecodeHandshakeType(t)));
rv = ssl3_AppendHandshakeNumber(ss, t, 1);
if (rv != SECSuccess) {
return rv; /* error code set by AppendHandshake, if applicable. */
}
rv = ssl3_AppendHandshakeNumber(ss, length, 3);
if (rv != SECSuccess) {
return rv; /* error code set by AppendHandshake, if applicable. */
}
if (IS_DTLS(ss)) {
/* RFC 9147. 5.2. DTLS Handshake Message Format.
* In DTLS 1.3, the message transcript is computed over the original TLS
* 1.3-style Handshake messages without the message_seq,
* fragment_offset, and fragment_length values. Note that this is a
* change from DTLS 1.2 where those values were included in the transcript. */
PRBool suppressHash = ss->version == SSL_LIBRARY_VERSION_TLS_1_3 ? PR_TRUE : PR_FALSE;
/* Note that we make an unfragmented message here. We fragment in the
* transmission code, if necessary */
rv = ssl3_AppendHandshakeNumberSuppressHash(ss, ss->ssl3.hs.sendMessageSeq, 2, suppressHash);
if (rv != SECSuccess) {
return rv; /* error code set by AppendHandshake, if applicable. */
}
/* In case if we provide a buffer for the sequence message,
we write down sendMessageSeq to the buffer. */
if (sendMessageSeqOut != NULL) {
*sendMessageSeqOut = ss->ssl3.hs.sendMessageSeq;
}
ss->ssl3.hs.sendMessageSeq++;
/* 0 is the fragment offset, because it's not fragmented yet */
rv = ssl3_AppendHandshakeNumberSuppressHash(ss, 0, 3, suppressHash);
if (rv != SECSuccess) {
return rv; /* error code set by AppendHandshake, if applicable. */
}
/* Fragment length -- set to the packet length because not fragmented */
rv = ssl3_AppendHandshakeNumberSuppressHash(ss, length, 3, suppressHash);
if (rv != SECSuccess) {
return rv; /* error code set by AppendHandshake, if applicable. */
}
}
return rv; /* error code set by AppendHandshake, if applicable. */
}
/* The function calls the ssl3_AppendHandshakeHeaderAndStashSeqNum implemented above.
As in the majority of the cases we do not need the last parameter,
we separate out this function. */
SECStatus
ssl3_AppendHandshakeHeader(sslSocket *ss, SSLHandshakeType t, PRUint32 length)
{
return ssl3_AppendHandshakeHeaderAndStashSeqNum(ss, t, length, NULL);
}
/**************************************************************************
* Consume Handshake functions.
*
* All data used in these functions is protected by two locks,
* the RecvBufLock and the SSL3HandshakeLock
**************************************************************************/
/* Read up the next "bytes" number of bytes from the (decrypted) input
* stream "b" (which is *length bytes long). Copy them into buffer "v".
* Reduces *length by bytes. Advances *b by bytes.
*
* If this function returns SECFailure, it has already sent an alert,
* and has set a generic error code. The caller should probably
* override the generic error code by setting another.
*/
SECStatus
ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRUint32 bytes, PRUint8 **b,
PRUint32 *length)
{
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
if ((PRUint32)bytes > *length) {
return ssl3_DecodeError(ss);
}
PORT_Memcpy(v, *b, bytes);
PRINT_BUF(60, (ss, "consume bytes:", *b, bytes));
*b += bytes;
*length -= bytes;
return SECSuccess;
}
/* Read up the next "bytes" number of bytes from the (decrypted) input
* stream "b" (which is *length bytes long), and interpret them as an
* integer in network byte order. Sets *num to the received value.
* Reduces *length by bytes. Advances *b by bytes.
*
* On error, an alert has been sent, and a generic error code has been set.
*/
SECStatus
ssl3_ConsumeHandshakeNumber64(sslSocket *ss, PRUint64 *num, PRUint32 bytes,
PRUint8 **b, PRUint32 *length)
{
PRUint8 *buf = *b;
PRUint32 i;
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
*num = 0;
if (bytes > sizeof(*num)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if (bytes > *length) {
return ssl3_DecodeError(ss);
}
PRINT_BUF(60, (ss, "consume bytes:", *b, bytes));
for (i = 0; i < bytes; i++) {
*num = (*num << 8) + buf[i];
}
*b += bytes;
*length -= bytes;
return SECSuccess;
}
SECStatus
ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRUint32 *num, PRUint32 bytes,
PRUint8 **b, PRUint32 *length)
{
PRUint64 num64;
SECStatus rv;
PORT_Assert(bytes <= sizeof(*num));
if (bytes > sizeof(*num)) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rv = ssl3_ConsumeHandshakeNumber64(ss, &num64, bytes, b, length);
if (rv != SECSuccess) {
return SECFailure;
}
*num = num64 & 0xffffffff;
return SECSuccess;
}
/* Read in two values from the incoming decrypted byte stream "b", which is
* *length bytes long. The first value is a number whose size is "bytes"
* bytes long. The second value is a byte-string whose size is the value
* of the first number received. The latter byte-string, and its length,
* is returned in the SECItem i.
*
* Returns SECFailure (-1) on failure.
* On error, an alert has been sent, and a generic error code has been set.
*
* RADICAL CHANGE for NSS 3.11. All callers of this function make copies
* of the data returned in the SECItem *i, so making a copy of it here
* is simply wasteful. So, This function now just sets SECItem *i to
* point to the values in the buffer **b.
*/
SECStatus
ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRUint32 bytes,
PRUint8 **b, PRUint32 *length)
{
PRUint32 count;
SECStatus rv;
PORT_Assert(bytes <= 3);
i->len = 0;
i->data = NULL;
i->type = siBuffer;
rv = ssl3_ConsumeHandshakeNumber(ss, &count, bytes, b, length);
if (rv != SECSuccess) {
return SECFailure;
}
if (count > 0) {
if (count > *length) {
return ssl3_DecodeError(ss);
}
i->data = *b;
i->len = count;
*b += count;
*length -= count;
}
return SECSuccess;
}
/* ssl3_TLSHashAlgorithmToOID converts a TLS hash identifier into an OID value.
* If the hash is not recognised, SEC_OID_UNKNOWN is returned.
*
SECOidTag
ssl3_HashTypeToOID(SSLHashType hashType)
{
switch (hashType) {
case ssl_hash_sha1:
return SEC_OID_SHA1;
case ssl_hash_sha256:
return SEC_OID_SHA256;
case ssl_hash_sha384:
return SEC_OID_SHA384;
case ssl_hash_sha512:
return SEC_OID_SHA512;
default:
break;
}
return SEC_OID_UNKNOWN;
}
SECOidTag
ssl3_AuthTypeToOID(SSLAuthType authType)
{
switch (authType) {
case ssl_auth_rsa_sign:
return SEC_OID_PKCS1_RSA_ENCRYPTION;
case ssl_auth_rsa_pss:
return SEC_OID_PKCS1_RSA_PSS_SIGNATURE;
case ssl_auth_ecdsa:
return SEC_OID_ANSIX962_EC_PUBLIC_KEY;
case ssl_auth_dsa:
return SEC_OID_ANSIX9_DSA_SIGNATURE;
default:
break;
}
/* shouldn't ever get there */
PORT_Assert(0);
return SEC_OID_UNKNOWN;
}
SSLHashType
ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme)
{
switch (scheme) {
case ssl_sig_rsa_pkcs1_sha1:
case ssl_sig_dsa_sha1:
case ssl_sig_ecdsa_sha1:
return ssl_hash_sha1;
case ssl_sig_rsa_pkcs1_sha256:
case ssl_sig_ecdsa_secp256r1_sha256:
case ssl_sig_rsa_pss_rsae_sha256:
case ssl_sig_rsa_pss_pss_sha256:
case ssl_sig_dsa_sha256:
return ssl_hash_sha256;
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_ecdsa_secp384r1_sha384:
case ssl_sig_rsa_pss_rsae_sha384:
case ssl_sig_rsa_pss_pss_sha384:
case ssl_sig_dsa_sha384:
return ssl_hash_sha384;
case ssl_sig_rsa_pkcs1_sha512:
case ssl_sig_ecdsa_secp521r1_sha512:
case ssl_sig_rsa_pss_rsae_sha512:
case ssl_sig_rsa_pss_pss_sha512:
case ssl_sig_dsa_sha512:
return ssl_hash_sha512;
case ssl_sig_rsa_pkcs1_sha1md5:
return ssl_hash_none; /* Special for TLS 1.0/1.1. */
case ssl_sig_none:
case ssl_sig_ed25519:
case ssl_sig_ed448:
break;
}
PORT_Assert(0);
return ssl_hash_none;
}
static PRBool
ssl_SignatureSchemeMatchesSpkiOid(SSLSignatureScheme scheme, SECOidTag spkiOid)
{
SECOidTag authOid = ssl3_AuthTypeToOID(ssl_SignatureSchemeToAuthType(scheme));
if (spkiOid == authOid) {
return PR_TRUE;
}
if ((authOid == SEC_OID_PKCS1_RSA_ENCRYPTION) &&
(spkiOid == SEC_OID_X500_RSA_ENCRYPTION)) {
return PR_TRUE;
}
return PR_FALSE;
}
/* Validate that the signature scheme works for the given key type. */
PRBool
ssl_SignatureSchemeValid(SSLSignatureScheme scheme, SECOidTag spkiOid,
PRBool isTls13)
{
if (!ssl_IsSupportedSignatureScheme(scheme)) {
return PR_FALSE;
}
/* if we are purposefully passed SEC_OID_UNKNOWN, it means
* we not checking the scheme against a potential key, so skip
* the call */
if ((spkiOid != SEC_OID_UNKNOWN) &&
!ssl_SignatureSchemeMatchesSpkiOid(scheme, spkiOid)) {
return PR_FALSE;
}
if (isTls13) {
if (ssl_SignatureSchemeToHashType(scheme) == ssl_hash_sha1) {
return PR_FALSE;
}
if (ssl_IsRsaPkcs1SignatureScheme(scheme)) {
return PR_FALSE;
}
if (ssl_IsDsaSignatureScheme(scheme)) {
return PR_FALSE;
}
/* With TLS 1.3, EC keys should have been selected based on calling
* ssl_SignatureSchemeFromSpki(), reject them otherwise. */
return spkiOid != SEC_OID_ANSIX962_EC_PUBLIC_KEY;
}
return PR_TRUE;
}
static SECStatus
ssl_SignatureSchemeFromPssSpki(const CERTSubjectPublicKeyInfo *spki,
SSLSignatureScheme *scheme)
{
SECKEYRSAPSSParams pssParam = { 0 };
PORTCheapArenaPool arena;
SECStatus rv;
/* The key doesn't have parameters, boo. */
if (!spki->algorithm.parameters.len) {
*scheme = ssl_sig_none;
return SECSuccess;
}
PORT_InitCheapArena(&arena, DER_DEFAULT_CHUNKSIZE);
rv = SEC_QuickDERDecodeItem(&arena.arena, &pssParam,
SEC_ASN1_GET(SECKEY_RSAPSSParamsTemplate),
&spki->algorithm.parameters);
if (rv != SECSuccess) {
goto loser;
}
/* Not having hashAlg means SHA-1 and we don't accept that. */
if (!pssParam.hashAlg) {
goto loser;
}
switch (SECOID_GetAlgorithmTag(pssParam.hashAlg)) {
case SEC_OID_SHA256:
*scheme = ssl_sig_rsa_pss_pss_sha256;
break;
case SEC_OID_SHA384:
*scheme = ssl_sig_rsa_pss_pss_sha384;
break;
case SEC_OID_SHA512:
*scheme = ssl_sig_rsa_pss_pss_sha512;
break;
default:
goto loser;
}
PORT_DestroyCheapArena(&arena);
return SECSuccess;
loser:
PORT_DestroyCheapArena(&arena);
PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
return SECFailure;
}
static SECStatus
ssl_SignatureSchemeFromEcSpki(const CERTSubjectPublicKeyInfo *spki,
SSLSignatureScheme *scheme)
{
const sslNamedGroupDef *group;
SECKEYPublicKey *key;
key = SECKEY_ExtractPublicKey(spki);
if (!key) {
PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
return SECFailure;
}
group = ssl_ECPubKey2NamedGroup(key);
SECKEY_DestroyPublicKey(key);
if (!group) {
PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
return SECFailure;
}
switch (group->name) {
case ssl_grp_ec_secp256r1:
*scheme = ssl_sig_ecdsa_secp256r1_sha256;
return SECSuccess;
case ssl_grp_ec_secp384r1:
*scheme = ssl_sig_ecdsa_secp384r1_sha384;
return SECSuccess;
case ssl_grp_ec_secp521r1:
*scheme = ssl_sig_ecdsa_secp521r1_sha512;
return SECSuccess;
default:
break;
}
PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
return SECFailure;
}
/* Newer signature schemes are designed so that a single SPKI can be used with
* that scheme. This determines that scheme from the SPKI. If the SPKI doesn't
* have a single scheme, |*scheme| is set to ssl_sig_none. */
SECStatus
ssl_SignatureSchemeFromSpki(const CERTSubjectPublicKeyInfo *spki,
PRBool isTls13, SSLSignatureScheme *scheme)
{
SECOidTag spkiOid = SECOID_GetAlgorithmTag(&spki->algorithm);
if (spkiOid == SEC_OID_PKCS1_RSA_PSS_SIGNATURE) {
return ssl_SignatureSchemeFromPssSpki(spki, scheme);
}
/* Only do this lookup for TLS 1.3, where the scheme can be determined from
* the SPKI alone because the ECDSA key size determines the hash. Earlier
* TLS versions allow the same EC key to be used with different hashes. */
if (isTls13 && spkiOid == SEC_OID_ANSIX962_EC_PUBLIC_KEY) {
return ssl_SignatureSchemeFromEcSpki(spki, scheme);
}
*scheme = ssl_sig_none;
return SECSuccess;
}
/* Check that a signature scheme is enabled by configuration. */
PRBool
ssl_SignatureSchemeEnabled(const sslSocket *ss, SSLSignatureScheme scheme)
{
unsigned int i;
for (i = 0; i < ss->ssl3.signatureSchemeCount; ++i) {
if (scheme == ss->ssl3.signatureSchemes[i]) {
return PR_TRUE;
}
}
return PR_FALSE;
}
static PRBool
ssl_SignatureKeyMatchesSpkiOid(const ssl3KEADef *keaDef, SECOidTag spkiOid)
{
switch (spkiOid) {
case SEC_OID_X500_RSA_ENCRYPTION:
case SEC_OID_PKCS1_RSA_ENCRYPTION:
case SEC_OID_PKCS1_RSA_PSS_SIGNATURE:
return keaDef->signKeyType == rsaKey;
case SEC_OID_ANSIX9_DSA_SIGNATURE:
return keaDef->signKeyType == dsaKey;
case SEC_OID_ANSIX962_EC_PUBLIC_KEY:
return keaDef->signKeyType == ecKey;
default:
break;
}
return PR_FALSE;
}
/* ssl3_CheckSignatureSchemeConsistency checks that the signature algorithm
* identifier in |scheme| is consistent with the public key in |spki|. It also
* checks the hash algorithm against the configured signature algorithms. If
* all the tests pass, SECSuccess is returned. Otherwise, PORT_SetError is
* called and SECFailure is returned. */
SECStatus
ssl_CheckSignatureSchemeConsistency(sslSocket *ss, SSLSignatureScheme scheme,
CERTSubjectPublicKeyInfo *spki)
{
SSLSignatureScheme spkiScheme;
PRBool isTLS13 = ss->version == SSL_LIBRARY_VERSION_TLS_1_3;
SECOidTag spkiOid;
SECStatus rv;
rv = ssl_SignatureSchemeFromSpki(spki, isTLS13, &spkiScheme);
if (rv != SECSuccess) {
return SECFailure;
}
if (spkiScheme != ssl_sig_none) {
/* The SPKI in the certificate can only be used for a single scheme. */
if (spkiScheme != scheme ||
!ssl_SignatureSchemeEnabled(ss, scheme)) {
PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
return SECFailure;
}
return SECSuccess;
}
spkiOid = SECOID_GetAlgorithmTag(&spki->algorithm);
/* If we're a client, check that the signature algorithm matches the signing
* key type of the cipher suite. */
if (!isTLS13 && !ss->sec.isServer) {
if (!ssl_SignatureKeyMatchesSpkiOid(ss->ssl3.hs.kea_def, spkiOid)) {
PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
return SECFailure;
}
}
/* Verify that the signature scheme matches the signing key. */
if ((spkiOid == SEC_OID_UNKNOWN) ||
!ssl_SignatureSchemeValid(scheme, spkiOid, isTLS13)) {
PORT_SetError(SSL_ERROR_INCORRECT_SIGNATURE_ALGORITHM);
return SECFailure;
}
if (!ssl_SignatureSchemeEnabled(ss, scheme)) {
PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
return SECFailure;
}
return SECSuccess;
}
PRBool
ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme)
{
switch (scheme) {
case ssl_sig_rsa_pkcs1_sha1:
case ssl_sig_rsa_pkcs1_sha256:
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_rsa_pkcs1_sha512:
case ssl_sig_rsa_pss_rsae_sha256:
case ssl_sig_rsa_pss_rsae_sha384:
case ssl_sig_rsa_pss_rsae_sha512:
case ssl_sig_rsa_pss_pss_sha256:
case ssl_sig_rsa_pss_pss_sha384:
case ssl_sig_rsa_pss_pss_sha512:
case ssl_sig_ecdsa_secp256r1_sha256:
case ssl_sig_ecdsa_secp384r1_sha384:
case ssl_sig_ecdsa_secp521r1_sha512:
case ssl_sig_dsa_sha1:
case ssl_sig_dsa_sha256:
case ssl_sig_dsa_sha384:
case ssl_sig_dsa_sha512:
case ssl_sig_ecdsa_sha1:
return ssl_SchemePolicyOK(scheme, kSSLSigSchemePolicy);
break;
case ssl_sig_rsa_pkcs1_sha1md5:
case ssl_sig_none:
case ssl_sig_ed25519:
case ssl_sig_ed448:
return PR_FALSE;
}
return PR_FALSE;
}
PRBool
ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme)
{
switch (scheme) {
case ssl_sig_rsa_pss_rsae_sha256:
case ssl_sig_rsa_pss_rsae_sha384:
case ssl_sig_rsa_pss_rsae_sha512:
case ssl_sig_rsa_pss_pss_sha256:
case ssl_sig_rsa_pss_pss_sha384:
case ssl_sig_rsa_pss_pss_sha512:
return PR_TRUE;
default:
return PR_FALSE;
}
return PR_FALSE;
}
PRBool
ssl_IsRsaeSignatureScheme(SSLSignatureScheme scheme)
{
switch (scheme) {
case ssl_sig_rsa_pss_rsae_sha256:
case ssl_sig_rsa_pss_rsae_sha384:
case ssl_sig_rsa_pss_rsae_sha512:
return PR_TRUE;
default:
return PR_FALSE;
}
return PR_FALSE;
}
PRBool
ssl_IsRsaPkcs1SignatureScheme(SSLSignatureScheme scheme)
{
switch (scheme) {
case ssl_sig_rsa_pkcs1_sha256:
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_rsa_pkcs1_sha512:
case ssl_sig_rsa_pkcs1_sha1:
return PR_TRUE;
default:
return PR_FALSE;
}
return PR_FALSE;
}
PRBool
ssl_IsDsaSignatureScheme(SSLSignatureScheme scheme)
{
switch (scheme) {
case ssl_sig_dsa_sha256:
case ssl_sig_dsa_sha384:
case ssl_sig_dsa_sha512:
case ssl_sig_dsa_sha1:
return PR_TRUE;
default:
return PR_FALSE;
}
return PR_FALSE;
}
SSLAuthType
ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme)
{
switch (scheme) {
case ssl_sig_rsa_pkcs1_sha1:
case ssl_sig_rsa_pkcs1_sha1md5:
case ssl_sig_rsa_pkcs1_sha256:
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_rsa_pkcs1_sha512:
/* We report based on the key type for PSS signatures. */
case ssl_sig_rsa_pss_rsae_sha256:
case ssl_sig_rsa_pss_rsae_sha384:
case ssl_sig_rsa_pss_rsae_sha512:
return ssl_auth_rsa_sign;
case ssl_sig_rsa_pss_pss_sha256:
case ssl_sig_rsa_pss_pss_sha384:
case ssl_sig_rsa_pss_pss_sha512:
return ssl_auth_rsa_pss;
case ssl_sig_ecdsa_secp256r1_sha256:
case ssl_sig_ecdsa_secp384r1_sha384:
case ssl_sig_ecdsa_secp521r1_sha512:
case ssl_sig_ecdsa_sha1:
return ssl_auth_ecdsa;
case ssl_sig_dsa_sha1:
case ssl_sig_dsa_sha256:
case ssl_sig_dsa_sha384:
case ssl_sig_dsa_sha512:
return ssl_auth_dsa;
default:
PORT_Assert(0);
}
return ssl_auth_null;
}
/* ssl_ConsumeSignatureScheme reads a SSLSignatureScheme (formerly
* SignatureAndHashAlgorithm) structure from |b| and puts the resulting value
* into |out|. |b| and |length| are updated accordingly.
*
SECStatus
ssl_ConsumeSignatureScheme(sslSocket *ss, PRUint8 **b,
PRUint32 *length, SSLSignatureScheme *out)
{
PRUint32 tmp;
SECStatus rv;
rv = ssl3_ConsumeHandshakeNumber(ss, &tmp, 2, b, length);
if (rv != SECSuccess) {
return SECFailure; /* Alert sent, Error code set already. */
}
if (!ssl_IsSupportedSignatureScheme((SSLSignatureScheme)tmp)) {
SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
return SECFailure;
}
*out = (SSLSignatureScheme)tmp;
return SECSuccess;
}
/**************************************************************************
* end of Consume Handshake functions.
**************************************************************************/
static SECStatus
ssl3_ComputeHandshakeHash(unsigned char *buf, unsigned int len,
SSLHashType hashAlg, SSL3Hashes *hashes)
{
SECStatus rv = SECFailure;
PK11Context *hashContext = PK11_CreateDigestContext(
ssl3_HashTypeToOID(hashAlg));
if (!hashContext) {
return rv;
}
rv = PK11_DigestBegin(hashContext);
if (rv == SECSuccess) {
rv = PK11_DigestOp(hashContext, buf, len);
}
if (rv == SECSuccess) {
rv = PK11_DigestFinal(hashContext, hashes->u.raw, &hashes->len,
sizeof(hashes->u.raw));
}
if (rv == SECSuccess) {
hashes->hashAlg = hashAlg;
}
PK11_DestroyContext(hashContext, PR_TRUE);
return rv;
}
/* Extract the hashes of handshake messages to this point.
* Called from ssl3_SendCertificateVerify
* ssl3_SendFinished
* ssl3_HandleHandshakeMessage
*
* Caller must hold the SSL3HandshakeLock.
* Caller must hold a read or write lock on the Spec R/W lock.
* (There is presently no way to assert on a Read lock.)
*/
SECStatus
ssl3_ComputeHandshakeHashes(sslSocket *ss,
ssl3CipherSpec *spec, /* uses ->master_secret */
SSL3Hashes *hashes, /* output goes here. */
PRUint32 sender)
{
SECStatus rv = SECSuccess;
PRBool isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0);
unsigned int outLength;
PRUint8 md5_inner[MAX_MAC_LENGTH];
PRUint8 sha_inner[MAX_MAC_LENGTH];
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
if (ss->ssl3.hs.hashType == handshake_hash_unknown) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
hashes->hashAlg = ssl_hash_none;
if (ss->ssl3.hs.hashType == handshake_hash_single) {
PK11Context *h;
unsigned int stateLen;
unsigned char stackBuf[1024];
unsigned char *stateBuf = NULL;
h = ss->ssl3.hs.sha;
stateBuf = PK11_SaveContextAlloc(h, stackBuf,
sizeof(stackBuf), &stateLen);
if (stateBuf == NULL) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
rv = SECFailure;
goto tls12_loser;
}
rv |= PK11_DigestFinal(h, hashes->u.raw, &hashes->len,
sizeof(hashes->u.raw));
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
rv = SECFailure;
goto tls12_loser;
}
hashes->hashAlg = ssl3_GetSuitePrfHash(ss);
tls12_loser:
if (stateBuf) {
if (PK11_RestoreContext(h, stateBuf, stateLen) != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
rv = SECFailure;
}
if (stateBuf != stackBuf) {
PORT_ZFree(stateBuf, stateLen);
}
}
} else if (ss->ssl3.hs.hashType == handshake_hash_record) {
rv = ssl3_ComputeHandshakeHash(ss->ssl3.hs.messages.buf,
ss->ssl3.hs.messages.len,
ssl3_GetSuitePrfHash(ss),
hashes);
} else {
PK11Context *md5;
PK11Context *sha = NULL;
unsigned char *md5StateBuf = NULL;
unsigned char *shaStateBuf = NULL;
unsigned int md5StateLen, shaStateLen;
unsigned char md5StackBuf[256];
unsigned char shaStackBuf[512];
const int md5Pad = ssl_GetMacDefByAlg(ssl_mac_md5)->pad_size;
const int shaPad = ssl_GetMacDefByAlg(ssl_mac_sha)->pad_size;
md5StateBuf = PK11_SaveContextAlloc(ss->ssl3.hs.md5, md5StackBuf,
sizeof md5StackBuf, &md5StateLen);
if (md5StateBuf == NULL) {
ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
rv = SECFailure;
goto loser;
}
md5 = ss->ssl3.hs.md5;
shaStateBuf = PK11_SaveContextAlloc(ss->ssl3.hs.sha, shaStackBuf,
sizeof shaStackBuf, &shaStateLen);
if (shaStateBuf == NULL) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
rv = SECFailure;
goto loser;
}
sha = ss->ssl3.hs.sha;
if (!isTLS) {
/* compute hashes for SSL3. */
unsigned char s[4];
if (!spec->masterSecret) {
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE);
rv = SECFailure;
goto loser;
}
s[0] = (unsigned char)(sender >> 24);
s[1] = (unsigned char)(sender >> 16);
s[2] = (unsigned char)(sender >> 8);
s[3] = (unsigned char)sender;
if (sender != 0) {
rv |= PK11_DigestOp(md5, s, 4);
PRINT_BUF(95, (NULL, "MD5 inner: sender", s, 4));
}
PRINT_BUF(95, (NULL, "MD5 inner: MAC Pad 1", mac_pad_1, md5Pad));
rv |= PK11_DigestKey(md5, spec->masterSecret);
rv |= PK11_DigestOp(md5, mac_pad_1, md5Pad);
rv |= PK11_DigestFinal(md5, md5_inner, &outLength, MD5_LENGTH);
PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
rv = SECFailure;
goto loser;
}
PRINT_BUF(95, (NULL, "MD5 inner: result", md5_inner, outLength));
if (sender != 0) {
rv |= PK11_DigestOp(sha, s, 4);
PRINT_BUF(95, (NULL, "SHA inner: sender", s, 4));
}
PRINT_BUF(95, (NULL, "SHA inner: MAC Pad 1", mac_pad_1, shaPad));
rv |= PK11_DigestKey(sha, spec->masterSecret);
rv |= PK11_DigestOp(sha, mac_pad_1, shaPad);
rv |= PK11_DigestFinal(sha, sha_inner, &outLength, SHA1_LENGTH);
PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
rv = SECFailure;
goto loser;
}
PRINT_BUF(95, (NULL, "SHA inner: result", sha_inner, outLength));
PRINT_BUF(95, (NULL, "MD5 outer: MAC Pad 2", mac_pad_2, md5Pad));
PRINT_BUF(95, (NULL, "MD5 outer: MD5 inner", md5_inner, MD5_LENGTH));
rv |= PK11_DigestBegin(md5);
rv |= PK11_DigestKey(md5, spec->masterSecret);
rv |= PK11_DigestOp(md5, mac_pad_2, md5Pad);
rv |= PK11_DigestOp(md5, md5_inner, MD5_LENGTH);
}
rv |= PK11_DigestFinal(md5, hashes->u.s.md5, &outLength, MD5_LENGTH);
PORT_Assert(rv != SECSuccess || outLength == MD5_LENGTH);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
rv = SECFailure;
goto loser;
}
PRINT_BUF(60, (NULL, "MD5 outer: result", hashes->u.s.md5, MD5_LENGTH));
if (!isTLS) {
PRINT_BUF(95, (NULL, "SHA outer: MAC Pad 2", mac_pad_2, shaPad));
PRINT_BUF(95, (NULL, "SHA outer: SHA inner", sha_inner, SHA1_LENGTH));
rv |= PK11_DigestBegin(sha);
rv |= PK11_DigestKey(sha, spec->masterSecret);
rv |= PK11_DigestOp(sha, mac_pad_2, shaPad);
rv |= PK11_DigestOp(sha, sha_inner, SHA1_LENGTH);
}
rv |= PK11_DigestFinal(sha, hashes->u.s.sha, &outLength, SHA1_LENGTH);
PORT_Assert(rv != SECSuccess || outLength == SHA1_LENGTH);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
rv = SECFailure;
goto loser;
}
PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH));
hashes->len = MD5_LENGTH + SHA1_LENGTH;
loser:
if (md5StateBuf) {
if (PK11_RestoreContext(ss->ssl3.hs.md5, md5StateBuf, md5StateLen) !=
SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
rv = SECFailure;
}
if (md5StateBuf != md5StackBuf) {
PORT_ZFree(md5StateBuf, md5StateLen);
}
}
if (shaStateBuf) {
if (PK11_RestoreContext(ss->ssl3.hs.sha, shaStateBuf, shaStateLen) !=
SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
rv = SECFailure;
}
if (shaStateBuf != shaStackBuf) {
PORT_ZFree(shaStateBuf, shaStateLen);
}
}
}
return rv;
}
/**************************************************************************
* end of Handshake Hash functions.
* Begin Send and Handle functions for handshakes.
**************************************************************************/
#ifdef TRACE
#define CHTYPE(t) \
case client_hello_##t: \
return #t;
static const char *
ssl_ClientHelloTypeName(sslClientHelloType type)
{
switch (type) {
CHTYPE(initial);
CHTYPE(retry);
CHTYPE(retransmit); /* DTLS only */
CHTYPE(renegotiation); /* TLS <= 1.2 only */
}
PORT_Assert(0);
return NULL;
}
#undef CHTYPE
#endif
PR_STATIC_ASSERT(SSL3_SESSIONID_BYTES == SSL3_RANDOM_LENGTH);
static void
ssl_MakeFakeSid(sslSocket *ss, PRUint8 *buf)
{
PRUint8 x = 0x5a;
int i;
for (i = 0; i < SSL3_SESSIONID_BYTES; ++i) {
x += ss->ssl3.hs.client_random[i];
buf[i] = x;
}
}
/* Set the version fields of the cipher spec for a ClientHello. */
static void
ssl_SetClientHelloSpecVersion(sslSocket *ss, ssl3CipherSpec *spec)
{
ssl_GetSpecWriteLock(ss);
PORT_Assert(spec->cipherDef->cipher == cipher_null);
/* This is - a best guess - but it doesn't matter here. */
spec->version = ss->vrange.max;
if (IS_DTLS(ss)) {
spec->recordVersion = SSL_LIBRARY_VERSION_DTLS_1_0_WIRE;
} else {
/* For new connections, cap the record layer version number of TLS
* ClientHello to { 3, 1 } (TLS 1.0). Some TLS 1.0 servers (which seem
* to use F5 BIG-IP) ignore ClientHello.client_version and use the
* record layer version number (TLSPlaintext.version) instead when
* negotiating protocol versions. In addition, if the record layer
* version number of ClientHello is { 3, 2 } (TLS 1.1) or higher, these
* servers reset the TCP connections. Lastly, some F5 BIG-IP servers
* hang if a record containing a ClientHello has a version greater than
* { 3, 1 } and a length greater than 255. Set this flag to work around
* such servers.
*
* The final version is set when a version is negotiated.
*/
spec->recordVersion = PR_MIN(SSL_LIBRARY_VERSION_TLS_1_0,
ss->vrange.max);
}
ssl_ReleaseSpecWriteLock(ss);
}
SECStatus
ssl3_InsertChHeaderSize(const sslSocket *ss, sslBuffer *preamble, const sslBuffer *extensions)
{
SECStatus rv;
unsigned int msgLen = preamble->len;
msgLen += extensions->len ? (2 + extensions->len) : 0;
unsigned int headerLen = IS_DTLS(ss) ? 12 : 4;
/* Record the message length. */
rv = sslBuffer_InsertNumber(preamble, 1, msgLen - headerLen, 3);
if (rv != SECSuccess) {
return SECFailure; /* code set */
}
if (IS_DTLS(ss)) {
/* Record the (unfragmented) fragment length. */
unsigned int offset = 1 /* ch */ + 3 /* len */ +
2 /* seq */ + 3 /* fragment offset */;
rv = sslBuffer_InsertNumber(preamble, offset, msgLen - headerLen, 3);
if (rv != SECSuccess) {
return SECFailure; /* code set */
}
}
return SECSuccess;
}
static SECStatus
ssl3_AppendCipherSuites(sslSocket *ss, PRBool fallbackSCSV, sslBuffer *buf)
{
SECStatus rv;
unsigned int offset;
unsigned int i;
unsigned int saveLen;
rv = sslBuffer_Skip(buf, 2, &offset);
if (rv != SECSuccess) {
return SECFailure;
}
if (ss->ssl3.hs.sendingSCSV) {
/* Add the actual SCSV */
rv = sslBuffer_AppendNumber(buf, TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
sizeof(ssl3CipherSuite));
if (rv != SECSuccess) {
return SECFailure;
}
}
if (fallbackSCSV) {
rv = sslBuffer_AppendNumber(buf, TLS_FALLBACK_SCSV,
sizeof(ssl3CipherSuite));
if (rv != SECSuccess) {
return SECFailure;
}
}
saveLen = SSL_BUFFER_LEN(buf);
/* CipherSuites are appended to Hello message here */
for (i = 0; i < ssl_V3_SUITES_IMPLEMENTED; i++) {
ssl3CipherSuiteCfg *suite = &ss->cipherSuites[i];
if (ssl3_config_match(suite, ss->ssl3.policy, &ss->vrange, ss)) {
rv = sslBuffer_AppendNumber(buf, suite->cipher_suite,
sizeof(ssl3CipherSuite));
if (rv != SECSuccess) {
return SECFailure;
}
}
}
/* GREASE CipherSuites:
* A client MAY select one or more GREASE cipher suite values and advertise
* them in the "cipher_suites" field [RFC8701, Section 3.1]. */
if (ss->opt.enableGrease && ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) {
rv = sslBuffer_AppendNumber(buf, ss->ssl3.hs.grease->idx[grease_cipher],
sizeof(ssl3CipherSuite));
if (rv != SECSuccess) {
return SECFailure;
}
}
if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange) ||
(SSL_BUFFER_LEN(buf) - saveLen) == 0) {
PORT_SetError(SSL_ERROR_SSL_DISABLED);
return SECFailure;
}
return sslBuffer_InsertLength(buf, offset, 2);
}
SECStatus
ssl3_CreateClientHelloPreamble(sslSocket *ss, const sslSessionID *sid,
PRBool realSid, PRUint16 version, PRBool isEchInner,
const sslBuffer *extensions, sslBuffer *preamble)
{
SECStatus rv;
sslBuffer constructed = SSL_BUFFER_EMPTY;
const PRUint8 *client_random = isEchInner ? ss->ssl3.hs.client_inner_random : ss->ssl3.hs.client_random;
PORT_Assert(sid);
PRBool fallbackSCSV = ss->opt.enableFallbackSCSV && !isEchInner &&
(!realSid || version < sid->version);
rv = sslBuffer_AppendNumber(&constructed, ssl_hs_client_hello, 1);
if (rv != SECSuccess) {
goto loser;
}
rv = sslBuffer_Skip(&constructed, 3, NULL);
if (rv != SECSuccess) {
goto loser;
}
if (IS_DTLS(ss)) {
/* Note that we make an unfragmented message here. We fragment in the
* transmission code, if necessary */
rv = sslBuffer_AppendNumber(&constructed, ss->ssl3.hs.sendMessageSeq, 2);
if (rv != SECSuccess) {
goto loser;
}
ss->ssl3.hs.sendMessageSeq++;
/* 0 is the fragment offset, because it's not fragmented yet */
rv = sslBuffer_AppendNumber(&constructed, 0, 3);
if (rv != SECSuccess) {
goto loser;
}
/* Fragment length -- set to the packet length because not fragmented */
rv = sslBuffer_Skip(&constructed, 3, NULL);
if (rv != SECSuccess) {
goto loser;
}
}
if (ss->firstHsDone) {
/* The client hello version must stay unchanged to work around
* the Windows SChannel bug described in ssl3_SendClientHello. */
PORT_Assert(version == ss->clientHelloVersion);
}
ss->clientHelloVersion = PR_MIN(version, SSL_LIBRARY_VERSION_TLS_1_2);
if (IS_DTLS(ss)) {
PRUint16 dtlsVersion = dtls_TLSVersionToDTLSVersion(ss->clientHelloVersion);
rv = sslBuffer_AppendNumber(&constructed, dtlsVersion, 2);
} else {
rv = sslBuffer_AppendNumber(&constructed, ss->clientHelloVersion, 2);
}
if (rv != SECSuccess) {
goto loser;
}
rv = sslBuffer_Append(&constructed, client_random, SSL3_RANDOM_LENGTH);
if (rv != SECSuccess) {
goto loser;
}
if (sid->version < SSL_LIBRARY_VERSION_TLS_1_3 && !isEchInner) {
rv = sslBuffer_AppendVariable(&constructed, sid->u.ssl3.sessionID,
sid->u.ssl3.sessionIDLength, 1);
} else if (ss->opt.enableTls13CompatMode && !IS_DTLS(ss)) {
/* We're faking session resumption, so rather than create new
* randomness, just mix up the client random a little. */
PRUint8 buf[SSL3_SESSIONID_BYTES];
ssl_MakeFakeSid(ss, buf);
rv = sslBuffer_AppendVariable(&constructed, buf, SSL3_SESSIONID_BYTES, 1);
} else {
rv = sslBuffer_AppendNumber(&constructed, 0, 1);
}
if (rv != SECSuccess) {
goto loser;
}
if (IS_DTLS(ss)) {
/* This cookieLen applies to the cookie that appears in the DTLS
* ClientHello, which isn't used in DTLS 1.3. */
rv = sslBuffer_AppendVariable(&constructed, ss->ssl3.hs.cookie.data,
ss->ssl3.hs.helloRetry ? 0 : ss->ssl3.hs.cookie.len,
1);
if (rv != SECSuccess) {
goto loser;
}
}
rv = ssl3_AppendCipherSuites(ss, fallbackSCSV, &constructed);
if (rv != SECSuccess) {
goto loser;
}
/* Compression methods: count is always 1, null compression. */
rv = sslBuffer_AppendNumber(&constructed, 1, 1);
if (rv != SECSuccess) {
goto loser;
}
rv = sslBuffer_AppendNumber(&constructed, ssl_compression_null, 1);
if (rv != SECSuccess) {
goto loser;
}
rv = ssl3_InsertChHeaderSize(ss, &constructed, extensions);
if (rv != SECSuccess) {
goto loser;
}
*preamble = constructed;
return SECSuccess;
loser:
sslBuffer_Clear(&constructed);
return SECFailure;
}
/* Called from ssl3_HandleHelloRequest(),
* ssl3_RedoHandshake()
* ssl_BeginClientHandshake (when resuming ssl3 session)
* dtls_HandleHelloVerifyRequest(with resending=PR_TRUE)
*
* The |type| argument indicates what is going on here:
* - client_hello_initial is set for the very first ClientHello
* - client_hello_retry indicates that this is a second attempt after receiving
* a HelloRetryRequest (in TLS 1.3)
* - client_hello_retransmit is used in DTLS when resending
* - client_hello_renegotiation is used to renegotiate (in TLS <1.3)
*/
SECStatus
ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
{
sslSessionID *sid;
SECStatus rv;
PRBool isTLS = PR_FALSE;
PRBool requestingResume = PR_FALSE;
PRBool unlockNeeded = PR_FALSE;
sslBuffer extensionBuf = SSL_BUFFER_EMPTY;
PRUint16 version = ss->vrange.max;
PRInt32 flags;
sslBuffer chBuf = SSL_BUFFER_EMPTY;
SSL_TRC(3, ("%d: SSL3[%d]: send %s ClientHello handshake", SSL_GETPID(),
ss->fd, ssl_ClientHelloTypeName(type)));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
/* shouldn't get here if SSL3 is disabled, but ... */
if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) {
PR_NOT_REACHED("No versions of SSL 3.0 or later are enabled");
PORT_SetError(SSL_ERROR_SSL_DISABLED);
return SECFailure;
}
/* If we are responding to a HelloRetryRequest, don't reinitialize. We need
* to maintain the handshake hashes. */
if (!ss->ssl3.hs.helloRetry) {
ssl3_RestartHandshakeHashes(ss);
}
PORT_Assert(!ss->ssl3.hs.helloRetry || type == client_hello_retry);
if (type == client_hello_initial) {
ssl_SetClientHelloSpecVersion(ss, ss->ssl3.cwSpec);
}
/* These must be reset every handshake. */
ssl3_ResetExtensionData(&ss->xtnData, ss);
ss->ssl3.hs.sendingSCSV = PR_FALSE;
ss->ssl3.hs.preliminaryInfo = 0;
PORT_Assert(IS_DTLS(ss) || type != client_hello_retransmit);
SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE);
ss->ssl3.hs.receivedNewSessionTicket = PR_FALSE;
/* How many suites does our PKCS11 support (regardless of policy)? */
if (ssl3_config_match_init(ss) == 0) {
return SECFailure; /* ssl3_config_match_init has set error code. */
}
/*
* During a renegotiation, ss->clientHelloVersion will be used again to
* work around a Windows SChannel bug. Ensure that it is still enabled.
*/
if (ss->firstHsDone) {
PORT_Assert(type != client_hello_initial);
if (SSL_ALL_VERSIONS_DISABLED(&ss->vrange)) {
PORT_SetError(SSL_ERROR_SSL_DISABLED);
return SECFailure;
}
if (ss->clientHelloVersion < ss->vrange.min ||
ss->clientHelloVersion > ss->vrange.max) {
PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP);
return SECFailure;
}
}
/* Check if we have a ss->sec.ci.sid.
* Check that it's not expired.
* If we have an sid and it comes from an external cache, we use it. */
if (ss->sec.ci.sid && ss->sec.ci.sid->cached == in_external_cache) {
PORT_Assert(!ss->sec.isServer);
sid = ssl_ReferenceSID(ss->sec.ci.sid);
SSL_TRC(3, ("%d: SSL3[%d]: using external resumption token in ClientHello",
SSL_GETPID(), ss->fd));
} else if (ss->sec.ci.sid && ss->statelessResume && type == client_hello_retry) {
/* If we are sending a second ClientHello, reuse the same SID
* as the original one. */
sid = ssl_ReferenceSID(ss->sec.ci.sid);
} else if (!ss->opt.noCache) {
/* We ignore ss->sec.ci.sid here, and use ssl_Lookup because Lookup
* handles expired entries and other details.
* XXX If we've been called from ssl_BeginClientHandshake, then
* this lookup is duplicative and wasteful.
*/
sid = ssl_LookupSID(ssl_Time(ss), &ss->sec.ci.peer,
ss->sec.ci.port, ss->peerID, ss->url);
} else {
sid = NULL;
}
/* We can't resume based on a different token. If the sid exists,
* make sure the token that holds the master secret still exists ...
* If we previously did client-auth, make sure that the token that holds
* the private key still exists, is logged in, hasn't been removed, etc.
*/
if (sid) {
PRBool sidOK = PR_TRUE;
if (sid->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
if (!tls13_ResumptionCompatible(ss, sid->u.ssl3.cipherSuite)) {
sidOK = PR_FALSE;
}
} else {
/* Check that the cipher suite we need is enabled. */
const ssl3CipherSuiteCfg *suite =
ssl_LookupCipherSuiteCfg(sid->u.ssl3.cipherSuite,
ss->cipherSuites);
SSLVersionRange vrange = { sid->version, sid->version };
if (!suite || !ssl3_config_match(suite, ss->ssl3.policy, &vrange, ss)) {
sidOK = PR_FALSE;
}
/* Check that no (valid) ECHConfigs are setup in combination with a
* (resumable) TLS < 1.3 session id. */
if (!PR_CLIST_IS_EMPTY(&ss->echConfigs)) {
/* If there are ECH configs, the client must not resume but
* offer ECH. */
sidOK = PR_FALSE;
}
}
/* Check that we can recover the master secret. */
if (sidOK) {
PK11SlotInfo *slot = NULL;
if (sid->u.ssl3.masterValid) {
slot = SECMOD_LookupSlot(sid->u.ssl3.masterModuleID,
sid->u.ssl3.masterSlotID);
}
if (slot == NULL) {
sidOK = PR_FALSE;
} else {
PK11SymKey *wrapKey = NULL;
if (!PK11_IsPresent(slot) ||
((wrapKey = PK11_GetWrapKey(slot,
sid->u.ssl3.masterWrapIndex,
sid->u.ssl3.masterWrapMech,
sid->u.ssl3.masterWrapSeries,
ss->pkcs11PinArg)) == NULL)) {
sidOK = PR_FALSE;
}
if (wrapKey)
PK11_FreeSymKey(wrapKey);
PK11_FreeSlot(slot);
slot = NULL;
}
}
/* If we previously did client-auth, make sure that the token that
** holds the private key still exists, is logged in, hasn't been
** removed, etc.
*/
if (sidOK && !ssl3_ClientAuthTokenPresent(sid)) {
sidOK = PR_FALSE;
}
if (sidOK) {
/* Set version based on the sid. */
if (ss->firstHsDone) {
/*
* Windows SChannel compares the client_version inside the RSA
* EncryptedPreMasterSecret of a renegotiation with the
* client_version of the initial ClientHello rather than the
* ClientHello in the renegotiation. To work around this bug, we
* continue to use the client_version used in the initial
* ClientHello when renegotiating.
*
* The client_version of the initial ClientHello is still
* available in ss->clientHelloVersion. Ensure that
* sid->version is bounded within
* [ss->vrange.min, ss->clientHelloVersion], otherwise we
* can't use sid.
*/
if (sid->version >= ss->vrange.min &&
sid->version <= ss->clientHelloVersion) {
version = ss->clientHelloVersion;
} else {
sidOK = PR_FALSE;
}
} else {
/*
* Check sid->version is OK first.
* Previously, we would cap the version based on sid->version,
* but that prevents negotiation of a higher version if the
* previous session was reduced (e.g., with version fallback)
*/
if (sid->version < ss->vrange.min ||
sid->version > ss->vrange.max) {
sidOK = PR_FALSE;
}
}
}
if (!sidOK) {
SSL_AtomicIncrementLong(&ssl3stats.sch_sid_cache_not_ok);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
}
if (sid) {
requestingResume = PR_TRUE;
SSL_AtomicIncrementLong(&ssl3stats.sch_sid_cache_hits);
PRINT_BUF(4, (ss, "client, found session-id:", sid->u.ssl3.sessionID,
sid->u.ssl3.sessionIDLength));
ss->ssl3.policy = sid->u.ssl3.policy;
} else {
SSL_AtomicIncrementLong(&ssl3stats.sch_sid_cache_misses);
/*
* Windows SChannel compares the client_version inside the RSA
* EncryptedPreMasterSecret of a renegotiation with the
* client_version of the initial ClientHello rather than the
* ClientHello in the renegotiation. To work around this bug, we
* continue to use the client_version used in the initial
* ClientHello when renegotiating.
*/
if (ss->firstHsDone) {
version = ss->clientHelloVersion;
}
sid = ssl3_NewSessionID(ss, PR_FALSE);
if (!sid) {
return SECFailure; /* memory error is set */
}
/* ss->version isn't set yet, but the sid needs a sane value. */
sid->version = version;
}
isTLS = (version > SSL_LIBRARY_VERSION_3_0);
ssl_GetSpecWriteLock(ss);
if (ss->ssl3.cwSpec->macDef->mac == ssl_mac_null) {
/* SSL records are not being MACed. */
ss->ssl3.cwSpec->version = version;
}
ssl_ReleaseSpecWriteLock(ss);
ssl_FreeSID(ss->sec.ci.sid); /* release the old sid */
ss->sec.ci.sid = sid;
/* HACK for SCSV in SSL 3.0. On initial handshake, prepend SCSV,
* only if TLS is disabled.
*/
if (!ss->firstHsDone && !isTLS) {
/* Must set this before calling Hello Extension Senders,
* to suppress sending of empty RI extension.
*/
ss->ssl3.hs.sendingSCSV = PR_TRUE;
}
/* When we attempt session resumption (only), we must lock the sid to
* prevent races with other resumption connections that receive a
* NewSessionTicket that will cause the ticket in the sid to be replaced.
* Once we've copied the session ticket into our ClientHello message, it
* is OK for the ticket to change, so we just need to make sure we hold
* the lock across the calls to ssl_ConstructExtensions.
*/
if (sid->u.ssl3.lock) {
unlockNeeded = PR_TRUE;
PR_RWLock_Rlock(sid->u.ssl3.lock);
}
/* Generate a new random if this is the first attempt or renegotiation. */
if (type == client_hello_initial ||
type == client_hello_renegotiation) {
rv = ssl3_GetNewRandom(ss->ssl3.hs.client_random);
if (rv != SECSuccess) {
goto loser; /* err set by GetNewRandom. */
}
}
if (ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) {
rv = tls13_SetupClientHello(ss, type);
if (rv != SECSuccess) {
goto loser;
}
}
/* Setup TLS ClientHello Extension Permutation? */
if (type == client_hello_initial &&
ss->vrange.max > SSL_LIBRARY_VERSION_3_0 &&
ss->opt.enableChXtnPermutation) {
rv = tls_ClientHelloExtensionPermutationSetup(ss);
if (rv != SECSuccess) {
goto loser;
}
}
if (isTLS || (ss->firstHsDone && ss->peerRequestedProtection)) {
rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_client_hello);
if (rv != SECSuccess) {
goto loser;
}
}
if (IS_DTLS(ss)) {
ssl3_DisableNonDTLSSuites(ss);
}
rv = ssl3_CreateClientHelloPreamble(ss, sid, requestingResume, version,
PR_FALSE, &extensionBuf, &chBuf);
if (rv != SECSuccess) {
goto loser; /* err set by ssl3_CreateClientHelloPreamble. */
}
if (!ss->ssl3.hs.echHpkeCtx) {
if (extensionBuf.len) {
rv = tls13_MaybeGreaseEch(ss, &chBuf, &extensionBuf);
if (rv != SECSuccess) {
goto loser; /* err set by tls13_MaybeGreaseEch. */
}
rv = ssl_InsertPaddingExtension(ss, chBuf.len, &extensionBuf);
if (rv != SECSuccess) {
goto loser; /* err set by ssl_InsertPaddingExtension. */
}
rv = ssl3_InsertChHeaderSize(ss, &chBuf, &extensionBuf);
if (rv != SECSuccess) {
goto loser; /* err set by ssl3_InsertChHeaderSize. */
}
/* If we are sending a PSK binder, replace the dummy value. */
if (ssl3_ExtensionAdvertised(ss, ssl_tls13_pre_shared_key_xtn)) {
rv = tls13_WriteExtensionsWithBinder(ss, &extensionBuf, &chBuf);
} else {
rv = sslBuffer_AppendNumber(&chBuf, extensionBuf.len, 2);
if (rv != SECSuccess) {
goto loser;
}
rv = sslBuffer_AppendBuffer(&chBuf, &extensionBuf);
}
if (rv != SECSuccess) {
goto loser; /* err set by sslBuffer_Append*. */
}
}
/* If we already have a message in place, we need to enqueue it.
* This empties the buffer. This is a convenient place to call
* dtls_StageHandshakeMessage to mark the message boundary. */
if (IS_DTLS(ss)) {
rv = dtls_StageHandshakeMessage(ss);
if (rv != SECSuccess) {
goto loser;
}
}
/* As here the function takes the full message and hashes it in one go,
* For DTLS1.3, we skip hashing the unnecessary header fields.
* See ssl3_AppendHandshakeHeader. */
if (IS_DTLS(ss) && ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3) {
rv = ssl3_AppendHandshakeSuppressHash(ss, chBuf.buf, chBuf.len);
if (rv != SECSuccess) {
goto loser; /* code set */
}
if (!ss->firstHsDone) {
PORT_Assert(type == client_hello_retransmit ||
ss->ssl3.hs.dtls13ClientMessageBuffer.len == 0);
sslBuffer_Clear(&ss->ssl3.hs.dtls13ClientMessageBuffer);
/* Here instead of computing the hash, we copy the data to a buffer.*/
rv = sslBuffer_Append(&ss->ssl3.hs.dtls13ClientMessageBuffer, chBuf.buf, chBuf.len);
}
} else {
rv = ssl3_AppendHandshake(ss, chBuf.buf, chBuf.len);
}
} else {
PORT_Assert(!IS_DTLS(ss));
rv = tls13_ConstructClientHelloWithEch(ss, sid, !requestingResume, &chBuf, &extensionBuf);
if (rv != SECSuccess) {
goto loser; /* code set */
}
rv = ssl3_UpdateDefaultHandshakeHashes(ss, chBuf.buf, chBuf.len);
if (rv != SECSuccess) {
goto loser; /* code set */
}
if (IS_DTLS(ss)) {
rv = dtls_StageHandshakeMessage(ss);
if (rv != SECSuccess) {
goto loser;
}
}
/* By default, all messagess are added to both the inner and
* outer transcripts. For CH (or CH2 if HRR), that's problematic. */
rv = ssl3_AppendHandshakeSuppressHash(ss, chBuf.buf, chBuf.len);
}
if (rv != SECSuccess) {
goto loser;
}
if (unlockNeeded) {
/* Note: goto loser can't be used past this point. */
PR_RWLock_Unlock(sid->u.ssl3.lock);
}
if (ss->xtnData.sentSessionTicketInClientHello) {
SSL_AtomicIncrementLong(&ssl3stats.sch_sid_stateless_resumes);
}
if (ss->ssl3.hs.sendingSCSV) {
/* Since we sent the SCSV, pretend we sent empty RI extension. */
TLSExtensionData *xtnData = &ss->xtnData;
xtnData->advertised[xtnData->numAdvertised++] =
ssl_renegotiation_info_xtn;
}
flags = 0;
rv = ssl3_FlushHandshake(ss, flags);
if (rv != SECSuccess) {
return rv; /* error code set by ssl3_FlushHandshake */
}
if (version >= SSL_LIBRARY_VERSION_TLS_1_3) {
rv = tls13_MaybeDo0RTTHandshake(ss);
if (rv != SECSuccess) {
return SECFailure; /* error code set already. */
}
}
ss->ssl3.hs.ws = wait_server_hello;
sslBuffer_Clear(&chBuf);
sslBuffer_Clear(&extensionBuf);
return SECSuccess;
loser:
if (unlockNeeded) {
PR_RWLock_Unlock(sid->u.ssl3.lock);
}
sslBuffer_Clear(&chBuf);
sslBuffer_Clear(&extensionBuf);
return SECFailure;
}
/* Called from ssl3_HandlePostHelloHandshakeMessage() when it has deciphered a
* complete ssl3 Hello Request.
* Caller must hold Handshake and RecvBuf locks.
*/
static SECStatus
ssl3_HandleHelloRequest(sslSocket *ss)
{
sslSessionID *sid = ss->sec.ci.sid;
SECStatus rv;
SSL_TRC(3, ("%d: SSL3[%d]: handle hello_request handshake",
SSL_GETPID(), ss->fd));
PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->version < SSL_LIBRARY_VERSION_TLS_1_3);
if (ss->ssl3.hs.ws == wait_server_hello)
return SECSuccess;
if (ss->ssl3.hs.ws != idle_handshake || ss->sec.isServer) {
(void)SSL3_SendAlert(ss, alert_fatal, unexpected_message);
PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST);
return SECFailure;
}
if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) {
(void)SSL3_SendAlert(ss, alert_warning, no_renegotiation);
PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED);
return SECFailure;
}
if (sid) {
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
ss->sec.ci.sid = NULL;
}
if (IS_DTLS(ss)) {
dtls_RehandshakeCleanup(ss);
}
ssl_GetXmitBufLock(ss);
rv = ssl3_SendClientHello(ss, client_hello_renegotiation);
ssl_ReleaseXmitBufLock(ss);
return rv;
}
static const CK_MECHANISM_TYPE wrapMechanismList[SSL_NUM_WRAP_MECHS] = {
CKM_DES3_ECB,
CKM_CAST5_ECB,
CKM_DES_ECB,
CKM_KEY_WRAP_LYNKS,
CKM_IDEA_ECB,
CKM_CAST3_ECB,
CKM_CAST_ECB,
CKM_RC5_ECB,
CKM_RC2_ECB,
CKM_CDMF_ECB,
CKM_SKIPJACK_WRAP,
CKM_SKIPJACK_CBC64,
CKM_AES_ECB,
CKM_CAMELLIA_ECB,
CKM_SEED_ECB
};
static SECStatus
ssl_FindIndexByWrapMechanism(CK_MECHANISM_TYPE mech, unsigned int *wrapMechIndex)
{
unsigned int i;
for (i = 0; i < SSL_NUM_WRAP_MECHS; ++i) {
if (wrapMechanismList[i] == mech) {
*wrapMechIndex = i;
return SECSuccess;
}
}
PORT_Assert(0);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
/* Each process sharing the server session ID cache has its own array of SymKey
* pointers for the symmetric wrapping keys that are used to wrap the master
* secrets. There is one key for each authentication type. These Symkeys
* correspond to the wrapped SymKeys kept in the server session cache.
*/
const SSLAuthType ssl_wrap_key_auth_type[SSL_NUM_WRAP_KEYS] = {
ssl_auth_rsa_decrypt,
ssl_auth_rsa_sign,
ssl_auth_rsa_pss,
ssl_auth_ecdsa,
ssl_auth_ecdh_rsa,
ssl_auth_ecdh_ecdsa
};
static SECStatus
ssl_FindIndexByWrapKey(const sslServerCert *serverCert, unsigned int *wrapKeyIndex)
{
unsigned int i;
for (i = 0; i < SSL_NUM_WRAP_KEYS; ++i) {
if (SSL_CERT_IS(serverCert, ssl_wrap_key_auth_type[i])) {
*wrapKeyIndex = i;
return SECSuccess;
}
}
/* Can't assert here because we still get people using DSA certificates. */
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
static PK11SymKey *
ssl_UnwrapSymWrappingKey(
SSLWrappedSymWrappingKey *pWswk,
SECKEYPrivateKey *svrPrivKey,
unsigned int wrapKeyIndex,
CK_MECHANISM_TYPE masterWrapMech,
void *pwArg)
{
PK11SymKey *unwrappedWrappingKey = NULL;
SECItem wrappedKey;
PK11SymKey *Ks;
SECKEYPublicKey pubWrapKey;
ECCWrappedKeyInfo *ecWrapped;
/* found the wrapping key on disk. */
PORT_Assert(pWswk->symWrapMechanism == masterWrapMech);
PORT_Assert(pWswk->wrapKeyIndex == wrapKeyIndex);
if (pWswk->symWrapMechanism != masterWrapMech ||
pWswk->wrapKeyIndex != wrapKeyIndex) {
goto loser;
}
wrappedKey.type = siBuffer;
wrappedKey.data = pWswk->wrappedSymmetricWrappingkey;
wrappedKey.len = pWswk->wrappedSymKeyLen;
PORT_Assert(wrappedKey.len <= sizeof pWswk->wrappedSymmetricWrappingkey);
switch (ssl_wrap_key_auth_type[wrapKeyIndex]) {
case ssl_auth_rsa_decrypt:
case ssl_auth_rsa_sign: /* bad: see Bug 1248320 */
unwrappedWrappingKey =
PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey,
masterWrapMech, CKA_UNWRAP, 0);
break;
case ssl_auth_ecdsa:
case ssl_auth_ecdh_rsa:
case ssl_auth_ecdh_ecdsa:
/*
* For ssl_auth_ecd*, we first create an EC public key based on
* data stored with the wrappedSymmetricWrappingkey. Next,
* we do an ECDH computation involving this public key and
* the SSL server's (long-term) EC private key. The resulting
* shared secret is treated the same way as Fortezza's Ks, i.e.,
* it is used to recover the symmetric wrapping key.
*
* The data in wrappedSymmetricWrappingkey is laid out as defined
* in the ECCWrappedKeyInfo structure.
*/
ecWrapped = (ECCWrappedKeyInfo *)pWswk->wrappedSymmetricWrappingkey;
PORT_Assert(ecWrapped->encodedParamLen + ecWrapped->pubValueLen +
ecWrapped->wrappedKeyLen <=
MAX_EC_WRAPPED_KEY_BUFLEN);
if (ecWrapped->encodedParamLen + ecWrapped->pubValueLen +
ecWrapped->wrappedKeyLen >
MAX_EC_WRAPPED_KEY_BUFLEN) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
pubWrapKey.keyType = ecKey;
pubWrapKey.u.ec.size = ecWrapped->size;
pubWrapKey.u.ec.DEREncodedParams.len = ecWrapped->encodedParamLen;
pubWrapKey.u.ec.DEREncodedParams.data = ecWrapped->var;
pubWrapKey.u.ec.publicValue.len = ecWrapped->pubValueLen;
pubWrapKey.u.ec.publicValue.data = ecWrapped->var +
ecWrapped->encodedParamLen;
wrappedKey.len = ecWrapped->wrappedKeyLen;
wrappedKey.data = ecWrapped->var + ecWrapped->encodedParamLen +
ecWrapped->pubValueLen;
/* Derive Ks using ECDH */
Ks = PK11_PubDeriveWithKDF(svrPrivKey, &pubWrapKey, PR_FALSE, NULL,
NULL, CKM_ECDH1_DERIVE, masterWrapMech,
CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
if (Ks == NULL) {
goto loser;
}
/* Use Ks to unwrap the wrapping key */
unwrappedWrappingKey = PK11_UnwrapSymKey(Ks, masterWrapMech, NULL,
&wrappedKey, masterWrapMech,
CKA_UNWRAP, 0);
PK11_FreeSymKey(Ks);
break;
default:
PORT_Assert(0);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
goto loser;
}
loser:
return unwrappedWrappingKey;
}
typedef struct {
PK11SymKey *symWrapKey[SSL_NUM_WRAP_KEYS];
} ssl3SymWrapKey;
static PZLock *symWrapKeysLock = NULL;
static ssl3SymWrapKey symWrapKeys[SSL_NUM_WRAP_MECHS];
SECStatus
ssl_FreeSymWrapKeysLock(void)
{
if (symWrapKeysLock) {
PZ_DestroyLock(symWrapKeysLock);
symWrapKeysLock = NULL;
return SECSuccess;
}
PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
return SECFailure;
}
SECStatus
SSL3_ShutdownServerCache(void)
{
int i, j;
if (!symWrapKeysLock)
return SECSuccess; /* lock was never initialized */
PZ_Lock(symWrapKeysLock);
/* get rid of all symWrapKeys */
for (i = 0; i < SSL_NUM_WRAP_MECHS; ++i) {
for (j = 0; j < SSL_NUM_WRAP_KEYS; ++j) {
PK11SymKey **pSymWrapKey;
pSymWrapKey = &symWrapKeys[i].symWrapKey[j];
if (*pSymWrapKey) {
PK11_FreeSymKey(*pSymWrapKey);
*pSymWrapKey = NULL;
}
}
}
PZ_Unlock(symWrapKeysLock);
ssl_FreeSessionCacheLocks();
return SECSuccess;
}
SECStatus
ssl_InitSymWrapKeysLock(void)
{
symWrapKeysLock = PZ_NewLock(nssILockOther);
return symWrapKeysLock ? SECSuccess : SECFailure;
}
/* Try to get wrapping key for mechanism from in-memory array.
* If that fails, look for one on disk.
* If that fails, generate a new one, put the new one on disk,
* Put the new key in the in-memory array.
*
* Note that this function performs some fairly inadvisable functions with
* certificate private keys. ECDSA keys are used with ECDH; similarly, RSA
* signing keys are used to encrypt. Bug 1248320.
*/
PK11SymKey *
ssl3_GetWrappingKey(sslSocket *ss,
PK11SlotInfo *masterSecretSlot,
CK_MECHANISM_TYPE masterWrapMech,
void *pwArg)
{
SSLAuthType authType;
SECKEYPrivateKey *svrPrivKey;
SECKEYPublicKey *svrPubKey = NULL;
PK11SymKey *unwrappedWrappingKey = NULL;
PK11SymKey **pSymWrapKey;
CK_MECHANISM_TYPE asymWrapMechanism = CKM_INVALID_MECHANISM;
int length;
unsigned int wrapMechIndex;
unsigned int wrapKeyIndex;
SECStatus rv;
SECItem wrappedKey;
SSLWrappedSymWrappingKey wswk;
PK11SymKey *Ks = NULL;
SECKEYPublicKey *pubWrapKey = NULL;
SECKEYPrivateKey *privWrapKey = NULL;
ECCWrappedKeyInfo *ecWrapped;
const sslServerCert *serverCert = ss->sec.serverCert;
PORT_Assert(serverCert);
PORT_Assert(serverCert->serverKeyPair);
PORT_Assert(serverCert->serverKeyPair->privKey);
PORT_Assert(serverCert->serverKeyPair->pubKey);
if (!serverCert || !serverCert->serverKeyPair ||
!serverCert->serverKeyPair->privKey ||
!serverCert->serverKeyPair->pubKey) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return NULL; /* hmm */
}
rv = ssl_FindIndexByWrapKey(serverCert, &wrapKeyIndex);
if (rv != SECSuccess)
return NULL; /* unusable wrapping key. */
rv = ssl_FindIndexByWrapMechanism(masterWrapMech, &wrapMechIndex);
if (rv != SECSuccess)
return NULL; /* invalid masterWrapMech. */
authType = ssl_wrap_key_auth_type[wrapKeyIndex];
svrPrivKey = serverCert->serverKeyPair->privKey;
pSymWrapKey = &symWrapKeys[wrapMechIndex].symWrapKey[wrapKeyIndex];
ssl_InitSessionCacheLocks(PR_TRUE);
PZ_Lock(symWrapKeysLock);
unwrappedWrappingKey = *pSymWrapKey;
if (unwrappedWrappingKey != NULL) {
if (PK11_VerifyKeyOK(unwrappedWrappingKey)) {
unwrappedWrappingKey = PK11_ReferenceSymKey(unwrappedWrappingKey);
goto done;
}
/* slot series has changed, so this key is no good any more. */
PK11_FreeSymKey(unwrappedWrappingKey);
*pSymWrapKey = unwrappedWrappingKey = NULL;
}
/* Try to get wrapped SymWrapping key out of the (disk) cache. */
/* Following call fills in wswk on success. */
rv = ssl_GetWrappingKey(wrapMechIndex, wrapKeyIndex, &wswk);
if (rv == SECSuccess) {
/* found the wrapped sym wrapping key on disk. */
unwrappedWrappingKey =
ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, wrapKeyIndex,
masterWrapMech, pwArg);
if (unwrappedWrappingKey) {
goto install;
}
}
if (!masterSecretSlot) /* caller doesn't want to create a new one. */
goto loser;
length = PK11_GetBestKeyLength(masterSecretSlot, masterWrapMech);
/* Zero length means fixed key length algorithm, or error.
* It's ambiguous.
*/
unwrappedWrappingKey = PK11_KeyGen(masterSecretSlot, masterWrapMech, NULL,
length, pwArg);
if (!unwrappedWrappingKey) {
goto loser;
}
/* Prepare the buffer to receive the wrappedWrappingKey,
* the symmetric wrapping key wrapped using the server's pub key.
*/
PORT_Memset(&wswk, 0, sizeof wswk); /* eliminate UMRs. */
svrPubKey = serverCert->serverKeyPair->pubKey;
wrappedKey.type = siBuffer;
wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey);
wrappedKey.data = wswk.wrappedSymmetricWrappingkey;
PORT_Assert(wrappedKey.len <= sizeof wswk.wrappedSymmetricWrappingkey);
if (wrappedKey.len > sizeof wswk.wrappedSymmetricWrappingkey)
goto loser;
/* wrap symmetric wrapping key in server's public key. */
switch (authType) {
case ssl_auth_rsa_decrypt:
case ssl_auth_rsa_sign: /* bad: see Bug 1248320 */
case ssl_auth_rsa_pss:
asymWrapMechanism = CKM_RSA_PKCS;
rv = PK11_PubWrapSymKey(asymWrapMechanism, svrPubKey,
unwrappedWrappingKey, &wrappedKey);
break;
case ssl_auth_ecdsa:
case ssl_auth_ecdh_rsa:
case ssl_auth_ecdh_ecdsa:
/*
* We generate an ephemeral EC key pair. Perform an ECDH
* computation involving this ephemeral EC public key and
* the SSL server's (long-term) EC private key. The resulting
* shared secret is treated in the same way as Fortezza's Ks,
* i.e., it is used to wrap the wrapping key. To facilitate
* unwrapping in ssl_UnwrapWrappingKey, we also store all
* relevant info about the ephemeral EC public key in
* wswk.wrappedSymmetricWrappingkey and lay it out as
* described in the ECCWrappedKeyInfo structure.
*/
PORT_Assert(SECKEY_GetPublicKeyType(svrPubKey) == ecKey);
if (SECKEY_GetPublicKeyType(svrPubKey) != ecKey) {
/* something is wrong in sslsecur.c if this isn't an ecKey */
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
rv = SECFailure;
goto ec_cleanup;
}
privWrapKey = SECKEY_CreateECPrivateKey(
&svrPubKey->u.ec.DEREncodedParams, &pubWrapKey, NULL);
if ((privWrapKey == NULL) || (pubWrapKey == NULL)) {
rv = SECFailure;
goto ec_cleanup;
}
/* Set the key size in bits */
if (pubWrapKey->u.ec.size == 0) {
pubWrapKey->u.ec.size = SECKEY_PublicKeyStrengthInBits(svrPubKey);
}
PORT_Assert(pubWrapKey->u.ec.DEREncodedParams.len +
pubWrapKey->u.ec.publicValue.len <
MAX_EC_WRAPPED_KEY_BUFLEN);
if (pubWrapKey->u.ec.DEREncodedParams.len +
pubWrapKey->u.ec.publicValue.len >=
MAX_EC_WRAPPED_KEY_BUFLEN) {
PORT_SetError(SEC_ERROR_INVALID_KEY);
rv = SECFailure;
goto ec_cleanup;
}
/* Derive Ks using ECDH */
Ks = PK11_PubDeriveWithKDF(svrPrivKey, pubWrapKey, PR_FALSE, NULL,
NULL, CKM_ECDH1_DERIVE, masterWrapMech,
CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
if (Ks == NULL) {
rv = SECFailure;
goto ec_cleanup;
}
ecWrapped = (ECCWrappedKeyInfo *)(wswk.wrappedSymmetricWrappingkey);
ecWrapped->size = pubWrapKey->u.ec.size;
ecWrapped->encodedParamLen = pubWrapKey->u.ec.DEREncodedParams.len;
PORT_Memcpy(ecWrapped->var, pubWrapKey->u.ec.DEREncodedParams.data,
pubWrapKey->u.ec.DEREncodedParams.len);
ecWrapped->pubValueLen = pubWrapKey->u.ec.publicValue.len;
PORT_Memcpy(ecWrapped->var + ecWrapped->encodedParamLen,
pubWrapKey->u.ec.publicValue.data,
pubWrapKey->u.ec.publicValue.len);
wrappedKey.len = MAX_EC_WRAPPED_KEY_BUFLEN -
(ecWrapped->encodedParamLen + ecWrapped->pubValueLen);
wrappedKey.data = ecWrapped->var + ecWrapped->encodedParamLen +
ecWrapped->pubValueLen;
/* wrap symmetricWrapping key with the local Ks */
rv = PK11_WrapSymKey(masterWrapMech, NULL, Ks,
unwrappedWrappingKey, &wrappedKey);
if (rv != SECSuccess) {
goto ec_cleanup;
}
/* Write down the length of wrapped key in the buffer
* wswk.wrappedSymmetricWrappingkey at the appropriate offset
*/
ecWrapped->wrappedKeyLen = wrappedKey.len;
ec_cleanup:
if (privWrapKey)
SECKEY_DestroyPrivateKey(privWrapKey);
if (pubWrapKey)
SECKEY_DestroyPublicKey(pubWrapKey);
if (Ks)
PK11_FreeSymKey(Ks);
asymWrapMechanism = masterWrapMech;
break;
default:
rv = SECFailure;
break;
}
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
goto loser;
}
PORT_Assert(asymWrapMechanism != CKM_INVALID_MECHANISM);
wswk.symWrapMechanism = masterWrapMech;
wswk.asymWrapMechanism = asymWrapMechanism;
wswk.wrapMechIndex = wrapMechIndex;
wswk.wrapKeyIndex = wrapKeyIndex;
wswk.wrappedSymKeyLen = wrappedKey.len;
/* put it on disk. */
/* If the wrapping key for this KEA type has already been set,
* then abandon the value we just computed and
* use the one we got from the disk.
*/
rv = ssl_SetWrappingKey(&wswk);
if (rv == SECSuccess) {
/* somebody beat us to it. The original contents of our wswk
* has been replaced with the content on disk. Now, discard
* the key we just created and unwrap this new one.
*/
PK11_FreeSymKey(unwrappedWrappingKey);
unwrappedWrappingKey =
ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, wrapKeyIndex,
masterWrapMech, pwArg);
}
install:
if (unwrappedWrappingKey) {
*pSymWrapKey = PK11_ReferenceSymKey(unwrappedWrappingKey);
}
loser:
done:
PZ_Unlock(symWrapKeysLock);
return unwrappedWrappingKey;
}
#ifdef NSS_ALLOW_SSLKEYLOGFILE
/* hexEncode hex encodes |length| bytes from |in| and writes it as |length*2|
* bytes to |out|. */
static void
hexEncode(char *out, const unsigned char *in, unsigned int length)
{
static const char hextable[] = "0123456789abcdef";
unsigned int i;
for (i = 0; i < length; i++) {
*(out++) = hextable[in[i] >> 4];
*(out++) = hextable[in[i] & 15];
}
}
#endif
/* Called from ssl3_SendClientKeyExchange(). */
static SECStatus
ssl3_SendRSAClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey)
{
PK11SymKey *pms = NULL;
SECStatus rv = SECFailure;
SECItem enc_pms = { siBuffer, NULL, 0 };
PRBool isTLS;
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss));
PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss));
/* Generate the pre-master secret ... */
ssl_GetSpecWriteLock(ss);
isTLS = (PRBool)(ss->version > SSL_LIBRARY_VERSION_3_0);
pms = ssl3_GenerateRSAPMS(ss, ss->ssl3.pwSpec, NULL);
ssl_ReleaseSpecWriteLock(ss);
if (pms == NULL) {
ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
goto loser;
}
/* Get the wrapped (encrypted) pre-master secret, enc_pms */
unsigned int svrPubKeyBits = SECKEY_PublicKeyStrengthInBits(svrPubKey);
enc_pms.len = (svrPubKeyBits + 7) / 8;
/* Check that the RSA key isn't larger than 8k bit. */
if (svrPubKeyBits > SSL_MAX_RSA_KEY_BITS) {
(void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter);
ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
goto loser;
}
enc_pms.data = (unsigned char *)PORT_Alloc(enc_pms.len);
if (enc_pms.data == NULL) {
goto loser; /* err set by PORT_Alloc */
}
/* Wrap pre-master secret in server's public key. */
rv = PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, pms, &enc_pms);
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
goto loser;
}
#ifdef TRACE
if (ssl_trace >= 100) {
SECStatus extractRV = PK11_ExtractKeyValue(pms);
if (extractRV == SECSuccess) {
SECItem *keyData = PK11_GetKeyData(pms);
if (keyData && keyData->data && keyData->len) {
ssl_PrintBuf(ss, "Pre-Master Secret",
keyData->data, keyData->len);
}
}
}
#endif
rv = ssl3_AppendHandshakeHeader(ss, ssl_hs_client_key_exchange,
isTLS ? enc_pms.len + 2
: enc_pms.len);
if (rv != SECSuccess) {
goto loser; /* err set by ssl3_AppendHandshake* */
}
if (isTLS) {
rv = ssl3_AppendHandshakeVariable(ss, enc_pms.data, enc_pms.len, 2);
} else {
rv = ssl3_AppendHandshake(ss, enc_pms.data, enc_pms.len);
}
if (rv != SECSuccess) {
goto loser; /* err set by ssl3_AppendHandshake* */
}
rv = ssl3_InitPendingCipherSpecs(ss, pms, PR_TRUE);
PK11_FreeSymKey(pms);
pms = NULL;
if (rv != SECSuccess) {
ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE);
goto loser;
}
rv = SECSuccess;
loser:
if (enc_pms.data != NULL) {
PORT_Free(enc_pms.data);
}
if (pms != NULL) {
PK11_FreeSymKey(pms);
}
return rv;
}
/* DH shares need to be padded to the size of their prime. Some implementations
* require this. TLS 1.3 also requires this. */
SECStatus
ssl_AppendPaddedDHKeyShare(sslBuffer *buf, const SECKEYPublicKey *pubKey,
PRBool appendLength)
{
SECStatus rv;
unsigned int pad = pubKey->u.dh.prime.len - pubKey->u.dh.publicValue.len;
if (appendLength) {
rv = sslBuffer_AppendNumber(buf, pubKey->u.dh.prime.len, 2);
if (rv != SECSuccess) {
return rv;
}
}
while (pad) {
rv = sslBuffer_AppendNumber(buf, 0, 1);
if (rv != SECSuccess) {
return rv;
}
--pad;
}
rv = sslBuffer_Append(buf, pubKey->u.dh.publicValue.data,
pubKey->u.dh.publicValue.len);
if (rv != SECSuccess) {
return rv;
}
return SECSuccess;
}
/* Called from ssl3_SendClientKeyExchange(). */
static SECStatus
ssl3_SendDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey)
{
PK11SymKey *pms = NULL;
SECStatus rv;
PRBool isTLS;
CK_MECHANISM_TYPE target;
const ssl3DHParams *params;
ssl3DHParams customParams;
const sslNamedGroupDef *groupDef;
static const sslNamedGroupDef customGroupDef = {
ssl_grp_ffdhe_custom, 0, ssl_kea_dh, SEC_OID_TLS_DHE_CUSTOM, PR_FALSE
};
sslEphemeralKeyPair *keyPair = NULL;
SECKEYPublicKey *pubKey;
PRUint8 dhData[SSL_MAX_DH_KEY_BITS / 8 + 2];
sslBuffer dhBuf = SSL_BUFFER(dhData);