1// Package gssapi implements Generic Security Services Application Program Interface required for SPNEGO kerberos authentication.
2package gssapi
3
4import (
5	"context"
6	"fmt"
7
8	"github.com/jcmturner/gofork/encoding/asn1"
9)
10
11// GSS-API OID names
12const (
13	// GSS-API OID names
14	OIDKRB5         OIDName = "KRB5"         // MechType OID for Kerberos 5
15	OIDMSLegacyKRB5 OIDName = "MSLegacyKRB5" // MechType OID for Kerberos 5
16	OIDSPNEGO       OIDName = "SPNEGO"
17)
18
19// GSS-API status values
20const (
21	StatusBadBindings = 1 << iota
22	StatusBadMech
23	StatusBadName
24	StatusBadNameType
25	StatusBadStatus
26	StatusBadSig
27	StatusBadMIC
28	StatusContextExpired
29	StatusCredentialsExpired
30	StatusDefectiveCredential
31	StatusDefectiveToken
32	StatusFailure
33	StatusNoContext
34	StatusNoCred
35	StatusBadQOP
36	StatusUnauthorized
37	StatusUnavailable
38	StatusDuplicateElement
39	StatusNameNotMN
40	StatusComplete
41	StatusContinueNeeded
42	StatusDuplicateToken
43	StatusOldToken
44	StatusUnseqToken
45	StatusGapToken
46)
47
48// ContextToken is an interface for a GSS-API context token.
49type ContextToken interface {
50	Marshal() ([]byte, error)
51	Unmarshal(b []byte) error
52	Verify() (bool, Status)
53	Context() context.Context
54}
55
56/*
57CREDENTIAL MANAGEMENT
58
59GSS_Acquire_cred             acquire credentials for use
60GSS_Release_cred             release credentials after use
61GSS_Inquire_cred             display information about credentials
62GSS_Add_cred                 construct credentials incrementally
63GSS_Inquire_cred_by_mech     display per-mechanism credential information
64
65CONTEXT-LEVEL CALLS
66
67GSS_Init_sec_context         initiate outbound security context
68GSS_Accept_sec_context       accept inbound security context
69GSS_Delete_sec_context       flush context when no longer needed
70GSS_Process_context_token    process received control token on context
71GSS_Context_time             indicate validity time remaining on context
72GSS_Inquire_context          display information about context
73GSS_Wrap_size_limit          determine GSS_Wrap token size limit
74GSS_Export_sec_context       transfer context to other process
75GSS_Import_sec_context       import transferred context
76
77PER-MESSAGE CALLS
78
79GSS_GetMIC                   apply integrity check, receive as token separate from message
80GSS_VerifyMIC                validate integrity check token along with message
81GSS_Wrap                     sign, optionally encrypt, encapsulate
82GSS_Unwrap                   decapsulate, decrypt if needed, validate integrity check
83
84SUPPORT CALLS
85
86GSS_Display_status           translate status codes to printable form
87GSS_Indicate_mechs           indicate mech_types supported on local system
88GSS_Compare_name             compare two names for equality
89GSS_Display_name             translate name to printable form
90GSS_Import_name              convert printable name to normalized form
91GSS_Release_name             free storage of normalized-form name
92GSS_Release_buffer           free storage of general GSS-allocated object
93GSS_Release_OID_set          free storage of OID set object
94GSS_Create_empty_OID_set     create empty OID set
95GSS_Add_OID_set_member       add member to OID set
96GSS_Test_OID_set_member      test if OID is member of OID set
97GSS_Inquire_names_for_mech   indicate name types supported by mechanism
98GSS_Inquire_mechs_for_name   indicates mechanisms supporting name type
99GSS_Canonicalize_name        translate name to per-mechanism form
100GSS_Export_name              externalize per-mechanism name
101GSS_Duplicate_name           duplicate name object
102*/
103
104// Mechanism is the GSS-API interface for authentication mechanisms.
105type Mechanism interface {
106	OID() asn1.ObjectIdentifier
107	AcquireCred() error                                               // acquire credentials for use (eg. AS exchange for KRB5)
108	InitSecContext() (ContextToken, error)                            // initiate outbound security context (eg TGS exchange builds AP_REQ to go into ContextToken to send to service)
109	AcceptSecContext(ct ContextToken) (bool, context.Context, Status) // service verifies the token server side to establish a context
110	MIC() MICToken                                                    // apply integrity check, receive as token separate from message
111	VerifyMIC(mt MICToken) (bool, error)                              // validate integrity check token along with message
112	Wrap(msg []byte) WrapToken                                        // sign, optionally encrypt, encapsulate
113	Unwrap(wt WrapToken) []byte                                       // decapsulate, decrypt if needed, validate integrity check
114}
115
116// OIDName is the type for defined GSS-API OIDs.
117type OIDName string
118
119// OID returns the OID for the provided OID name.
120func OID(o OIDName) asn1.ObjectIdentifier {
121	switch o {
122	case OIDSPNEGO:
123		return asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 2}
124	case OIDKRB5:
125		return asn1.ObjectIdentifier{1, 2, 840, 113554, 1, 2, 2}
126	case OIDMSLegacyKRB5:
127		return asn1.ObjectIdentifier{1, 2, 840, 48018, 1, 2, 2}
128	}
129	return asn1.ObjectIdentifier{}
130}
131
132// Status is the GSS-API status and implements the error interface.
133type Status struct {
134	Code    int
135	Message string
136}
137
138// Error returns the Status description.
139func (s Status) Error() string {
140	var str string
141	switch s.Code {
142	case StatusBadBindings:
143		str = "channel binding mismatch"
144	case StatusBadMech:
145		str = "unsupported mechanism requested"
146	case StatusBadName:
147		str = "invalid name provided"
148	case StatusBadNameType:
149		str = "name of unsupported type provided"
150	case StatusBadStatus:
151		str = "invalid input status selector"
152	case StatusBadSig:
153		str = "token had invalid integrity check"
154	case StatusBadMIC:
155		str = "preferred alias for GSS_S_BAD_SIG"
156	case StatusContextExpired:
157		str = "specified security context expired"
158	case StatusCredentialsExpired:
159		str = "expired credentials detected"
160	case StatusDefectiveCredential:
161		str = "defective credential detected"
162	case StatusDefectiveToken:
163		str = "defective token detected"
164	case StatusFailure:
165		str = "failure, unspecified at GSS-API level"
166	case StatusNoContext:
167		str = "no valid security context specified"
168	case StatusNoCred:
169		str = "no valid credentials provided"
170	case StatusBadQOP:
171		str = "unsupported QOP valu"
172	case StatusUnauthorized:
173		str = "operation unauthorized"
174	case StatusUnavailable:
175		str = "operation unavailable"
176	case StatusDuplicateElement:
177		str = "duplicate credential element requested"
178	case StatusNameNotMN:
179		str = "name contains multi-mechanism elements"
180	case StatusComplete:
181		str = "normal completion"
182	case StatusContinueNeeded:
183		str = "continuation call to routine required"
184	case StatusDuplicateToken:
185		str = "duplicate per-message token detected"
186	case StatusOldToken:
187		str = "timed-out per-message token detected"
188	case StatusUnseqToken:
189		str = "reordered (early) per-message token detected"
190	case StatusGapToken:
191		str = "skipped predecessor token(s) detected"
192	default:
193		str = "unknown GSS-API error status"
194	}
195	if s.Message != "" {
196		return fmt.Sprintf("%s: %s", str, s.Message)
197	}
198	return str
199}
200