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 794 : read_byte (ksba_reader_t reader)
47 : {
48 : unsigned char buf;
49 : size_t nread;
50 : int rc;
51 :
52 : do
53 794 : rc = ksba_reader_read (reader, &buf, 1, &nread);
54 794 : while (!rc && !nread);
55 794 : 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 8 : eof_or_error (ksba_reader_t reader, struct tag_info *ti, int premature)
71 : {
72 : gpg_error_t err;
73 :
74 8 : err = ksba_reader_error (reader);
75 8 : if (err)
76 : {
77 0 : ti->err_string = "read error";
78 0 : return err;
79 : }
80 8 : if (premature)
81 0 : return premature_eof (ti);
82 :
83 8 : 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 374 : _ksba_ber_read_tl (ksba_reader_t reader, struct tag_info *ti)
93 : {
94 : int c;
95 : unsigned long tag;
96 :
97 374 : ti->length = 0;
98 374 : ti->ndef = 0;
99 374 : ti->nhdr = 0;
100 374 : ti->err_string = NULL;
101 374 : ti->non_der = 0;
102 :
103 : /* Get the tag */
104 374 : c = read_byte (reader);
105 374 : if (c==-1)
106 8 : return eof_or_error (reader, ti, 0);
107 :
108 366 : ti->buf[ti->nhdr++] = c;
109 366 : ti->class = (c & 0xc0) >> 6;
110 366 : ti->is_constructed = !!(c & 0x20);
111 366 : tag = c & 0x1f;
112 :
113 366 : 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 366 : ti->tag = tag;
135 :
136 : /* Get the length */
137 366 : c = read_byte (reader);
138 366 : if (c == -1)
139 0 : return eof_or_error (reader, ti, 1);
140 366 : 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 366 : ti->buf[ti->nhdr++] = c;
146 :
147 366 : if ( !(c & 0x80) )
148 333 : ti->length = c;
149 33 : else if (c == 0x80)
150 : {
151 0 : ti->ndef = 1;
152 0 : ti->non_der = 1;
153 : }
154 33 : 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 33 : unsigned long len = 0;
162 33 : int count = c & 0x7f;
163 :
164 33 : if (count > sizeof (len) || count > sizeof (size_t))
165 0 : return gpg_error (GPG_ERR_BAD_BER);
166 :
167 87 : for (; count; count--)
168 : {
169 54 : len <<= 8;
170 54 : c = read_byte (reader);
171 54 : if (c == -1)
172 0 : return eof_or_error (reader, ti, 1);
173 54 : 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 54 : ti->buf[ti->nhdr++] = c;
179 54 : len |= c & 0xff;
180 : }
181 33 : ti->length = len;
182 : }
183 :
184 : /* Without this kludge some example certs can't be parsed */
185 366 : if (ti->class == CLASS_UNIVERSAL && !ti->tag)
186 0 : ti->length = 0;
187 :
188 366 : 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 100 : _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 100 : const unsigned char *buf = *buffer;
202 100 : size_t length = *size;
203 :
204 100 : ti->length = 0;
205 100 : ti->ndef = 0;
206 100 : ti->nhdr = 0;
207 100 : ti->err_string = NULL;
208 100 : ti->non_der = 0;
209 :
210 : /* Get the tag */
211 100 : if (!length)
212 0 : return premature_eof (ti);
213 100 : c = *buf++; length--;
214 :
215 100 : ti->buf[ti->nhdr++] = c;
216 100 : ti->class = (c & 0xc0) >> 6;
217 100 : ti->is_constructed = !!(c & 0x20);
218 100 : tag = c & 0x1f;
219 :
220 100 : 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 100 : ti->tag = tag;
242 :
243 : /* Get the length */
244 100 : if (!length)
245 0 : return premature_eof (ti);
246 100 : c = *buf++; length--;
247 100 : 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 100 : ti->buf[ti->nhdr++] = c;
253 :
254 100 : if ( !(c & 0x80) )
255 99 : ti->length = c;
256 1 : else if (c == 0x80)
257 : {
258 0 : ti->ndef = 1;
259 0 : ti->non_der = 1;
260 : }
261 1 : 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 1 : unsigned long len = 0;
269 1 : int count = c & 0x7f;
270 :
271 1 : if (count > sizeof (len) || count > sizeof (size_t))
272 0 : return gpg_error (GPG_ERR_BAD_BER);
273 :
274 2 : for (; count; count--)
275 : {
276 1 : len <<= 8;
277 1 : if (!length)
278 0 : return premature_eof (ti);
279 1 : c = *buf++; length--;
280 1 : 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 1 : ti->buf[ti->nhdr++] = c;
286 1 : len |= c & 0xff;
287 : }
288 1 : ti->length = len;
289 : }
290 :
291 : /* Without this kludge some example certs can't be parsed */
292 100 : if (ti->class == CLASS_UNIVERSAL && !ti->tag)
293 0 : ti->length = 0;
294 :
295 100 : *buffer = buf;
296 100 : *size = length;
297 100 : return 0;
298 : }
299 :
300 :
301 : /* Write TAG of CLASS to WRITER. constructed is a flag telling
302 : whether the value is a constructed one. length gives the length of
303 : the value, if it is 0 undefinite length is assumed. length is
304 : ignored for the NULL tag. */
305 : gpg_error_t
306 109 : _ksba_ber_write_tl (ksba_writer_t writer,
307 : unsigned long tag,
308 : enum tag_class class,
309 : int constructed,
310 : unsigned long length)
311 : {
312 : unsigned char buf[50];
313 109 : int buflen = 0;
314 :
315 109 : if (tag < 0x1f)
316 : {
317 109 : *buf = (class << 6) | tag;
318 109 : if (constructed)
319 51 : *buf |= 0x20;
320 109 : buflen++;
321 : }
322 : else
323 : {
324 0 : return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
325 : }
326 :
327 109 : if (!tag && !class)
328 0 : buf[buflen++] = 0; /* end tag */
329 109 : else if (tag == TYPE_NULL && !class)
330 6 : buf[buflen++] = 0; /* NULL tag */
331 103 : else if (!length)
332 0 : buf[buflen++] = 0x80; /* indefinite length */
333 103 : else if (length < 128)
334 79 : buf[buflen++] = length;
335 : else
336 : {
337 : int i;
338 :
339 : /* fixme: if we know the sizeof an ulong we could support larger
340 : objects - however this is pretty ridiculous */
341 40 : i = (length <= 0xff ? 1:
342 16 : length <= 0xffff ? 2:
343 0 : length <= 0xffffff ? 3: 4);
344 :
345 24 : buf[buflen++] = (0x80 | i);
346 24 : if (i > 3)
347 0 : buf[buflen++] = length >> 24;
348 24 : if (i > 2)
349 0 : buf[buflen++] = length >> 16;
350 24 : if (i > 1)
351 16 : buf[buflen++] = length >> 8;
352 24 : buf[buflen++] = length;
353 : }
354 :
355 109 : return ksba_writer_write (writer, buf, buflen);
356 : }
357 :
358 : /* Encode TAG of CLASS in BUFFER. CONSTRUCTED is a flag telling
359 : whether the value is a constructed one. LENGTH gives the length of
360 : the value, if it is 0 undefinite length is assumed. LENGTH is
361 : ignored for the NULL tag. It is assumed that the provide buffer is
362 : large enough for storing the result - this is usually achieved by
363 : using _ksba_ber_count_tl() in advance. Returns 0 in case of an
364 : error or the length of the encoding.*/
365 : size_t
366 0 : _ksba_ber_encode_tl (unsigned char *buffer,
367 : unsigned long tag,
368 : enum tag_class class,
369 : int constructed,
370 : unsigned long length)
371 : {
372 0 : unsigned char *buf = buffer;
373 :
374 0 : if (tag < 0x1f)
375 : {
376 0 : *buf = (class << 6) | tag;
377 0 : if (constructed)
378 0 : *buf |= 0x20;
379 0 : buf++;
380 : }
381 : else
382 : {
383 0 : return 0; /*Not implemented*/
384 : }
385 :
386 0 : if (!tag && !class)
387 0 : *buf++ = 0; /* end tag */
388 0 : else if (tag == TYPE_NULL && !class)
389 0 : *buf++ = 0; /* NULL tag */
390 0 : else if (!length)
391 0 : *buf++ = 0x80; /* indefinite length */
392 0 : else if (length < 128)
393 0 : *buf++ = length;
394 : else
395 : {
396 : int i;
397 :
398 : /* fixme: if we know the sizeof an ulong we could support larger
399 : objetcs - however this is pretty ridiculous */
400 0 : i = (length <= 0xff ? 1:
401 0 : length <= 0xffff ? 2:
402 0 : length <= 0xffffff ? 3: 4);
403 :
404 0 : *buf++ = (0x80 | i);
405 0 : if (i > 3)
406 0 : *buf++ = length >> 24;
407 0 : if (i > 2)
408 0 : *buf++ = length >> 16;
409 0 : if (i > 1)
410 0 : *buf++ = length >> 8;
411 0 : *buf++ = length;
412 : }
413 :
414 0 : return buf - buffer;
415 : }
416 :
417 :
418 : /* Calculate the length of the TL needed to encode a TAG of CLASS.
419 : CONSTRUCTED is a flag telling whether the value is a constructed
420 : one. LENGTH gives the length of the value; if it is 0 an
421 : indefinite length is assumed. LENGTH is ignored for the NULL
422 : tag. */
423 : size_t
424 78 : _ksba_ber_count_tl (unsigned long tag,
425 : enum tag_class class,
426 : int constructed,
427 : unsigned long length)
428 : {
429 78 : int buflen = 0;
430 :
431 : (void)constructed; /* Not used, but passed for uniformity of such calls. */
432 :
433 78 : if (tag < 0x1f)
434 : {
435 78 : buflen++;
436 : }
437 : else
438 : {
439 0 : buflen++; /* assume one and let the actual write function bail out */
440 : }
441 :
442 78 : if (!tag && !class)
443 0 : buflen++; /* end tag */
444 78 : else if (tag == TYPE_NULL && !class)
445 6 : buflen++; /* NULL tag */
446 72 : else if (!length)
447 0 : buflen++; /* indefinite length */
448 72 : else if (length < 128)
449 60 : buflen++;
450 : else
451 : {
452 : int i;
453 :
454 : /* fixme: if we know the sizeof an ulong we could support larger
455 : objetcs - however this is pretty ridiculous */
456 20 : i = (length <= 0xff ? 1:
457 8 : length <= 0xffff ? 2:
458 0 : length <= 0xffffff ? 3: 4);
459 :
460 12 : buflen++;
461 12 : if (i > 3)
462 0 : buflen++;
463 12 : if (i > 2)
464 0 : buflen++;
465 12 : if (i > 1)
466 8 : buflen++;
467 12 : buflen++;
468 : }
469 :
470 78 : return buflen;
471 : }
|