Dinesh Belwalkar | e63f7f9 | 2019-11-22 23:11:16 +0000 | [diff] [blame^] | 1 | // Package gssapi implements Generic Security Services Application Program Interface required for SPNEGO kerberos authentication. |
| 2 | package gssapi |
| 3 | |
| 4 | import ( |
| 5 | "context" |
| 6 | "fmt" |
| 7 | |
| 8 | "github.com/jcmturner/gofork/encoding/asn1" |
| 9 | ) |
| 10 | |
| 11 | // GSS-API OID names |
| 12 | const ( |
| 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 |
| 20 | const ( |
| 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. |
| 49 | type ContextToken interface { |
| 50 | Marshal() ([]byte, error) |
| 51 | Unmarshal(b []byte) error |
| 52 | Verify() (bool, Status) |
| 53 | Context() context.Context |
| 54 | } |
| 55 | |
| 56 | /* |
| 57 | CREDENTIAL MANAGEMENT |
| 58 | |
| 59 | GSS_Acquire_cred acquire credentials for use |
| 60 | GSS_Release_cred release credentials after use |
| 61 | GSS_Inquire_cred display information about credentials |
| 62 | GSS_Add_cred construct credentials incrementally |
| 63 | GSS_Inquire_cred_by_mech display per-mechanism credential information |
| 64 | |
| 65 | CONTEXT-LEVEL CALLS |
| 66 | |
| 67 | GSS_Init_sec_context initiate outbound security context |
| 68 | GSS_Accept_sec_context accept inbound security context |
| 69 | GSS_Delete_sec_context flush context when no longer needed |
| 70 | GSS_Process_context_token process received control token on context |
| 71 | GSS_Context_time indicate validity time remaining on context |
| 72 | GSS_Inquire_context display information about context |
| 73 | GSS_Wrap_size_limit determine GSS_Wrap token size limit |
| 74 | GSS_Export_sec_context transfer context to other process |
| 75 | GSS_Import_sec_context import transferred context |
| 76 | |
| 77 | PER-MESSAGE CALLS |
| 78 | |
| 79 | GSS_GetMIC apply integrity check, receive as token separate from message |
| 80 | GSS_VerifyMIC validate integrity check token along with message |
| 81 | GSS_Wrap sign, optionally encrypt, encapsulate |
| 82 | GSS_Unwrap decapsulate, decrypt if needed, validate integrity check |
| 83 | |
| 84 | SUPPORT CALLS |
| 85 | |
| 86 | GSS_Display_status translate status codes to printable form |
| 87 | GSS_Indicate_mechs indicate mech_types supported on local system |
| 88 | GSS_Compare_name compare two names for equality |
| 89 | GSS_Display_name translate name to printable form |
| 90 | GSS_Import_name convert printable name to normalized form |
| 91 | GSS_Release_name free storage of normalized-form name |
| 92 | GSS_Release_buffer free storage of general GSS-allocated object |
| 93 | GSS_Release_OID_set free storage of OID set object |
| 94 | GSS_Create_empty_OID_set create empty OID set |
| 95 | GSS_Add_OID_set_member add member to OID set |
| 96 | GSS_Test_OID_set_member test if OID is member of OID set |
| 97 | GSS_Inquire_names_for_mech indicate name types supported by mechanism |
| 98 | GSS_Inquire_mechs_for_name indicates mechanisms supporting name type |
| 99 | GSS_Canonicalize_name translate name to per-mechanism form |
| 100 | GSS_Export_name externalize per-mechanism name |
| 101 | GSS_Duplicate_name duplicate name object |
| 102 | */ |
| 103 | |
| 104 | // Mechanism is the GSS-API interface for authentication mechanisms. |
| 105 | type 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. |
| 117 | type OIDName string |
| 118 | |
| 119 | // OID returns the OID for the provided OID name. |
| 120 | func 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. |
| 133 | type Status struct { |
| 134 | Code int |
| 135 | Message string |
| 136 | } |
| 137 | |
| 138 | // Error returns the Status description. |
| 139 | func (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 | } |