Line data Source code
1 : /* ber-help.c - BER herlper functions
2 : * Copyright (C) 2001, 2012 g10 Code GmbH
3 : *
4 : * This file is part of KSBA.
5 : *
6 : * KSBA is free software; you can redistribute it and/or modify
7 : * it under the terms of either
8 : *
9 : * - the GNU Lesser General Public License as published by the Free
10 : * Software Foundation; either version 3 of the License, or (at
11 : * your option) any later version.
12 : *
13 : * or
14 : *
15 : * - the GNU General Public License as published by the Free
16 : * Software Foundation; either version 2 of the License, or (at
17 : * your option) any later version.
18 : *
19 : * or both in parallel, as here.
20 : *
21 : * KSBA is distributed in the hope that it will be useful, but WITHOUT
22 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23 : * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
24 : * License for more details.
25 : *
26 : * You should have received a copies of the GNU General Public License
27 : * and the GNU Lesser General Public License along with this program;
28 : * if not, see <http://www.gnu.org/licenses/>.
29 : */
30 :
31 : #include <config.h>
32 : #include <stdio.h>
33 : #include <stdlib.h>
34 : #include <string.h>
35 : #include <assert.h>
36 : #include "util.h"
37 :
38 : #include "asn1-func.h" /* need some constants */
39 : #include "ber-help.h"
40 :
41 : /* Fixme: The parser functions should check that primitive types don't
42 : have the constructed bit set (which is not allowed). This saves us
43 : some work when using these parsers */
44 :
45 : static int
46 0 : read_byte (ksba_reader_t reader)
47 : {
48 : unsigned char buf;
49 : size_t nread;
50 : int rc;
51 :
52 : do
53 0 : rc = ksba_reader_read (reader, &buf, 1, &nread);
54 0 : while (!rc && !nread);
55 0 : return rc? -1: buf;
56 : }
57 :
58 :
59 : static int
60 0 : premature_eof (struct tag_info *ti)
61 : {
62 : /* Note: We do an strcmp on this string at othyer places. */
63 0 : ti->err_string = "premature EOF";
64 0 : return gpg_error (GPG_ERR_BAD_BER);
65 : }
66 :
67 :
68 :
69 : static gpg_error_t
70 0 : eof_or_error (ksba_reader_t reader, struct tag_info *ti, int premature)
71 : {
72 : gpg_error_t err;
73 :
74 0 : err = ksba_reader_error (reader);
75 0 : if (err)
76 : {
77 0 : ti->err_string = "read error";
78 0 : return err;
79 : }
80 0 : if (premature)
81 0 : return premature_eof (ti);
82 :
83 0 : return gpg_error (GPG_ERR_EOF);
84 : }
85 :
86 :
87 :
88 : /*
89 : Read the tag and the length part from the TLV triplet.
90 : */
91 : gpg_error_t
92 0 : _ksba_ber_read_tl (ksba_reader_t reader, struct tag_info *ti)
93 : {
94 : int c;
95 : unsigned long tag;
96 :
97 0 : ti->length = 0;
98 0 : ti->ndef = 0;
99 0 : ti->nhdr = 0;
100 0 : ti->err_string = NULL;
101 0 : ti->non_der = 0;
102 :
103 : /* Get the tag */
104 0 : c = read_byte (reader);
105 0 : if (c==-1)
106 0 : return eof_or_error (reader, ti, 0);
107 :
108 0 : ti->buf[ti->nhdr++] = c;
109 0 : ti->class = (c & 0xc0) >> 6;
110 0 : ti->is_constructed = !!(c & 0x20);
111 0 : tag = c & 0x1f;
112 :
113 0 : if (tag == 0x1f)
114 : {
115 0 : tag = 0;
116 : do
117 : {
118 : /* We silently ignore an overflow in the tag value. It is
119 : not worth checking for it. */
120 0 : tag <<= 7;
121 0 : c = read_byte (reader);
122 0 : if (c == -1)
123 0 : return eof_or_error (reader, ti, 1);
124 0 : if (ti->nhdr >= DIM (ti->buf))
125 : {
126 0 : ti->err_string = "tag+length header too large";
127 0 : return gpg_error (GPG_ERR_BAD_BER);
128 : }
129 0 : ti->buf[ti->nhdr++] = c;
130 0 : tag |= c & 0x7f;
131 : }
132 0 : while (c & 0x80);
133 : }
134 0 : ti->tag = tag;
135 :
136 : /* Get the length */
137 0 : c = read_byte (reader);
138 0 : if (c == -1)
139 0 : return eof_or_error (reader, ti, 1);
140 0 : if (ti->nhdr >= DIM (ti->buf))
141 : {
142 0 : ti->err_string = "tag+length header too large";
143 0 : return gpg_error (GPG_ERR_BAD_BER);
144 : }
145 0 : ti->buf[ti->nhdr++] = c;
146 :
147 0 : if ( !(c & 0x80) )
148 0 : ti->length = c;
149 0 : else if (c == 0x80)
150 : {
151 0 : ti->ndef = 1;
152 0 : ti->non_der = 1;
153 : }
154 0 : else if (c == 0xff)
155 : {
156 0 : ti->err_string = "forbidden length value";
157 0 : return gpg_error (GPG_ERR_BAD_BER);
158 : }
159 : else
160 : {
161 0 : unsigned long len = 0;
162 0 : int count = c & 0x7f;
163 :
164 0 : if (count > sizeof (len) || count > sizeof (size_t))
165 0 : return gpg_error (GPG_ERR_BAD_BER);
166 :
167 0 : for (; count; count--)
168 : {
169 0 : len <<= 8;
170 0 : c = read_byte (reader);
171 0 : if (c == -1)
172 0 : return eof_or_error (reader, ti, 1);
173 0 : if (ti->nhdr >= DIM (ti->buf))
174 : {
175 0 : ti->err_string = "tag+length header too large";
176 0 : return gpg_error (GPG_ERR_BAD_BER);
177 : }
178 0 : ti->buf[ti->nhdr++] = c;
179 0 : len |= c & 0xff;
180 : }
181 0 : ti->length = len;
182 : }
183 :
184 : /* Without this kludge some example certs can't be parsed */
185 0 : if (ti->class == CLASS_UNIVERSAL && !ti->tag)
186 0 : ti->length = 0;
187 :
188 0 : return 0;
189 : }
190 :
191 : /*
192 : Parse the buffer at the address BUFFER which of SIZE and return
193 : the tag and the length part from the TLV triplet. Update BUFFER
194 : and SIZE on success. */
195 : gpg_error_t
196 0 : _ksba_ber_parse_tl (unsigned char const **buffer, size_t *size,
197 : struct tag_info *ti)
198 : {
199 : int c;
200 : unsigned long tag;
201 0 : const unsigned char *buf = *buffer;
202 0 : size_t length = *size;
203 :
204 0 : ti->length = 0;
205 0 : ti->ndef = 0;
206 0 : ti->nhdr = 0;
207 0 : ti->err_string = NULL;
208 0 : ti->non_der = 0;
209 :
210 : /* Get the tag */
211 0 : if (!length)
212 0 : return premature_eof (ti);
213 0 : c = *buf++; length--;
214 :
215 0 : ti->buf[ti->nhdr++] = c;
216 0 : ti->class = (c & 0xc0) >> 6;
217 0 : ti->is_constructed = !!(c & 0x20);
218 0 : tag = c & 0x1f;
219 :
220 0 : if (tag == 0x1f)
221 : {
222 0 : tag = 0;
223 : do
224 : {
225 : /* We silently ignore an overflow in the tag value. It is
226 : not worth checking for it. */
227 0 : tag <<= 7;
228 0 : if (!length)
229 0 : return premature_eof (ti);
230 0 : c = *buf++; length--;
231 0 : if (ti->nhdr >= DIM (ti->buf))
232 : {
233 0 : ti->err_string = "tag+length header too large";
234 0 : return gpg_error (GPG_ERR_BAD_BER);
235 : }
236 0 : ti->buf[ti->nhdr++] = c;
237 0 : tag |= c & 0x7f;
238 : }
239 0 : while (c & 0x80);
240 : }
241 0 : ti->tag = tag;
242 :
243 : /* Get the length */
244 0 : if (!length)
245 0 : return premature_eof (ti);
246 0 : c = *buf++; length--;
247 0 : if (ti->nhdr >= DIM (ti->buf))
248 : {
249 0 : ti->err_string = "tag+length header too large";
250 0 : return gpg_error (GPG_ERR_BAD_BER);
251 : }
252 0 : ti->buf[ti->nhdr++] = c;
253 :
254 0 : if ( !(c & 0x80) )
255 0 : ti->length = c;
256 0 : else if (c == 0x80)
257 : {
258 0 : ti->ndef = 1;
259 0 : ti->non_der = 1;
260 : }
261 0 : else if (c == 0xff)
262 : {
263 0 : ti->err_string = "forbidden length value";
264 0 : return gpg_error (GPG_ERR_BAD_BER);
265 : }
266 : else
267 : {
268 0 : unsigned long len = 0;
269 0 : int count = c & 0x7f;
270 :
271 0 : if (count > sizeof (len) || count > sizeof (size_t))
272 0 : return gpg_error (GPG_ERR_BAD_BER);
273 :
274 0 : for (; count; count--)
275 : {
276 0 : len <<= 8;
277 0 : if (!length)
278 0 : return premature_eof (ti);
279 0 : c = *buf++; length--;
280 0 : if (ti->nhdr >= DIM (ti->buf))
281 : {
282 0 : ti->err_string = "tag+length header too large";
283 0 : return gpg_error (GPG_ERR_BAD_BER);
284 : }
285 0 : ti->buf[ti->nhdr++] = c;
286 0 : len |= c & 0xff;
287 : }
288 : /* Sanity check for the length: This is done so that we can take
289 : * the value for malloc plus some additional bytes without
290 : * risking an overflow. */
291 0 : if (len > (1 << 30))
292 0 : return gpg_error (GPG_ERR_BAD_BER);
293 0 : ti->length = len;
294 : }
295 :
296 :
297 : /* Without this kludge some example certs can't be parsed */
298 0 : if (ti->class == CLASS_UNIVERSAL && !ti->tag)
299 0 : ti->length = 0;
300 :
301 0 : *buffer = buf;
302 0 : *size = length;
303 0 : return 0;
304 : }
305 :
306 :
307 : /* Write TAG of CLASS to WRITER. constructed is a flag telling
308 : whether the value is a constructed one. length gives the length of
309 : the value, if it is 0 undefinite length is assumed. length is
310 : ignored for the NULL tag. */
311 : gpg_error_t
312 0 : _ksba_ber_write_tl (ksba_writer_t writer,
313 : unsigned long tag,
314 : enum tag_class class,
315 : int constructed,
316 : unsigned long length)
317 : {
318 : unsigned char buf[50];
319 0 : int buflen = 0;
320 :
321 0 : if (tag < 0x1f)
322 : {
323 0 : *buf = (class << 6) | tag;
324 0 : if (constructed)
325 0 : *buf |= 0x20;
326 0 : buflen++;
327 : }
328 : else
329 : {
330 0 : return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
331 : }
332 :
333 0 : if (!tag && !class)
334 0 : buf[buflen++] = 0; /* end tag */
335 0 : else if (tag == TYPE_NULL && !class)
336 0 : buf[buflen++] = 0; /* NULL tag */
337 0 : else if (!length)
338 0 : buf[buflen++] = 0x80; /* indefinite length */
339 0 : else if (length < 128)
340 0 : buf[buflen++] = length;
341 : else
342 : {
343 : int i;
344 :
345 : /* fixme: if we know the sizeof an ulong we could support larger
346 : objects - however this is pretty ridiculous */
347 0 : i = (length <= 0xff ? 1:
348 0 : length <= 0xffff ? 2:
349 0 : length <= 0xffffff ? 3: 4);
350 :
351 0 : buf[buflen++] = (0x80 | i);
352 0 : if (i > 3)
353 0 : buf[buflen++] = length >> 24;
354 0 : if (i > 2)
355 0 : buf[buflen++] = length >> 16;
356 0 : if (i > 1)
357 0 : buf[buflen++] = length >> 8;
358 0 : buf[buflen++] = length;
359 : }
360 :
361 0 : return ksba_writer_write (writer, buf, buflen);
362 : }
363 :
364 : /* Encode TAG of CLASS in BUFFER. CONSTRUCTED is a flag telling
365 : whether the value is a constructed one. LENGTH gives the length of
366 : the value, if it is 0 undefinite length is assumed. LENGTH is
367 : ignored for the NULL tag. It is assumed that the provide buffer is
368 : large enough for storing the result - this is usually achieved by
369 : using _ksba_ber_count_tl() in advance. Returns 0 in case of an
370 : error or the length of the encoding.*/
371 : size_t
372 0 : _ksba_ber_encode_tl (unsigned char *buffer,
373 : unsigned long tag,
374 : enum tag_class class,
375 : int constructed,
376 : unsigned long length)
377 : {
378 0 : unsigned char *buf = buffer;
379 :
380 0 : if (tag < 0x1f)
381 : {
382 0 : *buf = (class << 6) | tag;
383 0 : if (constructed)
384 0 : *buf |= 0x20;
385 0 : buf++;
386 : }
387 : else
388 : {
389 0 : return 0; /*Not implemented*/
390 : }
391 :
392 0 : if (!tag && !class)
393 0 : *buf++ = 0; /* end tag */
394 0 : else if (tag == TYPE_NULL && !class)
395 0 : *buf++ = 0; /* NULL tag */
396 0 : else if (!length)
397 0 : *buf++ = 0x80; /* indefinite length */
398 0 : else if (length < 128)
399 0 : *buf++ = length;
400 : else
401 : {
402 : int i;
403 :
404 : /* fixme: if we know the sizeof an ulong we could support larger
405 : objetcs - however this is pretty ridiculous */
406 0 : i = (length <= 0xff ? 1:
407 0 : length <= 0xffff ? 2:
408 0 : length <= 0xffffff ? 3: 4);
409 :
410 0 : *buf++ = (0x80 | i);
411 0 : if (i > 3)
412 0 : *buf++ = length >> 24;
413 0 : if (i > 2)
414 0 : *buf++ = length >> 16;
415 0 : if (i > 1)
416 0 : *buf++ = length >> 8;
417 0 : *buf++ = length;
418 : }
419 :
420 0 : return buf - buffer;
421 : }
422 :
423 :
424 : /* Calculate the length of the TL needed to encode a TAG of CLASS.
425 : CONSTRUCTED is a flag telling whether the value is a constructed
426 : one. LENGTH gives the length of the value; if it is 0 an
427 : indefinite length is assumed. LENGTH is ignored for the NULL
428 : tag. */
429 : size_t
430 0 : _ksba_ber_count_tl (unsigned long tag,
431 : enum tag_class class,
432 : int constructed,
433 : unsigned long length)
434 : {
435 0 : int buflen = 0;
436 :
437 : (void)constructed; /* Not used, but passed for uniformity of such calls. */
438 :
439 0 : if (tag < 0x1f)
440 : {
441 0 : buflen++;
442 : }
443 : else
444 : {
445 0 : buflen++; /* assume one and let the actual write function bail out */
446 : }
447 :
448 0 : if (!tag && !class)
449 0 : buflen++; /* end tag */
450 0 : else if (tag == TYPE_NULL && !class)
451 0 : buflen++; /* NULL tag */
452 0 : else if (!length)
453 0 : buflen++; /* indefinite length */
454 0 : else if (length < 128)
455 0 : buflen++;
456 : else
457 : {
458 : int i;
459 :
460 : /* fixme: if we know the sizeof an ulong we could support larger
461 : objetcs - however this is pretty ridiculous */
462 0 : i = (length <= 0xff ? 1:
463 0 : length <= 0xffff ? 2:
464 0 : length <= 0xffffff ? 3: 4);
465 :
466 0 : buflen++;
467 0 : if (i > 3)
468 0 : buflen++;
469 0 : if (i > 2)
470 0 : buflen++;
471 0 : if (i > 1)
472 0 : buflen++;
473 0 : buflen++;
474 : }
475 :
476 0 : return buflen;
477 : }
|