blob: ddd0bf86b8f92204cf393dc11b2ff1c94546ed08 [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 */
5#include <constr_TYPE.h>
6#include <assert.h>
Lev Walkin4d9528c2004-08-11 08:10:13 +00007#include <errno.h>
Lev Walkinf15320b2004-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 */
15der_enc_rval_t
16der_encode(asn1_TYPE_descriptor_t *type_descriptor, void *struct_ptr,
17 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
35der_write_tags(asn1_TYPE_descriptor_t *sd,
36 size_t struct_length,
37 int tag_mode,
38 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
Lev Walkinf7a6c6d2004-07-21 03:55:44 +000047 ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, iskip=%d, tag=%s, mtc=%d)",
48 sd->name, tag_mode, sd->tags_count, sd->tags_impl_skip,
49 ber_tlv_tag_string(tag),
50 tag_mode
51 ?(sd->tags_count+1
52 -((tag_mode==-1)?sd->tags_impl_skip:0))
53 :sd->tags_count
54 );
55
Lev Walkinf15320b2004-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 */
Lev Walkinf7a6c6d2004-07-21 03:55:44 +000062 int stag_offset;
Lev Walkinc2346572004-08-11 09:07:36 +000063 tags = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t));
Lev Walkin7e0d2cb2004-08-11 07:41:45 +000064 if(!tags) { /* Can fail on !x86 */
65 errno = ENOMEM;
66 return -1;
67 }
Lev Walkinf15320b2004-06-03 03:38:44 +000068 tags_count = sd->tags_count
69 + 1 /* EXPLICIT or IMPLICIT tag is given */
70 - ((tag_mode==-1)?sd->tags_impl_skip:0);
71 /* Copy tags over */
72 tags[0] = tag;
Lev Walkinf7a6c6d2004-07-21 03:55:44 +000073 stag_offset = -1 + ((tag_mode==-1)?sd->tags_impl_skip:0);
Lev Walkinf15320b2004-06-03 03:38:44 +000074 for(i = 1; i < tags_count; i++)
Lev Walkinf7a6c6d2004-07-21 03:55:44 +000075 tags[i] = sd->tags[i + stag_offset];
Lev Walkinf15320b2004-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
Lev Walkinc2346572004-08-11 09:07:36 +000085 lens = (ssize_t *)alloca(tags_count * sizeof(lens[0]));
Lev Walkin7e0d2cb2004-08-11 07:41:45 +000086 if(!lens) {
87 errno = ENOMEM;
88 return -1;
89 }
Lev Walkinf15320b2004-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
115 /* If this one happens to be constructed, do it. */
116 if(i < (tags_count - 1) || sd->last_tag_form == 1)
117 _constr = 1;
118 else _constr = 0;
119
120 len = der_write_TL(tags[i], lens[i], cb, app_key, _constr);
121 if(len == -1) return -1;
122 }
123
124 return overall_length - struct_length;
125}
126
127static ssize_t
128der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
129 asn_app_consume_bytes_f *cb, void *app_key,
130 int constructed) {
131 uint8_t buf[32];
132 size_t size = 0;
133 int buf_size = cb?sizeof(buf):0;
134 ssize_t tmp;
135
136 /* Serialize tag (T from TLV) into possibly zero-length buffer */
137 tmp = der_tlv_tag_serialize(tag, buf, buf_size);
Lev Walkind9bd7752004-06-05 08:17:50 +0000138 if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1;
Lev Walkinf15320b2004-06-03 03:38:44 +0000139 size += tmp;
140
141 /* Serialize length (L from TLV) into possibly zero-length buffer */
142 tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0);
143 if(tmp == -1) return -1;
144 size += tmp;
145
146 if(size > sizeof(buf))
147 return -1;
148
149 /*
150 * If callback is specified, invoke it, and check its return value.
151 */
152 if(cb) {
153 if(constructed) *buf |= 0x20;
154 if(cb(buf, size, app_key) == -1) {
155 return -1;
156 }
157 }
158
159 return size;
160}