~vcs-imports/samba/main

« back to all changes in this revision

Viewing changes to source/libsmb/asn1.c

  • Committer: jerry
  • Date: 2006-07-14 21:48:39 UTC
  • Revision ID: vcs-imports@canonical.com-20060714214839-586d8c489a8fcead
gutting trunk to move to svn:externals

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* 
2
 
   Unix SMB/CIFS implementation.
3
 
   simple SPNEGO routines
4
 
   Copyright (C) Andrew Tridgell 2001
5
 
   
6
 
   This program is free software; you can redistribute it and/or modify
7
 
   it under the terms of the GNU General Public License as published by
8
 
   the Free Software Foundation; either version 2 of the License, or
9
 
   (at your option) any later version.
10
 
   
11
 
   This program is distributed in the hope that it will be useful,
12
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
   GNU General Public License for more details.
15
 
   
16
 
   You should have received a copy of the GNU General Public License
17
 
   along with this program; if not, write to the Free Software
18
 
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
 
*/
20
 
 
21
 
#include "includes.h"
22
 
 
23
 
/* free an asn1 structure */
24
 
void asn1_free(ASN1_DATA *data)
25
 
{
26
 
        SAFE_FREE(data->data);
27
 
}
28
 
 
29
 
/* write to the ASN1 buffer, advancing the buffer pointer */
30
 
BOOL asn1_write(ASN1_DATA *data, const void *p, int len)
31
 
{
32
 
        if (data->has_error) return False;
33
 
        if (data->length < data->ofs+len) {
34
 
                data->data = SMB_REALLOC(data->data, data->ofs+len);
35
 
                if (!data->data) {
36
 
                        data->has_error = True;
37
 
                        return False;
38
 
                }
39
 
                data->length = data->ofs+len;
40
 
        }
41
 
        memcpy(data->data + data->ofs, p, len);
42
 
        data->ofs += len;
43
 
        return True;
44
 
}
45
 
 
46
 
/* useful fn for writing a uint8 */
47
 
BOOL asn1_write_uint8(ASN1_DATA *data, uint8 v)
48
 
{
49
 
        return asn1_write(data, &v, 1);
50
 
}
51
 
 
52
 
/* push a tag onto the asn1 data buffer. Used for nested structures */
53
 
BOOL asn1_push_tag(ASN1_DATA *data, uint8 tag)
54
 
{
55
 
        struct nesting *nesting;
56
 
 
57
 
        asn1_write_uint8(data, tag);
58
 
        nesting = SMB_MALLOC_P(struct nesting);
59
 
        if (!nesting) {
60
 
                data->has_error = True;
61
 
                return False;
62
 
        }
63
 
 
64
 
        nesting->start = data->ofs;
65
 
        nesting->next = data->nesting;
66
 
        data->nesting = nesting;
67
 
        return asn1_write_uint8(data, 0xff);
68
 
}
69
 
 
70
 
/* pop a tag */
71
 
BOOL asn1_pop_tag(ASN1_DATA *data)
72
 
{
73
 
        struct nesting *nesting;
74
 
        size_t len;
75
 
 
76
 
        nesting = data->nesting;
77
 
 
78
 
        if (!nesting) {
79
 
                data->has_error = True;
80
 
                return False;
81
 
        }
82
 
        len = data->ofs - (nesting->start+1);
83
 
        /* yes, this is ugly. We don't know in advance how many bytes the length
84
 
           of a tag will take, so we assumed 1 byte. If we were wrong then we 
85
 
           need to correct our mistake */
86
 
        if (len > 0xFFFF) {
87
 
                data->data[nesting->start] = 0x83;
88
 
                if (!asn1_write_uint8(data, 0)) return False;
89
 
                if (!asn1_write_uint8(data, 0)) return False;
90
 
                if (!asn1_write_uint8(data, 0)) return False;
91
 
                memmove(data->data+nesting->start+4, data->data+nesting->start+1, len);
92
 
                data->data[nesting->start+1] = (len>>16) & 0xFF;
93
 
                data->data[nesting->start+2] = (len>>8) & 0xFF;
94
 
                data->data[nesting->start+3] = len&0xff;
95
 
        } else if (len > 255) {
96
 
                data->data[nesting->start] = 0x82;
97
 
                if (!asn1_write_uint8(data, 0)) return False;
98
 
                if (!asn1_write_uint8(data, 0)) return False;
99
 
                memmove(data->data+nesting->start+3, data->data+nesting->start+1, len);
100
 
                data->data[nesting->start+1] = len>>8;
101
 
                data->data[nesting->start+2] = len&0xff;
102
 
        } else if (len > 127) {
103
 
                data->data[nesting->start] = 0x81;
104
 
                if (!asn1_write_uint8(data, 0)) return False;
105
 
                memmove(data->data+nesting->start+2, data->data+nesting->start+1, len);
106
 
                data->data[nesting->start+1] = len;
107
 
        } else {
108
 
                data->data[nesting->start] = len;
109
 
        }
110
 
 
111
 
        data->nesting = nesting->next;
112
 
        free(nesting);
113
 
        return True;
114
 
}
115
 
 
116
 
 
117
 
