summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/ssl/dtls13con.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/ssl/dtls13con.c')
-rw-r--r--security/nss/lib/ssl/dtls13con.c129
1 files changed, 108 insertions, 21 deletions
diff --git a/security/nss/lib/ssl/dtls13con.c b/security/nss/lib/ssl/dtls13con.c
index 0c4fc7fcd..5307419b6 100644
--- a/security/nss/lib/ssl/dtls13con.c
+++ b/security/nss/lib/ssl/dtls13con.c
@@ -10,38 +10,52 @@
#include "ssl.h"
#include "sslimpl.h"
#include "sslproto.h"
+#include "keyhi.h"
+#include "pk11func.h"
+/*
+ * 0 1 2 3 4 5 6 7
+ * +-+-+-+-+-+-+-+-+
+ * |0|0|1|C|S|L|E E|
+ * +-+-+-+-+-+-+-+-+
+ * | Connection ID | Legend:
+ * | (if any, |
+ * / length as / C - CID present
+ * | negotiated) | S - Sequence number length
+ * +-+-+-+-+-+-+-+-+ L - Length present
+ * | 8 or 16 bit | E - Epoch
+ * |Sequence Number|
+ * +-+-+-+-+-+-+-+-+
+ * | 16 bit Length |
+ * | (if present) |
+ * +-+-+-+-+-+-+-+-+
+ */
SECStatus
-dtls13_InsertCipherTextHeader(const sslSocket *ss, ssl3CipherSpec *cwSpec,
+dtls13_InsertCipherTextHeader(const sslSocket *ss, const ssl3CipherSpec *cwSpec,
sslBuffer *wrBuf, PRBool *needsLength)
{
- PRUint32 seq;
- SECStatus rv;
-
/* Avoid using short records for the handshake. We pack multiple records
* into the one datagram for the handshake. */
if (ss->opt.enableDtlsShortHeader &&
- cwSpec->epoch != TrafficKeyHandshake) {
+ cwSpec->epoch > TrafficKeyHandshake) {
*needsLength = PR_FALSE;
/* The short header is comprised of two octets in the form
- * 0b001essssssssssss where 'e' is the low bit of the epoch and 's' is
- * the low 12 bits of the sequence number. */
- seq = 0x2000 |
- (((uint64_t)cwSpec->epoch & 1) << 12) |
- (cwSpec->nextSeqNum & 0xfff);
- return sslBuffer_AppendNumber(wrBuf, seq, 2);
+ * 0b001000eessssssss where 'e' is the low two bits of the
+ * epoch and 's' is the low 8 bits of the sequence number. */
+ PRUint8 ct = 0x20 | ((uint64_t)cwSpec->epoch & 0x3);
+ if (sslBuffer_AppendNumber(wrBuf, ct, 1) != SECSuccess) {
+ return SECFailure;
+ }
+ PRUint8 seq = cwSpec->nextSeqNum & 0xff;
+ return sslBuffer_AppendNumber(wrBuf, seq, 1);
}
- rv = sslBuffer_AppendNumber(wrBuf, ssl_ct_application_data, 1);
- if (rv != SECSuccess) {
+ PRUint8 ct = 0x2c | ((PRUint8)cwSpec->epoch & 0x3);
+ if (sslBuffer_AppendNumber(wrBuf, ct, 1) != SECSuccess) {
return SECFailure;
}
-
- /* The epoch and sequence number are encoded on 4 octets, with the epoch
- * consuming the first two bits. */
- seq = (((uint64_t)cwSpec->epoch & 3) << 30) | (cwSpec->nextSeqNum & 0x3fffffff);
- rv = sslBuffer_AppendNumber(wrBuf, seq, 4);
- if (rv != SECSuccess) {
+ if (sslBuffer_AppendNumber(wrBuf,
+ (cwSpec->nextSeqNum & 0xffff), 2) != SECSuccess) {
return SECFailure;
}
*needsLength = PR_TRUE;
@@ -171,6 +185,27 @@ dtls13_SendAckCb(sslSocket *ss)
(void)dtls13_SendAck(ss);
}
+/* Limits from draft-ietf-tls-dtls13-38; section 4.5.3. */
+PRBool
+dtls13_AeadLimitReached(ssl3CipherSpec *spec)
+{
+ if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
+ switch (spec->cipherDef->calg) {
+ case ssl_calg_chacha20:
+ case ssl_calg_aes_gcm:
+ return spec->deprotectionFailures >= (1ULL << 36);
+#ifdef UNSAFE_FUZZER_MODE
+ case ssl_calg_null:
+ return PR_FALSE;
+#endif
+ default:
+ PORT_Assert(0);
+ break;
+ }
+ }
+ return PR_FALSE;
+}
+
/* Zero length messages are very simple to check. */
static PRBool
dtls_IsEmptyMessageAcknowledged(sslSocket *ss, PRUint16 msgSeq, PRUint32 offset)
@@ -378,8 +413,7 @@ dtls13_HandleOutOfEpochRecord(sslSocket *ss, const ssl3CipherSpec *spec,
* server, we might have processed the client's Finished and
* moved on to application data keys, but the client has
* retransmitted Finished (e.g., because our ACK got lost.)
- * We just retransmit the previous Finished to let the client
- * complete. */
+ * We just retransmit the ACK to let the client complete. */
if (rType == ssl_ct_handshake) {
if ((ss->sec.isServer) &&
(ss->ssl3.hs.ws == idle_handshake)) {
@@ -512,3 +546,56 @@ dtls13_HolddownTimerCb(sslSocket *ss)
ssl_CipherSpecReleaseByEpoch(ss, ssl_secret_read, TrafficKeyHandshake);
ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL);
}
+
+SECStatus
+dtls13_MaskSequenceNumber(sslSocket *ss, ssl3CipherSpec *spec,
+ PRUint8 *hdr, PRUint8 *cipherText, PRUint32 cipherTextLen)
+{
+ PORT_Assert(IS_DTLS(ss));
+ if (spec->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ return SECSuccess;
+ }
+
+ if (spec->maskContext) {
+#ifdef UNSAFE_FUZZER_MODE
+ /* Use a null mask. */
+ PRUint8 mask[2] = { 0 };
+#else
+ /* "This procedure requires the ciphertext length be at least 16 bytes.
+ * Receivers MUST reject shorter records as if they had failed
+ * deprotection, as described in Section 4.5.2." */
+ if (cipherTextLen < 16) {
+ PORT_SetError(SSL_ERROR_BAD_MAC_READ);
+ return SECFailure;
+ }
+
+ PRUint8 mask[2];
+ SECStatus rv = ssl_CreateMaskInner(spec->maskContext, cipherText, cipherTextLen, mask, sizeof(mask));
+
+ if (rv != SECSuccess) {
+ PORT_SetError(SSL_ERROR_BAD_MAC_READ);
+ return SECFailure;
+ }
+#endif
+
+ hdr[1] ^= mask[0];
+ if (hdr[0] & 0x08) {
+ hdr[2] ^= mask[1];
+ }
+ }
+ return SECSuccess;
+}
+
+CK_MECHANISM_TYPE
+tls13_SequenceNumberEncryptionMechanism(SSLCipherAlgorithm bulkAlgorithm)
+{
+ switch (bulkAlgorithm) {
+ case ssl_calg_aes_gcm:
+ return CKM_AES_ECB;
+ case ssl_calg_chacha20:
+ return CKM_NSS_CHACHA20_CTR;
+ default:
+ PORT_Assert(PR_FALSE);
+ }
+ return CKM_INVALID_MECHANISM;
+}