summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/ssl/sslexp.h
blob: b51d224d50e6ba5420565ff741cd83a24f291c70 (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
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
/*
 * 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"
#include "pk11hpke.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. It will also fail when external PSK
 * authentication has been negotiated.
 */
#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.
 *
 * This function is not allowed for use with DTLS or when external
 * PSK authentication has been negotiated. SECFailure is returned
 * in both cases.
 *
 * 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))

/* Client:
 * If |enabled|, a GREASE ECH extension will be sent in every ClientHello,
 * unless a valid and supported ECHConfig is configured to the socket
 * (in which case real ECH takes precedence). If |!enabled|, it is not sent.
 *
 * Server:
 * If |enabled|, a GREASE ECH extensions will be sent in every HelloRetryRequest,
 * provided that the corresponding ClientHello contained an ECH extension. If ECH
 * is enabled, the real ECH HRR extension takes precedence.
 */
#define SSL_EnableTls13GreaseEch(fd, enabled)        \
    SSL_EXPERIMENTAL_API("SSL_EnableTls13GreaseEch", \
                         (PRFileDesc * _fd, PRBool _enabled), (fd, enabled))

/*
 * Client:
 * When sending a GREASE ECH extension in a ClientHello, pad it as though the
 * hypothetical ECHConfig had |maximum_name_length| equal to |size|. |size| may
 * vary between 1 and 255 and defaults to 100.
 *
 * Server:
 * Has no effect.
 */
#define SSL_SetTls13GreaseEchSize(fd, size)           \
    SSL_EXPERIMENTAL_API("SSL_SetTls13GreaseEchSize", \
                         (PRFileDesc * _fd, PRUint8 _size), (fd, size))

/* If |enabled|, a server receiving a Client Hello containing an encrypted_client_hello
 * of type inner will respond with the ECH
 * acceptance signal. This signals the client to continue with the inner
 * transcript rather than outer. */
#define SSL_EnableTls13BackendEch(fd, enabled)        \
    SSL_EXPERIMENTAL_API("SSL_EnableTls13BackendEch", \
                         (PRFileDesc * _fd, PRBool _enabled), (fd, enabled))

/* This allows an extension writer to supply different values for inner and
 * outer ClientHello when using encrypted ClientHello.
 *
 * When enabled, each extension writer can be called more than once for the same
 * message; it must provide the same response when called for the same message
 * type.  When calling the writer to construct the outer ClientHello, the
 * function will be called with ssl_hs_ech_outer_client_hello as the message
 * type (a value from outside the range of valid TLS handshake messages).
 *
 * When disabled, the extension writer is called once for the outer ClientHello
 * and the value is copied to the inner ClientHello.
 *
 * Enabling this affects all extension writers.  The order in which extension
 * writers are added is also important.  Any extension writer that writes
 * different values for inner and outer ClientHello will prevent later
 * extensions from being compressed.
 */
#define SSL_CallExtensionWriterOnEchInner(fd, enabled)        \
    SSL_EXPERIMENTAL_API("SSL_CallExtensionWriterOnEchInner", \
                         (PRFileDesc * _fd, PRBool _enabled), (fd, enabled))

/* Called by the client after an initial ECH connection fails with
 * SSL_ERROR_ECH_RETRY_WITH_ECH. Returns compatible ECHConfigs, which
 * are configured via SetClientEchConfigs for an ECH retry attempt.
 * These configs MUST NOT be used for more than the single retry
 * attempt. Subsequent connections MUST use advertised ECHConfigs. */
#define SSL_GetEchRetryConfigs(fd, out)            \
    SSL_EXPERIMENTAL_API("SSL_GetEchRetryConfigs", \
                         (PRFileDesc * _fd,        \
                          SECItem * _out),         \
                         (fd, out))

/* Called to remove all ECHConfigs from a socket (fd). */
#define SSL_RemoveEchConfigs(fd)                 \
    SSL_EXPERIMENTAL_API("SSL_RemoveEchConfigs", \
                         (PRFileDesc * _fd),     \
                         (fd))

/* Set the ECHConfig and key pair on a socket (server side)
 *
 * fd -- the socket
 * pubKey -- the server's SECKEYPublicKey for HPKE/ECH.
 * privateKey -- the server's SECKEYPrivateKey for HPKE/ECH.
 * record/recordLen -- the encoded DNS record (not base64)
 */