/* write an integer */
118
 
BOOL asn1_write_Integer(ASN1_DATA *data, int i)
119
 
{
120
 
        if (!asn1_push_tag(data, ASN1_INTEGER)) return False;
121
 
        do {
122
 
                asn1_write_uint8(data, i);
123
 
                i = i >> 8;
124
 
        } while (i);
125
 
        return asn1_pop_tag(data);
126
 
}
127
 
 
128
 
/* write an object ID to a ASN1 buffer */
129
 
BOOL asn1_write_OID(ASN1_DATA *data, const char *OID)
130
 
{
131
 
        unsigned v, v2;
132
 
        const char *p = (const char *)OID;
133
 
        char *newp;
134
 
 
135
 
        if (!asn1_push_tag(data, ASN1_OID))
136
 
                return False;
137
 
        v = strtol(p, &newp, 10);
138
 
        p = newp;
139
 
        v2 = strtol(p, &newp, 10);
140
 
        p = newp;
141
 
        if (!asn1_write_uint8(data, 40*v + v2))
142
 
                return False;
143
 
 
144
 
        while (*p) {
145
 
                v = strtol(p, &newp, 10);
146
 
                p = newp;
147
 
                if (v >= (1<<28)) asn1_write_uint8(data, 0x80 | ((v>>28)&0xff));
148
 
                if (v >= (1<<21)) asn1_write_uint8(data, 0x80 | ((v>>21)&0xff));
149
 
                if (v >= (1<<14)) asn1_write_uint8(data, 0x80 | ((v>>14)&0xff));
150
 
                if (v >= (1<<7)) asn1_write_uint8(data, 0x80 | ((v>>7)&0xff));
151
 
                if (!asn1_write_uint8(data, v&0x7f))
152
 
                        return False;
153
 
        }
154
 
        return asn1_pop_tag(data);
155
 
}
156
 
 
157
 
/* write an octet string */
158
 
BOOL asn1_write_OctetString(ASN1_DATA *data, const void *p, size_t length)
159
 
{
160
 
        asn1_push_tag(data, ASN1_OCTET_STRING);
161
 
        asn1_write(data, p, length);
162
 
        asn1_pop_tag(data);
163
 
        return !data->has_error;
164
 
}
165
 
 
166
 
/* write a general string */
167
 
BOOL asn1_write_GeneralString(ASN1_DATA *data, const char *s)
168
 
{
169
 
        asn1_push_tag(data, ASN1_GENERAL_STRING);
170
 
        asn1_write(data, s, strlen(s));
171
 
        asn1_pop_tag(data);
172
 
        return !data->has_error;
173
 
}
174
 
 
175
 
/* write a BOOLEAN */
176
 
BOOL asn1_write_BOOLEAN(ASN1_DATA *data, BOOL v)
177
 
{
178
 
        asn1_write_uint8(data, ASN1_BOOLEAN);
179
 
        asn1_write_uint8(data, v);
180
 
        return !data->has_error;
181
 
}
182
 
 
183
 
/* write a BOOLEAN - hmm, I suspect this one is the correct one, and the 
184
 
   above boolean is bogus. Need to check */
185
 
BOOL asn1_write_BOOLEAN2(ASN1_DATA *data, BOOL v)
186
 
{
187
 
        asn1_push_tag(data, ASN1_BOOLEAN);
188
 
        asn1_write_uint8(data, v);
189
 
        asn1_pop_tag(data);
190
 
        return !data->has_error;
191
 
}
192
 
 
193
 
/* check a BOOLEAN */
194
 
BOOL asn1_check_BOOLEAN(ASN1_DATA *data, BOOL v)
195
 
{
196
 
        uint8 b = 0;
197
 
 
198
 
        asn1_read_uint8(data, &b);
199
 
        if (b != ASN1_BOOLEAN) {
200
 
                data->has_error = True;
201
 
                return False;
202
 
        }
203
 
        asn1_read_uint8(data, &b);
204
 
        if (b != v) {
205
 
                data->has_error = True;
206
 
                return False;
207
 
        }
208
 
        return !data->has_error;
209
 
}
210
 
 
211
 
 
212
 
/* load a ASN1_DATA structure with a lump of data, ready to be parsed */
213
 
