Bug 1432177 - land NSS 10f7e0179b18 UPGRADE_NSS_RELEASE, r=me

--HG--
extra : rebase_source : 73060b7dd79b86f22b4f53d2d3491266b1968904
This commit is contained in:
Franziskus Kiefer 2018-01-23 11:48:27 +01:00
parent 3bdf7ef24a
commit cdd881cf58
62 changed files with 2450 additions and 346 deletions

View File

@ -1 +1 @@
NSS_3_35_RTM
10f7e0179b18

View File

@ -1,8 +0,0 @@
Functions changes summary: 1 Removed, 0 Changed, 0 Added function
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
1 Removed function:
'function void PR_EXPERIMENTAL_ONLY_IN_4_17_GetOverlappedIOHandle(void**)' {PR_EXPERIMENTAL_ONLY_IN_4_17_GetOverlappedIOHandle}

View File

@ -1,3 +1,28 @@
Functions changes summary: 0 Removed, 0 Changed (5 filtered out), 0 Added function
Functions changes summary: 0 Removed, 1 Changed (2 filtered out), 0 Added function
Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
1 function with some indirect sub-type change:
[C]'function SECStatus SSL_GetChannelInfo(SSLChannelInfo*, PRUintn)' at sslinfo.c:12:1 has some indirect sub-type changes:
parameter 1 of type 'SSLChannelInfo*' has sub-type changes:
in pointed to type 'typedef SSLChannelInfo' at sslt.h:318:1:
underlying type 'struct SSLChannelInfoStr' at sslt.h:259:1 changed:
1 data member change:
type of 'SSLSignatureScheme SSLChannelInfoStr::signatureScheme' changed:
underlying type 'enum __anonymous_enum__' changed:
3 enumerator deletions:
'__anonymous_enum__::ssl_sig_rsa_pss_sha256' value '2052'
'__anonymous_enum__::ssl_sig_rsa_pss_sha384' value '2053'
'__anonymous_enum__::ssl_sig_rsa_pss_sha512' value '2054'
6 enumerator insertions:
'__anonymous_enum__::ssl_sig_rsa_pss_rsae_sha256' value '2052'
'__anonymous_enum__::ssl_sig_rsa_pss_rsae_sha384' value '2053'
'__anonymous_enum__::ssl_sig_rsa_pss_rsae_sha512' value '2054'
'__anonymous_enum__::ssl_sig_rsa_pss_pss_sha256' value '2057'
'__anonymous_enum__::ssl_sig_rsa_pss_pss_sha384' value '2058'
'__anonymous_enum__::ssl_sig_rsa_pss_pss_sha512' value '2059'

View File

@ -1 +1 @@
NSS_3_34_BRANCH
NSS_3_35_BRANCH

View File

@ -269,9 +269,43 @@ check_abi()
abidiff --hd1 $PREVDIST/public/ --hd2 $NEWDIST/public \
$PREVDIST/*/lib/$SO $NEWDIST/*/lib/$SO \
> ${HGDIR}/nss/automation/abi-check/new-report-$SO.txt
if [ $? -ne 0 ]; then
RET=$?
ABIDIFF_ERROR=$((($RET & 0x01) != 0))
ABIDIFF_USAGE_ERROR=$((($RET & 0x02) != 0))
ABIDIFF_ABI_CHANGE=$((($RET & 0x04) != 0))
ABIDIFF_ABI_INCOMPATIBLE_CHANGE=$((($RET & 0x08) != 0))
ABIDIFF_UNKNOWN_BIT_SET=$((($RET & 0xf0) != 0))
# If abidiff reports an error, or a usage error, or if it sets a result
# bit value this script doesn't know yet about, we'll report failure.
# For ABI changes, we don't yet report an error. We'll compare the
# result report with our whitelist. This allows us to silence changes
# that we're already aware of and have been declared acceptable.
REPORT_RET_AS_FAILURE=0
if [ $ABIDIFF_ERROR -ne 0 ]; then
print_log "abidiff reported ABIDIFF_ERROR."
REPORT_RET_AS_FAILURE=1
fi
if [ $ABIDIFF_USAGE_ERROR -ne 0 ]; then
print_log "abidiff reported ABIDIFF_USAGE_ERROR."
REPORT_RET_AS_FAILURE=1
fi
if [ $ABIDIFF_UNKNOWN_BIT_SET -ne 0 ]; then
print_log "abidiff reported ABIDIFF_UNKNOWN_BIT_SET."
REPORT_RET_AS_FAILURE=1
fi
if [ $ABIDIFF_ABI_CHANGE -ne 0 ]; then
print_log "Ignoring abidiff result ABI_CHANGE, instead we'll check for non-whitelisted differences."
fi
if [ $ABIDIFF_ABI_INCOMPATIBLE_CHANGE -ne 0 ]; then
print_log "Ignoring abidiff result ABIDIFF_ABI_INCOMPATIBLE_CHANGE, instead we'll check for non-whitelisted differences."
fi
if [ $REPORT_RET_AS_FAILURE -ne 0 ]; then
ABI_PROBLEM_FOUND=1
print_log "FAILED to run abidiff {$PREVDIST , $NEWDIST} for $SO, or failed writing to ${HGDIR}/nss/automation/abi-check/new-report-$SO.txt"
print_log "abidiff {$PREVDIST , $NEWDIST} for $SO FAILED with result $RET, or failed writing to ${HGDIR}/nss/automation/abi-check/new-report-$SO.txt"
fi
if [ ! -f ${HGDIR}/nss/automation/abi-check/expected-report-$SO.txt ]; then
ABI_PROBLEM_FOUND=1

View File

@ -0,0 +1,8 @@
/* 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/. */
bmul : {n,m} (fin n, n >= 1, m == n*2 - 1) => [n] -> [n] -> ([n], [n])
bmul a b = (take`{n} prod, drop`{n} prod)
where prod = pad (pmult a b : [m])
pad x = zero # x

View File

@ -0,0 +1,26 @@
// 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/.
import "bmul.cry";
print "Loading LLVM bitcode...";
m <- llvm_load_module "../../../dist/Debug/lib/libfreeblpriv3.so.bc";
let SpecBinaryMul n = do {
x <- llvm_var "x" (llvm_int n);
y <- llvm_var "y" (llvm_int n);
llvm_ptr "r_high" (llvm_int n);
r_high <- llvm_var "*r_high" (llvm_int n);
llvm_ptr "r_low" (llvm_int n);
r_low <- llvm_var "*r_low" (llvm_int n);
let res = {{ bmul x y }};
llvm_ensure_eq "*r_high" {{ res.0 }};
llvm_ensure_eq "*r_low" {{ res.1 }};
llvm_verify_tactic abc;
};
print "Proving equality for 32-bit bmul()...";
time (llvm_verify m "bmul32" [] (SpecBinaryMul 32));

View File

@ -0,0 +1,357 @@
/*
** ChaCha20 specification
** Author: Austin Seipp <aseipp@pobox.com>. Released in the Public Domain.
**
** Based on RFC 7539 - "ChaCha20 and Poly1305 for IETF Protocols"
** https://tools.ietf.org/html/rfc7539
*/
module chacha20 where
/* -------------------------------------------------------------------------- */
/* -- Implementation -------------------------------------------------------- */
type Round = [16][32] // An input to the ChaCha20 core function
type Block = [64][8] // An output block from the ChaCha20 core function.
type Key = [32][8] // A 32-byte input key
type Nonce = [12][8] // A 12-byte nonce
type Counter = [32] // Starting block counter. Usually 1 or 0.
/* ---------------------------------- */
/* -- Quarter Round ----------------- */
// The quarter round. This takes 4 32-bit integers and diffuses them
// appropriately, and is the core of the column and diagonal round.
qround : [4][32] -> [4][32]
qround [ a0, b0, c0, d0 ] = [ a2, b4, c2, d4 ]
where
a1 = a0 + b0 /* a += b; d ^= a; d <<<= 16 */
d1 = d0 ^ a1
d2 = d1 <<< 16
c1 = c0 + d2 /* c += d; b ^= c; b <<<= 12 */
b1 = b0 ^ c1
b2 = b1 <<< 12
a2 = a1 + b2 /* a += b; d ^= a; d <<<= 8 */
d3 = d2 ^ a2
d4 = d3 <<< 8
c2 = c1 + d4 /* c += d; b ^= c; b <<<= 7 */
b3 = b2 ^ c2
b4 = b3 <<< 7
/* ---------------------------------- */
/* -- Column and diagonal rounds ---- */
// Perform the column round, followed by the diagonal round on the
// input state, which are both defined in terms of the quarter
// round. ChaCha20 requires 20 total rounds of interleaving
// column/diagonal passes on the state, and therefore `cdround` actually
// does two passes at once (mostly for simplicity).
cdround : Round -> Round
cdround [ x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 ]
= [ z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13, z14, z15 ]
where
// Column round
[ y0, y4, y8, y12 ] = qround [ x0, x4, x8, x12 ]
[ y1, y5, y9, y13 ] = qround [ x1, x5, x9, x13 ]
[ y2, y6, y10, y14 ] = qround [ x2, x6, x10, x14 ]
[ y3, y7, y11, y15 ] = qround [ x3, x7, x11, x15 ]
// Diagonal round
[ z0, z5, z10, z15 ] = qround [ y0, y5, y10, y15 ]
[ z1, z6, z11, z12 ] = qround [ y1, y6, y11, y12 ]
[ z2, z7, z8, z13 ] = qround [ y2, y7, y8, y13 ]
[ z3, z4, z9, z14 ] = qround [ y3, y4, y9, y14 ]
/* ---------------------------------- */
/* -- Block encryption -------------- */
// Given an input round, calculate the core ChaCha20 algorithm over
// the round and return an output block. These output blocks form the
// stream which you XOR your plaintext with, and successive iterations of
// the core algorithm result in an infinite stream you can use as a
// cipher.
core : Round -> Block
core x = block
where
rounds = iterate cdround x // Do a bunch of column/diagonal passes...
result = rounds @ 10 // And grab the 10th result (20 total passes)
block = blocked (x + result) // Add to input, convert to output block
/* ---------------------------------- */
/* -- Key Expansion ----------------- */
// Key expansion. Given a nonce and a key, compute a round (which is
// fed to the core algorithm above) by taking the initial round state and
// mixing in the key and nonce appropriately.
kexp : Key -> Counter -> Nonce -> Round
kexp k c n = [ c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11, c12, c13, c14, c15 ]
where
// The following describes the layout of the output round, which
// is fed into the core algorithm successively.
// Bytes 0-3: Constants
[ c0, c1, c2, c3 ] = [ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574 ]
// Bytes 4-11: Key
[ c4, c5, c6, c7 ] = map rjoin (groupBy`{4} kslice1 : [4][4][8]) : [4][32]
[ c8, c9, c10, c11 ] = map rjoin (groupBy`{4} kslice2 : [4][4][8]) : [4][32]
kslice1 = k @@ ([ 0 .. 15 ] : [16][32]) // Top half
kslice2 = k @@ ([ 16 .. 31 ] : [16][32]) // Bottom half
// Bytes 12: Counter, starts off with whatever the user specified
// (usually 0 or 1)
[ c12 ] = [ c ]
// Bytes 14-15: Nonce
[ c13, c14, c15 ] = map rjoin (groupBy`{4} n)
/* ---------------------------------- */
/* -- Round increments -------------- */
// Take a given number of iterations and the input round (after key
// expansion!), and calculate the input round for the core algorithm
// function. This allows you to index into a particular Round which
// can be passed to the 'core' function.
iround : [64] -> Round -> Round
iround n r = (iterate once r) @ n where
// Given a round, increment the counter inside (index no 12)
once [ x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 ]
= [ x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12+1, x13, x14, x15 ]
/* ---------------------------------- */
/* -- ChaCha20 encryption ----------- */
// Produce a psuedo-random stream given a nonce and a key, which can
// be XOR'd with your data to encrypt it.
stream : {n} (fin n) => Key -> Counter -> Nonce -> [n][8]
stream k c n = take`{n} (join rounds) // Take n bytes from the final result
where
// Expand key
key = kexp k c n
// Produce the stream by successively incrementing the input round
// by `i`, and running the core algorithm to get the resulting
// stream for the `i`th input. Once these are concatenated, you have
// an infinite list representing the ChaCha20 stream.
rounds = [ core (iround i key) | i <- [ 0, 1 ... ] ]
// Given an message, a nonce, and a key, produce an encrypted
// message. This is simply defined as the XOR of the message and the
// corresponding encryption stream.
encrypt : {n} (fin n) => Key -> Counter -> Nonce -> [n][8] -> [n][8]
encrypt k c n m = m ^ (stream k c n)
/* -------------------------------------------------------------------------- */
/* -- Theorems, tests ------------------------------------------------------- */
// Tests are private
private
qround01 = qround in == out
where
in = [ 0x11111111, 0x01020304, 0x9b8d6f43, 0x01234567 ]
out = [ 0xea2a92f4, 0xcb1cf8ce, 0x4581472e, 0x5881c4bb ]
core01 = kexp k 1 n == out
where
n = [ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a,
0x00, 0x00, 0x00, 0x00 ]
k = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f ]
out = [ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574,
0x03020100, 0x07060504, 0x0b0a0908, 0x0f0e0d0c,
0x13121110, 0x17161514, 0x1b1a1918, 0x1f1e1d1c,
0x00000001, 0x09000000, 0x4a000000, 0x00000000 ]
core02 = core (kexp k 1 n) == out
where
n = [ 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x4a,
0x00, 0x00, 0x00, 0x00 ]
k = [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f ]
out = [ 0x10, 0xf1, 0xe7, 0xe4, 0xd1, 0x3b, 0x59, 0x15,
0x50, 0x0f, 0xdd, 0x1f, 0xa3, 0x20, 0x71, 0xc4,
0xc7, 0xd1, 0xf4, 0xc7, 0x33, 0xc0, 0x68, 0x03,
0x04, 0x22, 0xaa, 0x9a, 0xc3, 0xd4, 0x6c, 0x4e,
0xd2, 0x82, 0x64, 0x46, 0x07, 0x9f, 0xaa, 0x09,
0x14, 0xc2, 0xd7, 0x05, 0xd9, 0x8b, 0x02, 0xa2,
0xb5, 0x12, 0x9c, 0xd1, 0xde, 0x16, 0x4e, 0xb9,
0xcb, 0xd0, 0x83, 0xe8, 0xa2, 0x50, 0x3c, 0x4e ]
rfctest01 = encrypt zero zero zero zero
== [ 0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, 0x40, 0x5d,
0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28, 0xbd, 0xd2, 0x19, 0xb8,
0xa0, 0x8d, 0xed, 0x1a, 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77,
0x0d, 0xc7, 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d,
0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37, 0x6a, 0x43,
0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c, 0xc3, 0x87, 0xb6, 0x69,
0xb2, 0xee, 0x65, 0x86 ]
rfctest02 = encrypt (zero # [1]) 1 (zero # [2]) msg == out
where
out = [ 0xa3, 0xfb, 0xf0, 0x7d, 0xf3, 0xfa, 0x2f, 0xde, 0x4f, 0x37,
0x6c, 0xa2, 0x3e, 0x82, 0x73, 0x70, 0x41, 0x60, 0x5d, 0x9f,
0x4f, 0x4f, 0x57, 0xbd, 0x8c, 0xff, 0x2c, 0x1d, 0x4b, 0x79,
0x55, 0xec, 0x2a, 0x97, 0x94, 0x8b, 0xd3, 0x72, 0x29, 0x15,
0xc8, 0xf3, 0xd3, 0x37, 0xf7, 0xd3, 0x70, 0x05, 0x0e, 0x9e,
0x96, 0xd6, 0x47, 0xb7, 0xc3, 0x9f, 0x56, 0xe0, 0x31, 0xca,
0x5e, 0xb6, 0x25, 0x0d, 0x40, 0x42, 0xe0, 0x27, 0x85, 0xec,
0xec, 0xfa, 0x4b, 0x4b, 0xb5, 0xe8, 0xea, 0xd0, 0x44, 0x0e,
0x20, 0xb6, 0xe8, 0xdb, 0x09, 0xd8, 0x81, 0xa7, 0xc6, 0x13,
0x2f, 0x42, 0x0e, 0x52, 0x79, 0x50, 0x42, 0xbd, 0xfa, 0x77,
0x73, 0xd8, 0xa9, 0x05, 0x14, 0x47, 0xb3, 0x29, 0x1c, 0xe1,
0x41, 0x1c, 0x68, 0x04, 0x65, 0x55, 0x2a, 0xa6, 0xc4, 0x05,
0xb7, 0x76, 0x4d, 0x5e, 0x87, 0xbe, 0xa8, 0x5a, 0xd0, 0x0f,
0x84, 0x49, 0xed, 0x8f, 0x72, 0xd0, 0xd6, 0x62, 0xab, 0x05,
0x26, 0x91, 0xca, 0x66, 0x42, 0x4b, 0xc8, 0x6d, 0x2d, 0xf8,
0x0e, 0xa4, 0x1f, 0x43, 0xab, 0xf9, 0x37, 0xd3, 0x25, 0x9d,
0xc4, 0xb2, 0xd0, 0xdf, 0xb4, 0x8a, 0x6c, 0x91, 0x39, 0xdd,
0xd7, 0xf7, 0x69, 0x66, 0xe9, 0x28, 0xe6, 0x35, 0x55, 0x3b,
0xa7, 0x6c, 0x5c, 0x87, 0x9d, 0x7b, 0x35, 0xd4, 0x9e, 0xb2,
0xe6, 0x2b, 0x08, 0x71, 0xcd, 0xac, 0x63, 0x89, 0x39, 0xe2,
0x5e, 0x8a, 0x1e, 0x0e, 0xf9, 0xd5, 0x28, 0x0f, 0xa8, 0xca,
0x32, 0x8b, 0x35, 0x1c, 0x3c, 0x76, 0x59, 0x89, 0xcb, 0xcf,
0x3d, 0xaa, 0x8b, 0x6c, 0xcc, 0x3a, 0xaf, 0x9f, 0x39, 0x79,
0xc9, 0x2b, 0x37, 0x20, 0xfc, 0x88, 0xdc, 0x95, 0xed, 0x84,
0xa1, 0xbe, 0x05, 0x9c, 0x64, 0x99, 0xb9, 0xfd, 0xa2, 0x36,
0xe7, 0xe8, 0x18, 0xb0, 0x4b, 0x0b, 0xc3, 0x9c, 0x1e, 0x87,
0x6b, 0x19, 0x3b, 0xfe, 0x55, 0x69, 0x75, 0x3f, 0x88, 0x12,
0x8c, 0xc0, 0x8a, 0xaa, 0x9b, 0x63, 0xd1, 0xa1, 0x6f, 0x80,
0xef, 0x25, 0x54, 0xd7, 0x18, 0x9c, 0x41, 0x1f, 0x58, 0x69,
0xca, 0x52, 0xc5, 0xb8, 0x3f, 0xa3, 0x6f, 0xf2, 0x16, 0xb9,
0xc1, 0xd3, 0x00, 0x62, 0xbe, 0xbc, 0xfd, 0x2d, 0xc5, 0xbc,
0xe0, 0x91, 0x19, 0x34, 0xfd, 0xa7, 0x9a, 0x86, 0xf6, 0xe6,
0x98, 0xce, 0xd7, 0x59, 0xc3, 0xff, 0x9b, 0x64, 0x77, 0x33,
0x8f, 0x3d, 0xa4, 0xf9, 0xcd, 0x85, 0x14, 0xea, 0x99, 0x82,
0xcc, 0xaf, 0xb3, 0x41, 0xb2, 0x38, 0x4d, 0xd9, 0x02, 0xf3,
0xd1, 0xab, 0x7a, 0xc6, 0x1d, 0xd2, 0x9c, 0x6f, 0x21, 0xba,
0x5b, 0x86, 0x2f, 0x37, 0x30, 0xe3, 0x7c, 0xfd, 0xc4, 0xfd,
0x80, 0x6c, 0x22, 0xf2, 0x21 ]
msg = [ 0x41, 0x6e, 0x79, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x69, 0x73,
0x73, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68,
0x65, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x69, 0x6e, 0x74,
0x65, 0x6e, 0x64, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74,
0x68, 0x65, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62,
0x75, 0x74, 0x6f, 0x72, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x70,
0x75, 0x62, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x20, 0x61, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x6f, 0x72,
0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x61,
0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x49, 0x6e, 0x74,
0x65, 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61, 0x66,
0x74, 0x20, 0x6f, 0x72, 0x20, 0x52, 0x46, 0x43, 0x20, 0x61,
0x6e, 0x64, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x73, 0x74, 0x61,
0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6d, 0x61, 0x64,
0x65, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74,
0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74,
0x20, 0x6f, 0x66, 0x20, 0x61, 0x6e, 0x20, 0x49, 0x45, 0x54,
0x46, 0x20, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79,
0x20, 0x69, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64,
0x65, 0x72, 0x65, 0x64, 0x20, 0x61, 0x6e, 0x20, 0x22, 0x49,
0x45, 0x54, 0x46, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x69,
0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x2e, 0x20, 0x53,
0x75, 0x63, 0x68, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x6d,
0x65, 0x6e, 0x74, 0x73, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75,
0x64, 0x65, 0x20, 0x6f, 0x72, 0x61, 0x6c, 0x20, 0x73, 0x74,
0x61, 0x74, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x69,
0x6e, 0x20, 0x49, 0x45, 0x54, 0x46, 0x20, 0x73, 0x65, 0x73,
0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x61, 0x73, 0x20,
0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20, 0x77, 0x72,
0x69, 0x74, 0x74, 0x65, 0x6e, 0x20, 0x61, 0x6e, 0x64, 0x20,
0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x6f, 0x6e, 0x69, 0x63,
0x20, 0x63, 0x6f, 0x6d, 0x6d, 0x75, 0x6e, 0x69, 0x63, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6d, 0x61, 0x64, 0x65,
0x20, 0x61, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x74, 0x69,
0x6d, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x70, 0x6c, 0x61, 0x63,
0x65, 0x2c, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x61,
0x72, 0x65, 0x20, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73,
0x65, 0x64, 0x20, 0x74, 0x6f ]
rfctest03 = encrypt key 42 (zero # [2]) msg == out
where
key = [ 0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, 0xf3, 0x33,
0x88, 0x86, 0x04, 0xf6, 0xb5, 0xf0, 0x47, 0x39, 0x17, 0xc1,
0x40, 0x2b, 0x80, 0x09, 0x9d, 0xca, 0x5c, 0xbc, 0x20, 0x70,
0x75, 0xc0 ]
out = [ 0x27, 0x54, 0x77, 0x61, 0x73, 0x20, 0x62, 0x72, 0x69, 0x6c,
0x6c, 0x69, 0x67, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74,
0x68, 0x65, 0x20, 0x73, 0x6c, 0x69, 0x74, 0x68, 0x79, 0x20,
0x74, 0x6f, 0x76, 0x65, 0x73, 0x0a, 0x44, 0x69, 0x64, 0x20,
0x67, 0x79, 0x72, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x67,
0x69, 0x6d, 0x62, 0x6c, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74,
0x68, 0x65, 0x20, 0x77, 0x61, 0x62, 0x65, 0x3a, 0x0a, 0x41,
0x6c, 0x6c, 0x20, 0x6d, 0x69, 0x6d, 0x73, 0x79, 0x20, 0x77,
0x65, 0x72, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6f,
0x72, 0x6f, 0x67, 0x6f, 0x76, 0x65, 0x73, 0x2c, 0x0a, 0x41,
0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x6d,
0x65, 0x20, 0x72, 0x61, 0x74, 0x68, 0x73, 0x20, 0x6f, 0x75,
0x74, 0x67, 0x72, 0x61, 0x62, 0x65, 0x2e ]
msg = [ 0x62, 0xe6, 0x34, 0x7f, 0x95, 0xed, 0x87, 0xa4, 0x5f, 0xfa,
0xe7, 0x42, 0x6f, 0x27, 0xa1, 0xdf, 0x5f, 0xb6, 0x91, 0x10,
0x04, 0x4c, 0x0d, 0x73, 0x11, 0x8e, 0xff, 0xa9, 0x5b, 0x01,
0xe5, 0xcf, 0x16, 0x6d, 0x3d, 0xf2, 0xd7, 0x21, 0xca, 0xf9,
0xb2, 0x1e, 0x5f, 0xb1, 0x4c, 0x61, 0x68, 0x71, 0xfd, 0x84,
0xc5, 0x4f, 0x9d, 0x65, 0xb2, 0x83, 0x19, 0x6c, 0x7f, 0xe4,
0xf6, 0x05, 0x53, 0xeb, 0xf3, 0x9c, 0x64, 0x02, 0xc4, 0x22,
0x34, 0xe3, 0x2a, 0x35, 0x6b, 0x3e, 0x76, 0x43, 0x12, 0xa6,
0x1a, 0x55, 0x32, 0x05, 0x57, 0x16, 0xea, 0xd6, 0x96, 0x25,
0x68, 0xf8, 0x7d, 0x3f, 0x3f, 0x77, 0x04, 0xc6, 0xa8, 0xd1,
0xbc, 0xd1, 0xbf, 0x4d, 0x50, 0xd6, 0x15, 0x4b, 0x6d, 0xa7,
0x31, 0xb1, 0x87, 0xb5, 0x8d, 0xfd, 0x72, 0x8a, 0xfa, 0x36,
0x75, 0x7a, 0x79, 0x7a, 0xc1, 0x88, 0xd1 ]
property allTestsPass =
([ // Basic tests
qround01, core01, core02
// Full RFC test vectors
, rfctest01, rfctest02, rfctest03
] : [_]Bit) == ~zero // All test bits should equal one
/* -------------------------------------------------------------------------- */
/* -- Private utilities ----------------------------------------------------- */
private
// Convert a round into a block, by splitting every 32-bit round entry
// into 4 bytes, and then serialize those values into a full block.
blocked : Round -> Block
blocked x = join (map toBytes x)
where
// This essentially splits a 32-bit number into 4-byte
// little-endian form, where 'rjoin' is the inverse and would merge
// 4 bytes as a 32-bit little endian number.
toBytes : [32] -> [4][8]
toBytes v = reverse (groupBy`{8} v)
// Map a function over a finite list.
map : { a, b, c }
(a -> b) -> [c]a -> [c]b
map f xs = [ f x | x <- xs ]
// Map a function iteratively over a seed value, producing an infinite
// list of successive function applications:
//
// iterate f 0 == [ 0, f 0, f (f 0), f (f (f 0)), ... ]
iterate : { a } (a -> a) -> a -> [inf]a
iterate f x = [x] # [ f v | v <- iterate f x ]
where
// NB: Needs a binded name in order to tie the recursive knot.
xs = [x] # [ f v | v <- xs ]
// rjoin = join . reverse
// This encodes a sequence of values as a little endian number
// e.g. [ 0xaa, 0xbb, 0xcc, 0xdd ] is serialized as \xdd\xcc\xbb\xaa
rjoin : {a, b, c}
( fin a, fin c
) => [c][a]b -> [a * c]b
rjoin x = join (reverse x)

View File

@ -0,0 +1,40 @@
// 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/.
import "chacha20.cry" as chacha20;
print "Proving ChaCha20 spec...";
prove_print abc {{ chacha20::allTestsPass }};
print "Loading LLVM bitcode...";
m <- llvm_load_module "../../../dist/Debug/lib/libfreeblpriv3.so.bc";
let SpecChaCha20 n = do {
llvm_ptr "output" (llvm_array n (llvm_int 8));
output <- llvm_var "*output" (llvm_array n (llvm_int 8));
llvm_ptr "plain" (llvm_array n (llvm_int 8));
plain <- llvm_var "*plain" (llvm_array n (llvm_int 8));
len <- llvm_var "len" (llvm_int 32);
llvm_assert_eq "len" {{ `n : [32] }};
llvm_ptr "k" (llvm_array 32 (llvm_int 8));
k <- llvm_var "*k" (llvm_array 32 (llvm_int 8));
llvm_ptr "n1" (llvm_array 12 (llvm_int 8));
n1 <- llvm_var "*n1" (llvm_array 12 (llvm_int 8));
ctr <- llvm_var "ctr" (llvm_int 32);
llvm_ensure_eq "*output" {{ chacha20::encrypt k ctr n1 plain }};
llvm_verify_tactic abc;
};
print "Proving equality for a single block...";
time (llvm_verify m "Hacl_Chacha20_chacha20" [] (SpecChaCha20 64));
print "Proving equality for multiple blocks...";
time (llvm_verify m "Hacl_Chacha20_chacha20" [] (SpecChaCha20 256));

