blob: f450e528dc36663fdc08c03ae3ca33fa10af37ba [file] [log] [blame]
/*
* This file contains prototypes for experimental SSL functions.
*
* 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/. */
#ifndef __sslexp_h_
#define __sslexp_h_
#include "ssl.h"
#include "sslerr.h"
SEC_BEGIN_PROTOS
/* The functions in this header file are not guaranteed to remain available in
* future NSS versions. Code that uses these functions needs to safeguard
* against the function not being available. */
#define SSL_EXPERIMENTAL_API(name, arglist, args) \
(SSL_GetExperimentalAPI(name) \
? ((SECStatus(*) arglist)SSL_GetExperimentalAPI(name))args \
: SECFailure)
#define SSL_DEPRECATED_EXPERIMENTAL_API \
(PR_SetError(SSL_ERROR_UNSUPPORTED_EXPERIMENTAL_API, 0), 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.
*
* To use 0-RTT on a server, you must call this function. Failing to call this
* function will result in all 0-RTT being rejected. Connections will complete,
* but early data will be rejected.
*
* NSS uses a Bloom filter to track the ClientHello messages that it receives
* (specifically, it uses the PSK binder). This function initializes a pair of
* Bloom filters. The two filters are alternated over time, with new
* ClientHello messages recorded in the current filter and, if they are not
* already present, being checked against the previous filter. If the
* ClientHello is found, then early data is rejected, but the handshake is
* allowed to proceed.
*
* The false-positive probability of Bloom filters means that some valid
* handshakes will be marked as potential replays. Early data will be rejected
* for a false positive. To minimize this and to allow a trade-off of space
* against accuracy, the size of the Bloom filter can be set by this function.
*
* The first tuning parameter to consider is |window|, which determines the
* window over which ClientHello messages will be tracked. This also causes
* early data to be rejected if a ClientHello contains a ticket age parameter
* that is outside of this window (see Section 4.2.10.4 of
* draft-ietf-tls-tls13-20 for details). Set |window| to account for any
* potential sources of clock error. |window| is the entire width of the
* window, which is symmetrical. Therefore to allow 5 seconds of clock error in
* both directions, set the value to 10 seconds (i.e., 10 * PR_USEC_PER_SEC).
*
* After calling this function, early data will be rejected until |window|
* elapses. This prevents replay across crashes and restarts. Only call this
* function once to avoid inadvertently disabling 0-RTT (use PR_CallOnce() to
* avoid this problem).
*
* The primary tuning parameter is |bits| which determines the amount of memory
* allocated to each Bloom filter. NSS will allocate two Bloom filters, each
* |2^(bits - 3)| octets in size. The value of |bits| is primarily driven by
* the number of connections that are expected in any time window. Note that
* this needs to account for there being two filters both of which have
* (presumably) independent false positive rates. The following formulae can be
* used to find a value of |bits| and |k| given a chosen false positive
* probability |p| and the number of requests expected in a given window |n|:
*
* bits = log2(n) + log2(-ln(1 - sqrt(1 - p))) + 1.0575327458897952
* k = -log2(p)
*
* ... where log2 and ln are base 2 and e logarithms respectively. For a target
* false positive rate of 1% and 1000 handshake attempts, this produces bits=14
* and k=7. This results in two Bloom filters that are 2kB each in size. Note
* that rounding |k| and |bits| up causes the false positive probability for
* these values to be a much lower 0.123%.
*
* IMPORTANT: This anti-replay scheme has several weaknesses. See the TLS 1.3
* specification for the details of the generic problems with this technique.
*
* In addition to the generic anti-replay weaknesses, the state that the server
* maintains is in local memory only. Servers that operate in a cluster, even
* those that use shared memory for tickets, will not share anti-replay state.
* Early data can be replayed at least once with every server instance that will
* accept tickets that are encrypted with the same key.
*/
#define SSL_SetupAntiReplay(window, k, bits) \
SSL_EXPERIMENTAL_API("SSL_SetupAntiReplay", \
(PRTime _window, unsigned int _k, unsigned int _bits), \
(window, k, bits))
/*
* This function allows a server application to generate a session ticket that
* will embed the provided token.
*
* This function will cause a NewSessionTicket message to be sent by a server.
* This happens even if SSL_ENABLE_SESSION_TICKETS is disabled. This allows a
* server to suppress the usually automatic generation of a session ticket at
* the completion of the handshake - which do not include any token - and to
* control when session tickets are transmitted.
*
* This function will fail unless the socket has an active TLS 1.3 session.
* Earlier versions of TLS do not support the spontaneous sending of the
* NewSessionTicket message.
*/
#define SSL_SendSessionTicket(fd, appToken, appTokenLen) \
SSL_EXPERIMENTAL_API("SSL_SendSessionTicket", \
(PRFileDesc * _fd, const PRUint8 *_appToken, \
unsigned int _appTokenLen), \
(fd, appToken, appTokenLen))
/*
* A stateless retry handler gives an application some control over NSS handling
* of ClientHello messages.
*
* SSL_HelloRetryRequestCallback() installs a callback that allows an
* application to control how NSS sends HelloRetryRequest messages. This
* handler is only used on servers and will only be called if the server selects
* TLS 1.3. Support for older TLS versions could be added in other releases.
*
* The SSLHelloRetryRequestCallback is invoked during the processing of a
* TLS 1.3 ClientHello message. It takes the following arguments:
*
* - |firstHello| indicates if the NSS believes that this is an initial
* ClientHello. An initial ClientHello will never include a cookie extension,
* though it may contain a session ticket.
*
* - |clientToken| includes a token previously provided by the application. If
* |clientTokenLen| is 0, then |clientToken| may be NULL.
*
* - If |firstHello| is PR_FALSE, the value that was provided in the
* |retryToken| outparam of previous invocations of this callback will be
* present here.
*
* - If |firstHello| is PR_TRUE, and the handshake is resuming a session, then
* this will contain any value that was passed in the |token| parameter of
* SSL_SendNewSessionTicket() method (see below). If this is not resuming a
* session, then the token will be empty (and this value could be NULL).
*
* - |clientTokenLen| is the length of |clientToken|.
*
* - |retryToken| is an item that callback can write to. This provides NSS with
* a token. This token is encrypted and integrity protected and embedded in
* the cookie extension of a HelloRetryRequest. The value of this field is
* only used if the handler returns ssl_stateless_retry_check. NSS allocates
* space for this value.
*
* - |retryTokenLen| is an outparam for the length of the token. If this value
* is not set, or set to 0, an empty token will be sent.
*
* - |retryTokenMax| is the size of the space allocated for retryToken. An
* application cannot write more than this many bytes to retryToken.
*
* - |arg| is the same value that was passed to
* SSL_InstallStatelessRetryHandler().
*
* The handler can validate any the value of |clientToken|, query the socket
* status (using SSL_GetPreliminaryChannelInfo() for example) and decide how to
* proceed:
*
* - Returning ssl_hello_retry_fail causes the handshake to fail. This might be
* used if the token is invalid or the application wishes to abort the
* handshake.
*
* - Returning ssl_hello_retry_accept causes the handshake to proceed.
*
* - Returning ssl_hello_retry_request causes NSS to send a HelloRetryRequest
* message and request a second ClientHello. NSS generates a cookie extension
* and embeds the value of |retryToken|. The value of |retryToken| value may
* be left empty if the application does not require any additional context to
* validate a second ClientHello attempt. This return code cannot be used to
* reject a second ClientHello (i.e., when firstHello is PR_FALSE); NSS will
* abort the handshake if this value is returned from a second call.
*
* An application that chooses to perform a stateless retry can discard the
* server socket. All necessary state to continue the TLS handshake will be
* included in the cookie extension. This makes it possible to use a new socket
* to handle the remainder of the handshake. The existing socket can be safely
* discarded.
*
* If the same socket is retained, the information in the cookie will be checked
* for consistency against the existing state of the socket. Any discrepancy
* will result in the connection being closed.
*
* Tokens should be kept as small as possible. NSS sets a limit on the size of
* tokens, which it passes in |retryTokenMax|. Depending on circumstances,
* observing a smaller limit might be desirable or even necessary. For
* instance, having HelloRetryRequest and ClientHello fit in a single packet has
* significant performance benefits.
*/
typedef enum {
ssl_hello_retry_fail,
ssl_hello_retry_accept,
ssl_hello_retry_request
} SSLHelloRetryRequestAction;
typedef SSLHelloRetryRequestAction(PR_CALLBACK *SSLHelloRetryRequestCallback)(
PRBool firstHello, const PRUint8 *clientToken, unsigned int clientTokenLen,
PRUint8 *retryToken, unsigned int *retryTokenLen, unsigned int retryTokMax,
void *arg);
#define SSL_HelloRetryRequestCallback(fd, cb, arg) \
SSL_EXPERIMENTAL_API("SSL_HelloRetryRequestCallback", \
(PRFileDesc * _fd, \
SSLHelloRetryRequestCallback _cb, void *_arg), \
(fd, cb, arg))
/* Update traffic keys (TLS 1.3 only).
*
* The |requestUpdate| flag determines whether to request an update from the
* remote peer.
*/
#define SSL_KeyUpdate(fd, requestUpdate) \
SSL_EXPERIMENTAL_API("SSL_KeyUpdate", \
(PRFileDesc * _fd, PRBool _requestUpdate), \
(fd, requestUpdate))
/*
* Session cache API.
*/
/*
* Information that can be retrieved about a resumption token.
* See SSL_GetResumptionTokenInfo for details about how to use this API.
* Note that peerCert points to a certificate in the NSS database and must be
* copied by the application if it should be used after NSS shutdown or after
* calling SSL_DestroyResumptionTokenInfo.
*/
typedef struct SSLResumptionTokenInfoStr {
PRUint16 length;
CERTCertificate *peerCert;
PRUint8 *alpnSelection;
PRUint32 alpnSelectionLen;
PRUint32 maxEarlyDataSize;
PRTime expirationTime; /* added in NSS 3.41 */
} SSLResumptionTokenInfo;
/*
* Allows applications to retrieve information about a resumption token.
* This does not require a TLS session.
*
* - The |tokenData| argument is a pointer to the resumption token as byte array
* of length |tokenLen|.
* - The |token| argument is a pointer to a SSLResumptionTokenInfo struct of
* of |len|. The struct gets filled by this function.
* See SSL_DestroyResumptionTokenInfo for information about how to manage the
* |token| memory.
*/
#define SSL_GetResumptionTokenInfo(tokenData, tokenLen, token, len) \
SSL_EXPERIMENTAL_API("SSL_GetResumptionTokenInfo", \
(const PRUint8 *_tokenData, unsigned int _tokenLen, \
SSLResumptionTokenInfo *_token, PRUintn _len), \
(tokenData, tokenLen, token, len))
/*
* SSL_GetResumptionTokenInfo allocates memory in order to populate |tokenInfo|.
* Any SSLResumptionTokenInfo struct filled with SSL_GetResumptionTokenInfo
* has to be freed with SSL_DestroyResumptionTokenInfo.
*/
#define SSL_DestroyResumptionTokenInfo(tokenInfo) \
SSL_EXPERIMENTAL_API( \
"SSL_DestroyResumptionTokenInfo", \
(SSLResumptionTokenInfo * _tokenInfo), \
(tokenInfo))
/*
* This is the function signature for function pointers used as resumption
* token callback. The caller has to copy the memory at |resumptionToken| with
* length |len| before returning.
*
* - The |fd| argument is the socket file descriptor.
* - The |resumptionToken| is a pointer to the resumption token as byte array
* of length |len|.
* - The |ctx| is a void pointer to the context set by the application in
* SSL_SetResumptionTokenCallback.
*/
typedef SECStatus(PR_CALLBACK *SSLResumptionTokenCallback)(
PRFileDesc *fd, const PRUint8 *resumptionToken, unsigned int len,
void *ctx);
/*
* This allows setting a callback for external session caches to store
* resumption tokens.
*
* - The |fd| argument is the socket file descriptor.
* - The |cb| is a function pointer to an implementation of
* SSLResumptionTokenCallback.
* - The |ctx| is a pointer to some application specific context, which is
* returned when |cb| is called.
*/
#define SSL_SetResumptionTokenCallback(fd, cb, ctx) \
SSL_EXPERIMENTAL_API( \
"SSL_SetResumptionTokenCallback", \
(PRFileDesc * _fd, SSLResumptionTokenCallback _cb, void *_ctx), \
(fd, cb, ctx))
/*
* This allows setting a resumption token for a session.
* The function returns SECSuccess iff the resumption token can be used,
* SECFailure in any other case. The caller should remove the |token| from its
* cache when the function returns SECFailure.
*
* - The |fd| argument is the socket file descriptor.
* - The |token| is a pointer to the resumption token as byte array
* of length |len|.
*/
#define SSL_SetResumptionToken(fd, token, len) \
SSL_EXPERIMENTAL_API( \
"SSL_SetResumptionToken", \
(PRFileDesc * _fd, const PRUint8 *_token, const unsigned int _len), \
(fd, token, len))
/* TLS 1.3 allows a server to set a limit on the number of bytes of early data
* that can be received. This allows that limit to be set. This function has no
* effect on a client. */
#define SSL_SetMaxEarlyDataSize(fd, size) \
SSL_EXPERIMENTAL_API("SSL_SetMaxEarlyDataSize", \
(PRFileDesc * _fd, PRUint32 _size), \
(fd, size))
/* Set the ESNI key pair on a socket (server side)
*
* fd -- the socket
* record/recordLen -- the encoded DNS record (not base64)
*
* Important: the suites that are advertised in the record must
* be configured on, or this call will fail.
*/
#define SSL_SetESNIKeyPair(fd, \
privKey, record, recordLen) \
SSL_EXPERIMENTAL_API("SSL_SetESNIKeyPair", \
(PRFileDesc * _fd, \
SECKEYPrivateKey * _privKey, \
const PRUint8 *_record, unsigned int _recordLen), \
(fd, privKey, \
record, recordLen))
/* Set the ESNI keys on a client
*
* fd -- the socket
* ensikeys/esniKeysLen -- the ESNI key structure (not base64)
* dummyESNI -- the dummy ESNI to use (if any)
*/
#define SSL_EnableESNI(fd, esniKeys, esniKeysLen, dummySNI) \
SSL_EXPERIMENTAL_API("SSL_EnableESNI", \
(PRFileDesc * _fd, \
const PRUint8 *_esniKeys, \
unsigned int _esniKeysLen, \
const char *_dummySNI), \
(fd, esniKeys, esniKeysLen, dummySNI))
/*
* Generate an encoded ESNIKeys structure (presumably server side).
*
* cipherSuites -- the cipher suites that can be used
* cipherSuitesCount -- the number of suites in cipherSuites
* group -- the named group this key corresponds to
* pubKey -- the public key for the key pair
* pad -- the length to pad to
* notBefore/notAfter -- validity range
* out/outlen/maxlen -- where to output the data
*/
#define SSL_EncodeESNIKeys(cipherSuites, cipherSuiteCount, \
group, pubKey, pad, notBefore, notAfter, \
out, outlen, maxlen) \
SSL_EXPERIMENTAL_API("SSL_EncodeESNIKeys", \
(PRUint16 * _cipherSuites, \
unsigned int _cipherSuiteCount, \
SSLNamedGroup _group, \
SECKEYPublicKey *_pubKey, \
PRUint16 _pad, \
PRUint64 _notBefore, PRUint64 _notAfter, \
PRUint8 *_out, unsigned int *_outlen, \
unsigned int _maxlen), \
(cipherSuites, cipherSuiteCount, \
group, pubKey, pad, notBefore, notAfter, \
out, outlen, maxlen))
/* Deprecated experimental APIs */
#define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API
SEC_END_PROTOS
#endif /* __sslexp_h_ */