blob: fc5c532c5a861dc72f5888d109ca04ceef50a2e9 [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001/*-
2 * Copyright (c) 2003 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
4 */
5#include <OCTET_STRING.h>
6#include <assert.h>
7#include <errno.h>
8
9/*
10 * OCTET STRING basic type description.
11 */
12static ber_tlv_tag_t asn1_DEF_OCTET_STRING_tags[] = {
13 (ASN_TAG_CLASS_UNIVERSAL | (4 << 2))
14};
15asn1_TYPE_descriptor_t asn1_DEF_OCTET_STRING = {
16 "OCTET STRING",
17 asn_generic_no_constraint,
18 OCTET_STRING_decode_ber,
19 OCTET_STRING_encode_der,
20 OCTET_STRING_print, /* non-ascii stuff, generally */
21 OCTET_STRING_free,
22 0, /* Use generic outmost tag fetcher */
23 asn1_DEF_OCTET_STRING_tags,
24 sizeof(asn1_DEF_OCTET_STRING_tags)
25 / sizeof(asn1_DEF_OCTET_STRING_tags[0]),
26 1, /* Single UNIVERSAL tag may be implicitly overriden */
27 -1, /* Both ways are fine (primitive and constructed) */
28};
29
30#define _CH_PHASE(ctx, inc) do { \
31 if(ctx->phase == 0) \
32 ctx->step = 0; \
33 ctx->phase += inc; \
34 } while(0)
35#define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1)
36#define PREV_PHASE(ctx) _CH_PHASE(ctx, -1)
37
38#define ADVANCE(num_bytes) do { \
39 size_t num = num_bytes; \
40 buf_ptr += num; \
41 size -= num; \
42 consumed_myself += num; \
43 } while(0)
44
45#define RETURN(_code) do { \
46 rval.code = _code; \
47 rval.consumed = consumed_myself;\
48 return rval; \
49 } while(0)
50
51#define APPEND(bufptr, bufsize) do { \
52 int _ns = ctx->step; /* Allocated */ \
53 if(_ns <= (st->size + bufsize)) { \
54 void *ptr; \
55 do { _ns = _ns ? _ns<<2 : 16; } \
56 while(_ns <= (st->size + bufsize)); \
57 ptr = REALLOC(st->buf, _ns); \
58 if(ptr) { \
59 st->buf = ptr; \
60 ctx->step = _ns; \
61 } else { \
62 RETURN(RC_FAIL); \
63 } \
64 } \
65 memcpy(st->buf + st->size, bufptr, bufsize); \
66 st->size += bufsize; \
67 if(st->size < 0) \
68 /* Why even care?.. JIC */ \
69 RETURN(RC_FAIL); \
70 /* Convenient nul-termination */ \
71 st->buf[st->size] = '\0'; \
72 } while(0)
73
74/*
75 * The main reason why ASN.1 is still alive is that too much time and effort
76 * is necessary for learning it more or less adequately, thus creating a gut
77 * necessity to demonstrate that aquired skill everywhere afterwards.
78 * No, I am not going to explain what the following stuff is.
79 */
80struct _stack_el {
81 ber_tlv_len_t left; /* What's left to read */
82 int want_nulls; /* Want null "end of content" octets? */
83 int bits_chopped; /* Flag in BIT STRING mode */
84 struct _stack_el *prev;
85 struct _stack_el *next;
86};
87struct _stack {
88 struct _stack_el *tail;
89 struct _stack_el *cur_ptr;
90};
91
92static struct _stack_el *
93_add_stack_el(struct _stack *st) {
94 struct _stack_el *nel;
95
96 if(st->cur_ptr && st->cur_ptr->next) {
97 nel = st->cur_ptr->next;
98 nel->left = 0;
99 nel->want_nulls = 0;
100 nel->bits_chopped = 0;
101 } else {
102 nel = CALLOC(1, sizeof(struct _stack_el));
103 if(nel == NULL)
104 return NULL;
105
106 if(st->tail) {
107 st->tail->next = nel;
108 }
109 nel->prev = st->tail;
110 st->tail = nel;
111 }
112
113 st->cur_ptr = nel;
114
115 return nel;
116}
117
118static struct _stack *
119_new_stack() {
120 struct _stack *st;
121 st = CALLOC(1, sizeof(struct _stack));
122 if(st == NULL)
123 return NULL;
124
125 st->cur_ptr = _add_stack_el(st);
126 if(st->cur_ptr == NULL) {
127 FREEMEM(st);
128 return NULL;
129 }
130
131 return st;
132}
133
134/*
135 * Decode OCTET STRING type.
136 */
137ber_dec_rval_t
138OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
139 void **os_structure, void *buf_ptr, size_t size, int tag_mode) {
140 OCTET_STRING_t *st = *os_structure;
141 ber_dec_rval_t rval;
142 ber_dec_ctx_t *ctx;
143 ssize_t consumed_myself = 0;
144 struct _stack *stck; /* A stack structure */
145 struct _stack_el *sel; /* Stack element */
146 int tlv_constr;
147 /*
148 * This is a some sort of a hack.
149 * The OCTET STRING decoder is being used in BIT STRING mode.
150 */
151 int is_bit_str = td->specifics?1:0;
152
153 ASN_DEBUG("Decoding %s as %s (%ld)",
154 td->name,
155 is_bit_str ? "BIT STRING" : "OCTET STRING",
156 (long)size);
157
158 /*
159 * Create the string if does not exist.
160 */
161 if(st == NULL) {
162 st = *os_structure = CALLOC(1, sizeof(*st));
163 if(st == NULL)
164 RETURN(RC_FAIL);
165 }
166
167 /* Restore parsing context */
168 ctx = &st->_ber_dec_ctx;
169
170 switch(ctx->phase) {
171 case 0:
172 /*
173 * Check tags.
174 */
175 rval = ber_check_tags(td, ctx,
176 buf_ptr, size, tag_mode,
177 &ctx->left, &tlv_constr);
178 if(rval.code != RC_OK) {
179 RETURN(rval.code);
180 }
181
182 ASN_DEBUG("OS length is %d bytes, form %d",
183 (int)ctx->left, tlv_constr);
184
185 if(tlv_constr) {
186 /*
187 * Complex operation, requires stack of expectations.
188 */
189 ctx->ptr = _new_stack();
190 if(ctx->ptr) {
191 stck = ctx->ptr;
192 if(ctx->left < 0) {
193 stck->cur_ptr->want_nulls = -ctx->left;
194 stck->cur_ptr->left = -1;
195 } else {
196 stck->cur_ptr->want_nulls = 0;
197 stck->cur_ptr->left = ctx->left;
198 }
199 ASN_DEBUG("Expectation left=%d wn=%d added",
200 stck->cur_ptr->left,
201 stck->cur_ptr->want_nulls);
202 if(is_bit_str) {
203 APPEND("\0", 1);
204 }
205 } else {
206 RETURN(RC_FAIL);
207 }
208 } else {
209 /*
210 * Jump into stackless primitive decoding.
211 */
212 _CH_PHASE(ctx, 3);
213 ADVANCE(rval.consumed);
214 goto phase3;
215 }
216
217 ADVANCE(rval.consumed);
218 NEXT_PHASE(ctx);
219 /* Fall through */
220 case 1:
221 phase1:
222 /*
223 * Fill the stack with expectations.
224 */
225 stck = ctx->ptr;
226 sel = stck->cur_ptr;
227 do {
228 ber_tlv_tag_t tlv_tag;
229 ber_tlv_len_t tlv_len;
230 ssize_t tl, ll;
231
232 tl = ber_fetch_tag(buf_ptr, size, &tlv_tag);
233 switch(tl) {
234 case -1: RETURN(RC_FAIL);
235 case 0: RETURN(RC_WMORE);
236 }
237
238 tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr);
239
240 ll = ber_fetch_length(tlv_constr,
241 buf_ptr + tl, size - tl, &tlv_len);
242 ASN_DEBUG("Got tag=%s, tl=%d, len=%d, ll=%d, {%d, %d}",
243 ber_tlv_tag_string(tlv_tag), tl, tlv_len, ll,
244 ((uint8_t *)buf_ptr)[0],
245 ((uint8_t *)buf_ptr)[1]);
246 switch(ll) {
247 case -1: RETURN(RC_FAIL);
248 case 0: RETURN(RC_WMORE);
249 }
250
251 if(sel->want_nulls
252 && ((uint8_t *)buf_ptr)[0] == 0
253 && ((uint8_t *)buf_ptr)[1] == 0)
254 {
255 sel->want_nulls--;
256 if(sel->want_nulls == 0) {
257 /* Move to the next expectation */
258 sel = stck->cur_ptr = sel->prev;
259 if(sel == NULL) {
260 ADVANCE(2);
261 break;
262 }
263 }
264 if(sel->want_nulls) {
265 /*
266 * Simulate while(TRUE) for this loop.
267 * This is necessary to fetch the next
268 * "end of content" expectation.
269 */
270 ADVANCE(2);
271 tlv_constr = 1;
272 continue;
273 }
274 } else if(tlv_tag != td->tags[td->tags_count-1]) {
275 char buf[2][32];
276 ber_tlv_tag_snprint(tlv_tag,
277 buf[0], sizeof(buf[0]));
278 ber_tlv_tag_snprint(td->tags[td->tags_count-1],
279 buf[1], sizeof(buf[1]));
280 ASN_DEBUG("Tag does not match expectation: %s != %s",
281 buf[0], buf[1]);
282 RETURN(RC_FAIL);
283 }
284
285 /*
286 * Append a new expectation.
287 */
288 sel = _add_stack_el(stck);
289 if(sel) {
290 sel->want_nulls = (tlv_len==-1);
291 sel->left = tlv_len;
292 ASN_DEBUG("Expectation %d %d added",
293 sel->left, sel->want_nulls);
294 } else {
295 RETURN(RC_FAIL);
296 }
297
298 ADVANCE(tl+ll);
299 } while(tlv_constr);
300 if(sel == NULL) {
301 /* Finished operation, "phase out" */
302 _CH_PHASE(ctx, +3);
303 break;
304 }
305
306 NEXT_PHASE(ctx);
307 /* Fall through */
308 case 2:
309 stck = ctx->ptr;
310 sel = stck->cur_ptr;
311 ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld",
312 (long)sel->left, (long)size);
313 {
314 ber_tlv_len_t len;
315
316 assert(sel->left >= 0);
317
318 len = (size < sel->left) ? size : sel->left;
319 if(len > 0) {
320 if(is_bit_str && sel->bits_chopped == 0) {
321 /*
322 * Finalize the previous chunk:
323 * strip down unused bits.
324 */
325 st->buf[st->size-1] &= 0xff << st->buf[0];
326
327 APPEND((buf_ptr+1), (len - 1));
328 st->buf[0] = *(uint8_t *)buf_ptr;
329 sel->bits_chopped = 1;
330 } else {
331 APPEND(buf_ptr, len);
332 }
333 ADVANCE(len);
334 sel->left -= len;
335 }
336
337 if(sel->left) {
338 RETURN(RC_WMORE);
339 } else {
340 sel->left = 0;
341 if(sel->prev)
342 sel = stck->cur_ptr = sel->prev;
343 PREV_PHASE(ctx);
344 goto phase1;
345 }
346 }
347 break;
348 case 3:
349 phase3:
350 /*
351 * Primitive form, no stack required.
352 */
353 if(size < ctx->left) {
354 APPEND(buf_ptr, size);
355 ctx->left -= size;
356 ADVANCE(size);
357 RETURN(RC_WMORE);
358 } else {
359 APPEND(buf_ptr, ctx->left);
360 ADVANCE(ctx->left);
361 ctx->left = 0;
362
363 NEXT_PHASE(ctx);
364 }
365 break;
366 }
367
368 /*
369 * BIT STRING-specific processing.
370 */
371 if(is_bit_str && st->size >= 2) {
372 /* Finalize BIT STRING: zero out unused bits. */
373 st->buf[st->size-1] &= 0xff << st->buf[0];
374 }
375
376 ASN_DEBUG("Took %d bytes to encode %s: [%s]:%d",
377 consumed_myself, td->name, st->buf, st->size);
378
379 rval.code = RC_OK;
380 rval.consumed = consumed_myself;
381
382 return rval;
383}
384
385/*
386 * Encode OCTET STRING type using DER.
387 */
388der_enc_rval_t
389OCTET_STRING_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
390 int tag_mode, ber_tlv_tag_t tag,
391 asn_app_consume_bytes_f *cb, void *app_key) {
392 der_enc_rval_t erval;
393 OCTET_STRING_t *st = ptr;
394 int add_byte = 0;
395
396 ASN_DEBUG("%s %s as OCTET STRING",
397 cb?"Estimating":"Encoding", sd->name);
398
399 /*
400 * Canonicalize BIT STRING.
401 */
402 if(sd->specifics && st->buf) {
403 switch(st->size) {
404 case 0: add_byte = 1; break;
405 case 1: st->buf[0] = 0; break;
406 default:
407 /* Finalize BIT STRING: zero out unused bits. */
408 st->buf[st->size-1] &= 0xff << st->buf[0];
409 }
410 }
411
412 erval.encoded = der_write_tags(sd, st->size + add_byte, tag_mode, tag,
413 cb, app_key);
414 if(erval.encoded == -1) {
415 erval.failed_type = sd;
416 erval.structure_ptr = ptr;
417 return erval;
418 }
419
420 if(cb) {
421 uint8_t zero;
422 uint8_t *buf;
423 int size;
424 ssize_t ret;
425
426 /* BIT STRING-aware handling */
427 if(add_byte) {
428 zero = 0;
429 buf = &zero;
430 size = 1;
431 } else if(st->buf) {
432 buf = st->buf;
433 size = st->size;
434 } else {
435 assert(st->size == 0);
436 buf = 0; /* Not used */
437 size = 0;
438 }
439
440 if(size) {
441 ret = cb(buf, size, app_key);
442 if(ret == -1) {
443 erval.encoded = -1;
444 erval.failed_type = sd;
445 erval.structure_ptr = ptr;
446 return erval;
447 }
448 }
449 }
450
451 erval.encoded += st->size + add_byte;
452
453 return erval;
454}
455
456int
457OCTET_STRING_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
458 asn_app_consume_bytes_f *cb, void *app_key) {
459 static char h2c[16] = "0123456789ABCDEF";
460 const OCTET_STRING_t *st = sptr;
461 char scratch[16 * 3 + 4];
462 char *p = scratch;
463 uint8_t *buf;
464 uint8_t *end;
465 size_t i;
466 int ret;
467
468 if(!st || !st->buf) return cb("<absent>", 8, app_key);
469
470 /*
471 * Dump the contents of the buffer in hexadecimal.
472 */
473 buf = st->buf;
474 end = buf + st->size;
475 for(i = 0; buf < end; buf++, i++) {
476 if(!(i % 16) && (i || st->size > 16)) {
477 if(cb(scratch, p - scratch, app_key)
478 || cb("\n", 1, app_key))
479 return -1;
480 for(ret = 0; ret < ilevel; ret++)
481 cb(" ", 1, app_key);
482 p = scratch;
483 }
484 *p++ = h2c[(*buf >> 4) & 0x0F];
485 *p++ = h2c[*buf & 0x0F];
486 *p++ = ' ';
487 }
488
489 return cb(scratch, p - scratch, app_key);
490}
491
492int
493OCTET_STRING_print_ascii(asn1_TYPE_descriptor_t *td, const void *sptr,
494 int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
495 const OCTET_STRING_t *st = sptr;
496
497 if(st && st->buf) {
498 return cb(st->buf, st->size, app_key);
499 } else {
500 return cb("<absent>", 8, app_key);
501 }
502}
503
504void
505OCTET_STRING_free(asn1_TYPE_descriptor_t *td, void *sptr, int contents_only) {
506 OCTET_STRING_t *st = sptr;
507 struct _stack *stck = st->_ber_dec_ctx.ptr;
508
509 if(!td || !st)
510 return;
511
512 ASN_DEBUG("Freeing %s as OCTET STRING", td->name);
513
514 if(st->buf) {
515 FREEMEM(st->buf);
516 }
517
518 /*
519 * Remove decode-time stack.
520 */
521 if(stck) {
522 while(stck->tail) {
523 struct _stack_el *sel = stck->tail;
524 stck->tail = sel->prev;
525 FREEMEM(sel);
526 }
527 FREEMEM(stck);
528 }
529
530 if(!contents_only) {
531 FREEMEM(st);
532 }
533}
534
535/*
536 * Conversion routines.
537 */
538int
539OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) {
540 void *buf;
541
542 if(st == 0 || (str == 0 && len)) {
543 errno = EINVAL;
544 return -1;
545 }
546
547 /*
548 * Clear the OCTET STRING.
549 */
550 if(str == NULL) {
551 if(st->buf)
552 FREEMEM(st->buf);
553 st->size = 0;
554 return 0;
555 }
556
557 /* Determine the original string size, if not explicitly given */
558 if(len < 0)
559 len = strlen(str);
560
561 /* Allocate and fill the memory */
562 buf = MALLOC(len + 1);
563 if(buf == NULL) {
564 return -1;
565 } else {
566 st->buf = buf;
567 st->size = len;
568 }
569
570 memcpy(buf, str, len);
571 st->buf[st->size] = '\0'; /* Couldn't use memcpy(len+1)! */
572
573 return 0;
574}
575
576OCTET_STRING_t *
577OCTET_STRING_new_fromBuf(const char *str, int len) {
578 OCTET_STRING_t *st;
579
580 st = CALLOC(1, sizeof(*st));
581 if(st && str && OCTET_STRING_fromBuf(st, str, len)) {
582 free(st);
583 st = NULL;
584 }
585
586 return st;
587}
588