diff -pu a/nss/lib/ssl/ssl3con.c b/nss/lib/ssl/ssl3con.c --- a/nss/lib/ssl/ssl3con.c 2014-01-17 17:59:03.242109996 -0800 +++ b/nss/lib/ssl/ssl3con.c 2014-01-17 17:59:45.862816905 -0800 @@ -12383,6 +12383,68 @@ ssl3_InitSocketPolicy(sslSocket *ss) PORT_Memcpy(ss->cipherSuites, cipherSuites, sizeof cipherSuites); } +SECStatus +ssl3_GetTLSUniqueChannelBinding(sslSocket *ss, + unsigned char *out, + unsigned int *outLen, + unsigned int outLenMax) { + PRBool isTLS; + int index = 0; + unsigned int len; + SECStatus rv = SECFailure; + + *outLen = 0; + + ssl_GetSSL3HandshakeLock(ss); + + ssl_GetSpecReadLock(ss); + isTLS = (PRBool)(ss->ssl3.cwSpec->version > SSL_LIBRARY_VERSION_3_0); + ssl_ReleaseSpecReadLock(ss); + + /* The tls-unique channel binding is the first Finished structure in the + * handshake. In the case of a resumption, that's the server's Finished. + * Otherwise, it's the client's Finished. */ + len = ss->ssl3.hs.finishedBytes; + + /* Sending or receiving a Finished message will set finishedBytes to a + * non-zero value. */ + if (len == 0) { + PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); + goto loser; + } + + /* If we are in the middle of a renegotiation then the channel binding + * value is poorly defined and depends on the direction that it will be + * used on. Therefore we simply return an error in this case. */ + if (ss->firstHsDone && ss->ssl3.hs.ws != idle_handshake) { + PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED); + goto loser; + } + + /* If resuming, then we want the second Finished value in the array, which + * is the server's */ + if (ss->ssl3.hs.isResuming) + index = 1; + + *outLen = len; + if (outLenMax < len) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); + goto loser; + } + + if (isTLS) { + memcpy(out, &ss->ssl3.hs.finishedMsgs.tFinished[index], len); + } else { + memcpy(out, &ss->ssl3.hs.finishedMsgs.sFinished[index], len); + } + + rv = SECSuccess; + +loser: + ssl_ReleaseSSL3HandshakeLock(ss); + return rv; +} + /* ssl3_config_match_init must have already been called by * the caller of this function. */ diff -pu a/nss/lib/ssl/ssl.h b/nss/lib/ssl/ssl.h --- a/nss/lib/ssl/ssl.h 2014-01-17 17:59:03.242109996 -0800 +++ b/nss/lib/ssl/ssl.h 2014-01-17 17:59:45.862816905 -0800 @@ -282,6 +282,27 @@ SSL_IMPORT SECStatus SSL_CipherPrefGetDe SSL_IMPORT SECStatus SSL_CipherPolicySet(PRInt32 cipher, PRInt32 policy); SSL_IMPORT SECStatus SSL_CipherPolicyGet(PRInt32 cipher, PRInt32 *policy); +/* SSLChannelBindingType enumerates the types of supported channel binding + * values. See RFC 5929. */ +typedef enum SSLChannelBindingType { + SSL_CHANNEL_BINDING_TLS_UNIQUE = 1, +} SSLChannelBindingType; + +/* SSL_GetChannelBinding copies the requested channel binding value, as defined + * in RFC 5929, into |out|. The full length of the binding value is written + * into |*outLen|. + * + * At most |outLenMax| bytes of data are copied. If |outLenMax| is + * insufficient then the function returns SECFailure and sets the error to + * SEC_ERROR_OUTPUT_LEN, but |*outLen| is still set. + * + * This call will fail if made during a renegotiation. */ +SSL_IMPORT SECStatus SSL_GetChannelBinding(PRFileDesc *fd, + SSLChannelBindingType binding_type, + unsigned char *out, + unsigned int *outLen, + unsigned int outLenMax); + /* SSL Version Range API ** ** This API should be used to control SSL 3.0 & TLS support instead of the diff -pu a/nss/lib/ssl/sslimpl.h b/nss/lib/ssl/sslimpl.h --- a/nss/lib/ssl/sslimpl.h 2014-01-17 17:59:03.242109996 -0800 +++ b/nss/lib/ssl/sslimpl.h 2014-01-17 17:59:45.862816905 -0800 @@ -1853,6 +1853,11 @@ extern PRBool ssl_GetSessionTicketKeysPK extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char* data, unsigned int length); +extern SECStatus ssl3_GetTLSUniqueChannelBinding(sslSocket *ss, + unsigned char *out, + unsigned int *outLen, + unsigned int outLenMax); + /* Construct a new NSPR socket for the app to use */ extern PRFileDesc *ssl_NewPRSocket(sslSocket *ss, PRFileDesc *fd); extern void ssl_FreePRSocket(PRFileDesc *fd); diff -pu a/nss/lib/ssl/sslsock.c b/nss/lib/ssl/sslsock.c --- a/nss/lib/ssl/sslsock.c 2014-01-17 17:59:03.252110162 -0800 +++ b/nss/lib/ssl/sslsock.c 2014-01-17 17:59:45.872817074 -0800 @@ -1308,6 +1308,27 @@ NSS_SetFrancePolicy(void) return NSS_SetDomesticPolicy(); } +SECStatus +SSL_GetChannelBinding(PRFileDesc *fd, + SSLChannelBindingType binding_type, + unsigned char *out, + unsigned int *outLen, + unsigned int outLenMax) { + sslSocket *ss = ssl_FindSocket(fd); + + if (!ss) { + SSL_DBG(("%d: SSL[%d]: bad socket in SSL_GetChannelBinding", + SSL_GETPID(), fd)); + return SECFailure; + } + + if (binding_type != SSL_CHANNEL_BINDING_TLS_UNIQUE) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return SECFailure; + } + + return ssl3_GetTLSUniqueChannelBinding(ss, out, outLen, outLenMax); +} /* LOCKS ??? XXX */