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
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
|
Internet Engineering Task Force (IETF) B. Kaduk
Request for Comments: 7546 MIT
Category: Informational May 2015
ISSN: 2070-1721
Structure of the Generic Security Service (GSS) Negotiation Loop
Abstract
This document specifies the generic structure of the negotiation loop
to establish a Generic Security Service (GSS) security context
between initiator and acceptor. The control flow of the loop is
indicated for both parties, including error conditions, and
indications are given for where application-specific behavior must be
specified.
Status of This Memo
This document is not an Internet Standards Track specification; it is
published for informational purposes.
This document is a product of the Internet Engineering Task Force
(IETF). It represents the consensus of the IETF community. It has
received public review and has been approved for publication by the
Internet Engineering Steering Group (IESG). Not all documents
approved by the IESG are a candidate for any level of Internet
Standard; see Section 2 of RFC 5741.
Information about the current status of this document, any errata,
and how to provide feedback on it may be obtained at
http://www.rfc-editor.org/info/rfc7546.
Copyright Notice
Copyright (c) 2015 IETF Trust and the persons identified as the
document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal
Provisions Relating to IETF Documents
(http://trustee.ietf.org/license-info) in effect on the date of
publication of this document. Please review these documents
carefully, as they describe your rights and restrictions with respect
to this document. Code Components extracted from this document must
include Simplified BSD License text as described in Section 4.e of
the Trust Legal Provisions and are provided without warranty as
described in the Simplified BSD License.
Kaduk Informational [Page 1]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
Table of Contents
1. Introduction ....................................................2
2. Application Protocol Requirements ...............................3
3. Loop Structure ..................................................4
3.1. Anonymous Initiators .......................................5
3.2. GSS_Init_sec_context .......................................5
3.3. Sending from Initiator to Acceptor .........................6
3.4. Acceptor Sanity Checking ...................................6
3.5. GSS_Accept_sec_context .....................................7
3.6. Sending from Acceptor to Initiator .........................8
3.7. Initiator Input Validation .................................9
3.8. Continue the Loop ..........................................9
4. After Security Context Negotiation ..............................9
4.1. Authorization Checks ......................................10
4.2. Using Partially Complete Security Contexts ................10
4.3. Additional Context Tokens .................................11
5. Sample Code ....................................................12
5.1. GSS Application Sample Code ...............................13
6. Security Considerations ........................................19
7. References .....................................................20
7.1. Normative References ......................................20
7.2. Informative References ....................................20
Acknowledgements ..................................................21
Author's Address ..................................................21
1. Introduction
"Generic Security Service Application Program Interface Version 2,
Update 1" [RFC2743] provides a generic interface for security
services in the form of an abstraction layer over the underlying
security mechanisms that an application may use. A GSS initiator and
acceptor exchange messages, called "tokens", until a security context
is established. Such a security context allows for each party to
authenticate the other, the passing of confidential and/or integrity-
protected messages between the initiator and acceptor, the generation
of identical pseudorandom bit strings by both participants [RFC4401],
and more.
During context establishment, security context tokens are exchanged
synchronously, one at a time; the initiator sends the first context
token. The number of tokens that must be exchanged between the
initiator and acceptor in order to establish the security context is
dependent on the underlying mechanism as well as the desired
properties of the security context and is, in general, not known to
the application. Accordingly, the application's control flow must
include a loop within which GSS security context tokens are
exchanged; the loop terminates upon successful establishment of a
Kaduk Informational [Page 2]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
security context or an error condition. The GSS-API, together with
its security mechanisms, specifies the format and encoding of the
context tokens themselves, but the application protocol must specify
the necessary framing for the application to determine what octet
strings constitute GSS security context tokens and pass them into the
GSS-API implementation as appropriate.
The GSS-API C-bindings [RFC2744] provide some example code for such a
negotiation loop, but this code does not specify the application's
behavior on unexpected or error conditions. As such, individual
application protocol specifications have had to specify the structure
of their GSS negotiation loops, including error handling, on a per-
protocol basis (see [RFC4462], [RFC3645], [RFC5801], [RFC4752], and
[RFC2203]). This represents a substantial duplication of effort, and
the various specifications go into different levels of detail and
describe different possible error conditions. Therefore, it is
preferable to have the structure of the GSS negotiation loop,
including error conditions and token passing, described in a single
specification that can then be referred to from other documents in
lieu of repeating the structure of the loop each time. This document
fills that role.
The necessary requirements for correctly performing a GSS negotiation
loop are essentially all included in [RFC2743], but they are
scattered in many different places. This document brings all the
requirements together into one place for the convenience of
implementors, even though the normative requirements remain in
[RFC2743]. In a few places, this document notes additional behavior
that is useful for applications but is not mandated by [RFC2743].
2. Application Protocol Requirements
Part of the purpose of this document is to guide the development of
new application protocols using the GSS-API, as well as the
development of new application software using such protocols. The
following list consists of features that are necessary or useful in
such an application protocol:
o Protocols require a way to frame and identify security context
negotiation tokens during the GSS negotiation loop.
o Error tokens should generally also get special framing, as the
recipient may have no other way to distinguish unexpected error
context tokens from per-message tokens.
Kaduk Informational [Page 3]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
o Protocols may benefit from a generic means of indicating an error,
possibly accompanied by a descriptive string, to be used if error
tokens are not available or not usable due to constraints of the
application protocol.
o A protocol may use the negotiated GSS security context for per-
message operations; in such cases, the protocol will need a way to
frame and identify those per-message tokens and the nature of
their contents. For example, a protocol message may be
accompanied by the output of GSS_GetMIC() over that message; the
protocol must identify the location and size of that Message
Identity Code (MIC) token and indicate that it is a MIC token and
to what cleartext it corresponds.
o Applications are responsible for authorization of the
authenticated peer principal names that are supplied by the GSS-
API. Such names are mechanism specific and may come from a
different portion of a federated identity scheme. Application
protocols may need to supply additional information to support the
authorization of access to a given resource, such as the Secure
Shell version 2 (SSHv2) "username" parameter.
3. Loop Structure
The loop is begun by the appropriately named initiator, which calls
GSS_Init_sec_context() with an empty (zero-length) input_token and a
fixed set of input flags containing the desired attributes for the
security context. The initiator should not change any of the input
parameters to GSS_Init_sec_context() between calls to it during the
loop, with the exception of the input_token parameter, which will
contain a message from the acceptor after the initial call, and the
input_context_handle, which must be the result returned in the
output_context_handle of the previous call to GSS_Init_sec_context()
(GSS_C_NO_CONTEXT for the first call). (In the C bindings, there is
only a single read/modify context_handle argument, so the same
variable should be passed for each call in the loop.) RFC 2743 only
requires that the claimant_cred_handle argument remain constant over
all calls in the loop, but the other non-excepted arguments should
also remain fixed for reliable operation.
The following subsections will describe the various steps of the
loop, without special consideration to whether a call to
GSS_Init_sec_context() or GSS_Accept_sec_context() is the first such
call in the loop.
Kaduk Informational [Page 4]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
3.1. Anonymous Initiators
If the initiator is requesting anonymity by setting the anon_req_flag
input to GSS_Init_sec_context(), then on non-error returns from
GSS_Init_sec_context() (that is, when the major status is
GSS_S_COMPLETE or GSS_S_CONTINUE_NEEDED) the initiator must verify
that the output value of anon_state from GSS_Init_sec_context() is
true before sending the security context token to the acceptor.
Failing to perform this check could cause the initiator to lose
anonymity.
3.2. GSS_Init_sec_context
The initiator calls GSS_Init_sec_context() using the
input_context_handle for the current security context being
established and its fixed set of input parameters and the input_token
received from the acceptor (if this is not the first iteration of the
loop). The presence or absence of a nonempty output_token and the
value of the major status code are the indicators for how to proceed:
o If the major status code is GSS_S_COMPLETE and the output_token is
empty, then the context negotiation is fully complete and ready
for use by the initiator with no further actions.
o If the major status code is GSS_S_COMPLETE and the output_token is
nonempty, then the initiator's portion of the security context
negotiation is complete but the acceptor's is not. The initiator
must send the output_token to the acceptor so that the acceptor
can establish its half of the security context.
o If the major status code is GSS_S_CONTINUE_NEEDED and the
output_token is nonempty, the context negotiation is incomplete.
The initiator must send the output_token to the acceptor and await
another input_token from the acceptor.
o If the major status code is GSS_S_CONTINUE_NEEDED and the
output_token is empty, the mechanism has produced an output that
is not compliant with [RFC2743]. However, there are some known
implementations of certain mechanisms such as NT LAN Manager
Security Support Provider [NTLMSSP] that do produce empty context
negotiation tokens. For maximum interoperability, applications
should be prepared to accept such tokens and should transmit them
to the acceptor if they are generated.
Kaduk Informational [Page 5]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
o If the major status code is any other value, the context
negotiation has failed. If the output_token is nonempty, it is an
error token and the initiator should send it to the acceptor. If
the output_token is empty, then the initiator should indicate the
failure to the acceptor if an appropriate application-protocol
channel to do so is available.
3.3. Sending from Initiator to Acceptor
The establishment of a GSS security context between initiator and
acceptor requires some communication channel by which to exchange the
context negotiation tokens. The nature of this channel is not
specified by the GSS specification -- it could be a dedicated TCP
channel, a UDP-based Remote Procedure Call (RPC) protocol, or any
other sort of channel. In many cases, the channel will be
multiplexed with non-GSS application data; the application protocol
must always provide some means by which the GSS context tokens can be
identified (e.g., length and start location) and passed through to
the mechanism accordingly. The application protocol may also include
a facility for indicating errors from one party to the other, which
can be used to convey errors resulting from GSS-API calls when
appropriate (such as when no error token was generated by the GSS-API
implementation). Note that GSS major and minor status codes are
specified by language bindings, not the abstract API; sending a major
status code and optionally the display form of the two error codes
may be the best that can be done in this case.
However, even the presence of a communication channel does not
necessarily indicate that it is appropriate for the initiator to
indicate such errors. For example, if the acceptor is a stateless or
near-stateless UDP server, there is probably no need for the
initiator to explicitly indicate its failure to the acceptor.
Conditions such as this can be treated in individual application
protocol specifications.
If a regular security context output_token is produced by the call to
GSS_Init_sec_context(), the initiator must transmit this token to the
acceptor over the application's communication channel. If the call
to GSS_Init_sec_context() returns an error token as output_token, it
is recommended that the initiator transmit this token to the acceptor
over the application's communication channel.
3.4. Acceptor Sanity Checking
The acceptor's half of the negotiation loop is triggered by the
receipt of a context token from the initiator. Before calling
GSS_Accept_sec_context(), the acceptor may find it useful to perform
some sanity checks on the state of the negotiation loop.
Kaduk Informational [Page 6]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
If the acceptor receives a context token but was not expecting such a
token (for example, if the acceptor's previous call to
GSS_Accept_sec_context() returned GSS_S_COMPLETE), this is probably
an error condition indicating that the initiator's state is invalid.
See Section 4.3 for some exceptional cases. It is likely appropriate
for the acceptor to report this error condition to the initiator via
the application's communication channel.
If the acceptor is expecting a context token (e.g., if the previous
call to GSS_Accept_sec_context() returned GSS_S_CONTINUE_NEEDED) but
does not receive such a token within a reasonable amount of time
after transmitting the previous output_token to the initiator, the
acceptor should assume that the initiator's state is invalid
(timeout) and fail the GSS negotiation. Again, it is likely
appropriate for the acceptor to report this error condition to the
initiator via the application's communication channel.
3.5. GSS_Accept_sec_context
The GSS acceptor responds to the actions of an initiator; as such,
there should always be a nonempty input_token to calls to
GSS_Accept_sec_context(). The input_context_handle parameter will
always be given as the output_context_handle from the previous call
to GSS_Accept_sec_context() in a given negotiation loop, or
GSS_C_NO_CONTEXT on the first call, but the acceptor_cred_handle and
chan_bindings arguments should remain fixed over the course of a
given GSS negotiation loop. [RFC2743] only requires that the
acceptor_cred_handle remain fixed throughout the loop, but the
chan_bindings argument should also remain fixed for reliable
operation.
The GSS acceptor calls GSS_Accept_sec_context(), using the
input_context_handle for the current security context being
established and the input_token received from the initiator. The
presence or absence of a nonempty output_token and the value of the
major status code are the indicators for how to proceed:
o If the major status code is GSS_S_COMPLETE and the output_token is
empty, then the context negotiation is fully complete and ready
for use by the acceptor with no further actions.
o If the major status code is GSS_S_COMPLETE and the output_token is
nonempty, then the acceptor's portion of the security context
negotiation is complete but the initiator's is not. The acceptor
must send the output_token to the initiator so that the initiator
can establish its half of the security context.
Kaduk Informational [Page 7]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
o If the major status code is GSS_S_CONTINUE_NEEDED and the
output_token is nonempty, the context negotiation is incomplete.
The acceptor must send the output_token to the initiator and await
another input_token from the initiator.
o If the major status code is GSS_S_CONTINUE_NEEDED and the
output_token is empty, the mechanism has produced an output that
is not compliant with [RFC2743]. However, there are some known
implementations of certain mechanisms such as NTLMSSP [NTLMSSP]
that do produce empty context negotiation tokens. For maximum
interoperability, applications should be prepared to accept such
tokens and should transmit them to the initiator if they are
generated.
o If the major status code is any other value, the context
negotiation has failed. If the output_token is nonempty, it is an
error token and the acceptor should send it to the initiator. If
the output_token is empty, then the acceptor should indicate the
failure to the initiator if an appropriate application-protocol
channel to do so is available.
3.6. Sending from Acceptor to Initiator
The mechanism for sending the context token from acceptor to
initiator will depend on the nature of the communication channel
between the two parties. For a synchronous bidirectional channel, it
can be just another piece of data sent over the link, but for a
stateless UDP RPC acceptor, the token will probably end up being sent
as an RPC output parameter. Application protocol specifications will
need to specify the nature of this behavior.
If the application protocol has the initiator driving the
application's control flow, it is particularly helpful for the
acceptor to indicate a failure to the initiator, as mentioned in some
of the above cases conditional on "an appropriate application-
protocol channel to do so".
If a regular security context output_token is produced by the call to
GSS_Accept_sec_context(), the acceptor must transmit this token to
the initiator over the application's communication channel. If the
call to GSS_Accept_sec_context() returns an error token as
output_token, it is recommended that the acceptor transmit this token
to the initiator over the application's communication channel.
Kaduk Informational [Page 8]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
3.7. Initiator Input Validation
The initiator's half of the negotiation loop is triggered (after the
first call) by receipt of a context token from the acceptor. Before
calling GSS_Init_sec_context(), the initiator may find it useful to
perform some sanity checks on the state of the negotiation loop.
If the initiator receives a context token but was not expecting such
a token (for example, if the initiator's previous call to
GSS_Init_sec_context() returned GSS_S_COMPLETE), this is probably an
error condition indicating that the acceptor's state is invalid. See
Section 4.3 for some exceptional cases. It may be appropriate for
the initiator to report this error condition to the acceptor via the
application's communication channel.
If the initiator is expecting a context token (that is, the previous
call to GSS_Init_sec_context() returned GSS_S_CONTINUE_NEEDED) but
does not receive such a token within a reasonable amount of time
after transmitting the previous output_token to the acceptor, the
initiator should assume that the acceptor's state is invalid and fail
the GSS negotiation. Again, it may be appropriate for the initiator
to report this error condition to the acceptor via the application's
communication channel.
3.8. Continue the Loop
If the loop is in neither a success nor a failure condition, then the
loop must continue. Control flow returns to Section 3.2.
4. After Security Context Negotiation
Once a party has completed its half of the security context and
fulfilled its obligations to the other party, the context is
complete, but it is not necessarily ready and appropriate for use.
In particular, the security context flags may not be appropriate for
the given application's use. In some cases, the context may be ready
for use before the negotiation is complete, see Section 4.2.
The initiator specifies, as part of its fixed set of inputs to
GSS_Init_sec_context(), values for all defined request flag booleans,
among them: deleg_req_flag, mutual_req_flag, replay_det_req_flag,
sequence_req_flag, conf_req_flag, and integ_req_flag. Upon
completion of the security context negotiation, the initiator must
verify that the values of deleg_state, mutual_state,
replay_det_state, sequence_state, conf_avail, and integ_avail (and
any additional flags added by extensions) from the last call to
GSS_Init_sec_context() correspond to the requested flags. If a flag
Kaduk Informational [Page 9]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
was requested but is not available and that feature is necessary for
the application protocol, the initiator must destroy the security
context and not use the security context for application traffic.
Application protocol specifications citing this document should
indicate which context flags are required for their application
protocol.
The acceptor receives as output the following booleans: deleg_state,
mutual_state, replay_det_state, sequence_state, anon_state,
trans_state, conf_avail, and integ_avail, and any additional flags
added by extensions to the GSS-API. The acceptor must verify that
any flags necessary for the application protocol are set. If a
necessary flag is not set, the acceptor must destroy the security
context and not use the security context for application traffic.
4.1. Authorization Checks
The acceptor receives as one of the outputs of
GSS_Accept_sec_context() the name of the initiator that has
authenticated during the security context negotiation. Applications
need to implement authorization checks on this received name
('client_name' in the sample code) before providing access to
restricted resources. In particular, security context negotiation
can be successful when the client is anonymous or is from a different
identity realm than the acceptor, depending on the details of the
mechanism used by the GSS-API to establish the security context.
Acceptor applications can check which target name was used by the
initiator, but the details are out of scope for this document. See
Sections 2.2.6 and 1.1.5 of [RFC2743]. Additional information can be
available in GSS-API Naming Extensions [RFC6680].
4.2. Using Partially Complete Security Contexts
For mechanism/flag combinations that require multiple token
exchanges, the GSS-API specification [RFC2743] provides a
prot_ready_state output value from GSS_Init_sec_context() and
GSS_Accept_sec_context(), which indicates when per-message operations
are available. However, many mechanism implementations do not
provide this functionality and the analysis of the security
consequences of its use is rather complicated, so it is not expected
to be useful in most application protocols.
In particular, mutual authentication, replay protection, and other
services (if requested) are services that will be active when
GSS_S_COMPLETE is returned but that are not necessarily active before
the security context is fully established.
Kaduk Informational [Page 10]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
4.3. Additional Context Tokens
Under some conditions, a context token will be received by a party to
a security context negotiation after that party has completed the
negotiation (i.e., after GSS_Init_sec_context() or
GSS_Accept_sec_context() has returned GSS_S_COMPLETE). Such tokens
must be passed to GSS_Process_context_token() for processing. It may
not always be necessary for a mechanism implementation to generate an
error token on the initiator side or for an initiator application to
transmit that token to the acceptor; such decisions are out of scope
for this document. Both peers should always be prepared to process
such tokens and application protocols should provide means by which
they can be transmitted.
Such tokens can be security context deletion tokens, emitted when the
remote party called GSS_Delete_sec_context() with a non-null
output_context_token parameter, or error tokens, emitted when the
remote party experiences an error processing the last token in a
security context negotiation exchange. Errors experienced when
processing tokens earlier in the negotiation would be transmitted as
normal security context tokens and processed by
GSS_Init_sec_context() or GSS_Accept_sec_context(), as appropriate.
With the GSS-API version 2, it is not recommended to use security
context deletion tokens, so error tokens are expected to be the most
common form of additional context token for new application
protocols.
GSS_Process_context_token() may indicate an error in its major_status
field if an error is encountered locally during token processing or
to indicate that an error was encountered on the peer and conveyed in
an error token. See [Err4151] of [RFC2743]. Regardless of the
major_status output of GSS_Process_context_token(),
GSS_Inquire_context() should be used after processing the extra
token, to query the status of the security context and whether it can
supply the features necessary for the application protocol.
At present, all tokens that should be handled by
GSS_Process_context_token() will lead to the security context being
effectively unusable. Future extensions to the GSS-API may allow for
applications to continue to function after a call to
GSS_Process_context_token(), and it is expected that the outputs of
GSS_Inquire_context() will indicate whether it is safe to do so.
However, since there are no such extensions at present (error tokens
and deletion tokens both result in the security context being
essentially unusable), there is no guidance to give to applications
regarding this possibility at this time.
Kaduk Informational [Page 11]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
Even if GSS_Process_context_token() processes an error or deletion
token that renders the context essentially unusable, the resources
associated with the context must eventually be freed with a call to
GSS_Delete_sec_context(), just as would be needed if
GSS_Init_sec_context() or GSS_Accept_sec_context() had returned an
error while processing an input context token and the
input_context_handle was not GSS_C_NO_CONTEXT. RFC 2743 has some
text that is slightly ambiguous in this regard, but the best practice
is to always call GSS_Delete_sec_context().
5. Sample Code
This section gives sample code for the GSS negotiation loop, both for
a regular application and for an application where the initiator
wishes to remain anonymous. Since the code for the two cases is very
similar, the anonymous-specific additions are wrapped in a
conditional check; that check and the conditional code may be ignored
if anonymous processing is not needed.
Since the communication channel between the initiator and acceptor is
a matter for individual application protocols, it is inherently
unspecified at the GSS-API level, which can lead to examples that are
less satisfying than may be desired. For example, the sample code in
[RFC2744] uses an unspecified send_token_to_peer() routine. Fully
correct and general code to frame and transmit tokens requires a
substantial amount of error checking and would detract from the core
purpose of this document, so we only present the function signature
for one example of what such functions might be and leave some
comments in the otherwise empty function bodies.
This sample code is written in C, using the GSS-API C-bindings
[RFC2744]. It uses the macro GSS_ERROR() to help unpack the various
sorts of information that can be stored in the major status field;
supplementary information does not necessarily indicate an error.
Applications written in other languages will need to exercise care
that checks against the major status value are written correctly.
This sample code should be compilable as a standalone program, linked
against a GSS-API library. In addition to supplying implementations
for the token transmission/receipt routines, in order for the program
to successfully run when linked against most GSS-API libraries, the
initiator will need to specify an explicit target name for the
acceptor, which must match the credentials available to the acceptor.
A skeleton for how this may be done is provided, using a dummy name.
This sample code assumes use of v2 of the GSS-API. Applications
wishing to remain compatible with v1 of the GSS-API may need to
perform additional checks in some locations.
Kaduk Informational [Page 12]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
5.1. GSS Application Sample Code
#include <unistd.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gssapi/gssapi.h>
/*
* This helper is used only on buffers that we allocate ourselves (e.g.,
* from receive_token()). Buffers allocated by GSS routines must use
* gss_release_buffer().
*/
static void
release_buffer(gss_buffer_t buf)
{
free(buf->value);
buf->value = NULL;
buf->length = 0;
}
/*
* Helper to send a token on the specified file descriptor.
*
* If errors are encountered, this routine must not directly cause
* termination of the process because compliant GSS applications
* must release resources allocated by the GSS library before
* exiting.
*
* Returns 0 on success, nonzero on failure.
*/
static int
send_token(int fd, gss_buffer_t token)
{
/*
* Supply token framing and transmission code here.
*
* It is advisable for the application protocol to specify the
* length of the token being transmitted unless the underlying
* transit does so implicitly.
*
* In addition to checking for error returns from whichever
* syscall(s) are used to send data, applications should have
* a loop to handle EINTR returns.
*/
return 1;
}
Kaduk Informational [Page 13]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
/*
* Helper to receive a token on the specified file descriptor.
*
* If errors are encountered, this routine must not directly cause
* termination of the process because compliant GSS applications
* must release resources allocated by the GSS library before
* exiting.
*
* Returns 0 on success, nonzero on failure.
*/
static int
receive_token(int fd, gss_buffer_t token)
{
/*
* Supply token framing and transmission code here.
*
* In addition to checking for error returns from whichever
* syscall(s) are used to receive data, applications should have
* a loop to handle EINTR returns.
*
* This routine is assumed to allocate memory for the local copy
* of the received token, which must be freed with release_buffer().
*/
return 1;
}
static void
do_initiator(int readfd, int writefd, int anon)
{
int initiator_established = 0, ret;
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
OM_uint32 major, minor, req_flags, ret_flags;
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc name_buf = GSS_C_EMPTY_BUFFER;
gss_name_t target_name = GSS_C_NO_NAME;
/* Applications should set target_name to a real value. */
name_buf.value = "<service>@<hostname.domain>";
name_buf.length = strlen(name_buf.value);
major = gss_import_name(&minor, &name_buf,
GSS_C_NT_HOSTBASED_SERVICE, &target_name);
if (GSS_ERROR(major)) {
warnx(1, "Could not import name\n");
goto cleanup;
}
Kaduk Informational [Page 14]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
/* Mutual authentication will require a token from acceptor to
* initiator and thus a second call to gss_init_sec_context(). */
req_flags = GSS_C_MUTUAL_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG;
if (anon)
req_flags |= GSS_C_ANON_FLAG;
while (!initiator_established) {
/* The initiator_cred_handle, mech_type, time_req,
* input_chan_bindings, actual_mech_type, and time_rec
* parameters are not needed in many cases. We pass
* GSS_C_NO_CREDENTIAL, GSS_C_NO_OID, 0, NULL, NULL, and NULL
* for them, respectively. */
major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL, &ctx,
target_name, GSS_C_NO_OID,
req_flags, 0, NULL, &input_token,
NULL, &output_token, &ret_flags,
NULL);
/* This was allocated by receive_token() and is no longer
* needed. Free it now to avoid leaks if the loop continues. */
release_buffer(&input_token);
if (anon) {
/* Initiators that wish to remain anonymous must check
* whether their request has been honored before sending
* each token. */
if (!(ret_flags & GSS_C_ANON_FLAG)) {
warnx("Anonymous requested but not available\n");
goto cleanup;
}
}
/* Always send a token if we are expecting another input token
* (GSS_S_CONTINUE_NEEDED is set) or if it is nonempty. */
if ((major & GSS_S_CONTINUE_NEEDED) ||
output_token.length > 0) {
ret = send_token(writefd, &output_token);
if (ret != 0)
goto cleanup;
}
/* Check for errors after sending the token so that we will send
* error tokens. */
if (GSS_ERROR(major)) {
warnx("gss_init_sec_context() error major 0x%x\n", major);
goto cleanup;
}
/* Free the output token's storage; we don't need it anymore.
* gss_release_buffer() is safe to call on the output buffer
* from gss_int_sec_context(), even if there is no storage
* associated with that buffer. */
(void)gss_release_buffer(&minor, &output_token);
Kaduk Informational [Page 15]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
if (major & GSS_S_CONTINUE_NEEDED) {
ret = receive_token(readfd, &input_token);
if (ret != 0)
goto cleanup;
} else if (major == GSS_S_COMPLETE) {
initiator_established = 1;
} else {
/* This situation is forbidden by RFC 2743. Bail out. */
warnx("major not complete or continue but not error\n");
goto cleanup;
}
} /* while (!initiator_established) */
if ((ret_flags & req_flags) != req_flags) {
warnx("Negotiated context does not support requested flags\n");
goto cleanup;
}
printf("Initiator's context negotiation successful\n");
cleanup:
/* We are required to release storage for nonzero-length output
* tokens. gss_release_buffer() zeros the length, so we
* will not attempt to release the same buffer twice. */
if (output_token.length > 0)
(void)gss_release_buffer(&minor, &output_token);
/* Do not request a context deletion token; pass NULL. */
(void)gss_delete_sec_context(&minor, &ctx, NULL);
(void)gss_release_name(&minor, &target_name);
}
/*
* Perform authorization checks on the initiator's GSS name object.
*
* Returns 0 on success (the initiator is authorized) and nonzero
* when the initiator is not authorized.
*/
static int
check_authz(gss_name_t client_name)
{
/*
* Supply authorization checking code here.
*
* Options include bitwise comparison of the exported name against
* a local database and introspection against name attributes.
*/
return 0;
}
Kaduk Informational [Page 16]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
static void
do_acceptor(int readfd, int writefd)
{
int acceptor_established = 0, ret;
gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
OM_uint32 major, minor, ret_flags;
gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
gss_name_t client_name;
major = GSS_S_CONTINUE_NEEDED;
while (!acceptor_established) {
if (major & GSS_S_CONTINUE_NEEDED) {
ret = receive_token(readfd, &input_token);
if (ret != 0)
goto cleanup;
} else if (major == GSS_S_COMPLETE) {
acceptor_established = 1;
break;
} else {
/* This situation is forbidden by RFC 2743. Bail out. */
warnx("major not complete or continue but not error\n");
goto cleanup;
}
/* We can use the default behavior or do not need the returned
* information for the parameters acceptor_cred_handle,
* input_chan_bindings, mech_type, time_rec, and
* delegated_cred_handle, and pass the values
* GSS_C_NO_CREDENTIAL, NULL, NULL, NULL, and NULL,
* respectively. In some cases the src_name will not be
* needed, but most likely it will be needed for some
* authorization or logging functionality. */
major = gss_accept_sec_context(&minor, &ctx,
GSS_C_NO_CREDENTIAL,
&input_token, NULL,
&client_name, NULL,
&output_token, &ret_flags, NULL,
NULL);
/* This was allocated by receive_token() and is no longer
* needed. Free it now to avoid leaks if the loop continues. */
release_buffer(&input_token);
/* Always send a token if we are expecting another input token
* (GSS_S_CONTINUE_NEEDED is set) or if it is nonempty. */
if ((major & GSS_S_CONTINUE_NEEDED) ||
output_token.length > 0) {
ret = send_token(writefd, &output_token);
if (ret != 0)
Kaduk Informational [Page 17]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
goto cleanup;
}
/* Check for errors after sending the token so that we will send
* error tokens. */
if (GSS_ERROR(major)) {
warnx("gss_accept_sec_context() error major 0x%x\n", major);
goto cleanup;
}
/* Free the output token's storage; we don't need it anymore.
* gss_release_buffer() is safe to call on the output buffer
* from gss_accept_sec_context(), even if there is no storage
* associated with that buffer. */
(void)gss_release_buffer(&minor, &output_token);
} /* while (!acceptor_established) */
if (!(ret_flags & GSS_C_INTEG_FLAG)) {
warnx("Negotiated context does not support integrity\n");
goto cleanup;
}
printf("Acceptor's context negotiation successful\n");
ret = check_authz(client_name);
if (ret != 0)
printf("Client is not authorized; rejecting access\n");
cleanup:
release_buffer(&input_token);
/* We are required to release storage for nonzero-length output
* tokens. gss_release_buffer() zeros the length, so we
* will not attempt to release the same buffer twice. */
if (output_token.length > 0)
(void)gss_release_buffer(&minor, &output_token);
/* Do not request a context deletion token, pass NULL. */
(void)gss_delete_sec_context(&minor, &ctx, NULL);
(void)gss_release_name(&minor, &client_name);
}
int
main(void)
{
pid_t pid;
int fd1 = -1, fd2 = -1;
/* Create file descriptors for reading/writing here. */
pid = fork();
if (pid == 0)
do_initiator(fd1, fd2, 0);
else if (pid > 0)
do_acceptor(fd2, fd1);
else
err(1, "fork() failed\n");
Kaduk Informational [Page 18]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
exit(0);
}
6. Security Considerations
This document provides a (reasonably) concise description and example
for correct construction of the GSS-API security context negotiation
loop. Since everything relating to the construction and use of a GSS
security context is security related, there are security-relevant
considerations throughout the document. It is useful to call out a
few things in this section, though.
The GSS-API uses a request-and-check model for features. An
application using the GSS-API requests certain features (e.g.,
confidentiality protection for messages or anonymity), but such a
request does not require the GSS implementation to provide that
feature. The application must check the returned flags to verify
whether a requested feature is present; if the feature was non-
optional for the application, the application must generate an error.
Phrased differently, the GSS-API will not generate an error if it is
unable to satisfy the features requested by the application.
In many cases, it is convenient for GSS acceptors to accept security
contexts using multiple acceptor names (such as by using the default
credential set, as happens when GSS_C_NO_CREDENTIAL is passed to
GSS_Accept_sec_context()). This allows acceptors to use any
credentials to which they have access for accepting security
contexts, which may not be the desired behavior for a given
application. (For example, the Secure Shell daemon (sshd) may wish
to accept only using GSS_C_NT_HOSTBASED credentials of the form
host@<hostname>, and not nfs@<hostname>.) Acceptor applications can
check which target name was used by the initiator, but the details
are out of scope for this document. See Sections 2.2.6 and 1.1.5 of
[RFC2743]
The C sample code uses the macro GSS_ERROR() to assess the return
value of gss_init_sec_context() and gss_accept_sec_context(). This
is done to indicate where checks are needed in writing code for other
languages and what the nature of those checks might be. The C code
could be made simpler by omitting that macro. In applications
expecting to receive protected octet streams, this macro should not
be used on the result of per-message operations, as it omits checking
for supplementary status values such as GSS_S_DUPLICATE_TOKEN,
GSS_S_OLD_TOKEN, etc. Use of the GSS_ERROR() macro on the results of
GSS-API per-message operations has resulted in security
vulnerabilities in existing software.
Kaduk Informational [Page 19]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
The security considerations from RFCs 2743 and 2744 remain applicable
to consumers of this document.
7. References
7.1. Normative References
[RFC2743] Linn, J., "Generic Security Service Application Program
Interface Version 2, Update 1", RFC 2743,
DOI 10.17487/RFC2743, January 2000,
<http://www.rfc-editor.org/info/rfc2743>.
[RFC2744] Wray, J., "Generic Security Service API Version 2 :
C-bindings", RFC 2744, DOI 10.17487/RFC2744, January 2000,
<http://www.rfc-editor.org/info/rfc2744>.
7.2. Informative References
[Err4151] RFC Errata, Erratum ID 4151, RFC 2743.
[NTLMSSP] Microsoft Corporation, "[MS-NLMP]: NT LAN Manager (NTLM)
Authentication Protocol", May 2014,
<https://msdn.microsoft.com/en-us/library/cc236621.aspx>.
[RFC2203] Eisler, M., Chiu, A., and L. Ling, "RPCSEC_GSS Protocol
Specification", RFC 2203, DOI 10.17487/RFC2203, September
1997, <http://www.rfc-editor.org/info/rfc2203>.
[RFC3645] Kwan, S., Garg, P., Gilroy, J., Esibov, L., Westhead, J.,
and R. Hall, "Generic Security Service Algorithm for
Secret Key Transaction Authentication for DNS (GSS-TSIG)",
RFC 3645, DOI 10.17487/RFC3645, October 2003,
<http://www.rfc-editor.org/info/rfc3645>.
[RFC4401] Williams, N., "A Pseudo-Random Function (PRF) API
Extension for the Generic Security Service Application
Program Interface (GSS-API)", RFC 4401,
DOI 10.17487/RFC4401, February 2006,
<http://www.rfc-editor.org/info/rfc4401>.
[RFC4462] Hutzelman, J., Salowey, J., Galbraith, J., and V. Welch,
"Generic Security Service Application Program Interface
(GSS-API) Authentication and Key Exchange for the Secure
Shell (SSH) Protocol", RFC 4462, DOI 10.17487/RFC4462, May
2006, <http://www.rfc-editor.org/info/rfc4462>.
Kaduk Informational [Page 20]
^L
RFC 7546 Structure of the GSS Negotiation Loop May 2015
[RFC4752] Melnikov, A., Ed., "The Kerberos V5 ("GSSAPI") Simple
Authentication and Security Layer (SASL) Mechanism",
RFC 4752, DOI 10.17487/RFC4752, November 2006,
<http://www.rfc-editor.org/info/rfc4752>.
[RFC5801] Josefsson, S. and N. Williams, "Using Generic Security
Service Application Program Interface (GSS-API) Mechanisms
in Simple Authentication and Security Layer (SASL): The
GS2 Mechanism Family", RFC 5801, DOI 10.17487/RFC5801,
July 2010, <http://www.rfc-editor.org/info/rfc5801>.
[RFC6680] Williams, N., Johansson, L., Hartman, S., and S.
Josefsson, "Generic Security Service Application
Programming Interface (GSS-API) Naming Extensions",
RFC 6680, DOI 10.17487/RFC6680, August 2012,
<http://www.rfc-editor.org/info/rfc6680>.
Acknowledgements
Thanks to Nico Williams and Jeff Hutzleman for prompting me to write
this document.
Author's Address
Benjamin Kaduk
MIT Kerberos Consortium
EMail: kaduk@mit.edu
Kaduk Informational [Page 21]
^L
|