diff --git a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c index 3f52e59..50348e3 100644 --- a/nss/lib/ssl/ssl3con.c +++ b/nss/lib/ssl/ssl3con.c @@ -2636,12 +2636,21 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, /* Limit length of ciphertext we produce */ PRUint32 ctextLen = TLS13_PAD_FRAGMENT_LENGTH; + if (cwSpec->writeNextLen != 0) { /* length already committed? */ + ctextLen = cwSpec->writeNextLen; /* then abide by it */ + headerLen = 0; /* and go headerless */ + } /* Limit cleartext contentLen accordingly */ PRUint32 thisLen = PR_MIN(contentLen, ctextLen - overhead); + PRUint32 nextLen = contentLen - thisLen; /* left for next record */ *pContentLen = contentLen = thisLen; PRUint32 padLen = ctextLen - contentLen - overhead; + /* The next record can be any multiple of the padding granularity */ + cwSpec->writeNextLen = (nextLen+overhead+TLS13_PAD_FRAGMENT_LENGTH-1) + & ~(+TLS13_PAD_FRAGMENT_LENGTH-1); + /* We must copy input into wrBuf to append the internal trailer */ unsigned char *wrPtr = wrBuf->buf + headerLen + nonceLen; if (pIn != wrPtr) { @@ -2654,7 +2663,9 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, /* Append the TLS 1.3 internal trailer */ unsigned char *trailer = &wrPtr[contentLen]; contentLen += TLS13_RECORD_TRAILER_LENGTH; - trailer[0] = type; /* inner content type */ + trailer[0] = cwSpec->writeNextLen >> 8; + trailer[1] = cwSpec->writeNextLen; + trailer[2] = type; /* inner content type */ PORT_Assert(type != 0); /* must be distinct from padding bytes! */ type = content_application_data; /* fixed outer content type */ @@ -2779,8 +2790,9 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024); wrBuf->len = cipherBytes + headerLen; - wrBuf->buf[0] = type; - if (isDTLS) { + if (headerLen > 0) { + wrBuf->buf[0] = type; + if (isDTLS) { SSL3ProtocolVersion version; version = dtls_TLSVersionToDTLSVersion(cwSpec->version); @@ -2796,7 +2808,7 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, wrBuf->buf[10] = (unsigned char)(cwSpec->write_seq_num.low >> 0); wrBuf->buf[11] = MSB(cipherBytes); wrBuf->buf[12] = LSB(cipherBytes); - } else { + } else { SSL3ProtocolVersion version = cwSpec->version; if (capRecordVersion) { @@ -2806,6 +2818,7 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, wrBuf->buf[2] = LSB(version); wrBuf->buf[3] = MSB(cipherBytes); wrBuf->buf[4] = LSB(cipherBytes); + } } ssl3_BumpSequenceNumber(&cwSpec->write_seq_num); @@ -12255,7 +12268,8 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) /* Decode and strip the internal trailer */ decryptedLen -= TLS13_RECORD_TRAILER_LENGTH; unsigned char *trailer = &plaintext->buf[decryptedLen]; - rType = trailer[0]; + rType = trailer[2]; + ss->gs.readNextLen = (trailer[0] << 8) | trailer[1]; } plaintext->len = decryptedLen; @@ -12525,6 +12539,8 @@ ssl3_InitCipherSpec(sslSocket *ss, ssl3CipherSpec *spec) spec->read_seq_num.high = 0; spec->read_seq_num.low = 0; + spec->writeNextLen = 0; + spec->epoch = 0; dtls_InitRecvdRecords(&spec->recvdRecords); diff --git a/nss/lib/ssl/ssl3gthr.c b/nss/lib/ssl/ssl3gthr.c index 23b9755..63f140e 100644 --- a/nss/lib/ssl/ssl3gthr.c +++ b/nss/lib/ssl/ssl3gthr.c @@ -42,8 +42,19 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags) PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); if (gs->state == GS_INIT) { - gs->state = GS_HEADER; - gs->remainder = 5; + if (gs->readNextLen == 0) { + gs->state = GS_HEADER; + gs->remainder = 5; + } else { /* TLS 1.3: length carried in prior record's trailer */ + gs->state = GS_DATA; + gs->remainder = gs->readNextLen; + if (gs->remainder > gs->inbuf.space) { + err = sslBuffer_Grow(&gs->inbuf, gs->remainder); + if (err) { /* realloc has set error code to no mem. */ + return err; + } + } + } gs->offset = 0; gs->writeOffset = 0; gs->readOffset = 0; diff --git a/nss/lib/ssl/ssl3prot.h b/nss/lib/ssl/ssl3prot.h index cc1f169..c970440 100644 --- a/nss/lib/ssl/ssl3prot.h +++ b/nss/lib/ssl/ssl3prot.h @@ -38,7 +38,7 @@ typedef PRUint16 ssl3CipherSuite; #define MAX_FRAGMENT_LENGTH 16384 /* max payload per record */ /* TLS 1.3 adds a trailer and optional padding in the AEAD-encrypted payload */ -#define TLS13_RECORD_TRAILER_LENGTH 1 /* plus optional padding */ +#define TLS13_RECORD_TRAILER_LENGTH 3 /* plus optional padding */ #define TLS13_PAD_FRAGMENT_LENGTH 256 /* padding granularity */ typedef enum { diff --git a/nss/lib/ssl/sslgathr.c b/nss/lib/ssl/sslgathr.c index bdf470b..5caab67 100644 --- a/nss/lib/ssl/sslgathr.c +++ b/nss/lib/ssl/sslgathr.c @@ -373,6 +373,7 @@ ssl_InitGather(sslGather *gs) gs->state = GS_INIT; gs->writeOffset = 0; gs->readOffset = 0; + gs->readNextLen = 0; gs->dtlsPacketOffset = 0; gs->dtlsPacket.len = 0; status = sslBuffer_Grow(&gs->buf, 4096); diff --git a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h index 16240c3..70878ea 100644 --- a/nss/lib/ssl/sslimpl.h +++ b/nss/lib/ssl/sslimpl.h @@ -407,6 +407,9 @@ struct sslGatherStr { */ unsigned int recordPadding; /* ssl2 only */ + /* TLS 1.3: if nonzero, length of next record carried in prior record */ + PRUint32 readNextLen; + /* plaintext DATA begins this many bytes into "buf". */ unsigned int recordOffset; /* ssl2 only */ @@ -589,6 +592,7 @@ typedef struct { PK11SymKey * master_secret; SSL3SequenceNumber write_seq_num; SSL3SequenceNumber read_seq_num; + PRUint32 writeNextLen; /* TLS 1.3 promised next record len */ SSL3ProtocolVersion version; ssl3KeyMaterial client; ssl3KeyMaterial server;