diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/third_party/nss/README.chromium | 3 | ||||
-rwxr-xr-x | net/third_party/nss/patches/applypatches.sh | 2 | ||||
-rw-r--r-- | net/third_party/nss/patches/channelid.patch | 430 | ||||
-rw-r--r-- | net/third_party/nss/ssl/SSLerrs.h | 9 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl.h | 19 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3con.c | 142 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3ext.c | 52 | ||||
-rw-r--r-- | net/third_party/nss/ssl/ssl3prot.h | 3 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslauth.c | 18 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslerr.h | 4 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslimpl.h | 2 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslsock.c | 8 | ||||
-rw-r--r-- | net/third_party/nss/ssl/sslt.h | 3 |
13 files changed, 689 insertions, 6 deletions
diff --git a/net/third_party/nss/README.chromium b/net/third_party/nss/README.chromium index 3f14a7a..3b810a3 100644 --- a/net/third_party/nss/README.chromium +++ b/net/third_party/nss/README.chromium @@ -62,6 +62,9 @@ Patches: * Reject DH generators and public values equal to zero or one. patches/dhvalues.patch + * Add support for TLS Channel IDs + patches/channelid.patch + Apply the patches to NSS by running the patches/applypatches.sh script. Read the comments at the top of patches/applypatches.sh for instructions. diff --git a/net/third_party/nss/patches/applypatches.sh b/net/third_party/nss/patches/applypatches.sh index b713a46..5eb654d 100755 --- a/net/third_party/nss/patches/applypatches.sh +++ b/net/third_party/nss/patches/applypatches.sh @@ -35,3 +35,5 @@ patch -p4 < $patches_dir/dtls.patch patch -p5 < $patches_dir/falsestartnpn.patch patch -p5 < $patches_dir/dhvalues.patch + +patch -p4 < $patches_dir/channelid.patch diff --git a/net/third_party/nss/patches/channelid.patch b/net/third_party/nss/patches/channelid.patch new file mode 100644 index 0000000..d700f11 --- /dev/null +++ b/net/third_party/nss/patches/channelid.patch @@ -0,0 +1,430 @@ +diff --git a/net/third_party/nss/ssl/SSLerrs.h b/net/third_party/nss/ssl/SSLerrs.h +index e3f9a1c..2d92514 100644 +--- a/net/third_party/nss/ssl/SSLerrs.h ++++ b/net/third_party/nss/ssl/SSLerrs.h +@@ -429,3 +429,12 @@ ER3(SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST, (SSL_ERROR_BASE + 122), + + ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST, (SSL_ERROR_BASE + 123), + "SSL received an unexpected Hello Verify Request handshake message.") ++ ++ER3(SSL_ERROR_BAD_CHANNEL_ID_DATA, (SSL_ERROR_BASE + 124), ++"SSL received a malformed TLS Channel ID extension.") ++ ++ER3(SSL_ERROR_INVALID_CHANNEL_ID_KEY, (SSL_ERROR_BASE + 125), ++"The application provided an invalid TLS Channel ID key.") ++ ++ER3(SSL_ERROR_GET_CHANNEL_ID_FAILED, (SSL_ERROR_BASE + 126), ++"The application could not get a TLS Channel ID.") +diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h +index 1368e2f..3d8fdcb 100644 +--- a/net/third_party/nss/ssl/ssl.h ++++ b/net/third_party/nss/ssl/ssl.h +@@ -945,6 +945,25 @@ SSL_IMPORT SECStatus SSL_HandshakeNegotiatedExtension(PRFileDesc * socket, + SSL_IMPORT SECStatus SSL_HandshakeResumedSession(PRFileDesc *fd, + PRBool *last_handshake_resumed); + ++/* See SSL_SetClientChannelIDCallback for usage. The callback must return ++ * SECFailure or SECSuccess (not SECWouldBlock). On SECSuccess, the callback ++ * must have written a P-256, EC key pair to |*out_public_key| and ++ * |*out_private_key|. */ ++typedef SECStatus (PR_CALLBACK *SSLClientChannelIDCallback)( ++ void *arg, ++ PRFileDesc *fd, ++ SECKEYPublicKey **out_public_key, ++ SECKEYPrivateKey **out_private_key); ++ ++/* SSL_SetClientChannelIDCallback sets a callback function that will be called ++ * just before a Channel ID is sent. This is only applicable to a client socket ++ * and setting this callback causes the TLS Channel ID extension to be ++ * advertised. */ ++SSL_IMPORT SECStatus SSL_SetClientChannelIDCallback( ++ PRFileDesc *fd, ++ SSLClientChannelIDCallback callback, ++ void *arg); ++ + /* + ** How long should we wait before retransmitting the next flight of + ** the DTLS handshake? Returns SECFailure if not DTLS or not in a +diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c +index db9fad3..f714a98 100644 +--- a/net/third_party/nss/ssl/ssl3con.c ++++ b/net/third_party/nss/ssl/ssl3con.c +@@ -86,6 +86,7 @@ static SECStatus ssl3_SendCertificate( sslSocket *ss); + static SECStatus ssl3_SendEmptyCertificate( sslSocket *ss); + static SECStatus ssl3_SendCertificateRequest(sslSocket *ss); + static SECStatus ssl3_SendNextProto( sslSocket *ss); ++static SECStatus ssl3_SendEncryptedExtensions(sslSocket *ss); + static SECStatus ssl3_SendFinished( sslSocket *ss, PRInt32 flags); + static SECStatus ssl3_SendServerHello( sslSocket *ss); + static SECStatus ssl3_SendServerHelloDone( sslSocket *ss); +@@ -6239,6 +6240,10 @@ ssl3_SendClientSecondRound(sslSocket *ss) + goto loser; /* err code was set. */ + } + } ++ rv = ssl3_SendEncryptedExtensions(ss); ++ if (rv != SECSuccess) { ++ goto loser; /* err code was set. */ ++ } + + rv = ssl3_SendFinished(ss, 0); + if (rv != SECSuccess) { +@@ -8855,6 +8860,130 @@ ssl3_SendNextProto(sslSocket *ss) + return rv; + } + ++/* called from ssl3_SendClientSecondRound ++ * ssl3_HandleFinished ++ */ ++static SECStatus ++ssl3_SendEncryptedExtensions(sslSocket *ss) ++{ ++ static const char CHANNEL_ID_MAGIC[] = "TLS Channel ID signature"; ++ /* This is the ASN.1 prefix for a P-256 public key. Specifically it's: ++ * SEQUENCE ++ * SEQUENCE ++ * OID id-ecPublicKey ++ * OID prime256v1 ++ * BIT STRING, length 66, 0 trailing bits: 0x04 ++ * ++ * The 0x04 in the BIT STRING is the prefix for an uncompressed, X9.62 ++ * public key. Following that are the two field elements as 32-byte, ++ * big-endian numbers, as required by the Channel ID. */ ++ static const unsigned char P256_SPKI_PREFIX[] = { ++ 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, ++ 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, ++ 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, ++ 0x42, 0x00, 0x04 ++ }; ++ /* ChannelIDs are always 128 bytes long: 64 bytes of P-256 public key and 64 ++ * bytes of ECDSA signature. */ ++ static const int CHANNEL_ID_PUBLIC_KEY_LENGTH = 64; ++ static const int CHANNEL_ID_LENGTH = 128; ++ ++ SECStatus rv = SECFailure; ++ SECItem *spki = NULL; ++ SSL3Hashes hashes; ++ const unsigned char *pub_bytes; ++ unsigned char signed_data[sizeof(CHANNEL_ID_MAGIC) + sizeof(SSL3Hashes)]; ++ unsigned char digest[SHA256_LENGTH]; ++ SECItem digest_item; ++ unsigned char signature[64]; ++ SECItem signature_item; ++ SECKEYPrivateKey *channelID = NULL; ++ SECKEYPublicKey *channelIDPub = NULL; ++ ++ PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); ++ PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); ++ ++ if (ss->getChannelID == NULL || ++ !ssl3_ExtensionNegotiated(ss, ssl_channel_id_xtn)) { ++ return SECSuccess; ++ } ++ ++ rv = ss->getChannelID(ss->getChannelIDArg, ss->fd, ++ &channelIDPub, &channelID); ++ if (rv != SECSuccess) { ++ PORT_SetError(SSL_ERROR_GET_CHANNEL_ID_FAILED); ++ goto loser; ++ } ++ ++ if (SECKEY_GetPrivateKeyType(channelID) != ecKey || ++ PK11_SignatureLen(channelID) != sizeof(signature)) { ++ PORT_SetError(SSL_ERROR_INVALID_CHANNEL_ID_KEY); ++ rv = SECFailure; ++ goto loser; ++ } ++ ++ ssl_GetSpecReadLock(ss); ++ rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.cwSpec, &hashes, 0); ++ ssl_ReleaseSpecReadLock(ss); ++ ++ if (rv != SECSuccess) ++ goto loser; ++ ++ rv = ssl3_AppendHandshakeHeader(ss, encrypted_extensions, ++ 2 + 2 + CHANNEL_ID_LENGTH); ++ if (rv != SECSuccess) ++ goto loser; /* error code set by AppendHandshakeHeader */ ++ rv = ssl3_AppendHandshakeNumber(ss, ssl_channel_id_xtn, 2); ++ if (rv != SECSuccess) ++ goto loser; /* error code set by AppendHandshake */ ++ rv = ssl3_AppendHandshakeNumber(ss, CHANNEL_ID_LENGTH, 2); ++ if (rv != SECSuccess) ++ goto loser; /* error code set by AppendHandshake */ ++ ++ spki = SECKEY_EncodeDERSubjectPublicKeyInfo(channelIDPub); ++ ++ if (spki->len != sizeof(P256_SPKI_PREFIX) + CHANNEL_ID_PUBLIC_KEY_LENGTH || ++ memcmp(spki->data, P256_SPKI_PREFIX, sizeof(P256_SPKI_PREFIX) != 0)) { ++ PORT_SetError(SSL_ERROR_INVALID_CHANNEL_ID_KEY); ++ rv = SECFailure; ++ goto loser; ++ } ++ ++ pub_bytes = spki->data + sizeof(P256_SPKI_PREFIX); ++ ++ memcpy(signed_data, CHANNEL_ID_MAGIC, sizeof(CHANNEL_ID_MAGIC)); ++ memcpy(signed_data + sizeof(CHANNEL_ID_MAGIC), &hashes, sizeof(hashes)); ++ ++ rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data, sizeof(signed_data)); ++ if (rv != SECSuccess) ++ goto loser; ++ ++ digest_item.data = digest; ++ digest_item.len = sizeof(digest); ++ ++ signature_item.data = signature; ++ signature_item.len = sizeof(signature); ++ ++ rv = PK11_Sign(channelID, &signature_item, &digest_item); ++ if (rv != SECSuccess) ++ goto loser; ++ ++ rv = ssl3_AppendHandshake(ss, pub_bytes, CHANNEL_ID_PUBLIC_KEY_LENGTH); ++ if (rv != SECSuccess) ++ goto loser; ++ rv = ssl3_AppendHandshake(ss, signature, sizeof(signature)); ++ ++loser: ++ if (spki) ++ SECITEM_FreeItem(spki, PR_TRUE); ++ if (channelID) ++ SECKEY_DestroyPrivateKey(channelID); ++ if (channelIDPub) ++ SECKEY_DestroyPublicKey(channelIDPub); ++ ++ return rv; ++} ++ + /* called from ssl3_HandleServerHelloDone + * ssl3_HandleClientHello + * ssl3_HandleFinished +@@ -9105,11 +9234,16 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, + flags = ssl_SEND_FLAG_FORCE_INTO_BUFFER; + } + +- if (!isServer && !ss->firstHsDone) { +- rv = ssl3_SendNextProto(ss); +- if (rv != SECSuccess) { +- goto xmit_loser; /* err code was set. */ ++ if (!isServer) { ++ if (!ss->firstHsDone) { ++ rv = ssl3_SendNextProto(ss); ++ if (rv != SECSuccess) { ++ goto xmit_loser; /* err code was set. */ ++ } + } ++ rv = ssl3_SendEncryptedExtensions(ss); ++ if (rv != SECSuccess) ++ goto xmit_loser; /* err code was set. */ + } + + if (IS_DTLS(ss)) { +diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c +index b9fd6e7..029487e 100644 +--- a/net/third_party/nss/ssl/ssl3ext.c ++++ b/net/third_party/nss/ssl/ssl3ext.c +@@ -80,10 +80,14 @@ static SECStatus ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, + PRUint16 ex_type, SECItem *data); + static SECStatus ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, + PRUint16 ex_type, SECItem *data); ++static SECStatus ssl3_ClientHandleChannelIDXtn(sslSocket *ss, ++ PRUint16 ex_type, SECItem *data); + static SECStatus ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss, + PRUint16 ex_type, SECItem *data); + static PRInt32 ssl3_ClientSendNextProtoNegoXtn(sslSocket *ss, PRBool append, + PRUint32 maxBytes); ++static PRInt32 ssl3_ClientSendChannelIDXtn(sslSocket *ss, PRBool append, ++ PRUint32 maxBytes); + + /* + * Write bytes. Using this function means the SECItem structure +@@ -253,6 +257,7 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = { + { ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn }, + { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, + { ssl_next_proto_nego_xtn, &ssl3_ClientHandleNextProtoNegoXtn }, ++ { ssl_channel_id_xtn, &ssl3_ClientHandleChannelIDXtn }, + { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn }, + { -1, NULL } + }; +@@ -278,6 +283,7 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = { + #endif + { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, + { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn }, ++ { ssl_channel_id_xtn, &ssl3_ClientSendChannelIDXtn }, + { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn } + /* any extra entries will appear as { 0, NULL } */ + }; +@@ -668,6 +674,52 @@ loser: + return -1; + } + ++static SECStatus ++ssl3_ClientHandleChannelIDXtn(sslSocket *ss, PRUint16 ex_type, ++ SECItem *data) ++{ ++ PORT_Assert(ss->getChannelID != NULL); ++ ++ if (data->len) { ++ PORT_SetError(SSL_ERROR_BAD_CHANNEL_ID_DATA); ++ return SECFailure; ++ } ++ ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; ++ return SECSuccess; ++} ++ ++static PRInt32 ++ssl3_ClientSendChannelIDXtn(sslSocket * ss, PRBool append, ++ PRUint32 maxBytes) ++{ ++ PRInt32 extension_length = 4; ++ ++ if (!ss->getChannelID) ++ return 0; ++ ++ if (maxBytes < extension_length) { ++ PORT_Assert(0); ++ return 0; ++ } ++ ++ if (append) { ++ SECStatus rv; ++ rv = ssl3_AppendHandshakeNumber(ss, ssl_channel_id_xtn, 2); ++ if (rv != SECSuccess) ++ goto loser; ++ rv = ssl3_AppendHandshakeNumber(ss, 0, 2); ++ if (rv != SECSuccess) ++ goto loser; ++ ss->xtnData.advertised[ss->xtnData.numAdvertised++] = ++ ssl_channel_id_xtn; ++ } ++ ++ return extension_length; ++ ++loser: ++ return -1; ++} ++ + SECStatus + ssl3_ClientHandleStatusRequestXtn(sslSocket *ss, PRUint16 ex_type, + SECItem *data) +diff --git a/net/third_party/nss/ssl/ssl3prot.h b/net/third_party/nss/ssl/ssl3prot.h +index 550c341..11f9624 100644 +--- a/net/third_party/nss/ssl/ssl3prot.h ++++ b/net/third_party/nss/ssl/ssl3prot.h +@@ -163,7 +163,8 @@ typedef enum { + client_key_exchange = 16, + finished = 20, + certificate_status = 22, +- next_proto = 67 ++ next_proto = 67, ++ encrypted_extensions= 203 + } SSL3HandshakeType; + + typedef struct { +diff --git a/net/third_party/nss/ssl/sslauth.c b/net/third_party/nss/ssl/sslauth.c +index 8ccd1a4..e8b4acb 100644 +--- a/net/third_party/nss/ssl/sslauth.c ++++ b/net/third_party/nss/ssl/sslauth.c +@@ -251,6 +251,24 @@ SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func, + return SECSuccess; + } + ++SECStatus ++SSL_SetClientChannelIDCallback(PRFileDesc *fd, ++ SSLClientChannelIDCallback callback, ++ void *arg) { ++ sslSocket *ss = ssl_FindSocket(fd); ++ ++ if (!ss) { ++ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetClientChannelIDCallback", ++ SSL_GETPID(), fd)); ++ return SECFailure; ++ } ++ ++ ss->getChannelID = callback; ++ ss->getChannelIDArg = arg; ++ ++ return SECSuccess; ++} ++ + #ifdef NSS_PLATFORM_CLIENT_AUTH + /* NEED LOCKS IN HERE. */ + SECStatus +diff --git a/net/third_party/nss/ssl/sslerr.h b/net/third_party/nss/ssl/sslerr.h +index 9d3bebc..53c897c 100644 +--- a/net/third_party/nss/ssl/sslerr.h ++++ b/net/third_party/nss/ssl/sslerr.h +@@ -218,6 +218,10 @@ SSL_ERROR_RX_UNEXPECTED_CERT_STATUS = (SSL_ERROR_BASE + 121), + SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST = (SSL_ERROR_BASE + 122), + SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST = (SSL_ERROR_BASE + 123), + ++SSL_ERROR_BAD_CHANNEL_ID_DATA = (SSL_ERROR_BASE + 124), ++SSL_ERROR_INVALID_CHANNEL_ID_KEY = (SSL_ERROR_BASE + 125), ++SSL_ERROR_GET_CHANNEL_ID_FAILED = (SSL_ERROR_BASE + 126), ++ + SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ + } SSLErrorCodes; + #endif /* NO_SECURITY_ERROR_ENUM */ +diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h +index 8ab865a..7cd2298 100644 +--- a/net/third_party/nss/ssl/sslimpl.h ++++ b/net/third_party/nss/ssl/sslimpl.h +@@ -1198,6 +1198,8 @@ const unsigned char * preferredCipher; + void *pkcs11PinArg; + SSLNextProtoCallback nextProtoCallback; + void *nextProtoArg; ++ SSLClientChannelIDCallback getChannelID; ++ void *getChannelIDArg; + + PRIntervalTime rTimeout; /* timeout for NSPR I/O */ + PRIntervalTime wTimeout; /* timeout for NSPR I/O */ +diff --git a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c +index ebc245a..9498828 100644 +--- a/net/third_party/nss/ssl/sslsock.c ++++ b/net/third_party/nss/ssl/sslsock.c +@@ -374,6 +374,8 @@ ssl_DupSocket(sslSocket *os) + ss->handshakeCallback = os->handshakeCallback; + ss->handshakeCallbackData = os->handshakeCallbackData; + ss->pkcs11PinArg = os->pkcs11PinArg; ++ ss->getChannelID = os->getChannelID; ++ ss->getChannelIDArg = os->getChannelIDArg; + + /* Create security data */ + rv = ssl_CopySecurityInfo(ss, os); +@@ -1688,6 +1690,10 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) + ss->handshakeCallbackData = sm->handshakeCallbackData; + if (sm->pkcs11PinArg) + ss->pkcs11PinArg = sm->pkcs11PinArg; ++ if (sm->getChannelID) ++ ss->getChannelID = sm->getChannelID; ++ if (sm->getChannelIDArg) ++ ss->getChannelIDArg = sm->getChannelIDArg; + return fd; + loser: + return NULL; +@@ -2938,6 +2944,8 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) + ss->handleBadCert = NULL; + ss->badCertArg = NULL; + ss->pkcs11PinArg = NULL; ++ ss->getChannelID = NULL; ++ ss->getChannelIDArg = NULL; + + ssl_ChooseOps(ss); + ssl2_InitSocketPolicy(ss); +diff --git a/net/third_party/nss/ssl/sslt.h b/net/third_party/nss/ssl/sslt.h +index 0636570..978b1cb 100644 +--- a/net/third_party/nss/ssl/sslt.h ++++ b/net/third_party/nss/ssl/sslt.h +@@ -215,9 +215,10 @@ typedef enum { + #endif + ssl_session_ticket_xtn = 35, + ssl_next_proto_nego_xtn = 13172, ++ ssl_channel_id_xtn = 30031, + ssl_renegotiation_info_xtn = 0xff01 /* experimental number */ + } SSLExtensionType; + +-#define SSL_MAX_EXTENSIONS 7 ++#define SSL_MAX_EXTENSIONS 8 + + #endif /* __sslt_h_ */ diff --git a/net/third_party/nss/ssl/SSLerrs.h b/net/third_party/nss/ssl/SSLerrs.h index e3f9a1c..2d92514 100644 --- a/net/third_party/nss/ssl/SSLerrs.h +++ b/net/third_party/nss/ssl/SSLerrs.h @@ -429,3 +429,12 @@ ER3(SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST, (SSL_ERROR_BASE + 122), ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST, (SSL_ERROR_BASE + 123), "SSL received an unexpected Hello Verify Request handshake message.") + +ER3(SSL_ERROR_BAD_CHANNEL_ID_DATA, (SSL_ERROR_BASE + 124), +"SSL received a malformed TLS Channel ID extension.") + +ER3(SSL_ERROR_INVALID_CHANNEL_ID_KEY, (SSL_ERROR_BASE + 125), +"The application provided an invalid TLS Channel ID key.") + +ER3(SSL_ERROR_GET_CHANNEL_ID_FAILED, (SSL_ERROR_BASE + 126), +"The application could not get a TLS Channel ID.") diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h index 1368e2f..3d8fdcb 100644 --- a/net/third_party/nss/ssl/ssl.h +++ b/net/third_party/nss/ssl/ssl.h @@ -945,6 +945,25 @@ SSL_IMPORT SECStatus SSL_HandshakeNegotiatedExtension(PRFileDesc * socket, SSL_IMPORT SECStatus SSL_HandshakeResumedSession(PRFileDesc *fd, PRBool *last_handshake_resumed); +/* See SSL_SetClientChannelIDCallback for usage. The callback must return + * SECFailure or SECSuccess (not SECWouldBlock). On SECSuccess, the callback + * must have written a P-256, EC key pair to |*out_public_key| and + * |*out_private_key|. */ +typedef SECStatus (PR_CALLBACK *SSLClientChannelIDCallback)( + void *arg, + PRFileDesc *fd, + SECKEYPublicKey **out_public_key, + SECKEYPrivateKey **out_private_key); + +/* SSL_SetClientChannelIDCallback sets a callback function that will be called + * just before a Channel ID is sent. This is only applicable to a client socket + * and setting this callback causes the TLS Channel ID extension to be + * advertised. */ +SSL_IMPORT SECStatus SSL_SetClientChannelIDCallback( + PRFileDesc *fd, + SSLClientChannelIDCallback callback, + void *arg); + /* ** How long should we wait before retransmitting the next flight of ** the DTLS handshake? Returns SECFailure if not DTLS or not in a diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c index db9fad3..f714a98 100644 --- a/net/third_party/nss/ssl/ssl3con.c +++ b/net/third_party/nss/ssl/ssl3con.c @@ -86,6 +86,7 @@ static SECStatus ssl3_SendCertificate( sslSocket *ss); static SECStatus ssl3_SendEmptyCertificate( sslSocket *ss); static SECStatus ssl3_SendCertificateRequest(sslSocket *ss); static SECStatus ssl3_SendNextProto( sslSocket *ss); +static SECStatus ssl3_SendEncryptedExtensions(sslSocket *ss); static SECStatus ssl3_SendFinished( sslSocket *ss, PRInt32 flags); static SECStatus ssl3_SendServerHello( sslSocket *ss); static SECStatus ssl3_SendServerHelloDone( sslSocket *ss); @@ -6239,6 +6240,10 @@ ssl3_SendClientSecondRound(sslSocket *ss) goto loser; /* err code was set. */ } } + rv = ssl3_SendEncryptedExtensions(ss); + if (rv != SECSuccess) { + goto loser; /* err code was set. */ + } rv = ssl3_SendFinished(ss, 0); if (rv != SECSuccess) { @@ -8855,6 +8860,130 @@ ssl3_SendNextProto(sslSocket *ss) return rv; } +/* called from ssl3_SendClientSecondRound + * ssl3_HandleFinished + */ +static SECStatus +ssl3_SendEncryptedExtensions(sslSocket *ss) +{ + static const char CHANNEL_ID_MAGIC[] = "TLS Channel ID signature"; + /* This is the ASN.1 prefix for a P-256 public key. Specifically it's: + * SEQUENCE + * SEQUENCE + * OID id-ecPublicKey + * OID prime256v1 + * BIT STRING, length 66, 0 trailing bits: 0x04 + * + * The 0x04 in the BIT STRING is the prefix for an uncompressed, X9.62 + * public key. Following that are the two field elements as 32-byte, + * big-endian numbers, as required by the Channel ID. */ + static const unsigned char P256_SPKI_PREFIX[] = { + 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, + 0x42, 0x00, 0x04 + }; + /* ChannelIDs are always 128 bytes long: 64 bytes of P-256 public key and 64 + * bytes of ECDSA signature. */ + static const int CHANNEL_ID_PUBLIC_KEY_LENGTH = 64; + static const int CHANNEL_ID_LENGTH = 128; + + SECStatus rv = SECFailure; + SECItem *spki = NULL; + SSL3Hashes hashes; + const unsigned char *pub_bytes; + unsigned char signed_data[sizeof(CHANNEL_ID_MAGIC) + sizeof(SSL3Hashes)]; + unsigned char digest[SHA256_LENGTH]; + SECItem digest_item; + unsigned char signature[64]; + SECItem signature_item; + SECKEYPrivateKey *channelID = NULL; + SECKEYPublicKey *channelIDPub = NULL; + + PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); + + if (ss->getChannelID == NULL || + !ssl3_ExtensionNegotiated(ss, ssl_channel_id_xtn)) { + return SECSuccess; + } + + rv = ss->getChannelID(ss->getChannelIDArg, ss->fd, + &channelIDPub, &channelID); + if (rv != SECSuccess) { + PORT_SetError(SSL_ERROR_GET_CHANNEL_ID_FAILED); + goto loser; + } + + if (SECKEY_GetPrivateKeyType(channelID) != ecKey || + PK11_SignatureLen(channelID) != sizeof(signature)) { + PORT_SetError(SSL_ERROR_INVALID_CHANNEL_ID_KEY); + rv = SECFailure; + goto loser; + } + + ssl_GetSpecReadLock(ss); + rv = ssl3_ComputeHandshakeHashes(ss, ss->ssl3.cwSpec, &hashes, 0); + ssl_ReleaseSpecReadLock(ss); + + if (rv != SECSuccess) + goto loser; + + rv = ssl3_AppendHandshakeHeader(ss, encrypted_extensions, + 2 + 2 + CHANNEL_ID_LENGTH); + if (rv != SECSuccess) + goto loser; /* error code set by AppendHandshakeHeader */ + rv = ssl3_AppendHandshakeNumber(ss, ssl_channel_id_xtn, 2); + if (rv != SECSuccess) + goto loser; /* error code set by AppendHandshake */ + rv = ssl3_AppendHandshakeNumber(ss, CHANNEL_ID_LENGTH, 2); + if (rv != SECSuccess) + goto loser; /* error code set by AppendHandshake */ + + spki = SECKEY_EncodeDERSubjectPublicKeyInfo(channelIDPub); + + if (spki->len != sizeof(P256_SPKI_PREFIX) + CHANNEL_ID_PUBLIC_KEY_LENGTH || + memcmp(spki->data, P256_SPKI_PREFIX, sizeof(P256_SPKI_PREFIX) != 0)) { + PORT_SetError(SSL_ERROR_INVALID_CHANNEL_ID_KEY); + rv = SECFailure; + goto loser; + } + + pub_bytes = spki->data + sizeof(P256_SPKI_PREFIX); + + memcpy(signed_data, CHANNEL_ID_MAGIC, sizeof(CHANNEL_ID_MAGIC)); + memcpy(signed_data + sizeof(CHANNEL_ID_MAGIC), &hashes, sizeof(hashes)); + + rv = PK11_HashBuf(SEC_OID_SHA256, digest, signed_data, sizeof(signed_data)); + if (rv != SECSuccess) + goto loser; + + digest_item.data = digest; + digest_item.len = sizeof(digest); + + signature_item.data = signature; + signature_item.len = sizeof(signature); + + rv = PK11_Sign(channelID, &signature_item, &digest_item); + if (rv != SECSuccess) + goto loser; + + rv = ssl3_AppendHandshake(ss, pub_bytes, CHANNEL_ID_PUBLIC_KEY_LENGTH); + if (rv != SECSuccess) + goto loser; + rv = ssl3_AppendHandshake(ss, signature, sizeof(signature)); + +loser: + if (spki) + SECITEM_FreeItem(spki, PR_TRUE); + if (channelID) + SECKEY_DestroyPrivateKey(channelID); + if (channelIDPub) + SECKEY_DestroyPublicKey(channelIDPub); + + return rv; +} + /* called from ssl3_HandleServerHelloDone * ssl3_HandleClientHello * ssl3_HandleFinished @@ -9105,11 +9234,16 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, flags = ssl_SEND_FLAG_FORCE_INTO_BUFFER; } - if (!isServer && !ss->firstHsDone) { - rv = ssl3_SendNextProto(ss); - if (rv != SECSuccess) { - goto xmit_loser; /* err code was set. */ + if (!isServer) { + if (!ss->firstHsDone) { + rv = ssl3_SendNextProto(ss); + if (rv != SECSuccess) { + goto xmit_loser; /* err code was set. */ + } } + rv = ssl3_SendEncryptedExtensions(ss); + if (rv != SECSuccess) + goto xmit_loser; /* err code was set. */ } if (IS_DTLS(ss)) { diff --git a/net/third_party/nss/ssl/ssl3ext.c b/net/third_party/nss/ssl/ssl3ext.c index b9fd6e7..029487e 100644 --- a/net/third_party/nss/ssl/ssl3ext.c +++ b/net/third_party/nss/ssl/ssl3ext.c @@ -80,10 +80,14 @@ static SECStatus ssl3_HandleRenegotiationInfoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data); static SECStatus ssl3_ClientHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data); +static SECStatus ssl3_ClientHandleChannelIDXtn(sslSocket *ss, + PRUint16 ex_type, SECItem *data); static SECStatus ssl3_ServerHandleNextProtoNegoXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data); static PRInt32 ssl3_ClientSendNextProtoNegoXtn(sslSocket *ss, PRBool append, PRUint32 maxBytes); +static PRInt32 ssl3_ClientSendChannelIDXtn(sslSocket *ss, PRBool append, + PRUint32 maxBytes); /* * Write bytes. Using this function means the SECItem structure @@ -253,6 +257,7 @@ static const ssl3HelloExtensionHandler serverHelloHandlersTLS[] = { { ssl_session_ticket_xtn, &ssl3_ClientHandleSessionTicketXtn }, { ssl_renegotiation_info_xtn, &ssl3_HandleRenegotiationInfoXtn }, { ssl_next_proto_nego_xtn, &ssl3_ClientHandleNextProtoNegoXtn }, + { ssl_channel_id_xtn, &ssl3_ClientHandleChannelIDXtn }, { ssl_cert_status_xtn, &ssl3_ClientHandleStatusRequestXtn }, { -1, NULL } }; @@ -278,6 +283,7 @@ ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] = { #endif { ssl_session_ticket_xtn, &ssl3_SendSessionTicketXtn }, { ssl_next_proto_nego_xtn, &ssl3_ClientSendNextProtoNegoXtn }, + { ssl_channel_id_xtn, &ssl3_ClientSendChannelIDXtn }, { ssl_cert_status_xtn, &ssl3_ClientSendStatusRequestXtn } /* any extra entries will appear as { 0, NULL } */ }; @@ -668,6 +674,52 @@ loser: return -1; } +static SECStatus +ssl3_ClientHandleChannelIDXtn(sslSocket *ss, PRUint16 ex_type, + SECItem *data) +{ + PORT_Assert(ss->getChannelID != NULL); + + if (data->len) { + PORT_SetError(SSL_ERROR_BAD_CHANNEL_ID_DATA); + return SECFailure; + } + ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ex_type; + return SECSuccess; +} + +static PRInt32 +ssl3_ClientSendChannelIDXtn(sslSocket * ss, PRBool append, + PRUint32 maxBytes) +{ + PRInt32 extension_length = 4; + + if (!ss->getChannelID) + return 0; + + if (maxBytes < extension_length) { + PORT_Assert(0); + return 0; + } + + if (append) { + SECStatus rv; + rv = ssl3_AppendHandshakeNumber(ss, ssl_channel_id_xtn, 2); + if (rv != SECSuccess) + goto loser; + rv = ssl3_AppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) + goto loser; + ss->xtnData.advertised[ss->xtnData.numAdvertised++] = + ssl_channel_id_xtn; + } + + return extension_length; + +loser: + return -1; +} + SECStatus ssl3_ClientHandleStatusRequestXtn(sslSocket *ss, PRUint16 ex_type, SECItem *data) diff --git a/net/third_party/nss/ssl/ssl3prot.h b/net/third_party/nss/ssl/ssl3prot.h index 550c341..11f9624 100644 --- a/net/third_party/nss/ssl/ssl3prot.h +++ b/net/third_party/nss/ssl/ssl3prot.h @@ -163,7 +163,8 @@ typedef enum { client_key_exchange = 16, finished = 20, certificate_status = 22, - next_proto = 67 + next_proto = 67, + encrypted_extensions= 203 } SSL3HandshakeType; typedef struct { diff --git a/net/third_party/nss/ssl/sslauth.c b/net/third_party/nss/ssl/sslauth.c index 8ccd1a4..e8b4acb 100644 --- a/net/third_party/nss/ssl/sslauth.c +++ b/net/third_party/nss/ssl/sslauth.c @@ -251,6 +251,24 @@ SSL_GetClientAuthDataHook(PRFileDesc *s, SSLGetClientAuthData func, return SECSuccess; } +SECStatus +SSL_SetClientChannelIDCallback(PRFileDesc *fd, + SSLClientChannelIDCallback callback, + void *arg) { + sslSocket *ss = ssl_FindSocket(fd); + + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetClientChannelIDCallback", + SSL_GETPID(), fd)); + return SECFailure; + } + + ss->getChannelID = callback; + ss->getChannelIDArg = arg; + + return SECSuccess; +} + #ifdef NSS_PLATFORM_CLIENT_AUTH /* NEED LOCKS IN HERE. */ SECStatus diff --git a/net/third_party/nss/ssl/sslerr.h b/net/third_party/nss/ssl/sslerr.h index 9d3bebc..53c897c 100644 --- a/net/third_party/nss/ssl/sslerr.h +++ b/net/third_party/nss/ssl/sslerr.h @@ -218,6 +218,10 @@ SSL_ERROR_RX_UNEXPECTED_CERT_STATUS = (SSL_ERROR_BASE + 121), SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST = (SSL_ERROR_BASE + 122), SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST = (SSL_ERROR_BASE + 123), +SSL_ERROR_BAD_CHANNEL_ID_DATA = (SSL_ERROR_BASE + 124), +SSL_ERROR_INVALID_CHANNEL_ID_KEY = (SSL_ERROR_BASE + 125), +SSL_ERROR_GET_CHANNEL_ID_FAILED = (SSL_ERROR_BASE + 126), + SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ } SSLErrorCodes; #endif /* NO_SECURITY_ERROR_ENUM */ diff --git a/net/third_party/nss/ssl/sslimpl.h b/net/third_party/nss/ssl/sslimpl.h index 8ab865a..7cd2298 100644 --- a/net/third_party/nss/ssl/sslimpl.h +++ b/net/third_party/nss/ssl/sslimpl.h @@ -1198,6 +1198,8 @@ const unsigned char * preferredCipher; void *pkcs11PinArg; SSLNextProtoCallback nextProtoCallback; void *nextProtoArg; + SSLClientChannelIDCallback getChannelID; + void *getChannelIDArg; PRIntervalTime rTimeout; /* timeout for NSPR I/O */ PRIntervalTime wTimeout; /* timeout for NSPR I/O */ diff --git a/net/third_party/nss/ssl/sslsock.c b/net/third_party/nss/ssl/sslsock.c index ebc245a..9498828 100644 --- a/net/third_party/nss/ssl/sslsock.c +++ b/net/third_party/nss/ssl/sslsock.c @@ -374,6 +374,8 @@ ssl_DupSocket(sslSocket *os) ss->handshakeCallback = os->handshakeCallback; ss->handshakeCallbackData = os->handshakeCallbackData; ss->pkcs11PinArg = os->pkcs11PinArg; + ss->getChannelID = os->getChannelID; + ss->getChannelIDArg = os->getChannelIDArg; /* Create security data */ rv = ssl_CopySecurityInfo(ss, os); @@ -1688,6 +1690,10 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) ss->handshakeCallbackData = sm->handshakeCallbackData; if (sm->pkcs11PinArg) ss->pkcs11PinArg = sm->pkcs11PinArg; + if (sm->getChannelID) + ss->getChannelID = sm->getChannelID; + if (sm->getChannelIDArg) + ss->getChannelIDArg = sm->getChannelIDArg; return fd; loser: return NULL; @@ -2938,6 +2944,8 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) ss->handleBadCert = NULL; ss->badCertArg = NULL; ss->pkcs11PinArg = NULL; + ss->getChannelID = NULL; + ss->getChannelIDArg = NULL; ssl_ChooseOps(ss); ssl2_InitSocketPolicy(ss); diff --git a/net/third_party/nss/ssl/sslt.h b/net/third_party/nss/ssl/sslt.h index 0636570..978b1cb 100644 --- a/net/third_party/nss/ssl/sslt.h +++ b/net/third_party/nss/ssl/sslt.h @@ -215,9 +215,10 @@ typedef enum { #endif ssl_session_ticket_xtn = 35, ssl_next_proto_nego_xtn = 13172, + ssl_channel_id_xtn = 30031, ssl_renegotiation_info_xtn = 0xff01 /* experimental number */ } SSLExtensionType; -#define SSL_MAX_EXTENSIONS 7 +#define SSL_MAX_EXTENSIONS 8 #endif /* __sslt_h_ */ |