Index: net/third_party/nss/ssl/ssl3con.c |
=================================================================== |
--- net/third_party/nss/ssl/ssl3con.c (revision 215189) |
+++ net/third_party/nss/ssl/ssl3con.c (working copy) |
@@ -44,6 +44,9 @@ |
#ifdef NSS_ENABLE_ZLIB |
#include "zlib.h" |
#endif |
+#ifdef LINUX |
+#include <dlfcn.h> |
+#endif |
#ifndef PK11_SETATTRS |
#define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \ |
@@ -89,7 +92,10 @@ |
*/ |
static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { |
/* cipher_suite policy enabled is_present*/ |
+ { TLS_RSA_WITH_AES_128_GCM_SHA256, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE}, |
#ifdef NSS_ENABLE_ECC |
+ { TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE}, |
+ { TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, SSL_NOT_ALLOWED, PR_TRUE,PR_FALSE}, |
{ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, |
{ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, |
#endif /* NSS_ENABLE_ECC */ |
@@ -233,23 +239,30 @@ |
/* indexed by SSL3BulkCipher */ |
static const ssl3BulkCipherDef bulk_cipher_defs[] = { |
- /* cipher calg keySz secretSz type ivSz BlkSz keygen */ |
- {cipher_null, calg_null, 0, 0, type_stream, 0, 0, kg_null}, |
- {cipher_rc4, calg_rc4, 16, 16, type_stream, 0, 0, kg_strong}, |
- {cipher_rc4_40, calg_rc4, 16, 5, type_stream, 0, 0, kg_export}, |
- {cipher_rc4_56, calg_rc4, 16, 7, type_stream, 0, 0, kg_export}, |
- {cipher_rc2, calg_rc2, 16, 16, type_block, 8, 8, kg_strong}, |
- {cipher_rc2_40, calg_rc2, 16, 5, type_block, 8, 8, kg_export}, |
- {cipher_des, calg_des, 8, 8, type_block, 8, 8, kg_strong}, |
- {cipher_3des, calg_3des, 24, 24, type_block, 8, 8, kg_strong}, |
- {cipher_des40, calg_des, 8, 5, type_block, 8, 8, kg_export}, |
- {cipher_idea, calg_idea, 16, 16, type_block, 8, 8, kg_strong}, |
- {cipher_aes_128, calg_aes, 16, 16, type_block, 16,16, kg_strong}, |
- {cipher_aes_256, calg_aes, 32, 32, type_block, 16,16, kg_strong}, |
- {cipher_camellia_128, calg_camellia,16, 16, type_block, 16,16, kg_strong}, |
- {cipher_camellia_256, calg_camellia,32, 32, type_block, 16,16, kg_strong}, |
- {cipher_seed, calg_seed, 16, 16, type_block, 16,16, kg_strong}, |
- {cipher_missing, calg_null, 0, 0, type_stream, 0, 0, kg_null}, |
+ /* |--------- Lengths --------| */ |
+ /* cipher calg K S type I B T N */ |
+ /* e e V l a o */ |
+ /* y c | o g n */ |
+ /* | r | c | c */ |
+ /* | e | k | e */ |
+ /* | t | | | | */ |
+ {cipher_null, calg_null, 0, 0, type_stream, 0, 0, 0, 0}, |
+ {cipher_rc4, calg_rc4, 16,16, type_stream, 0, 0, 0, 0}, |
+ {cipher_rc4_40, calg_rc4, 16, 5, type_stream, 0, 0, 0, 0}, |
+ {cipher_rc4_56, calg_rc4, 16, 7, type_stream, 0, 0, 0, 0}, |
+ {cipher_rc2, calg_rc2, 16,16, type_block, 8, 8, 0, 0}, |
+ {cipher_rc2_40, calg_rc2, 16, 5, type_block, 8, 8, 0, 0}, |
+ {cipher_des, calg_des, 8, 8, type_block, 8, 8, 0, 0}, |
+ {cipher_3des, calg_3des, 24,24, type_block, 8, 8, 0, 0}, |
+ {cipher_des40, calg_des, 8, 5, type_block, 8, 8, 0, 0}, |
+ {cipher_idea, calg_idea, 16,16, type_block, 8, 8, 0, 0}, |
+ {cipher_aes_128, calg_aes, 16,16, type_block, 16,16, 0, 0}, |
+ {cipher_aes_256, calg_aes, 32,32, type_block, 16,16, 0, 0}, |
+ {cipher_camellia_128, calg_camellia, 16,16, type_block, 16,16, 0, 0}, |
+ {cipher_camellia_256, calg_camellia, 32,32, type_block, 16,16, 0, 0}, |
+ {cipher_seed, calg_seed, 16,16, type_block, 16,16, 0, 0}, |
+ {cipher_aes_128_gcm, calg_aes_128_gcm, 16,16, type_aead, 4, 0,16, 8}, |
+ {cipher_missing, calg_null, 0, 0, type_stream, 0, 0, 0, 0}, |
}; |
static const ssl3KEADef kea_defs[] = |
@@ -371,6 +384,10 @@ |
{SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_rsa_fips}, |
{SSL_RSA_FIPS_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_rsa_fips}, |
+ {TLS_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_null, kea_rsa}, |
+ {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_null, kea_ecdhe_rsa}, |
+ {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, cipher_aes_128_gcm, mac_null, kea_ecdhe_ecdsa}, |
+ |
#ifdef NSS_ENABLE_ECC |
{TLS_ECDH_ECDSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_ecdsa}, |
{TLS_ECDH_ECDSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_ecdsa}, |
@@ -434,6 +451,7 @@ |
{ calg_aes , CKM_AES_CBC }, |
{ calg_camellia , CKM_CAMELLIA_CBC }, |
{ calg_seed , CKM_SEED_CBC }, |
+ { calg_aes_128_gcm, CKM_AES_GCM }, |
/* { calg_init , (CK_MECHANISM_TYPE)0x7fffffffL } */ |
}; |
@@ -472,6 +490,7 @@ |
"Camellia-128", |
"Camellia-256", |
"SEED-CBC", |
+ "AES-128-GCM", |
"missing" |
}; |
@@ -598,9 +617,12 @@ |
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_128_GCM_SHA256: |
case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: |
+ case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: |
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_NULL_SHA256: |
return version >= SSL_LIBRARY_VERSION_TLS_1_2; |
default: |
@@ -1360,7 +1382,7 @@ |
cipher = suite_def->bulk_cipher_alg; |
kea = suite_def->key_exchange_alg; |
mac = suite_def->mac_alg; |
- if (mac <= ssl_mac_sha && isTLS) |
+ if (mac <= ssl_mac_sha && mac != mac_null && isTLS) |
mac += 2; |
ss->ssl3.hs.suite_def = suite_def; |
@@ -1554,7 +1576,6 @@ |
unsigned int optArg2 = 0; |
PRBool server_encrypts = ss->sec.isServer; |
SSLCipherAlgorithm calg; |
- SSLCompressionMethod compression_method; |
SECStatus rv; |
PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); |
@@ -1565,7 +1586,6 @@ |
cipher_def = pwSpec->cipher_def; |
calg = cipher_def->calg; |
- compression_method = pwSpec->compression_method; |
serverContext = pwSpec->server.cipher_context; |
clientContext = pwSpec->client.cipher_context; |
@@ -1721,6 +1741,165 @@ |
return param; |
} |
+/* ssl3_build_record_pseudo_header writes the TLS pseudo-header (the data which |
+ * is included in the MAC) to |out| and returns its length. */ |
+static int |
+ssl3_build_record_pseudo_header(unsigned char* out, |
+ SSL3ContentType type, |
+ SSL3ProtocolVersion version, |
+ PRBool isDTLS, |
+ SSL3SequenceNumber seq_num, |
+ int length) { |
+ out[0] = (unsigned char)(seq_num.high >> 24); |
+ out[1] = (unsigned char)(seq_num.high >> 16); |
+ out[2] = (unsigned char)(seq_num.high >> 8); |
+ out[3] = (unsigned char)(seq_num.high >> 0); |
+ out[4] = (unsigned char)(seq_num.low >> 24); |
+ out[5] = (unsigned char)(seq_num.low >> 16); |
+ out[6] = (unsigned char)(seq_num.low >> 8); |
+ out[7] = (unsigned char)(seq_num.low >> 0); |
+ out[8] = type; |
+ |
+ /* TLS MAC includes the record's version field, SSL's doesn't. We decide |
+ * which MAC defintiion to use based on the version of the protocol that |
+ * was negotiated when the spec became current, NOT based on the version |
+ * value in the record itself. But, we use the record'v version value in |
+ * the computation. */ |
+ if (version <= SSL_LIBRARY_VERSION_3_0) { |
+ out[9] = MSB(length); |
+ out[10] = LSB(length); |
+ return 11; |
+ } else { |
+ /* New TLS hash includes version. */ |
+ if (isDTLS) { |
+ SSL3ProtocolVersion dtls_version; |
+ |
+ dtls_version = dtls_TLSVersionToDTLSVersion(version); |
+ out[9] = MSB(dtls_version); |
+ out[10] = LSB(dtls_version); |
+ } else { |
+ out[9] = MSB(version); |
+ out[10] = LSB(version); |
+ } |
+ out[11] = MSB(length); |
+ out[12] = LSB(length); |
+ return 13; |
+ } |
+} |
+ |
+typedef SECStatus (*PK11CryptFcn)( |
+ PK11SymKey *symKey, CK_MECHANISM_TYPE mechanism, SECItem *param, |
+ unsigned char *out, unsigned int *outLen, unsigned int maxLen, |
+ const unsigned char *in, unsigned int inLen); |
+ |
+static PK11CryptFcn pk11_encrypt = NULL; |
+static PK11CryptFcn pk11_decrypt = NULL; |
+ |
+static PRCallOnceType checkGCMSupportOnce; |
+ |
+static PRStatus |
+ssl3_CheckGCMSupport(void) |
agl
2013/08/02 14:59:50
This function is called CheckGCMSupport, but it do
wtc
2013/08/03 01:02:15
Done. Renamed this function ssl3_ResolvePK11CryptF
|
+{ |
+#ifdef LINUX |
+ void *handle = dlopen(NULL, RTLD_LAZY); |
+ if (!handle) { |
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
+ return PR_FAILURE; |
+ } |
+ pk11_encrypt = (PK11CryptFcn)dlsym(handle, "PK11_Encrypt"); |
+ pk11_decrypt = (PK11CryptFcn)dlsym(handle, "PK11_Decrypt"); |
+ dlclose(handle); |
+ return PR_SUCCESS; |
+#else |
+ pk11_encrypt = PK11_Encrypt; |
+ pk11_decrypt = PK11_Decrypt; |
+ return PR_SUCCESS; |
+#endif |
+} |
+ |
+/* List of all GCM cipher suites */ |
+static const ssl3CipherSuite gcmSuites[] = { |
+ TLS_RSA_WITH_AES_128_GCM_SHA256, |
+#ifdef NSS_ENABLE_ECC |
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, |
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, |
+#endif |
+ 0 /* end of list marker */ |
+}; |
+ |
+/* On this socket, disable the GCM cipher suites */ |
+SECStatus |
+ssl3_DisableGCMSuites(sslSocket * ss) |
+{ |
+ const ssl3CipherSuite * suite; |
agl
2013/08/02 14:59:50
It occurs that the cipher of the ciphersuites coul
wtc
2013/08/03 01:02:15
I re-implemented ssl3_DisableGCMSuites in patch se
|
+ |
+ for (suite = gcmSuites; *suite; ++suite) { |
+ SECStatus rv = ssl3_CipherPrefSet(ss, *suite, PR_FALSE); |
+ |
+ PORT_Assert(rv == SECSuccess); /* else is coding error */ |
+ } |
+ return SECSuccess; |
+} |
+ |
+static SECStatus |
+ssl3_aes_gcm(ssl3KeyMaterial *keys, |
+ PRBool doDecrypt, |
+ unsigned char *out, |
+ int *outlen, |
+ int maxout, |
+ const unsigned char *in, |
+ int inlen, |
+ const unsigned char *explicitNonce, |
+ int explicitNonceLen, |
+ SSL3ContentType type, |
+ SSL3ProtocolVersion version, |
+ SSL3SequenceNumber seq_num) { |
+ SECItem param; |
+ SECStatus rv = SECFailure; |
+ unsigned char nonce[12]; |
+ unsigned char additionalData[13]; |
+ int additionalDataLen; |
+ unsigned int uOutLen; |
+ CK_GCM_PARAMS gcmParams; |
+ |
+ static const int tagSize = 16; |
+ |
+ PORT_Assert(explicitNonceLen == 8); |
+ |
+ /* See https://tools.ietf.org/html/rfc5288#section-3 for details of how the |
+ * nonce is formed. */ |
+ memcpy(nonce, keys->write_iv, 4); |
+ memcpy(nonce + 4, explicitNonce, 8); |
+ |
+ /* See https://tools.ietf.org/html/rfc5246#section-6.2.3.3 for the |
+ * definition of the AEAD additional data. */ |
+ additionalDataLen = ssl3_build_record_pseudo_header( |
+ additionalData, type, version, PR_FALSE /* not DTLS */, seq_num, |
+ inlen - (doDecrypt ? tagSize : 0)); |
+ PORT_Assert(additionalDataLen <= sizeof(additionalData)); |
+ |
+ memset(¶m, 0, sizeof(param)); |
+ param.len = sizeof(CK_GCM_PARAMS); |
+ param.data = (unsigned char *) &gcmParams; |
+ memset(&gcmParams, 0, sizeof(CK_GCM_PARAMS)); |
+ gcmParams.pIv = nonce; |
+ gcmParams.ulIvLen = sizeof(nonce); |
+ gcmParams.pAAD = additionalData; |
+ gcmParams.ulAADLen = additionalDataLen; |
+ gcmParams.ulTagBits = tagSize * 8; |
+ |
+ if (doDecrypt) { |
+ rv = pk11_decrypt(keys->write_key, CKM_AES_GCM, ¶m, out, &uOutLen, |
+ maxout, in, inlen); |
+ } else { |
+ rv = pk11_encrypt(keys->write_key, CKM_AES_GCM, ¶m, out, &uOutLen, |
+ maxout, in, inlen); |
+ } |
+ *outlen = (int) uOutLen; |
+ |
+ return rv; |
+} |
+ |
/* Initialize encryption and MAC contexts for pending spec. |
* Master Secret already is derived. |
* Caller holds Spec write lock. |
@@ -1748,14 +1927,28 @@ |
pwSpec = ss->ssl3.pwSpec; |
cipher_def = pwSpec->cipher_def; |
macLength = pwSpec->mac_size; |
+ calg = cipher_def->calg; |
+ PORT_Assert(alg2Mech[calg].calg == calg); |
+ mechanism = alg2Mech[calg].cmech; |
+ pwSpec->client.write_mac_context = NULL; |
+ pwSpec->server.write_mac_context = NULL; |
+ |
+ if (calg == calg_aes_128_gcm) { |
+ pwSpec->encode = NULL; |
+ pwSpec->decode = NULL; |
+ pwSpec->destroy = NULL; |
+ pwSpec->encodeContext = NULL; |
+ pwSpec->decodeContext = NULL; |
+ pwSpec->aead = ssl3_aes_gcm; |
+ return SECSuccess; |
+ } |
+ |
/* |
** Now setup the MAC contexts, |
** crypto contexts are setup below. |
*/ |
- pwSpec->client.write_mac_context = NULL; |
- pwSpec->server.write_mac_context = NULL; |
mac_mech = pwSpec->mac_def->mmech; |
mac_param.data = (unsigned char *)&macLength; |
mac_param.len = sizeof(macLength); |
@@ -1778,16 +1971,12 @@ |
** Now setup the crypto contexts. |
*/ |
- calg = cipher_def->calg; |
- PORT_Assert(alg2Mech[calg].calg == calg); |
- |
if (calg == calg_null) { |
pwSpec->encode = Null_Cipher; |
pwSpec->decode = Null_Cipher; |
pwSpec->destroy = NULL; |
return SECSuccess; |
} |
- mechanism = alg2Mech[calg].cmech; |
effKeyBits = cipher_def->key_size * BPB; |
/* |
@@ -1999,55 +2188,20 @@ |
{ |
const ssl3MACDef * mac_def; |
SECStatus rv; |
-#ifndef NO_PKCS11_BYPASS |
- PRBool isTLS; |
-#endif |
unsigned int tempLen; |
unsigned char temp[MAX_MAC_LENGTH]; |
- |
- temp[0] = (unsigned char)(seq_num.high >> 24); |
- temp[1] = (unsigned char)(seq_num.high >> 16); |
- temp[2] = (unsigned char)(seq_num.high >> 8); |
- temp[3] = (unsigned char)(seq_num.high >> 0); |
- temp[4] = (unsigned char)(seq_num.low >> 24); |
- temp[5] = (unsigned char)(seq_num.low >> 16); |
- temp[6] = (unsigned char)(seq_num.low >> 8); |
- temp[7] = (unsigned char)(seq_num.low >> 0); |
- temp[8] = type; |
- |
- /* TLS MAC includes the record's version field, SSL's doesn't. |
- ** We decide which MAC defintiion to use based on the version of |
- ** the protocol that was negotiated when the spec became current, |
- ** NOT based on the version value in the record itself. |
- ** But, we use the record'v version value in the computation. |
- */ |
- if (spec->version <= SSL_LIBRARY_VERSION_3_0) { |
- temp[9] = MSB(inputLength); |
- temp[10] = LSB(inputLength); |
- tempLen = 11; |
#ifndef NO_PKCS11_BYPASS |
- isTLS = PR_FALSE; |
-#endif |
- } else { |
- /* New TLS hash includes version. */ |
- if (isDTLS) { |
- SSL3ProtocolVersion dtls_version; |
+ PRBool isTLS = PR_FALSE; |
- dtls_version = dtls_TLSVersionToDTLSVersion(version); |
- temp[9] = MSB(dtls_version); |
- temp[10] = LSB(dtls_version); |
- } else { |
- temp[9] = MSB(version); |
- temp[10] = LSB(version); |
- } |
- temp[11] = MSB(inputLength); |
- temp[12] = LSB(inputLength); |
- tempLen = 13; |
-#ifndef NO_PKCS11_BYPASS |
- isTLS = PR_TRUE; |
+ if (spec->version >= SSL_LIBRARY_VERSION_3_0) { |
+ isTLS = PR_TRUE; |
+ } |
#endif |
- } |
+ tempLen = ssl3_build_record_pseudo_header(temp, type, version, isDTLS, |
+ seq_num, inputLength); |
+ PORT_Assert(tempLen <= sizeof(temp)); |
+ |
PRINT_BUF(95, (NULL, "frag hash1: temp", temp, tempLen)); |
PRINT_BUF(95, (NULL, "frag hash1: input", input, inputLength)); |
@@ -2390,86 +2544,124 @@ |
contentLen = outlen; |
} |
- /* |
- * Add the MAC |
- */ |
- rv = ssl3_ComputeRecordMAC( cwSpec, isServer, isDTLS, |
- type, cwSpec->version, cwSpec->write_seq_num, pIn, contentLen, |
- wrBuf->buf + headerLen + ivLen + 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); |
+ if (cipher_def->type == type_aead) { |
+ /* Prepend the explicit part of the nonce. See |
+ * https://tools.ietf.org/html/rfc5246#section-6.2.3.3 */ |
+ const int nonceLen = cipher_def->explicit_nonce_size; |
+ const int tagLen = cipher_def->tag_size; |
- /* |
- * Pad the text (if we're doing a block cipher) |
- * then Encrypt it |
- */ |
- if (cipher_def->type == type_block) { |
- unsigned char * pBuf; |
- int padding_length; |
- int i; |
+ if (nonceLen > wrBuf->space - headerLen) { |
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
+ return SECFailure; |
+ } |
+ rv = PK11_GenerateRandom(wrBuf->buf + headerLen, nonceLen); |
+ if (rv != SECSuccess) { |
+ ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE); |
+ return rv; |
+ } |
+ if (headerLen + nonceLen + contentLen + tagLen > wrBuf->space) { |
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
+ return SECFailure; |
+ } |
- oddLen = contentLen % cipher_def->block_size; |
- /* Assume blockSize is a power of two */ |
- padding_length = cipher_def->block_size - 1 - |
- ((fragLen) & (cipher_def->block_size - 1)); |
- fragLen += padding_length + 1; |
- PORT_Assert((fragLen % cipher_def->block_size) == 0); |
- |
- /* Pad according to TLS rules (also acceptable to SSL3). */ |
- pBuf = &wrBuf->buf[headerLen + ivLen + fragLen - 1]; |
- for (i = padding_length + 1; i > 0; --i) { |
- *pBuf-- = padding_length; |
+ cipherBytes = contentLen; |
+ rv = cwSpec->aead( |
+ isServer ? &cwSpec->server : &cwSpec->client, |
+ PR_FALSE, /* do encrypt */ |
+ wrBuf->buf + headerLen + nonceLen, /* output */ |
+ &cipherBytes, /* out len */ |
+ wrBuf->space - headerLen - nonceLen, /* max out */ |
+ pIn, contentLen, /* input */ |
+ wrBuf->buf + headerLen, nonceLen, /* explicit nonce */ |
+ type, cwSpec->version, cwSpec->write_seq_num); |
+ if (rv != SECSuccess) { |
+ PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); |
+ return SECFailure; |
} |
- /* now, if contentLen is not a multiple of block size, fix it */ |
- p2Len = fragLen - p1Len; |
- } |
- if (p1Len < 256) { |
- oddLen = p1Len; |
- p1Len = 0; |
+ cipherBytes += nonceLen; |
} else { |
- p1Len -= oddLen; |
- } |
- if (oddLen) { |
- p2Len += oddLen; |
- PORT_Assert( (cipher_def->block_size < 2) || \ |
- (p2Len % cipher_def->block_size) == 0); |
- memmove(wrBuf->buf + headerLen + ivLen + p1Len, pIn + p1Len, oddLen); |
- } |
- if (p1Len > 0) { |
- int cipherBytesPart1 = -1; |
- rv = cwSpec->encode( cwSpec->encodeContext, |
- wrBuf->buf + headerLen + ivLen, /* output */ |
- &cipherBytesPart1, /* actual outlen */ |
- p1Len, /* max outlen */ |
- pIn, p1Len); /* input, and inputlen */ |
- PORT_Assert(rv == SECSuccess && cipherBytesPart1 == (int) p1Len); |
- if (rv != SECSuccess || cipherBytesPart1 != (int) p1Len) { |
- PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); |
+ /* |
+ * Add the MAC |
+ */ |
+ rv = ssl3_ComputeRecordMAC( cwSpec, isServer, isDTLS, |
+ type, cwSpec->version, cwSpec->write_seq_num, pIn, contentLen, |
+ wrBuf->buf + headerLen + ivLen + contentLen, &macLen); |
+ if (rv != SECSuccess) { |
+ ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE); |
return SECFailure; |
} |
- cipherBytes += cipherBytesPart1; |
+ 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 (cipher_def->type == type_block) { |
+ unsigned char * pBuf; |
+ int padding_length; |
+ int i; |
+ |
+ oddLen = contentLen % cipher_def->block_size; |
+ /* Assume blockSize is a power of two */ |
+ padding_length = cipher_def->block_size - 1 - |
+ ((fragLen) & (cipher_def->block_size - 1)); |
+ fragLen += padding_length + 1; |
+ PORT_Assert((fragLen % cipher_def->block_size) == 0); |
+ |
+ /* Pad according to TLS rules (also acceptable to SSL3). */ |
+ pBuf = &wrBuf->buf[headerLen + ivLen + 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( (cipher_def->block_size < 2) || \ |
+ (p2Len % cipher_def->block_size) == 0); |
+ memmove(wrBuf->buf + headerLen + ivLen + p1Len, pIn + p1Len, oddLen); |
+ } |
+ if (p1Len > 0) { |
+ int cipherBytesPart1 = -1; |
+ rv = cwSpec->encode( cwSpec->encodeContext, |
+ wrBuf->buf + headerLen + ivLen, /* output */ |
+ &cipherBytesPart1, /* actual outlen */ |
+ p1Len, /* max outlen */ |
+ pIn, p1Len); /* input, and inputlen */ |
+ PORT_Assert(rv == SECSuccess && cipherBytesPart1 == (int) p1Len); |
+ if (rv != SECSuccess || cipherBytesPart1 != (int) p1Len) { |
+ PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); |
+ return SECFailure; |
+ } |
+ cipherBytes += cipherBytesPart1; |
+ } |
+ if (p2Len > 0) { |
+ int cipherBytesPart2 = -1; |
+ rv = cwSpec->encode( cwSpec->encodeContext, |
+ wrBuf->buf + headerLen + ivLen + p1Len, |
+ &cipherBytesPart2, /* output and actual outLen */ |
+ p2Len, /* max outlen */ |
+ wrBuf->buf + headerLen + ivLen + p1Len, |
+ p2Len); /* input and inputLen*/ |
+ PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int) p2Len); |
+ if (rv != SECSuccess || cipherBytesPart2 != (int) p2Len) { |
+ PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); |
+ return SECFailure; |
+ } |
+ cipherBytes += cipherBytesPart2; |
+ } |
} |
- if (p2Len > 0) { |
- int cipherBytesPart2 = -1; |
- rv = cwSpec->encode( cwSpec->encodeContext, |
- wrBuf->buf + headerLen + ivLen + p1Len, |
- &cipherBytesPart2, /* output and actual outLen */ |
- p2Len, /* max outlen */ |
- wrBuf->buf + headerLen + ivLen + p1Len, |
- p2Len); /* input and inputLen*/ |
- PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int) p2Len); |
- if (rv != SECSuccess || cipherBytesPart2 != (int) p2Len) { |
- PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); |
- return SECFailure; |
- } |
- cipherBytes += cipherBytesPart2; |
- } |
+ |
PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024); |
wrBuf->len = cipherBytes + headerLen; |
@@ -3012,9 +3204,6 @@ |
static SECStatus |
ssl3_IllegalParameter(sslSocket *ss) |
{ |
- PRBool isTLS; |
- |
- isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); |
(void)SSL3_SendAlert(ss, alert_fatal, illegal_parameter); |
PORT_SetError(ss->sec.isServer ? SSL_ERROR_BAD_CLIENT |
: SSL_ERROR_BAD_SERVER ); |
@@ -4830,6 +5019,11 @@ |
ssl3_DisableNonDTLSSuites(ss); |
} |
+ (void) PR_CallOnce(&checkGCMSupportOnce, ssl3_CheckGCMSupport); |
+ if (!pk11_encrypt) { |
agl
2013/08/02 14:59:50
(Assuming that PK11_Encrypt and PK11_Decrypt appea
wtc
2013/08/03 01:02:15
Yes, PK11_Encrypt and PK11_Decrypt were added in t
|
+ ssl3_DisableGCMSuites(ss); |
+ } |
+ |
/* how many suites are permitted by policy and user preference? */ |
num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE); |
if (!num_suites) |
@@ -9946,7 +10140,6 @@ |
static void |
ssl3_RecordKeyLog(sslSocket *ss) |
{ |
- sslSessionID *sid; |
SECStatus rv; |
SECItem *keyData; |
char buf[14 /* "CLIENT_RANDOM " */ + |
@@ -9958,8 +10151,6 @@ |
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); |
- sid = ss->sec.ci.sid; |
- |
if (!ssl_keylog_iob) |
return; |
@@ -11171,12 +11362,14 @@ |
/* With >= TLS 1.1, CBC records have an explicit IV. */ |
minLength += cipher_def->iv_size; |
} |
+ } else if (cipher_def->type == type_aead) { |
+ minLength = cipher_def->explicit_nonce_size + cipher_def->tag_size; |
} |
/* We can perform this test in variable time because the record's total |
* length and the ciphersuite are both public knowledge. */ |
if (cText->buf->len < minLength) { |
- goto decrypt_loser; |
+ goto decrypt_loser; |
} |
if (cipher_def->type == type_block && |
@@ -11207,6 +11400,8 @@ |
sizeof(iv), cText->buf->buf, ivLen); |
good &= SECStatusToMask(rv); |
+ } else if (cipher_def->type == type_aead) { |
+ ivLen = cipher_def->explicit_nonce_size; |
} |
/* If we will be decompressing the buffer we need to decrypt somewhere |
@@ -11244,78 +11439,97 @@ |
return SECFailure; |
} |
- if (cipher_def->type == type_block && |
- ((cText->buf->len - ivLen) % cipher_def->block_size) != 0) { |
- goto decrypt_loser; |
- } |
+ rType = cText->type; |
+ if (cipher_def->type == type_aead) { |
+ rv = crSpec->aead( |
+ ss->sec.isServer ? &crSpec->client : &crSpec->server, |
+ PR_TRUE, /* do decrypt */ |
+ plaintext->buf, /* out */ |
+ (int*) &plaintext->len, /* outlen */ |
+ plaintext->space, /* maxout */ |
+ cText->buf->buf + ivLen, /* in */ |
+ cText->buf->len - ivLen, /* inlen */ |
+ cText->buf->buf, /* explicitNonce */ |
+ cipher_def->explicit_nonce_size, /* explicitNonceLen */ |
+ rType, /* record type */ |
+ cText->version, |
+ crSpec->read_seq_num); |
+ if (rv != SECSuccess) { |
+ good = 0; |
+ } |
+ } else { |
+ if (cipher_def->type == type_block && |
+ ((cText->buf->len - ivLen) % cipher_def->block_size) != 0) { |
+ goto decrypt_loser; |
+ } |
- /* decrypt from cText buf to plaintext. */ |
- rv = crSpec->decode( |
- crSpec->decodeContext, plaintext->buf, (int *)&plaintext->len, |
- plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen); |
- if (rv != SECSuccess) { |
- goto decrypt_loser; |
- } |
+ /* decrypt from cText buf to plaintext. */ |
+ rv = crSpec->decode( |
+ crSpec->decodeContext, plaintext->buf, (int *)&plaintext->len, |
+ plaintext->space, cText->buf->buf + ivLen, cText->buf->len - ivLen); |
+ if (rv != SECSuccess) { |
+ goto decrypt_loser; |
+ } |
- PRINT_BUF(80, (ss, "cleartext:", plaintext->buf, plaintext->len)); |
+ PRINT_BUF(80, (ss, "cleartext:", plaintext->buf, plaintext->len)); |
- originalLen = plaintext->len; |
+ originalLen = plaintext->len; |
- /* If it's a block cipher, check and strip the padding. */ |
- if (cipher_def->type == type_block) { |
- const unsigned int blockSize = cipher_def->block_size; |
- const unsigned int macSize = crSpec->mac_size; |
+ /* If it's a block cipher, check and strip the padding. */ |
+ if (cipher_def->type == type_block) { |
+ const unsigned int blockSize = cipher_def->block_size; |
+ const unsigned int macSize = crSpec->mac_size; |
- if (crSpec->version <= SSL_LIBRARY_VERSION_3_0) { |
- good &= SECStatusToMask(ssl_RemoveSSLv3CBCPadding( |
- plaintext, blockSize, macSize)); |
- } else { |
- good &= SECStatusToMask(ssl_RemoveTLSCBCPadding( |
- plaintext, macSize)); |
+ if (crSpec->version <= SSL_LIBRARY_VERSION_3_0) { |
+ good &= SECStatusToMask(ssl_RemoveSSLv3CBCPadding( |
+ plaintext, blockSize, macSize)); |
+ } else { |
+ good &= SECStatusToMask(ssl_RemoveTLSCBCPadding( |
+ plaintext, macSize)); |
+ } |
} |
- } |
- /* compute the MAC */ |
- rType = cText->type; |
- if (cipher_def->type == type_block) { |
- rv = ssl3_ComputeRecordMACConstantTime( |
- crSpec, (PRBool)(!ss->sec.isServer), |
- IS_DTLS(ss), rType, cText->version, |
- IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num, |
- plaintext->buf, plaintext->len, originalLen, |
- hash, &hashBytes); |
+ /* compute the MAC */ |
+ if (cipher_def->type == type_block) { |
+ rv = ssl3_ComputeRecordMACConstantTime( |
+ crSpec, (PRBool)(!ss->sec.isServer), |
+ IS_DTLS(ss), rType, cText->version, |
+ IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num, |
+ plaintext->buf, plaintext->len, originalLen, |
+ hash, &hashBytes); |
- ssl_CBCExtractMAC(plaintext, originalLen, givenHashBuf, |
- crSpec->mac_size); |
- givenHash = givenHashBuf; |
+ ssl_CBCExtractMAC(plaintext, originalLen, givenHashBuf, |
+ crSpec->mac_size); |
+ givenHash = givenHashBuf; |
- /* plaintext->len will always have enough space to remove the MAC |
- * because in ssl_Remove{SSLv3|TLS}CBCPadding we only adjust |
- * plaintext->len if the result has enough space for the MAC and we |
- * tested the unadjusted size against minLength, above. */ |
- plaintext->len -= crSpec->mac_size; |
- } else { |
- /* This is safe because we checked the minLength above. */ |
- plaintext->len -= crSpec->mac_size; |
+ /* plaintext->len will always have enough space to remove the MAC |
+ * because in ssl_Remove{SSLv3|TLS}CBCPadding we only adjust |
+ * plaintext->len if the result has enough space for the MAC and we |
+ * tested the unadjusted size against minLength, above. */ |
+ plaintext->len -= crSpec->mac_size; |
+ } else { |
+ /* This is safe because we checked the minLength above. */ |
+ plaintext->len -= crSpec->mac_size; |
- rv = ssl3_ComputeRecordMAC( |
- crSpec, (PRBool)(!ss->sec.isServer), |
- IS_DTLS(ss), rType, cText->version, |
- IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num, |
- plaintext->buf, plaintext->len, |
- hash, &hashBytes); |
+ rv = ssl3_ComputeRecordMAC( |
+ crSpec, (PRBool)(!ss->sec.isServer), |
+ IS_DTLS(ss), rType, cText->version, |
+ IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num, |
+ plaintext->buf, plaintext->len, |
+ hash, &hashBytes); |
- /* We can read the MAC directly from the record because its location is |
- * public when a stream cipher is used. */ |
- givenHash = plaintext->buf + plaintext->len; |
- } |
+ /* We can read the MAC directly from the record because its location is |
+ * public when a stream cipher is used. */ |
+ givenHash = plaintext->buf + plaintext->len; |
+ } |
- good &= SECStatusToMask(rv); |
+ good &= SECStatusToMask(rv); |
- if (hashBytes != (unsigned)crSpec->mac_size || |
- NSS_SecureMemcmp(givenHash, hash, crSpec->mac_size) != 0) { |
- /* We're allowed to leak whether or not the MAC check was correct */ |
- good = 0; |
+ if (hashBytes != (unsigned)crSpec->mac_size || |
+ NSS_SecureMemcmp(givenHash, hash, crSpec->mac_size) != 0) { |
+ /* We're allowed to leak whether or not the MAC check was correct */ |
+ good = 0; |
+ } |
} |
if (good == 0) { |