DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (772f7e11c7e5)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797
/*
 * 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))

/*
 * Create an anti-replay context for supporting 0-RTT in TLS 1.3 on servers.
 *
 * To use 0-RTT on a server, you must create an anti-replay context using
 * SSL_CreateAntiReplayContext and set that on the socket with
 * SSL_SetAntiReplayContext.  Failing to set a context on the server will result
 * in all 0-RTT being rejected.  Connections will complete, but early data will
 * be rejected.
 *
 * Anti-replay contexts are reference counted and are released with
 * SSL_ReleaseAntiReplayContext.
 *
 * 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 8.3 of RFC 8446 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.
 */
typedef struct SSLAntiReplayContextStr SSLAntiReplayContext;
#define SSL_CreateAntiReplayContext(now, window, k, bits, ctx) \
    SSL_EXPERIMENTAL_API("SSL_CreateAntiReplayContext",        \
                         (PRTime _now, PRTime _window,         \
                          unsigned int _k, unsigned int _bits, \
                          SSLAntiReplayContext **_ctx),        \
                         (now, window, k, bits, ctx))

#define SSL_SetAntiReplayContext(fd, ctx)                                 \
    SSL_EXPERIMENTAL_API("SSL_SetAntiReplayContext",                      \
                         (PRFileDesc * _fd, SSLAntiReplayContext * _ctx), \
                         (fd, ctx))

#define SSL_ReleaseAntiReplayContext(ctx)                \
    SSL_EXPERIMENTAL_API("SSL_ReleaseAntiReplayContext", \
                         (SSLAntiReplayContext * _ctx),  \
                         (ctx))

/*
 * 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.
 *
 * - Returning ssl_hello_retry_reject_0rtt causes NSS to proceed normally, but
 *   to reject 0-RTT.  Use this if there is something in the token that
 *   indicates that 0-RTT might be unsafe.
 *
 * 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,
    ssl_hello_retry_reject_0rtt
} 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))

/* This function allows a server application to trigger
 * re-authentication (TLS 1.3 only) after handshake.
 *
 * This function will cause a CertificateRequest message to be sent by
 * a server.  This can be called once at a time, and is not allowed
 * until an answer is received.
 *
 * The AuthCertificateCallback is called when the answer is received.
 * If the answer is accepted by the server, the value returned by
 * SSL_PeerCertificate() is replaced.  If you need to remember all the
 * certificates, you will need to call SSL_PeerCertificate() and save
 * what you get before calling this.
 *
 * If the AuthCertificateCallback returns SECFailure, the connection
 * is aborted.
 */
#define SSL_SendCertificateRequest(fd)                 \
    SSL_EXPERIMENTAL_API("SSL_SendCertificateRequest", \
                         (PRFileDesc * _fd),           \
                         (fd))

/*
 * 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))

/* SSL_SetSecretCallback installs a callback that TLS calls when it installs new
 * traffic secrets.
 *
 * SSLSecretCallback is called with the current epoch and the corresponding
 * secret; this matches the epoch used in DTLS 1.3, even if the socket is
 * operating in stream mode:
 *
 * - client_early_traffic_secret corresponds to epoch 1
 * - {client|server}_handshake_traffic_secret is epoch 2
 * - {client|server}_application_traffic_secret_{N} is epoch 3+N
 *
 * The callback is invoked separately for read secrets (client secrets on the
 * server; server secrets on the client), and write secrets.
 *
 * This callback is only called if (D)TLS 1.3 is negotiated.
 */
typedef void(PR_CALLBACK *SSLSecretCallback)(
    PRFileDesc *fd, PRUint16 epoch, SSLSecretDirection dir, PK11SymKey *secret,
    void *arg);

#define SSL_SecretCallback(fd, cb, arg)                                         \
    SSL_EXPERIMENTAL_API("SSL_SecretCallback",                                  \
                         (PRFileDesc * _fd, SSLSecretCallback _cb, void *_arg), \
                         (fd, cb, arg))

/* SSL_RecordLayerWriteCallback() is used to replace the TLS record layer.  This
 * function installs a callback that TLS calls when it would otherwise encrypt
 * and write a record to the underlying NSPR IO layer.  The application is
 * responsible for ensuring that these records are encrypted and written.
 *
 * Calling this API also disables reads from the underlying NSPR layer.  The
 * application is expected to push data when it is available using
 * SSL_RecordLayerData().
 *
 * When data would be written, the provided SSLRecordWriteCallback with the
 * epoch, TLS content type, and the data. The data provided to the callback is
 * not split into record-sized writes.  If the callback returns SECFailure, the
 * write will be considered to have failed; in particular, PR_WOULD_BLOCK_ERROR
 * is not handled specially.
 *
 * If TLS 1.3 is in use, the epoch indicates the expected level of protection
 * that the record would receive, this matches that used in DTLS 1.3:
 *
 * - epoch 0 corresponds to no record protection
 * - epoch 1 corresponds to 0-RTT
 * - epoch 2 corresponds to TLS handshake
 * - epoch 3 and higher are application data
 *
 * Prior versions of TLS use epoch 1 and higher for application data.
 *
 * This API is not supported for DTLS.
 */