View File

@ -0,0 +1,46 @@
FROM ubuntu:latest
MAINTAINER Tim Taubert <ttaubert@mozilla.com>
RUN useradd -d /home/worker -s /bin/bash -m worker
WORKDIR /home/worker
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update && apt-get install -y \
binutils \
build-essential \
bzip2 \
clang-3.8 \
curl \
gcc-multilib \
g++-multilib \
gyp \
lib32z1-dev \
mercurial \
ninja-build \
unzip \
zlib1g-dev
# Add missing LLVM plugin for gold linker.
ADD LLVMgold.so.zip /usr/lib/llvm-3.8/lib/LLVMgold.so.zip
RUN unzip /usr/lib/llvm-3.8/lib/LLVMgold.so.zip -d /usr/lib/llvm-3.8/lib/
# Install SAW/Cryptol.
RUN curl -LO https://saw.galois.com/builds/nightly/saw-0.2-2018-01-14-Ubuntu14.04-64.tar.gz && \
tar xzvf saw-*.tar.gz -C /usr/local --strip-components=1 && \
rm saw-*.tar.gz
# Install Z3.
RUN curl -LO https://github.com/Z3Prover/z3/releases/download/z3-4.6.0/z3-4.6.0-x64-ubuntu-16.04.zip && \
unzip z3*.zip && \
cp -r z3*/* /usr/local/ && \
rm -fr z3*
ADD bin /home/worker/bin
RUN chmod +x /home/worker/bin/*
# Change user.
USER worker
# Set a default command useful for debugging
CMD ["/bin/bash", "--login"]

View File

@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -v -e -x
# Default values for testing.
REVISION=${NSS_HEAD_REVISION:-default}
REPOSITORY=${NSS_HEAD_REPOSITORY:-https://hg.mozilla.org/projects/nss}
# Clone NSS.
for i in 0 2 5; do
sleep $i
hg clone -r $REVISION $REPOSITORY nss && exit 0
rm -rf nss
done
exit 1

View File

@ -30,6 +30,11 @@ const HACL_GEN_IMAGE = {
path: "automation/taskcluster/docker-hacl"
};
const SAW_IMAGE = {
name: "saw",
path: "automation/taskcluster/docker-saw"
};
const WINDOWS_CHECKOUT_CMD =
"bash -c \"hg clone -r $NSS_HEAD_REVISION $NSS_HEAD_REPOSITORY nss || " +
"(sleep 2; hg clone -r $NSS_HEAD_REVISION $NSS_HEAD_REPOSITORY nss) || " +
@ -991,5 +996,56 @@ async function scheduleTools() {
]
}));
let task_saw = queue.scheduleTask(merge(base, {
symbol: "B",
group: "SAW",
name: "LLVM bitcode build (32 bit)",
image: SAW_IMAGE,
kind: "build",
env: {
AR: "llvm-ar-3.8",
CC: "clang-3.8",
CCC: "clang++-3.8"
},
artifacts: {
public: {
expires: 24 * 7,
type: "directory",
path: "/home/worker/artifacts"
}
},
command: [
"/bin/bash",
"-c",
"bin/checkout.sh && nss/automation/taskcluster/scripts/build_gyp.sh --disable-tests --emit-llvm -m32"
]
}));
queue.scheduleTask(merge(base, {
parent: task_saw,
symbol: "bmul",
group: "SAW",
name: "bmul.saw",
image: SAW_IMAGE,
command: [
"/bin/bash",
"-c",
"bin/checkout.sh && nss/automation/taskcluster/scripts/run_saw.sh bmul"
]
}));
queue.scheduleTask(merge(base, {
parent: task_saw,
symbol: "ChaCha20",
group: "SAW",
name: "chacha20.saw",
image: SAW_IMAGE,
command: [
"/bin/bash",
"-c",
"bin/checkout.sh && nss/automation/taskcluster/scripts/run_saw.sh chacha20"
]
}));
return queue.submit();
}

View File

@ -30,7 +30,7 @@ export async function buildTask({name, path}) {
let ns = `docker.images.v1.${process.env.TC_PROJECT}.${name}.hash.${hash}`;
return {
name: "Image Builder",
name: `Image Builder (${name})`,
image: "nssdev/image_builder:0.1.5",
routes: ["index." + ns],
env: {

View File

@ -51,7 +51,7 @@ function parseOptions(opts) {
}
// Parse tools.
let allTools = ["clang-format", "scan-build", "hacl"];
let allTools = ["clang-format", "scan-build", "hacl", "saw"];
let tools = intersect(opts.tools.split(/\s*,\s*/), allTools);
// If the given value is "all" run all tools.
@ -77,7 +77,8 @@ function filter(opts) {
// are not affected by platform or build type selectors.
if (task.platform == "nss-tools") {
return opts.tools.some(tool => {
return task.symbol.toLowerCase().startsWith(tool);
return task.symbol.toLowerCase().startsWith(tool) ||
(task.group && task.group.toLowerCase().startsWith(tool));
});
}

View File

@ -0,0 +1,9 @@
#!/usr/bin/env bash
source $(dirname "$0")/tools.sh
# Fetch artifact if needed.
fetch_dist
# Run SAW.
saw "nss/automation/saw/$1.saw"

View File

@ -91,6 +91,7 @@ while [ $# -gt 0 ]; do
--sancov=?*) enable_sancov "${1#*=}" ;;
--pprof) gyp_params+=(-Duse_pprof=1) ;;
--ct-verif) gyp_params+=(-Dct_verif=1) ;;
--emit-llvm) gyp_params+=(-Demit_llvm=1 -Dsign_libs=0) ;;
--disable-tests) gyp_params+=(-Ddisable_tests=1) ;;
--no-zdefs) gyp_params+=(-Dno_zdefs=1) ;;
--system-sqlite) gyp_params+=(-Duse_system_sqlite=1) ;;

View File

