blob: df6f86e82621c05e302d5a288a415623d40f772f [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 */
Lev Walkina9cc46e2004-09-22 16:06:28 +00005#include <asn_internal.h>
Lev Walkinf15320b2004-06-03 03:38:44 +00006#include <OCTET_STRING.h>
7#include <assert.h>
8#include <errno.h>
9
10/*
11 * OCTET STRING basic type description.
12 */
13static ber_tlv_tag_t asn1_DEF_OCTET_STRING_tags[] = {
14 (ASN_TAG_CLASS_UNIVERSAL | (4 << 2))
15};
16asn1_TYPE_descriptor_t asn1_DEF_OCTET_STRING = {
17 "OCTET STRING",
Lev Walkina9cc46e2004-09-22 16:06:28 +000018 OCTET_STRING_free,
19 OCTET_STRING_print, /* non-ascii stuff, generally */
Lev Walkinf15320b2004-06-03 03:38:44 +000020 asn_generic_no_constraint,
21 OCTET_STRING_decode_ber,
22 OCTET_STRING_encode_der,
Lev Walkina9cc46e2004-09-22 16:06:28 +000023 0, /* Not implemented yet */
24 OCTET_STRING_encode_xer,
Lev Walkinf15320b2004-06-03 03:38:44 +000025 0, /* Use generic outmost tag fetcher */
26 asn1_DEF_OCTET_STRING_tags,
27 sizeof(asn1_DEF_OCTET_STRING_tags)
28 / sizeof(asn1_DEF_OCTET_STRING_tags[0]),
Lev Walkin188ed2c2004-09-13 08:31:01 +000029 asn1_DEF_OCTET_STRING_tags, /* Same as above */
30 sizeof(asn1_DEF_OCTET_STRING_tags)
31 / sizeof(asn1_DEF_OCTET_STRING_tags[0]),
Lev Walkinf15320b2004-06-03 03:38:44 +000032 -1, /* Both ways are fine (primitive and constructed) */
Lev Walkin449f8322004-08-20 13:23:42 +000033 0, 0, /* No members */
Lev Walkind9bd7752004-06-05 08:17:50 +000034 0 /* No specifics */
Lev Walkinf15320b2004-06-03 03:38:44 +000035};
36
Lev Walkincc6a9102004-09-23 22:06:26 +000037#undef _CH_PHASE
38#undef NEXT_PHASE
39#undef PREV_PHASE
Lev Walkinf15320b2004-06-03 03:38:44 +000040#define _CH_PHASE(ctx, inc) do { \
41 if(ctx->phase == 0) \
42 ctx->step = 0; \
43 ctx->phase += inc; \
44 } while(0)
45#define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1)
46#define PREV_PHASE(ctx) _CH_PHASE(ctx, -1)
47
Lev Walkincc6a9102004-09-23 22:06:26 +000048#undef ADVANCE
Lev Walkin4ce78ca2004-08-25 01:34:11 +000049#define ADVANCE(num_bytes) do { \
Lev Walkin3990ba62004-09-24 20:57:41 +000050 size_t num = (num_bytes); \
Lev Walkin4ce78ca2004-08-25 01:34:11 +000051 buf_ptr = ((char *)buf_ptr) + num; \
52 size -= num; \
53 consumed_myself += num; \
Lev Walkinf15320b2004-06-03 03:38:44 +000054 } while(0)
55
Lev Walkincc6a9102004-09-23 22:06:26 +000056#undef RETURN
Lev Walkinf15320b2004-06-03 03:38:44 +000057#define RETURN(_code) do { \
58 rval.code = _code; \
59 rval.consumed = consumed_myself;\
60 return rval; \
61 } while(0)
62
Lev Walkincc6a9102004-09-23 22:06:26 +000063#undef APPEND
Lev Walkind9bd7752004-06-05 08:17:50 +000064#define APPEND(bufptr, bufsize) do { \
Lev Walkin8d127872004-09-04 04:44:50 +000065 size_t _bs = (bufsize); \
Lev Walkind9bd7752004-06-05 08:17:50 +000066 size_t _ns = ctx->step; /* Allocated */ \
Lev Walkin8d127872004-09-04 04:44:50 +000067 if(_ns <= (size_t)(st->size + _bs)) { \
Lev Walkind9bd7752004-06-05 08:17:50 +000068 void *ptr; \
Lev Walkin188ed2c2004-09-13 08:31:01 +000069 /* Be nice and round to the memory allocator */ \
Lev Walkind9bd7752004-06-05 08:17:50 +000070 do { _ns = _ns ? _ns<<2 : 16; } \
Lev Walkin8d127872004-09-04 04:44:50 +000071 while(_ns <= (size_t)(st->size + _bs)); \
Lev Walkind9bd7752004-06-05 08:17:50 +000072 ptr = REALLOC(st->buf, _ns); \
73 if(ptr) { \
Lev Walkinc2346572004-08-11 09:07:36 +000074 st->buf = (uint8_t *)ptr; \
Lev Walkind9bd7752004-06-05 08:17:50 +000075 ctx->step = _ns; \
76 } else { \
77 RETURN(RC_FAIL); \
78 } \
79 } \
Lev Walkin8d127872004-09-04 04:44:50 +000080 memcpy(st->buf + st->size, bufptr, _bs); \
81 st->size += _bs; \
Lev Walkind9bd7752004-06-05 08:17:50 +000082 if(st->size < 0) \
83 /* Why even care?.. JIC */ \
84 RETURN(RC_FAIL); \
85 /* Convenient nul-termination */ \
86 st->buf[st->size] = '\0'; \
Lev Walkinf15320b2004-06-03 03:38:44 +000087 } while(0)
88
89/*
90 * The main reason why ASN.1 is still alive is that too much time and effort
91 * is necessary for learning it more or less adequately, thus creating a gut
92 * necessity to demonstrate that aquired skill everywhere afterwards.
93 * No, I am not going to explain what the following stuff is.
94 */
95struct _stack_el {
Lev Walkin3990ba62004-09-24 20:57:41 +000096 ber_tlv_len_t left; /* What's left to read (or -1) */
97 ber_tlv_len_t frame; /* What was planned to read (or -1) */
Lev Walkin188ed2c2004-09-13 08:31:01 +000098 int cont_level; /* Depth of subcontainment */
Lev Walkinf15320b2004-06-03 03:38:44 +000099 int want_nulls; /* Want null "end of content" octets? */
100 int bits_chopped; /* Flag in BIT STRING mode */
101 struct _stack_el *prev;
102 struct _stack_el *next;
103};
104struct _stack {
105 struct _stack_el *tail;
106 struct _stack_el *cur_ptr;
107};
108
109static struct _stack_el *
Lev Walkin3990ba62004-09-24 20:57:41 +0000110OS__add_stack_el(struct _stack *st) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000111 struct _stack_el *nel;
112
Lev Walkin188ed2c2004-09-13 08:31:01 +0000113 /*
114 * Reuse the old stack frame or allocate a new one.
115 */
Lev Walkinf15320b2004-06-03 03:38:44 +0000116 if(st->cur_ptr && st->cur_ptr->next) {
117 nel = st->cur_ptr->next;
Lev Walkinf15320b2004-06-03 03:38:44 +0000118 nel->bits_chopped = 0;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000119 /* Retain nel->cont_level, it's correct. */
Lev Walkinf15320b2004-06-03 03:38:44 +0000120 } else {
Lev Walkinc2346572004-08-11 09:07:36 +0000121 (void *)nel = CALLOC(1, sizeof(struct _stack_el));
Lev Walkinf15320b2004-06-03 03:38:44 +0000122 if(nel == NULL)
123 return NULL;
124
125 if(st->tail) {
Lev Walkin188ed2c2004-09-13 08:31:01 +0000126 /* Increase a subcontainment depth */
127 nel->cont_level = st->tail->cont_level + 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000128 st->tail->next = nel;
129 }
130 nel->prev = st->tail;
131 st->tail = nel;
132 }
133
134 st->cur_ptr = nel;
135
136 return nel;
137}
138
139static struct _stack *
140_new_stack() {
141 struct _stack *st;
Lev Walkinc2346572004-08-11 09:07:36 +0000142 (void *)st = CALLOC(1, sizeof(struct _stack));
Lev Walkinf15320b2004-06-03 03:38:44 +0000143 if(st == NULL)
144 return NULL;
145
Lev Walkinf15320b2004-06-03 03:38:44 +0000146 return st;
147}
148
149/*
150 * Decode OCTET STRING type.
151 */
152ber_dec_rval_t
153OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
154 void **os_structure, void *buf_ptr, size_t size, int tag_mode) {
Lev Walkinc2346572004-08-11 09:07:36 +0000155 OCTET_STRING_t *st = (OCTET_STRING_t *)*os_structure;
Lev Walkinf15320b2004-06-03 03:38:44 +0000156 ber_dec_rval_t rval;
157 ber_dec_ctx_t *ctx;
158 ssize_t consumed_myself = 0;
159 struct _stack *stck; /* A stack structure */
160 struct _stack_el *sel; /* Stack element */
161 int tlv_constr;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000162 enum type_type_e {
163 _TT_GENERIC = 0, /* Just a random OCTET STRING */
164 _TT_BIT_STRING = -1, /* BIT STRING type, a special case */
165 _TT_ANY = 1, /* ANY type, a special case too */
166 } type_type
167 = (enum type_type_e)(int)td->specifics; /* An ugly hack */
Lev Walkinf15320b2004-06-03 03:38:44 +0000168
Lev Walkincc6a9102004-09-23 22:06:26 +0000169 ASN_DEBUG("Decoding %s as %s (frame %ld)",
170 td->name,
171 (type_type == _TT_GENERIC) ? "OCTET STRING" : "OS-SpecialCase",
172 (long)size);
Lev Walkinf15320b2004-06-03 03:38:44 +0000173
174 /*
175 * Create the string if does not exist.
176 */
177 if(st == NULL) {
Lev Walkinc2346572004-08-11 09:07:36 +0000178 (void *)st = *os_structure = CALLOC(1, sizeof(*st));
Lev Walkinf15320b2004-06-03 03:38:44 +0000179 if(st == NULL)
180 RETURN(RC_FAIL);
181 }
182
183 /* Restore parsing context */
184 ctx = &st->_ber_dec_ctx;
185
186 switch(ctx->phase) {
187 case 0:
188 /*
189 * Check tags.
190 */
191 rval = ber_check_tags(td, ctx,
192 buf_ptr, size, tag_mode,
193 &ctx->left, &tlv_constr);
194 if(rval.code != RC_OK) {
195 RETURN(rval.code);
196 }
197
Lev Walkinf15320b2004-06-03 03:38:44 +0000198 if(tlv_constr) {
199 /*
200 * Complex operation, requires stack of expectations.
201 */
202 ctx->ptr = _new_stack();
203 if(ctx->ptr) {
Lev Walkinc2346572004-08-11 09:07:36 +0000204 (void *)stck = ctx->ptr;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000205 if(type_type == _TT_BIT_STRING) {
Lev Walkin8d127872004-09-04 04:44:50 +0000206 /* Number of meaningless tail bits */
Lev Walkinf15320b2004-06-03 03:38:44 +0000207 APPEND("\0", 1);
208 }
209 } else {
210 RETURN(RC_FAIL);
211 }
212 } else {
213 /*
214 * Jump into stackless primitive decoding.
215 */
216 _CH_PHASE(ctx, 3);
Lev Walkin188ed2c2004-09-13 08:31:01 +0000217 if(type_type == _TT_ANY)
218 APPEND(buf_ptr, rval.consumed);
Lev Walkinf15320b2004-06-03 03:38:44 +0000219 ADVANCE(rval.consumed);
220 goto phase3;
221 }
222
Lev Walkinf15320b2004-06-03 03:38:44 +0000223 NEXT_PHASE(ctx);
224 /* Fall through */
225 case 1:
226 phase1:
227 /*
228 * Fill the stack with expectations.
229 */
Lev Walkinc2346572004-08-11 09:07:36 +0000230 (void *)stck = ctx->ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000231 sel = stck->cur_ptr;
232 do {
233 ber_tlv_tag_t tlv_tag;
234 ber_tlv_len_t tlv_len;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000235 ber_tlv_tag_t expected_tag;
Lev Walkinf15320b2004-06-03 03:38:44 +0000236 ssize_t tl, ll;
Lev Walkin3990ba62004-09-24 20:57:41 +0000237 ssize_t Left = ((!sel||sel->left==-1||sel->left >= size)
238 ?size:sel->left);
Lev Walkinf15320b2004-06-03 03:38:44 +0000239
Lev Walkin3990ba62004-09-24 20:57:41 +0000240
241 ASN_DEBUG("fetch tag(size=%d,L=%d), %sstack, left=%d, want0=%d",
242 (int)size, Left, sel?"":"!",
Lev Walkin8d127872004-09-04 04:44:50 +0000243 sel?sel->left:0, sel?sel->want_nulls:0);
Lev Walkin3990ba62004-09-24 20:57:41 +0000244 tl = ber_fetch_tag(buf_ptr, Left, &tlv_tag);
Lev Walkinf15320b2004-06-03 03:38:44 +0000245 switch(tl) {
246 case -1: RETURN(RC_FAIL);
247 case 0: RETURN(RC_WMORE);
248 }
249
250 tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr);
251
252 ll = ber_fetch_length(tlv_constr,
Lev Walkin3990ba62004-09-24 20:57:41 +0000253 (char *)buf_ptr + tl, Left - tl, &tlv_len);
Lev Walkin8d127872004-09-04 04:44:50 +0000254 ASN_DEBUG("Got tag=%s, tc=%d, size=%d, tl=%d, len=%d, ll=%d, {%d, %d}",
255 ber_tlv_tag_string(tlv_tag), tlv_constr,
Lev Walkin3990ba62004-09-24 20:57:41 +0000256 (int)Left, tl, tlv_len, ll,
Lev Walkinf15320b2004-06-03 03:38:44 +0000257 ((uint8_t *)buf_ptr)[0],
258 ((uint8_t *)buf_ptr)[1]);
259 switch(ll) {
260 case -1: RETURN(RC_FAIL);
261 case 0: RETURN(RC_WMORE);
262 }
263
Lev Walkin8d127872004-09-04 04:44:50 +0000264 if(sel && sel->want_nulls
Lev Walkinf15320b2004-06-03 03:38:44 +0000265 && ((uint8_t *)buf_ptr)[0] == 0
266 && ((uint8_t *)buf_ptr)[1] == 0)
267 {
Lev Walkin8d127872004-09-04 04:44:50 +0000268 ADVANCE(2);
Lev Walkin188ed2c2004-09-13 08:31:01 +0000269 if(type_type == _TT_ANY) APPEND("\0\0", 2);
Lev Walkin8d127872004-09-04 04:44:50 +0000270
271 ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls);
272
Lev Walkinf15320b2004-06-03 03:38:44 +0000273 sel->want_nulls--;
274 if(sel->want_nulls == 0) {
275 /* Move to the next expectation */
276 sel = stck->cur_ptr = sel->prev;
Lev Walkin8d127872004-09-04 04:44:50 +0000277 if(sel == NULL)
Lev Walkinf15320b2004-06-03 03:38:44 +0000278 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000279 }
Lev Walkin8d127872004-09-04 04:44:50 +0000280
Lev Walkinf15320b2004-06-03 03:38:44 +0000281 if(sel->want_nulls) {
282 /*
283 * Simulate while(TRUE) for this loop.
284 * This is necessary to fetch the next
Lev Walkin8d127872004-09-04 04:44:50 +0000285 * expectation after current "end of content",
286 * for which tlv_constr is 0.
Lev Walkinf15320b2004-06-03 03:38:44 +0000287 */
Lev Walkinf15320b2004-06-03 03:38:44 +0000288 tlv_constr = 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000289 }
Lev Walkin8d127872004-09-04 04:44:50 +0000290
291 continue;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000292 }
293
294 /*
295 * Set up expected tags,
296 * depending on ASN.1 type being decoded.
297 */
298 switch(type_type) {
299 case _TT_BIT_STRING:
300 /* X.690: 8.6.4.1, NOTE 2 */
301 /* Fall through */
302 case _TT_GENERIC:
303 default:
304 if(sel) {
305 int level = sel->cont_level;
306 if(level < td->all_tags_count) {
307 expected_tag = td->all_tags[level];
308 break;
309 } else if(td->all_tags_count) {
310 expected_tag = td->all_tags
311 [td->all_tags_count - 1];
312 break;
313 }
314 /* else, Fall through */
315 }
316 /* Fall through */
317 case _TT_ANY:
318 expected_tag = tlv_tag;
319 break;
320 }
321
322
323 if(tlv_tag != expected_tag) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000324 char buf[2][32];
325 ber_tlv_tag_snprint(tlv_tag,
326 buf[0], sizeof(buf[0]));
327 ber_tlv_tag_snprint(td->tags[td->tags_count-1],
328 buf[1], sizeof(buf[1]));
329 ASN_DEBUG("Tag does not match expectation: %s != %s",
330 buf[0], buf[1]);
331 RETURN(RC_FAIL);
332 }
333
334 /*
Lev Walkin3990ba62004-09-24 20:57:41 +0000335 * Consult with the old expectation.
336 * Check that it knows what we are doing here, and how much.
337 */
338 if(sel && sel->left != -1) {
339 if(sel->left < (tl + ll))
340 RETURN(RC_FAIL);
341 sel->left -= (tl + ll);
342 if(sel->left < tlv_len)
343 RETURN(RC_FAIL);
344 }
345
346
347 /*
Lev Walkinf15320b2004-06-03 03:38:44 +0000348 * Append a new expectation.
349 */
Lev Walkin3990ba62004-09-24 20:57:41 +0000350 sel = OS__add_stack_el(stck);
Lev Walkinf15320b2004-06-03 03:38:44 +0000351 if(sel) {
352 sel->want_nulls = (tlv_len==-1);
Lev Walkin3990ba62004-09-24 20:57:41 +0000353 sel->frame = sel->left = tlv_len;
354 ASN_DEBUG("+EXPECT2 frame=%d wn=%d, clvl=%d",
355 sel->frame, sel->want_nulls, sel->cont_level);
Lev Walkinf15320b2004-06-03 03:38:44 +0000356 } else {
357 RETURN(RC_FAIL);
358 }
359
Lev Walkin188ed2c2004-09-13 08:31:01 +0000360 if(type_type == _TT_ANY) APPEND(buf_ptr, tl + ll);
Lev Walkinf15320b2004-06-03 03:38:44 +0000361 ADVANCE(tl+ll);
362 } while(tlv_constr);
363 if(sel == NULL) {
364 /* Finished operation, "phase out" */
Lev Walkin188ed2c2004-09-13 08:31:01 +0000365 ASN_DEBUG("Phase out");
Lev Walkinf15320b2004-06-03 03:38:44 +0000366 _CH_PHASE(ctx, +3);
367 break;
368 }
369
370 NEXT_PHASE(ctx);
371 /* Fall through */
372 case 2:
Lev Walkinc2346572004-08-11 09:07:36 +0000373 (void *)stck = ctx->ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000374 sel = stck->cur_ptr;
375 ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld",
376 (long)sel->left, (long)size);
377 {
378 ber_tlv_len_t len;
379
380 assert(sel->left >= 0);
381
Lev Walkinec1ffd42004-08-18 04:53:32 +0000382 len = ((ber_tlv_len_t)size < sel->left)
383 ? (ber_tlv_len_t)size : sel->left;
Lev Walkinf15320b2004-06-03 03:38:44 +0000384 if(len > 0) {
Lev Walkin188ed2c2004-09-13 08:31:01 +0000385 if(type_type == _TT_BIT_STRING
386 && sel->bits_chopped == 0) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000387 /*
388 * Finalize the previous chunk:
389 * strip down unused bits.
390 */
391 st->buf[st->size-1] &= 0xff << st->buf[0];
392
Lev Walkin4d9528c2004-08-11 08:10:13 +0000393 APPEND(((char *)buf_ptr+1), (len - 1));
Lev Walkinf15320b2004-06-03 03:38:44 +0000394 st->buf[0] = *(uint8_t *)buf_ptr;
395 sel->bits_chopped = 1;
396 } else {
397 APPEND(buf_ptr, len);
398 }
399 ADVANCE(len);
400 sel->left -= len;
401 }
402
Lev Walkin3990ba62004-09-24 20:57:41 +0000403 if(sel->left)
Lev Walkinf15320b2004-06-03 03:38:44 +0000404 RETURN(RC_WMORE);
Lev Walkin3990ba62004-09-24 20:57:41 +0000405
406 while(sel->left == 0) {
407 ASN_DEBUG("sel %p, l=%d, f=%d, %p->l=%d p->f=%d\n",
408 sel, sel->left, sel->frame,
409 sel->prev,
410 sel->prev?sel->prev->left:0,
411 sel->prev?sel->prev->frame:0
412 );
413 if(sel->prev) {
414 if(sel->prev->left != -1) {
415 if(sel->prev->left < sel->frame)
416 RETURN(RC_FAIL);
417 sel->prev->left -= sel->frame;
418 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000419 sel = stck->cur_ptr = sel->prev;
Lev Walkin3990ba62004-09-24 20:57:41 +0000420 if(sel->left) {
421 PREV_PHASE(ctx);
422 goto phase1;
423 }
424 } else {
425 break;
426 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000427 }
428 }
429 break;
430 case 3:
431 phase3:
432 /*
433 * Primitive form, no stack required.
434 */
Lev Walkind9bd7752004-06-05 08:17:50 +0000435 if(size < (size_t)ctx->left) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000436 APPEND(buf_ptr, size);
437 ctx->left -= size;
438 ADVANCE(size);
439 RETURN(RC_WMORE);
440 } else {
441 APPEND(buf_ptr, ctx->left);
442 ADVANCE(ctx->left);
443 ctx->left = 0;
444
445 NEXT_PHASE(ctx);
446 }
447 break;
448 }
449
450 /*
451 * BIT STRING-specific processing.
452 */
Lev Walkin188ed2c2004-09-13 08:31:01 +0000453 if(type_type == _TT_BIT_STRING && st->size >= 2) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000454 /* Finalize BIT STRING: zero out unused bits. */
455 st->buf[st->size-1] &= 0xff << st->buf[0];
456 }
457
458 ASN_DEBUG("Took %d bytes to encode %s: [%s]:%d",
Lev Walkin3990ba62004-09-24 20:57:41 +0000459 consumed_myself, td->name,
460 (type_type == _TT_GENERIC) ? (char *)st->buf : "", st->size);
Lev Walkinf15320b2004-06-03 03:38:44 +0000461
462 rval.code = RC_OK;
463 rval.consumed = consumed_myself;
464
465 return rval;
466}
467
468/*
469 * Encode OCTET STRING type using DER.
470 */
Lev Walkina9cc46e2004-09-22 16:06:28 +0000471asn_enc_rval_t
Lev Walkin1f670c12004-09-02 12:57:25 +0000472OCTET_STRING_encode_der(asn1_TYPE_descriptor_t *td, void *ptr,
Lev Walkinf15320b2004-06-03 03:38:44 +0000473 int tag_mode, ber_tlv_tag_t tag,
474 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkina9cc46e2004-09-22 16:06:28 +0000475 asn_enc_rval_t erval;
Lev Walkinc2346572004-08-11 09:07:36 +0000476 OCTET_STRING_t *st = (OCTET_STRING_t *)ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000477 int add_byte = 0;
Lev Walkina737f3b2004-09-02 12:11:47 +0000478 int is_bit_str = (td->specifics == (void *)-1);
Lev Walkin1f670c12004-09-02 12:57:25 +0000479 int is_ANY_type = (td->specifics == (void *)1);
Lev Walkinf15320b2004-06-03 03:38:44 +0000480
481 ASN_DEBUG("%s %s as OCTET STRING",
Lev Walkin1f670c12004-09-02 12:57:25 +0000482 cb?"Estimating":"Encoding", td->name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000483
484 /*
485 * Canonicalize BIT STRING.
486 */
Lev Walkina737f3b2004-09-02 12:11:47 +0000487 if(is_bit_str && st->buf) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000488 switch(st->size) {
489 case 0: add_byte = 1; break;
490 case 1: st->buf[0] = 0; break;
491 default:
492 /* Finalize BIT STRING: zero out unused bits. */
493 st->buf[st->size-1] &= 0xff << st->buf[0];
494 }
495 }
496
Lev Walkina737f3b2004-09-02 12:11:47 +0000497 if(is_ANY_type) {
498 erval.encoded = 0;
499 } else {
Lev Walkin1f670c12004-09-02 12:57:25 +0000500 erval.encoded = der_write_tags(td, st->size + add_byte,
Lev Walkina737f3b2004-09-02 12:11:47 +0000501 tag_mode, tag, cb, app_key);
502 if(erval.encoded == -1) {
Lev Walkin1f670c12004-09-02 12:57:25 +0000503 erval.failed_type = td;
Lev Walkina737f3b2004-09-02 12:11:47 +0000504 erval.structure_ptr = ptr;
505 return erval;
506 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000507 }
508
509 if(cb) {
510 uint8_t zero;
511 uint8_t *buf;
512 int size;
513 ssize_t ret;
514
515 /* BIT STRING-aware handling */
516 if(add_byte) {
517 zero = 0;
518 buf = &zero;
519 size = 1;
520 } else if(st->buf) {
521 buf = st->buf;
522 size = st->size;
523 } else {
524 assert(st->size == 0);
525 buf = 0; /* Not used */
526 size = 0;
527 }
528
529 if(size) {
530 ret = cb(buf, size, app_key);
531 if(ret == -1) {
532 erval.encoded = -1;
Lev Walkin1f670c12004-09-02 12:57:25 +0000533 erval.failed_type = td;
Lev Walkinf15320b2004-06-03 03:38:44 +0000534 erval.structure_ptr = ptr;
535 return erval;
536 }
537 }
538 }
539
540 erval.encoded += st->size + add_byte;
541
542 return erval;
543}
544
Lev Walkina9cc46e2004-09-22 16:06:28 +0000545asn_enc_rval_t
546OCTET_STRING_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
547 int ilevel, enum xer_encoder_flags_e flags,
548 asn_app_consume_bytes_f *cb, void *app_key) {
549 static const char *h2c = "0123456789ABCDEF";
550 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
551 asn_enc_rval_t er;
552 char scratch[16 * 3 + 4];
553 char *p = scratch;
554 uint8_t *buf;
555 uint8_t *end;
556 size_t i;
557
558 if(!st || !st->buf) {
559 er.encoded = -1;
560 er.failed_type = td;
561 er.structure_ptr = sptr;
562 return er;
563 }
564
565 er.encoded = 0;
566
567 /*
568 * Dump the contents of the buffer in hexadecimal.
569 */
570 buf = st->buf;
571 end = buf + st->size;
572 if(flags & XER_F_CANONICAL) {
573 char *scend = scratch + (sizeof(scratch) - 2);
574 for(; buf < end; buf++) {
575 if(p >= scend) {
576 _ASN_CALLBACK(scratch, p - scratch);
577 er.encoded += p - scratch;
578 p = scratch;
579 }
580 *p++ = h2c[(*buf >> 4) & 0x0F];
581 *p++ = h2c[*buf & 0x0F];
582 }
Lev Walkincc6a9102004-09-23 22:06:26 +0000583
584 _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */
585 er.encoded += p - scratch;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000586 } else {
587 for(i = 0; buf < end; buf++, i++) {
588 if(!(i % 16) && (i || st->size > 16)) {
589 _ASN_CALLBACK(scratch, p-scratch);
590 er.encoded += (p-scratch);
591 p = scratch;
592 _i_ASN_TEXT_INDENT(1, ilevel);
593 }
594 *p++ = h2c[(*buf >> 4) & 0x0F];
595 *p++ = h2c[*buf & 0x0F];
596 *p++ = 0x20;
597 }
Lev Walkincc6a9102004-09-23 22:06:26 +0000598 if(p - scratch) {
599 p--; /* Remove the tail space */
600 _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */
601 er.encoded += p - scratch;
602 if(st->size > 16)
603 _i_ASN_TEXT_INDENT(1, ilevel-1);
604 }
Lev Walkina9cc46e2004-09-22 16:06:28 +0000605 }
606
Lev Walkina9cc46e2004-09-22 16:06:28 +0000607 return er;
608}
609
610asn_enc_rval_t
611OCTET_STRING_encode_xer_ascii(asn1_TYPE_descriptor_t *td, void *sptr,
612 int ilevel, enum xer_encoder_flags_e flags,
613 asn_app_consume_bytes_f *cb, void *app_key) {
614 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
615 asn_enc_rval_t er;
616
617 (void)ilevel; /* Unused argument */
618 (void)flags; /* Unused argument */
619
620 if(!st || !st->buf)
621 _ASN_ENCODE_FAILED;
622
623 _ASN_CALLBACK(st->buf, st->size);
624 er.encoded = st->size;
625
626 return er;
627}
628
Lev Walkinf15320b2004-06-03 03:38:44 +0000629int
630OCTET_STRING_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
631 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin4d9528c2004-08-11 08:10:13 +0000632 static const char *h2c = "0123456789ABCDEF";
Lev Walkinc2346572004-08-11 09:07:36 +0000633 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000634 char scratch[16 * 3 + 4];
635 char *p = scratch;
636 uint8_t *buf;
637 uint8_t *end;
638 size_t i;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000639 int lvl;
Lev Walkinf15320b2004-06-03 03:38:44 +0000640
Lev Walkind9bd7752004-06-05 08:17:50 +0000641 (void)td; /* Unused argument */
642
Lev Walkinf15320b2004-06-03 03:38:44 +0000643 if(!st || !st->buf) return cb("<absent>", 8, app_key);
644
645 /*
646 * Dump the contents of the buffer in hexadecimal.
647 */
648 buf = st->buf;
649 end = buf + st->size;
650 for(i = 0; buf < end; buf++, i++) {
651 if(!(i % 16) && (i || st->size > 16)) {
652 if(cb(scratch, p - scratch, app_key)
653 || cb("\n", 1, app_key))
654 return -1;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000655 for(lvl = 0; lvl < ilevel; lvl++)
Lev Walkinf15320b2004-06-03 03:38:44 +0000656 cb(" ", 1, app_key);
657 p = scratch;
658 }
659 *p++ = h2c[(*buf >> 4) & 0x0F];
660 *p++ = h2c[*buf & 0x0F];
Lev Walkina9cc46e2004-09-22 16:06:28 +0000661 *p++ = 0x20;
Lev Walkinf15320b2004-06-03 03:38:44 +0000662 }
663
Lev Walkincc6a9102004-09-23 22:06:26 +0000664 if(p > scratch) {
665 p--; /* Remove the tail space */
666 if(cb(scratch, p - scratch, app_key))
667 return -1;
668 }
669
670 return 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000671}
672
673int
674OCTET_STRING_print_ascii(asn1_TYPE_descriptor_t *td, const void *sptr,
675 int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +0000676 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000677
Lev Walkind9bd7752004-06-05 08:17:50 +0000678 (void)td; /* Unused argument */
679 (void)ilevel; /* Unused argument */
680
Lev Walkinf15320b2004-06-03 03:38:44 +0000681 if(st && st->buf) {
682 return cb(st->buf, st->size, app_key);
683 } else {
684 return cb("<absent>", 8, app_key);
685 }
686}
687
688void
689OCTET_STRING_free(asn1_TYPE_descriptor_t *td, void *sptr, int contents_only) {
Lev Walkinc2346572004-08-11 09:07:36 +0000690 OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
691 struct _stack *stck = (struct _stack *)st->_ber_dec_ctx.ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000692
693 if(!td || !st)
694 return;
695
696 ASN_DEBUG("Freeing %s as OCTET STRING", td->name);
697
698 if(st->buf) {
699 FREEMEM(st->buf);
700 }
701
702 /*
703 * Remove decode-time stack.
704 */
705 if(stck) {
706 while(stck->tail) {
707 struct _stack_el *sel = stck->tail;
708 stck->tail = sel->prev;
709 FREEMEM(sel);
710 }
711 FREEMEM(stck);
712 }
713
714 if(!contents_only) {
715 FREEMEM(st);
716 }
717}
718
719/*
720 * Conversion routines.
721 */
722int
723OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) {
724 void *buf;
725
726 if(st == 0 || (str == 0 && len)) {
727 errno = EINVAL;
728 return -1;
729 }
730
731 /*
732 * Clear the OCTET STRING.
733 */
734 if(str == NULL) {
735 if(st->buf)
736 FREEMEM(st->buf);
737 st->size = 0;
738 return 0;
739 }
740
741 /* Determine the original string size, if not explicitly given */
742 if(len < 0)
743 len = strlen(str);
744
745 /* Allocate and fill the memory */
746 buf = MALLOC(len + 1);
747 if(buf == NULL) {
748 return -1;
749 } else {
Lev Walkinc2346572004-08-11 09:07:36 +0000750 st->buf = (uint8_t *)buf;
Lev Walkinf15320b2004-06-03 03:38:44 +0000751 st->size = len;
752 }
753
754 memcpy(buf, str, len);
755 st->buf[st->size] = '\0'; /* Couldn't use memcpy(len+1)! */
756
757 return 0;
758}
759
760OCTET_STRING_t *
761OCTET_STRING_new_fromBuf(const char *str, int len) {
762 OCTET_STRING_t *st;
763
Lev Walkinc2346572004-08-11 09:07:36 +0000764 (void *)st = CALLOC(1, sizeof(*st));
Lev Walkinf15320b2004-06-03 03:38:44 +0000765 if(st && str && OCTET_STRING_fromBuf(st, str, len)) {
766 free(st);
767 st = NULL;
768 }
769
770 return st;
771}
772