typedef SECStatus(PR_CALLBACK *SSLRecordWriteCallback)(
    PRFileDesc *fd, PRUint16 epoch, SSLContentType contentType,
    const PRUint8 *data, unsigned int len, void *arg);

#define SSL_RecordLayerWriteCallback(fd, writeCb, arg)                   \
    SSL_EXPERIMENTAL_API("SSL_RecordLayerWriteCallback",                 \
                         (PRFileDesc * _fd, SSLRecordWriteCallback _wCb, \
                          void *_arg),                                   \
                         (fd, writeCb, arg))

/* SSL_RecordLayerData() is used to provide new data to TLS.  The application
 * indicates the epoch (see the description of SSL_RecordLayerWriteCallback()),
 * content type, and the data that was received.  The application is responsible
 * for removing any encryption or other protection before passing data to this
 * function.
 *
 * This returns SECSuccess if the data was successfully processed.  If this
 * function is used to drive the handshake and the caller needs to know when the
 * handshake is complete, a call to SSL_ForceHandshake will return SECSuccess
 * when the handshake is complete.
 *
 * This API is not supported for DTLS sockets.
 */
#define SSL_RecordLayerData(fd, epoch, ct, data, len)               \
    SSL_EXPERIMENTAL_API("SSL_RecordLayerData",                     \
                         (PRFileDesc * _fd, PRUint16 _epoch,        \
                          SSLContentType _contentType,              \
                          const PRUint8 *_data, unsigned int _len), \
                         (fd, epoch, ct, data, len))

/*
 * SSL_GetCurrentEpoch() returns the read and write epochs that the socket is
 * currently using.  NULL values for readEpoch or writeEpoch are ignored.
 *
 * See SSL_RecordLayerWriteCallback() for details on epochs.
 */
#define SSL_GetCurrentEpoch(fd, readEpoch, writeEpoch)             \
    SSL_EXPERIMENTAL_API("SSL_GetCurrentEpoch",                    \
                         (PRFileDesc * _fd, PRUint16 * _readEpoch, \
                          PRUint16 * _writeEpoch),                 \
                         (fd, readEpoch, writeEpoch))

/*
 * The following AEAD functions expose an AEAD primitive that uses a ciphersuite
 * to set parameters.  The ciphersuite determines the Hash function used by
 * HKDF, the AEAD function, and the size of key and IV.  This is only supported
 * for TLS 1.3.
 *
 * The key and IV are generated using the TLS KDF with a custom label.  That is
 * HKDF-Expand-Label(secret, labelPrefix + " key" or " iv", "", L).
 *
 * The encrypt and decrypt functions use a nonce construction identical to that
 * used in TLS.  The lower bits of the IV are XORed with the 64-bit counter to
 * produce the nonce.  Otherwise, this is an AEAD interface similar to that
 * described in RFC 5116.
 */
typedef struct SSLAeadContextStr SSLAeadContext;

#define SSL_MakeAead(version, cipherSuite, secret,                  \
                     labelPrefix, labelPrefixLen, ctx)              \
    SSL_EXPERIMENTAL_API("SSL_MakeAead",                            \
                         (PRUint16 _version, PRUint16 _cipherSuite, \
                          PK11SymKey * _secret,                     \
                          const char *_labelPrefix,                 \
                          unsigned int _labelPrefixLen,             \
                          SSLAeadContext **_ctx),                   \
                         (version, cipherSuite, secret,             \
                          labelPrefix, labelPrefixLen, ctx))

#define SSL_AeadEncrypt(ctx, counter, aad, aadLen, in, inLen,            \
                        output, outputLen, maxOutputLen)                 \
    SSL_EXPERIMENTAL_API("SSL_AeadEncrypt",                              \
                         (const SSLAeadContext *_ctx, PRUint64 _counter, \
                          const PRUint8 *_aad, unsigned int _aadLen,     \
                          const PRUint8 *_in, unsigned int _inLen,       \
                          PRUint8 *_out, unsigned int *_outLen,          \
                          unsigned int _maxOut),                         \
                         (ctx, counter, aad, aadLen, in, inLen,          \
                          output, outputLen, maxOutputLen))

#define SSL_AeadDecrypt(ctx, counter, aad, aadLen, in, inLen,            \
                        output, outputLen, maxOutputLen)                 \
    SSL_EXPERIMENTAL_API("SSL_AeadDecrypt",                              \
                         (const SSLAeadContext *_ctx, PRUint64 _counter, \
                          const PRUint8 *_aad, unsigned int _aadLen,     \
                          const PRUint8 *_in, unsigned int _inLen,       \
                          PRUint8 *_output, unsigned int *_outLen,       \
                          unsigned int _maxOut),                         \
                         (ctx, counter, aad, aadLen, in, inLen,          \
                          output, outputLen, maxOutputLen))

#define SSL_DestroyAead(ctx)                      \
    SSL_EXPERIMENTAL_API("SSL_DestroyAead",       \
                         (SSLAeadContext * _ctx), \
                         (ctx))

