summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/ssl/sslexp.h
blob: b734d86ca386186775acad7be8349991efb349d0 (plain)
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
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
/*
 * 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 in seconds since epoch
 * 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))

/* New functions created to permit get/set the CipherSuites Order for the
 * handshake (Client Hello).
 *
 * The *Get function puts the current set of active (enabled and policy set as
 * PR_TRUE) cipher suites in the cipherOrder outparam. Cipher suites that
 * aren't active aren't included. The paramenters are:
 *   - PRFileDesc *fd = FileDescriptor to get information.
 *   - PRUint16 *cipherOrder = The memory allocated for cipherOrder needs to be
 *     SSL_GetNumImplementedCiphers() * sizeof(PRUint16) or more.
 *   - PRUint16 numCiphers = The number of active ciphersuites listed in
 *     *cipherOrder is written here.
 *
 * The *Set function permits reorder the CipherSuites list for the Handshake
 * (Client Hello). The default ordering defined in ssl3con.c is enough in
 * almost all cases. But, if the client needs some hardening or performance
 * adjusts related to CipherSuites, this can be done with this function.
 * The caller has to be aware about the risk of call this function while a
 * handshake are being processed in this fd/socket. For example, if you disable
 * a cipher after the handshake and this cipher was choosen for that
 * connection, something bad will happen.
 * The parameters are:
 *   - PRFileDesc *fd = FileDescriptor to change.
 *   - const PRUint16 *cipherOrder = Must receive all ciphers to be ordered, in
 *     the desired order. They will be set in the begin of the list. Only
 *     suites listed by SSL_ImplementedCiphers() can be included.
 *   - PRUint16 numCiphers = Must receive the number of items in *cipherOrder.
 * */
#define SSL_CipherSuiteOrderGet(fd, cipherOrder, numCiphers)         \
    SSL_EXPERIMENTAL_API("SSL_CipherSuiteOrderGet",                  \
                         (PRFileDesc * _fd, PRUint16 * _cipherOrder, \
                          unsigned int *_numCiphers),                \
                         (fd, cipherOrder, numCiphers))

#define SSL_CipherSuiteOrderSet(fd, cipherOrder, numCiphers)              \
    SSL_EXPERIMENTAL_API("SSL_CipherSuiteOrderSet",                       \
                         (PRFileDesc * _fd, const PRUint16 *_cipherOrder, \
                          PRUint16 _numCiphers),                          \
                         (fd, cipherOrder, numCiphers))

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