blob: 8906c6f8198a525b292b270d061517309db99914 [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 { \
50 size_t num = num_bytes; \
51 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 {
96 ber_tlv_len_t left; /* What's left to read */
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 *
109_add_stack_el(struct _stack *st) {
110 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;
117 nel->left = 0;
118 nel->want_nulls = 0;
119 nel->bits_chopped = 0;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000120 /* Retain nel->cont_level, it's correct. */
Lev Walkinf15320b2004-06-03 03:38:44 +0000121 } else {
Lev Walkinc2346572004-08-11 09:07:36 +0000122 (void *)nel = CALLOC(1, sizeof(struct _stack_el));
Lev Walkinf15320b2004-06-03 03:38:44 +0000123 if(nel == NULL)
124 return NULL;
125
126 if(st->tail) {
Lev Walkin188ed2c2004-09-13 08:31:01 +0000127 /* Increase a subcontainment depth */
128 nel->cont_level = st->tail->cont_level + 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000129 st->tail->next = nel;
130 }
131 nel->prev = st->tail;
132 st->tail = nel;
133 }
134
135 st->cur_ptr = nel;
136
137 return nel;
138}
139
140static struct _stack *
141_new_stack() {
142 struct _stack *st;
Lev Walkinc2346572004-08-11 09:07:36 +0000143 (void *)st = CALLOC(1, sizeof(struct _stack));
Lev Walkinf15320b2004-06-03 03:38:44 +0000144 if(st == NULL)
145 return NULL;
146
Lev Walkinf15320b2004-06-03 03:38:44 +0000147 return st;
148}
149
150/*
151 * Decode OCTET STRING type.
152 */
153ber_dec_rval_t
154OCTET_STRING_decode_ber(asn1_TYPE_descriptor_t *td,
155 void **os_structure, void *buf_ptr, size_t size, int tag_mode) {
Lev Walkinc2346572004-08-11 09:07:36 +0000156 OCTET_STRING_t *st = (OCTET_STRING_t *)*os_structure;
Lev Walkinf15320b2004-06-03 03:38:44 +0000157 ber_dec_rval_t rval;
158 ber_dec_ctx_t *ctx;
159 ssize_t consumed_myself = 0;
160 struct _stack *stck; /* A stack structure */
161 struct _stack_el *sel; /* Stack element */
162 int tlv_constr;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000163 enum type_type_e {
164 _TT_GENERIC = 0, /* Just a random OCTET STRING */
165 _TT_BIT_STRING = -1, /* BIT STRING type, a special case */
166 _TT_ANY = 1, /* ANY type, a special case too */
167 } type_type
168 = (enum type_type_e)(int)td->specifics; /* An ugly hack */
Lev Walkinf15320b2004-06-03 03:38:44 +0000169
Lev Walkincc6a9102004-09-23 22:06:26 +0000170 ASN_DEBUG("Decoding %s as %s (frame %ld)",
171 td->name,
172 (type_type == _TT_GENERIC) ? "OCTET STRING" : "OS-SpecialCase",
173 (long)size);
Lev Walkinf15320b2004-06-03 03:38:44 +0000174
175 /*
176 * Create the string if does not exist.
177 */
178 if(st == NULL) {
Lev Walkinc2346572004-08-11 09:07:36 +0000179 (void *)st = *os_structure = CALLOC(1, sizeof(*st));
Lev Walkinf15320b2004-06-03 03:38:44 +0000180 if(st == NULL)
181 RETURN(RC_FAIL);
182 }
183
184 /* Restore parsing context */
185 ctx = &st->_ber_dec_ctx;
186
187 switch(ctx->phase) {
188 case 0:
189 /*
190 * Check tags.
191 */
192 rval = ber_check_tags(td, ctx,
193 buf_ptr, size, tag_mode,
194 &ctx->left, &tlv_constr);
195 if(rval.code != RC_OK) {
196 RETURN(rval.code);
197 }
198
Lev Walkincc6a9102004-09-23 22:06:26 +0000199 ASN_DEBUG("OS length is %d bytes, form %d (consumed %d==0)",
200 (int)ctx->left, tlv_constr, rval.consumed);
Lev Walkinf15320b2004-06-03 03:38:44 +0000201
202 if(tlv_constr) {
203 /*
204 * Complex operation, requires stack of expectations.
205 */
206 ctx->ptr = _new_stack();
207 if(ctx->ptr) {
Lev Walkinc2346572004-08-11 09:07:36 +0000208 (void *)stck = ctx->ptr;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000209 if(type_type == _TT_BIT_STRING) {
Lev Walkin8d127872004-09-04 04:44:50 +0000210 /* Number of meaningless tail bits */
Lev Walkinf15320b2004-06-03 03:38:44 +0000211 APPEND("\0", 1);
212 }
213 } else {
214 RETURN(RC_FAIL);
215 }
216 } else {
217 /*
218 * Jump into stackless primitive decoding.
219 */
220 _CH_PHASE(ctx, 3);
Lev Walkin188ed2c2004-09-13 08:31:01 +0000221 if(type_type == _TT_ANY)
222 APPEND(buf_ptr, rval.consumed);
Lev Walkinf15320b2004-06-03 03:38:44 +0000223 ADVANCE(rval.consumed);
224 goto phase3;
225 }
226
Lev Walkinf15320b2004-06-03 03:38:44 +0000227 NEXT_PHASE(ctx);
228 /* Fall through */
229 case 1:
230 phase1:
231 /*
232 * Fill the stack with expectations.
233 */
Lev Walkinc2346572004-08-11 09:07:36 +0000234 (void *)stck = ctx->ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000235 sel = stck->cur_ptr;
236 do {
237 ber_tlv_tag_t tlv_tag;
238 ber_tlv_len_t tlv_len;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000239 ber_tlv_tag_t expected_tag;
Lev Walkinf15320b2004-06-03 03:38:44 +0000240 ssize_t tl, ll;
241
Lev Walkin8d127872004-09-04 04:44:50 +0000242 ASN_DEBUG("fetch tag(size=%d), %sstack, left=%d, want0=%d",
243 (int)size, sel?"":"!",
244 sel?sel->left:0, sel?sel->want_nulls:0);
Lev Walkinf15320b2004-06-03 03:38:44 +0000245 tl = ber_fetch_tag(buf_ptr, size, &tlv_tag);
246 switch(tl) {
247 case -1: RETURN(RC_FAIL);
248 case 0: RETURN(RC_WMORE);
249 }
250
251 tlv_constr = BER_TLV_CONSTRUCTED(buf_ptr);
252
253 ll = ber_fetch_length(tlv_constr,
Lev Walkin4d9528c2004-08-11 08:10:13 +0000254 (char *)buf_ptr + tl, size - tl, &tlv_len);
Lev Walkin8d127872004-09-04 04:44:50 +0000255 ASN_DEBUG("Got tag=%s, tc=%d, size=%d, tl=%d, len=%d, ll=%d, {%d, %d}",
256 ber_tlv_tag_string(tlv_tag), tlv_constr,
257 (int)size, tl, tlv_len, ll,
Lev Walkinf15320b2004-06-03 03:38:44 +0000258 ((uint8_t *)buf_ptr)[0],
259 ((uint8_t *)buf_ptr)[1]);
260 switch(ll) {
261 case -1: RETURN(RC_FAIL);
262 case 0: RETURN(RC_WMORE);
263 }
264
Lev Walkin8d127872004-09-04 04:44:50 +0000265 if(sel && sel->want_nulls
Lev Walkinf15320b2004-06-03 03:38:44 +0000266 && ((uint8_t *)buf_ptr)[0] == 0
267 && ((uint8_t *)buf_ptr)[1] == 0)
268 {
Lev Walkin8d127872004-09-04 04:44:50 +0000269 ADVANCE(2);
Lev Walkin188ed2c2004-09-13 08:31:01 +0000270 if(type_type == _TT_ANY) APPEND("\0\0", 2);
Lev Walkin8d127872004-09-04 04:44:50 +0000271
272 ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls);
273
Lev Walkinf15320b2004-06-03 03:38:44 +0000274 sel->want_nulls--;
275 if(sel->want_nulls == 0) {
276 /* Move to the next expectation */
277 sel = stck->cur_ptr = sel->prev;
Lev Walkin8d127872004-09-04 04:44:50 +0000278 if(sel == NULL)
Lev Walkinf15320b2004-06-03 03:38:44 +0000279 break;
Lev Walkinf15320b2004-06-03 03:38:44 +0000280 }
Lev Walkin8d127872004-09-04 04:44:50 +0000281
Lev Walkinf15320b2004-06-03 03:38:44 +0000282 if(sel->want_nulls) {
283 /*
284 * Simulate while(TRUE) for this loop.
285 * This is necessary to fetch the next
Lev Walkin8d127872004-09-04 04:44:50 +0000286 * expectation after current "end of content",
287 * for which tlv_constr is 0.
Lev Walkinf15320b2004-06-03 03:38:44 +0000288 */
Lev Walkinf15320b2004-06-03 03:38:44 +0000289 tlv_constr = 1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000290 }
Lev Walkin8d127872004-09-04 04:44:50 +0000291
292 continue;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000293 }
294
295 /*
296 * Set up expected tags,
297 * depending on ASN.1 type being decoded.
298 */
299 switch(type_type) {
300 case _TT_BIT_STRING:
301 /* X.690: 8.6.4.1, NOTE 2 */
302 /* Fall through */
303 case _TT_GENERIC:
304 default:
305 if(sel) {
306 int level = sel->cont_level;
307 if(level < td->all_tags_count) {
308 expected_tag = td->all_tags[level];
309 break;
310 } else if(td->all_tags_count) {
311 expected_tag = td->all_tags
312 [td->all_tags_count - 1];
313 break;
314 }
315 /* else, Fall through */
316 }
317 /* Fall through */
318 case _TT_ANY:
319 expected_tag = tlv_tag;
320 break;
321 }
322
323
324 if(tlv_tag != expected_tag) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000325 char buf[2][32];
326 ber_tlv_tag_snprint(tlv_tag,
327 buf[0], sizeof(buf[0]));
328 ber_tlv_tag_snprint(td->tags[td->tags_count-1],
329 buf[1], sizeof(buf[1]));
330 ASN_DEBUG("Tag does not match expectation: %s != %s",
331 buf[0], buf[1]);
332 RETURN(RC_FAIL);
333 }
334
335 /*
336 * Append a new expectation.
337 */
338 sel = _add_stack_el(stck);
339 if(sel) {
340 sel->want_nulls = (tlv_len==-1);
341 sel->left = tlv_len;
Lev Walkin188ed2c2004-09-13 08:31:01 +0000342 ASN_DEBUG("+EXPECT2 left=%d wn=%d, clvl=%d",
343 sel->left, sel->want_nulls, sel->cont_level);
Lev Walkinf15320b2004-06-03 03:38:44 +0000344 } else {
345 RETURN(RC_FAIL);
346 }
347
Lev Walkin188ed2c2004-09-13 08:31:01 +0000348 if(type_type == _TT_ANY) APPEND(buf_ptr, tl + ll);
Lev Walkinf15320b2004-06-03 03:38:44 +0000349 ADVANCE(tl+ll);
350 } while(tlv_constr);
351 if(sel == NULL) {
352 /* Finished operation, "phase out" */
Lev Walkin188ed2c2004-09-13 08:31:01 +0000353 ASN_DEBUG("Phase out");
Lev Walkinf15320b2004-06-03 03:38:44 +0000354 _CH_PHASE(ctx, +3);
355 break;
356 }
357
358 NEXT_PHASE(ctx);
359 /* Fall through */
360 case 2:
Lev Walkinc2346572004-08-11 09:07:36 +0000361 (void *)stck = ctx->ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000362 sel = stck->cur_ptr;
363 ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld",
364 (long)sel->left, (long)size);
365 {
366 ber_tlv_len_t len;
367
368 assert(sel->left >= 0);
369
Lev Walkinec1ffd42004-08-18 04:53:32 +0000370 len = ((ber_tlv_len_t)size < sel->left)
371 ? (ber_tlv_len_t)size : sel->left;
Lev Walkinf15320b2004-06-03 03:38:44 +0000372 if(len > 0) {
Lev Walkin188ed2c2004-09-13 08:31:01 +0000373 if(type_type == _TT_BIT_STRING
374 && sel->bits_chopped == 0) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000375 /*
376 * Finalize the previous chunk:
377 * strip down unused bits.
378 */
379 st->buf[st->size-1] &= 0xff << st->buf[0];
380
Lev Walkin4d9528c2004-08-11 08:10:13 +0000381 APPEND(((char *)buf_ptr+1), (len - 1));
Lev Walkinf15320b2004-06-03 03:38:44 +0000382 st->buf[0] = *(uint8_t *)buf_ptr;
383 sel->bits_chopped = 1;
384 } else {
385 APPEND(buf_ptr, len);
386 }
387 ADVANCE(len);
388 sel->left -= len;
389 }
390
391 if(sel->left) {
392 RETURN(RC_WMORE);
393 } else {
394 sel->left = 0;
395 if(sel->prev)
396 sel = stck->cur_ptr = sel->prev;
397 PREV_PHASE(ctx);
398 goto phase1;
399 }
400 }
401 break;
402 case 3:
403 phase3:
404 /*
405 * Primitive form, no stack required.
406 */
Lev Walkind9bd7752004-06-05 08:17:50 +0000407 if(size < (size_t)ctx->left) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000408 APPEND(buf_ptr, size);
409 ctx->left -= size;
410 ADVANCE(size);
411 RETURN(RC_WMORE);
412 } else {
413 APPEND(buf_ptr, ctx->left);
414 ADVANCE(ctx->left);
415 ctx->left = 0;
416
417 NEXT_PHASE(ctx);
418 }
419 break;
420 }
421
422 /*
423 * BIT STRING-specific processing.
424 */
Lev Walkin188ed2c2004-09-13 08:31:01 +0000425 if(type_type == _TT_BIT_STRING && st->size >= 2) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000426 /* Finalize BIT STRING: zero out unused bits. */
427 st->buf[st->size-1] &= 0xff << st->buf[0];
428 }
429
430 ASN_DEBUG("Took %d bytes to encode %s: [%s]:%d",
431 consumed_myself, td->name, st->buf, st->size);
432
433 rval.code = RC_OK;
434 rval.consumed = consumed_myself;
435
436 return rval;
437}
438
439/*
440 * Encode OCTET STRING type using DER.
441 */
Lev Walkina9cc46e2004-09-22 16:06:28 +0000442asn_enc_rval_t
Lev Walkin1f670c12004-09-02 12:57:25 +0000443OCTET_STRING_encode_der(asn1_TYPE_descriptor_t *td, void *ptr,
Lev Walkinf15320b2004-06-03 03:38:44 +0000444 int tag_mode, ber_tlv_tag_t tag,
445 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkina9cc46e2004-09-22 16:06:28 +0000446 asn_enc_rval_t erval;
Lev Walkinc2346572004-08-11 09:07:36 +0000447 OCTET_STRING_t *st = (OCTET_STRING_t *)ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000448 int add_byte = 0;
Lev Walkina737f3b2004-09-02 12:11:47 +0000449 int is_bit_str = (td->specifics == (void *)-1);
Lev Walkin1f670c12004-09-02 12:57:25 +0000450 int is_ANY_type = (td->specifics == (void *)1);
Lev Walkinf15320b2004-06-03 03:38:44 +0000451
452 ASN_DEBUG("%s %s as OCTET STRING",
Lev Walkin1f670c12004-09-02 12:57:25 +0000453 cb?"Estimating":"Encoding", td->name);
Lev Walkinf15320b2004-06-03 03:38:44 +0000454
455 /*
456 * Canonicalize BIT STRING.
457 */
Lev Walkina737f3b2004-09-02 12:11:47 +0000458 if(is_bit_str && st->buf) {
Lev Walkinf15320b2004-06-03 03:38:44 +0000459 switch(st->size) {
460 case 0: add_byte = 1; break;
461 case 1: st->buf[0] = 0; break;
462 default:
463 /* Finalize BIT STRING: zero out unused bits. */
464 st->buf[st->size-1] &= 0xff << st->buf[0];
465 }
466 }
467
Lev Walkina737f3b2004-09-02 12:11:47 +0000468 if(is_ANY_type) {
469 erval.encoded = 0;
470 } else {
Lev Walkin1f670c12004-09-02 12:57:25 +0000471 erval.encoded = der_write_tags(td, st->size + add_byte,
Lev Walkina737f3b2004-09-02 12:11:47 +0000472 tag_mode, tag, cb, app_key);
473 if(erval.encoded == -1) {
Lev Walkin1f670c12004-09-02 12:57:25 +0000474 erval.failed_type = td;
Lev Walkina737f3b2004-09-02 12:11:47 +0000475 erval.structure_ptr = ptr;
476 return erval;
477 }
Lev Walkinf15320b2004-06-03 03:38:44 +0000478 }
479
480 if(cb) {
481 uint8_t zero;
482 uint8_t *buf;
483 int size;
484 ssize_t ret;
485
486 /* BIT STRING-aware handling */
487 if(add_byte) {
488 zero = 0;
489 buf = &zero;
490 size = 1;
491 } else if(st->buf) {
492 buf = st->buf;
493 size = st->size;
494 } else {
495 assert(st->size == 0);
496 buf = 0; /* Not used */
497 size = 0;
498 }
499
500 if(size) {
501 ret = cb(buf, size, app_key);
502 if(ret == -1) {
503 erval.encoded = -1;
Lev Walkin1f670c12004-09-02 12:57:25 +0000504 erval.failed_type = td;
Lev Walkinf15320b2004-06-03 03:38:44 +0000505 erval.structure_ptr = ptr;
506 return erval;
507 }
508 }
509 }
510
511 erval.encoded += st->size + add_byte;
512
513 return erval;
514}
515
Lev Walkina9cc46e2004-09-22 16:06:28 +0000516asn_enc_rval_t
517OCTET_STRING_encode_xer(asn1_TYPE_descriptor_t *td, void *sptr,
518 int ilevel, enum xer_encoder_flags_e flags,
519 asn_app_consume_bytes_f *cb, void *app_key) {
520 static const char *h2c = "0123456789ABCDEF";
521 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
522 asn_enc_rval_t er;
523 char scratch[16 * 3 + 4];
524 char *p = scratch;
525 uint8_t *buf;
526 uint8_t *end;
527 size_t i;
528
529 if(!st || !st->buf) {
530 er.encoded = -1;
531 er.failed_type = td;
532 er.structure_ptr = sptr;
533 return er;
534 }
535
536 er.encoded = 0;
537
538 /*
539 * Dump the contents of the buffer in hexadecimal.
540 */
541 buf = st->buf;
542 end = buf + st->size;
543 if(flags & XER_F_CANONICAL) {
544 char *scend = scratch + (sizeof(scratch) - 2);
545 for(; buf < end; buf++) {
546 if(p >= scend) {
547 _ASN_CALLBACK(scratch, p - scratch);
548 er.encoded += p - scratch;
549 p = scratch;
550 }
551 *p++ = h2c[(*buf >> 4) & 0x0F];
552 *p++ = h2c[*buf & 0x0F];
553 }
Lev Walkincc6a9102004-09-23 22:06:26 +0000554
555 _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */
556 er.encoded += p - scratch;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000557 } else {
558 for(i = 0; buf < end; buf++, i++) {
559 if(!(i % 16) && (i || st->size > 16)) {
560 _ASN_CALLBACK(scratch, p-scratch);
561 er.encoded += (p-scratch);
562 p = scratch;
563 _i_ASN_TEXT_INDENT(1, ilevel);
564 }
565 *p++ = h2c[(*buf >> 4) & 0x0F];
566 *p++ = h2c[*buf & 0x0F];
567 *p++ = 0x20;
568 }
Lev Walkincc6a9102004-09-23 22:06:26 +0000569 if(p - scratch) {
570 p--; /* Remove the tail space */
571 _ASN_CALLBACK(scratch, p-scratch); /* Dump the rest */
572 er.encoded += p - scratch;
573 if(st->size > 16)
574 _i_ASN_TEXT_INDENT(1, ilevel-1);
575 }
Lev Walkina9cc46e2004-09-22 16:06:28 +0000576 }
577
Lev Walkina9cc46e2004-09-22 16:06:28 +0000578 return er;
579}
580
581asn_enc_rval_t
582OCTET_STRING_encode_xer_ascii(asn1_TYPE_descriptor_t *td, void *sptr,
583 int ilevel, enum xer_encoder_flags_e flags,
584 asn_app_consume_bytes_f *cb, void *app_key) {
585 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
586 asn_enc_rval_t er;
587
588 (void)ilevel; /* Unused argument */
589 (void)flags; /* Unused argument */
590
591 if(!st || !st->buf)
592 _ASN_ENCODE_FAILED;
593
594 _ASN_CALLBACK(st->buf, st->size);
595 er.encoded = st->size;
596
597 return er;
598}
599
Lev Walkinf15320b2004-06-03 03:38:44 +0000600int
601OCTET_STRING_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel,
602 asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkin4d9528c2004-08-11 08:10:13 +0000603 static const char *h2c = "0123456789ABCDEF";
Lev Walkinc2346572004-08-11 09:07:36 +0000604 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000605 char scratch[16 * 3 + 4];
606 char *p = scratch;
607 uint8_t *buf;
608 uint8_t *end;
609 size_t i;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000610 int lvl;
Lev Walkinf15320b2004-06-03 03:38:44 +0000611
Lev Walkind9bd7752004-06-05 08:17:50 +0000612 (void)td; /* Unused argument */
613
Lev Walkinf15320b2004-06-03 03:38:44 +0000614 if(!st || !st->buf) return cb("<absent>", 8, app_key);
615
616 /*
617 * Dump the contents of the buffer in hexadecimal.
618 */
619 buf = st->buf;
620 end = buf + st->size;
621 for(i = 0; buf < end; buf++, i++) {
622 if(!(i % 16) && (i || st->size > 16)) {
623 if(cb(scratch, p - scratch, app_key)
624 || cb("\n", 1, app_key))
625 return -1;
Lev Walkina9cc46e2004-09-22 16:06:28 +0000626 for(lvl = 0; lvl < ilevel; lvl++)
Lev Walkinf15320b2004-06-03 03:38:44 +0000627 cb(" ", 1, app_key);
628 p = scratch;
629 }
630 *p++ = h2c[(*buf >> 4) & 0x0F];
631 *p++ = h2c[*buf & 0x0F];
Lev Walkina9cc46e2004-09-22 16:06:28 +0000632 *p++ = 0x20;
Lev Walkinf15320b2004-06-03 03:38:44 +0000633 }
634
Lev Walkincc6a9102004-09-23 22:06:26 +0000635 if(p > scratch) {
636 p--; /* Remove the tail space */
637 if(cb(scratch, p - scratch, app_key))
638 return -1;
639 }
640
641 return 0;
Lev Walkinf15320b2004-06-03 03:38:44 +0000642}
643
644int
645OCTET_STRING_print_ascii(asn1_TYPE_descriptor_t *td, const void *sptr,
646 int ilevel, asn_app_consume_bytes_f *cb, void *app_key) {
Lev Walkinc2346572004-08-11 09:07:36 +0000647 const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000648
Lev Walkind9bd7752004-06-05 08:17:50 +0000649 (void)td; /* Unused argument */
650 (void)ilevel; /* Unused argument */
651
Lev Walkinf15320b2004-06-03 03:38:44 +0000652 if(st && st->buf) {
653 return cb(st->buf, st->size, app_key);
654 } else {
655 return cb("<absent>", 8, app_key);
656 }
657}
658
659void
660OCTET_STRING_free(asn1_TYPE_descriptor_t *td, void *sptr, int contents_only) {
Lev Walkinc2346572004-08-11 09:07:36 +0000661 OCTET_STRING_t *st = (OCTET_STRING_t *)sptr;
662 struct _stack *stck = (struct _stack *)st->_ber_dec_ctx.ptr;
Lev Walkinf15320b2004-06-03 03:38:44 +0000663
664 if(!td || !st)
665 return;
666
667 ASN_DEBUG("Freeing %s as OCTET STRING", td->name);
668
669 if(st->buf) {
670 FREEMEM(st->buf);
671 }
672
673 /*
674 * Remove decode-time stack.
675 */
676 if(stck) {
677 while(stck->tail) {
678 struct _stack_el *sel = stck->tail;
679 stck->tail = sel->prev;
680 FREEMEM(sel);
681 }
682 FREEMEM(stck);
683 }
684
685 if(!contents_only) {
686 FREEMEM(st);
687 }
688}
689
690/*
691 * Conversion routines.
692 */
693int
694OCTET_STRING_fromBuf(OCTET_STRING_t *st, const char *str, int len) {
695 void *buf;
696
697 if(st == 0 || (str == 0 && len)) {
698 errno = EINVAL;
699 return -1;
700 }
701
702 /*
703 * Clear the OCTET STRING.
704 */
705 if(str == NULL) {
706 if(st->buf)
707 FREEMEM(st->buf);
708 st->size = 0;
709 return 0;
710 }
711
712 /* Determine the original string size, if not explicitly given */
713 if(len < 0)
714 len = strlen(str);
715
716 /* Allocate and fill the memory */
717 buf = MALLOC(len + 1);
718 if(buf == NULL) {
719 return -1;
720 } else {
Lev Walkinc2346572004-08-11 09:07:36 +0000721 st->buf = (uint8_t *)buf;
Lev Walkinf15320b2004-06-03 03:38:44 +0000722 st->size = len;
723 }
724
725 memcpy(buf, str, len);
726 st->buf[st->size] = '\0'; /* Couldn't use memcpy(len+1)! */
727
728 return 0;
729}
730
731OCTET_STRING_t *
732OCTET_STRING_new_fromBuf(const char *str, int len) {
733 OCTET_STRING_t *st;
734
Lev Walkinc2346572004-08-11 09:07:36 +0000735 (void *)st = CALLOC(1, sizeof(*st));
Lev Walkinf15320b2004-06-03 03:38:44 +0000736 if(st && str && OCTET_STRING_fromBuf(st, str, len)) {
737 free(st);
738 st = NULL;
739 }
740
741 return st;
742}
743