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 = SMB_MALLOC_P(const char *);
46
for (i = 0; !asn1->has_error &&
47
0 < asn1_tag_remaining(asn1); i++) {
50
SMB_REALLOC_ARRAY(token->mechTypes, const char *, i + 2);
51
if (!token->mechTypes) {
52
asn1->has_error = True;
55
asn1_read_OID(asn1, &p_oid);
56
token->mechTypes[i] = p_oid;
58
token->mechTypes[i] = NULL;
65
asn1_start_tag(asn1, ASN1_CONTEXT(1));
66
asn1_read_Integer(asn1, &token->reqFlags);
67
token->reqFlags |= SPNEGO_REQ_FLAG;
72
asn1_start_tag(asn1, ASN1_CONTEXT(2));
73
asn1_read_OctetString(asn1, &token->mechToken);
78
asn1_start_tag(asn1, ASN1_CONTEXT(3));
79
if (asn1->data[asn1->ofs] == ASN1_OCTET_STRING) {
80
asn1_read_OctetString(asn1,
83
/* RFC 2478 says we have an Octet String here,
84
but W2k sends something different... */
86
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
87
asn1_push_tag(asn1, ASN1_CONTEXT(0));
88
asn1_read_GeneralString(asn1, &mechListMIC);
93
data_blob(mechListMIC, strlen(mechListMIC));
94
SAFE_FREE(mechListMIC);
99
asn1->has_error = True;
107
return !asn1->has_error;
110
static BOOL write_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
112
asn1_push_tag(asn1, ASN1_CONTEXT(0));
113
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
115
/* Write mechTypes */
116
if (token->mechTypes && *token->mechTypes) {
119
asn1_push_tag(asn1, ASN1_CONTEXT(0));
120
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
121
for (i = 0; token->mechTypes[i]; i++) {
122
asn1_write_OID(asn1, token->mechTypes[i]);
129
if (token->reqFlags & SPNEGO_REQ_FLAG) {
130
int flags = token->reqFlags & ~SPNEGO_REQ_FLAG;
132
asn1_push_tag(asn1, ASN1_CONTEXT(1));
133
asn1_write_Integer(asn1, flags);
137
/* write mechToken */
138
if (token->mechToken.data) {
139
asn1_push_tag(asn1, ASN1_CONTEXT(2));
140
asn1_write_OctetString(asn1, token->mechToken.data,
141
token->mechToken.length);
145
/* write mechListMIC */
146
if (token->mechListMIC.data) {
147
asn1_push_tag(asn1, ASN1_CONTEXT(3));
149
/* This is what RFC 2478 says ... */
150
asn1_write_OctetString(asn1, token->mechListMIC.data,
151
token->mechListMIC.length);
153
/* ... but unfortunately this is what Windows
155
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
156
asn1_push_tag(asn1, ASN1_CONTEXT(0));
157
asn1_push_tag(asn1, ASN1_GENERAL_STRING);
158
asn1_write(asn1, token->mechListMIC.data,
159
token->mechListMIC.length);
170
return !asn1->has_error;
173
static BOOL read_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
177
asn1_start_tag(asn1, ASN1_CONTEXT(1));
178
asn1_start_tag(asn1, ASN1_SEQUENCE(0));
180
while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
181
switch (asn1->data[asn1->ofs]) {
182
case ASN1_CONTEXT(0):
183
asn1_start_tag(asn1, ASN1_CONTEXT(0));
184
asn1_start_tag(asn1, ASN1_ENUMERATED);
185
asn1_read_uint8(asn1, &token->negResult);
189
case ASN1_CONTEXT(1):
190
asn1_start_tag(asn1, ASN1_CONTEXT(1));
191
asn1_read_OID(asn1, &token->supportedMech);
194
case ASN1_CONTEXT(2):
195
asn1_start_tag(asn1, ASN1_CONTEXT(2));
196
asn1_read_OctetString(asn1, &token->responseToken);
199
case ASN1_CONTEXT(3):
200
asn1_start_tag(asn1, ASN1_CONTEXT(3));
201
asn1_read_OctetString(asn1, &token->mechListMIC);
205
asn1->has_error = True;
213
return !asn1->has_error;
216
static BOOL write_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
218
asn1_push_tag(asn1, ASN1_CONTEXT(1));
219
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
221
asn1_push_tag(asn1, ASN1_CONTEXT(0));
222
asn1_write_enumerated(asn1, token->negResult);
225
if (token->supportedMech) {
226
asn1_push_tag(asn1, ASN1_CONTEXT(1));
227
asn1_write_OID(asn1, token->supportedMech);
231
if (token->responseToken.data) {
232
asn1_push_tag(asn1, ASN1_CONTEXT(2));
233
asn1_write_OctetString(asn1, token->responseToken.data,
234
token->responseToken.length);
238
if (token->mechListMIC.data) {
239
asn1_push_tag(asn1, ASN1_CONTEXT(3));
240
asn1_write_OctetString(asn1, token->mechListMIC.data,
241
token->mechListMIC.length);
248
return !asn1->has_error;
251
ssize_t read_spnego_data(DATA_BLOB data, SPNEGO_DATA *token)
258
asn1_load(&asn1, data);
260
switch (asn1.data[asn1.ofs]) {
261
case ASN1_APPLICATION(0):
262
asn1_start_tag(&asn1, ASN1_APPLICATION(0));
263
asn1_check_OID(&asn1, OID_SPNEGO);
264
if (read_negTokenInit(&asn1, &token->negTokenInit)) {
265
token->type = SPNEGO_NEG_TOKEN_INIT;
269
case ASN1_CONTEXT(1):
270
if (read_negTokenTarg(&asn1, &token->negTokenTarg)) {
271
token->type = SPNEGO_NEG_TOKEN_TARG;
278
if (!asn1.has_error) ret = asn1.ofs;
284
ssize_t write_spnego_data(DATA_BLOB *blob, SPNEGO_DATA *spnego)
291
switch (spnego->type) {
292
case SPNEGO_NEG_TOKEN_INIT:
293
asn1_push_tag(&asn1, ASN1_APPLICATION(0));
294
asn1_write_OID(&asn1, OID_SPNEGO);
295
write_negTokenInit(&asn1, &spnego->negTokenInit);
298
case SPNEGO_NEG_TOKEN_TARG:
299
write_negTokenTarg(&asn1, &spnego->negTokenTarg);
302
asn1.has_error = True;
306
if (!asn1.has_error) {
307
*blob = data_blob(asn1.data, asn1.length);
315
BOOL free_spnego_data(SPNEGO_DATA *spnego)
319
if (!spnego) goto out;
321
switch(spnego->type) {
322
case SPNEGO_NEG_TOKEN_INIT:
323
if (spnego->negTokenInit.mechTypes) {
325
for (i = 0; spnego->negTokenInit.mechTypes[i]; i++) {
326
free(CONST_DISCARD(char *,spnego->negTokenInit.mechTypes[i]));
328
free(spnego->negTokenInit.mechTypes);
330
data_blob_free(&spnego->negTokenInit.mechToken);
331
data_blob_free(&spnego->negTokenInit.mechListMIC);
333
case SPNEGO_NEG_TOKEN_TARG:
334
if (spnego->negTokenTarg.supportedMech) {
335
free(spnego->negTokenTarg.supportedMech);
337
data_blob_free(&spnego->negTokenTarg.responseToken);
338
data_blob_free(&spnego->negTokenTarg.mechListMIC);
344
ZERO_STRUCTP(spnego);