ITS
der_encoder.c
Go to the documentation of this file.
1 /*-
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 <asn_internal.h>
6 #include <errno.h>
7 
8 static 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  */
15 der_encode(asn_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  * Argument type and callback necessary for der_encode_to_buffer().
32  */
33 typedef struct enc_to_buf_arg {
34  void *buffer;
35  size_t left;
37 static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) {
38  enc_to_buf_arg *arg = (enc_to_buf_arg *)key;
39 
40  if(arg->left < size)
41  return -1; /* Data exceeds the available buffer size */
42 
43  memcpy(arg->buffer, buffer, size);
44  arg->buffer = ((char *)arg->buffer) + size;
45  arg->left -= size;
46 
47  return 0;
48 }
49 
50 /*
51  * A variant of the der_encode() which encodes the data into the provided buffer
52  */
54 der_encode_to_buffer(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr,
55  void *buffer, size_t buffer_size) {
56  enc_to_buf_arg arg;
57  asn_enc_rval_t ec;
58 
59  arg.buffer = buffer;
60  arg.left = buffer_size;
61 
62  ec = type_descriptor->der_encoder(type_descriptor,
63  struct_ptr, /* Pointer to the destination structure */
64  0, 0, encode_to_buffer_cb, &arg);
65  if(ec.encoded != -1) {
66  assert(ec.encoded == (ssize_t)(buffer_size - arg.left));
67  /* Return the encoded contents size */
68  }
69  return ec;
70 }
71 
72 
73 /*
74  * Write out leading TL[v] sequence according to the type definition.
75  */
76 ssize_t
78  size_t struct_length,
79  int tag_mode, int last_tag_form,
80  ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */
82  void *app_key) {
83  ber_tlv_tag_t *tags; /* Copy of tags stream */
84  int tags_count; /* Number of tags */
85  size_t overall_length;
86  ssize_t *lens;
87  int i;
88 
89  ASN_DEBUG("Writing tags (%s, tm=%d, tc=%d, tag=%s, mtc=%d)",
90  sd->name, tag_mode, sd->tags_count,
91  ber_tlv_tag_string(tag),
92  tag_mode
93  ?(sd->tags_count+1
94  -((tag_mode == -1) && sd->tags_count))
95  :sd->tags_count
96  );
97 
98  if(tag_mode) {
99  /*
100  * Instead of doing shaman dance like we do in ber_check_tags(),
101  * allocate a small array on the stack
102  * and initialize it appropriately.
103  */
104  int stag_offset;
105  tags = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t));
106  if(!tags) { /* Can fail on !x86 */
107  errno = ENOMEM;
108  return -1;
109  }
110  tags_count = sd->tags_count
111  + 1 /* EXPLICIT or IMPLICIT tag is given */
112  - ((tag_mode == -1) && sd->tags_count);
113  /* Copy tags over */
114  tags[0] = tag;
115  stag_offset = -1 + ((tag_mode == -1) && sd->tags_count);
116  for(i = 1; i < tags_count; i++)
117  tags[i] = sd->tags[i + stag_offset];
118  } else {
119  tags = sd->tags;
120  tags_count = sd->tags_count;
121  }
122 
123  /* No tags to write */
124  if(tags_count == 0)
125  return 0;
126 
127  lens = (ssize_t *)alloca(tags_count * sizeof(lens[0]));
128  if(!lens) {
129  errno = ENOMEM;
130  return -1;
131  }
132 
133  /*
134  * Array of tags is initialized.
135  * Now, compute the size of the TLV pairs, from right to left.
136  */
137  overall_length = struct_length;
138  for(i = tags_count - 1; i >= 0; --i) {
139  lens[i] = der_write_TL(tags[i], overall_length, 0, 0, 0);
140  if(lens[i] == -1) return -1;
141  overall_length += lens[i];
142  lens[i] = overall_length - lens[i];
143  }
144 
145  if(!cb) return overall_length - struct_length;
146 
147  ASN_DEBUG("%s %s TL sequence (%d elements)",
148  cb?"Encoding":"Estimating", sd->name, tags_count);
149 
150  /*
151  * Encode the TL sequence for real.
152  */
153  for(i = 0; i < tags_count; i++) {
154  ssize_t len;
155  int _constr;
156 
157  /* Check if this tag happens to be constructed */
158  _constr = (last_tag_form || i < (tags_count - 1));
159 
160  len = der_write_TL(tags[i], lens[i], cb, app_key, _constr);
161  if(len == -1) return -1;
162  }
163 
164  return overall_length - struct_length;
165 }
166 
167 static ssize_t
169  asn_app_consume_bytes_f *cb, void *app_key,
170  int constructed) {
171  uint8_t buf[32];
172  size_t size = 0;
173  int buf_size = cb?sizeof(buf):0;
174  ssize_t tmp;
175 
176  /* Serialize tag (T from TLV) into possibly zero-length buffer */
177  tmp = ber_tlv_tag_serialize(tag, buf, buf_size);
178  if(tmp == -1 || tmp > (ssize_t)sizeof(buf)) return -1;
179  size += tmp;
180 
181  /* Serialize length (L from TLV) into possibly zero-length buffer */
182  tmp = der_tlv_length_serialize(len, buf+size, buf_size?buf_size-size:0);
183  if(tmp == -1) return -1;
184  size += tmp;
185 
186  if(size > sizeof(buf))
187  return -1;
188 
189  /*
190  * If callback is specified, invoke it, and check its return value.
191  */
192  if(cb) {
193  if(constructed) *buf |= 0x20;
194  if(cb(buf, size, app_key) < 0)
195  return -1;
196  }
197 
198  return size;
199 }
static ssize_t der_write_TL(ber_tlv_tag_t tag, ber_tlv_len_t len, asn_app_consume_bytes_f *cb, void *app_key, int constructed)
Definition: der_encoder.c:168
size_t der_tlv_length_serialize(ber_tlv_len_t len, void *bufptr, size_t size)
char * ber_tlv_tag_string(ber_tlv_tag_t tag)
Definition: ber_tlv_tag.c:94
asn_enc_rval_t der_encode_to_buffer(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr, void *buffer, size_t buffer_size)
Definition: der_encoder.c:54
ssize_t der_write_tags(asn_TYPE_descriptor_t *sd, size_t struct_length, int tag_mode, int last_tag_form, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb, void *app_key)
Definition: der_encoder.c:77
static int encode_to_buffer_cb(const void *buffer, size_t size, void *key)
Definition: der_encoder.c:37
ssize_t encoded
Definition: asn_codecs.h:48
ssize_t ber_tlv_len_t
ber_tlv_tag_t * tags
Definition: constr_TYPE.h:111
asn_enc_rval_t der_encode(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr, asn_app_consume_bytes_f *consume_bytes, void *app_key)
Definition: der_encoder.c:15
int() asn_app_consume_bytes_f(const void *buffer, size_t size, void *application_specific_key)
der_type_encoder_f * der_encoder
Definition: constr_TYPE.h:97
struct enc_to_buf_arg enc_to_buf_arg
static void ASN_DEBUG(const char *fmt,...)
Definition: asn_internal.h:62
size_t ber_tlv_tag_serialize(ber_tlv_tag_t tag, void *bufptr, size_t size)
Definition: ber_tlv_tag.c:104
unsigned ber_tlv_tag_t
Definition: ber_tlv_tag.h:18