blob: 919350c5e94b96d7899c73e7b7434aaa5b2e54d3 [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));
vlmfa67ddc2004-06-03 03:38:44 +000063 if(tags == NULL) return -1; /* Impossible on i386 */
64 tags_count = sd->tags_count
65 + 1 /* EXPLICIT or IMPLICIT tag is given */
66 - ((tag_mode==-1)?sd->tags_impl_skip:0);
67 /* Copy tags over */
68 tags[0] = tag;
vlm796c1da2004-07-21 03:55:44 +000069 stag_offset = -1 + ((tag_mode==-1)?sd->tags_impl_skip:0);
vlmfa67ddc2004-06-03 03:38:44 +000070 for(i = 1; i < tags_count; i++)
vlm796c1da2004-07-21 03:55:44 +000071 tags[i] = sd->tags[i + stag_offset];
vlmfa67ddc2004-06-03 03:38:44 +000072 } else {
73 tags = sd->tags;
74 tags_count = sd->tags_count;
75 }
76
77 /* No tags to write */
78 if(tags_count == 0)
79 return 0;
80
81 lens = alloca(tags_count * sizeof(lens[0]));
82 if(lens == NULL) return -1;
83
84 /*
85 * Array of tags is initialized.
86 * Now, compute the size of the TLV pairs, from right to left.
87 */
88 overall_length = struct_length;
89 for(i = tags_count - 1; i >= 0; --i) {
90 lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0);
91 if(lens[i] == -1) return -1;
92 overall_length += lens[i];
93 lens[i] = overall_length - lens[i];
94 }
95
96 if(!cb) return overall_length - struct_length;
97
98 ASN_DEBUG("%s %s TL sequence (%d elements)",
99 cb?"Encoding":"Estimating", sd->name, tags_count);
100
101 /*
102 * Encode the TL sequence for real.
103 */
104 for(i = 0; i < tags_count; i++) {
105 ssize_t len;
106 int _constr;
107
108 /* If this one happens to be constructed, do it. */
109 if(i < (tags_count - 1) || sd->last_tag_form == 1)
110 _constr = 1;
111 else _constr = 0;
112
113 len = der_write_TL(tags[i], lens[i], cb, app_key, _constr);
114 if(len == -1) return -1;
115 }
116
117 return overall_length - struct_length;
118}
119
120static ssize_t
121der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len,
122 asn_app_consume_bytes_f *cb, void *app_key,
123 int constructed) {
124 uint8_t buf[32];
125 size_t size = 0;
126 int buf_size = cb?sizeof(buf):0;
127 ssize_t tmp;
128
129 /* Serialize tag (T from TLV) into possibly zero-length buffer */
130 tmp = der_tlv_tag_serialize(tag, buf, buf_size);
vlmb42843a2004-06-05 08:17:50 +0000131 if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1;
vlmfa67ddc2004-06-03 03:38:44 +0000132 size += tmp;
133
134 /* Serialize length (L from TLV) into possibly zero-length buffer */
135 tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0);
136 if(tmp == -1) return -1;
137 size += tmp;
138
139 if(size > sizeof(buf))
140 return -1;
141
142 /*
143 * If callback is specified, invoke it, and check its return value.
144 */
145 if(cb) {
146 if(constructed) *buf |= 0x20;
147 if(cb(buf, size, app_key) == -1) {
148 return -1;
149 }
150 }
151
152 return size;
153}