diff options
Diffstat (limited to 'lib/ssl')
-rw-r--r-- | lib/ssl/manifest.mn | 25 | ||||
-rw-r--r-- | lib/ssl/ssl.gyp | 1 | ||||
-rw-r--r-- | lib/ssl/tls13ech.c | 17 | ||||
-rw-r--r-- | lib/ssl/tls13ech.h | 3 | ||||
-rw-r--r-- | lib/ssl/tls13echv.c | 167 |
5 files changed, 193 insertions, 20 deletions
diff --git a/lib/ssl/manifest.mn b/lib/ssl/manifest.mn index d3e38b85b..fedc42b4e 100644 --- a/lib/ssl/manifest.mn +++ b/lib/ssl/manifest.mn @@ -21,24 +21,32 @@ EXPORTS = \ MODULE = nss CSRCS = \ - dtlscon.c \ + authcert.c \ + cmpcert.c \ dtls13con.c \ + dtlscon.c \ prelib.c \ + selfencrypt.c \ ssl3con.c \ + ssl3ecc.c \ + ssl3ext.c \ + ssl3exthandle.c \ ssl3gthr.c \ sslauth.c \ sslbloom.c \ + sslcert.c \ sslcon.c \ ssldef.c \ sslencode.c \ sslenum.c \ sslerr.c \ sslerrstrs.c \ + sslgrp.c \ + sslinfo.c \ sslinit.c \ - ssl3ext.c \ - ssl3exthandle.c \ sslmutex.c \ sslnonce.c \ + sslprimitive.c \ sslreveal.c \ sslsecur.c \ sslsnce.c \ @@ -46,21 +54,14 @@ CSRCS = \ sslspec.c \ ssltrace.c \ sslver.c \ - authcert.c \ - cmpcert.c \ - selfencrypt.c \ - sslinfo.c \ - ssl3ecc.c \ tls13con.c \ + tls13ech.c \ + tls13echv.c \ tls13exthandle.c \ tls13hashstate.c \ tls13hkdf.c \ tls13psk.c \ tls13replay.c \ - sslcert.c \ - sslgrp.c \ - sslprimitive.c \ - tls13ech.c \ tls13subcerts.c \ $(NULL) diff --git a/lib/ssl/ssl.gyp b/lib/ssl/ssl.gyp index c3c792805..2aa35cc96 100644 --- a/lib/ssl/ssl.gyp +++ b/lib/ssl/ssl.gyp @@ -45,6 +45,7 @@ 'sslver.c', 'tls13con.c', 'tls13ech.c', + 'tls13echv.c', 'tls13exthandle.c', 'tls13hashstate.c', 'tls13hkdf.c', diff --git a/lib/ssl/tls13ech.c b/lib/ssl/tls13ech.c index 1891caf39..ff6a634d8 100644 --- a/lib/ssl/tls13ech.c +++ b/lib/ssl/tls13ech.c @@ -243,11 +243,10 @@ tls13_DecodeEchConfigContents(const sslReadBuffer *rawConfig, PORT_SetError(SSL_ERROR_RX_MALFORMED_ECH_CONFIG); goto loser; } - for (tmpn = 0; tmpn < tmpBuf.len; tmpn++) { - if (tmpBuf.buf[tmpn] == '\0') { - PORT_SetError(SSL_ERROR_RX_MALFORMED_ECH_CONFIG); - goto loser; - } + if (!tls13_IsLDH(tmpBuf.buf, tmpBuf.len) || + tls13_IsIp(tmpBuf.buf, tmpBuf.len)) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_ECH_CONFIG); + goto loser; } contents.publicName = PORT_ZAlloc(tmpBuf.len + 1); @@ -603,9 +602,11 @@ SSLExp_RemoveEchConfigs(PRFileDesc *fd) return SECFailure; } - if (!PR_CLIST_IS_EMPTY(&ss->echConfigs)) { - tls13_DestroyEchConfigs(&ss->echConfigs); - } + SECKEY_DestroyPrivateKey(ss->echPrivKey); + ss->echPrivKey = NULL; + SECKEY_DestroyPublicKey(ss->echPubKey); + ss->echPubKey = NULL; + tls13_DestroyEchConfigs(&ss->echConfigs); /* Also remove any retry_configs and handshake context. */ if (ss->xtnData.ech && ss->xtnData.ech->retryConfigs.len) { diff --git a/lib/ssl/tls13ech.h b/lib/ssl/tls13ech.h index 55abf76ea..83f92a452 100644 --- a/lib/ssl/tls13ech.h +++ b/lib/ssl/tls13ech.h @@ -90,4 +90,7 @@ SECStatus tls13_MaybeAcceptEch(sslSocket *ss, const SECItem *sidBytes, const PRU SECStatus tls13_MaybeGreaseEch(sslSocket *ss, unsigned int prefixLen, sslBuffer *buf); SECStatus tls13_WriteServerEchSignal(sslSocket *ss, PRUint8 *sh, unsigned int shLen); +PRBool tls13_IsIp(const PRUint8 *str, unsigned int len); +PRBool tls13_IsLDH(const PRUint8 *str, unsigned int len); + #endif diff --git a/lib/ssl/tls13echv.c b/lib/ssl/tls13echv.c new file mode 100644 index 000000000..ae9792a91 --- /dev/null +++ b/lib/ssl/tls13echv.c @@ -0,0 +1,167 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* 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/. */ + +/* Validation functions for ECH public names. */ + +#include "seccomon.h" + +/* Convert a single character `c` into a number `*d` with the given radix. + * Fails if the character isn't valid for the radix. + */ +static SECStatus +tls13_IpDigit(PRUint8 c, PRUint8 radix, PRUint8 *d) +{ + PRUint8 v = 0xff; + if (c >= '0' && c <= '9') { + v = c - '0'; + } else if (radix > 10) { + if (c >= 'a' && c <= 'f') { + v = c - 'a'; + } else if (c >= 'A' && c <= 'F') { + v = c - 'A'; + } + } + if (v >= radix) { + return SECFailure; + } + *d = v; + return SECSuccess; +} + +/* This function takes the first couple of characters from `str`, starting at offset + * `*i` and calculates a radix. If it starts with "0x" or "0X", then `*i` is moved up + * by two and `*radix` is set to 16 (hexadecimal). If it starts with "0", then `*i` is + * moved up by one and `*radix` is set to 8 (octal). Otherwise, `*i` is left alone and + * `*radix` is set to 10 (decimal). + * Fails if there are no characters remaining or the next character is '.', either at + * the start or after "0x". + */ +static SECStatus +tls13_IpRadix(const PRUint8 *str, unsigned int len, unsigned int *i, PRUint8 *radix) +{ + if (*i == len || str[*i] == '.') { + return SECFailure; + } + if (str[*i] == '0') { + (*i)++; + if (*i < len && (str[*i] == 'x' || str[*i] == 'X')) { + (*i)++; + if (*i == len || str[*i] == '.') { + return SECFailure; + } + *radix = 16; + } else { + *radix = 8; + } + } else { + *radix = 10; + } + return SECSuccess; +} + +/* Take a number from `str` from offset `*i` and put the value in `*v`. + * This calculates the radix and returns a value between 0 and 2^32-1, using all + * of the digits up to the end of the string (determined by `len`) or a period ('.'). + * Fails if there is no value, if there a non-digit characters, or if the value is + * too large. + */ +static SECStatus +tls13_IpValue(const PRUint8 *str, unsigned int len, unsigned int *i, PRUint32 *v) +{ + PRUint8 radix; + SECStatus rv = tls13_IpRadix(str, len, i, &radix); + if (rv != SECSuccess) { + return SECFailure; + } + PRUint64 part = 0; + while (*i < len) { + PRUint8 d; + rv = tls13_IpDigit(str[*i], radix, &d); + if (rv != SECSuccess) { + if (str[*i] != '.') { + return SECFailure; + } + break; + } + part = part * radix + d; + if (part > PR_UINT32_MAX) { + return SECFailure; + } + (*i)++; + } + *v = part; + return SECSuccess; +} + +/* Returns true if `end` is true and `v` is within the `limit`. Used to validate the + * last part of an IPv4 address, which can hold larger numbers if there are fewer then + * four parts. */ +static PRBool +tls13_IpLastPart(PRBool end, PRUint32 v, PRUint32 limit) +{ + if (!end) { + return PR_FALSE; + } + return v <= limit; +} + +/* Returns true if `str` contains an IPv4 address. */ +PRBool +tls13_IsIp(const PRUint8 *str, unsigned int len) +{ + PRUint32 part; + PRUint32 v; + unsigned int i = 0; + for (part = 0; part < 4; part++) { + SECStatus rv = tls13_IpValue(str, len, &i, &v); + if (rv != SECSuccess) { + return PR_FALSE; + } + if (v > 0xff || i == len) { + return tls13_IpLastPart(i == len, v, PR_UINT32_MAX >> (part * 8)); + } + PORT_Assert(str[i] == '.'); + i++; + } + + return tls13_IpLastPart(i == len, v, 0xff); +} + +static PRBool +tls13_IsLD(PRUint8 c) +{ + return (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '_'; /* not in spec, but in the world; bug 1136616 */ +} + +/* Is this a valid dotted LDH string (that is, an A-Label domain name)? + * This does not tolerate a trailing '.', where the DNS generally does. + */ +PRBool +tls13_IsLDH(const PRUint8 *str, unsigned int len) +{ + unsigned int i = 0; + while (i < len && tls13_IsLD(str[i])) { + unsigned int labelEnd = PR_MIN(len, i + 63); + i++; + while (i < labelEnd && (tls13_IsLD(str[i]) || str[i] == '-')) { + i++; + } + if (str[i - 1] == '-') { + /* labels cannot end in a hyphen */ + return PR_FALSE; + } + if (i == len) { + return PR_TRUE; + } + if (str[i] != '.') { + return PR_FALSE; + } + i++; + } + return PR_FALSE; +} |