blob: 3523cb12e5052842ffaee14f974e36042c2a3022 [file] [log] [blame]
vlmfa67ddc2004-06-03 03:38:44 +00001/*-
2 * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
3 * Redistribution and modifications are permitted subject to BSD license.
4 */
vlm39ba4c42004-09-22 16:06:28 +00005#include <asn_internal.h>
vlmfa67ddc2004-06-03 03:38:44 +00006#include <assert.h>
vlm1ff928d2004-08-11 08:10:13 +00007#include <errno.h>
vlmfa67ddc2004-06-03 03:38:44 +00008
9static ssize_t der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
10 asn_app_consume_bytes_f *cb, void *app_key, int constructed);
11
12/*
13 * The DER encoder of any type.
14 */
vlm39ba4c42004-09-22 16:06:28 +000015asn_enc_rval_t
vlmef6355b2004-09-29 13:26:15 +000016der_encode(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr,
vlmfa67ddc2004-06-03 03:38:44 +000017 asn_app_consume_bytes_f *consume_bytes, void *app_key) {
18
19 ASN_DEBUG("DER encoder invoked for %s",
20 type_descriptor->name);
21
22 /*
23 * Invoke type-specific encoder.
24 */
25 return type_descriptor->der_encoder(type_descriptor,
26 struct_ptr, /* Pointer to the destination structure */
27 0, 0,
28 consume_bytes, app_key);
29}
30
31/*
32 * Write out leading TL[v] sequence according to the type definition.
33 */
34ssize_t
vlmef6355b2004-09-29 13:26:15 +000035der_write_tags(asn_TYPE_descriptor_t *sd,
vlmfa67ddc2004-06-03 03:38:44 +000036 size_t struct_length,
vlm6678cb12004-09-26 13:10:40 +000037 int tag_mode, int last_tag_form,
vlmfa67ddc2004-06-03 03:38:44 +000038 ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */
39 asn_app_consume_bytes_f *cb,
40 void *app_key) {
41 ber_tlv_tag_t *tags; /* Copy of tags stream */
42 int tags_count; /* Number of tags */
43 size_t overall_length;
44 ssize_t *lens;
45 int i;
46
vlm1308d2b2004-09-10 15:49:15 +000047 ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, tag=%s, mtc=%d)",
48 sd->name, tag_mode, sd->tags_count,
vlm796c1da2004-07-21 03:55:44 +000049 ber_tlv_tag_string(tag),
50 tag_mode
51 ?(sd->tags_count+1
vlm1308d2b2004-09-10 15:49:15 +000052 -((tag_mode == -1) && sd->tags_count))
vlm796c1da2004-07-21 03:55:44 +000053 :sd->tags_count
54 );
55
vlmfa67ddc2004-06-03 03:38:44 +000056 if(tag_mode) {
57 /*
58 * Instead of doing shaman dance like we do in ber_check_tags(),
59 * allocate a small array on the stack
60 * and initialize it appropriately.
61 */
vlm796c1da2004-07-21 03:55:44 +000062 int stag_offset;
vlmda674682004-08-11 09:07:36 +000063 tags = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t));
vlm7a6a60e2004-08-11 07:41:45 +000064 if(!tags) { /* Can fail on !x86 */
65 errno = ENOMEM;
66 return -1;
67 }
vlmfa67ddc2004-06-03 03:38:44 +000068 tags_count = sd->tags_count
69 + 1 /* EXPLICIT or IMPLICIT tag is given */
vlm1308d2b2004-09-10 15:49:15 +000070 - ((tag_mode == -1) && sd->tags_count);
vlmfa67ddc2004-06-03 03:38:44 +000071 /* Copy tags over */
72 tags[0] = tag;
vlm1308d2b2004-09-10 15:49:15 +000073 stag_offset = -1 + ((tag_mode == -1) && sd->tags_count);
vlmfa67ddc2004-06-03 03:38:44 +000074 for(i = 1; i < tags_count; i++)
vlm796c1da2004-07-21 03:55:44 +000075 tags[i] = sd->tags[i + stag_offset];
vlmfa67ddc2004-06-03 03:38:44 +000076 } else {
77 tags = sd->tags;
78 tags_count = sd->tags_count;
79 }
80
81 /* No tags to write */
82 if(tags_count == 0)
83 return 0;
84
vlmda674682004-08-11 09:07:36 +000085 lens = (ssize_t *)alloca(tags_count * sizeof(lens[0]));
vlm7a6a60e2004-08-11 07:41:45 +000086 if(!lens) {
87 errno = ENOMEM;
88 return -1;
89 }
vlmfa67ddc2004-06-03 03:38:44 +000090
91 /*
92 * Array of tags is initialized.
93 * Now, compute the size of the TLV pairs, from right to left.
94 */
95 overall_length = struct_length;
96 for(i = tags_count - 1; i >= 0; --i) {
97 lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0);
98 if(lens[i] == -1) return -1;
99 overall_length += lens[i];
100 lens[i] = overall_length - lens[i];
101 }
102
103 if(!cb) return overall_length - struct_length;
104
105 ASN_DEBUG("%s %s TL sequence (%d elements)",
106 cb?"Encoding":"Estimating", sd->name, tags_count);
107
108 /*
109 * Encode the TL sequence for real.
110 */
111 for(i = 0; i < tags_count; i++) {
112 ssize_t len;
113 int _constr;
114
vlm6678cb12004-09-26 13:10:40 +0000115 /* Check if this tag happens to be constructed */
116 _constr = (last_tag_form || i < (tags_count - 1));
vlmfa67ddc2004-06-03 03:38:44 +0000117
118 len = der_write_TL(tags[i], lens[i], cb, app_key, _constr);
119 if(len == -1) return -1;
120 }
121
122 return overall_length - struct_length;
123}
124
125static ssize_t
126der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
127 asn_app_consume_bytes_f *cb, void *app_key,
128 int constructed) {
129 uint8_t buf[32];
130 size_t size = 0;
131 int buf_size = cb?sizeof(buf):0;
132 ssize_t tmp;
133
134 /* Serialize tag (T from TLV) into possibly zero-length buffer */
vlm044e8d42004-08-19 13:27:34 +0000135 tmp = ber_tlv_tag_serialize(tag, buf, buf_size);
vlmb42843a2004-06-05 08:17:50 +0000136 if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1;
vlmfa67ddc2004-06-03 03:38:44 +0000137 size += tmp;
138
139 /* Serialize length (L from TLV) into possibly zero-length buffer */
140 tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0);
141 if(tmp == -1) return -1;
142 size += tmp;
143
144 if(size > sizeof(buf))
145 return -1;
146
147 /*
148 * If callback is specified, invoke it, and check its return value.
149 */
150 if(cb) {
151 if(constructed) *buf |= 0x20;
vlm6678cb12004-09-26 13:10:40 +0000152 if(cb(buf, size, app_key) < 0)
vlmfa67ddc2004-06-03 03:38:44 +0000153 return -1;
vlmfa67ddc2004-06-03 03:38:44 +0000154 }
155
156 return size;
157}