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