- leak detective is usable, but does not show static function names
[strongswan.git] / Source / lib / asn1 / der_encoder.c
1 /**
2 * @file der_encoder.c
3 *
4 * @brief Implementation of der_encoder_t.
5 */
6
7 /*
8 * Copyright (C) 2005 Jan Hutter, Martin Willi
9 * Hochschule fuer Technik Rapperswil
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
15 *
16 * This program is distributed in the hope that it will be useful, but
17 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * for more details.
20 */
21
22 #include <gmp.h>
23
24 #include "der_encoder.h"
25
26 #include <daemon.h>
27
28
29
30 typedef struct private_der_encoder_t private_der_encoder_t;
31
32 /**
33 * Private data of a der_encoder_t object.
34 */
35 struct private_der_encoder_t {
36 /**
37 * Public interface for this signer.
38 */
39 der_encoder_t public;
40
41 asn1_rule_t *rule;
42
43 asn1_rule_t *first_rule;
44
45 void *output;
46
47 logger_t *logger;
48 };
49
50 static status_t read_hdr(private_der_encoder_t *this, chunk_t *data);
51
52 static status_t read_sequence(private_der_encoder_t *this, chunk_t data)
53 {
54 while (this->rule->type != ASN1_END)
55 {
56 read_hdr(this, &data);
57 }
58 return SUCCESS;
59 }
60
61
62 static status_t read_int(private_der_encoder_t *this, chunk_t data)
63 {
64 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "ASN1_INTEGER", data);
65 u_int *integ = (u_int*)((u_int8_t*)this->output + this->rule->data_offset);
66
67 *integ = 0;
68 while (data.len-- > 0)
69 {
70 *integ = 256 * (*integ) + *data.ptr++;
71 }
72 return SUCCESS;
73 }
74
75 static status_t read_mpz(private_der_encoder_t *this, chunk_t data)
76 {
77 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "ASN1_INTEGER as mpz", data);
78 mpz_t *mpz = (mpz_t*)((u_int8_t*)this->output + this->rule->data_offset);
79
80 mpz_import(*mpz, data.len, 1, 1, 1, 0, data.ptr);
81 return SUCCESS;
82 }
83
84 static u_int32_t read_length(chunk_t *data)
85 {
86 u_int8_t n;
87 size_t len;
88
89 /* read first octet of length field */
90 n = *data->ptr++;
91
92 if ((n & 0x80) == 0)
93 {
94 /* single length octet */
95 return n;
96 }
97
98 /* composite length, determine number of length octets */
99 n &= 0x7f;
100
101 if (n > data->len)
102 {
103 /* length longer than available bytes */
104 return -1;
105 }
106
107 if (n > sizeof(len))
108 {
109 /* larger than size_t can hold */
110 return -1;
111 }
112
113 len = 0;
114 while (n-- > 0)
115 {
116 len = 256 * len + *data->ptr++;
117 }
118 return len;
119 }
120
121 static status_t read_hdr(private_der_encoder_t *this, chunk_t *data)
122 {
123 chunk_t inner;
124
125 /* advance to the next rule */
126 this->rule++;
127
128 if (this->rule->type == ASN1_END)
129 {
130 return SUCCESS;
131 }
132
133 this->logger->log(this->logger, CONTROL|LEVEL2, "reading header of rule %s",
134 mapping_find(asn1_type_m, this->rule->type));
135
136 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "reading from:", *data);
137
138 /* read type, advance in data */
139 if (*(data->ptr) != this->rule->type)
140 {
141 this->logger->log(this->logger, CONTROL|LEVEL2, "Bad byte found (%x)", *data->ptr);
142 return PARSE_ERROR;
143 }
144 data->ptr++;
145 data->len--;
146
147 /* read length, advance in data */
148 inner.len = read_length(data);
149 if (inner.len == -1)
150 {
151 this->logger->log(this->logger, CONTROL|LEVEL2, "Error reading length");
152 return PARSE_ERROR;
153 }
154 this->logger->log(this->logger, CONTROL|LEVEL2, "Length is %d",
155 inner.len);
156 inner.ptr = data->ptr;
157
158 /* advance in data */
159 data->ptr += inner.len;
160 data->len -= inner.len;
161
162 /* process inner */
163 switch (this->rule->type)
164 {
165 case ASN1_INTEGER:
166 if (this->rule->flags & ASN1_MPZ)
167 {
168 read_mpz(this, inner);
169 }
170 else
171 {
172 read_int(this, inner);
173 }
174 break;
175 case ASN1_SEQUENCE:
176 read_sequence(this, inner);
177 break;
178 default:
179 break;
180 }
181
182 return SUCCESS;
183 }
184
185
186
187 static status_t decode(private_der_encoder_t *this, chunk_t input, void *output)
188 {
189 this->rule = this->first_rule - 1;
190 this->output = output;
191 return read_hdr(this, &input);
192 }
193
194 /**
195 * Implementation of der_encoder.destroy.
196 */
197 static void destroy(private_der_encoder_t *this)
198 {
199 free(this);
200 }
201
202 /*
203 * Described in header.
204 */
205 der_encoder_t *der_encoder_create(asn1_rule_t *rules)
206 {
207 private_der_encoder_t *this = malloc_thing(private_der_encoder_t);
208
209 /* public functions */
210 this->public.decode = (status_t (*) (der_encoder_t*,chunk_t,void*))decode;
211 this->public.destroy = (void (*) (der_encoder_t*))destroy;
212
213 this->first_rule = rules;
214 this->logger = logger_manager>logger_manager->get_logger(logger_manager>logger_manager, DER_DECODER);
215
216 return &(this->public);
217 }