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 3 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, see <http://www.gnu.org/licenses/>.
26
#define DBGC_CLASS DBGC_AUTH
28
static bool read_negTokenInit(TALLOC_CTX *mem_ctx, ASN1_DATA *asn1, negTokenInit_t *token)
32
asn1_start_tag(asn1, ASN1_CONTEXT(0));
33
asn1_start_tag(asn1, ASN1_SEQUENCE(0));
35
while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
38
switch (asn1->data[asn1->ofs]) {
41
asn1_start_tag(asn1, ASN1_CONTEXT(0));
42
asn1_start_tag(asn1, ASN1_SEQUENCE(0));
44
token->mechTypes = TALLOC_P(mem_ctx, const char *);
45
for (i = 0; !asn1->has_error &&
46
0 < asn1_tag_remaining(asn1); i++) {
47
const char *p_oid = NULL;
49
TALLOC_REALLOC_ARRAY(mem_ctx, token->mechTypes, const char *, i + 2);
50
if (!token->mechTypes) {
51
asn1->has_error = True;
54
asn1_read_OID(asn1, mem_ctx, &p_oid);
55
token->mechTypes[i] = p_oid;
57
token->mechTypes[i] = NULL;
64
asn1_start_tag(asn1, ASN1_CONTEXT(1));
65
asn1_read_Integer(asn1, &token->reqFlags);
66
token->reqFlags |= SPNEGO_REQ_FLAG;
71
asn1_start_tag(asn1, ASN1_CONTEXT(2));
72
asn1_read_OctetString(asn1, mem_ctx, &token->mechToken);
77
asn1_start_tag(asn1, ASN1_CONTEXT(3));
78
if (asn1->data[asn1->ofs] == ASN1_OCTET_STRING) {
79
asn1_read_OctetString(asn1, mem_ctx,
82
/* RFC 2478 says we have an Octet String here,
83
but W2k sends something different... */
85
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
86
asn1_push_tag(asn1, ASN1_CONTEXT(0));
87
asn1_read_GeneralString(asn1, mem_ctx, &mechListMIC);
92
data_blob(mechListMIC, strlen(mechListMIC));
93
TALLOC_FREE(mechListMIC);
98
asn1->has_error = True;
106
return !asn1->has_error;
109
static bool write_negTokenInit(ASN1_DATA *asn1, negTokenInit_t *token)
111
asn1_push_tag(asn1, ASN1_CONTEXT(0));
112
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
114
/* Write mechTypes */
115
if (token->mechTypes && *token->mechTypes) {
118
asn1_push_tag(asn1, ASN1_CONTEXT(0));
119
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
120
for (i = 0; token->mechTypes[i]; i++) {
121
asn1_write_OID(asn1, token->mechTypes[i]);
128
if (token->reqFlags & SPNEGO_REQ_FLAG) {
129
int flags = token->reqFlags & ~SPNEGO_REQ_FLAG;
131
asn1_push_tag(asn1, ASN1_CONTEXT(1));
132
asn1_write_Integer(asn1, flags);
136
/* write mechToken */
137
if (token->mechToken.data) {
138
asn1_push_tag(asn1, ASN1_CONTEXT(2));
139
asn1_write_OctetString(asn1, token->mechToken.data,
140
token->mechToken.length);
144
/* write mechListMIC */
145
if (token->mechListMIC.data) {
146
asn1_push_tag(asn1, ASN1_CONTEXT(3));
148
/* This is what RFC 2478 says ... */
149
asn1_write_OctetString(asn1, token->mechListMIC.data,
150
token->mechListMIC.length);
152
/* ... but unfortunately this is what Windows
154
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
155
asn1_push_tag(asn1, ASN1_CONTEXT(0));
156
asn1_push_tag(asn1, ASN1_GENERAL_STRING);
157
asn1_write(asn1, token->mechListMIC.data,
158
token->mechListMIC.length);
169
return !asn1->has_error;
172
static bool read_negTokenTarg(TALLOC_CTX *mem_ctx, ASN1_DATA *asn1, negTokenTarg_t *token)
176
asn1_start_tag(asn1, ASN1_CONTEXT(1));
177
asn1_start_tag(asn1, ASN1_SEQUENCE(0));
179
while (!asn1->has_error && 0 < asn1_tag_remaining(asn1)) {
180
switch (asn1->data[asn1->ofs]) {
181
case ASN1_CONTEXT(0):
182
asn1_start_tag(asn1, ASN1_CONTEXT(0));
183
asn1_start_tag(asn1, ASN1_ENUMERATED);
184
asn1_read_uint8(asn1, &token->negResult);
188
case ASN1_CONTEXT(1): {
189
const char *mech = NULL;
190
asn1_start_tag(asn1, ASN1_CONTEXT(1));
191
asn1_read_OID(asn1, mem_ctx, &mech);
193
token->supportedMech = CONST_DISCARD(char *, mech);
196
case ASN1_CONTEXT(2):
197
asn1_start_tag(asn1, ASN1_CONTEXT(2));
198
asn1_read_OctetString(asn1, mem_ctx, &token->responseToken);
201
case ASN1_CONTEXT(3):
202
asn1_start_tag(asn1, ASN1_CONTEXT(3));
203
asn1_read_OctetString(asn1, mem_ctx, &token->mechListMIC);
207
asn1->has_error = True;
215
return !asn1->has_error;
218
static bool write_negTokenTarg(ASN1_DATA *asn1, negTokenTarg_t *token)
220
asn1_push_tag(asn1, ASN1_CONTEXT(1));
221
asn1_push_tag(asn1, ASN1_SEQUENCE(0));
223
asn1_push_tag(asn1, ASN1_CONTEXT(0));
224
asn1_write_enumerated(asn1, token->negResult);
227
if (token->supportedMech) {
228
asn1_push_tag(asn1, ASN1_CONTEXT(1));
229
asn1_write_OID(asn1, token->supportedMech);
233
if (token->responseToken.data) {
234
asn1_push_tag(asn1, ASN1_CONTEXT(2));
235
asn1_write_OctetString(asn1, token->responseToken.data,
236
token->responseToken.length);
240
if (token->mechListMIC.data) {
241
asn1_push_tag(asn1, ASN1_CONTEXT(3));
242
asn1_write_OctetString(asn1, token->mechListMIC.data,
243
token->mechListMIC.length);
250
return !asn1->has_error;
253
ssize_t read_spnego_data(TALLOC_CTX *mem_ctx, DATA_BLOB data, SPNEGO_DATA *token)
260
asn1 = asn1_init(mem_ctx);
265
asn1_load(asn1, data);
267
switch (asn1->data[asn1->ofs]) {
268
case ASN1_APPLICATION(0):
269
asn1_start_tag(asn1, ASN1_APPLICATION(0));
270
asn1_check_OID(asn1, OID_SPNEGO);
271
if (read_negTokenInit(mem_ctx, asn1, &token->negTokenInit)) {
272
token->type = SPNEGO_NEG_TOKEN_INIT;
276
case ASN1_CONTEXT(1):
277
if (read_negTokenTarg(mem_ctx, asn1, &token->negTokenTarg)) {
278
token->type = SPNEGO_NEG_TOKEN_TARG;
285
if (!asn1->has_error) ret = asn1->ofs;
291
ssize_t write_spnego_data(DATA_BLOB *blob, SPNEGO_DATA *spnego)
296
asn1 = asn1_init(talloc_tos());
301
switch (spnego->type) {
302
case SPNEGO_NEG_TOKEN_INIT:
303
asn1_push_tag(asn1, ASN1_APPLICATION(0));
304
asn1_write_OID(asn1, OID_SPNEGO);
305
write_negTokenInit(asn1, &spnego->negTokenInit);
308
case SPNEGO_NEG_TOKEN_TARG:
309
write_negTokenTarg(asn1, &spnego->negTokenTarg);
312
asn1->has_error = True;
316
if (!asn1->has_error) {
317
*blob = data_blob(asn1->data, asn1->length);
325
bool free_spnego_data(SPNEGO_DATA *spnego)
329
if (!spnego) goto out;
331
switch(spnego->type) {
332
case SPNEGO_NEG_TOKEN_INIT:
333
if (spnego->negTokenInit.mechTypes) {
335
for (i = 0; spnego->negTokenInit.mechTypes[i]; i++) {
336
talloc_free(CONST_DISCARD(char *,spnego->negTokenInit.mechTypes[i]));
338
talloc_free(spnego->negTokenInit.mechTypes);
340
data_blob_free(&spnego->negTokenInit.mechToken);
341
data_blob_free(&spnego->negTokenInit.mechListMIC);
343
case SPNEGO_NEG_TOKEN_TARG:
344
if (spnego->negTokenTarg.supportedMech) {
345
talloc_free(spnego->negTokenTarg.supportedMech);
347
data_blob_free(&spnego->negTokenTarg.responseToken);
348
data_blob_free(&spnego->negTokenTarg.mechListMIC);
354
ZERO_STRUCTP(spnego);