blob: 62ad757ee9be42c537922e56f3c27a1b4e8c980f [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/*
vlmcd05d3d2004-11-16 09:46:00 +000032 * Argument type and callback necessary for der_encode_to_buffer().
33 */
34typedef struct enc_to_buf_arg {
35 void *buffer;
36 size_t left;
37} enc_to_buf_arg;
38static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) {
vlmd3c80792004-12-15 23:23:53 +000039 enc_to_buf_arg *arg = (enc_to_buf_arg *)key;
vlmcd05d3d2004-11-16 09:46:00 +000040
41 if(arg->left < size)
42 return -1; /* Data exceeds the available buffer size */
43
44 memcpy(arg->buffer, buffer, size);
45 arg->buffer = ((char *)arg->buffer) + size;
46 arg->left -= size;
47
48 return 0;
49}
50
51/*
52 * A variant of the der_encode() which encodes the data into the provided buffer
53 */
54asn_enc_rval_t
55der_encode_to_buffer(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr,
56 void *buffer, size_t *buffer_size) {
57 enc_to_buf_arg arg;
58 asn_enc_rval_t ec;
59
60 arg.buffer = buffer;
61 arg.left = *buffer_size;
62
63 ec = type_descriptor->der_encoder(type_descriptor,
64 struct_ptr, /* Pointer to the destination structure */
65 0, 0, encode_to_buffer_cb, &arg);
66 if(ec.encoded != -1) {
vlmd3c80792004-12-15 23:23:53 +000067 assert(ec.encoded == (ssize_t)(*buffer_size - arg.left));
vlmcd05d3d2004-11-16 09:46:00 +000068 /* Return the encoded contents size */
69 *buffer_size = ec.encoded;
70 }
71 return ec;
72}
73
74
75/*
vlmfa67ddc2004-06-03 03:38:44 +000076 * Write out leading TL[v] sequence according to the type definition.
77 */
78ssize_t
vlmef6355b2004-09-29 13:26:15 +000079der_write_tags(asn_TYPE_descriptor_t *sd,
vlmfa67ddc2004-06-03 03:38:44 +000080 size_t struct_length,
vlm6678cb12004-09-26 13:10:40 +000081 int tag_mode, int last_tag_form,
vlmfa67ddc2004-06-03 03:38:44 +000082 ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */
83 asn_app_consume_bytes_f *cb,
84 void *app_key) {
85 ber_tlv_tag_t *tags; /* Copy of tags stream */
86 int tags_count; /* Number of tags */
87 size_t overall_length;
88 ssize_t *lens;
89 int i;
90
vlm1308d2b2004-09-10 15:49:15 +000091 ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, tag=%s, mtc=%d)",
92 sd->name, tag_mode, sd->tags_count,
vlm796c1da2004-07-21 03:55:44 +000093 ber_tlv_tag_string(tag),
94 tag_mode
95 ?(sd->tags_count+1
vlm1308d2b2004-09-10 15:49:15 +000096 -((tag_mode == -1) && sd->tags_count))
vlm796c1da2004-07-21 03:55:44 +000097 :sd->tags_count
98 );
99
vlmfa67ddc2004-06-03 03:38:44 +0000100 if(tag_mode) {
101 /*
102 * Instead of doing shaman dance like we do in ber_check_tags(),
103 * allocate a small array on the stack
104 * and initialize it appropriately.
105 */
vlm796c1da2004-07-21 03:55:44 +0000106 int stag_offset;
vlmda674682004-08-11 09:07:36 +0000107 tags = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t));
vlm7a6a60e2004-08-11 07:41:45 +0000108 if(!tags) { /* Can fail on !x86 */
109 errno = ENOMEM;
110 return -1;
111 }
vlmfa67ddc2004-06-03 03:38:44 +0000112 tags_count = sd->tags_count
113 + 1 /* EXPLICIT or IMPLICIT tag is given */
vlm1308d2b2004-09-10 15:49:15 +0000114 - ((tag_mode == -1) && sd->tags_count);
vlmfa67ddc2004-06-03 03:38:44 +0000115 /* Copy tags over */
116 tags[0] = tag;
vlm1308d2b2004-09-10 15:49:15 +0000117 stag_offset = -1 + ((tag_mode == -1) && sd->tags_count);
vlmfa67ddc2004-06-03 03:38:44 +0000118 for(i = 1; i < tags_count; i++)
vlm796c1da2004-07-21 03:55:44 +0000119 tags[i] = sd->tags[i + stag_offset];
vlmfa67ddc2004-06-03 03:38:44 +0000120 } else {
121 tags = sd->tags;
122 tags_count = sd->tags_count;
123 }
124
125 /* No tags to write */
126 if(tags_count == 0)
127 return 0;
128
vlmda674682004-08-11 09:07:36 +0000129 lens = (ssize_t *)alloca(tags_count * sizeof(lens[0]));
vlm7a6a60e2004-08-11 07:41:45 +0000130 if(!lens) {
131 errno = ENOMEM;
132 return -1;
133 }
vlmfa67ddc2004-06-03 03:38:44 +0000134
135 /*
136 * Array of tags is initialized.
137 * Now, compute the size of the TLV pairs, from right to left.
138 */
139 overall_length = struct_length;
140 for(i = tags_count - 1; i >= 0; --i) {
141 lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0);
142 if(lens[i] == -1) return -1;
143 overall_length += lens[i];
144 lens[i] = overall_length - lens[i];
145 }
146
147 if(!cb) return overall_length - struct_length;
148
149 ASN_DEBUG("%s %s TL sequence (%d elements)",
150 cb?"Encoding":"Estimating", sd->name, tags_count);
151
152 /*
153 * Encode the TL sequence for real.
154 */
155 for(i = 0; i < tags_count; i++) {
156 ssize_t len;
157 int _constr;
158
vlm6678cb12004-09-26 13:10:40 +0000159 /* Check if this tag happens to be constructed */
160 _constr = (last_tag_form || i < (tags_count - 1));
vlmfa67ddc2004-06-03 03:38:44 +0000161
162 len = der_write_TL(tags[i], lens[i], cb, app_key, _constr);
163 if(len == -1) return -1;
164 }
165
166 return overall_length - struct_length;
167}
168
169static ssize_t
170der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
171 asn_app_consume_bytes_f *cb, void *app_key,
172 int constructed) {
173 uint8_t buf[32];
174 size_t size = 0;
175 int buf_size = cb?sizeof(buf):0;
176 ssize_t tmp;
177
178 /* Serialize tag (T from TLV) into possibly zero-length buffer */
vlm044e8d42004-08-19 13:27:34 +0000179 tmp = ber_tlv_tag_serialize(tag, buf, buf_size);
vlmb42843a2004-06-05 08:17:50 +0000180 if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1;
vlmfa67ddc2004-06-03 03:38:44 +0000181 size += tmp;
182
183 /* Serialize length (L from TLV) into possibly zero-length buffer */
184 tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0);
185 if(tmp == -1) return -1;
186 size += tmp;
187
188 if(size > sizeof(buf))
189 return -1;
190
191 /*
192 * If callback is specified, invoke it, and check its return value.
193 */
194 if(cb) {
195 if(constructed) *buf |= 0x20;
vlm6678cb12004-09-26 13:10:40 +0000196 if(cb(buf, size, app_key) < 0)
vlmfa67ddc2004-06-03 03:38:44 +0000197 return -1;
vlmfa67ddc2004-06-03 03:38:44 +0000198 }
199
200 return size;
201}