#define SSL_SetServerEchConfigs(fd, pubKey,                                 \
                                privKey, record, recordLen)                 \
    SSL_EXPERIMENTAL_API("SSL_SetServerEchConfigs",                         \
                         (PRFileDesc * _fd,                                 \
                          const SECKEYPublicKey *_pubKey,                   \
                          const SECKEYPrivateKey *_privKey,                 \
                          const PRUint8 *_record, unsigned int _recordLen), \
                         (fd, pubKey, privKey,                              \
                          record, recordLen))

/* Set ECHConfig(s) on a client. The first supported ECHConfig will be used.
 *
 * fd -- the socket
 * echConfigs/echConfigsLen -- the ECHConfigs structure (not base64)
 */
#define SSL_SetClientEchConfigs(fd, echConfigs, echConfigsLen) \
    SSL_EXPERIMENTAL_API("SSL_SetClientEchConfigs",            \
                         (PRFileDesc * _fd,                    \
                          const PRUint8 *_echConfigs,          \
                          unsigned int _echConfigsLen),        \
                         (fd, echConfigs, echConfigsLen))

/*
 * Generate an encoded ECHConfig structure (presumably server side).
 *
 * configId -- an identifier for the configuration.
 * publicName -- the public_name value to be placed in SNI.
 * maxNameLen -- the maximum length of protected names
 * kemId -- the HKPE KEM ID value
 * pubKey -- the public key for the key pair
 * hpkeSuites -- the HPKE cipher suites that can be used
 * hpkeSuitesCount -- the number of suites in hpkeSuites
 * out/outlen/maxlen -- where to output the data
 */