BOOL asn1_load(ASN1_DATA *data, DATA_BLOB blob)
214
 
{
215
 
        ZERO_STRUCTP(data);
216
 
        data->data = memdup(blob.data, blob.length);
217
 
        if (!data->data) {
218
 
                data->has_error = True;
219
 
                return False;
220
 
        }
221
 
        data->length = blob.length;
222
 
        return True;
223
 
}
224
 
 
225
 
/* read from a ASN1 buffer, advancing the buffer pointer */
226
 
BOOL asn1_read(ASN1_DATA *data, void *p, int len)
227
 
{
228
 
        if (data->has_error)
229
 
                return False;
230
 
 
231
 
        if (len < 0 || data->ofs + len < data->ofs || data->ofs + len < len) {
232
 
                data->has_error = True;
233
 
                return False;
234
 
        }
235
 
 
236
 
        if (data->ofs + len > data->length) {
237
 
                data->has_error = True;
238
 
                return False;
239
 
        }
240
 
        memcpy(p, data->data + data->ofs, len);
241
 
        data->ofs += len;
242
 
        return True;
243
 
}
244
 
 
245
 
/* read a uint8 from a ASN1 buffer */
246
 
BOOL asn1_read_uint8(ASN1_DATA *data, uint8 *v)
247
 
{
248
 
        return asn1_read(data, v, 1);
249
 
}
250
 
 
251
 
/* start reading a nested asn1 structure */
252
 
BOOL asn1_start_tag(ASN1_DATA *data, uint8 tag)
253
 
{
254
 
        uint8 b;
255
 
        struct nesting *nesting;
256
 
        
257
 
        if (!asn1_read_uint8(data, &b))
258
 
                return False;
259
 
 
260
 
        if (b != tag) {
261
 
                data->has_error = True;
262
 
                return False;
263
 
        }
264
 
        nesting = SMB_MALLOC_P(struct nesting);
265
 
        if (!nesting) {
266
 
                data->has_error = True;
267
 
                return False;
268
 
        }
269
 
 
270
 
        if (!asn1_read_uint8(data, &b)) {
271
 
                SAFE_FREE(nesting);
272
 
                return False;
273
 
        }
274
 
 
275
 
        if (b & 0x80) {
276
 
                int n = b & 0x7f;
277
 
                if (!asn1_read_uint8(data, &b)) {
278
 
                        SAFE_FREE(nesting);
279
 
                        return False;
280
 
                }
281
 
                nesting->taglen = b;
282
 
                while (n > 1) {
283
 
                        if (!asn1_read_uint8(data, &b)) {
284
 
                                SAFE_FREE(nesting);
285
 
                                return False;
286
 
                        }
287
 
                        nesting->taglen = (nesting->taglen << 8) | b;
288
 
                        n--;
289
 
                }
290
 
        } else {
291
 
                nesting->taglen = b;
292
 
        }
293
 
        nesting->start = data->ofs;
294
 
        nesting->next = data->nesting;
295
 
        data->nesting = nesting;
296
 
        return !data->has_error;
297
 
}
298
 
 
299
 
 
300
 
/* stop reading a tag */
301
 
BOOL asn1_end_tag(ASN1_DATA *data)
302
 
{
303
 
        struct nesting *nesting;
304
 
 
305
 
        /* make sure we read it all */
306
 
        if (asn1_tag_remaining(data) != 0) {
307
 
                data->has_error = True;
308
 
                return False;
309
 
        }
310
 
 
311
 
        nesting = data->nesting;
312
 
 
313
 
        if (!nesting) {
314
 
                data->has_error = True;
315
 
                return False;
316
 
        }
317
 
 
318
 
        data->nesting = nesting->next;
319
 
        free(nesting);
320
 
        return True;
321
 
}
322
 
 
323
 
/* work out how many bytes are left in this nested tag */
324
 
int asn1_tag_remaining(ASN1_DATA *data)
325
 
{
326
 
        if (data->has_error)
327
 
                return 0;
328
 
 
329
 
        if (!data->nesting) {
330
 
                data->has_error = True;
331
 
                return -1;
332
 
        }
333
 
        return data->nesting->taglen - (data->ofs - data->nesting->start);
334
 
}
335
 
 
336
 
/* read an object ID from a ASN1 buffer */
337
 
BOOL asn1_read_OID(ASN1_DATA *data, char **OID)
338
 
