blob: dc547a2cbcff895973ef99e8a474e4e5b3b29b44 [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 */
5#include <constr_TYPE.h>
6#include <assert.h>
7
8static ssize_t der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
9 asn_app_consume_bytes_f *cb, void *app_key, int constructed);
10
11/*
12 * The DER encoder of any type.
13 */
14der_enc_rval_t
15der_encode(asn1_TYPE_descriptor_t *type_descriptor, void *struct_ptr,
16 asn_app_consume_bytes_f *consume_bytes, void *app_key) {
17
18 ASN_DEBUG("DER encoder invoked for %s",
19 type_descriptor->name);
20
21 /*
22 * Invoke type-specific encoder.
23 */
24 return type_descriptor->der_encoder(type_descriptor,
25 struct_ptr, /* Pointer to the destination structure */
26 0, 0,
27 consume_bytes, app_key);
28}
29
30/*
31 * Write out leading TL[v] sequence according to the type definition.
32 */
33ssize_t
34der_write_tags(asn1_TYPE_descriptor_t *sd,
35 size_t struct_length,
36 int tag_mode,
37 ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */
38 asn_app_consume_bytes_f *cb,
39 void *app_key) {
40 ber_tlv_tag_t *tags; /* Copy of tags stream */
41 int tags_count; /* Number of tags */
42 size_t overall_length;
43 ssize_t *lens;
44 int i;
45
vlm796c1da2004-07-21 03:55:44 +000046 ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, iskip=%d, tag=%s, mtc=%d)",
47 sd->name, tag_mode, sd->tags_count, sd->tags_impl_skip,
48 ber_tlv_tag_string(tag),
49 tag_mode
50 ?(sd->tags_count+1
51 -((tag_mode==-1)?sd->tags_impl_skip:0))
52 :sd->tags_count
53 );
54
vlmfa67ddc2004-06-03 03:38:44 +000055 if(tag_mode) {
56 /*
57 * Instead of doing shaman dance like we do in ber_check_tags(),
58 * allocate a small array on the stack
59 * and initialize it appropriately.
60 */
vlm796c1da2004-07-21 03:55:44 +000061 int stag_offset;
62 tags = alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t));
vlm7a6a60e2004-08-11 07:41:45 +000063 if(!tags) { /* Can fail on !x86 */
64 errno = ENOMEM;
65 return -1;
66 }
vlmfa67ddc2004-06-03 03:38:44 +000067 tags_count = sd->tags_count
68 + 1 /* EXPLICIT or IMPLICIT tag is given */
69 - ((tag_mode==-1)?sd->tags_impl_skip:0);
70 /* Copy tags over */
71 tags[0] = tag;
vlm796c1da2004-07-21 03:55:44 +000072 stag_offset = -1 + ((tag_mode==-1)?sd->tags_impl_skip:0);
vlmfa67ddc2004-06-03 03:38:44 +000073 for(i = 1; i < tags_count; i++)
vlm796c1da2004-07-21 03:55:44 +000074 tags[i] = sd->tags[i + stag_offset];
vlmfa67ddc2004-06-03 03:38:44 +000075 } else {
76 tags = sd->tags;
77 tags_count = sd->tags_count;
78 }
79
80 /* No tags to write */
81 if(tags_count == 0)
82 return 0;
83
84 lens = alloca(tags_count * sizeof(lens[0]));
vlm7a6a60e2004-08-11 07:41:45 +000085 if(!lens) {
86 errno = ENOMEM;
87 return -1;
88 }
vlmfa67ddc2004-06-03 03:38:44 +000089
90 /*
91 * Array of tags is initialized.
92 * Now, compute the size of the TLV pairs, from right to left.
93 */
94 overall_length = struct_length;
95 for(i = tags_count - 1; i >= 0; --i) {
96 lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0);
97 if(lens[i] == -1) return -1;
98 overall_length += lens[i];
99 lens[i] = overall_length - lens[i];
100 }
101
102 if(!cb) return overall_length - struct_length;
103
104 ASN_DEBUG("%s %s TL sequence (%d elements)",
105 cb?"Encoding":"Estimating", sd->name, tags_count);
106
107 /*
108 * Encode the TL sequence for real.
109 */
110 for(i = 0; i < tags_count; i++) {
111 ssize_t len;
112 int _constr;
113
114 /* If this one happens to be constructed, do it. */
115 if(i < (tags_count - 1) || sd->last_tag_form == 1)
116 _constr = 1;
117 else _constr = 0;
118
119 len = der_write_TL(tags[i], lens[i], cb, app_key, _constr);
120 if(len == -1) return -1;
121 }
122
123 return overall_length - struct_length;
124}
125
126static ssize_t
127der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
128 asn_app_consume_bytes_f *cb, void *app_key,
129 int constructed) {
130 uint8_t buf[32];
131 size_t size = 0;
132 int buf_size = cb?sizeof(buf):0;
133 ssize_t tmp;
134
135 /* Serialize tag (T from TLV) into possibly zero-length buffer */
136 tmp = der_tlv_tag_serialize(tag, buf, buf_size);
vlmb42843a2004-06-05 08:17:50 +0000137 if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1;
vlmfa67ddc2004-06-03 03:38:44 +0000138 size += tmp;
139
140 /* Serialize length (L from TLV) into possibly zero-length buffer */
141 tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0);
142 if(tmp == -1) return -1;
143 size += tmp;
144
145 if(size > sizeof(buf))
146 return -1;
147
148 /*
149 * If callback is specified, invoke it, and check its return value.
150 */
151 if(cb) {
152 if(constructed) *buf |= 0x20;
153 if(cb(buf, size, app_key) == -1) {
154 return -1;
155 }
156 }
157
158 return size;
159}