typedef struct HpkeSymmetricSuiteStr {
    HpkeKdfId kdfId;
    HpkeAeadId aeadId;
} HpkeSymmetricSuite;
#define SSL_EncodeEchConfigId(configId, publicName, maxNameLen,          \
                              kemId, pubKey, hpkeSuites, hpkeSuiteCount, \
                              out, outlen, maxlen)                       \
    SSL_EXPERIMENTAL_API("SSL_EncodeEchConfigId",                        \
                         (PRUint8 _configId, const char *_publicName,    \
                          unsigned int _maxNameLen, HpkeKemId _kemId,    \
                          const SECKEYPublicKey *_pubKey,                \
                          const HpkeSymmetricSuite *_hpkeSuites,         \
                          unsigned int _hpkeSuiteCount,                  \
                          PRUint8 *_out, unsigned int *_outlen,          \
                          unsigned int _maxlen),                         \
                         (configId, publicName, maxNameLen,              \
                          kemId, pubKey, hpkeSuites, hpkeSuiteCount,     \
                          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.
 *
 * Note: SSL_MakeAead internally calls SSL_MakeVariantAead with a variant of
 * "stream", behaving as noted above. If "datagram" variant is passed instead,
 * the Label prefix used in HKDF-Expand is "dtls13" instead of "tls13 ". See
 * 7.1 of RFC 8446 and draft-ietf-tls-dtls13-34. */
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_MakeVariantAead(version, cipherSuite, variant, secret,  \
                            labelPrefix, labelPrefixLen, ctx)       \
    SSL_EXPERIMENTAL_API("SSL_MakeVariantAead",                     \
                         (PRUint16 _version, PRUint16 _cipherSuite, \
                          SSLProtocolVariant _variant,              \
                          PK11SymKey * _secret,                     \
                          const char *_labelPrefix,                 \
                          unsigned int _labelPrefixLen,             \
                          SSLAeadContext **_ctx),                   \
                         (version, cipherSuite, variant, 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 and SSL_HkdfVariantExpandLabel produce a key with a
 * mechanism that is suitable for input to SSL_HkdfExpandLabel or SSL_MakeAead.
 *
 * Note: SSL_HkdfVariantExpandLabel internally calls SSL_HkdfExpandLabel with
 * a default "stream" variant. If "datagram" variant is passed instead, the
 * Label prefix used in HKDF-Expand is "dtls13" instead of "tls13 ". See 7.1 of
 * RFC 8446 and draft-ietf-tls-dtls13-34. */
#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))

#define SSL_HkdfVariantExpandLabel(version, cipherSuite, prk,                   \
                                   hsHash, hsHashLen, label, labelLen, variant, \
                                   keyp)                                        \
    SSL_EXPERIMENTAL_API("SSL_HkdfVariantExpandLabel",                          \
                         (PRUint16 _version, PRUint16 _cipherSuite,             \
                          PK11SymKey * _prk,                                    \
                          const PRUint8 *_hsHash, unsigned int _hsHashLen,      \
                          const char *_label, unsigned int _labelLen,           \
                          SSLProtocolVariant _variant,                          \
                          PK11SymKey **_keyp),                                  \
                         (version, cipherSuite, prk,                            \
                          hsHash, hsHashLen, label, labelLen, variant,          \
                          keyp))

/* SSL_HkdfExpandLabelWithMech and SSL_HkdfVariantExpandLabelWithMech use 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.
 *
 * Note: SSL_HkdfExpandLabelWithMech internally calls SSL_HkdfVariantExpandLabelWithMech
 * with a default "stream" variant. If "datagram" variant is passed instead, the
 * Label prefix used in HKDF-Expand is "dtls13" instead of "tls13 ". See 7.1 of
 * RFC 8446 and draft-ietf-tls-dtls13-34. */
#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))

#define SSL_HkdfVariantExpandLabelWithMech(version, cipherSuite, prk,          \
                                           hsHash, hsHashLen, label, labelLen, \
                                           mech, keySize, variant, keyp)       \
    SSL_EXPERIMENTAL_API("SSL_HkdfVariantExpandLabelWithMech",                 \
                         (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,      \
                          SSLProtocolVariant _variant,                         \
                          PK11SymKey **_keyp),                                 \
                         (version, cipherSuite, prk,                           \
                          hsHash, hsHashLen, label, labelLen,                  \
                          mech, keySize, variant, 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))

/*
 * The following functions expose a masking primitive that uses ciphersuite and
 * version information to set paramaters for the masking key and mask generation
 * logic. 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, label, "", L), where |label| is an input to
 * SSL_CreateMaskingContext.
 *
 * The mask generation logic in SSL_CreateMask is determined by the underlying
 * symmetric cipher:
 *  - For AES-ECB, mask = AES-ECB(mask_key, sample). |len| must be <= 16 as
 *    the output is limited to a single block.
 *  - For CHACHA20, mask = ChaCha20(mask_key, sample[0..3], sample[4..15], {0}.len)
 *    That is, the low 4 bytes of |sample| used as the counter, the remaining 12 bytes
 *    the nonce. We encrypt |len| bytes of zeros, returning the raw key stream.
 *
 *  The caller must pre-allocate at least |len| bytes for output. If the underlying
 *  cipher cannot produce the requested amount of data, SECFailure is returned.
 */

typedef struct SSLMaskingContextStr {
    CK_MECHANISM_TYPE mech;
    PRUint16 version;
    PRUint16 cipherSuite;
    PK11SymKey *secret;
} SSLMaskingContext;

#define SSL_CreateMaskingContext(version, cipherSuite, secret,      \
                                 label, labelLen, ctx)              \
    SSL_EXPERIMENTAL_API("SSL_CreateMaskingContext",                \
                         (PRUint16 _version, PRUint16 _cipherSuite, \
                          PK11SymKey * _secret,                     \
                          const char *_label,                       \
                          unsigned int _labelLen,                   \
                          SSLMaskingContext **_ctx),                \
                         (version, cipherSuite, secret, label, labelLen, ctx))

#define SSL_CreateVariantMaskingContext(version, cipherSuite, variant, \
                                        secret, label, labelLen, ctx)  \
    SSL_EXPERIMENTAL_API("SSL_CreateVariantMaskingContext",            \
                         (PRUint16 _version, PRUint16 _cipherSuite,    \
                          SSLProtocolVariant _variant,                 \
                          PK11SymKey * _secret,                        \
                          const char *_label,                          \
                          unsigned int _labelLen,                      \
                          SSLMaskingContext **_ctx),                   \
                         (version, cipherSuite, variant, secret,       \
                          label, labelLen, ctx))

#define SSL_DestroyMaskingContext(ctx)                \
    SSL_EXPERIMENTAL_API("SSL_DestroyMaskingContext", \
                         (SSLMaskingContext * _ctx),  \
                         (ctx))