{
339
 
        uint8 b;
340
 
        pstring oid_str;
341
 
        fstring el;
342
 
 
343
 
        *OID = NULL;
344
 
 
345
 
        if (!asn1_start_tag(data, ASN1_OID)) {
346
 
                return False;
347
 
        }
348
 
        asn1_read_uint8(data, &b);
349
 
 
350
 
        oid_str[0] = 0;
351
 
        fstr_sprintf(el, "%u",  b/40);
352
 
        pstrcat(oid_str, el);
353
 
        fstr_sprintf(el, " %u",  b%40);
354
 
        pstrcat(oid_str, el);
355
 
 
356
 
        while (asn1_tag_remaining(data) > 0) {
357
 
                unsigned v = 0;
358
 
                do {
359
 
                        asn1_read_uint8(data, &b);
360
 
                        v = (v<<7) | (b&0x7f);
361
 
                } while (!data->has_error && b & 0x80);
362
 
                fstr_sprintf(el, " %u",  v);
363
 
                pstrcat(oid_str, el);
364
 
        }
365
 
 
366
 
        asn1_end_tag(data);
367
 
 
368
 
        if (!data->has_error) {
369
 
                *OID = SMB_STRDUP(oid_str);
370
 
        }
371
 
 
372
 
        return !data->has_error;
373
 
}
374
 
 
375
 
/* check that the next object ID is correct */
376
 
BOOL asn1_check_OID(ASN1_DATA *data, const char *OID)
377
 
{
378
 
        char *id;
379
 
 
380
 
        if (!asn1_read_OID(data, &id)) {
381
 
                return False;
382
 
        }
383
 
 
384
 
        if (strcmp(id, OID) != 0) {
385
 
                data->has_error = True;
386
 
                return False;
387
 
        }
388
 
        free(id);
389
 
        return True;
390
 
}
391
 
 
392
 
/* read a GeneralString from a ASN1 buffer */
393
 
BOOL asn1_read_GeneralString(ASN1_DATA *data, char **s)
394
 
{
395
 
        int len;
396
 
        char *str;
397
 
 
398
 
        *s = NULL;
399
 
 
400
 
        if (!asn1_start_tag(data, ASN1_GENERAL_STRING)) {
401
 
                return False;
402
 
        }
403
 
        len = asn1_tag_remaining(data);
404
 
        if (len < 0) {
405
 
                data->has_error = True;
406
 
                return False;
407
 
        }
408
 
        str = SMB_MALLOC(len+1);
409
 
        if (!str) {
410
 
                data->has_error = True;
411
 
                return False;
412
 
        }
413
 
        asn1_read(data, str, len);
414
 
        str[len] = 0;
415
 
        asn1_end_tag(data);
416
 
 
417
 
        if (!data->has_error) {
418
 
                *s = str;
419
 
        }
420
 
        return !data->has_error;
421
 
}
422
 
 
423
 
/* read a octet string blob */
424
 
BOOL asn1_read_OctetString(ASN1_DATA *data, DATA_BLOB *blob)
425
 
{
426
 
        int len;
427
 
        ZERO_STRUCTP(blob);
428
 
        if (!asn1_start_tag(data, ASN1_OCTET_STRING)) return False;
429
 
        len = asn1_tag_remaining(data);
430
 
        if (len < 0) {
431
 
                data->has_error = True;
432
 
                return False;
433
 
        }
434
 
        *blob = data_blob(NULL, len);
435
 
        asn1_read(data, blob->data, len);
436
 
        asn1_end_tag(data);
437
 
        return !data->has_error;
438
 
}
439
 
 
440
 
/* read an interger */
441
 
BOOL asn1_read_Integer(ASN1_DATA *data, int *i)
442
 
{
443
 
        uint8 b;
444
 
        *i = 0;
445
 
        
446
 
        if (!asn1_start_tag(data, ASN1_INTEGER)) return False;
447
 
        while (asn1_tag_remaining(data)>0) {
448
 
                asn1_read_uint8(data, &b);
449
 
                *i = (*i << 8) + b;
450
 
        }
451
 
        return asn1_end_tag(data);      
452
 
        
453
 
}
454
 
 
455
 
/* check a enumarted value is correct */
456
 
BOOL asn1_check_enumerated(ASN1_DATA *data, int v)
457
 
{
458
 
        uint8 b;
459
 
        if (!asn1_start_tag(data, ASN1_ENUMERATED)) return False;
460
 
        asn1_read_uint8(data, &b);
461
 
        asn1_end_tag(data);
462
 
 
463
 
        if (v != b)
464
 
                data->has_error = False;
465
 
 
466
 
        return !data->has_error;
467
 
}
468
 
 
469
 
/* write an enumarted value to the stream */
470
 
BOOL asn1_write_enumerated(ASN1_DATA *data, uint8 v)
471
 
{
472
 
        if (!asn1_push_tag(data, ASN1_ENUMERATED)) return False;
473
 
        asn1_write_uint8(data, v);
474
 
        asn1_pop_tag(data);
475
 
        return !data->has_error;
476
 
}