2
Unix SMB/CIFS implementation.
4
RFC2478 Compliant SPNEGO implementation
6
Copyright (C) Jim McDonough <jmcd@us.ibm.com> 2003
8
This program is free software; you can redistribute it and/or modify
9
it under the terms of the GNU General Public License as published by
10
the Free Software Foundation; either version 2 of the License, or
11
(at your option) any later version.
13
This program is distributed in the hope that it will be useful,
14
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
GNU General Public License for more details.
19
You should have received a copy of the GNU General Public License
20
along with this program; if not, write to the Free Software
21
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27
#define DBGC_CLASS DBGC_AUTH
29
static BOOL read_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
33
asn1_start_tag(asn1, ASN1_CONTEXT(0));
34
asn1_start_tag(asn1, ASN1_SEQUENCE(0));
36
while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
39
switch (asn1->data[asn1->ofs]) {
42
asn1_start_tag(asn1, ASN1_CONTEXT(0));
43
asn1_start_tag(asn1, ASN1_SEQUENCE(0));
45
token->mechTypes = malloc(sizeof(*token->mechTypes));
46
for (i = 0; !asn1->has_error &&
47
0 < asn1_tag_remaining(asn1); i++) {
49
realloc(token->mechTypes, (i + 2) *
50
sizeof(*token->mechTypes));
51
asn1_read_OID(asn1, token->mechTypes + i);
53
token->mechTypes[i] = NULL;
60
asn1_start_tag(asn1, ASN1_CONTEXT(1));
61
asn1_read_Integer(asn1, &token->reqFlags);
62
token->reqFlags |= SPNEGO_REQ_FLAG;
67
asn1_start_tag(asn1, ASN1_CONTEXT(2));
68
asn1_read_OctetString(asn1, &token->mechToken);
73
asn1_start_tag(asn1, ASN1_CONTEXT(3));
74
if (asn1->data[asn1->ofs] == ASN1_OCTET_STRING) {
75
asn1_read_OctetString(asn1,
78
/* RFC 2478 says we have an Octet String here,
79
but W2k sends something different... */
81
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
82
asn1_push_tag(asn1, ASN1_CONTEXT(0));
83
asn1_read_GeneralString(asn1, &mechListMIC);
88
data_blob(mechListMIC, strlen(mechListMIC));
89
SAFE_FREE(mechListMIC);
94
asn1->has_error = True;
102
return !asn1->has_error;
105
static BOOL write_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
107
asn1_push_tag(asn1, ASN1_CONTEXT(0));
108
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
110
/* Write mechTypes */
111
if (token->mechTypes && *token->mechTypes) {
114
asn1_push_tag(asn1, ASN1_CONTEXT(0));
115
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
116
for (i = 0; token->mechTypes[i]; i++) {
117
asn1_write_OID(asn1, token->mechTypes[i]);
124
if (token->reqFlags & SPNEGO_REQ_FLAG) {
125
int flags = token->reqFlags & ~SPNEGO_REQ_FLAG;
127
asn1_push_tag(asn1, ASN1_CONTEXT(1));
128
asn1_write_Integer(asn1, flags);
132
/* write mechToken */
133
if (token->mechToken.data) {
134
asn1_push_tag(asn1, ASN1_CONTEXT(2));
135
asn1_write_OctetString(asn1, token->mechToken.data,
136
token->mechToken.length);
140
/* write mechListMIC */
141
if (token->mechListMIC.data) {
142
asn1_push_tag(asn1, ASN1_CONTEXT(3));
144
/* This is what RFC 2478 says ... */
145
asn1_write_OctetString(asn1, token->mechListMIC.data,
146
token->mechListMIC.length);
148
/* ... but unfortunately this is what Windows
150
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
151
asn1_push_tag(asn1, ASN1_CONTEXT(0));
152
asn1_push_tag(asn1, ASN1_GENERAL_STRING);
153
asn1_write(asn1, token->mechListMIC.data,
154
token->mechListMIC.length);
165
return !asn1->has_error;
168
static BOOL read_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
172
asn1_start_tag(asn1, ASN1_CONTEXT(1));
173
asn1_start_tag(asn1, ASN1_SEQUENCE(0));
175
while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
176
switch (asn1->data[asn1->ofs]) {
177
case ASN1_CONTEXT(0):
178
asn1_start_tag(asn1, ASN1_CONTEXT(0));
179
asn1_start_tag(asn1, ASN1_ENUMERATED);
180
asn1_read_uint8(asn1, &token->negResult);
184
case ASN1_CONTEXT(1):
185
asn1_start_tag(asn1, ASN1_CONTEXT(1));
186
asn1_read_OID(asn1, &token->supportedMech);
189
case ASN1_CONTEXT(2):
190
asn1_start_tag(asn1, ASN1_CONTEXT(2));
191
asn1_read_OctetString(asn1, &token->responseToken);
194
case ASN1_CONTEXT(3):
195
asn1_start_tag(asn1, ASN1_CONTEXT(3));
196
asn1_read_OctetString(asn1, &token->mechListMIC);
200
asn1->has_error = True;
208
return !asn1->has_error;
211
static BOOL write_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
213
asn1_push_tag(asn1, ASN1_CONTEXT(1));
214
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
216
asn1_push_tag(asn1, ASN1_CONTEXT(0));
217
asn1_write_enumerated(asn1, token->negResult);
220
if (token->supportedMech) {
221
asn1_push_tag(asn1, ASN1_CONTEXT(1));
222
asn1_write_OID(asn1, token->supportedMech);
226
if (token->responseToken.data) {
227
asn1_push_tag(asn1, ASN1_CONTEXT(2));
228
asn1_write_OctetString(asn1, token->responseToken.data,
229
token->responseToken.length);
233
if (token->mechListMIC.data) {
234
asn1_push_tag(asn1, ASN1_CONTEXT(3));
235
asn1_write_OctetString(asn1, token->mechListMIC.data,
236
token->mechListMIC.length);
243
return !asn1->has_error;
246
ssize_t read_spnego_data(DATA_BLOB data, SPNEGO_DATA *token)
253
asn1_load(&asn1, data);
255
switch (asn1.data[asn1.ofs]) {
256
case ASN1_APPLICATION(0):
257
asn1_start_tag(&asn1, ASN1_APPLICATION(0));
258
asn1_check_OID(&asn1, OID_SPNEGO);
259
if (read_negTokenInit(&asn1, &token->negTokenInit)) {
260
token->type = SPNEGO_NEG_TOKEN_INIT;
264
case ASN1_CONTEXT(1):
265
if (read_negTokenTarg(&asn1, &token->negTokenTarg)) {
266
token->type = SPNEGO_NEG_TOKEN_TARG;
273
if (!asn1.has_error) ret = asn1.ofs;
279
ssize_t write_spnego_data(DATA_BLOB *blob, SPNEGO_DATA *spnego)
286
switch (spnego->type) {
287
case SPNEGO_NEG_TOKEN_INIT:
288
asn1_push_tag(&asn1, ASN1_APPLICATION(0));
289
asn1_write_OID(&asn1, OID_SPNEGO);
290
write_negTokenInit(&asn1, &spnego->negTokenInit);
293
case SPNEGO_NEG_TOKEN_TARG:
294
write_negTokenTarg(&asn1, &spnego->negTokenTarg);
297
asn1.has_error = True;
301
if (!asn1.has_error) {
302
*blob = data_blob(asn1.data, asn1.length);
310
BOOL free_spnego_data(SPNEGO_DATA *spnego)
314
if (!spnego) goto out;
316
switch(spnego->type) {
317
case SPNEGO_NEG_TOKEN_INIT:
318
if (spnego->negTokenInit.mechTypes) {
320
for (i = 0; spnego->negTokenInit.mechTypes[i]; i++) {
321
free(spnego->negTokenInit.mechTypes[i]);
323
free(spnego->negTokenInit.mechTypes);
325
data_blob_free(&spnego->negTokenInit.mechToken);
326
data_blob_free(&spnego->negTokenInit.mechListMIC);
328
case SPNEGO_NEG_TOKEN_TARG:
329
if (spnego->negTokenTarg.supportedMech) {
330
free(spnego->negTokenTarg.supportedMech);
332
data_blob_free(&spnego->negTokenTarg.responseToken);
333
data_blob_free(&spnego->negTokenTarg.mechListMIC);
339
ZERO_STRUCTP(spnego);