blob: 4f1936f8e248dbecc46b3f714ee7da15d1da4868 [file] [log] [blame]
Lev Walkinf15320b2004-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 */
Lev Walkina9cc46e2004-09-22 16:06:28 +00005#include <asn_internal.h>
Lev Walkinf15320b2004-06-03 03:38:44 +00006#include <constr_TYPE.h>
7#include <assert.h>
Lev Walkin4d9528c2004-08-11 08:10:13 +00008#include <errno.h>
Lev Walkinf15320b2004-06-03 03:38:44 +00009
10static ssize_t der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
11 asn_app_consume_bytes_f *cb, void *app_key, int constructed);
12
13/*
14 * The DER encoder of any type.
15 */
Lev Walkina9cc46e2004-09-22 16:06:28 +000016asn_enc_rval_t
Lev Walkinf15320b2004-06-03 03:38:44 +000017der_encode(asn1_TYPE_descriptor_t *type_descriptor, void *struct_ptr,
18 asn_app_consume_bytes_f *consume_bytes, void *app_key) {
19
20 ASN_DEBUG("DER encoder invoked for %s",
21 type_descriptor->name);
22
23 /*
24 * Invoke type-specific encoder.
25 */
26 return type_descriptor->der_encoder(type_descriptor,
27 struct_ptr, /* Pointer to the destination structure */
28 0, 0,
29 consume_bytes, app_key);
30}
31
32/*
33 * Write out leading TL[v] sequence according to the type definition.
34 */
35ssize_t
36der_write_tags(asn1_TYPE_descriptor_t *sd,
37 size_t struct_length,
38 int tag_mode,
39 ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */
40 asn_app_consume_bytes_f *cb,
41 void *app_key) {
42 ber_tlv_tag_t *tags; /* Copy of tags stream */
43 int tags_count; /* Number of tags */
44 size_t overall_length;
45 ssize_t *lens;
46 int i;
47
Lev Walkin906654e2004-09-10 15:49:15 +000048 ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, tag=%s, mtc=%d)",
49 sd->name, tag_mode, sd->tags_count,
Lev Walkinf7a6c6d2004-07-21 03:55:44 +000050 ber_tlv_tag_string(tag),
51 tag_mode
52 ?(sd->tags_count+1
Lev Walkin906654e2004-09-10 15:49:15 +000053 -((tag_mode == -1) && sd->tags_count))
Lev Walkinf7a6c6d2004-07-21 03:55:44 +000054 :sd->tags_count
55 );
56
Lev Walkinf15320b2004-06-03 03:38:44 +000057 if(tag_mode) {
58 /*
59 * Instead of doing shaman dance like we do in ber_check_tags(),
60 * allocate a small array on the stack
61 * and initialize it appropriately.
62 */
Lev Walkinf7a6c6d2004-07-21 03:55:44 +000063 int stag_offset;
Lev Walkinc2346572004-08-11 09:07:36 +000064 tags = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t));
Lev Walkin7e0d2cb2004-08-11 07:41:45 +000065 if(!tags) { /* Can fail on !x86 */
66 errno = ENOMEM;
67 return -1;
68 }
Lev Walkinf15320b2004-06-03 03:38:44 +000069 tags_count = sd->tags_count
70 + 1 /* EXPLICIT or IMPLICIT tag is given */
Lev Walkin906654e2004-09-10 15:49:15 +000071 - ((tag_mode == -1) && sd->tags_count);
Lev Walkinf15320b2004-06-03 03:38:44 +000072 /* Copy tags over */
73 tags[0] = tag;
Lev Walkin906654e2004-09-10 15:49:15 +000074 stag_offset = -1 + ((tag_mode == -1) && sd->tags_count);
Lev Walkinf15320b2004-06-03 03:38:44 +000075 for(i = 1; i < tags_count; i++)
Lev Walkinf7a6c6d2004-07-21 03:55:44 +000076 tags[i] = sd->tags[i + stag_offset];
Lev Walkinf15320b2004-06-03 03:38:44 +000077 } else {
78 tags = sd->tags;
79 tags_count = sd->tags_count;
80 }
81
82 /* No tags to write */
83 if(tags_count == 0)
84 return 0;
85
Lev Walkinc2346572004-08-11 09:07:36 +000086 lens = (ssize_t *)alloca(tags_count * sizeof(lens[0]));
Lev Walkin7e0d2cb2004-08-11 07:41:45 +000087 if(!lens) {
88 errno = ENOMEM;
89 return -1;
90 }
Lev Walkinf15320b2004-06-03 03:38:44 +000091
92 /*
93 * Array of tags is initialized.
94 * Now, compute the size of the TLV pairs, from right to left.
95 */
96 overall_length = struct_length;
97 for(i = tags_count - 1; i >= 0; --i) {
98 lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0);
99 if(lens[i] == -1) return -1;
100 overall_length += lens[i];
101 lens[i] = overall_length - lens[i];
102 }
103
104 if(!cb) return overall_length - struct_length;
105
106 ASN_DEBUG("%s %s TL sequence (%d elements)",
107 cb?"Encoding":"Estimating", sd->name, tags_count);
108
109 /*
110 * Encode the TL sequence for real.
111 */
112 for(i = 0; i < tags_count; i++) {
113 ssize_t len;
114 int _constr;
115
116 /* If this one happens to be constructed, do it. */
117 if(i < (tags_count - 1) || sd->last_tag_form == 1)
118 _constr = 1;
119 else _constr = 0;
120
121 len = der_write_TL(tags[i], lens[i], cb, app_key, _constr);
122 if(len == -1) return -1;
123 }
124
125 return overall_length - struct_length;
126}
127
128static ssize_t
129der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
130 asn_app_consume_bytes_f *cb, void *app_key,
131 int constructed) {
132 uint8_t buf[32];
133 size_t size = 0;
134 int buf_size = cb?sizeof(buf):0;
135 ssize_t tmp;
136
137 /* Serialize tag (T from TLV) into possibly zero-length buffer */
Lev Walkin2ca95432004-08-19 13:27:34 +0000138 tmp = ber_tlv_tag_serialize(tag, buf, buf_size);
Lev Walkind9bd7752004-06-05 08:17:50 +0000139 if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000140 size += tmp;
141
142 /* Serialize length (L from TLV) into possibly zero-length buffer */
143 tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0);
144 if(tmp == -1) return -1;
145 size += tmp;
146
147 if(size > sizeof(buf))
148 return -1;
149
150 /*
151 * If callback is specified, invoke it, and check its return value.
152 */
153 if(cb) {
154 if(constructed) *buf |= 0x20;
155 if(cb(buf, size, app_key) == -1) {
156 return -1;
157 }
158 }
159
160 return size;
161}