@ -105,6 +105,7 @@
'sign_libs%': 1,
'use_pprof%': 0,
'ct_verif%': 0,
'emit_llvm%': 0,
'nss_public_dist_dir%': '<(nss_dist_dir)/public',
'nss_private_dist_dir%': '<(nss_dist_dir)/private',
'only_dev_random%': 1,
@ -431,6 +432,10 @@
'LIBRARY_SEARCH_PATHS': ['/usr/lib <(sanitizer_flags)'],
},
}],
[ 'emit_llvm==1', {
'cflags': ['-flto'],
'ldflags': ['-flto', '-fuse-ld=gold', '-Wl,-plugin-opt=save-temps'],
}],
[ 'OS=="android" and mozilla_client==0', {
'defines': [
'NO_SYSINFO',

View File

@ -10,4 +10,3 @@
*/
#error "Do not include this header file."

View File

@ -12,6 +12,7 @@
#include "keyhi.h"
#include "pk11pub.h"
#include "pkcs11uri.h"
#include "sslexp.h"
struct ScopedDelete {
void operator()(CERTCertificate* cert) { CERT_DestroyCertificate(cert); }
@ -37,6 +38,9 @@ struct ScopedDelete {
void operator()(PLArenaPool* arena) { PORT_FreeArena(arena, PR_FALSE); }
void operator()(PK11Context* context) { PK11_DestroyContext(context, true); }
void operator()(PK11GenericObject* obj) { PK11_DestroyGenericObject(obj); }
void operator()(SSLResumptionTokenInfo* token) {
SSL_DestroyResumptionTokenInfo(token);
}
};
template <class T>
@ -68,6 +72,7 @@ SCOPED(PK11URI);
SCOPED(PLArenaPool);
SCOPED(PK11Context);
SCOPED(PK11GenericObject);
SCOPED(SSLResumptionTokenInfo);
#undef SCOPED

View File

@ -47,6 +47,7 @@ const uint8_t kTlsAlertUnexpectedMessage = 10;
const uint8_t kTlsAlertBadRecordMac = 20;
const uint8_t kTlsAlertRecordOverflow = 22;
const uint8_t kTlsAlertHandshakeFailure = 40;
const uint8_t kTlsAlertBadCertificate = 42;
const uint8_t kTlsAlertIllegalParameter = 47;
const uint8_t kTlsAlertDecodeError = 50;
const uint8_t kTlsAlertDecryptError = 51;

View File

@ -405,6 +405,9 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRttDowngrade) {
// The client should abort the connection when sending a 0-rtt handshake but
// the servers responds with a TLS 1.2 ServerHello. (with app data)
TEST_P(TlsConnectTls13, TestTls13ZeroRttDowngradeEarlyData) {
const char* k0RttData = "ABCDEF";
const PRInt32 k0RttDataLen = static_cast<PRInt32>(strlen(k0RttData));
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
server_->Set0RttEnabled(true); // set ticket_allow_early_data
Connect();
@ -422,27 +425,28 @@ TEST_P(TlsConnectTls13, TestTls13ZeroRttDowngradeEarlyData) {
// Send the early data xtn in the CH, followed by early app data. The server
// will fail right after sending its flight, when receiving the early data.
client_->Set0RttEnabled(true);
ZeroRttSendReceive(true, false, [this]() {
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
if (variant_ == ssl_variant_stream) {
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
}
return true;
});
client_->Handshake(); // Send ClientHello.
PRInt32 rv =
PR_Write(client_->ssl_fd(), k0RttData, k0RttDataLen); // 0-RTT write.
EXPECT_EQ(k0RttDataLen, rv);
client_->Handshake();
server_->Handshake();
ASSERT_TRUE_WAIT(
(client_->error_code() == SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA), 2000);
// DTLS will timeout as we bump the epoch when installing the early app data
// cipher suite. Thus the encrypted alert will be ignored.
if (variant_ == ssl_variant_stream) {
// The server sends an alert when receiving the early app data record.
ASSERT_TRUE_WAIT(
(server_->error_code() == SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA),
2000);
// When the server receives the early data, it will fail.
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
server_->Handshake(); // Consume ClientHello
EXPECT_EQ(TlsAgent::STATE_ERROR, server_->state());
server_->CheckErrorCode(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA);
} else {
// If it's datagram, we just discard the early data.
server_->Handshake(); // Consume ClientHello
EXPECT_EQ(TlsAgent::STATE_CONNECTING, server_->state());
}
// The client now reads the ServerHello and fails.
ASSERT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
client_->ExpectSendAlert(kTlsAlertIllegalParameter);
client_->Handshake();
client_->CheckErrorCode(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA);
}
static void CheckEarlyDataLimit(const std::shared_ptr<TlsAgent>& agent,
@ -521,6 +525,8 @@ TEST_P(TlsConnectTls13, ReceiveTooMuchEarlyData) {
client_->Handshake(); // Send ClientHello
CheckEarlyDataLimit(client_, limit);
server_->Handshake(); // Process ClientHello, send server flight.
// Lift the limit on the client.
EXPECT_EQ(SECSuccess,
SSLInt_SetSocketMaxEarlyDataSize(client_->ssl_fd(), 1000));
@ -534,21 +540,31 @@ TEST_P(TlsConnectTls13, ReceiveTooMuchEarlyData) {
// This error isn't fatal for DTLS.
ExpectAlert(server_, kTlsAlertUnexpectedMessage);
}
server_->Handshake(); // Process ClientHello, send server flight.
server_->Handshake(); // Just to make sure that we don't read ahead.
server_->Handshake(); // This reads the early data and maybe throws an error.
if (variant_ == ssl_variant_stream) {
server_->CheckErrorCode(SSL_ERROR_TOO_MUCH_EARLY_DATA);
} else {
EXPECT_EQ(TlsAgent::STATE_CONNECTING, server_->state());
}
CheckEarlyDataLimit(server_, limit);
// Attempt to read early data.
// Attempt to read early data. This will get an error.
std::vector<uint8_t> buf(strlen(message) + 1);
EXPECT_GT(0, PR_Read(server_->ssl_fd(), buf.data(), buf.capacity()));
if (variant_ == ssl_variant_stream) {
server_->CheckErrorCode(SSL_ERROR_TOO_MUCH_EARLY_DATA);
EXPECT_EQ(SSL_ERROR_HANDSHAKE_FAILED, PORT_GetError());
} else {
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
}
client_->Handshake(); // Process the handshake.
client_->Handshake(); // Process the alert.
client_->Handshake(); // Process the server's first flight.
if (variant_ == ssl_variant_stream) {
client_->Handshake(); // Process the alert.
client_->CheckErrorCode(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT);
} else {
server_->Handshake(); // Finish connecting.
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
}
}

View File

@ -127,7 +127,8 @@ TEST_P(TlsConnectTls12, ServerAuthCheckSigAlg) {
EXPECT_TRUE(buffer.Read(1, 2, &tmp)) << "read NamedCurve";
EXPECT_EQ(ssl_grp_ec_curve25519, tmp);
EXPECT_TRUE(buffer.Read(3, 1, &tmp)) << " read ECPoint";
CheckSigScheme(capture_ske, 4 + tmp, client_, ssl_sig_rsa_pss_sha256, 1024);
CheckSigScheme(capture_ske, 4 + tmp, client_, ssl_sig_rsa_pss_rsae_sha256,
1024);
}
TEST_P(TlsConnectTls12, ClientAuthCheckSigAlg) {
@ -154,7 +155,8 @@ TEST_P(TlsConnectTls12, ClientAuthBigRsaCheckSigAlg) {
server_->RequestClientAuth(true);
Connect();
CheckKeys();
CheckSigScheme(capture_cert_verify, 0, server_, ssl_sig_rsa_pss_sha256, 2048);
CheckSigScheme(capture_cert_verify, 0, server_, ssl_sig_rsa_pss_rsae_sha256,
2048);
}
class TlsZeroCertificateRequestSigAlgsFilter : public TlsHandshakeFilter {
@ -620,6 +622,31 @@ TEST_P(TlsConnectGenericPre13, AuthCompleteDelayed) {
client_->DeletePacketFilter();
}
TEST_P(TlsConnectGenericPre13, AuthCompleteFailDelayed) {
client_->SetAuthCertificateCallback(AuthCompleteBlock);
StartConnect();
client_->Handshake(); // Send ClientHello
server_->Handshake(); // Send ServerHello
client_->Handshake(); // Send ClientKeyExchange and Finished
server_->Handshake(); // Send Finished
// The server should now report that it is connected
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
// The client should send nothing from here on.
client_->SetPacketFilter(std::make_shared<EnforceNoActivity>());
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
// Report failure.
client_->DeletePacketFilter();
client_->ExpectSendAlert(kTlsAlertBadCertificate);
EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(),
SSL_ERROR_BAD_CERTIFICATE));
client_->Handshake(); // Fail
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
}
// TLS 1.3 handles a delayed AuthComplete callback differently since the
// shape of the handshake is different.
TEST_P(TlsConnectTls13, AuthCompleteDelayed) {
@ -645,6 +672,44 @@ TEST_P(TlsConnectTls13, AuthCompleteDelayed) {
EXPECT_EQ(TlsAgent::STATE_CONNECTED, server_->state());
}
TEST_P(TlsConnectTls13, AuthCompleteFailDelayed) {
client_->SetAuthCertificateCallback(AuthCompleteBlock);
StartConnect();
client_->Handshake(); // Send ClientHello
server_->Handshake(); // Send ServerHello
EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
EXPECT_EQ(TlsAgent::STATE_CONNECTING, server_->state());
// The client will send nothing until AuthCertificateComplete is called.
client_->SetPacketFilter(std::make_shared<EnforceNoActivity>());
client_->Handshake();
EXPECT_EQ(TlsAgent::STATE_CONNECTING, client_->state());
// Report failure.
client_->DeletePacketFilter();
ExpectAlert(client_, kTlsAlertBadCertificate);
EXPECT_EQ(SECSuccess, SSL_AuthCertificateComplete(client_->ssl_fd(),
SSL_ERROR_BAD_CERTIFICATE));
client_->Handshake(); // This should now fail.
server_->Handshake(); // Get the error.
EXPECT_EQ(TlsAgent::STATE_ERROR, client_->state());
EXPECT_EQ(TlsAgent::STATE_ERROR, server_->state());
}
static SECStatus AuthCompleteFail(TlsAgent*, PRBool, PRBool) {
PORT_SetError(SSL_ERROR_BAD_CERTIFICATE);
return SECFailure;
}
TEST_P(TlsConnectGeneric, AuthFailImmediate) {
client_->SetAuthCertificateCallback(AuthCompleteFail);
StartConnect();
ConnectExpectAlert(client_, kTlsAlertBadCertificate);
client_->CheckErrorCode(SSL_ERROR_BAD_CERTIFICATE);
}
static const SSLExtraServerCertData ServerCertDataRsaPkcs1Decrypt = {
ssl_auth_rsa_decrypt, nullptr, nullptr, nullptr};
static const SSLExtraServerCertData ServerCertDataRsaPkcs1Sign = {
@ -796,8 +861,8 @@ INSTANTIATE_TEST_CASE_P(
::testing::Values(TlsAgent::kServerRsaSign),
::testing::Values(ssl_auth_rsa_sign),
::testing::Values(ssl_sig_rsa_pkcs1_sha256, ssl_sig_rsa_pkcs1_sha384,
ssl_sig_rsa_pkcs1_sha512, ssl_sig_rsa_pss_sha256,
ssl_sig_rsa_pss_sha384)));
ssl_sig_rsa_pkcs1_sha512, ssl_sig_rsa_pss_rsae_sha256,
ssl_sig_rsa_pss_rsae_sha384)));
// PSS with SHA-512 needs a bigger key to work.
INSTANTIATE_TEST_CASE_P(
SignatureSchemeBigRsa, TlsSignatureSchemeConfiguration,
@ -805,7 +870,7 @@ INSTANTIATE_TEST_CASE_P(
TlsConnectTestBase::kTlsV12Plus,
::testing::Values(TlsAgent::kRsa2048),
::testing::Values(ssl_auth_rsa_sign),
::testing::Values(ssl_sig_rsa_pss_sha512)));
::testing::Values(ssl_sig_rsa_pss_rsae_sha512)));
INSTANTIATE_TEST_CASE_P(
SignatureSchemeRsaSha1, TlsSignatureSchemeConfiguration,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,

View File

@ -74,12 +74,12 @@ class TlsCipherSuiteTestBase : public TlsConnectTestBase {
Reset(TlsAgent::kServerRsaSign);
auth_type_ = ssl_auth_rsa_sign;
break;
case ssl_sig_rsa_pss_sha256:
case ssl_sig_rsa_pss_sha384:
case ssl_sig_rsa_pss_rsae_sha256:
case ssl_sig_rsa_pss_rsae_sha384:
Reset(TlsAgent::kServerRsaSign);
auth_type_ = ssl_auth_rsa_sign;
break;
case ssl_sig_rsa_pss_sha512:
case ssl_sig_rsa_pss_rsae_sha512:
// You can't fit SHA-512 PSS in a 1024-bit key.
Reset(TlsAgent::kRsa2048);
auth_type_ = ssl_auth_rsa_sign;
@ -313,8 +313,8 @@ static const auto kDummySignatureSchemesParams =
static SSLSignatureScheme kSignatureSchemesParamsArr[] = {
ssl_sig_rsa_pkcs1_sha256, ssl_sig_rsa_pkcs1_sha384,
ssl_sig_rsa_pkcs1_sha512, ssl_sig_ecdsa_secp256r1_sha256,
ssl_sig_ecdsa_secp384r1_sha384, ssl_sig_rsa_pss_sha256,
ssl_sig_rsa_pss_sha384, ssl_sig_rsa_pss_sha512,
ssl_sig_ecdsa_secp384r1_sha384, ssl_sig_rsa_pss_rsae_sha256,
ssl_sig_rsa_pss_rsae_sha384, ssl_sig_rsa_pss_rsae_sha512,
};
#endif

View File

@ -24,7 +24,7 @@ TEST_P(TlsConnectGeneric, ConnectDhe) {
EnableOnlyDheCiphers();
Connect();
CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
}
TEST_P(TlsConnectTls13, SharesForBothEcdheAndDhe) {
@ -455,7 +455,7 @@ TEST_P(TlsConnectGenericPre13, NamedGroupMismatchPre13) {
Connect();
CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_custom, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
}
// Same test but for TLS 1.3. This has to fail.
@ -499,8 +499,8 @@ TEST_P(TlsConnectGenericPre13, PreferredFfdhe) {
Connect();
client_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072);
server_->CheckKEA(ssl_kea_dh, ssl_grp_ffdhe_3072, 3072);
client_->CheckAuthType(ssl_auth_rsa_sign, ssl_sig_rsa_pss_sha256);
server_->CheckAuthType(ssl_auth_rsa_sign, ssl_sig_rsa_pss_sha256);
client_->CheckAuthType(ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
server_->CheckAuthType(ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
}
TEST_P(TlsConnectGenericPre13, MismatchDHE) {
@ -524,7 +524,7 @@ TEST_P(TlsConnectTls13, ResumeFfdhe) {
Connect();
SendReceive(); // Need to read so that we absorb the session ticket.
CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
@ -538,7 +538,7 @@ TEST_P(TlsConnectTls13, ResumeFfdhe) {
ExpectResumption(RESUME_TICKET);
Connect();
CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
ASSERT_LT(0UL, clientCapture->extension().len());
ASSERT_LT(0UL, serverCapture->extension().len());
}

View File

@ -69,7 +69,7 @@ TEST_P(TlsConnectGeneric, ConnectEcdheP384Client) {
server_->ConfigNamedGroups(groups);
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
}
// This causes a HelloRetryRequest in TLS 1.3. Earlier versions don't care.
@ -82,7 +82,7 @@ TEST_P(TlsConnectGeneric, ConnectEcdheP384Server) {
server_->ConfigNamedGroups(groups);
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
EXPECT_EQ(version_ == SSL_LIBRARY_VERSION_TLS_1_3,
hrr_capture->buffer().len() != 0);
}
@ -112,7 +112,7 @@ TEST_P(TlsKeyExchangeTest, P384Priority) {
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
std::vector<SSLNamedGroup> shares = {ssl_grp_ec_secp384r1};
CheckKEXDetails(groups, shares);
@ -129,7 +129,7 @@ TEST_P(TlsKeyExchangeTest, DuplicateGroupConfig) {
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
std::vector<SSLNamedGroup> shares = {ssl_grp_ec_secp384r1};
std::vector<SSLNamedGroup> expectedGroups = {ssl_grp_ec_secp384r1,
@ -147,7 +147,7 @@ TEST_P(TlsKeyExchangeTest, P384PriorityDHEnabled) {
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_3) {
std::vector<SSLNamedGroup> shares = {ssl_grp_ec_secp384r1};
@ -172,7 +172,7 @@ TEST_P(TlsConnectGenericPre13, P384PriorityOnServer) {
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
}
TEST_P(TlsConnectGenericPre13, P384PriorityFromModelSocket) {
@ -188,7 +188,7 @@ TEST_P(TlsConnectGenericPre13, P384PriorityFromModelSocket) {
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp384r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
}
class TlsKeyExchangeGroupCapture : public TlsHandshakeFilter {
@ -276,7 +276,7 @@ TEST_P(TlsConnectStreamPre13, ConfiguredGroupsRenegotiate) {
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
CheckConnected();
// The renegotiation has to use the same preferences as the original session.
@ -284,7 +284,7 @@ TEST_P(TlsConnectStreamPre13, ConfiguredGroupsRenegotiate) {
client_->StartRenegotiate();
Handshake();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
}
TEST_P(TlsKeyExchangeTest, Curve25519) {
@ -318,7 +318,7 @@ TEST_P(TlsConnectGenericPre13, GroupPreferenceServerPriority) {
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
}
#ifndef NSS_DISABLE_TLS_1_3
@ -337,7 +337,7 @@ TEST_P(TlsKeyExchangeTest13, Curve25519P256EqualPriorityClient13) {
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_secp256r1};
CheckKEXDetails(client_groups, shares);
}
@ -357,7 +357,7 @@ TEST_P(TlsKeyExchangeTest13, Curve25519P256EqualPriorityServer13) {
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
CheckKEXDetails(client_groups, shares);
}
@ -379,7 +379,7 @@ TEST_P(TlsKeyExchangeTest13, EqualPriorityTestRetryECServer13) {
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
CheckKEXDetails(client_groups, shares, ssl_grp_ec_secp256r1);
}
@ -401,7 +401,7 @@ TEST_P(TlsKeyExchangeTest13, NotEqualPriorityWithIntermediateGroup13) {
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
CheckKEXDetails(client_groups, shares, ssl_grp_ec_secp256r1);
}
@ -423,7 +423,7 @@ TEST_P(TlsKeyExchangeTest13,
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
CheckKEXDetails(client_groups, shares, ssl_grp_ec_secp256r1);
}
@ -445,7 +445,7 @@ TEST_P(TlsKeyExchangeTest13,
Connect();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519};
CheckKEXDetails(client_groups, shares, ssl_grp_ec_secp256r1);
}
@ -507,7 +507,7 @@ TEST_P(TlsKeyExchangeTest13, MultipleClientShares) {
// The server would accept 25519 but its preferred group (P256) has to win.
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_secp256r1, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
const std::vector<SSLNamedGroup> shares = {ssl_grp_ec_curve25519,
ssl_grp_ec_secp256r1};
CheckKEXDetails(client_groups, shares);

View File

@ -424,7 +424,16 @@ TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsEmpty) {
const uint8_t val[] = {0x00, 0x00};
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
ssl_signature_algorithms_xtn, extension));
ssl_signature_algorithms_xtn, extension),
kTlsAlertHandshakeFailure);
}
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsNoOverlap) {
const uint8_t val[] = {0x00, 0x02, 0xff, 0xff};
DataBuffer extension(val, sizeof(val));
ClientHelloErrorTest(std::make_shared<TlsExtensionReplacer>(
ssl_signature_algorithms_xtn, extension),
kTlsAlertHandshakeFailure);
}
TEST_P(TlsExtensionTest12Plus, SignatureAlgorithmsOddLength) {
@ -507,8 +516,8 @@ TEST_P(TlsExtensionTestPre13, RenegotiationInfoExtensionEmpty) {
// This only works on TLS 1.2, since it relies on static RSA; otherwise libssl
// picks the wrong cipher suite.
TEST_P(TlsExtensionTest12, SignatureAlgorithmConfiguration) {
const SSLSignatureScheme schemes[] = {ssl_sig_rsa_pss_sha512,
ssl_sig_rsa_pss_sha384};
const SSLSignatureScheme schemes[] = {ssl_sig_rsa_pss_rsae_sha512,
ssl_sig_rsa_pss_rsae_sha384};
auto capture =
std::make_shared<TlsExtensionCapture>(ssl_signature_algorithms_xtn);

View File

@ -535,4 +535,27 @@ INSTANTIATE_TEST_CASE_P(Version12Plus, TlsConnectTls12Plus,
::testing::Combine(TlsConnectTestBase::kTlsVariantsAll,
TlsConnectTestBase::kTlsV12Plus));
} // namespace nspr_test
INSTANTIATE_TEST_CASE_P(
GenericStream, TlsConnectGenericResumption,
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
TlsConnectTestBase::kTlsVAll,
::testing::Values(true, false)));
INSTANTIATE_TEST_CASE_P(
GenericDatagram, TlsConnectGenericResumption,
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
TlsConnectTestBase::kTlsV11Plus,
::testing::Values(true, false)));
INSTANTIATE_TEST_CASE_P(
GenericStream, TlsConnectGenericResumptionToken,
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,
TlsConnectTestBase::kTlsVAll));
INSTANTIATE_TEST_CASE_P(
GenericDatagram, TlsConnectGenericResumptionToken,
::testing::Combine(TlsConnectTestBase::kTlsVariantsDatagram,
TlsConnectTestBase::kTlsV11Plus));
INSTANTIATE_TEST_CASE_P(GenericDatagram, TlsConnectTls13ResumptionToken,
TlsConnectTestBase::kTlsVariantsAll);
} // namespace nss_test

View File

@ -60,7 +60,7 @@ TEST_P(TlsConnectGenericPre13, ConnectResumed) {
Connect();
}
TEST_P(TlsConnectGeneric, ConnectClientCacheDisabled) {
TEST_P(TlsConnectGenericResumption, ConnectClientCacheDisabled) {
ConfigureSessionCache(RESUME_NONE, RESUME_SESSIONID);
Connect();
SendReceive();
@ -71,7 +71,7 @@ TEST_P(TlsConnectGeneric, ConnectClientCacheDisabled) {
SendReceive();
}
TEST_P(TlsConnectGeneric, ConnectServerCacheDisabled) {
TEST_P(TlsConnectGenericResumption, ConnectServerCacheDisabled) {
ConfigureSessionCache(RESUME_SESSIONID, RESUME_NONE);
Connect();
SendReceive();
@ -82,7 +82,7 @@ TEST_P(TlsConnectGeneric, ConnectServerCacheDisabled) {
SendReceive();
}
TEST_P(TlsConnectGeneric, ConnectSessionCacheDisabled) {
TEST_P(TlsConnectGenericResumption, ConnectSessionCacheDisabled) {
ConfigureSessionCache(RESUME_NONE, RESUME_NONE);
Connect();
SendReceive();
@ -93,7 +93,7 @@ TEST_P(TlsConnectGeneric, ConnectSessionCacheDisabled) {
SendReceive();
}
TEST_P(TlsConnectGeneric, ConnectResumeSupportBoth) {
TEST_P(TlsConnectGenericResumption, ConnectResumeSupportBoth) {
// This prefers tickets.
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
Connect();
@ -106,7 +106,7 @@ TEST_P(TlsConnectGeneric, ConnectResumeSupportBoth) {
SendReceive();
}
TEST_P(TlsConnectGeneric, ConnectResumeClientTicketServerBoth) {
TEST_P(TlsConnectGenericResumption, ConnectResumeClientTicketServerBoth) {
// This causes no resumption because the client needs the
// session cache to resume even with tickets.
ConfigureSessionCache(RESUME_TICKET, RESUME_BOTH);
@ -120,7 +120,7 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientTicketServerBoth) {
SendReceive();
}
TEST_P(TlsConnectGeneric, ConnectResumeClientBothTicketServerTicket) {
TEST_P(TlsConnectGenericResumption, ConnectResumeClientBothTicketServerTicket) {
// This causes a ticket resumption.
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
Connect();
@ -133,7 +133,7 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientBothTicketServerTicket) {
SendReceive();
}
TEST_P(TlsConnectGeneric, ConnectResumeClientServerTicketOnly) {
TEST_P(TlsConnectGenericResumption, ConnectResumeClientServerTicketOnly) {
// This causes no resumption because the client needs the
// session cache to resume even with tickets.
ConfigureSessionCache(RESUME_TICKET, RESUME_TICKET);
@ -147,7 +147,7 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientServerTicketOnly) {
SendReceive();
}
TEST_P(TlsConnectGeneric, ConnectResumeClientBothServerNone) {
TEST_P(TlsConnectGenericResumption, ConnectResumeClientBothServerNone) {
ConfigureSessionCache(RESUME_BOTH, RESUME_NONE);
Connect();
SendReceive();
@ -159,7 +159,7 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientBothServerNone) {
SendReceive();
}
TEST_P(TlsConnectGeneric, ConnectResumeClientNoneServerBoth) {
TEST_P(TlsConnectGenericResumption, ConnectResumeClientNoneServerBoth) {
ConfigureSessionCache(RESUME_NONE, RESUME_BOTH);
Connect();
SendReceive();
@ -202,7 +202,7 @@ TEST_P(TlsConnectGeneric, ConnectResumeClientBothTicketServerTicketForget) {
SendReceive();
}
TEST_P(TlsConnectGeneric, ConnectWithExpiredTicketAtClient) {
TEST_P(TlsConnectGenericResumption, ConnectWithExpiredTicketAtClient) {
SSLInt_SetTicketLifetime(1); // one second
// This causes a ticket resumption.
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
@ -397,7 +397,7 @@ TEST_P(TlsConnectTls13, TestTls13ResumeDifferentGroup) {
server_->ConfigNamedGroups(kFFDHEGroups);
Connect();
CheckKeys(ssl_kea_dh, ssl_grp_ffdhe_2048, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
}
// We need to enable different cipher suites at different times in the following
@ -417,7 +417,7 @@ static uint16_t ChooseAnotherCipher(uint16_t version) {
}
// Test that we don't resume when we can't negotiate the same cipher.
TEST_P(TlsConnectGeneric, TestResumeClientDifferentCipher) {
TEST_P(TlsConnectGenericResumption, TestResumeClientDifferentCipher) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
client_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
@ -442,7 +442,7 @@ TEST_P(TlsConnectGeneric, TestResumeClientDifferentCipher) {
}
// Test that we don't resume when we can't negotiate the same cipher.
TEST_P(TlsConnectGeneric, TestResumeServerDifferentCipher) {
TEST_P(TlsConnectGenericResumption, TestResumeServerDifferentCipher) {
ConfigureSessionCache(RESUME_BOTH, RESUME_TICKET);
server_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
@ -572,7 +572,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionTwice) {
Connect();
SendReceive();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
// The filter will go away when we reset, so save the captured extension.
DataBuffer initialTicket(c1->extension());
ASSERT_LT(0U, initialTicket.len());
@ -590,7 +590,7 @@ TEST_F(TlsConnectTest, TestTls13ResumptionTwice) {
Connect();
SendReceive();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
ASSERT_LT(0U, c2->extension().len());
ScopedCERTCertificate cert2(SSL_PeerCertificate(client_->ssl_fd()));
@ -845,13 +845,13 @@ TEST_F(TlsConnectTest, TestTls13ResumptionForcedDowngrade) {
server_->CheckErrorCode(SSL_ERROR_BAD_MAC_READ);
}
TEST_P(TlsConnectGeneric, ReConnectTicket) {
TEST_P(TlsConnectGenericResumption, ReConnectTicket) {
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
server_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
SendReceive();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
// Resume
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
@ -859,7 +859,7 @@ TEST_P(TlsConnectGeneric, ReConnectTicket) {
Connect();
// Only the client knows this.
CheckKeysResumption(ssl_kea_ecdh, ssl_grp_none, ssl_grp_ec_curve25519,
ssl_auth_rsa_sign, ssl_sig_rsa_pss_sha256);
ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
}
TEST_P(TlsConnectGenericPre13, ReConnectCache) {
@ -868,22 +868,22 @@ TEST_P(TlsConnectGenericPre13, ReConnectCache) {
Connect();
SendReceive();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
// Resume
Reset();
ExpectResumption(RESUME_SESSIONID);
Connect();
CheckKeysResumption(ssl_kea_ecdh, ssl_grp_none, ssl_grp_ec_curve25519,
ssl_auth_rsa_sign, ssl_sig_rsa_pss_sha256);
ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
}
TEST_P(TlsConnectGeneric, ReConnectAgainTicket) {
TEST_P(TlsConnectGenericResumption, ReConnectAgainTicket) {
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
server_->EnableSingleCipher(ChooseOneCipher(version_));
Connect();
SendReceive();
CheckKeys(ssl_kea_ecdh, ssl_grp_ec_curve25519, ssl_auth_rsa_sign,
ssl_sig_rsa_pss_sha256);
ssl_sig_rsa_pss_rsae_sha256);
// Resume
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
@ -891,7 +891,7 @@ TEST_P(TlsConnectGeneric, ReConnectAgainTicket) {
Connect();
// Only the client knows this.
CheckKeysResumption(ssl_kea_ecdh, ssl_grp_none, ssl_grp_ec_curve25519,
ssl_auth_rsa_sign, ssl_sig_rsa_pss_sha256);
ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
// Resume connection again
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
@ -899,7 +899,119 @@ TEST_P(TlsConnectGeneric, ReConnectAgainTicket) {
Connect();
// Only the client knows this.
CheckKeysResumption(ssl_kea_ecdh, ssl_grp_none, ssl_grp_ec_curve25519,
ssl_auth_rsa_sign, ssl_sig_rsa_pss_sha256);
ssl_auth_rsa_sign, ssl_sig_rsa_pss_rsae_sha256);
}
void CheckGetInfoResult(uint32_t alpnSize, uint32_t earlyDataSize,
ScopedCERTCertificate& cert,
ScopedSSLResumptionTokenInfo& token) {
ASSERT_TRUE(cert);
ASSERT_TRUE(token->peerCert);
// Check that the server cert is the correct one.
ASSERT_EQ(cert->derCert.len, token->peerCert->derCert.len);
EXPECT_EQ(0, memcmp(cert->derCert.data, token->peerCert->derCert.data,
cert->derCert.len));
ASSERT_EQ(alpnSize, token->alpnSelectionLen);
EXPECT_EQ(0, memcmp("a", token->alpnSelection, token->alpnSelectionLen));
ASSERT_EQ(earlyDataSize, token->maxEarlyDataSize);
}
TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfo) {
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
Connect();
SendReceive();
Reset();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
ExpectResumption(RESUME_TICKET);
StartConnect();
ASSERT_TRUE(client_->MaybeSetResumptionToken());
// Get resumption token infos
SSLResumptionTokenInfo tokenInfo = {0};
ScopedSSLResumptionTokenInfo token(&tokenInfo);
client_->GetTokenInfo(token);
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
CheckGetInfoResult(0, 0, cert, token);
Handshake();
CheckConnected();
SendReceive();
}
TEST_P(TlsConnectGenericResumptionToken, ConnectResumeGetInfoAlpn) {
EnableAlpn();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
Connect();
CheckAlpn("a");
SendReceive();
Reset();
EnableAlpn();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
ExpectResumption(RESUME_TICKET);
StartConnect();
ASSERT_TRUE(client_->MaybeSetResumptionToken());
// Get resumption token infos
SSLResumptionTokenInfo tokenInfo = {0};
ScopedSSLResumptionTokenInfo token(&tokenInfo);
client_->GetTokenInfo(token);
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
CheckGetInfoResult(1, 0, cert, token);
Handshake();
CheckConnected();
CheckAlpn("a");
SendReceive();
}
TEST_P(TlsConnectTls13ResumptionToken, ConnectResumeGetInfoZeroRtt) {
EnableAlpn();
SSLInt_RolloverAntiReplay();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
server_->Set0RttEnabled(true);
Connect();
CheckAlpn("a");
SendReceive();
Reset();
EnableAlpn();
ConfigureSessionCache(RESUME_BOTH, RESUME_BOTH);
ExpectResumption(RESUME_TICKET);
StartConnect();
server_->Set0RttEnabled(true);
client_->Set0RttEnabled(true);
ASSERT_TRUE(client_->MaybeSetResumptionToken());
// Get resumption token infos
SSLResumptionTokenInfo tokenInfo = {0};
ScopedSSLResumptionTokenInfo token(&tokenInfo);
client_->GetTokenInfo(token);
ScopedCERTCertificate cert(
PK11_FindCertFromNickname(server_->name().c_str(), nullptr));
CheckGetInfoResult(1, 1024, cert, token);
ZeroRttSendReceive(true, true);
Handshake();
ExpectEarlyDataAccepted(true);
CheckConnected();
CheckAlpn("a");
SendReceive();
}
} // namespace nss_test

View File

@ -73,7 +73,8 @@ TlsAgent::TlsAgent(const std::string& name, Role role,
handshake_callback_(),
auth_certificate_callback_(),
sni_callback_(),
skip_version_checks_(false) {
skip_version_checks_(false),
resumption_token_() {
memset(&info_, 0, sizeof(info_));
memset(&csinfo_, 0, sizeof(csinfo_));
SECStatus rv = SSL_VersionRangeGetDefault(variant_, &vrange_);
@ -207,6 +208,29 @@ bool TlsAgent::EnsureTlsSetup(PRFileDesc* modelSocket) {
return true;
}
bool TlsAgent::MaybeSetResumptionToken() {
if (!resumption_token_.empty()) {
SECStatus rv = SSL_SetResumptionToken(ssl_fd(), resumption_token_.data(),
resumption_token_.size());
// rv is SECFailure with error set to SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR
// if the resumption token was bad (expired/malformed/etc.).
if (expect_resumption_) {
// Only in case we expect resumption this has to be successful. We might
// not expect resumption due to some reason but the token is totally fine.
EXPECT_EQ(SECSuccess, rv);
}
if (rv != SECSuccess) {
EXPECT_EQ(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR, PORT_GetError());
resumption_token_.clear();
EXPECT_FALSE(expect_resumption_);
if (expect_resumption_) return false;
}
}
return true;
}
void TlsAgent::SetupClientAuth() {
EXPECT_TRUE(EnsureTlsSetup());
ASSERT_EQ(CLIENT, role_);
@ -386,6 +410,26 @@ void TlsAgent::SetVersionRange(uint16_t minver, uint16_t maxver) {
}
}
SECStatus ResumptionTokenCallback(PRFileDesc* fd,
const PRUint8* resumptionToken,
unsigned int len, void* ctx) {
EXPECT_NE(nullptr, resumptionToken);
if (!resumptionToken) {
return SECFailure;
}
std::vector<uint8_t> new_token(resumptionToken, resumptionToken + len);
reinterpret_cast<TlsAgent*>(ctx)->SetResumptionToken(new_token);
return SECSuccess;
}
void TlsAgent::SetResumptionTokenCallback() {
EXPECT_TRUE(EnsureTlsSetup());
SECStatus rv =
SSL_SetResumptionTokenCallback(ssl_fd(), ResumptionTokenCallback, this);
EXPECT_EQ(SECSuccess, rv);
}
void TlsAgent::GetVersionRange(uint16_t* minver, uint16_t* maxver) {
*minver = vrange_.min;
*maxver = vrange_.max;

View File

@ -165,6 +165,20 @@ class TlsAgent : public PollTarget {
void DisableECDHEServerKeyReuse();
bool GetPeerChainLength(size_t* count);
void CheckCipherSuite(uint16_t cipher_suite);
void SetResumptionTokenCallback();
bool MaybeSetResumptionToken();
void SetResumptionToken(const std::vector<uint8_t>& resumption_token) {
resumption_token_ = resumption_token;
}
const std::vector<uint8_t>& GetResumptionToken() const {
return resumption_token_;
}
void GetTokenInfo(ScopedSSLResumptionTokenInfo& token) {
SECStatus rv = SSL_GetResumptionTokenInfo(
resumption_token_.data(), resumption_token_.size(), token.get(),
sizeof(SSLResumptionTokenInfo));
ASSERT_EQ(SECSuccess, rv);
}
const std::string& name() const { return name_; }
@ -393,6 +407,7 @@ class TlsAgent : public PollTarget {
AuthCertificateCallbackFunction auth_certificate_callback_;
SniCallbackFunction sni_callback_;
bool skip_version_checks_;
std::vector<uint8_t> resumption_token_;
};
inline std::ostream& operator<<(std::ostream& stream,

View File

@ -230,7 +230,9 @@ void TlsConnectTestBase::Reset() {
void TlsConnectTestBase::Reset(const std::string& server_name,
const std::string& client_name) {
auto token = client_->GetResumptionToken();
client_.reset(new TlsAgent(client_name, TlsAgent::CLIENT, variant_));
client_->SetResumptionToken(token);
server_.reset(new TlsAgent(server_name, TlsAgent::SERVER, variant_));
if (skip_version_checks_) {
client_->SkipVersionChecks();
@ -290,6 +292,7 @@ void TlsConnectTestBase::EnableExtendedMasterSecret() {
void TlsConnectTestBase::Connect() {
server_->StartConnect(server_model_ ? server_model_->ssl_fd() : nullptr);
client_->StartConnect(client_model_ ? client_model_->ssl_fd() : nullptr);
client_->MaybeSetResumptionToken();
Handshake();
CheckConnected();
}
@ -402,13 +405,13 @@ void TlsConnectTestBase::CheckKeys(SSLKEAType kea_type,
break;
case ssl_auth_rsa_sign:
if (version_ >= SSL_LIBRARY_VERSION_TLS_1_2) {
scheme = ssl_sig_rsa_pss_sha256;
scheme = ssl_sig_rsa_pss_rsae_sha256;
} else {
scheme = ssl_sig_rsa_pkcs1_sha256;
}
break;
case ssl_auth_rsa_pss:
scheme = ssl_sig_rsa_pss_sha256;
scheme = ssl_sig_rsa_pss_rsae_sha256;
break;
case ssl_auth_ecdsa:
scheme = ssl_sig_ecdsa_secp256r1_sha256;
@ -670,7 +673,8 @@ void TlsConnectTestBase::ZeroRttSendReceive(
EXPECT_EQ(k0RttDataLen, rv);
} else {
EXPECT_EQ(SECFailure, rv);
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError());
EXPECT_EQ(PR_WOULD_BLOCK_ERROR, PORT_GetError())
<< "Unexpected error: " << PORT_ErrorToName(PORT_GetError());
}
// Do a second read. this should fail.
@ -754,6 +758,16 @@ TlsConnectTls12Plus::TlsConnectTls12Plus()
TlsConnectTls13::TlsConnectTls13()
: TlsConnectTestBase(GetParam(), SSL_LIBRARY_VERSION_TLS_1_3) {}
TlsConnectGenericResumption::TlsConnectGenericResumption()
: TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())),
external_cache_(std::get<2>(GetParam())) {}
TlsConnectTls13ResumptionToken::TlsConnectTls13ResumptionToken()
: TlsConnectTestBase(GetParam(), SSL_LIBRARY_VERSION_TLS_1_3) {}
TlsConnectGenericResumptionToken::TlsConnectGenericResumptionToken()
: TlsConnectTestBase(std::get<0>(GetParam()), std::get<1>(GetParam())) {}
void TlsKeyExchangeTest::EnsureKeyShareSetup() {
EnsureTlsSetup();
groups_capture_ =

View File

@ -55,7 +55,7 @@ class TlsConnectTestBase : public ::testing::Test {
// Clear the server session cache.
void ClearServerCache();
// Make sure TLS is configured for a connection.
void EnsureTlsSetup();
virtual void EnsureTlsSetup();
// Reset and keep the same certificate names
void Reset();
// Reset, and update the certificate names on both peers
@ -208,6 +208,50 @@ class TlsConnectGeneric : public TlsConnectTestBase,
TlsConnectGeneric();
};
class TlsConnectGenericResumption
: public TlsConnectTestBase,
public ::testing::WithParamInterface<
std::tuple<SSLProtocolVariant, uint16_t, bool>> {
private:
bool external_cache_;
public:
TlsConnectGenericResumption();
virtual void EnsureTlsSetup() {
TlsConnectTestBase::EnsureTlsSetup();
// Enable external resumption token cache.
if (external_cache_) {
client_->SetResumptionTokenCallback();
}
}
};
class TlsConnectTls13ResumptionToken
: public TlsConnectTestBase,
public ::testing::WithParamInterface<SSLProtocolVariant> {
public:
TlsConnectTls13ResumptionToken();
virtual void EnsureTlsSetup() {
TlsConnectTestBase::EnsureTlsSetup();
client_->SetResumptionTokenCallback();
}
};
class TlsConnectGenericResumptionToken
: public TlsConnectTestBase,
public ::testing::WithParamInterface<
std::tuple<SSLProtocolVariant, uint16_t>> {
public:
TlsConnectGenericResumptionToken();
virtual void EnsureTlsSetup() {
TlsConnectTestBase::EnsureTlsSetup();
client_->SetResumptionTokenCallback();
}
};
// A Pre TLS 1.2 generic test.
class TlsConnectPre12 : public TlsConnectTestBase,
public ::testing::WithParamInterface<

View File

@ -37,6 +37,8 @@ NSS build tool options:
--msan do an msan build
--sancov do sanitize coverage builds
--sancov=func sets coverage to function level for example
--emit-llvm emit LLVM bitcode while building
(requires the gold linker, use clang-3.8 for SAW)
--disable-tests don't build tests and corresponding cmdline utils
--system-sqlite use system sqlite
--no-zdefs don't set -Wl,-z,defs

View File

@ -343,7 +343,7 @@ CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert,
/* First, see if it is already a temp cert */
c = NSSCryptoContext_FindCertificateByEncodedCertificate(gCC,
&encoding);
if (!c) {
if (!c && handle) {
/* Then, see if it is already a perm cert */
c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle,
&encoding);

View File

@ -33,6 +33,8 @@ nssSlot_Destroy(
if (PR_ATOMIC_DECREMENT(&slot->base.refCount) == 0) {
PK11_FreeSlot(slot->pk11slot);
PZ_DestroyLock(slot->base.lock);
PZ_DestroyCondVar(slot->isPresentCondition);
PZ_DestroyLock(slot->isPresentLock);
return nssArena_Destroy(slot->base.arena);
}
}
@ -117,35 +119,61 @@ nssSlot_IsTokenPresent(
nssSession *session;
CK_SLOT_INFO slotInfo;
void *epv;
PRBool isPresent = PR_FALSE;
/* permanent slots are always present unless they're disabled */
if (nssSlot_IsPermanent(slot)) {
return !PK11_IsDisabled(slot->pk11slot);
}
/* avoid repeated calls to check token status within set interval */
if (within_token_delay_period(slot)) {
return ((slot->ckFlags & CKF_TOKEN_PRESENT) != 0);
}
/* First obtain the slot info */
/* avoid repeated calls to check token status within set interval */
PZ_Lock(slot->isPresentLock);
if (within_token_delay_period(slot)) {
CK_FLAGS ckFlags = slot->ckFlags;
PZ_Unlock(slot->isPresentLock);
return ((ckFlags & CKF_TOKEN_PRESENT) != 0);
}
PZ_Unlock(slot->isPresentLock);
/* First obtain the slot epv before we set up the condition
* variable, so we can just return if we couldn't get it. */
epv = slot->epv;
if (!epv) {
return PR_FALSE;
}
/* set up condition so only one thread is active in this part of the code at a time */
PZ_Lock(slot->isPresentLock);
while (slot->inIsPresent) {
PR_WaitCondVar(slot->isPresentCondition, 0);
}
/* if we were one of multiple threads here, the first thread will have
* given us the answer, no need to make more queries of the token. */
if (within_token_delay_period(slot)) {
CK_FLAGS ckFlags = slot->ckFlags;
PZ_Unlock(slot->isPresentLock);
return ((ckFlags & CKF_TOKEN_PRESENT) != 0);
}
/* this is the winning thread, block all others until we've determined
* if the token is present and that it needs initialization. */
slot->inIsPresent = PR_TRUE;
PZ_Unlock(slot->isPresentLock);
nssSlot_EnterMonitor(slot);
ckrv = CKAPI(epv)->C_GetSlotInfo(slot->slotID, &slotInfo);
nssSlot_ExitMonitor(slot);
if (ckrv != CKR_OK) {
slot->token->base.name[0] = 0; /* XXX */
slot->lastTokenPing = PR_IntervalNow();
return PR_FALSE;
isPresent = PR_FALSE;
goto done;
}
slot->ckFlags = slotInfo.flags;
/* check for the presence of the token */
if ((slot->ckFlags & CKF_TOKEN_PRESENT) == 0) {
if (!slot->token) {
/* token was never present */
slot->lastTokenPing = PR_IntervalNow();
return PR_FALSE;
isPresent = PR_FALSE;
goto done;
}
session = nssToken_GetDefaultSession(slot->token);
if (session) {
@ -167,15 +195,15 @@ nssSlot_IsTokenPresent(
slot->token->base.name[0] = 0; /* XXX */
/* clear the token cache */
nssToken_Remove(slot->token);
slot->lastTokenPing = PR_IntervalNow();
return PR_FALSE;
isPresent = PR_FALSE;
goto done;
}
/* token is present, use the session info to determine if the card
* has been removed and reinserted.
*/
session = nssToken_GetDefaultSession(slot->token);
if (session) {
PRBool isPresent = PR_FALSE;
PRBool tokenRemoved;
nssSession_EnterMonitor(session);
if (session->handle != CK_INVALID_SESSION) {
CK_SESSION_INFO sessionInfo;
@ -187,12 +215,12 @@ nssSlot_IsTokenPresent(
session->handle = CK_INVALID_SESSION;
}
}
isPresent = session->handle != CK_INVALID_SESSION;
tokenRemoved = (session->handle == CK_INVALID_SESSION);
nssSession_ExitMonitor(session);
/* token not removed, finished */
if (isPresent) {
slot->lastTokenPing = PR_IntervalNow();
return PR_TRUE;
if (!tokenRemoved) {
isPresent = PR_TRUE;
goto done;
}
}
/* the token has been removed, and reinserted, or the slot contains
@ -203,15 +231,27 @@ nssSlot_IsTokenPresent(
nssToken_Remove(slot->token);
/* token has been removed, need to refresh with new session */
nssrv = nssSlot_Refresh(slot);
isPresent = PR_TRUE;
if (nssrv != PR_SUCCESS) {
slot->token->base.name[0] = 0; /* XXX */
slot->ckFlags &= ~CKF_TOKEN_PRESENT;
/* TODO: insert a barrier here to avoid reordering of the assingments */
slot->lastTokenPing = PR_IntervalNow();
return PR_FALSE;
isPresent = PR_FALSE;
}
done:
/* Once we've set up the condition variable,
* Before returning, it's necessary to:
* 1) Set the lastTokenPing time so that any other threads waiting on this
* initialization and any future calls within the initialization window
* return the just-computed status.
* 2) Indicate we're complete, waking up all other threads that may still
* be waiting on initialization can progress.
*/
PZ_Lock(slot->isPresentLock);
slot->lastTokenPing = PR_IntervalNow();
return PR_TRUE;
slot->inIsPresent = PR_FALSE;
PR_NotifyAllCondVar(slot->isPresentCondition);
PZ_Unlock(slot->isPresentLock);
return isPresent;
}
NSS_IMPLEMENT void *
@ -229,7 +269,7 @@ nssSlot_GetToken(
if (nssSlot_IsTokenPresent(slot)) {
/* Even if a token should be present, check `slot->token` too as it
* might be gone already. This would happen mostly on shutdown. */
* might be gone already. This would happen mostly on shutdown. */
nssSlot_EnterMonitor(slot);
if (slot->token)
rvToken = nssToken_AddRef(slot->token);

View File

@ -81,6 +81,9 @@ struct NSSSlotStr {
PZLock *lock;
void *epv;
PK11SlotInfo *pk11slot;
PZLock *isPresentLock;
PRCondVar *isPresentCondition;
PRBool inIsPresent;
};
struct nssSessionStr {

View File

@ -22,12 +22,12 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define NSS_VERSION "3.35" _NSS_CUSTOMIZED
#define NSS_VERSION "3.36" _NSS_CUSTOMIZED " Beta"
#define NSS_VMAJOR 3
#define NSS_VMINOR 35
#define NSS_VMINOR 36
#define NSS_VPATCH 0
#define NSS_VBUILD 0
#define NSS_BETA PR_FALSE
#define NSS_BETA PR_TRUE
#ifndef RC_INVOKED

View File

@ -120,6 +120,9 @@ nssSlot_CreateFromPK11SlotInfo(NSSTrustDomain *td, PK11SlotInfo *nss3slot)
/* Grab the slot name from the PKCS#11 fixed-length buffer */
rvSlot->base.name = nssUTF8_Duplicate(nss3slot->slot_name, td->arena);
rvSlot->lock = (nss3slot->isThreadSafe) ? NULL : nss3slot->sessionLock;
rvSlot->isPresentLock = PZ_NewLock(nssiLockOther);
rvSlot->isPresentCondition = PR_NewCondVar(rvSlot->isPresentLock);
rvSlot->inIsPresent = PR_FALSE;
return rvSlot;
}

View File

@ -17,11 +17,11 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define SOFTOKEN_VERSION "3.35" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VERSION "3.36" SOFTOKEN_ECC_STRING " Beta"
#define SOFTOKEN_VMAJOR 3
#define SOFTOKEN_VMINOR 35
#define SOFTOKEN_VMINOR 36
#define SOFTOKEN_VPATCH 0
#define SOFTOKEN_VBUILD 0
#define SOFTOKEN_BETA PR_FALSE
#define SOFTOKEN_BETA PR_TRUE
#endif /* _SOFTKVER_H_ */

View File

@ -540,3 +540,6 @@ ER3(SSL_ERROR_RX_MALFORMED_KEY_UPDATE, (SSL_ERROR_BASE + 170),
ER3(SSL_ERROR_TOO_MANY_KEY_UPDATES, (SSL_ERROR_BASE + 171),
"SSL attempted too many key updates.")
ER3(SSL_ERROR_HANDSHAKE_FAILED, (SSL_ERROR_BASE + 172),
"SSL handshake has already failed. No more operations possible.")

View File

@ -192,75 +192,71 @@ ssl_SelfEncryptUnprotectInt(
const PRUint8 *in, unsigned int inLen,
PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen)
{
unsigned char *encodedKeyName;
unsigned char *iv;
SECItem ivItem = { siBuffer, NULL, 0 };
SECItem inItem = { siBuffer, (unsigned char *)in, inLen };
unsigned char *cipherText;
PRUint32 cipherTextLen;
unsigned char *encodedMac;
unsigned char computedMac[SHA256_LENGTH];
unsigned int computedMacLen;
unsigned int bytesToMac;
SECStatus rv;
sslReader reader = SSL_READER(in, inLen);
rv = ssl3_ConsumeFromItem(&inItem, &encodedKeyName,
SELF_ENCRYPT_KEY_NAME_LEN);
sslReadBuffer encodedKeyNameBuffer = { 0 };
SECStatus rv = sslRead_Read(&reader, SELF_ENCRYPT_KEY_NAME_LEN,
&encodedKeyNameBuffer);
if (rv != SECSuccess) {
return SECFailure;
}
rv = ssl3_ConsumeFromItem(&inItem, &iv, AES_BLOCK_SIZE);
sslReadBuffer ivBuffer = { 0 };
rv = sslRead_Read(&reader, AES_BLOCK_SIZE, &ivBuffer);
if (rv != SECSuccess) {
return SECFailure;
}
rv = ssl3_ConsumeNumberFromItem(&inItem, &cipherTextLen, 2);
PRUint64 cipherTextLen = 0;
rv = sslRead_ReadNumber(&reader, 2, &cipherTextLen);
if (rv != SECSuccess) {
return SECFailure;
}
rv = ssl3_ConsumeFromItem(&inItem, &cipherText, cipherTextLen);
sslReadBuffer cipherTextBuffer = { 0 };
rv = sslRead_Read(&reader, (unsigned int)cipherTextLen, &cipherTextBuffer);
if (rv != SECSuccess) {
return SECFailure;
}
bytesToMac = inItem.data - in;
unsigned int bytesToMac = reader.offset;
rv = ssl3_ConsumeFromItem(&inItem, &encodedMac, SHA256_LENGTH);
sslReadBuffer encodedMacBuffer = { 0 };
rv = sslRead_Read(&reader, SHA256_LENGTH, &encodedMacBuffer);
if (rv != SECSuccess) {
return SECFailure;
}
/* Make sure we're at the end of the block. */
if (inItem.len) {
if (reader.offset != reader.buf.len) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
/* Now that everything is decoded, we can make progress. */
/* 1. Check that we have the right key. */
if (PORT_Memcmp(keyName, encodedKeyName, SELF_ENCRYPT_KEY_NAME_LEN)) {
if (PORT_Memcmp(keyName, encodedKeyNameBuffer.buf, SELF_ENCRYPT_KEY_NAME_LEN)) {
PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
return SECFailure;
}
/* 2. Check the MAC */
unsigned char computedMac[SHA256_LENGTH];
unsigned int computedMacLen = 0;
rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, in, bytesToMac,
computedMac, &computedMacLen, sizeof(computedMac));
if (rv != SECSuccess) {
return SECFailure;
}
PORT_Assert(computedMacLen == SHA256_LENGTH);
if (NSS_SecureMemcmp(computedMac, encodedMac, computedMacLen) != 0) {
if (NSS_SecureMemcmp(computedMac, encodedMacBuffer.buf, computedMacLen) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
/* 3. OK, it verifies, now decrypt. */
ivItem.data = iv;
ivItem.len = AES_BLOCK_SIZE;
SECItem ivItem = { siBuffer, (unsigned char *)ivBuffer.buf, AES_BLOCK_SIZE };
rv = PK11_Decrypt(encKey, CKM_AES_CBC_PAD, &ivItem,
out, outLen, maxOutLen, cipherText, cipherTextLen);
out, outLen, maxOutLen, cipherTextBuffer.buf, cipherTextLen);
if (rv != SECSuccess) {
return SECFailure;
}

View File

@ -183,9 +183,9 @@ static const SSLSignatureScheme defaultSignatureSchemes[] = {
ssl_sig_ecdsa_secp384r1_sha384,
ssl_sig_ecdsa_secp521r1_sha512,
ssl_sig_ecdsa_sha1,
ssl_sig_rsa_pss_sha256,
ssl_sig_rsa_pss_sha384,
ssl_sig_rsa_pss_sha512,
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,
@ -852,7 +852,7 @@ ssl3_config_match_init(sslSocket *ss)
* enabled, has a certificate (as needed), has a viable key agreement method, is
* usable with the negotiated TLS version, and is otherwise usable. */
static PRBool
config_match(const ssl3CipherSuiteCfg *suite, int policy,
config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy,
const SSLVersionRange *vrange, const sslSocket *ss)
{
const ssl3CipherSuiteDef *cipher_def;
@ -888,7 +888,7 @@ config_match(const ssl3CipherSuiteCfg *suite, int policy,
/* Return the number of cipher suites that are usable. */
/* called from ssl3_SendClientHello */
static unsigned int
count_cipher_suites(sslSocket *ss, int policy)
count_cipher_suites(sslSocket *ss, PRUint8 policy)
{
unsigned int i, count = 0;
@ -2336,6 +2336,11 @@ ssl3_SendRecord(sslSocket *ss,
if (ss->ssl3.fatalAlertSent) {
SSL_TRC(3, ("%d: SSL3[%d] Suppress write, fatal alert already sent",
SSL_GETPID(), ss->fd));
if (type != content_alert) {
/* If we are sending an alert, then we already have an
* error, so don't overwrite. */
PORT_SetError(SSL_ERROR_HANDSHAKE_FAILED);
}
return SECFailure;
}
@ -2647,9 +2652,7 @@ ssl3_HandleNoCertificate(sslSocket *ss)
(ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE))) {
PRFileDesc *lower;
if (!ss->opt.noCache) {
ss->sec.uncache(ss->sec.ci.sid);
}
ssl_UncacheSessionID(ss);
SSL3_SendAlert(ss, alert_fatal, bad_certificate);
lower = ss->fd->lower;
@ -2711,8 +2714,8 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc)
ssl_GetSSL3HandshakeLock(ss);
}
if (level == alert_fatal) {
if (!ss->opt.noCache && ss->sec.ci.sid) {
ss->sec.uncache(ss->sec.ci.sid);
if (ss->sec.ci.sid) {
ssl_UncacheSessionID(ss);
}
}
@ -2976,9 +2979,7 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf)
}
}
if (level == alert_fatal) {
if (!ss->opt.noCache) {
ss->sec.uncache(ss->sec.ci.sid);
}
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
@ -3962,17 +3963,20 @@ ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme)
return ssl_hash_sha1;
case ssl_sig_rsa_pkcs1_sha256:
case ssl_sig_ecdsa_secp256r1_sha256:
case ssl_sig_rsa_pss_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_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_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:
@ -3994,9 +3998,12 @@ ssl_SignatureSchemeToKeyType(SSLSignatureScheme scheme)
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_rsa_pkcs1_sha512:
case ssl_sig_rsa_pkcs1_sha1:
case ssl_sig_rsa_pss_sha256:
case ssl_sig_rsa_pss_sha384:
case ssl_sig_rsa_pss_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_rsa_pkcs1_sha1md5:
return rsaKey;
case ssl_sig_ecdsa_secp256r1_sha256:
@ -4131,9 +4138,9 @@ ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme)
case ssl_sig_rsa_pkcs1_sha256:
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_rsa_pkcs1_sha512:
case ssl_sig_rsa_pss_sha256:
case ssl_sig_rsa_pss_sha384:
case ssl_sig_rsa_pss_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_ecdsa_secp256r1_sha256:
case ssl_sig_ecdsa_secp384r1_sha384:
case ssl_sig_ecdsa_secp521r1_sha512:
@ -4145,6 +4152,9 @@ ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme)
return PR_TRUE;
case ssl_sig_rsa_pkcs1_sha1md5:
case ssl_sig_rsa_pss_pss_sha256:
case ssl_sig_rsa_pss_pss_sha384:
case ssl_sig_rsa_pss_pss_sha512:
case ssl_sig_none:
case ssl_sig_ed25519:
case ssl_sig_ed448:
@ -4157,9 +4167,9 @@ PRBool
ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme)
{
switch (scheme) {
case ssl_sig_rsa_pss_sha256:
case ssl_sig_rsa_pss_sha384:
case ssl_sig_rsa_pss_sha512:
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:
@ -4589,13 +4599,24 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
}
}
/* 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 = (ss->opt.noCache) ? NULL
: ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, ss->url);
/* 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 = ss->sec.ci.sid;
SSL_TRC(3, ("%d: SSL3[%d]: using external resumption token in ClientHello",
SSL_GETPID(), ss->fd));
} 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(&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 ...
@ -4686,7 +4707,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
if (!sidOK) {
SSL_AtomicIncrementLong(&ssl3stats.sch_sid_cache_not_ok);
ss->sec.uncache(sid);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@ -5017,7 +5038,7 @@ ssl3_HandleHelloRequest(sslSocket *ss)
}
if (sid) {
ss->sec.uncache(sid);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
ss->sec.ci.sid = NULL;
}
@ -6592,7 +6613,7 @@ ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes,
/* throw the old one away */
sid->u.ssl3.keys.resumable = PR_FALSE;
ss->sec.uncache(sid);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
/* get a new sid */
@ -7502,8 +7523,6 @@ ssl3_NewSessionID(sslSocket *ss, PRBool is_server)
sid->u.ssl3.keys.resumable = PR_TRUE;
sid->u.ssl3.policy = SSL_ALLOWED;
sid->u.ssl3.clientWriteKey = NULL;
sid->u.ssl3.serverWriteKey = NULL;
sid->u.ssl3.keys.extendedMasterSecretUsed = PR_FALSE;
if (is_server) {
@ -8102,6 +8121,9 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
rv = ssl3_HandleParsedExtensions(ss, ssl_hs_client_hello);
ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
if (rv != SECSuccess) {
if (PORT_GetError() == SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM) {
errCode = SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM;
}
goto loser; /* malformed */
}
@ -8229,7 +8251,7 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
!ss->firstHsDone))) {
SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_not_ok);
ss->sec.uncache(sid);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@ -8435,7 +8457,7 @@ cipher_found:
}
if (ss->sec.ci.sid) {
ss->sec.uncache(ss->sec.ci.sid);
ssl_UncacheSessionID(ss);
PORT_Assert(ss->sec.ci.sid != sid); /* should be impossible, but ... */
if (ss->sec.ci.sid != sid) {
ssl_FreeSID(ss->sec.ci.sid);
@ -8531,7 +8553,7 @@ cipher_found:
if (sid) { /* we had a sid, but it's no longer valid, free it */
ss->statelessResume = PR_FALSE;
SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_not_ok);
ss->sec.uncache(sid);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@ -8597,7 +8619,7 @@ alert_loser:
/* FALLTHRU */
loser:
if (sid && sid != ss->sec.ci.sid) {
ss->sec.uncache(sid);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
}
@ -11137,6 +11159,7 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, PK11SymKey *secret)
if (ss->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
ss->xtnData.nextProto.data) {
SECITEM_FreeItem(&sid->u.ssl3.alpnSelection, PR_FALSE);
if (SECITEM_CopyItem(
NULL, &sid->u.ssl3.alpnSelection, &ss->xtnData.nextProto) != SECSuccess) {
return SECFailure; /* error already set. */
@ -11166,7 +11189,7 @@ ssl3_FinishHandshake(sslSocket *ss)
* the handshake is finished (we have verified the server's Finished
* AND the server's certificate) before we update the ticket in the sid.
*
* This must be done before we call ss->sec.cache(ss->sec.ci.sid)
* This must be done before we call ssl_CacheSessionID(ss)
* because CacheSID requires the session ticket to already be set, and also
* because of the lazy lock creation scheme used by CacheSID and
* ssl3_SetSIDSessionTicket.
@ -11181,7 +11204,7 @@ ssl3_FinishHandshake(sslSocket *ss)
if (ss->ssl3.hs.cacheSID) {
PORT_Assert(ss->sec.ci.sid->cached == never_cached);
ss->sec.cache(ss->sec.ci.sid);
ssl_CacheSessionID(ss);
ss->ssl3.hs.cacheSID = PR_FALSE;
}
@ -12645,8 +12668,8 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache)
}
if (sid && flushCache) {
ss->sec.uncache(sid); /* remove it from whichever cache it's in. */
ssl_FreeSID(sid); /* dec ref count and free if zero. */
ssl_UncacheSessionID(ss); /* remove it from whichever cache it's in. */
ssl_FreeSID(sid); /* dec ref count and free if zero. */
ss->sec.ci.sid = NULL;
}

View File

@ -519,6 +519,8 @@ ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message)
}
/* Fall through. */
case tls13_extension_disallowed:
SSL_TRC(3, ("%d: TLS13: unexpected extension %d in message %d",
SSL_GETPID(), extension, message));
tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION,
unsupported_extension);
return SECFailure;

View File

@ -182,7 +182,7 @@ ssl3_ClientSendSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData,
/* Never send an extension with a ticket for TLS 1.3, but
* OK to send the empty one in case the server does 1.2. */
if (sid->cached == in_client_cache &&
if ((sid->cached == in_client_cache || sid->cached == in_external_cache) &&
sid->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
return SECSuccess;
}
@ -1219,6 +1219,7 @@ ssl_CreateSIDFromTicket(sslSocket *ss, const SECItem *rawTicket,
}
}
if (parsedTicket->alpnSelection.data != NULL) {
SECITEM_FreeItem(&sid->u.ssl3.alpnSelection, PR_FALSE);
rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.alpnSelection,
&parsedTicket->alpnSelection);
if (rv != SECSuccess) {
@ -1245,7 +1246,7 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket,
SECStatus rv;
if (ss->sec.ci.sid != NULL) {
ss->sec.uncache(ss->sec.ci.sid);
ssl_UncacheSessionID(ss);
ssl_FreeSID(ss->sec.ci.sid);
ss->sec.ci.sid = NULL;
}
@ -1652,11 +1653,16 @@ ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
&xtnData->sigSchemes,
&xtnData->numSigSchemes,
&data->data, &data->len);
if (rv != SECSuccess || xtnData->numSigSchemes == 0) {
if (rv != SECSuccess) {
ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
return SECFailure;
}
if (xtnData->numSigSchemes == 0) {
ssl3_ExtSendAlert(ss, alert_fatal, handshake_failure);
PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
return SECFailure;
}
/* Check for trailing data. */
if (data->len != 0) {
ssl3_ExtSendAlert(ss, alert_fatal, decode_error);

View File

@ -386,6 +386,13 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
SSL3Ciphertext cText;
PRBool keepGoing = PR_TRUE;
if (ss->ssl3.fatalAlertSent) {
SSL_TRC(3, ("%d: SSL3[%d] Cannot gather data; fatal alert already sent",
SSL_GETPID(), ss->fd));
PORT_SetError(SSL_ERROR_HANDSHAKE_FAILED);
return SECFailure;
}
SSL_TRC(30, ("%d: SSL3[%d]: ssl3_GatherCompleteHandshake",
SSL_GETPID(), ss->fd));

View File

@ -119,13 +119,12 @@ ssl_CheckConfigSanity(sslSocket *ss)
SECStatus
ssl_BeginClientHandshake(sslSocket *ss)
{
sslSessionID *sid;
sslSessionID *sid = NULL;
SECStatus rv;
PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
ss->sec.isServer = PR_FALSE;
ssl_ChooseSessionIDProcs(&ss->sec);
rv = ssl_CheckConfigSanity(ss);
if (rv != SECSuccess)
@ -156,19 +155,22 @@ ssl_BeginClientHandshake(sslSocket *ss)
SSL_TRC(3, ("%d: SSL[%d]: sending client-hello", SSL_GETPID(), ss->fd));
/* Try to find server in our session-id cache */
if (ss->opt.noCache) {
sid = NULL;
} else {
/* If there's an sid set from an external cache, use it. */
if (ss->sec.ci.sid && ss->sec.ci.sid->cached == in_external_cache) {
sid = ss->sec.ci.sid;
SSL_TRC(3, ("%d: SSL[%d]: using external token", SSL_GETPID(), ss->fd));
} else if (!ss->opt.noCache) {
/* Try to find server in our session-id cache */
sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID,
ss->url);
}
if (sid) {
if (sid->version >= ss->vrange.min && sid->version <= ss->vrange.max) {
PORT_Assert(!ss->sec.localCert);
ss->sec.localCert = CERT_DupCertificate(sid->localCert);
} else {
ss->sec.uncache(sid);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@ -218,7 +220,6 @@ ssl_BeginServerHandshake(sslSocket *ss)
ss->sec.isServer = PR_TRUE;
ss->ssl3.hs.ws = wait_client_hello;
ssl_ChooseSessionIDProcs(&ss->sec);
rv = ssl_CheckConfigSanity(ss);
if (rv != SECSuccess)

View File

@ -29,6 +29,7 @@ ssl_EncodeUintX(PRUint8 *to, PRUint64 value, unsigned int bytes)
SECStatus
sslBuffer_Grow(sslBuffer *b, unsigned int newLen)
{
PORT_Assert(b);
if (b->fixed) {
PORT_Assert(newLen <= b->space);
if (newLen > b->space) {
@ -84,6 +85,7 @@ sslBuffer_AppendVariable(sslBuffer *b, const PRUint8 *data, unsigned int len,
unsigned int size)
{
PORT_Assert(size <= 4 && size > 0);
PORT_Assert(b);
if (len >= (1ULL << (8 * size))) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@ -95,7 +97,11 @@ sslBuffer_AppendVariable(sslBuffer *b, const PRUint8 *data, unsigned int len,
ssl_EncodeUintX(SSL_BUFFER_NEXT(b), len, size);
b->len += size;
PORT_Memcpy(SSL_BUFFER_NEXT(b), data, len);
if (len != 0) {
PORT_Assert(data);
/* We sometimes pass NULL, 0 and memcpy() doesn't want NULL. */
PORT_Memcpy(SSL_BUFFER_NEXT(b), data, len);
}
b->len += len;
return SECSuccess;
}
@ -169,37 +175,63 @@ sslBuffer_Clear(sslBuffer *b)
}
SECStatus
ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, unsigned int size)
sslRead_Read(sslReader *reader, unsigned int count, sslReadBuffer *out)
{
if (size > item->len) {
if (!reader || !out) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (reader->buf.len < reader->offset ||
count > SSL_READER_REMAINING(reader)) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
*buf = item->data;
item->data += size;
item->len -= size;
out->buf = SSL_READER_CURRENT(reader);
out->len = count;
reader->offset += count;
return SECSuccess;
}
SECStatus
ssl3_ConsumeNumberFromItem(SECItem *item, PRUint32 *num, unsigned int size)
sslRead_ReadVariable(sslReader *reader, unsigned int sizeLen, sslReadBuffer *out)
{
int i;
if (size > item->len || size > sizeof(*num)) {
PRUint64 variableLen = 0;
SECStatus rv = sslRead_ReadNumber(reader, sizeLen, &variableLen);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
if (!variableLen) {
// It is ok to have an empty variable.
out->len = variableLen;
return SECSuccess;
}
return sslRead_Read(reader, variableLen, out);
}
*num = 0;
for (i = 0; i < size; i++) {
*num = (*num << 8) + item->data[i];
SECStatus
sslRead_ReadNumber(sslReader *reader, unsigned int bytes, PRUint64 *num)
{
if (!reader || !num) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (reader->buf.len < reader->offset ||
bytes > SSL_READER_REMAINING(reader) ||
bytes > 8) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
unsigned int i;
PRUint64 number = 0;
for (i = 0; i < bytes; i++) {
number = (number << 8) + reader->buf.buf[i + reader->offset];
}
item->data += size;
item->len -= size;
reader->offset = reader->offset + bytes;
*num = number;
return SECSuccess;
}

View File

@ -47,13 +47,6 @@ SECStatus sslBuffer_InsertLength(sslBuffer *b, unsigned int at,
unsigned int size);
void sslBuffer_Clear(sslBuffer *b);
/* All of these functions modify the underlying SECItem, and so should
* be performed on a shallow copy.*/
SECStatus ssl3_ConsumeFromItem(SECItem *item,
PRUint8 **buf, unsigned int size);
SECStatus ssl3_ConsumeNumberFromItem(SECItem *item,
PRUint32 *num, unsigned int size);
SECStatus ssl3_AppendHandshake(sslSocket *ss, const void *void_src,
unsigned int bytes);
SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss,
@ -66,4 +59,27 @@ SECStatus ssl3_AppendBufferToHandshake(sslSocket *ss, sslBuffer *buf);
SECStatus ssl3_AppendBufferToHandshakeVariable(sslSocket *ss, sslBuffer *buf,
unsigned int lenSize);
typedef struct {
const PRUint8 *buf;
unsigned int len;
} sslReadBuffer;
typedef struct {
sslReadBuffer buf;
unsigned int offset;
} sslReader;
#define SSL_READER(b, l) \
{ \
{ b, l }, 0 \
}
#define SSL_READER_CURRENT(r) \
((r)->buf.buf + (r)->offset)
#define SSL_READER_REMAINING(r) \
((r)->buf.len - (r)->offset)
SECStatus sslRead_Read(sslReader *reader, unsigned int count,
sslReadBuffer *out);
SECStatus sslRead_ReadVariable(sslReader *reader, unsigned int sizeLen,
sslReadBuffer *out);
SECStatus sslRead_ReadNumber(sslReader *reader, unsigned int bytes,
PRUint64 *val);
#endif /* __sslencode_h_ */

View File

@ -260,6 +260,8 @@ typedef enum {
SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE = (SSL_ERROR_BASE + 169),
SSL_ERROR_RX_MALFORMED_KEY_UPDATE = (SSL_ERROR_BASE + 170),
SSL_ERROR_TOO_MANY_KEY_UPDATES = (SSL_ERROR_BASE + 171),
SSL_ERROR_HANDSHAKE_FAILED = (SSL_ERROR_BASE + 172),
SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR = (SSL_ERROR_BASE + 173),
SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */
} SSLErrorCodes;
#endif /* NO_SECURITY_ERROR_ENUM */

View File

@ -350,8 +350,103 @@ typedef SSLHelloRetryRequestAction(PR_CALLBACK *SSLHelloRetryRequestCallback)(
(PRFileDesc * _fd, PRBool _requestUpdate), \
(fd, requestUpdate))
#define SSL_UseAltServerHelloType(fd, enable) \
SSL_DEPRECATED_EXPERIMENTAL_API
/*
* Session cache API.
*/
/*
* Information that can be retrieved about a resumption token.
* See SSL_GetResumptionTokenInfo for details about how to use this API.
* Note that peerCert points to a certificate in the NSS database and must be
* copied by the application if it should be used after NSS shutdown or after
* calling SSL_DestroyResumptionTokenInfo.
*/
typedef struct SSLResumptionTokenInfoStr {
PRUint16 length;
CERTCertificate *peerCert;
PRUint8 *alpnSelection;
PRUint32 alpnSelectionLen;
PRUint32 maxEarlyDataSize;
} SSLResumptionTokenInfo;
/*
* Allows applications to retrieve information about a resumption token.
* This does not require a TLS session.
*
* - The |tokenData| argument is a pointer to the resumption token as byte array
* of length |tokenLen|.
* - The |token| argument is a pointer to a SSLResumptionTokenInfo struct of
* of |len|. The struct gets filled by this function.
* See SSL_DestroyResumptionTokenInfo for information about how to manage the
* |token| memory.
*/
#define SSL_GetResumptionTokenInfo(tokenData, tokenLen, token, len) \
SSL_EXPERIMENTAL_API("SSL_GetResumptionTokenInfo", \
(const PRUint8 *_tokenData, unsigned int _tokenLen, \
SSLResumptionTokenInfo *_token, PRUintn _len), \
(tokenData, tokenLen, token, len))
/*
* SSL_GetResumptionTokenInfo allocates memory in order to populate |tokenInfo|.
* Any SSLResumptionTokenInfo struct filled with SSL_GetResumptionTokenInfo
* has to be freed with SSL_DestroyResumptionTokenInfo.
*/
#define SSL_DestroyResumptionTokenInfo(tokenInfo) \
SSL_EXPERIMENTAL_API( \
"SSL_DestroyResumptionTokenInfo", \
(SSLResumptionTokenInfo * _tokenInfo), \
(tokenInfo))
/*
* This is the function signature for function pointers used as resumption
* token callback. The caller has to copy the memory at |resumptionToken| with
* length |len| before returning.
*
* - The |fd| argument is the socket file descriptor.
* - The |resumptionToken| is a pointer to the resumption token as byte array
* of length |len|.
* - The |ctx| is a void pointer to the context set by the application in
* SSL_SetResumptionTokenCallback.
*/
typedef SECStatus(PR_CALLBACK *SSLResumptionTokenCallback)(
PRFileDesc *fd, const PRUint8 *resumptionToken, unsigned int len,
void *ctx);
/*
* This allows setting a callback for external session caches to store
* resumption tokens.
*
* - The |fd| argument is the socket file descriptor.
* - The |cb| is a function pointer to an implementation of
* SSLResumptionTokenCallback.
* - The |ctx| is a pointer to some application specific context, which is
* returned when |cb| is called.
*/
#define SSL_SetResumptionTokenCallback(fd, cb, ctx) \
SSL_EXPERIMENTAL_API( \
"SSL_SetResumptionTokenCallback", \
(PRFileDesc * _fd, SSLResumptionTokenCallback _cb, void *_ctx), \
(fd, cb, ctx))
/*
* This allows setting a resumption token for a session.
* The function returns SECSuccess iff the resumption token can be used,
* SECFailure in any other case. The caller should remove the |token| from its
* cache when the function returns SECFailure.
*
* - The |fd| argument is the socket file descriptor.
* - The |token| is a pointer to the resumption token as byte array
* of length |len|.
*/
#define SSL_SetResumptionToken(fd, token, len) \
SSL_EXPERIMENTAL_API( \
"SSL_SetResumptionToken", \
(PRFileDesc * _fd, const PRUint8 *_token, const unsigned int _len), \
(fd, token, len))
/* Deprecated experimental APIs */
#define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API
SEC_END_PROTOS

View File

@ -168,8 +168,11 @@ struct ssl3CertNodeStr {
typedef SECStatus (*sslHandshakeFunc)(sslSocket *ss);
typedef void (*sslSessionIDCacheFunc)(sslSessionID *sid);
typedef void (*sslSessionIDUncacheFunc)(sslSessionID *sid);
void ssl_CacheSessionID(sslSocket *ss);
void ssl_UncacheSessionID(sslSocket *ss);
void ssl_ServerCacheSessionID(sslSessionID *sid);
void ssl_ServerUncacheSessionID(sslSessionID *sid);
typedef sslSessionID *(*sslSessionIDLookupFunc)(const PRIPv6Addr *addr,
unsigned char *sid,
unsigned int sidLen,
@ -341,9 +344,11 @@ struct sslGatherStr {
#define GS_HEADER 1
#define GS_DATA 2
#define WRAPPED_MASTER_SECRET_SIZE 48
typedef struct {
PRUint8 wrapped_master_secret[48];
PRUint16 wrapped_master_secret_len;
PRUint8 wrapped_master_secret[WRAPPED_MASTER_SECRET_SIZE];
PRUint8 wrapped_master_secret_len;
PRUint8 resumable;
PRUint8 extendedMasterSecretUsed;
} ssl3SidKeys; /* 52 bytes */
@ -351,7 +356,8 @@ typedef struct {
typedef enum { never_cached,
in_client_cache,
in_server_cache,
invalid_cache /* no longer in any cache. */
invalid_cache, /* no longer in any cache. */
in_external_cache
} Cached;
#include "sslcert.h"
@ -398,17 +404,11 @@ struct sslSessionIDStr {
PRUint8 sessionID[SSL3_SESSIONID_BYTES];
ssl3CipherSuite cipherSuite;
int policy;
PRUint8 policy;
ssl3SidKeys keys;
/* mechanism used to wrap master secret */
CK_MECHANISM_TYPE masterWrapMech;
/* The following values are NOT restored from the server's on-disk
* session cache, but are restored from the client's cache.
*/
PK11SymKey *clientWriteKey;
PK11SymKey *serverWriteKey;
/* The following values pertain to the slot that wrapped the
** master secret. (used only in client)
*/
@ -740,7 +740,7 @@ struct ssl3StateStr {
CERTCertificateList *clientCertChain; /* used by client */
PRBool sendEmptyCert; /* used by client */
int policy;
PRUint8 policy;
/* This says what cipher suites we can do, and should
* be either SSL_ALLOWED or SSL_RESTRICTED
*/
@ -897,14 +897,6 @@ struct sslSecurityInfoStr {
/* The selected certificate (for servers only). */
const sslServerCert *serverCert;
/*
** Procs used for SID cache (nonce) management.
** Different implementations exist for clients/servers
** The lookup proc is only used for servers. Baloney!
*/
sslSessionIDCacheFunc cache;
sslSessionIDUncacheFunc uncache;
/* These are used during a connection handshake */
sslConnectInfo ci;
};
@ -982,6 +974,8 @@ struct sslSocketStr {
SSLHelloRetryRequestCallback hrrCallback;
void *hrrCallbackArg;
PRCList extensionHooks;
SSLResumptionTokenCallback resumptionTokenCallback;
void *resumptionTokenContext;
PRIntervalTime rTimeout; /* timeout for NSPR I/O */
PRIntervalTime wTimeout; /* timeout for NSPR I/O */
@ -1080,8 +1074,6 @@ extern PRUint32 ssl_max_early_data_size;
extern const char *const ssl3_cipherName[];
extern sslSessionIDLookupFunc ssl_sid_lookup;
extern sslSessionIDCacheFunc ssl_sid_cache;
extern sslSessionIDUncacheFunc ssl_sid_uncache;
extern const sslNamedGroupDef ssl_named_groups[];
@ -1163,14 +1155,13 @@ extern SECStatus ssl_BeginClientHandshake(sslSocket *ss);
extern SECStatus ssl_BeginServerHandshake(sslSocket *ss);
extern int ssl_Do1stHandshake(sslSocket *ss);
extern void ssl_ChooseSessionIDProcs(sslSecurityInfo *sec);
extern SECStatus ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret,
PRBool derive);
extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server);
extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port,
const char *peerID, const char *urlSvrName);
extern void ssl_FreeSID(sslSessionID *sid);
extern void ssl_DestroySID(sslSessionID *sid, PRBool freeIt);
extern int ssl3_SendApplicationData(sslSocket *ss, const PRUint8 *in,
int len, int flags);
@ -1692,6 +1683,26 @@ PRBool ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag);
void ssl_Trace(const char *format, ...);
void ssl_CacheExternalToken(sslSocket *ss);
SECStatus ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedTicket,
PRUint32 encodedTicketLen);
PRBool ssl_IsResumptionTokenValid(sslSocket *ss);
/* Remove when stable. */
SECStatus SSLExp_SetResumptionTokenCallback(PRFileDesc *fd,
SSLResumptionTokenCallback cb,
void *ctx);
SECStatus SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token,
unsigned int len);
SECStatus SSLExp_GetResumptionTokenInfo(const PRUint8 *tokenData, unsigned int tokenLen,
SSLResumptionTokenInfo *token, unsigned int version);
SECStatus SSLExp_DestroyResumptionTokenInfo(SSLResumptionTokenInfo *token);
#define SSLResumptionTokenVersion 1
SEC_END_PROTOS
#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)

View File

@ -15,6 +15,7 @@
static int ssl_isInited = 0;
static PRCallOnceType ssl_init = { 0 };
PR_STATIC_ASSERT(sizeof(unsigned long) <= sizeof(PRUint64));
PRStatus
ssl_InitCallOnce(void *arg)

View File

@ -15,6 +15,7 @@
#include "sslimpl.h"
#include "sslproto.h"
#include "nssilock.h"
#include "sslencode.h"
#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)
#include <time.h>
#endif
@ -24,12 +25,13 @@ PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
static sslSessionID *cache = NULL;
static PZLock *cacheLock = NULL;
/* sids can be in one of 4 states:
/* sids can be in one of 5 states:
*
* never_cached, created, but not yet put into cache.
* in_client_cache, in the client cache's linked list.
* in_server_cache, entry came from the server's cache file.
* invalid_cache has been removed from the cache.
* in_external_cache sid comes from an external cache.
*/
#define LOCK_CACHE lock_cache()
@ -164,8 +166,8 @@ lock_cache(void)
/* BEWARE: This function gets called for both client and server SIDs !!
* If the unreferenced sid is not in the cache, Free sid and its contents.
*/
static void
ssl_DestroySID(sslSessionID *sid)
void
ssl_DestroySID(sslSessionID *sid, PRBool freeIt)
{
SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached));
PORT_Assert(sid->references == 0);
@ -186,11 +188,8 @@ ssl_DestroySID(sslSessionID *sid)
PR_DestroyRWLock(sid->u.ssl3.lock);
}
if (sid->peerID != NULL)
PORT_Free((void *)sid->peerID); /* CONST */
if (sid->urlSvrName != NULL)
PORT_Free((void *)sid->urlSvrName); /* CONST */
PORT_Free((void *)sid->peerID);
PORT_Free((void *)sid->urlSvrName);
if (sid->peerCert) {
CERT_DestroyCertificate(sid->peerCert);
@ -205,7 +204,9 @@ ssl_DestroySID(sslSessionID *sid)
SECITEM_FreeItem(&sid->u.ssl3.alpnSelection, PR_FALSE);
PORT_ZFree(sid, sizeof(sslSessionID));
if (freeIt) {
PORT_ZFree(sid, sizeof(sslSessionID));
}
}
/* BEWARE: This function gets called for both client and server SIDs !!
@ -220,7 +221,7 @@ ssl_FreeLockedSID(sslSessionID *sid)
{
PORT_Assert(sid->references >= 1);
if (--sid->references == 0) {
ssl_DestroySID(sid);
ssl_DestroySID(sid, PR_TRUE);
}
}
@ -306,6 +307,7 @@ ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
static void
CacheSID(sslSessionID *sid)
{
PORT_Assert(sid);
PORT_Assert(sid->cached == never_cached);
SSL_TRC(8, ("SSL: Cache: sid=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
@ -400,7 +402,7 @@ UncacheSID(sslSessionID *zap)
/* If sid "zap" is in the cache,
* removes sid from cache, and decrements reference count.
* Although this function is static, it is called externally via
* ss->sec.uncache().
* ssl_UncacheSessionID.
*/
static void
LockAndUncacheSID(sslSessionID *zap)
@ -410,16 +412,758 @@ LockAndUncacheSID(sslSessionID *zap)
UNLOCK_CACHE;
}
/* choose client or server cache functions for this sslsocket. */
void
ssl_ChooseSessionIDProcs(sslSecurityInfo *sec)
SECStatus
ReadVariableFromBuffer(sslReader *reader, sslReadBuffer *readerBuffer,
uint8_t lenBytes, SECItem *dest)
{
if (sec->isServer) {
sec->cache = ssl_sid_cache;
sec->uncache = ssl_sid_uncache;
if (sslRead_ReadVariable(reader, lenBytes, readerBuffer) != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (readerBuffer->len) {
SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer->buf,
readerBuffer->len };
SECITEM_CopyItem(NULL, dest, &tempItem);
}
return SECSuccess;
}
/* Fill sid with the values from the encoded resumption token.
* sid has to be allocated.
* We don't care about locks here as this cache entry is externally stored.
*/
SECStatus
ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedToken,
PRUint32 encodedTokenLen)
{
PORT_Assert(encodedTokenLen);
PORT_Assert(encodedToken);
PORT_Assert(sid);
if (!sid || !encodedToken || !encodedTokenLen) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (encodedToken[0] != SSLResumptionTokenVersion) {
/* Unknown token format version. */
PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
return SECFailure;
}
/* These variables are used across macros. Don't use them outside. */
sslReader reader = SSL_READER(encodedToken, encodedTokenLen);
reader.offset += 1; // We read the version already. Skip the first byte.
sslReadBuffer readerBuffer = { 0 };
PRUint64 tmpInt = 0;
if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->lastAccessTime = (PRTime)tmpInt;
if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->expirationTime = (PRTime)tmpInt;
if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.locked.sessionTicket.received_timestamp = (PRTime)tmpInt;
if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.locked.sessionTicket.ticket_lifetime_hint = (PRUint32)tmpInt;
if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.locked.sessionTicket.flags = (PRUint32)tmpInt;
if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.locked.sessionTicket.ticket_age_add = (PRUint32)tmpInt;
if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.locked.sessionTicket.max_early_data_size = (PRUint32)tmpInt;
if (sslRead_ReadVariable(&reader, 3, &readerBuffer) != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (readerBuffer.len) {
PORT_Assert(!sid->peerCert);
SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer.buf,
readerBuffer.len };
sid->peerCert = CERT_NewTempCertificate(NULL, /* dbHandle */
&tempItem,
NULL, PR_FALSE, PR_TRUE);
if (!sid->peerCert) {
return SECFailure;
}
}
if (sslRead_ReadVariable(&reader, 2, &readerBuffer) != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (readerBuffer.len) {
SECITEM_AllocArray(NULL, &sid->peerCertStatus, 1);
if (!sid->peerCertStatus.items) {
return SECFailure;
}
SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer.buf,
readerBuffer.len };
SECITEM_CopyItem(NULL, &sid->peerCertStatus.items[0], &tempItem);
}
if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (readerBuffer.len) {
sid->peerID = PORT_Strdup((const char *)readerBuffer.buf);
}
if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (readerBuffer.len) {
if (sid->urlSvrName) {
PORT_Free((void *)sid->urlSvrName);
}
sid->urlSvrName = PORT_Strdup((const char *)readerBuffer.buf);
}
if (sslRead_ReadVariable(&reader, 3, &readerBuffer) != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (readerBuffer.len) {
PORT_Assert(!sid->localCert);
SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer.buf,
readerBuffer.len };
sid->localCert = CERT_NewTempCertificate(NULL, /* dbHandle */
&tempItem,
NULL, PR_FALSE, PR_TRUE);
}
if (sslRead_ReadNumber(&reader, 8, &sid->addr.pr_s6_addr64[0]) != SECSuccess) {
return SECFailure;
}
if (sslRead_ReadNumber(&reader, 8, &sid->addr.pr_s6_addr64[1]) != SECSuccess) {
return SECFailure;
}
if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->port = (PRUint16)tmpInt;
if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->version = (PRUint16)tmpInt;
if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->creationTime = (PRTime)tmpInt;
if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->authType = (SSLAuthType)tmpInt;
if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->authKeyBits = (PRUint32)tmpInt;
if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->keaType = (SSLKEAType)tmpInt;
if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->keaKeyBits = (PRUint32)tmpInt;
if (sslRead_ReadNumber(&reader, 3, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->keaGroup = (SSLNamedGroup)tmpInt;
if (sslRead_ReadNumber(&reader, 3, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->sigScheme = (SSLSignatureScheme)tmpInt;
if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.sessionIDLength = (PRUint8)tmpInt;
if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (readerBuffer.len) {
PORT_Memcpy(sid->u.ssl3.sessionID, readerBuffer.buf, readerBuffer.len);
}
if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.cipherSuite = (PRUint16)tmpInt;
if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.policy = (PRUint8)tmpInt;
if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Assert(readerBuffer.len == WRAPPED_MASTER_SECRET_SIZE);
if (readerBuffer.len != WRAPPED_MASTER_SECRET_SIZE) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret, readerBuffer.buf,
readerBuffer.len);
if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.keys.wrapped_master_secret_len = (PRUint8)tmpInt;
if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.keys.extendedMasterSecretUsed = (PRUint8)tmpInt;
if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.masterWrapMech = (unsigned long)tmpInt;
if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.masterModuleID = (unsigned long)tmpInt;
if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.masterSlotID = (unsigned long)tmpInt;
if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.masterWrapIndex = (PRUint32)tmpInt;
if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.masterWrapSeries = (PRUint16)tmpInt;
if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.clAuthModuleID = (unsigned long)tmpInt;
if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.clAuthSlotID = (unsigned long)tmpInt;
if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.clAuthSeries = (PRUint16)tmpInt;
if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.masterValid = (char)tmpInt;
if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
return SECFailure;
}
sid->u.ssl3.clAuthValid = (char)tmpInt;
if (ReadVariableFromBuffer(&reader, &readerBuffer, 1,
&sid->u.ssl3.srvName) != SECSuccess) {
return SECFailure;
}
if (ReadVariableFromBuffer(&reader, &readerBuffer, 2,
&sid->u.ssl3.signedCertTimestamps) != SECSuccess) {
return SECFailure;
}
if (ReadVariableFromBuffer(&reader, &readerBuffer, 1,
&sid->u.ssl3.alpnSelection) != SECSuccess) {
return SECFailure;
}
if (ReadVariableFromBuffer(&reader, &readerBuffer, 2,
&sid->u.ssl3.locked.sessionTicket.ticket) != SECSuccess) {
return SECFailure;
}
if (!sid->u.ssl3.locked.sessionTicket.ticket.len) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* At this point we must have read everything. */
PORT_Assert(reader.offset == reader.buf.len);
if (reader.offset != reader.buf.len) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
return SECSuccess;
}
PRBool
ssl_IsResumptionTokenValid(sslSocket *ss)
{
PORT_Assert(ss);
sslSessionID *sid = ss->sec.ci.sid;
PORT_Assert(sid);
// Check that the ticket didn't expire.
PRTime endTime = 0;
NewSessionTicket *ticket = &sid->u.ssl3.locked.sessionTicket;
if (ticket->ticket_lifetime_hint != 0) {
endTime = ticket->received_timestamp +
(PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC);
if (endTime < ssl_TimeUsec()) {
return PR_FALSE;
}
}
// Check that the session entry didn't expire.
if (sid->expirationTime < ssl_TimeUsec()) {
return PR_FALSE;
}
// Check that the server name (SNI) matches the one set for this session.
// Don't use the token if there's no server name.
if (sid->urlSvrName == NULL || PORT_Strcmp(ss->url, sid->urlSvrName) != 0) {
return PR_FALSE;
}
// This shouldn't be false, but let's check it anyway.
if (!sid->u.ssl3.keys.resumable) {
return PR_FALSE;
}
return PR_TRUE;
}
/* Encode a session ticket into a byte array that can be handed out to a cache.
* Needed memory in encodedToken has to be allocated according to
* *encodedTokenLen. */
static SECStatus
ssl_EncodeResumptionToken(sslSessionID *sid, sslBuffer *encodedTokenBuf)
{
PORT_Assert(encodedTokenBuf);
PORT_Assert(sid);
if (!sid->u.ssl3.locked.sessionTicket.ticket.len || !encodedTokenBuf ||
!sid || !sid->u.ssl3.keys.resumable || !sid->urlSvrName) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* Encoding format:
* 0-byte: version
* Integers are encoded according to their length.
* SECItems are prepended with a 64-bit length field followed by the bytes.
* Optional bytes are encoded as a 0-length item if not present.
*/
SECStatus rv = sslBuffer_AppendNumber(encodedTokenBuf,
SSLResumptionTokenVersion, 1);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->lastAccessTime, 8);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->expirationTime, 8);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
// session ticket
rv = sslBuffer_AppendNumber(encodedTokenBuf,
sid->u.ssl3.locked.sessionTicket.received_timestamp,
8);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf,
sid->u.ssl3.locked.sessionTicket.ticket_lifetime_hint,
4);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf,
sid->u.ssl3.locked.sessionTicket.flags,
4);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf,
sid->u.ssl3.locked.sessionTicket.ticket_age_add,
4);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf,
sid->u.ssl3.locked.sessionTicket.max_early_data_size,
4);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendVariable(encodedTokenBuf, sid->peerCert->derCert.data,
sid->peerCert->derCert.len, 3);
if (rv != SECSuccess) {
return SECFailure;
}
if (sid->peerCertStatus.len > 1) {
/* This is not implemented so it shouldn't happen.
* If it gets implemented, this has to change.
*/
PORT_Assert(0);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
if (sid->peerCertStatus.len == 1 && sid->peerCertStatus.items[0].len) {
rv = sslBuffer_AppendVariable(encodedTokenBuf,
sid->peerCertStatus.items[0].data,
sid->peerCertStatus.items[0].len, 2);
if (rv != SECSuccess) {
return SECFailure;
}
} else {
sec->cache = CacheSID;
sec->uncache = LockAndUncacheSID;
rv = sslBuffer_AppendVariable(encodedTokenBuf, NULL, 0, 2);
if (rv != SECSuccess) {
return SECFailure;
}
}
PRUint64 len = sid->peerID ? strlen(sid->peerID) : 0;
if (len > PR_UINT8_MAX) {
// This string really shouldn't be that long.
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rv = sslBuffer_AppendVariable(encodedTokenBuf,
(const unsigned char *)sid->peerID, len, 1);
if (rv != SECSuccess) {
return SECFailure;
}
len = sid->urlSvrName ? strlen(sid->urlSvrName) : 0;
if (!len) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (len > PR_UINT8_MAX) {
// This string really shouldn't be that long.
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rv = sslBuffer_AppendVariable(encodedTokenBuf,
(const unsigned char *)sid->urlSvrName,
len, 1);
if (rv != SECSuccess) {
return SECFailure;
}
if (sid->localCert) {
rv = sslBuffer_AppendVariable(encodedTokenBuf,
sid->localCert->derCert.data,
sid->localCert->derCert.len, 3);
if (rv != SECSuccess) {
return SECFailure;
}
} else {
rv = sslBuffer_AppendVariable(encodedTokenBuf, NULL, 0, 3);
if (rv != SECSuccess) {
return SECFailure;
}
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->addr.pr_s6_addr64[0], 8);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->addr.pr_s6_addr64[1], 8);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->port, 2);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->version, 2);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->creationTime, 8);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->authType, 2);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->authKeyBits, 4);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->keaType, 2);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->keaKeyBits, 4);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->keaGroup, 3);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->sigScheme, 3);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.sessionIDLength, 1);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendVariable(encodedTokenBuf, sid->u.ssl3.sessionID,
SSL3_SESSIONID_BYTES, 1);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.cipherSuite, 2);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.policy, 1);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendVariable(encodedTokenBuf,
sid->u.ssl3.keys.wrapped_master_secret,
WRAPPED_MASTER_SECRET_SIZE, 1);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf,
sid->u.ssl3.keys.wrapped_master_secret_len,
1);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf,
sid->u.ssl3.keys.extendedMasterSecretUsed,
1);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterWrapMech, 8);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterModuleID, 8);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterSlotID, 8);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterWrapIndex, 4);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterWrapSeries, 2);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.clAuthModuleID, 8);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.clAuthSlotID, 8);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.clAuthSeries, 2);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterValid, 1);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.clAuthValid, 1);
if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
rv = sslBuffer_AppendVariable(encodedTokenBuf, sid->u.ssl3.srvName.data,
sid->u.ssl3.srvName.len, 1);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendVariable(encodedTokenBuf,
sid->u.ssl3.signedCertTimestamps.data,
sid->u.ssl3.signedCertTimestamps.len, 2);
if (rv != SECSuccess) {
return SECFailure;
}
rv = sslBuffer_AppendVariable(encodedTokenBuf,
sid->u.ssl3.alpnSelection.data,
sid->u.ssl3.alpnSelection.len, 1);
if (rv != SECSuccess) {
return SECFailure;
}
PORT_Assert(sid->u.ssl3.locked.sessionTicket.ticket.len > 1);
rv = sslBuffer_AppendVariable(encodedTokenBuf,
sid->u.ssl3.locked.sessionTicket.ticket.data,
sid->u.ssl3.locked.sessionTicket.ticket.len,
2);
if (rv != SECSuccess) {
return SECFailure;
}
return SECSuccess;
}
void
ssl_CacheExternalToken(sslSocket *ss)
{
PORT_Assert(ss);
sslSessionID *sid = ss->sec.ci.sid;
PORT_Assert(sid);
PORT_Assert(sid->cached == never_cached);
PORT_Assert(ss->resumptionTokenCallback);
SSL_TRC(8, ("SSL [%d]: Cache External: sid=0x%x cached=%d "
"addr=0x%08x%08x%08x%08x port=0x%04x time=%x cached=%d",
ss->fd,
sid, sid->cached, sid->addr.pr_s6_addr32[0],
sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2],
sid->addr.pr_s6_addr32[3], sid->port, sid->creationTime,
sid->cached));
/* This is only available for stateless resumption. */
if (sid->u.ssl3.locked.sessionTicket.ticket.data == NULL) {
return;
}
if (!sid->creationTime) {
sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
}
if (!sid->expirationTime) {
sid->expirationTime = sid->creationTime + ssl3_sid_timeout;
}
sslBuffer encodedToken = SSL_BUFFER_EMPTY;
if (ssl_EncodeResumptionToken(sid, &encodedToken) != SECSuccess) {
SSL_TRC(3, ("SSL [%d]: encoding resumption token failed", ss->fd));
return;
}
PORT_Assert(SSL_BUFFER_LEN(&encodedToken) > 0);
PRINT_BUF(40, (ss, "SSL: encoded resumption token",
SSL_BUFFER_BASE(&encodedToken),
SSL_BUFFER_LEN(&encodedToken)));
ss->resumptionTokenCallback(ss->fd, SSL_BUFFER_BASE(&encodedToken),
SSL_BUFFER_LEN(&encodedToken),
ss->resumptionTokenContext);
sslBuffer_Clear(&encodedToken);
}
void
ssl_CacheSessionID(sslSocket *ss)
{
sslSecurityInfo *sec = &ss->sec;
PORT_Assert(sec);
if (sec->ci.sid && !sec->ci.sid->u.ssl3.keys.resumable) {
return;
}
if (!ss->sec.isServer && ss->resumptionTokenCallback) {
ssl_CacheExternalToken(ss);
return;
}
PORT_Assert(!ss->resumptionTokenCallback);
if (sec->isServer) {
ssl_ServerCacheSessionID(sec->ci.sid);
return;
}
CacheSID(sec->ci.sid);
}
void
ssl_UncacheSessionID(sslSocket *ss)
{
if (ss->opt.noCache) {
return;
}
sslSecurityInfo *sec = &ss->sec;
PORT_Assert(sec);
if (sec->isServer) {
ssl_ServerUncacheSessionID(sec->ci.sid);
} else if (!ss->resumptionTokenCallback) {
LockAndUncacheSID(sec->ci.sid);
}
}

View File

@ -599,9 +599,6 @@ ssl_CopySecurityInfo(sslSocket *ss, sslSocket *os)
if (os->sec.peerCert && !ss->sec.peerCert)
goto loser;
ss->sec.cache = os->sec.cache;
ss->sec.uncache = os->sec.uncache;
return SECSuccess;
loser:
@ -1159,7 +1156,7 @@ SSL_InvalidateSession(PRFileDesc *fd)
ssl_GetSSL3HandshakeLock(ss);
if (ss->sec.ci.sid) {
ss->sec.uncache(ss->sec.ci.sid);
ssl_UncacheSessionID(ss);
rv = SECSuccess;
}

View File

@ -495,12 +495,6 @@ ConvertToSID(sidCacheEntry *from,
PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
/* the portions of the SID that are only restored on the client
* are set to invalid values on the server.
*/
to->u.ssl3.clientWriteKey = NULL;
to->u.ssl3.serverWriteKey = NULL;
to->urlSvrName = NULL;
to->u.ssl3.masterModuleID = (SECMODModuleID)-1; /* invalid value */
@ -735,9 +729,11 @@ ServerSessionIDLookup(const PRIPv6Addr *addr,
/*
** Place a sid into the cache, if it isn't already there.
*/
static void
ServerSessionIDCache(sslSessionID *sid)
void
ssl_ServerCacheSessionID(sslSessionID *sid)
{
PORT_Assert(sid);
sidCacheEntry sce;
PRUint32 now = 0;
cacheDesc *cache = &globalCache;
@ -800,8 +796,8 @@ ServerSessionIDCache(sslSessionID *sid)
** Although this is static, it is called from ssl via global function pointer
** ssl_sid_uncache. This invalidates the referenced cache entry.
*/
static void
ServerSessionIDUncache(sslSessionID *sid)
void
ssl_ServerUncacheSessionID(sslSessionID *sid)
{
cacheDesc *cache = &globalCache;
PRUint8 *sessionID;
@ -1172,8 +1168,6 @@ ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
}
ssl_sid_lookup = ServerSessionIDLookup;
ssl_sid_cache = ServerSessionIDCache;
ssl_sid_uncache = ServerSessionIDUncache;
return SECSuccess;
}
@ -1356,8 +1350,6 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char *envString)
ssl_InitSessionCacheLocks(PR_FALSE);
ssl_sid_lookup = ServerSessionIDLookup;
ssl_sid_cache = ServerSessionIDCache;
ssl_sid_uncache = ServerSessionIDUncache;
if (!envString) {
envString = PR_GetEnvSecure(envVarName);

View File

@ -104,8 +104,6 @@ static SSLVersionRange versions_defaults_datagram = {
(variant == ssl_variant_stream ? NSS_TLS_VERSION_MAX_POLICY : NSS_DTLS_VERSION_MAX_POLICY)
sslSessionIDLookupFunc ssl_sid_lookup;
sslSessionIDCacheFunc ssl_sid_cache;
sslSessionIDUncacheFunc ssl_sid_uncache;
static PRDescIdentity ssl_layer_id;
@ -356,6 +354,8 @@ ssl_DupSocket(sslSocket *os)
os->namedGroupPreferences,
sizeof(ss->namedGroupPreferences));
ss->additionalShares = os->additionalShares;
ss->resumptionTokenCallback = os->resumptionTokenCallback;
ss->resumptionTokenContext = os->resumptionTokenContext;
/* Create security data */
rv = ssl_CopySecurityInfo(ss, os);
@ -3933,6 +3933,10 @@ struct {
EXP(KeyUpdate),
EXP(SendSessionTicket),
EXP(SetupAntiReplay),
EXP(SetResumptionTokenCallback),
EXP(SetResumptionToken),
EXP(GetResumptionTokenInfo),
EXP(DestroyResumptionTokenInfo),
#endif
{ "", NULL }
};
@ -3967,3 +3971,156 @@ ssl_ClearPRCList(PRCList *list, void (*f)(void *))
PORT_Free(cursor);
}
}
/* Experimental APIs for session cache handling. */
SECStatus
SSLExp_SetResumptionTokenCallback(PRFileDesc *fd,
SSLResumptionTokenCallback cb,
void *ctx)
{
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetResumptionTokenCallback",
SSL_GETPID(), fd));
return SECFailure;
}
ssl_Get1stHandshakeLock(ss);
ssl_GetSSL3HandshakeLock(ss);
ss->resumptionTokenCallback = cb;
ss->resumptionTokenContext = ctx;
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_Release1stHandshakeLock(ss);
return SECSuccess;
}
SECStatus
SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token,
unsigned int len)
{
sslSocket *ss = ssl_FindSocket(fd);
if (!ss) {
SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetResumptionToken",
SSL_GETPID(), fd));
return SECFailure;
}
ssl_Get1stHandshakeLock(ss);
ssl_GetSSL3HandshakeLock(ss);
if (ss->firstHsDone || ss->ssl3.hs.ws != idle_handshake ||
ss->sec.isServer || len == 0 || !token) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
goto done;
}
// We override any previously set session.
if (ss->sec.ci.sid) {
ssl_FreeSID(ss->sec.ci.sid);
ss->sec.ci.sid = NULL;
}
PRINT_BUF(50, (ss, "incoming resumption token", token, len));
ss->sec.ci.sid = ssl3_NewSessionID(ss, PR_FALSE);
if (!ss->sec.ci.sid) {
goto done;
}
/* Populate NewSessionTicket values */
SECStatus rv = ssl_DecodeResumptionToken(ss->sec.ci.sid, token, len);
if (rv != SECSuccess) {
// If decoding fails, we assume the token is bad.
PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
ssl_FreeSID(ss->sec.ci.sid);
ss->sec.ci.sid = NULL;
goto done;
}
// Make sure that the token is valid.
if (!ssl_IsResumptionTokenValid(ss)) {
ssl_FreeSID(ss->sec.ci.sid);
ss->sec.ci.sid = NULL;
PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
goto done;
}
/* Use the sid->cached as marker that this is from an external cache and
* we don't have to look up anything in the NSS internal cache. */
ss->sec.ci.sid->cached = in_external_cache;
// This has to be 2 to not free this in sendClientHello.
ss->sec.ci.sid->references = 2;
ss->sec.ci.sid->lastAccessTime = ssl_TimeSec();
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_Release1stHandshakeLock(ss);
return SECSuccess;
done:
ssl_ReleaseSSL3HandshakeLock(ss);
ssl_Release1stHandshakeLock(ss);
return SECFailure;
}
SECStatus
SSLExp_DestroyResumptionTokenInfo(SSLResumptionTokenInfo *token)
{
if (!token) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
if (token->peerCert) {
CERT_DestroyCertificate(token->peerCert);
}
PORT_Free(token->alpnSelection);
PORT_Memset(token, 0, token->length);
return SECSuccess;
}
SECStatus
SSLExp_GetResumptionTokenInfo(const PRUint8 *tokenData, unsigned int tokenLen,
SSLResumptionTokenInfo *tokenOut, PRUintn len)
{
if (!tokenData || !tokenOut || !tokenLen ||
len > sizeof(SSLResumptionTokenInfo)) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
sslSessionID sid = { 0 };
SSLResumptionTokenInfo token;
/* Populate sid values */
if (ssl_DecodeResumptionToken(&sid, tokenData, tokenLen) != SECSuccess) {
// If decoding fails, we assume the token is bad.
PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
return SECFailure;
}
token.peerCert = CERT_DupCertificate(sid.peerCert);
token.alpnSelectionLen = sid.u.ssl3.alpnSelection.len;
token.alpnSelection = PORT_ZAlloc(token.alpnSelectionLen);
if (!token.alpnSelection) {
return SECFailure;
}
PORT_Memcpy(token.alpnSelection, sid.u.ssl3.alpnSelection.data,
token.alpnSelectionLen);
if (sid.u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) {
token.maxEarlyDataSize =
sid.u.ssl3.locked.sessionTicket.max_early_data_size;
} else {
token.maxEarlyDataSize = 0;
}
token.length = PR_MIN(sizeof(SSLResumptionTokenInfo), len);
PORT_Memcpy(tokenOut, &token, token.length);
ssl_DestroySID(&sid, PR_FALSE);
return SECSuccess;
}

View File

@ -123,11 +123,14 @@ typedef enum {
ssl_sig_ecdsa_secp256r1_sha256 = 0x0403,
ssl_sig_ecdsa_secp384r1_sha384 = 0x0503,
ssl_sig_ecdsa_secp521r1_sha512 = 0x0603,
ssl_sig_rsa_pss_sha256 = 0x0804,
ssl_sig_rsa_pss_sha384 = 0x0805,
ssl_sig_rsa_pss_sha512 = 0x0806,
ssl_sig_rsa_pss_rsae_sha256 = 0x0804,
ssl_sig_rsa_pss_rsae_sha384 = 0x0805,
ssl_sig_rsa_pss_rsae_sha512 = 0x0806,
ssl_sig_ed25519 = 0x0807,
ssl_sig_ed448 = 0x0808,
ssl_sig_rsa_pss_pss_sha256 = 0x0809,
ssl_sig_rsa_pss_pss_sha384 = 0x080a,
ssl_sig_rsa_pss_pss_sha512 = 0x080b,
ssl_sig_dsa_sha1 = 0x0202,
ssl_sig_dsa_sha256 = 0x0402,
@ -143,20 +146,25 @@ typedef enum {
ssl_sig_rsa_pkcs1_sha1md5 = 0x10101,
} SSLSignatureScheme;
/* Deprecated names maintained only for source compatibility. */
#define ssl_sig_rsa_pss_sha256 ssl_sig_rsa_pss_rsae_sha256
#define ssl_sig_rsa_pss_sha384 ssl_sig_rsa_pss_rsae_sha384
#define ssl_sig_rsa_pss_sha512 ssl_sig_rsa_pss_rsae_sha512
/*
** SSLAuthType describes the type of key that is used to authenticate a
** connection. That is, the type of key in the end-entity certificate.
*/
typedef enum {
ssl_auth_null = 0,
ssl_auth_rsa_decrypt = 1, /* static RSA */
ssl_auth_rsa_decrypt = 1, /* RSA key exchange. */
ssl_auth_dsa = 2,
ssl_auth_kea = 3, /* unused */
ssl_auth_ecdsa = 4,
ssl_auth_ecdh_rsa = 5, /* ECDH cert with an RSA signature */
ssl_auth_ecdh_ecdsa = 6, /* ECDH cert with an ECDSA signature */
ssl_auth_rsa_sign = 7, /* RSA PKCS#1.5 signing */
ssl_auth_rsa_pss = 8,
ssl_auth_ecdh_rsa = 5, /* ECDH cert with an RSA signature. */
ssl_auth_ecdh_ecdsa = 6, /* ECDH cert with an ECDSA signature. */
ssl_auth_rsa_sign = 7, /* RSA signing with an rsaEncryption key. */
ssl_auth_rsa_pss = 8, /* RSA signing with a PSS key. */
ssl_auth_psk = 9,
ssl_auth_tls13_any = 10,
ssl_auth_size /* number of authentication types */

View File

@ -462,7 +462,7 @@ tls13_SetupClientHello(sslSocket *ss)
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
SSL_AtomicIncrementLong(&ssl3stats->sch_sid_cache_not_ok);
ss->sec.uncache(ss->sec.ci.sid);
ssl_UncacheSessionID(ss);
ssl_FreeSID(ss->sec.ci.sid);
ss->sec.ci.sid = NULL;
return SECFailure;
@ -1426,9 +1426,9 @@ ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme)
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_rsa_pkcs1_sha512:
/* We report PSS signatures as being just RSA signatures. */
case ssl_sig_rsa_pss_sha256:
case ssl_sig_rsa_pss_sha384:
case ssl_sig_rsa_pss_sha512:
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_ecdsa_secp256r1_sha256:
case ssl_sig_ecdsa_secp384r1_sha384:
@ -1719,7 +1719,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
}
if (hrr) {
if (sid) { /* Free the sid. */
ss->sec.uncache(sid);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
}
PORT_Assert(ss->ssl3.hs.helloRetry);
@ -1769,8 +1769,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
} else {
if (sid) { /* we had a sid, but it's no longer valid, free it */
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
if (ss->sec.uncache)
ss->sec.uncache(sid);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@ -1830,7 +1829,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
if (sid) {
/* We had a sid, but it's no longer valid, free it. */
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
ss->sec.uncache(sid);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
} else {
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_misses);
@ -1866,7 +1865,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
loser:
if (sid) {
ss->sec.uncache(sid);
ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
}
return SECFailure;
@ -2539,7 +2538,7 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
}
if (sid->cached == in_client_cache) {
/* If we tried to resume and failed, let's not try again. */
ss->sec.uncache(sid);
ssl_UncacheSessionID(ss);
}
}
@ -4681,7 +4680,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
/* Destroy the old SID. */
ss->sec.uncache(ss->sec.ci.sid);
ssl_UncacheSessionID(ss);
ssl_FreeSID(ss->sec.ci.sid);
ss->sec.ci.sid = sid;
}
@ -4707,7 +4706,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
/* Cache the session. */
ss->sec.cache(ss->sec.ci.sid);
ssl_CacheSessionID(ss);
}
return SECSuccess;
@ -4772,9 +4771,6 @@ tls13_ExtensionStatus(PRUint16 extension, SSLHandshakeType message)
/* Return "disallowed" if the message mask bit isn't set. */
if (!(_M(message) & KnownExtensions[i].messages)) {
SSL_TRC(3, ("%d: TLS13: unexpected extension %d in message %d",
SSL_GETPID(), extension, message));
return tls13_extension_disallowed;
}

View File

@ -88,36 +88,37 @@ tls13_RecoverHashState(sslSocket *ss,
{
SECStatus rv;
unsigned char plaintext[1024];
SECItem ptItem = { siBuffer, plaintext, 0 };
unsigned int plaintextLen = 0;
sslBuffer messageBuf = SSL_BUFFER_EMPTY;
PRUint32 sentinel;
PRUint32 cipherSuite;
PRUint32 group;
PRUint64 sentinel;
PRUint64 cipherSuite;
PRUint64 group;
const sslNamedGroupDef *selectedGroup;
PRUint32 appTokenLen;
PRUint8 *appToken;
PRUint64 appTokenLen;
rv = ssl_SelfEncryptUnprotect(ss, cookie, cookieLen,
ptItem.data, &ptItem.len, sizeof(plaintext));
plaintext, &plaintextLen, sizeof(plaintext));
if (rv != SECSuccess) {
return SECFailure;
}
sslReader reader = SSL_READER(plaintext, plaintextLen);
/* Should start with 0xff. */
rv = ssl3_ConsumeNumberFromItem(&ptItem, &sentinel, 1);
rv = sslRead_ReadNumber(&reader, 1, &sentinel);
if ((rv != SECSuccess) || (sentinel != 0xff)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* The cipher suite should be the same or there are some shenanigans. */
rv = ssl3_ConsumeNumberFromItem(&ptItem, &cipherSuite, 2);
rv = sslRead_ReadNumber(&reader, 2, &cipherSuite);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* The named group, if any. */
rv = ssl3_ConsumeNumberFromItem(&ptItem, &group, 2);
rv = sslRead_ReadNumber(&reader, 2, &group);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
@ -126,7 +127,7 @@ tls13_RecoverHashState(sslSocket *ss,
/* Application token. */
PORT_Assert(ss->xtnData.applicationToken.len == 0);
rv = ssl3_ConsumeNumberFromItem(&ptItem, &appTokenLen, 2);
rv = sslRead_ReadNumber(&reader, 2, &appTokenLen);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
@ -137,15 +138,18 @@ tls13_RecoverHashState(sslSocket *ss,
return SECFailure;
}
ss->xtnData.applicationToken.len = appTokenLen;
rv = ssl3_ConsumeFromItem(&ptItem, &appToken, appTokenLen);
sslReadBuffer appTokenReader = { 0 };
rv = sslRead_Read(&reader, appTokenLen, &appTokenReader);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
PORT_Memcpy(ss->xtnData.applicationToken.data, appToken, appTokenLen);
PORT_Assert(appTokenReader.len == appTokenLen);
PORT_Memcpy(ss->xtnData.applicationToken.data, appTokenReader.buf, appTokenLen);
/* The remainder is the hash. */
if (ptItem.len != tls13_GetHashSize(ss)) {
unsigned int hashLen = SSL_READER_REMAINING(&reader);
if (hashLen != tls13_GetHashSize(ss)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
@ -153,7 +157,7 @@ tls13_RecoverHashState(sslSocket *ss,
/* Now reinject the message. */
SSL_ASSERT_HASHES_EMPTY(ss);
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_message_hash, 0,
ptItem.data, ptItem.len);
SSL_READER_CURRENT(&reader), hashLen);
if (rv != SECSuccess) {
return SECFailure;
}

View File

@ -19,12 +19,12 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
*/
#define NSSUTIL_VERSION "3.35"
#define NSSUTIL_VERSION "3.36 Beta"
#define NSSUTIL_VMAJOR 3
#define NSSUTIL_VMINOR 35
#define NSSUTIL_VMINOR 36
#define NSSUTIL_VPATCH 0
#define NSSUTIL_VBUILD 0
#define NSSUTIL_BETA PR_FALSE
#define NSSUTIL_BETA PR_TRUE
SEC_BEGIN_PROTOS

View File

@ -24,7 +24,8 @@ interop_init()
cd "${HOSTDIR}/interop"
INTEROP=${INTEROP:=tls_interop}
if [ ! -d "$INTEROP" ]; then
git clone -q https://github.com/mozilla/tls-interop "$INTEROP"
git clone -q https://github.com/ttaubert/tls-interop "$INTEROP"
git -C "$INTEROP" checkout -q 07930b791827c1bdb6f4c19ca0aa63850fd59e22
fi
INTEROP=$(cd "$INTEROP";pwd -P)