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