blob: 6a72d1a192c50b92e04637354de13d1ec0089559 [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 Walkin449f8322004-08-20 13:23:42 +000032 0, 0, /* No members */
Lev Walkind9bd7752004-06-05 08:17:50 +000033 0 /* No specifics */
Lev Walkinf15320b2004-06-03 03:38:44 +000034};
35
Lev Walkincc6a9102004-09-23 22:06:26 +000036#undef _CH_PHASE
37#undef NEXT_PHASE
38#undef PREV_PHASE
Lev Walkinf15320b2004-06-03 03:38:44 +000039#define _CH_PHASE(ctx, inc) do { \
40 if(ctx->phase == 0) \
41 ctx->step = 0; \
42 ctx->phase += inc; \
43 } while(0)
44#define NEXT_PHASE(ctx) _CH_PHASE(ctx, +1)
45#define PREV_PHASE(ctx) _CH_PHASE(ctx, -1)
46
Lev Walkincc6a9102004-09-23 22:06:26 +000047#undef ADVANCE
Lev Walkin4ce78ca2004-08-25 01:34:11 +000048#define ADVANCE(num_bytes) do { \
Lev Walkin3990ba62004-09-24 20:57:41 +000049 size_t num = (num_bytes); \
Lev Walkin4ce78ca2004-08-25 01:34:11 +000050 buf_ptr = ((char *)buf_ptr) + num; \
51 size -= num; \
52 consumed_myself += num; \
Lev Walkinf15320b2004-06-03 03:38:44 +000053 } while(0)
54
Lev Walkincc6a9102004-09-23 22:06:26 +000055#undef RETURN
Lev Walkinf15320b2004-06-03 03:38:44 +000056#define RETURN(_code) do { \
57 rval.code = _code; \
58 rval.consumed = consumed_myself;\
59 return rval; \
60 } while(0)
61
Lev Walkincc6a9102004-09-23 22:06:26 +000062#undef APPEND
Lev Walkind9bd7752004-06-05 08:17:50 +000063#define APPEND(bufptr, bufsize) do { \
Lev Walkin8d127872004-09-04 04:44:50 +000064 size_t _bs = (bufsize); \
Lev Walkind9bd7752004-06-05 08:17:50 +000065 size_t _ns = ctx->step; /* Allocated */ \
Lev Walkin8d127872004-09-04 04:44:50 +000066 if(_ns <= (size_t)(st->size + _bs)) { \
Lev Walkind9bd7752004-06-05 08:17:50 +000067 void *ptr; \
Lev Walkin188ed2c2004-09-13 08:31:01 +000068 /* Be nice and round to the memory allocator */ \
Lev Walkind9bd7752004-06-05 08:17:50 +000069 do { _ns = _ns ? _ns<<2 : 16; } \
Lev Walkin8d127872004-09-04 04:44:50 +000070 while(_ns <= (size_t)(st->size + _bs)); \
Lev Walkind9bd7752004-06-05 08:17:50 +000071 ptr = REALLOC(st->buf, _ns); \
72 if(ptr) { \
Lev Walkinc2346572004-08-11 09:07:36 +000073 st->buf = (uint8_t *)ptr; \
Lev Walkind9bd7752004-06-05 08:17:50 +000074 ctx->step = _ns; \
75 } else { \
76 RETURN(RC_FAIL); \
77 } \
78 } \
Lev Walkin8d127872004-09-04 04:44:50 +000079 memcpy(st->buf + st->size, bufptr, _bs); \
80 st->size += _bs; \
Lev Walkind9bd7752004-06-05 08:17:50 +000081 if(st->size < 0) \
82 /* Why even care?.. JIC */ \
83 RETURN(RC_FAIL); \
84 /* Convenient nul-termination */ \
85 st->buf[st->size] = '\0'; \
Lev Walkinf15320b2004-06-03 03:38:44 +000086 } while(0)
87
88/*
89 * The main reason why ASN.1 is still alive is that too much time and effort
90 * is necessary for learning it more or less adequately, thus creating a gut
91 * necessity to demonstrate that aquired skill everywhere afterwards.
92 * No, I am not going to explain what the following stuff is.
93 */
94struct _stack_el {
Lev Walkin3990ba62004-09-24 20:57:41 +000095 ber_tlv_len_t left; /* What's left to read (or -1) */
96 ber_tlv_len_t frame; /* What was planned to read (or -1) */
Lev Walkin188ed2c2004-09-13 08:31:01 +000097 int cont_level; /* Depth of subcontainment */
Lev Walkinf15320b2004-06-03 03:38:44 +000098 int want_nulls; /* Want null "end of content" octets? */
99 int bits_chopped; /* Flag in BIT STRING mode */
100 struct _stack_el *prev;
101 struct _stack_el *next;
102};
103struct _stack {
104 struct _stack_el *tail;
105 struct _stack_el *cur_ptr;
106};
107
108static struct _stack_el *
Lev Walkin3990ba62004-09-24 20:57:41 +0000109OS__add_stack_el(struct _stack *st) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000110 struct _stack_el *nel;
111
Lev Walkin188ed2c2004-09-13 08:31:01 +0000112 /*
113 * Reuse the old stack frame or allocate a new one.
114 */
Lev Walkinf15320b2004-06-03 03:38:44 +0000115 if(st->cur_ptr && st->cur_ptr->next) {
116 nel = st->cur_ptr->next;
Lev Walkinf15320b2004-06-03 03:38:44 +0000117 nel->bits_chopped = 0;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000118 /* Retain nel->cont_level, it's correct. */
Lev Walkinf15320b2004-06-03 03:38:44 +0000119 } else {
Lev Walkinc2346572004-08-11 09:07:36 +0000120 (void *)nel = CALLOC(1, sizeof(struct _stack_el));
Lev Walkinf15320b2004-06-03 03:38:44 +0000121 if(nel == NULL)
122 return NULL;
123
124 if(st->tail) {
Lev Walkin188ed2c2004-09-13 08:31:01 +0000125 /* Increase a subcontainment depth */
126 nel->cont_level = st->tail->cont_level + 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000127 st->tail->next = nel;
128 }
129 nel->prev = st->tail;
130 st->tail = nel;
131 }
132
133 st->cur_ptr = nel;
134
135 return nel;
136}
137
138static struct _stack *
139_new_stack() {
140 struct _stack *st;
Lev Walkinc2346572004-08-11 09:07:36 +0000141 (void *)st = CALLOC(1, sizeof(struct _stack));
Lev Walkinf15320b2004-06-03 03:38:44 +0000142 if(st == NULL)
143 return NULL;
144
Lev Walkinf15320b2004-06-03 03:38:44 +0000145 return st;
146}
147
148/*
149 * Decode OCTET STRING type.
150 */
151ber_dec_rval_t
152OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
153 void **os_structure, void *buf_ptr, size_t size, int tag_mode) {
Lev Walkinc2346572004-08-11 09:07:36 +0000154 OCTET_STRING_t *st = (OCTET_STRING_t *)*os_structure;
Lev Walkinf15320b2004-06-03 03:38:44 +0000155 ber_dec_rval_t rval;
156 ber_dec_ctx_t *ctx;
157 ssize_t consumed_myself = 0;
158 struct _stack *stck; /* A stack structure */
159 struct _stack_el *sel; /* Stack element */
160 int tlv_constr;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000161 enum type_type_e {
162 _TT_GENERIC = 0, /* Just a random OCTET STRING */
Lev Walkin8e8078a2004-09-26 13:10:40 +0000163 _TT_BIT_STRING = 1, /* BIT STRING type, a special case */
164 _TT_ANY = 2, /* ANY type, a special case too */
165 } type_type = (enum type_type_e)(int)td->specifics;
Lev Walkinf15320b2004-06-03 03:38:44 +0000166
Lev Walkincc6a9102004-09-23 22:06:26 +0000167 ASN_DEBUG("Decoding %s as %s (frame %ld)",
168 td->name,
169 (type_type == _TT_GENERIC) ? "OCTET STRING" : "OS-SpecialCase",
170 (long)size);
Lev Walkinf15320b2004-06-03 03:38:44 +0000171
172 /*
173 * Create the string if does not exist.
174 */
175 if(st == NULL) {
Lev Walkinc2346572004-08-11 09:07:36 +0000176 (void *)st = *os_structure = CALLOC(1, sizeof(*st));
Lev Walkinf15320b2004-06-03 03:38:44 +0000177 if(st == NULL)
178 RETURN(RC_FAIL);
179 }
180
181 /* Restore parsing context */
182 ctx = &st->_ber_dec_ctx;
183
184 switch(ctx->phase) {
185 case 0:
186 /*
187 * Check tags.
188 */
189 rval = ber_check_tags(td, ctx,
Lev Walkin8e8078a2004-09-26 13:10:40 +0000190 buf_ptr, size, tag_mode, -1,
Lev Walkinf15320b2004-06-03 03:38:44 +0000191 &ctx->left, &tlv_constr);
192 if(rval.code != RC_OK) {
193 RETURN(rval.code);
194 }
195
Lev Walkinf15320b2004-06-03 03:38:44 +0000196 if(tlv_constr) {
197 /*
198 * Complex operation, requires stack of expectations.
199 */
200 ctx->ptr = _new_stack();
201 if(ctx->ptr) {
Lev Walkinc2346572004-08-11 09:07:36 +0000202 (void *)stck = ctx->ptr;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000203 if(type_type == _TT_BIT_STRING) {
Lev Walkin8d127872004-09-04 04:44:50 +0000204 /* Number of meaningless tail bits */
Lev Walkinf15320b2004-06-03 03:38:44 +0000205 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);
Lev Walkin188ed2c2004-09-13 08:31:01 +0000215 if(type_type == _TT_ANY)
216 APPEND(buf_ptr, rval.consumed);
Lev Walkinf15320b2004-06-03 03:38:44 +0000217 ADVANCE(rval.consumed);
218 goto phase3;
219 }
220
Lev Walkinf15320b2004-06-03 03:38:44 +0000221 NEXT_PHASE(ctx);
222 /* Fall through */
223 case 1:
224 phase1:
225 /*
226 * Fill the stack with expectations.
227 */
Lev Walkinc2346572004-08-11 09:07:36 +0000228 (void *)stck = ctx->ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000229 sel = stck->cur_ptr;
230 do {
231 ber_tlv_tag_t tlv_tag;
232 ber_tlv_len_t tlv_len;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000233 ber_tlv_tag_t expected_tag;
Lev Walkinf15320b2004-06-03 03:38:44 +0000234 ssize_t tl, ll;
Lev Walkin8e8078a2004-09-26 13:10:40 +0000235 /* This one works even if (sel->left == -1) */
236 ssize_t Left = ((!sel||(size_t)sel->left >= size)
237 ?size:(size_t)sel->left);
Lev Walkinf15320b2004-06-03 03:38:44 +0000238
Lev Walkin3990ba62004-09-24 20:57:41 +0000239
240 ASN_DEBUG("fetch tag(size=%d,L=%d), %sstack, left=%d, want0=%d",
241 (int)size, Left, sel?"":"!",
Lev Walkin8d127872004-09-04 04:44:50 +0000242 sel?sel->left:0, sel?sel->want_nulls:0);
Lev Walkin3990ba62004-09-24 20:57:41 +0000243 tl = ber_fetch_tag(buf_ptr, Left, &tlv_tag);
Lev Walkinf15320b2004-06-03 03:38:44 +0000244 switch(tl) {
245 case -1: RETURN(RC_FAIL);
246 case 0: RETURN(RC_WMORE);
247 }
248
249 tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr);
250
251 ll = ber_fetch_length(tlv_constr,
Lev Walkin3990ba62004-09-24 20:57:41 +0000252 (char *)buf_ptr + tl, Left - tl, &tlv_len);
Lev Walkin8d127872004-09-04 04:44:50 +0000253 ASN_DEBUG("Got tag=%s, tc=%d, size=%d, tl=%d, len=%d, ll=%d, {%d, %d}",
254 ber_tlv_tag_string(tlv_tag), tlv_constr,
Lev Walkin3990ba62004-09-24 20:57:41 +0000255 (int)Left, tl, tlv_len, ll,
Lev Walkinf15320b2004-06-03 03:38:44 +0000256 ((uint8_t *)buf_ptr)[0],
257 ((uint8_t *)buf_ptr)[1]);
258 switch(ll) {
259 case -1: RETURN(RC_FAIL);
260 case 0: RETURN(RC_WMORE);
261 }
262
Lev Walkin8d127872004-09-04 04:44:50 +0000263 if(sel && sel->want_nulls
Lev Walkinf15320b2004-06-03 03:38:44 +0000264 && ((uint8_t *)buf_ptr)[0] == 0
265 && ((uint8_t *)buf_ptr)[1] == 0)
266 {
Lev Walkin8d127872004-09-04 04:44:50 +0000267 ADVANCE(2);
Lev Walkin188ed2c2004-09-13 08:31:01 +0000268 if(type_type == _TT_ANY) APPEND("\0\0", 2);
Lev Walkin8d127872004-09-04 04:44:50 +0000269
270 ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls);
271
Lev Walkinf15320b2004-06-03 03:38:44 +0000272 sel->want_nulls--;
273 if(sel->want_nulls == 0) {
274 /* Move to the next expectation */
275 sel = stck->cur_ptr = sel->prev;
Lev Walkin8d127872004-09-04 04:44:50 +0000276 if(sel == NULL)
Lev Walkinf15320b2004-06-03 03:38:44 +0000277 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000278 }
Lev Walkin8d127872004-09-04 04:44:50 +0000279
Lev Walkinf15320b2004-06-03 03:38:44 +0000280 if(sel->want_nulls) {
281 /*
282 * Simulate while(TRUE) for this loop.
283 * This is necessary to fetch the next
Lev Walkin8d127872004-09-04 04:44:50 +0000284 * expectation after current "end of content",
285 * for which tlv_constr is 0.
Lev Walkinf15320b2004-06-03 03:38:44 +0000286 */
Lev Walkinf15320b2004-06-03 03:38:44 +0000287 tlv_constr = 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000288 }
Lev Walkin8d127872004-09-04 04:44:50 +0000289
290 continue;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000291 }
292
293 /*
294 * Set up expected tags,
295 * depending on ASN.1 type being decoded.
296 */
297 switch(type_type) {
298 case _TT_BIT_STRING:
299 /* X.690: 8.6.4.1, NOTE 2 */
300 /* Fall through */
301 case _TT_GENERIC:
302 default:
303 if(sel) {
304 int level = sel->cont_level;
305 if(level < td->all_tags_count) {
306 expected_tag = td->all_tags[level];
307 break;
308 } else if(td->all_tags_count) {
309 expected_tag = td->all_tags
310 [td->all_tags_count - 1];
311 break;
312 }
313 /* else, Fall through */
314 }
315 /* Fall through */
316 case _TT_ANY:
317 expected_tag = tlv_tag;
318 break;
319 }
320
321
322 if(tlv_tag != expected_tag) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000323 char buf[2][32];
324 ber_tlv_tag_snprint(tlv_tag,
325 buf[0], sizeof(buf[0]));
326 ber_tlv_tag_snprint(td->tags[td->tags_count-1],
327 buf[1], sizeof(buf[1]));
328 ASN_DEBUG("Tag does not match expectation: %s != %s",
329 buf[0], buf[1]);
330 RETURN(RC_FAIL);
331 }
332
333 /*
Lev Walkin3990ba62004-09-24 20:57:41 +0000334 * Consult with the old expectation.
335 * Check that it knows what we are doing here, and how much.
336 */
337 if(sel && sel->left != -1) {
338 if(sel->left < (tl + ll))
339 RETURN(RC_FAIL);
340 sel->left -= (tl + ll);
341 if(sel->left < tlv_len)
342 RETURN(RC_FAIL);
343 }
344
345
346 /*
Lev Walkinf15320b2004-06-03 03:38:44 +0000347 * Append a new expectation.
348 */
Lev Walkin3990ba62004-09-24 20:57:41 +0000349 sel = OS__add_stack_el(stck);
Lev Walkinf15320b2004-06-03 03:38:44 +0000350 if(sel) {
351 sel->want_nulls = (tlv_len==-1);
Lev Walkin3990ba62004-09-24 20:57:41 +0000352 sel->frame = sel->left = tlv_len;
353 ASN_DEBUG("+EXPECT2 frame=%d wn=%d, clvl=%d",
354 sel->frame, sel->want_nulls, sel->cont_level);
Lev Walkinf15320b2004-06-03 03:38:44 +0000355 } else {
356 RETURN(RC_FAIL);
357 }
358
Lev Walkin188ed2c2004-09-13 08:31:01 +0000359 if(type_type == _TT_ANY) APPEND(buf_ptr, tl + ll);
Lev Walkinf15320b2004-06-03 03:38:44 +0000360 ADVANCE(tl+ll);
361 } while(tlv_constr);
362 if(sel == NULL) {
363 /* Finished operation, "phase out" */
Lev Walkin188ed2c2004-09-13 08:31:01 +0000364 ASN_DEBUG("Phase out");
Lev Walkinf15320b2004-06-03 03:38:44 +0000365 _CH_PHASE(ctx, +3);
366 break;
367 }
368
369 NEXT_PHASE(ctx);
370 /* Fall through */
371 case 2:
Lev Walkinc2346572004-08-11 09:07:36 +0000372 (void *)stck = ctx->ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000373 sel = stck->cur_ptr;
374 ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld",
375 (long)sel->left, (long)size);
376 {
377 ber_tlv_len_t len;
378
379 assert(sel->left >= 0);
380
Lev Walkinec1ffd42004-08-18 04:53:32 +0000381 len = ((ber_tlv_len_t)size < sel->left)
382 ? (ber_tlv_len_t)size : sel->left;
Lev Walkinf15320b2004-06-03 03:38:44 +0000383 if(len > 0) {
Lev Walkin188ed2c2004-09-13 08:31:01 +0000384 if(type_type == _TT_BIT_STRING
385 && sel->bits_chopped == 0) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000386 /*
387 * Finalize the previous chunk:
388 * strip down unused bits.
389 */
390 st->buf[st->size-1] &= 0xff << st->buf[0];
391
Lev Walkin4d9528c2004-08-11 08:10:13 +0000392 APPEND(((char *)buf_ptr+1), (len - 1));
Lev Walkinf15320b2004-06-03 03:38:44 +0000393 st->buf[0] = *(uint8_t *)buf_ptr;
394 sel->bits_chopped = 1;
395 } else {
396 APPEND(buf_ptr, len);
397 }
398 ADVANCE(len);
399 sel->left -= len;
400 }
401
Lev Walkin3990ba62004-09-24 20:57:41 +0000402 if(sel->left)
Lev Walkinf15320b2004-06-03 03:38:44 +0000403 RETURN(RC_WMORE);
Lev Walkin3990ba62004-09-24 20:57:41 +0000404
405 while(sel->left == 0) {
406 ASN_DEBUG("sel %p, l=%d, f=%d, %p->l=%d p->f=%d\n",
407 sel, sel->left, sel->frame,
408 sel->prev,
409 sel->prev?sel->prev->left:0,
410 sel->prev?sel->prev->frame:0
411 );
412 if(sel->prev) {
413 if(sel->prev->left != -1) {
414 if(sel->prev->left < sel->frame)
415 RETURN(RC_FAIL);
416 sel->prev->left -= sel->frame;
417 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000418 sel = stck->cur_ptr = sel->prev;
Lev Walkin3990ba62004-09-24 20:57:41 +0000419 if(sel->left) {
420 PREV_PHASE(ctx);
421 goto phase1;
422 }
423 } else {
424 break;
425 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000426 }
427 }
428 break;
429 case 3:
430 phase3:
431 /*
432 * Primitive form, no stack required.
433 */
Lev Walkind9bd7752004-06-05 08:17:50 +0000434 if(size < (size_t)ctx->left) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000435 APPEND(buf_ptr, size);
436 ctx->left -= size;
437 ADVANCE(size);
438 RETURN(RC_WMORE);
439 } else {
440 APPEND(buf_ptr, ctx->left);
441 ADVANCE(ctx->left);
442 ctx->left = 0;
443
444 NEXT_PHASE(ctx);
445 }
446 break;
447 }
448
449 /*
450 * BIT STRING-specific processing.
451 */
Lev Walkin188ed2c2004-09-13 08:31:01 +0000452 if(type_type == _TT_BIT_STRING && st->size >= 2) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000453 /* Finalize BIT STRING: zero out unused bits. */
454 st->buf[st->size-1] &= 0xff << st->buf[0];
455 }
456
457 ASN_DEBUG("Took %d bytes to encode %s: [%s]:%d",
Lev Walkin3990ba62004-09-24 20:57:41 +0000458 consumed_myself, td->name,
459 (type_type == _TT_GENERIC) ? (char *)st->buf : "", st->size);
Lev Walkinf15320b2004-06-03 03:38:44 +0000460
461 rval.code = RC_OK;
462 rval.consumed = consumed_myself;
463
464 return rval;
465}
466
467/*
468 * Encode OCTET STRING type using DER.
469 */
Lev Walkina9cc46e2004-09-22 16:06:28 +0000470asn_enc_rval_t
Lev Walkin1f670c12004-09-02 12:57:25 +0000471OCTET_STRING_encode_der(asn1_TYPE_descriptor_t *td, void *ptr,
Lev Walkinf15320b2004-06-03 03:38:44 +0000472 int tag_mode, ber_tlv_tag_t tag,
473 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkina9cc46e2004-09-22 16:06:28 +0000474 asn_enc_rval_t erval;
Lev Walkinc2346572004-08-11 09:07:36 +0000475 OCTET_STRING_t *st = (OCTET_STRING_t *)ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000476 int add_byte = 0;
Lev Walkin8e8078a2004-09-26 13:10:40 +0000477 int is_bit_str = (td->specifics == (void *)1);
478 int is_ANY_type = (td->specifics == (void *)2);
Lev Walkinf15320b2004-06-03 03:38:44 +0000479
480 ASN_DEBUG("%s %s as OCTET STRING",
Lev Walkin1f670c12004-09-02 12:57:25 +0000481 cb?"Estimating":"Encoding", td->name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000482
483 /*
484 * Canonicalize BIT STRING.
485 */
Lev Walkina737f3b2004-09-02 12:11:47 +0000486 if(is_bit_str && st->buf) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000487 switch(st->size) {
488 case 0: add_byte = 1; break;
489 case 1: st->buf[0] = 0; break;
490 default:
491 /* Finalize BIT STRING: zero out unused bits. */
492 st->buf[st->size-1] &= 0xff << st->buf[0];
493 }
494 }
495
Lev Walkina737f3b2004-09-02 12:11:47 +0000496 if(is_ANY_type) {
497 erval.encoded = 0;
498 } else {
Lev Walkin1f670c12004-09-02 12:57:25 +0000499 erval.encoded = der_write_tags(td, st->size + add_byte,
Lev Walkin8e8078a2004-09-26 13:10:40 +0000500 tag_mode, 0, tag, cb, app_key);
Lev Walkina737f3b2004-09-02 12:11:47 +0000501 if(erval.encoded == -1) {
Lev Walkin1f670c12004-09-02 12:57:25 +0000502 erval.failed_type = td;
Lev Walkina737f3b2004-09-02 12:11:47 +0000503 erval.structure_ptr = ptr;
504 return erval;
505 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000506 }
507
508 if(cb) {
509 uint8_t zero;
510 uint8_t *buf;
511 int size;
Lev Walkinf15320b2004-06-03 03:38:44 +0000512
513 /* BIT STRING-aware handling */
514 if(add_byte) {
515 zero = 0;
516 buf = &zero;
517 size = 1;
518 } else if(st->buf) {
519 buf = st->buf;
520 size = st->size;
521 } else {
522 assert(st->size == 0);
523 buf = 0; /* Not used */
524 size = 0;
525 }
526
527 if(size) {
Lev Walkin8e8078a2004-09-26 13:10:40 +0000528 if(cb(buf, size, app_key) < 0) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000529 erval.encoded = -1;
Lev Walkin1f670c12004-09-02 12:57:25 +0000530 erval.failed_type = td;
Lev Walkinf15320b2004-06-03 03:38:44 +0000531 erval.structure_ptr = ptr;
532 return erval;
533 }
534 }
535 }
536
537 erval.encoded += st->size + add_byte;
538
539 return erval;
540}
541
Lev Walkina9cc46e2004-09-22 16:06:28 +0000542asn_enc_rval_t
543OCTET_STRING_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
544 int ilevel, enum xer_encoder_flags_e flags,
545 asn_app_consume_bytes_f *cb, void *app_key) {
546 static const char *h2c = "0123456789ABCDEF";
547 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
548 asn_enc_rval_t er;
549 char scratch[16 * 3 + 4];
550 char *p = scratch;
551 uint8_t *buf;
552 uint8_t *end;
553 size_t i;
554
555 if(!st || !st->buf) {
556 er.encoded = -1;
557 er.failed_type = td;
558 er.structure_ptr = sptr;
559 return er;
560 }
561
562 er.encoded = 0;
563
564 /*
565 * Dump the contents of the buffer in hexadecimal.
566 */
567 buf = st->buf;
568 end = buf + st->size;
569 if(flags & XER_F_CANONICAL) {
570 char *scend = scratch + (sizeof(scratch) - 2);
571 for(; buf < end; buf++) {
572 if(p >= scend) {
573 _ASN_CALLBACK(scratch, p - scratch);
574 er.encoded += p - scratch;
575 p = scratch;
576 }
577 *p++ = h2c[(*buf >> 4) & 0x0F];
578 *p++ = h2c[*buf & 0x0F];
579 }
Lev Walkincc6a9102004-09-23 22:06:26 +0000580
581 _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */
582 er.encoded += p - scratch;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000583 } else {
584 for(i = 0; buf < end; buf++, i++) {
585 if(!(i % 16) && (i || st->size > 16)) {
586 _ASN_CALLBACK(scratch, p-scratch);
587 er.encoded += (p-scratch);
588 p = scratch;
589 _i_ASN_TEXT_INDENT(1, ilevel);
590 }
591 *p++ = h2c[(*buf >> 4) & 0x0F];
592 *p++ = h2c[*buf & 0x0F];
593 *p++ = 0x20;
594 }
Lev Walkincc6a9102004-09-23 22:06:26 +0000595 if(p - scratch) {
596 p--; /* Remove the tail space */
597 _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */
598 er.encoded += p - scratch;
599 if(st->size > 16)
600 _i_ASN_TEXT_INDENT(1, ilevel-1);
601 }
Lev Walkina9cc46e2004-09-22 16:06:28 +0000602 }
603
Lev Walkina9cc46e2004-09-22 16:06:28 +0000604 return er;
605}
606
607asn_enc_rval_t
608OCTET_STRING_encode_xer_ascii(asn1_TYPE_descriptor_t *td, void *sptr,
609 int ilevel, enum xer_encoder_flags_e flags,
610 asn_app_consume_bytes_f *cb, void *app_key) {
611 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
612 asn_enc_rval_t er;
613
614 (void)ilevel; /* Unused argument */
615 (void)flags; /* Unused argument */
616
617 if(!st || !st->buf)
618 _ASN_ENCODE_FAILED;
619
620 _ASN_CALLBACK(st->buf, st->size);
621 er.encoded = st->size;
622
623 return er;
624}
625
Lev Walkinf15320b2004-06-03 03:38:44 +0000626int
627OCTET_STRING_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
628 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin4d9528c2004-08-11 08:10:13 +0000629 static const char *h2c = "0123456789ABCDEF";
Lev Walkinc2346572004-08-11 09:07:36 +0000630 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000631 char scratch[16 * 3 + 4];
632 char *p = scratch;
633 uint8_t *buf;
634 uint8_t *end;
635 size_t i;
Lev Walkinf15320b2004-06-03 03:38:44 +0000636
Lev Walkind9bd7752004-06-05 08:17:50 +0000637 (void)td; /* Unused argument */
638
Lev Walkin8e8078a2004-09-26 13:10:40 +0000639 if(!st || !st->buf) return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000640
641 /*
642 * Dump the contents of the buffer in hexadecimal.
643 */
644 buf = st->buf;
645 end = buf + st->size;
646 for(i = 0; buf < end; buf++, i++) {
647 if(!(i % 16) && (i || st->size > 16)) {
Lev Walkin8e8078a2004-09-26 13:10:40 +0000648 if(cb(scratch, p - scratch, app_key) < 0)
Lev Walkinf15320b2004-06-03 03:38:44 +0000649 return -1;
Lev Walkin8e8078a2004-09-26 13:10:40 +0000650 _i_INDENT(1);
Lev Walkinf15320b2004-06-03 03:38:44 +0000651 p = scratch;
652 }
653 *p++ = h2c[(*buf >> 4) & 0x0F];
654 *p++ = h2c[*buf & 0x0F];
Lev Walkina9cc46e2004-09-22 16:06:28 +0000655 *p++ = 0x20;
Lev Walkinf15320b2004-06-03 03:38:44 +0000656 }
657
Lev Walkincc6a9102004-09-23 22:06:26 +0000658 if(p > scratch) {
659 p--; /* Remove the tail space */
Lev Walkin8e8078a2004-09-26 13:10:40 +0000660 if(cb(scratch, p - scratch, app_key) < 0)
Lev Walkincc6a9102004-09-23 22:06:26 +0000661 return -1;
662 }
663
664 return 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000665}
666
667int
668OCTET_STRING_print_ascii(asn1_TYPE_descriptor_t *td, const void *sptr,
669 int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +0000670 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000671
Lev Walkind9bd7752004-06-05 08:17:50 +0000672 (void)td; /* Unused argument */
673 (void)ilevel; /* Unused argument */
674
Lev Walkinf15320b2004-06-03 03:38:44 +0000675 if(st && st->buf) {
Lev Walkin8e8078a2004-09-26 13:10:40 +0000676 return (cb(st->buf, st->size, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000677 } else {
Lev Walkin8e8078a2004-09-26 13:10:40 +0000678 return (cb("<absent>", 8, app_key) < 0) ? -1 : 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000679 }
680}
681
682void
683OCTET_STRING_free(asn1_TYPE_descriptor_t *td, void *sptr, int contents_only) {
Lev Walkinc2346572004-08-11 09:07:36 +0000684 OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
685 struct _stack *stck = (struct _stack *)st->_ber_dec_ctx.ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000686
687 if(!td || !st)
688 return;
689
690 ASN_DEBUG("Freeing %s as OCTET STRING", td->name);
691
692 if(st->buf) {
693 FREEMEM(st->buf);
694 }
695
696 /*
697 * Remove decode-time stack.
698 */
699 if(stck) {
700 while(stck->tail) {
701 struct _stack_el *sel = stck->tail;
702 stck->tail = sel->prev;
703 FREEMEM(sel);
704 }
705 FREEMEM(stck);
706 }
707
708 if(!contents_only) {
709 FREEMEM(st);
710 }
711}
712
713/*
714 * Conversion routines.
715 */
716int
717OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) {
718 void *buf;
719
720 if(st == 0 || (str == 0 && len)) {
721 errno = EINVAL;
722 return -1;
723 }
724
725 /*
726 * Clear the OCTET STRING.
727 */
728 if(str == NULL) {
729 if(st->buf)
730 FREEMEM(st->buf);
731 st->size = 0;
732 return 0;
733 }
734
735 /* Determine the original string size, if not explicitly given */
736 if(len < 0)
737 len = strlen(str);
738
739 /* Allocate and fill the memory */
740 buf = MALLOC(len + 1);
741 if(buf == NULL) {
742 return -1;
743 } else {
Lev Walkinc2346572004-08-11 09:07:36 +0000744 st->buf = (uint8_t *)buf;
Lev Walkinf15320b2004-06-03 03:38:44 +0000745 st->size = len;
746 }
747
748 memcpy(buf, str, len);
749 st->buf[st->size] = '\0'; /* Couldn't use memcpy(len+1)! */
750
751 return 0;
752}
753
754OCTET_STRING_t *
755OCTET_STRING_new_fromBuf(const char *str, int len) {
756 OCTET_STRING_t *st;
757
Lev Walkinc2346572004-08-11 09:07:36 +0000758 (void *)st = CALLOC(1, sizeof(*st));
Lev Walkinf15320b2004-06-03 03:38:44 +0000759 if(st && str && OCTET_STRING_fromBuf(st, str, len)) {
760 free(st);
761 st = NULL;
762 }
763
764 return st;
765}
766