/* SSL_HkdfExtract and SSL_HkdfExpandLabel implement the functions from TLS,
 * using the version and ciphersuite to set parameters. This allows callers to
 * use these TLS functions as a KDF. This is only supported for TLS 1.3.
 *
 * SSL_HkdfExtract produces a key with a mechanism that is suitable for input to
 * SSL_HkdfExpandLabel (and SSL_HkdfExpandLabelWithMech). */
#define SSL_HkdfExtract(version, cipherSuite, salt, ikm, keyp)      \
    SSL_EXPERIMENTAL_API("SSL_HkdfExtract",                         \
                         (PRUint16 _version, PRUint16 _cipherSuite, \
                          PK11SymKey * _salt, PK11SymKey * _ikm,    \
                          PK11SymKey * *_keyp),                     \
                         (version, cipherSuite, salt, ikm, keyp))

/* SSL_HkdfExpandLabel produces a key with a mechanism that is suitable for
 * input to SSL_HkdfExpandLabel or SSL_MakeAead. */
#define SSL_HkdfExpandLabel(version, cipherSuite, prk,                     \
                            hsHash, hsHashLen, label, labelLen, keyp)      \
    SSL_EXPERIMENTAL_API("SSL_HkdfExpandLabel",                            \
                         (PRUint16 _version, PRUint16 _cipherSuite,        \
                          PK11SymKey * _prk,                               \
                          const PRUint8 *_hsHash, unsigned int _hsHashLen, \
                          const char *_label, unsigned int _labelLen,      \
                          PK11SymKey **_keyp),                             \
                         (version, cipherSuite, prk,                       \
                          hsHash, hsHashLen, label, labelLen, keyp))

/* SSL_HkdfExpandLabelWithMech uses the KDF from the selected TLS version and
 * cipher suite, as with the other calls, but the provided mechanism and key
 * size. This allows the key to be used more widely. */
#define SSL_HkdfExpandLabelWithMech(version, cipherSuite, prk,             \
                                    hsHash, hsHashLen, label, labelLen,    \
                                    mech, keySize, keyp)                   \
    SSL_EXPERIMENTAL_API("SSL_HkdfExpandLabelWithMech",                    \
                         (PRUint16 _version, PRUint16 _cipherSuite,        \
                          PK11SymKey * _prk,                               \
                          const PRUint8 *_hsHash, unsigned int _hsHashLen, \
                          const char *_label, unsigned int _labelLen,      \
                          CK_MECHANISM_TYPE _mech, unsigned int _keySize,  \
                          PK11SymKey **_keyp),                             \
                         (version, cipherSuite, prk,                       \
                          hsHash, hsHashLen, label, labelLen,              \
                          mech, keySize, keyp))

/* SSL_SetTimeFunc overrides the default time function (PR_Now()) and provides
 * an alternative source of time for the socket. This is used in testing, and in
 * applications that need better control over how the clock is accessed. Set the
 * function to NULL to use PR_Now().*/
typedef PRTime(PR_CALLBACK *SSLTimeFunc)(void *arg);

#define SSL_SetTimeFunc(fd, f, arg)                                      \
    SSL_EXPERIMENTAL_API("SSL_SetTimeFunc",                              \
                         (PRFileDesc * _fd, SSLTimeFunc _f, void *_arg), \
                         (fd, f, arg))

/* Create a delegated credential (DC) for the draft-ietf-tls-subcerts extension
 * using the given certificate |cert| and its signing key |certPriv| and write
 * the serialized DC to |out|. The
 * parameters are:
 *  - the DC public key |dcPub|;
 *  - the DC signature scheme |dcCertVerifyAlg|, used to verify the handshake.
 *  - the DC time-to-live |dcValidFor|, the number of seconds from now for which
 *    the DC should be valid; and
 *  - the current time |now|.
 *
 *  The signing algorithm used to verify the DC signature is deduced from
 *  |cert|.
 *
 *  It's the caller's responsibility to ensure the input parameters are all
 *  valid. This procedure is meant primarily for testing; for this purpose it is
 *  useful to do no validation.
 */
#define SSL_DelegateCredential(cert, certPriv, dcPub, dcCertVerifyAlg,        \
                               dcValidFor, now, out)                          \
    SSL_EXPERIMENTAL_API("SSL_DelegateCredential",                            \
                         (const CERTCertificate *_cert,                       \
                          const SECKEYPrivateKey *_certPriv,                  \
                          const SECKEYPublicKey *_dcPub,                      \
                          SSLSignatureScheme _dcCertVerifyAlg,                \
                          PRUint32 _dcValidFor,                               \
                          PRTime _now,                                        \
                          SECItem *_out),                                     \
                         (cert, certPriv, dcPub, dcCertVerifyAlg, dcValidFor, \
                          now, out))

/* Deprecated experimental APIs */
#define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API
#define SSL_SetupAntiReplay(a, b, c) SSL_DEPRECATED_EXPERIMENTAL_API
#define SSL_InitAntiReplay(a, b, c) SSL_DEPRECATED_EXPERIMENTAL_API

SEC_END_PROTOS

#endif /* __sslexp_h_ */