eliminated TIMETOA_BUF definition
[strongswan.git] / src / pluto / asn1.c
1 /* Simple ASN.1 parser
2 * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * for more details.
13 *
14 * RCSID $Id$
15 */
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <time.h>
20
21 #include <freeswan.h>
22
23 #include "constants.h"
24 #include "defs.h"
25 #include "mp_defs.h"
26 #include "asn1.h"
27 #include <asn1/oid.h>
28 #include "log.h"
29
30 /* some common prefabricated ASN.1 constants */
31
32 static u_char ASN1_INTEGER_0_str[] = { 0x02, 0x00 };
33 static u_char ASN1_INTEGER_1_str[] = { 0x02, 0x01, 0x01 };
34 static u_char ASN1_INTEGER_2_str[] = { 0x02, 0x01, 0x02 };
35
36 const chunk_t ASN1_INTEGER_0 = chunk_from_buf(ASN1_INTEGER_0_str);
37 const chunk_t ASN1_INTEGER_1 = chunk_from_buf(ASN1_INTEGER_1_str);
38 const chunk_t ASN1_INTEGER_2 = chunk_from_buf(ASN1_INTEGER_2_str);
39
40 /* some popular algorithmIdentifiers */
41
42 static u_char ASN1_md5_id_str[] = {
43 0x30, 0x0C,
44 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05,
45 0x05, 0x00
46 };
47
48 static u_char ASN1_sha1_id_str[] = {
49 0x30, 0x09,
50 0x06, 0x05, 0x2B, 0x0E,0x03, 0x02, 0x1A,
51 0x05, 0x00
52 };
53
54 static u_char ASN1_md5WithRSA_id_str[] = {
55 0x30, 0x0D,
56 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x04,
57 0x05, 0x00
58 };
59
60 static u_char ASN1_sha1WithRSA_id_str[] = {
61 0x30, 0x0D,
62 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05,
63 0x05, 0x00
64 };
65
66 static u_char ASN1_rsaEncryption_id_str[] = {
67 0x30, 0x0D,
68 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01,
69 0x05, 0x00
70 };
71
72 const chunk_t ASN1_md5_id = chunk_from_buf(ASN1_md5_id_str);
73 const chunk_t ASN1_sha1_id = chunk_from_buf(ASN1_sha1_id_str);
74 const chunk_t ASN1_rsaEncryption_id = chunk_from_buf(ASN1_rsaEncryption_id_str);
75 const chunk_t ASN1_md5WithRSA_id = chunk_from_buf(ASN1_md5WithRSA_id_str);
76 const chunk_t ASN1_sha1WithRSA_id = chunk_from_buf(ASN1_sha1WithRSA_id_str);
77
78 /* ASN.1 definition of an algorithmIdentifier */
79
80 static const asn1Object_t algorithmIdentifierObjects[] = {
81 { 0, "algorithmIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
82 { 1, "algorithm", ASN1_OID, ASN1_BODY }, /* 1 */
83 { 1, "parameters", ASN1_EOC, ASN1_OPT |
84 ASN1_RAW }, /* 2 */
85 { 1, "end opt", ASN1_EOC, ASN1_END } /* 3 */
86 };
87
88 #define ALGORITHM_ID_ALG 1
89 #define ALGORITHM_ID_PARAMETERS 2
90 #define ALGORITHM_ID_ROOF 4
91
92 /*
93 * return the ASN.1 encoded algorithm identifier
94 */
95 chunk_t
96 asn1_algorithmIdentifier(int oid)
97 {
98 switch (oid)
99 {
100 case OID_RSA_ENCRYPTION:
101 return ASN1_rsaEncryption_id;
102 case OID_MD5_WITH_RSA:
103 return ASN1_md5WithRSA_id;
104 case OID_SHA1_WITH_RSA:
105 return ASN1_sha1WithRSA_id;
106 case OID_MD5:
107 return ASN1_md5_id;
108 case OID_SHA1:
109 return ASN1_sha1_id;
110 default:
111 return chunk_empty;
112 }
113 }
114
115 /* If the oid is listed in the oid_names table then the corresponding
116 * position in the oid_names table is returned otherwise -1 is returned
117 */
118 int
119 asn1_known_oid(chunk_t object)
120 {
121 int oid = 0;
122
123 while (object.len)
124 {
125 if (oid_names[oid].octet == *object.ptr)
126 {
127 if (--object.len == 0 || oid_names[oid].down == 0)
128 {
129 return oid; /* found terminal symbol */
130 }
131 else
132 {
133 object.ptr++; oid++; /* advance to next hex octet */
134 }
135 }
136 else
137 {
138 if (oid_names[oid].next)
139 {
140 oid = oid_names[oid].next;
141 }
142 else
143 {
144 return OID_UNKNOWN;
145 }
146 }
147 }
148 return -1;
149 }
150
151 /*
152 * Converts a known OID index to an ASN.1 OID
153 */
154 chunk_t
155 asn1_build_known_oid(int n)
156 {
157 chunk_t oid;
158 int i;
159
160 if (n < 0 || n >= OID_MAX)
161 {
162 return chunk_empty;
163 }
164
165 i = oid_names[n].level + 1;
166 oid.ptr = malloc(2 + i);
167 oid.len = i;
168 oid.ptr[0] = ASN1_OID;
169 oid.ptr[1] = i;
170
171 do
172 {
173 if (oid_names[n].level >= i)
174 {
175 n--;
176 continue;
177 }
178 oid.ptr[--i + 2] = oid_names[n--].octet;
179 }
180 while (i > 0);
181
182 return oid;
183 }
184
185 /*
186 * Decodes the length in bytes of an ASN.1 object
187 */
188 u_int
189 asn1_length(chunk_t *blob)
190 {
191 u_char n;
192 size_t len;
193
194 /* advance from tag field on to length field */
195 blob->ptr++;
196 blob->len--;
197
198 /* read first octet of length field */
199 n = *blob->ptr++;
200 blob->len--;
201
202 if ((n & 0x80) == 0) /* single length octet */
203 return n;
204
205 /* composite length, determine number of length octets */
206 n &= 0x7f;
207
208 if (n > blob->len)
209 {
210 DBG(DBG_PARSING,
211 DBG_log("number of length octets is larger than ASN.1 object")
212 )
213 return ASN1_INVALID_LENGTH;
214 }
215
216 if (n > sizeof(len))
217 {
218 DBG(DBG_PARSING,
219 DBG_log("number of length octets is larger than limit of %d octets"
220 , (int)sizeof(len))
221 )
222 return ASN1_INVALID_LENGTH;
223 }
224
225 len = 0;
226
227 while (n-- > 0)
228 {
229 len = 256*len + *blob->ptr++;
230 blob->len--;
231 }
232 return len;
233 }
234
235 /*
236 * codes ASN.1 lengths up to a size of 16'777'215 bytes
237 */
238 void
239 code_asn1_length(size_t length, chunk_t *code)
240 {
241 if (length < 128)
242 {
243 code->ptr[0] = length;
244 code->len = 1;
245 }
246 else if (length < 256)
247 {
248 code->ptr[0] = 0x81;
249 code->ptr[1] = (u_char) length;
250 code->len = 2;
251 }
252 else if (length < 65536)
253 {
254 code->ptr[0] = 0x82;
255 code->ptr[1] = length >> 8;
256 code->ptr[2] = length & 0x00ff;
257 code->len = 3;
258 }
259 else
260 {
261 code->ptr[0] = 0x83;
262 code->ptr[1] = length >> 16;
263 code->ptr[2] = (length >> 8) & 0x00ff;
264 code->ptr[3] = length & 0x0000ff;
265 code->len = 4;
266 }
267 }
268
269 /*
270 * build an empty asn.1 object with tag and length fields already filled in
271 */
272 u_char*
273 build_asn1_object(chunk_t *object, asn1_t type, size_t datalen)
274 {
275 u_char length_buf[4];
276 chunk_t length = { length_buf, 0 };
277 u_char *pos;
278
279 /* code the asn.1 length field */
280 code_asn1_length(datalen, &length);
281
282 /* allocate memory for the asn.1 TLV object */
283 object->len = 1 + length.len + datalen;
284 object->ptr = malloc(object->len);
285
286 /* set position pointer at the start of the object */
287 pos = object->ptr;
288
289 /* copy the asn.1 tag field and advance the pointer */
290 *pos++ = type;
291
292 /* copy the asn.1 length field and advance the pointer */
293 chunkcpy(pos, length);
294
295 return pos;
296 }
297
298 /*
299 * build a simple ASN.1 object
300 */
301 chunk_t
302 asn1_simple_object(asn1_t tag, chunk_t content)
303 {
304 chunk_t object;
305
306 u_char *pos = build_asn1_object(&object, tag, content.len);
307 chunkcpy(pos, content);
308
309 return object;
310 }
311
312 /* Build an ASN.1 object from a variable number of individual chunks.
313 * Depending on the mode, chunks either are moved ('m') or copied ('c').
314 */
315 chunk_t
316 asn1_wrap(asn1_t type, const char *mode, ...)
317 {
318 chunk_t construct;
319 va_list chunks;
320 u_char *pos;
321 int i;
322 int count = strlen(mode);
323
324 /* sum up lengths of individual chunks */
325 va_start(chunks, mode);
326 construct.len = 0;
327 for (i = 0; i < count; i++)
328 {
329 chunk_t ch = va_arg(chunks, chunk_t);
330 construct.len += ch.len;
331 }
332 va_end(chunks);
333
334 /* allocate needed memory for construct */
335 pos = build_asn1_object(&construct, type, construct.len);
336
337 /* copy or move the chunks */
338 va_start(chunks, mode);
339 for (i = 0; i < count; i++)
340 {
341 chunk_t ch = va_arg(chunks, chunk_t);
342
343 switch (*mode++)
344 {
345 case 'm':
346 mv_chunk(&pos, ch);
347 break;
348 case 'c':
349 default:
350 chunkcpy(pos, ch);
351 }
352 }
353 va_end(chunks);
354
355 return construct;
356 }
357
358 /*
359 * convert a MP integer into a DER coded ASN.1 object
360 */
361 chunk_t
362 asn1_integer_from_mpz(const mpz_t value)
363 {
364 size_t bits = mpz_sizeinbase(value, 2); /* size in bits */
365 size_t size = 1 + bits / BITS_PER_BYTE; /* size in bytes */
366 chunk_t n = mpz_to_n(value, size);
367
368 return asn1_wrap(ASN1_INTEGER, "m", n);
369 }
370
371 /*
372 * determines if a character string is of type ASN.1 printableString
373 */
374 bool
375 is_printablestring(chunk_t str)
376 {
377 const char printablestring_charset[] =
378 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 '()+,-./:=?";
379 u_int i;
380
381 for (i = 0; i < str.len; i++)
382 {
383 if (strchr(printablestring_charset, str.ptr[i]) == NULL)
384 return FALSE;
385 }
386 return TRUE;
387 }
388
389 #define TIME_MAX 0x7fffffff
390
391 /*
392 * Converts ASN.1 UTCTIME or GENERALIZEDTIME into calender time
393 */
394 time_t
395 asn1totime(const chunk_t *utctime, asn1_t type)
396 {
397 struct tm t;
398 time_t tc, tz_offset;
399 u_char *eot = NULL;
400
401 if ((eot = memchr(utctime->ptr, 'Z', utctime->len)) != NULL)
402 {
403 tz_offset = 0; /* Zulu time with a zero time zone offset */
404 }
405 else if ((eot = memchr(utctime->ptr, '+', utctime->len)) != NULL)
406 {
407 int tz_hour, tz_min;
408
409 sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
410 tz_offset = 3600*tz_hour + 60*tz_min; /* positive time zone offset */
411 }
412 else if ((eot = memchr(utctime->ptr, '-', utctime->len)) != NULL)
413 {
414 int tz_hour, tz_min;
415
416 sscanf(eot+1, "%2d%2d", &tz_hour, &tz_min);
417 tz_offset = -3600*tz_hour - 60*tz_min; /* negative time zone offset */
418 }
419 else
420 {
421 return 0; /* error in time format */
422 }
423
424 /* parse ASN.1 time string */
425 {
426 const char* format = (type == ASN1_UTCTIME)? "%2d%2d%2d%2d%2d":
427 "%4d%2d%2d%2d%2d";
428
429 sscanf(utctime->ptr, format, &t.tm_year, &t.tm_mon, &t.tm_mday,
430 &t.tm_hour, &t.tm_min);
431 }
432
433 /* is there a seconds field? */
434 if ((eot - utctime->ptr) == ((type == ASN1_UTCTIME)?12:14))
435 {
436 sscanf(eot-2, "%2d", &t.tm_sec);
437 }
438 else
439 {
440 t.tm_sec = 0;
441 }
442
443 /* representation of year */
444 if (t.tm_year >= 1900)
445 {
446 t.tm_year -= 1900;
447 }
448 else if (t.tm_year >= 100)
449 {
450 return 0;
451 }
452 else if (t.tm_year < 50)
453 {
454 t.tm_year += 100;
455 }
456
457 /* representation of month 0..11*/
458 t.tm_mon--;
459
460 /* set daylight saving time to off */
461 t.tm_isdst = 0;
462
463 /* convert to time_t */
464 tc = mktime(&t);
465
466 /* if no conversion overflow occurred, compensate timezone */
467 return (tc == -1) ? TIME_MAX : (tc - timezone - tz_offset);
468 }
469
470 /*
471 * convert a date into ASN.1 UTCTIME or GENERALIZEDTIME format
472 */
473 chunk_t
474 timetoasn1(const time_t *time, asn1_t type)
475 {
476 int offset;
477 const char *format;
478 char buf[BUF_LEN];
479 chunk_t formatted_time;
480 struct tm *t = gmtime(time);
481
482 if (type == ASN1_GENERALIZEDTIME)
483 {
484 format = "%04d%02d%02d%02d%02d%02dZ";
485 offset = 1900;
486 }
487 else /* ASN1_UTCTIME */
488 {
489 format = "%02d%02d%02d%02d%02d%02dZ";
490 offset = (t->tm_year < 100)? 0 : -100;
491 }
492 sprintf(buf, format, t->tm_year + offset, t->tm_mon + 1, t->tm_mday
493 , t->tm_hour, t->tm_min, t->tm_sec);
494 formatted_time.ptr = buf;
495 formatted_time.len = strlen(buf);
496 return asn1_simple_object(type, formatted_time);
497 }
498
499
500 /*
501 * Initializes the internal context of the ASN.1 parser
502 */
503 void
504 asn1_init(asn1_ctx_t *ctx, chunk_t blob, u_int level0,
505 bool implicit, u_int cond)
506 {
507 ctx->blobs[0] = blob;
508 ctx->level0 = level0;
509 ctx->implicit = implicit;
510 ctx->cond = cond;
511 memset(ctx->loopAddr, '\0', sizeof(ctx->loopAddr));
512 }
513
514 /*
515 * print the value of an ASN.1 simple object
516 */
517 static void
518 debug_asn1_simple_object(chunk_t object, asn1_t type, u_int cond)
519 {
520 int oid;
521
522 switch (type)
523 {
524 case ASN1_OID:
525 oid = asn1_known_oid(object);
526 if (oid != OID_UNKNOWN)
527 {
528 DBG(DBG_PARSING,
529 DBG_log(" '%s'",oid_names[oid].name);
530 )
531 return;
532 }
533 break;
534 case ASN1_UTF8STRING:
535 case ASN1_IA5STRING:
536 case ASN1_PRINTABLESTRING:
537 case ASN1_T61STRING:
538 case ASN1_VISIBLESTRING:
539 DBG(DBG_PARSING,
540 DBG_log(" '%.*s'", (int)object.len, object.ptr);
541 )
542 return;
543 case ASN1_UTCTIME:
544 case ASN1_GENERALIZEDTIME:
545 DBG(DBG_PARSING,
546 time_t time = asn1totime(&object, type);
547 DBG_log(" '%T'", &time, TRUE);
548 )
549 return;
550 default:
551 break;
552 }
553 DBG(cond,
554 DBG_dump_chunk("", object);
555 )
556 }
557
558 /*
559 * Parses and extracts the next ASN.1 object
560 */
561 bool
562 extract_object(asn1Object_t const *objects,
563 u_int *objectID, chunk_t *object, u_int *level, asn1_ctx_t *ctx)
564 {
565 asn1Object_t obj = objects[*objectID];
566 chunk_t *blob;
567 chunk_t *blob1;
568 u_char *start_ptr;
569
570 *object = chunk_empty;
571
572 if (obj.flags & ASN1_END) /* end of loop or option found */
573 {
574 if (ctx->loopAddr[obj.level] && ctx->blobs[obj.level+1].len > 0)
575 {
576 *objectID = ctx->loopAddr[obj.level]; /* another iteration */
577 obj = objects[*objectID];
578 }
579 else
580 {
581 ctx->loopAddr[obj.level] = 0; /* exit loop or option*/
582 return TRUE;
583 }
584 }
585
586 *level = ctx->level0 + obj.level;
587 blob = ctx->blobs + obj.level;
588 blob1 = blob + 1;
589 start_ptr = blob->ptr;
590
591 /* handle ASN.1 defaults values */
592
593 if ((obj.flags & ASN1_DEF)
594 && (blob->len == 0 || *start_ptr != obj.type) )
595 {
596 /* field is missing */
597 DBG(DBG_PARSING,
598 DBG_log("L%d - %s:", *level, obj.name);
599 )
600 if (obj.type & ASN1_CONSTRUCTED)
601 {
602 (*objectID)++ ; /* skip context-specific tag */
603 }
604 return TRUE;
605 }
606
607 /* handle ASN.1 options */
608
609 if ((obj.flags & ASN1_OPT)
610 && (blob->len == 0 || *start_ptr != obj.type))
611 {
612 /* advance to end of missing option field */
613 do
614 (*objectID)++;
615 while (!((objects[*objectID].flags & ASN1_END)
616 && (objects[*objectID].level == obj.level)));
617 return TRUE;
618 }
619
620 /* an ASN.1 object must possess at least a tag and length field */
621
622 if (blob->len < 2)
623 {
624 DBG(DBG_PARSING,
625 DBG_log("L%d - %s: ASN.1 object smaller than 2 octets",
626 *level, obj.name);
627 )
628 return FALSE;
629 }
630
631 blob1->len = asn1_length(blob);
632
633 if (blob1->len == ASN1_INVALID_LENGTH || blob->len < blob1->len)
634 {
635 DBG(DBG_PARSING,
636 DBG_log("L%d - %s: length of ASN.1 object invalid or too large",
637 *level, obj.name);
638 )
639 return FALSE;
640 }
641
642 blob1->ptr = blob->ptr;
643 blob->ptr += blob1->len;
644 blob->len -= blob1->len;
645
646 /* return raw ASN.1 object without prior type checking */
647
648 if (obj.flags & ASN1_RAW)
649 {
650 DBG(DBG_PARSING,
651 DBG_log("L%d - %s:", *level, obj.name);
652 )
653 object->ptr = start_ptr;
654 object->len = (size_t)(blob->ptr - start_ptr);
655 return TRUE;
656 }
657
658 if (*start_ptr != obj.type && !(ctx->implicit && *objectID == 0))
659 {
660 DBG(DBG_PARSING,
661 DBG_log("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
662 *level, obj.name, obj.type, *start_ptr);
663 DBG_dump("", start_ptr, (u_int)(blob->ptr - start_ptr));
664 )
665 return FALSE;
666 }
667
668 DBG(DBG_PARSING,
669 DBG_log("L%d - %s:", ctx->level0+obj.level, obj.name);
670 )
671
672 /* In case of "SEQUENCE OF" or "SET OF" start a loop */
673
674 if (obj.flags & ASN1_LOOP)
675 {
676 if (blob1->len > 0)
677 {
678 /* at least one item, start the loop */
679 ctx->loopAddr[obj.level] = *objectID + 1;
680 }
681 else
682 {
683 /* no items, advance directly to end of loop */
684 do
685 (*objectID)++;
686 while (!((objects[*objectID].flags & ASN1_END)
687 && (objects[*objectID].level == obj.level)));
688 return TRUE;
689 }
690 }
691
692 if (obj.flags & ASN1_OBJ)
693 {
694 object->ptr = start_ptr;
695 object->len = (size_t)(blob->ptr - start_ptr);
696 DBG(ctx->cond,
697 DBG_dump_chunk("", *object);
698 )
699 }
700 else if (obj.flags & ASN1_BODY)
701 {
702 *object = *blob1;
703 debug_asn1_simple_object(*object, obj.type, ctx->cond);
704 }
705 return TRUE;
706 }
707
708 /*
709 * parse an ASN.1 simple type
710 */
711 bool
712 parse_asn1_simple_object(chunk_t *object, asn1_t type, u_int level
713 , const char* name)
714 {
715 size_t len;
716
717 /* an ASN.1 object must possess at least a tag and length field */
718 if (object->len < 2)
719 {
720 DBG(DBG_PARSING,
721 DBG_log("L%d - %s: ASN.1 object smaller than 2 octets",
722 level, name);
723 )
724 return FALSE;
725 }
726
727 if (*object->ptr != type)
728 {
729 DBG(DBG_PARSING,
730 DBG_log("L%d - %s: ASN1 tag 0x%02x expected, but is 0x%02x",
731 level, name, type, *object->ptr);
732 )
733 return FALSE;
734 }
735
736 len = asn1_length(object);
737
738 if (len == ASN1_INVALID_LENGTH || object->len < len)
739 {
740 DBG(DBG_PARSING,
741 DBG_log("L%d - %s: length of ASN.1 object invalid or too large",
742 level, name);
743 )
744 return FALSE;
745 }
746
747 DBG(DBG_PARSING,
748 DBG_log("L%d - %s:", level, name);
749 )
750 debug_asn1_simple_object(*object, type, DBG_RAW);
751 return TRUE;
752 }
753
754 /*
755 * extracts an algorithmIdentifier
756 */
757 int
758 parse_algorithmIdentifier(chunk_t blob, int level0, chunk_t *parameters)
759 {
760 asn1_ctx_t ctx;
761 chunk_t object;
762 u_int level;
763 int alg = OID_UNKNOWN;
764 int objectID = 0;
765
766 asn1_init(&ctx, blob, level0, FALSE, DBG_RAW);
767
768 while (objectID < ALGORITHM_ID_ROOF)
769 {
770 if (!extract_object(algorithmIdentifierObjects, &objectID, &object, &level, &ctx))
771 return alg;
772
773 switch (objectID)
774 {
775 case ALGORITHM_ID_ALG:
776 alg = asn1_known_oid(object);
777 break;
778 case ALGORITHM_ID_PARAMETERS:
779 if (parameters != NULL)
780 *parameters = object;
781 break;
782 default:
783 break;
784 }
785 objectID++;
786 }
787 return alg;
788 }
789
790 /*
791 * tests if a blob contains a valid ASN.1 set or sequence
792 */
793 bool
794 is_asn1(chunk_t blob)
795 {
796 u_int len;
797 u_char tag = *blob.ptr;
798
799 if (tag != ASN1_SEQUENCE && tag != ASN1_SET)
800 {
801 DBG(DBG_PARSING,
802 DBG_log(" file content is not binary ASN.1");
803 )
804 return FALSE;
805 }
806
807 len = asn1_length(&blob);
808
809 /* exact match */
810 if (len == blob.len)
811 {
812 return TRUE;
813 }
814
815 /* some websites append a surplus newline character to the blob */
816 if (len + 1 == blob.len && *(blob.ptr + len) == '\n')
817 {
818 return TRUE;
819 }
820
821 DBG(DBG_PARSING,
822 DBG_log(" file size does not match ASN.1 coded length");
823 )
824 return FALSE;
825 }