#define SSL_CreateMask(ctx, sample, sampleLen, mask, maskLen)               \
    SSL_EXPERIMENTAL_API("SSL_CreateMask",                                  \
                         (SSLMaskingContext * _ctx, const PRUint8 *_sample, \
                          unsigned int _sampleLen, PRUint8 *_mask,          \
                          unsigned int _maskLen),                           \
                         (ctx, sample, sampleLen, mask, maskLen))

#define SSL_SetDtls13VersionWorkaround(fd, enabled)        \
    SSL_EXPERIMENTAL_API("SSL_SetDtls13VersionWorkaround", \
                         (PRFileDesc * _fd, PRBool _enabled), (fd, enabled))

/* SSL_AddExternalPsk() and SSL_AddExternalPsk0Rtt() can be used to
 * set an external PSK on a socket. If successful, this PSK will
 * be used in all subsequent connection attempts for this socket.
 * This has no effect if the maximum TLS version is < 1.3.
 *
 * This API currently only accepts a single PSK, so multiple calls to
 * either function will fail. An EPSK can be replaced by calling
 * SSL_RemoveExternalPsk followed by SSL_AddExternalPsk.
 * For both functions, the label is expected to be a unique identifier
 * for the external PSK. Should en external PSK have the same label
 * as a configured resumption PSK identity, the external PSK will
 * take precedence.
 *
 * If you want to enable early data, you need to also provide a
 * cipher suite for 0-RTT and a limit for the early data using
 * SSL_AddExternalPsk0Rtt(). If you want to explicitly disallow
 * certificate authentication, use SSL_AuthCertificateHook to set
 * a callback that rejects all certificate chains.
 */
#define SSL_AddExternalPsk(fd, psk, identity, identityLen, hash)               \
    SSL_EXPERIMENTAL_API("SSL_AddExternalPsk",                                 \
                         (PRFileDesc * _fd, PK11SymKey * _psk,                 \
                          const PRUint8 *_identity, unsigned int _identityLen, \
                          SSLHashType _hash),                                  \
                         (fd, psk, identity, identityLen, hash))

#define SSL_AddExternalPsk0Rtt(fd, psk, identity, identityLen, hash,           \
                               zeroRttSuite, maxEarlyData)                     \
    SSL_EXPERIMENTAL_API("SSL_AddExternalPsk0Rtt",                             \
                         (PRFileDesc * _fd, PK11SymKey * _psk,                 \
                          const PRUint8 *_identity, unsigned int _identityLen, \
                          SSLHashType _hash, PRUint16 _zeroRttSuite,           \
                          PRUint32 _maxEarlyData),                             \
                         (fd, psk, identity, identityLen, hash,                \
                          zeroRttSuite, maxEarlyData))

/* SSLExp_RemoveExternalPsk() removes an external PSK from socket
 * configuration. Returns SECSuccess if the PSK was removed
 * successfully, and SECFailure otherwise. */
#define SSL_RemoveExternalPsk(fd, identity, identityLen)              \
    SSL_EXPERIMENTAL_API("SSL_RemoveExternalPsk",                     \
                         (PRFileDesc * _fd, const PRUint8 *_identity, \
                          unsigned int _identityLen),                 \
                         (fd, identity, identityLen))

/* The next function is used to provide support for TLS RFC 8879 
 * (Certificate Compression). 
 * 
 * The function SSL_SetCertificateCompressionAlgorithm() adds a certificate
 * compression mechanism to the socket fd. */

#define SSL_SetCertificateCompressionAlgorithm(fd, t)              \
    SSL_EXPERIMENTAL_API("SSL_SetCertificateCompressionAlgorithm", \
                         (PRFileDesc * _fd,                        \
                          SSLCertificateCompressionAlgorithm t),   \
                         (fd, t))

/* 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
#define SSL_EnableESNI(a, b, c, d) SSL_DEPRECATED_EXPERIMENTAL_API
#define SSL_EncodeESNIKeys(a, b, c, d, e, f, g, h, i, j) SSL_DEPRECATED_EXPERIMENTAL_API
#define SSL_SetESNIKeyPair(a, b, c, d) SSL_DEPRECATED_EXPERIMENTAL_API
#define SSL_EncodeEchConfig(a, b, c, d, e, f, g, h, i) SSL_DEPRECATED_EXPERIMENTAL_API

SEC_END_PROTOS

#endif /* __sslexp_h_ */