blob: e246314ec54ca630c3bc35dfb990786a7ab54371 [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
vlmb42843a2004-06-05 08:17:50 +0000319 len = ((ber_tlv_len_t)size < sel->left) ? size : sel->left;
vlmfa67ddc2004-06-03 03:38:44 +0000320 if(len > 0) {
321 if(is_bit_str && sel->bits_chopped == 0) {
322 /*
323 * Finalize the previous chunk:
324 * strip down unused bits.
325 */
326 st->buf[st->size-1] &= 0xff << st->buf[0];
327
vlm1ff928d2004-08-11 08:10:13 +0000328 APPEND(((char *)buf_ptr+1), (len - 1));
vlmfa67ddc2004-06-03 03:38:44 +0000329 st->buf[0] = *(uint8_t *)buf_ptr;
330 sel->bits_chopped = 1;
331 } else {
332 APPEND(buf_ptr, len);
333 }
334 ADVANCE(len);
335 sel->left -= len;
336 }
337
338 if(sel->left) {
339 RETURN(RC_WMORE);
340 } else {
341 sel->left = 0;
342 if(sel->prev)
343 sel = stck->cur_ptr = sel->prev;
344 PREV_PHASE(ctx);
345 goto phase1;
346 }
347 }
348 break;
349 case 3:
350 phase3:
351 /*
352 * Primitive form, no stack required.
353 */
vlmb42843a2004-06-05 08:17:50 +0000354 if(size < (size_t)ctx->left) {
vlmfa67ddc2004-06-03 03:38:44 +0000355 APPEND(buf_ptr, size);
356 ctx->left -= size;
357 ADVANCE(size);
358 RETURN(RC_WMORE);
359 } else {
360 APPEND(buf_ptr, ctx->left);
361 ADVANCE(ctx->left);
362 ctx->left = 0;
363
364 NEXT_PHASE(ctx);
365 }
366 break;
367 }
368
369 /*
370 * BIT STRING-specific processing.
371 */
372 if(is_bit_str && st->size >= 2) {
373 /* Finalize BIT STRING: zero out unused bits. */
374 st->buf[st->size-1] &= 0xff << st->buf[0];
375 }
376
377 ASN_DEBUG("Took %d bytes to encode %s: [%s]:%d",
378 consumed_myself, td->name, st->buf, st->size);
379
380 rval.code = RC_OK;
381 rval.consumed = consumed_myself;
382
383 return rval;
384}
385
386/*
387 * Encode OCTET STRING type using DER.
388 */
389der_enc_rval_t
390OCTET_STRING_encode_der(asn1_TYPE_descriptor_t *sd, void *ptr,
391 int tag_mode, ber_tlv_tag_t tag,
392 asn_app_consume_bytes_f *cb, void *app_key) {
393 der_enc_rval_t erval;
vlmda674682004-08-11 09:07:36 +0000394 OCTET_STRING_t *st = (OCTET_STRING_t *)ptr;
vlmfa67ddc2004-06-03 03:38:44 +0000395 int add_byte = 0;
396
397 ASN_DEBUG("%s %s as OCTET STRING",
398 cb?"Estimating":"Encoding", sd->name);
399
400 /*
401 * Canonicalize BIT STRING.
402 */
403 if(sd->specifics && st->buf) {
404 switch(st->size) {
405 case 0: add_byte = 1; break;
406 case 1: st->buf[0] = 0; break;
407 default:
408 /* Finalize BIT STRING: zero out unused bits. */
409 st->buf[st->size-1] &= 0xff << st->buf[0];
410 }
411 }
412
413 erval.encoded = der_write_tags(sd, st->size + add_byte, tag_mode, tag,
414 cb, app_key);
415 if(erval.encoded == -1) {
416 erval.failed_type = sd;
417 erval.structure_ptr = ptr;
418 return erval;
419 }
420
421 if(cb) {
422 uint8_t zero;
423 uint8_t *buf;
424 int size;
425 ssize_t ret;
426
427 /* BIT STRING-aware handling */
428 if(add_byte) {
429 zero = 0;
430 buf = &zero;
431 size = 1;
432 } else if(st->buf) {
433 buf = st->buf;
434 size = st->size;
435 } else {
436 assert(st->size == 0);
437 buf = 0; /* Not used */
438 size = 0;
439 }
440
441 if(size) {
442 ret = cb(buf, size, app_key);
443 if(ret == -1) {
444 erval.encoded = -1;
445 erval.failed_type = sd;
446 erval.structure_ptr = ptr;
447 return erval;
448 }
449 }
450 }
451
452 erval.encoded += st->size + add_byte;
453
454 return erval;
455}
456
457int
458OCTET_STRING_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
459 asn_app_consume_bytes_f *cb, void *app_key) {
vlm1ff928d2004-08-11 08:10:13 +0000460 static const char *h2c = "0123456789ABCDEF";
vlmda674682004-08-11 09:07:36 +0000461 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
vlmfa67ddc2004-06-03 03:38:44 +0000462 char scratch[16 * 3 + 4];
463 char *p = scratch;
464 uint8_t *buf;
465 uint8_t *end;
466 size_t i;
467 int ret;
468
vlmb42843a2004-06-05 08:17:50 +0000469 (void)td; /* Unused argument */
470
vlmfa67ddc2004-06-03 03:38:44 +0000471 if(!st || !st->buf) return cb("<absent>", 8, app_key);
472
473 /*
474 * Dump the contents of the buffer in hexadecimal.
475 */
476 buf = st->buf;
477 end = buf + st->size;
478 for(i = 0; buf < end; buf++, i++) {
479 if(!(i % 16) && (i || st->size > 16)) {
480 if(cb(scratch, p - scratch, app_key)
481 || cb("\n", 1, app_key))
482 return -1;
483 for(ret = 0; ret < ilevel; ret++)
484 cb(" ", 1, app_key);
485 p = scratch;
486 }
487 *p++ = h2c[(*buf >> 4) & 0x0F];
488 *p++ = h2c[*buf & 0x0F];
489 *p++ = ' ';
490 }
491
492 return cb(scratch, p - scratch, app_key);
493}
494
495int
496OCTET_STRING_print_ascii(asn1_TYPE_descriptor_t *td, const void *sptr,
497 int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
vlmda674682004-08-11 09:07:36 +0000498 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
vlmfa67ddc2004-06-03 03:38:44 +0000499
vlmb42843a2004-06-05 08:17:50 +0000500 (void)td; /* Unused argument */
501 (void)ilevel; /* Unused argument */
502
vlmfa67ddc2004-06-03 03:38:44 +0000503 if(st && st->buf) {
504 return cb(st->buf, st->size, app_key);
505 } else {
506 return cb("<absent>", 8, app_key);
507 }
508}
509
510void
511OCTET_STRING_free(asn1_TYPE_descriptor_t *td, void *sptr, int contents_only) {
vlmda674682004-08-11 09:07:36 +0000512 OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
513 struct _stack *stck = (struct _stack *)st->_ber_dec_ctx.ptr;
vlmfa67ddc2004-06-03 03:38:44 +0000514
515 if(!td || !st)
516 return;
517
518 ASN_DEBUG("Freeing %s as OCTET STRING", td->name);
519
520 if(st->buf) {
521 FREEMEM(st->buf);
522 }
523
524 /*
525 * Remove decode-time stack.
526 */
527 if(stck) {
528 while(stck->tail) {
529 struct _stack_el *sel = stck->tail;
530 stck->tail = sel->prev;
531 FREEMEM(sel);
532 }
533 FREEMEM(stck);
534 }
535
536 if(!contents_only) {
537 FREEMEM(st);
538 }
539}
540
541/*
542 * Conversion routines.
543 */
544int
545OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) {
546 void *buf;
547
548 if(st == 0 || (str == 0 && len)) {
549 errno = EINVAL;
550 return -1;
551 }
552
553 /*
554 * Clear the OCTET STRING.
555 */
556 if(str == NULL) {
557 if(st->buf)
558 FREEMEM(st->buf);
559 st->size = 0;
560 return 0;
561 }
562
563 /* Determine the original string size, if not explicitly given */
564 if(len < 0)
565 len = strlen(str);
566
567 /* Allocate and fill the memory */
568 buf = MALLOC(len + 1);
569 if(buf == NULL) {
570 return -1;
571 } else {
vlmda674682004-08-11 09:07:36 +0000572 st->buf = (uint8_t *)buf;
vlmfa67ddc2004-06-03 03:38:44 +0000573 st->size = len;
574 }
575
576 memcpy(buf, str, len);
577 st->buf[st->size] = '\0'; /* Couldn't use memcpy(len+1)! */
578
579 return 0;
580}
581
582OCTET_STRING_t *
583OCTET_STRING_new_fromBuf(const char *str, int len) {
584 OCTET_STRING_t *st;
585
vlmda674682004-08-11 09:07:36 +0000586 (void *)st = CALLOC(1, sizeof(*st));
vlmfa67ddc2004-06-03 03:38:44 +0000587 if(st && str && OCTET_STRING_fromBuf(st, str, len)) {
588 free(st);
589 st = NULL;
590 }
591
592 return st;
593}
594