blob: e0af730aa40e6df8c5caffb2be47d5c904a1257b [file] [log] [blame]
Lev Walkinf15320b2004-06-03 03:38:44 +00001/*-
Lev Walkin188ed2c2004-09-13 08:31:01 +00002 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
Lev Walkinf15320b2004-06-03 03:38:44 +00003 * 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]),
Lev Walkin188ed2c2004-09-13 08:31:01 +000026 asn1_DEF_OCTET_STRING_tags, /* Same as above */
27 sizeof(asn1_DEF_OCTET_STRING_tags)
28 / sizeof(asn1_DEF_OCTET_STRING_tags[0]),
Lev Walkinf15320b2004-06-03 03:38:44 +000029 -1, /* Both ways are fine (primitive and constructed) */
Lev Walkin449f8322004-08-20 13:23:42 +000030 0, 0, /* No members */
Lev Walkind9bd7752004-06-05 08:17:50 +000031 0 /* No specifics */
Lev Walkinf15320b2004-06-03 03:38:44 +000032};
33
34#define _CH_PHASE(ctx, inc) do { \
35 if(ctx->phase == 0) \
36 ctx->step = 0; \
37 ctx->phase += inc; \
38 } while(0)
39#define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1)
40#define PREV_PHASE(ctx) _CH_PHASE(ctx, -1)
41
Lev Walkin4ce78ca2004-08-25 01:34:11 +000042#define ADVANCE(num_bytes) do { \
43 size_t num = num_bytes; \
44 buf_ptr = ((char *)buf_ptr) + num; \
45 size -= num; \
46 consumed_myself += num; \
Lev Walkinf15320b2004-06-03 03:38:44 +000047 } while(0)
48
49#define RETURN(_code) do { \
50 rval.code = _code; \
51 rval.consumed = consumed_myself;\
52 return rval; \
53 } while(0)
54
Lev Walkind9bd7752004-06-05 08:17:50 +000055#define APPEND(bufptr, bufsize) do { \
Lev Walkin8d127872004-09-04 04:44:50 +000056 size_t _bs = (bufsize); \
Lev Walkind9bd7752004-06-05 08:17:50 +000057 size_t _ns = ctx->step; /* Allocated */ \
Lev Walkin8d127872004-09-04 04:44:50 +000058 if(_ns <= (size_t)(st->size + _bs)) { \
Lev Walkind9bd7752004-06-05 08:17:50 +000059 void *ptr; \
Lev Walkin188ed2c2004-09-13 08:31:01 +000060 /* Be nice and round to the memory allocator */ \
Lev Walkind9bd7752004-06-05 08:17:50 +000061 do { _ns = _ns ? _ns<<2 : 16; } \
Lev Walkin8d127872004-09-04 04:44:50 +000062 while(_ns <= (size_t)(st->size + _bs)); \
Lev Walkind9bd7752004-06-05 08:17:50 +000063 ptr = REALLOC(st->buf, _ns); \
64 if(ptr) { \
Lev Walkinc2346572004-08-11 09:07:36 +000065 st->buf = (uint8_t *)ptr; \
Lev Walkind9bd7752004-06-05 08:17:50 +000066 ctx->step = _ns; \
67 } else { \
68 RETURN(RC_FAIL); \
69 } \
70 } \
Lev Walkin8d127872004-09-04 04:44:50 +000071 memcpy(st->buf + st->size, bufptr, _bs); \
72 st->size += _bs; \
Lev Walkind9bd7752004-06-05 08:17:50 +000073 if(st->size < 0) \
74 /* Why even care?.. JIC */ \
75 RETURN(RC_FAIL); \
76 /* Convenient nul-termination */ \
77 st->buf[st->size] = '\0'; \
Lev Walkinf15320b2004-06-03 03:38:44 +000078 } while(0)
79
80/*
81 * The main reason why ASN.1 is still alive is that too much time and effort
82 * is necessary for learning it more or less adequately, thus creating a gut
83 * necessity to demonstrate that aquired skill everywhere afterwards.
84 * No, I am not going to explain what the following stuff is.
85 */
86struct _stack_el {
87 ber_tlv_len_t left; /* What's left to read */
Lev Walkin188ed2c2004-09-13 08:31:01 +000088 int cont_level; /* Depth of subcontainment */
Lev Walkinf15320b2004-06-03 03:38:44 +000089 int want_nulls; /* Want null "end of content" octets? */
90 int bits_chopped; /* Flag in BIT STRING mode */
91 struct _stack_el *prev;
92 struct _stack_el *next;
93};
94struct _stack {
95 struct _stack_el *tail;
96 struct _stack_el *cur_ptr;
97};
98
99static struct _stack_el *
100_add_stack_el(struct _stack *st) {
101 struct _stack_el *nel;
102
Lev Walkin188ed2c2004-09-13 08:31:01 +0000103 /*
104 * Reuse the old stack frame or allocate a new one.
105 */
Lev Walkinf15320b2004-06-03 03:38:44 +0000106 if(st->cur_ptr && st->cur_ptr->next) {
107 nel = st->cur_ptr->next;
108 nel->left = 0;
109 nel->want_nulls = 0;
110 nel->bits_chopped = 0;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000111 /* Retain nel->cont_level, it's correct. */
Lev Walkinf15320b2004-06-03 03:38:44 +0000112 } else {
Lev Walkinc2346572004-08-11 09:07:36 +0000113 (void *)nel = CALLOC(1, sizeof(struct _stack_el));
Lev Walkinf15320b2004-06-03 03:38:44 +0000114 if(nel == NULL)
115 return NULL;
116
117 if(st->tail) {
Lev Walkin188ed2c2004-09-13 08:31:01 +0000118 /* Increase a subcontainment depth */
119 nel->cont_level = st->tail->cont_level + 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000120 st->tail->next = nel;
121 }
122 nel->prev = st->tail;
123 st->tail = nel;
124 }
125
126 st->cur_ptr = nel;
127
128 return nel;
129}
130
131static struct _stack *
132_new_stack() {
133 struct _stack *st;
Lev Walkinc2346572004-08-11 09:07:36 +0000134 (void *)st = CALLOC(1, sizeof(struct _stack));
Lev Walkinf15320b2004-06-03 03:38:44 +0000135 if(st == NULL)
136 return NULL;
137
Lev Walkinf15320b2004-06-03 03:38:44 +0000138 return st;
139}
140
141/*
142 * Decode OCTET STRING type.
143 */
144ber_dec_rval_t
145OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
146 void **os_structure, void *buf_ptr, size_t size, int tag_mode) {
Lev Walkinc2346572004-08-11 09:07:36 +0000147 OCTET_STRING_t *st = (OCTET_STRING_t *)*os_structure;
Lev Walkinf15320b2004-06-03 03:38:44 +0000148 ber_dec_rval_t rval;
149 ber_dec_ctx_t *ctx;
150 ssize_t consumed_myself = 0;
151 struct _stack *stck; /* A stack structure */
152 struct _stack_el *sel; /* Stack element */
153 int tlv_constr;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000154 enum type_type_e {
155 _TT_GENERIC = 0, /* Just a random OCTET STRING */
156 _TT_BIT_STRING = -1, /* BIT STRING type, a special case */
157 _TT_ANY = 1, /* ANY type, a special case too */
158 } type_type
159 = (enum type_type_e)(int)td->specifics; /* An ugly hack */
Lev Walkinf15320b2004-06-03 03:38:44 +0000160
161 ASN_DEBUG("Decoding %s as %s (%ld)",
Lev Walkin8d127872004-09-04 04:44:50 +0000162 td->name, "OCTET STRING", (long)size);
Lev Walkinf15320b2004-06-03 03:38:44 +0000163
164 /*
165 * Create the string if does not exist.
166 */
167 if(st == NULL) {
Lev Walkinc2346572004-08-11 09:07:36 +0000168 (void *)st = *os_structure = CALLOC(1, sizeof(*st));
Lev Walkinf15320b2004-06-03 03:38:44 +0000169 if(st == NULL)
170 RETURN(RC_FAIL);
171 }
172
173 /* Restore parsing context */
174 ctx = &st->_ber_dec_ctx;
175
176 switch(ctx->phase) {
177 case 0:
178 /*
179 * Check tags.
180 */
181 rval = ber_check_tags(td, ctx,
182 buf_ptr, size, tag_mode,
183 &ctx->left, &tlv_constr);
184 if(rval.code != RC_OK) {
185 RETURN(rval.code);
186 }
187
188 ASN_DEBUG("OS length is %d bytes, form %d",
189 (int)ctx->left, tlv_constr);
190
191 if(tlv_constr) {
192 /*
193 * Complex operation, requires stack of expectations.
194 */
195 ctx->ptr = _new_stack();
196 if(ctx->ptr) {
Lev Walkinc2346572004-08-11 09:07:36 +0000197 (void *)stck = ctx->ptr;
Lev Walkin8d127872004-09-04 04:44:50 +0000198#if 0
Lev Walkinf15320b2004-06-03 03:38:44 +0000199 if(ctx->left < 0) {
200 stck->cur_ptr->want_nulls = -ctx->left;
201 stck->cur_ptr->left = -1;
202 } else {
203 stck->cur_ptr->want_nulls = 0;
204 stck->cur_ptr->left = ctx->left;
205 }
Lev Walkin8d127872004-09-04 04:44:50 +0000206 ASN_DEBUG("+EXPECT1 left=%d wn=%d",
Lev Walkinf15320b2004-06-03 03:38:44 +0000207 stck->cur_ptr->left,
208 stck->cur_ptr->want_nulls);
Lev Walkin8d127872004-09-04 04:44:50 +0000209#endif
Lev Walkin188ed2c2004-09-13 08:31:01 +0000210 if(type_type == _TT_BIT_STRING) {
Lev Walkin8d127872004-09-04 04:44:50 +0000211 /* Number of meaningless tail bits */
Lev Walkinf15320b2004-06-03 03:38:44 +0000212 APPEND("\0", 1);
213 }
214 } else {
215 RETURN(RC_FAIL);
216 }
217 } else {
218 /*
219 * Jump into stackless primitive decoding.
220 */
221 _CH_PHASE(ctx, 3);
Lev Walkin188ed2c2004-09-13 08:31:01 +0000222 if(type_type == _TT_ANY)
223 APPEND(buf_ptr, rval.consumed);
Lev Walkinf15320b2004-06-03 03:38:44 +0000224 ADVANCE(rval.consumed);
225 goto phase3;
226 }
227
Lev Walkinf15320b2004-06-03 03:38:44 +0000228 NEXT_PHASE(ctx);
229 /* Fall through */
230 case 1:
231 phase1:
232 /*
233 * Fill the stack with expectations.
234 */
Lev Walkinc2346572004-08-11 09:07:36 +0000235 (void *)stck = ctx->ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000236 sel = stck->cur_ptr;
237 do {
238 ber_tlv_tag_t tlv_tag;
239 ber_tlv_len_t tlv_len;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000240 ber_tlv_tag_t expected_tag;
Lev Walkinf15320b2004-06-03 03:38:44 +0000241 ssize_t tl, ll;
242
Lev Walkin8d127872004-09-04 04:44:50 +0000243 ASN_DEBUG("fetch tag(size=%d), %sstack, left=%d, want0=%d",
244 (int)size, sel?"":"!",
245 sel?sel->left:0, sel?sel->want_nulls:0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000246 tl = ber_fetch_tag(buf_ptr, size, &tlv_tag);
247 switch(tl) {
248 case -1: RETURN(RC_FAIL);
249 case 0: RETURN(RC_WMORE);
250 }
251
252 tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr);
253
254 ll = ber_fetch_length(tlv_constr,
Lev Walkin4d9528c2004-08-11 08:10:13 +0000255 (char *)buf_ptr + tl, size - tl, &tlv_len);
Lev Walkin8d127872004-09-04 04:44:50 +0000256 ASN_DEBUG("Got tag=%s, tc=%d, size=%d, tl=%d, len=%d, ll=%d, {%d, %d}",
257 ber_tlv_tag_string(tlv_tag), tlv_constr,
258 (int)size, tl, tlv_len, ll,
Lev Walkinf15320b2004-06-03 03:38:44 +0000259 ((uint8_t *)buf_ptr)[0],
260 ((uint8_t *)buf_ptr)[1]);
261 switch(ll) {
262 case -1: RETURN(RC_FAIL);
263 case 0: RETURN(RC_WMORE);
264 }
265
Lev Walkin8d127872004-09-04 04:44:50 +0000266 if(sel && sel->want_nulls
Lev Walkinf15320b2004-06-03 03:38:44 +0000267 && ((uint8_t *)buf_ptr)[0] == 0
268 && ((uint8_t *)buf_ptr)[1] == 0)
269 {
Lev Walkin8d127872004-09-04 04:44:50 +0000270 ADVANCE(2);
Lev Walkin188ed2c2004-09-13 08:31:01 +0000271 if(type_type == _TT_ANY) APPEND("\0\0", 2);
Lev Walkin8d127872004-09-04 04:44:50 +0000272
273 ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls);
274
Lev Walkinf15320b2004-06-03 03:38:44 +0000275 sel->want_nulls--;
276 if(sel->want_nulls == 0) {
277 /* Move to the next expectation */
278 sel = stck->cur_ptr = sel->prev;
Lev Walkin8d127872004-09-04 04:44:50 +0000279 if(sel == NULL)
Lev Walkinf15320b2004-06-03 03:38:44 +0000280 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000281 }
Lev Walkin8d127872004-09-04 04:44:50 +0000282
Lev Walkinf15320b2004-06-03 03:38:44 +0000283 if(sel->want_nulls) {
284 /*
285 * Simulate while(TRUE) for this loop.
286 * This is necessary to fetch the next
Lev Walkin8d127872004-09-04 04:44:50 +0000287 * expectation after current "end of content",
288 * for which tlv_constr is 0.
Lev Walkinf15320b2004-06-03 03:38:44 +0000289 */
Lev Walkinf15320b2004-06-03 03:38:44 +0000290 tlv_constr = 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000291 }
Lev Walkin8d127872004-09-04 04:44:50 +0000292
293 continue;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000294 }
295
296 /*
297 * Set up expected tags,
298 * depending on ASN.1 type being decoded.
299 */
300 switch(type_type) {
301 case _TT_BIT_STRING:
302 /* X.690: 8.6.4.1, NOTE 2 */
303 /* Fall through */
304 case _TT_GENERIC:
305 default:
306 if(sel) {
307 int level = sel->cont_level;
308 if(level < td->all_tags_count) {
309 expected_tag = td->all_tags[level];
310 break;
311 } else if(td->all_tags_count) {
312 expected_tag = td->all_tags
313 [td->all_tags_count - 1];
314 break;
315 }
316 /* else, Fall through */
317 }
318 /* Fall through */
319 case _TT_ANY:
320 expected_tag = tlv_tag;
321 break;
322 }
323
324
325 if(tlv_tag != expected_tag) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000326 char buf[2][32];
327 ber_tlv_tag_snprint(tlv_tag,
328 buf[0], sizeof(buf[0]));
329 ber_tlv_tag_snprint(td->tags[td->tags_count-1],
330 buf[1], sizeof(buf[1]));
331 ASN_DEBUG("Tag does not match expectation: %s != %s",
332 buf[0], buf[1]);
333 RETURN(RC_FAIL);
334 }
335
336 /*
337 * Append a new expectation.
338 */
339 sel = _add_stack_el(stck);
340 if(sel) {
341 sel->want_nulls = (tlv_len==-1);
342 sel->left = tlv_len;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000343 ASN_DEBUG("+EXPECT2 left=%d wn=%d, clvl=%d",
344 sel->left, sel->want_nulls, sel->cont_level);
Lev Walkinf15320b2004-06-03 03:38:44 +0000345 } else {
346 RETURN(RC_FAIL);
347 }
348
Lev Walkin188ed2c2004-09-13 08:31:01 +0000349 if(type_type == _TT_ANY) APPEND(buf_ptr, tl + ll);
Lev Walkinf15320b2004-06-03 03:38:44 +0000350 ADVANCE(tl+ll);
351 } while(tlv_constr);
352 if(sel == NULL) {
353 /* Finished operation, "phase out" */
Lev Walkin188ed2c2004-09-13 08:31:01 +0000354 ASN_DEBUG("Phase out");
Lev Walkinf15320b2004-06-03 03:38:44 +0000355 _CH_PHASE(ctx, +3);
356 break;
357 }
358
359 NEXT_PHASE(ctx);
360 /* Fall through */
361 case 2:
Lev Walkinc2346572004-08-11 09:07:36 +0000362 (void *)stck = ctx->ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000363 sel = stck->cur_ptr;
364 ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld",
365 (long)sel->left, (long)size);
366 {
367 ber_tlv_len_t len;
368
369 assert(sel->left >= 0);
370
Lev Walkinec1ffd42004-08-18 04:53:32 +0000371 len = ((ber_tlv_len_t)size < sel->left)
372 ? (ber_tlv_len_t)size : sel->left;
Lev Walkinf15320b2004-06-03 03:38:44 +0000373 if(len > 0) {
Lev Walkin188ed2c2004-09-13 08:31:01 +0000374 if(type_type == _TT_BIT_STRING
375 && sel->bits_chopped == 0) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000376 /*
377 * Finalize the previous chunk:
378 * strip down unused bits.
379 */
380 st->buf[st->size-1] &= 0xff << st->buf[0];
381
Lev Walkin4d9528c2004-08-11 08:10:13 +0000382 APPEND(((char *)buf_ptr+1), (len - 1));
Lev Walkinf15320b2004-06-03 03:38:44 +0000383 st->buf[0] = *(uint8_t *)buf_ptr;
384 sel->bits_chopped = 1;
385 } else {
386 APPEND(buf_ptr, len);
387 }
388 ADVANCE(len);
389 sel->left -= len;
390 }
391
392 if(sel->left) {
393 RETURN(RC_WMORE);
394 } else {
395 sel->left = 0;
396 if(sel->prev)
397 sel = stck->cur_ptr = sel->prev;
398 PREV_PHASE(ctx);
399 goto phase1;
400 }
401 }
402 break;
403 case 3:
404 phase3:
405 /*
406 * Primitive form, no stack required.
407 */
Lev Walkind9bd7752004-06-05 08:17:50 +0000408 if(size < (size_t)ctx->left) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000409 APPEND(buf_ptr, size);
410 ctx->left -= size;
411 ADVANCE(size);
412 RETURN(RC_WMORE);
413 } else {
414 APPEND(buf_ptr, ctx->left);
415 ADVANCE(ctx->left);
416 ctx->left = 0;
417
418 NEXT_PHASE(ctx);
419 }
420 break;
421 }
422
423 /*
424 * BIT STRING-specific processing.
425 */
Lev Walkin188ed2c2004-09-13 08:31:01 +0000426 if(type_type == _TT_BIT_STRING && st->size >= 2) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000427 /* Finalize BIT STRING: zero out unused bits. */
428 st->buf[st->size-1] &= 0xff << st->buf[0];
429 }
430
431 ASN_DEBUG("Took %d bytes to encode %s: [%s]:%d",
432 consumed_myself, td->name, st->buf, st->size);
433
434 rval.code = RC_OK;
435 rval.consumed = consumed_myself;
436
437 return rval;
438}
439
440/*
441 * Encode OCTET STRING type using DER.
442 */
443der_enc_rval_t
Lev Walkin1f670c12004-09-02 12:57:25 +0000444OCTET_STRING_encode_der(asn1_TYPE_descriptor_t *td, void *ptr,
Lev Walkinf15320b2004-06-03 03:38:44 +0000445 int tag_mode, ber_tlv_tag_t tag,
446 asn_app_consume_bytes_f *cb, void *app_key) {
447 der_enc_rval_t erval;
Lev Walkinc2346572004-08-11 09:07:36 +0000448 OCTET_STRING_t *st = (OCTET_STRING_t *)ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000449 int add_byte = 0;
Lev Walkina737f3b2004-09-02 12:11:47 +0000450 int is_bit_str = (td->specifics == (void *)-1);
Lev Walkin1f670c12004-09-02 12:57:25 +0000451 int is_ANY_type = (td->specifics == (void *)1);
Lev Walkinf15320b2004-06-03 03:38:44 +0000452
453 ASN_DEBUG("%s %s as OCTET STRING",
Lev Walkin1f670c12004-09-02 12:57:25 +0000454 cb?"Estimating":"Encoding", td->name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000455
456 /*
457 * Canonicalize BIT STRING.
458 */
Lev Walkina737f3b2004-09-02 12:11:47 +0000459 if(is_bit_str && st->buf) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000460 switch(st->size) {
461 case 0: add_byte = 1; break;
462 case 1: st->buf[0] = 0; break;
463 default:
464 /* Finalize BIT STRING: zero out unused bits. */
465 st->buf[st->size-1] &= 0xff << st->buf[0];
466 }
467 }
468
Lev Walkina737f3b2004-09-02 12:11:47 +0000469 if(is_ANY_type) {
470 erval.encoded = 0;
471 } else {
Lev Walkin1f670c12004-09-02 12:57:25 +0000472 erval.encoded = der_write_tags(td, st->size + add_byte,
Lev Walkina737f3b2004-09-02 12:11:47 +0000473 tag_mode, tag, cb, app_key);
474 if(erval.encoded == -1) {
Lev Walkin1f670c12004-09-02 12:57:25 +0000475 erval.failed_type = td;
Lev Walkina737f3b2004-09-02 12:11:47 +0000476 erval.structure_ptr = ptr;
477 return erval;
478 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000479 }
480
481 if(cb) {
482 uint8_t zero;
483 uint8_t *buf;
484 int size;
485 ssize_t ret;
486
487 /* BIT STRING-aware handling */
488 if(add_byte) {
489 zero = 0;
490 buf = &zero;
491 size = 1;
492 } else if(st->buf) {
493 buf = st->buf;
494 size = st->size;
495 } else {
496 assert(st->size == 0);
497 buf = 0; /* Not used */
498 size = 0;
499 }
500
501 if(size) {
502 ret = cb(buf, size, app_key);
503 if(ret == -1) {
504 erval.encoded = -1;
Lev Walkin1f670c12004-09-02 12:57:25 +0000505 erval.failed_type = td;
Lev Walkinf15320b2004-06-03 03:38:44 +0000506 erval.structure_ptr = ptr;
507 return erval;
508 }
509 }
510 }
511
512 erval.encoded += st->size + add_byte;
513
514 return erval;
515}
516
517int
518OCTET_STRING_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
519 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin4d9528c2004-08-11 08:10:13 +0000520 static const char *h2c = "0123456789ABCDEF";
Lev Walkinc2346572004-08-11 09:07:36 +0000521 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000522 char scratch[16 * 3 + 4];
523 char *p = scratch;
524 uint8_t *buf;
525 uint8_t *end;
526 size_t i;
527 int ret;
528
Lev Walkind9bd7752004-06-05 08:17:50 +0000529 (void)td; /* Unused argument */
530
Lev Walkinf15320b2004-06-03 03:38:44 +0000531 if(!st || !st->buf) return cb("<absent>", 8, app_key);
532
533 /*
534 * Dump the contents of the buffer in hexadecimal.
535 */
536 buf = st->buf;
537 end = buf + st->size;
538 for(i = 0; buf < end; buf++, i++) {
539 if(!(i % 16) && (i || st->size > 16)) {
540 if(cb(scratch, p - scratch, app_key)
541 || cb("\n", 1, app_key))
542 return -1;
543 for(ret = 0; ret < ilevel; ret++)
544 cb(" ", 1, app_key);
545 p = scratch;
546 }
547 *p++ = h2c[(*buf >> 4) & 0x0F];
548 *p++ = h2c[*buf & 0x0F];
549 *p++ = ' ';
550 }
551
552 return cb(scratch, p - scratch, app_key);
553}
554
555int
556OCTET_STRING_print_ascii(asn1_TYPE_descriptor_t *td, const void *sptr,
557 int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +0000558 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000559
Lev Walkind9bd7752004-06-05 08:17:50 +0000560 (void)td; /* Unused argument */
561 (void)ilevel; /* Unused argument */
562
Lev Walkinf15320b2004-06-03 03:38:44 +0000563 if(st && st->buf) {
564 return cb(st->buf, st->size, app_key);
565 } else {
566 return cb("<absent>", 8, app_key);
567 }
568}
569
570void
571OCTET_STRING_free(asn1_TYPE_descriptor_t *td, void *sptr, int contents_only) {
Lev Walkinc2346572004-08-11 09:07:36 +0000572 OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
573 struct _stack *stck = (struct _stack *)st->_ber_dec_ctx.ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000574
575 if(!td || !st)
576 return;
577
578 ASN_DEBUG("Freeing %s as OCTET STRING", td->name);
579
580 if(st->buf) {
581 FREEMEM(st->buf);
582 }
583
584 /*
585 * Remove decode-time stack.
586 */
587 if(stck) {
588 while(stck->tail) {
589 struct _stack_el *sel = stck->tail;
590 stck->tail = sel->prev;
591 FREEMEM(sel);
592 }
593 FREEMEM(stck);
594 }
595
596 if(!contents_only) {
597 FREEMEM(st);
598 }
599}
600
601/*
602 * Conversion routines.
603 */
604int
605OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) {
606 void *buf;
607
608 if(st == 0 || (str == 0 && len)) {
609 errno = EINVAL;
610 return -1;
611 }
612
613 /*
614 * Clear the OCTET STRING.
615 */
616 if(str == NULL) {
617 if(st->buf)
618 FREEMEM(st->buf);
619 st->size = 0;
620 return 0;
621 }
622
623 /* Determine the original string size, if not explicitly given */
624 if(len < 0)
625 len = strlen(str);
626
627 /* Allocate and fill the memory */
628 buf = MALLOC(len + 1);
629 if(buf == NULL) {
630 return -1;
631 } else {
Lev Walkinc2346572004-08-11 09:07:36 +0000632 st->buf = (uint8_t *)buf;
Lev Walkinf15320b2004-06-03 03:38:44 +0000633 st->size = len;
634 }
635
636 memcpy(buf, str, len);
637 st->buf[st->size] = '\0'; /* Couldn't use memcpy(len+1)! */
638
639 return 0;
640}
641
642OCTET_STRING_t *
643OCTET_STRING_new_fromBuf(const char *str, int len) {
644 OCTET_STRING_t *st;
645
Lev Walkinc2346572004-08-11 09:07:36 +0000646 (void *)st = CALLOC(1, sizeof(*st));
Lev Walkinf15320b2004-06-03 03:38:44 +0000647 if(st && str && OCTET_STRING_fromBuf(st, str, len)) {
648 free(st);
649 st = NULL;
650 }
651
652 return st;
653}
654