../svn-commit.tmp
[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 <utils/allocator.h>
27 #include <daemon.h>
28
29
30
31 typedef struct private_der_encoder_t private_der_encoder_t;
32
33 /**
34 * Private data of a der_encoder_t object.
35 */
36 struct private_der_encoder_t {
37 /**
38 * Public interface for this signer.
39 */
40 der_encoder_t public;
41
42 asn1_rule_t *rule;
43
44 asn1_rule_t *first_rule;
45
46 void *output;
47
48 logger_t *logger;
49 };
50
51 static status_t read_hdr(private_der_encoder_t *this, chunk_t *data);
52
53 static status_t read_sequence(private_der_encoder_t *this, chunk_t data)
54 {
55 while (this->rule->type != ASN1_END)
56 {
57 read_hdr(this, &data);
58 }
59 return SUCCESS;
60 }
61
62
63 static status_t read_int(private_der_encoder_t *this, chunk_t data)
64 {
65 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "ASN1_INTEGER", data);
66 u_int *integ = (u_int*)((u_int8_t*)this->output + this->rule->data_offset);
67
68 *integ = 0;
69 while (data.len-- > 0)
70 {
71 *integ = 256 * (*integ) + *data.ptr++;
72 }
73 return SUCCESS;
74 }
75
76 static status_t read_mpz(private_der_encoder_t *this, chunk_t data)
77 {
78 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "ASN1_INTEGER as mpz", data);
79 mpz_t *mpz = (mpz_t*)((u_int8_t*)this->output + this->rule->data_offset);
80
81 mpz_import(*mpz, data.len, 1, 1, 1, 0, data.ptr);
82 return SUCCESS;
83 }
84
85 static u_int32_t read_length(chunk_t *data)
86 {
87 u_int8_t n;
88 size_t len;
89
90 /* read first octet of length field */
91 n = *data->ptr++;
92
93 if ((n & 0x80) == 0)
94 {
95 /* single length octet */
96 return n;
97 }
98
99 /* composite length, determine number of length octets */
100 n &= 0x7f;
101
102 if (n > data->len)
103 {
104 /* length longer than available bytes */
105 return -1;
106 }
107
108 if (n > sizeof(len))
109 {
110 /* larger than size_t can hold */
111 return -1;
112 }
113
114 len = 0;
115 while (n-- > 0)
116 {
117 len = 256 * len + *data->ptr++;
118 }
119 return len;
120 }
121
122 static status_t read_hdr(private_der_encoder_t *this, chunk_t *data)
123 {
124 chunk_t inner;
125
126 /* advance to the next rule */
127 this->rule++;
128
129 if (this->rule->type == ASN1_END)
130 {
131 return SUCCESS;
132 }
133
134 this->logger->log(this->logger, CONTROL|LEVEL2, "reading header of rule %s",
135 mapping_find(asn1_type_m, this->rule->type));
136
137 this->logger->log_chunk(this->logger, CONTROL|LEVEL2, "reading from:", *data);
138
139 /* read type, advance in data */
140 if (*(data->ptr) != this->rule->type)
141 {
142 this->logger->log(this->logger, CONTROL|LEVEL2, "Bad byte found (%x)", *data->ptr);
143 return PARSE_ERROR;
144 }
145 data->ptr++;
146 data->len--;
147
148 /* read length, advance in data */
149 inner.len = read_length(data);
150 if (inner.len == -1)
151 {
152 this->logger->log(this->logger, CONTROL|LEVEL2, "Error reading length");
153 return PARSE_ERROR;
154 }
155 this->logger->log(this->logger, CONTROL|LEVEL2, "Length is %d",
156 inner.len);
157 inner.ptr = data->ptr;
158
159 /* advance in data */
160 data->ptr += inner.len;
161 data->len -= inner.len;
162
163 /* process inner */
164 switch (this->rule->type)
165 {
166 case ASN1_INTEGER:
167 if (this->rule->flags & ASN1_MPZ)
168 {
169 read_mpz(this, inner);
170 }
171 else
172 {
173 read_int(this, inner);
174 }
175 break;
176 case ASN1_SEQUENCE:
177 read_sequence(this, inner);
178 break;
179 default:
180 break;
181 }
182
183 return SUCCESS;
184 }
185
186
187
188 static status_t decode(private_der_encoder_t *this, chunk_t input, void *output)
189 {
190 this->rule = this->first_rule - 1;
191 this->output = output;
192 return read_hdr(this, &input);
193 }
194
195 /**
196 * Implementation of der_encoder.destroy.
197 */
198 static void destroy(private_der_encoder_t *this)
199 {
200 allocator_free(this);
201 }
202
203 /*
204 * Described in header.
205 */
206 der_encoder_t *der_encoder_create(asn1_rule_t *rules)
207 {
208 private_der_encoder_t *this = allocator_alloc_thing(private_der_encoder_t);
209
210 /* public functions */
211 this->public.decode = (status_t (*) (der_encoder_t*,chunk_t,void*))decode;
212 this->public.destroy = (void (*) (der_encoder_t*))destroy;
213
214 this->first_rule = rules;
215 this->logger = charon->logger_manager->get_logger(charon->logger_manager, DER_DECODER);
216
217 return &(this->public);
218 }