blob: 72a33ebcdc1f53774383d5c057957bac56a3da04 [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
46 if(tag_mode) {
47 /*
48 * Instead of doing shaman dance like we do in ber_check_tags(),
49 * allocate a small array on the stack
50 * and initialize it appropriately.
51 */
52 tags = alloca((sd->tags_count + (tag_mode?1:0))
53 * sizeof(ber_tlv_tag_t));
54 if(tags == NULL) return -1; /* Impossible on i386 */
55 tags_count = sd->tags_count
56 + 1 /* EXPLICIT or IMPLICIT tag is given */
57 - ((tag_mode==-1)?sd->tags_impl_skip:0);
58 /* Copy tags over */
59 tags[0] = tag;
60 for(i = 1; i < tags_count; i++)
61 tags[i] = sd->tags[i - 1 + sd->tags_impl_skip];
62 } else {
63 tags = sd->tags;
64 tags_count = sd->tags_count;
65 }
66
67 /* No tags to write */
68 if(tags_count == 0)
69 return 0;
70
71 lens = alloca(tags_count * sizeof(lens[0]));
72 if(lens == NULL) return -1;
73
74 /*
75 * Array of tags is initialized.
76 * Now, compute the size of the TLV pairs, from right to left.
77 */
78 overall_length = struct_length;
79 for(i = tags_count - 1; i >= 0; --i) {
80 lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0);
81 if(lens[i] == -1) return -1;
82 overall_length += lens[i];
83 lens[i] = overall_length - lens[i];
84 }
85
86 if(!cb) return overall_length - struct_length;
87
88 ASN_DEBUG("%s %s TL sequence (%d elements)",
89 cb?"Encoding":"Estimating", sd->name, tags_count);
90
91 /*
92 * Encode the TL sequence for real.
93 */
94 for(i = 0; i < tags_count; i++) {
95 ssize_t len;
96 int _constr;
97
98 /* If this one happens to be constructed, do it. */
99 if(i < (tags_count - 1) || sd->last_tag_form == 1)
100 _constr = 1;
101 else _constr = 0;
102
103 len = der_write_TL(tags[i], lens[i], cb, app_key, _constr);
104 if(len == -1) return -1;
105 }
106
107 return overall_length - struct_length;
108}
109
110static ssize_t
111der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
112 asn_app_consume_bytes_f *cb, void *app_key,
113 int constructed) {
114 uint8_t buf[32];
115 size_t size = 0;
116 int buf_size = cb?sizeof(buf):0;
117 ssize_t tmp;
118
119 /* Serialize tag (T from TLV) into possibly zero-length buffer */
120 tmp = der_tlv_tag_serialize(tag, buf, buf_size);
vlmb42843a2004-06-05 08:17:50 +0000121 if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1;
vlmfa67ddc2004-06-03 03:38:44 +0000122 size += tmp;
123
124 /* Serialize length (L from TLV) into possibly zero-length buffer */
125 tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0);
126 if(tmp == -1) return -1;
127 size += tmp;
128
129 if(size > sizeof(buf))
130 return -1;
131
132 /*
133 * If callback is specified, invoke it, and check its return value.
134 */
135 if(cb) {
136 if(constructed) *buf |= 0x20;
137 if(cb(buf, size, app_key) == -1) {
138 return -1;
139 }
140 }
141
142 return size;
143}