Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Bug 1385158 - Move custom extension handlers to experimental API, r=ekr
--HG--
branch : NSS_TLS13_DRAFT19_BRANCH
  • Loading branch information
martinthomson committed Jul 31, 2017
1 parent e9c5d52 commit 50c65c0
Show file tree
Hide file tree
Showing 8 changed files with 163 additions and 140 deletions.
11 changes: 7 additions & 4 deletions gtests/ssl_gtest/ssl_custext_unittest.cc
Expand Up @@ -8,6 +8,7 @@
#include "ssl3prot.h"
#include "sslerr.h"
#include "sslproto.h"
#include "sslexp.h"

#include <memory>

Expand Down Expand Up @@ -75,10 +76,12 @@ void InstallManyWriters(std::shared_ptr<TlsAgent> agent,
SSLExtensionWriter writer, size_t *installed = nullptr,
size_t *called = nullptr) {
for (size_t i = 0; i < PR_ARRAY_SIZE(kManyExtensions); ++i) {
SSLExtensionSupport support = SSL_GetExtensionSupport(kManyExtensions[i]);
SECStatus rv =
SSL_InstallExtensionHooks(agent->ssl_fd(), kManyExtensions[i], writer,
called, NoopExtensionHandler, nullptr);
SSLExtensionSupport support;
SECStatus rv = SSL_GetExtensionSupport(kManyExtensions[i], &support);
ASSERT_EQ(SECSuccess, rv) << "SSL_GetExtensionSupport cannot fail";

rv = SSL_InstallExtensionHooks(agent->ssl_fd(), kManyExtensions[i], writer,
called, NoopExtensionHandler, nullptr);
if (support == ssl_ext_native_only) {
EXPECT_EQ(SECFailure, rv);
EXPECT_EQ(SEC_ERROR_INVALID_ARGS, PORT_GetError());
Expand Down
2 changes: 0 additions & 2 deletions lib/ssl/ssl.def
Expand Up @@ -237,8 +237,6 @@ SSL_AlertSentCallback;
;+NSS_3.33 { # NSS 3.33 release
;+ global:
SSL_GetExperimentalAPI;
SSL_GetExtensionSupport;
SSL_InstallExtensionHooks;
;+ local:
;+*;
;+};
127 changes: 0 additions & 127 deletions lib/ssl/ssl.h
Expand Up @@ -1375,133 +1375,6 @@ extern const char *NSSSSL_GetVersion(void);
SSL_IMPORT SECStatus SSL_AuthCertificateComplete(PRFileDesc *fd,
PRErrorCode error);

/*
<<<<<<< dest
* SSL_GetExtensionSupport() returns whether NSS supports a particular TLS extension.
*
* - ssl_ext_none indicates that NSS does not support the extension and
* extension hooks can be installed.
*
* - ssl_ext_native indicates that NSS supports the extension natively, but
* allows an application to override that support and install its own
* extension hooks.
*
* - ssl_ext_native_only indicates that NSS supports the extension natively
* and does not permit custom extension hooks to be installed. These
* extensions are critical to the functioning of NSS.
*/
typedef enum {
ssl_ext_none,
ssl_ext_native,
ssl_ext_native_only
} SSLExtensionSupport;

SSL_IMPORT SSLExtensionSupport
SSL_GetExtensionSupport(PRUint16 extension);

/*
* Custom extension hooks.
*
* The SSL_InstallExtensionHooks() registers two callback functions for use
* with the identified extension type.
*
* Installing extension hooks disables the checks in TLS 1.3 that ensure that
* extensions are only added to the correct messages. The application is
* responsible for ensuring that extensions are only sent with the right message
* or messages.
*
* Installing an extension handler does not disable checks for whether an
* extension can be used in a message that is a response to an extension in
* another message. Extensions in ServerHello, EncryptedExtensions and the
* server Certificate messages are rejected unless the client sends an extension
* in the ClientHello. Similarly, a client Certificate message cannot contain
* extensions that don't appear in a CertificateRequest (in TLS 1.3).
*
* Setting both |writer| and |handler| to NULL removes any existing hooks for
* that extension.
*
* == SSLExtensionWriter
*
* An SSLExtensionWriter function is responsible for constructing the contents
* of an extension. This function is called during the construction of all
* handshake messages where an extension might be included.
*
* - The |fd| argument is the socket file descriptor.
*
* - The |message| argument is the TLS handshake message type. The writer will
* be called for every handshake message that NSS sends. Most extensions
* should only be sent in a subset of messages. NSS doesn’t check that
* extension writers don’t violate protocol rules regarding which message an
* extension can be sent in.
*
* - The |data| argument is a pointer to a buffer that should be written to with
* any data for the extension.
*
* - The |len| argument is an outparam indicating how many bytes were written to
* |data|. The value referenced by |len| is initialized to zero, so an
* extension that is empty does not need to write to this value.
*
* - The |maxLen| indicates the maximum number of bytes that can be written to
* |data|.
*
* - The |arg| argument is the value of the writerArg that was passed during
* installation.
*
* An SSLExtensionWriter function returns PR_TRUE if an extension should be
* written, and PR_FALSE otherwise.
*
* If there is an error, return PR_FALSE; if the error is truly fatal, the
* application can mark the connection as failed. However, recursively calling
* functions that alter the file descriptor in the callback - such as PR_Close()
* - should be avoided.
*
* Note: The ClientHello message can be sent twice in TLS 1.3. An
* SSLExtensionWriter will be called twice with the same arguments in that case;
* NSS does not distinguish between a first and second ClientHello. It is up to
* the application to track this if it needs to act differently each time. In
* most cases the correct behaviour is to provide an identical extension on each
* invocation.
*
* == SSLExtensionHandler
*
* An SSLExtensionHandler function consumes a handshake message. This function
* is called when an extension is present.
*
* - The |fd| argument is the socket file descriptor.
*
* - The |message| argument is the TLS handshake message type. This can be used
* to validate that the extension was included in the correct handshake
* message.
*
* - The |data| argument points to the contents of the extension.
*
* - The |len| argument contains the length of the extension.
*
* - The |alert| argument is an outparam that allows an application to choose
* which alert is sent in the case of a fatal error.
*
* - The |arg| argument is the value of the handlerArg that was passed during
* installation.
*
* An SSLExtensionHandler function returns SECSuccess when the extension is
* process successfully. It can return SECFailure to cause the handshake to
* fail. If the value of alert is written to, NSS will generate a fatal alert
* using the provided alert code. The value of |alert| is otherwise not used.
*/
typedef PRBool(PR_CALLBACK *SSLExtensionWriter)(
PRFileDesc *fd, SSLHandshakeType message,
PRUint8 *data, unsigned int *len, unsigned int maxLen, void *arg);

typedef SECStatus(PR_CALLBACK *SSLExtensionHandler)(
PRFileDesc *fd, SSLHandshakeType message,
const PRUint8 *data, unsigned int len,
SSLAlertDescription *alert, void *arg);

SSL_IMPORT SECStatus
SSL_InstallExtensionHooks(PRFileDesc *fd, PRUint16 extension,
SSLExtensionWriter writer, void *writerArg,
SSLExtensionHandler handler, void *handlerArg);

/*
* This is used to access experimental APIs. Don't call this directly. This is
* used to enable the experimental APIs that are defined in "sslexp.h".
Expand Down
19 changes: 13 additions & 6 deletions lib/ssl/ssl3ext.c
Expand Up @@ -177,8 +177,8 @@ static const struct {
{ ssl_renegotiation_info_xtn, ssl_ext_native }
};

SSLExtensionSupport
SSL_GetExtensionSupport(PRUint16 type)
static SSLExtensionSupport
ssl_GetExtensionSupport(PRUint16 type)
{
unsigned int i;
for (i = 0; i < PR_ARRAY_SIZE(ssl_supported_extensions); ++i) {
Expand All @@ -190,9 +190,16 @@ SSL_GetExtensionSupport(PRUint16 type)
}

SECStatus
SSL_InstallExtensionHooks(PRFileDesc *fd, PRUint16 extension,
SSLExtensionWriter writer, void *writerArg,
SSLExtensionHandler handler, void *handlerArg)
SSLExp_GetExtensionSupport(PRUint16 type, SSLExtensionSupport *support)
{
*support = ssl_GetExtensionSupport(type);
return SECSuccess;
}

SECStatus
SSLExp_InstallExtensionHooks(PRFileDesc *fd, PRUint16 extension,
SSLExtensionWriter writer, void *writerArg,
SSLExtensionHandler handler, void *handlerArg)
{
sslSocket *ss = ssl_FindSocket(fd);
PRCList *cursor;
Expand All @@ -208,7 +215,7 @@ SSL_InstallExtensionHooks(PRFileDesc *fd, PRUint16 extension,
return SECFailure;
}

if (SSL_GetExtensionSupport(extension) == ssl_ext_native_only) {
if (ssl_GetExtensionSupport(extension) == ssl_ext_native_only) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
Expand Down
6 changes: 6 additions & 0 deletions lib/ssl/ssl3ext.h
Expand Up @@ -150,4 +150,10 @@ SECStatus ssl3_ExtConsumeHandshakeVariable(const sslSocket *ss, SECItem *i,
PRUint32 bytes, PRUint8 **b,
PRUint32 *length);

SECStatus SSLExp_GetExtensionSupport(PRUint16 type,
SSLExtensionSupport *support);
SECStatus SSLExp_InstallExtensionHooks(
PRFileDesc *fd, PRUint16 extension, SSLExtensionWriter writer,
void *writerArg, SSLExtensionHandler handler, void *handlerArg);

#endif
134 changes: 134 additions & 0 deletions lib/ssl/sslexp.h
Expand Up @@ -22,6 +22,140 @@ SEC_BEGIN_PROTOS
? ((SECStatus(*) arglist)SSL_GetExperimentalAPI(name))args \
: SECFailure)

/*
* SSL_GetExtensionSupport() returns whether NSS supports a particular TLS
* extension.
*
* - ssl_ext_none indicates that NSS does not support the extension and
* extension hooks can be installed.
*
* - ssl_ext_native indicates that NSS supports the extension natively, but
* allows an application to override that support and install its own
* extension hooks.
*
* - ssl_ext_native_only indicates that NSS supports the extension natively
* and does not permit custom extension hooks to be installed. These
* extensions are critical to the functioning of NSS.
*/
typedef enum {
ssl_ext_none,
ssl_ext_native,
ssl_ext_native_only
} SSLExtensionSupport;

#define SSL_GetExtensionSupport(extension, support) \
SSL_EXPERIMENTAL_API("SSL_GetExtensionSupport", \
(PRUint16 _extension, \
SSLExtensionSupport * _support), \
(extension, support))

/*
* Custom extension hooks.
*
* The SSL_InstallExtensionHooks() registers two callback functions for use
* with the identified extension type.
*
* Installing extension hooks disables the checks in TLS 1.3 that ensure that
* extensions are only added to the correct messages. The application is
* responsible for ensuring that extensions are only sent with the right message
* or messages.
*
* Installing an extension handler does not disable checks for whether an
* extension can be used in a message that is a response to an extension in
* another message. Extensions in ServerHello, EncryptedExtensions and the
* server Certificate messages are rejected unless the client sends an extension
* in the ClientHello. Similarly, a client Certificate message cannot contain
* extensions that don't appear in a CertificateRequest (in TLS 1.3).
*
* Setting both |writer| and |handler| to NULL removes any existing hooks for
* that extension.
*
* == SSLExtensionWriter
*
* An SSLExtensionWriter function is responsible for constructing the contents
* of an extension. This function is called during the construction of all
* handshake messages where an extension might be included.
*
* - The |fd| argument is the socket file descriptor.
*
* - The |message| argument is the TLS handshake message type. The writer will
* be called for every handshake message that NSS sends. Most extensions
* should only be sent in a subset of messages. NSS doesn’t check that
* extension writers don’t violate protocol rules regarding which message an
* extension can be sent in.
*
* - The |data| argument is a pointer to a buffer that should be written to with
* any data for the extension.
*
* - The |len| argument is an outparam indicating how many bytes were written to
* |data|. The value referenced by |len| is initialized to zero, so an
* extension that is empty does not need to write to this value.
*
* - The |maxLen| indicates the maximum number of bytes that can be written to
* |data|.
*
* - The |arg| argument is the value of the writerArg that was passed during
* installation.
*
* An SSLExtensionWriter function returns PR_TRUE if an extension should be
* written, and PR_FALSE otherwise.
*
* If there is an error, return PR_FALSE; if the error is truly fatal, the
* application can mark the connection as failed. However, recursively calling
* functions that alter the file descriptor in the callback - such as PR_Close()
* - should be avoided.
*
* Note: The ClientHello message can be sent twice in TLS 1.3. An
* SSLExtensionWriter will be called twice with the same arguments in that case;
* NSS does not distinguish between a first and second ClientHello. It is up to
* the application to track this if it needs to act differently each time. In
* most cases the correct behaviour is to provide an identical extension on each
* invocation.
*
* == SSLExtensionHandler
*
* An SSLExtensionHandler function consumes a handshake message. This function
* is called when an extension is present.
*
* - The |fd| argument is the socket file descriptor.
*
* - The |message| argument is the TLS handshake message type. This can be used
* to validate that the extension was included in the correct handshake
* message.
*
* - The |data| argument points to the contents of the extension.
*
* - The |len| argument contains the length of the extension.
*
* - The |alert| argument is an outparam that allows an application to choose
* which alert is sent in the case of a fatal error.
*
* - The |arg| argument is the value of the handlerArg that was passed during
* installation.
*
* An SSLExtensionHandler function returns SECSuccess when the extension is
* process successfully. It can return SECFailure to cause the handshake to
* fail. If the value of alert is written to, NSS will generate a fatal alert
* using the provided alert code. The value of |alert| is otherwise not used.
*/
typedef PRBool(PR_CALLBACK *SSLExtensionWriter)(
PRFileDesc *fd, SSLHandshakeType message,
PRUint8 *data, unsigned int *len, unsigned int maxLen, void *arg);

typedef SECStatus(PR_CALLBACK *SSLExtensionHandler)(
PRFileDesc *fd, SSLHandshakeType message,
const PRUint8 *data, unsigned int len,
SSLAlertDescription *alert, void *arg);

#define SSL_InstallExtensionHooks(fd, extension, writer, writerArg, \
handler, handlerArg) \
SSL_EXPERIMENTAL_API("SSL_InstallExtensionHooks", \
(PRFileDesc * _fd, PRUint16 _extension, \
SSLExtensionWriter _writer, void *_writerArg, \
SSLExtensionHandler _handler, void *_handlerArg), \
(fd, extension, writer, writerArg, \
handler, handlerArg))

/*
* Setup the anti-replay buffer for supporting 0-RTT in TLS 1.3 on servers.
*
Expand Down
2 changes: 1 addition & 1 deletion lib/ssl/sslimpl.h
Expand Up @@ -35,6 +35,7 @@

typedef struct sslSocketStr sslSocket;
typedef struct ssl3CipherSpecStr ssl3CipherSpec;
#include "sslexp.h"
#include "ssl3ext.h"
#include "sslencode.h"

Expand Down Expand Up @@ -1350,7 +1351,6 @@ extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket *ss,
SECStatus ssl_HashHandshakeMessage(sslSocket *ss, SSLHandshakeType type,
const PRUint8 *b, PRUint32 length);


/* Returns PR_TRUE if we are still waiting for the server to complete its
* response to our client second round. Once we've received the Finished from
* the server then there is no need to check false start.
Expand Down
2 changes: 2 additions & 0 deletions lib/ssl/sslsock.c
Expand Up @@ -3902,6 +3902,8 @@ struct {
void *function;
} ssl_experimental_functions[] = {
#ifndef SSL_DISABLE_EXPERIMENTAL_API
EXP(GetExtensionSupport),
EXP(InstallExtensionHooks),
EXP(SetupAntiReplay),
#endif
{ "", NULL }
Expand Down

0 comments on commit 50c65c0

Please sign in to comment.