1 /* asn1-func.c - Fucntions for the ASN.1 data structures.
2 * Copyright (C) 2000, 2001 Fabio Fiorina
3 * Copyright (C) 2001 Free Software Foundation, Inc.
4 * Copyright (C) 2002, 2003, 2006, 2007, 2010, 2012 g10 Code GmbH
6 * KSBA is free software; you can redistribute it and/or modify
7 * it under the terms of either
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.
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.
19 * or both in parallel, as here.
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.
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/>.
31 #ifndef BUILD_GENTOOLS
42 # include "gen-help.h"
48 #include "asn1-func.h"
51 #define gpgrt_log_debug(...) /**/
55 static AsnNode resolve_identifier (AsnNode root, AsnNode node, int nestlevel);
59 add_node (node_type_t type)
63 punt = xmalloc (sizeof *punt);
68 punt->valuetype = VALTYPE_NULL;
69 punt->value.v_cstr = NULL;
75 punt->link_next = NULL;
80 _ksba_asn_new_node (node_type_t type)
82 return add_node (type);
87 _ksba_asn_is_primitive (node_type_t type)
94 case TYPE_OCTET_STRING:
97 case TYPE_OBJECT_DESCRIPTOR:
100 case TYPE_UTF8_STRING:
101 case TYPE_REALTIVE_OID:
102 case TYPE_NUMERIC_STRING:
103 case TYPE_PRINTABLE_STRING:
104 case TYPE_TELETEX_STRING:
105 case TYPE_VIDEOTEX_STRING:
106 case TYPE_IA5_STRING:
108 case TYPE_GENERALIZED_TIME:
109 case TYPE_GRAPHIC_STRING:
110 case TYPE_VISIBLE_STRING:
111 case TYPE_GENERAL_STRING:
112 case TYPE_UNIVERSAL_STRING:
113 case TYPE_CHARACTER_STRING:
114 case TYPE_BMP_STRING:
115 case TYPE_PRE_SEQUENCE:
123 /* Change the value field of the node to the content of buffer value
124 of size LEN. With VALUE of NULL or LEN of 0 and a VTYPE of
125 VALTYPE_NULL the value field is deleted */
127 _ksba_asn_set_value (AsnNode node,
128 enum asn_value_type vtype, const void *value, size_t len)
130 return_if_fail (node);
134 if (node->valuetype == VALTYPE_CSTR)
135 xfree (node->value.v_cstr);
136 else if (node->valuetype == VALTYPE_MEM)
137 xfree (node->value.v_mem.buf);
146 return_if_fail (len && value);
147 node->value.v_bool = !!*(const unsigned *)value;
150 return_if_fail (value);
151 node->value.v_cstr = xstrdup (value);
154 node->value.v_mem.len = len;
157 node->value.v_mem.buf = xmalloc (len);
158 memcpy (node->value.v_mem.buf, value, len);
161 node->value.v_mem.buf = NULL;
164 return_if_fail (sizeof (long) == len && value);
165 node->value.v_long = *(long *)value;
169 return_if_fail (sizeof (unsigned long) == len && value);
170 node->value.v_ulong = *(unsigned long *)value;
176 node->valuetype = vtype;
180 copy_value (AsnNode d, const AsnNode s)
183 const void *buf = NULL;
186 return_if_fail (d != s);
188 switch (s->valuetype)
194 helpbuf[0] = s->value.v_bool;
198 buf = s->value.v_cstr;
201 len = s->value.v_mem.len;
202 buf = len? s->value.v_mem.buf : NULL;
206 buf = &s->value.v_long;
209 len = sizeof (unsigned long);
210 buf = &s->value.v_ulong;
216 _ksba_asn_set_value (d, s->valuetype, buf, len);
223 copy_node (const AsnNode s)
225 AsnNode d = add_node (s->type);
228 d->name = xstrdup (s->name);
237 /* Change the name field of the node to NAME.
240 _ksba_asn_set_name (AsnNode node, const char *name)
242 return_if_fail (node);
251 node->name = xstrdup (name);
256 set_right (AsnNode node, AsnNode right)
269 set_down (AsnNode node, AsnNode down)
282 _ksba_asn_remove_node (AsnNode node)
288 if (node->valuetype == VALTYPE_CSTR)
289 xfree (node->value.v_cstr);
290 else if (node->valuetype == VALTYPE_MEM)
291 xfree (node->value.v_mem.buf);
296 /* find the node with the given name. A name part of "?LAST" matches
297 the last element of a SET_OF. A "+" matches the CHOICE with values
300 find_node (AsnNode root, const char *name, int resolve)
307 if (!name || !name[0])
310 /* gpgrt_log_debug ("%s: looking for '%s'\n", __func__, name); */
311 /* find the first part */
313 for (i=0; *s && *s != '.' && i < DIM(buf)-1; s++)
316 return_null_if_fail (i < DIM(buf)-1);
318 for (p = root; p && (!p->name || strcmp (p->name, buf)); p = p->right)
321 /* find other parts */
325 s++; /* skip the dot */
328 return NULL; /* not found */
331 for (i=0; *s && *s != '.' && i < DIM(buf)-1; s++)
334 return_null_if_fail (i < DIM(buf)-1);
338 /* a double dot can be used to get over an unnamed sequence
339 in a set - Actually a hack to workaround a bug. We should
340 rethink the entire node naming issue */
341 /* gpgrt_log_debug ("%s: .. to '%s'\n", __func__, p?p->name:""); */
343 else if (!strcmp (buf, "?LAST"))
350 else if (*buf == '+' && !buf[1])
352 for (; p ; p = p->right)
355 /* gpgrt_log_debug ("%s: + to '%s'\n", __func__, p?p->name:""); */
359 for (; p ; p = p->right)
361 /* gpgrt_log_debug ("%s: '%s' to '%s'\n", */
362 /* __func__, buf, p?p->name:""); */
363 if (p->name && !strcmp (p->name, buf))
365 if (resolve && p->name && p->type == TYPE_IDENTIFIER)
369 p2 = resolve_identifier (root, p, 0);
370 if (p2 && p2->name && !strcmp (p2->name, buf))
375 if (resolve && p && p->type == TYPE_IDENTIFIER)
376 p = resolve_identifier (root, p, 0);
384 _ksba_asn_find_node (AsnNode root, const char *name)
386 return find_node (root, name, 0);
391 _asn1_find_left (AsnNode node)
393 if ((node == NULL) || (node->left == NULL) || (node->left->down == node))
401 find_up (AsnNode node)
409 while ((p->left != NULL) && (p->left->right == p))
418 print_value (AsnNode node, FILE *fp)
420 if (!node->valuetype)
422 fprintf (fp, " vt=%d val=", node->valuetype);
423 switch (node->valuetype)
426 fputs (node->value.v_bool? "True":"False", fp);
429 fputs (node->value.v_cstr, fp);
435 for (p=node->value.v_mem.buf, n=node->value.v_mem.len; n; n--, p++)
436 fprintf (fp, "%02X", *p);
440 fprintf (fp, "%ld", node->value.v_long);
443 fprintf (fp, "%lu", node->value.v_ulong);
451 _ksba_asn_node_dump (AsnNode p, FILE *fp)
457 case TYPE_NULL: typestr = "NULL"; break;
458 case TYPE_CONSTANT: typestr = "CONST"; break;
459 case TYPE_IDENTIFIER: typestr = "IDENTIFIER"; break;
460 case TYPE_INTEGER: typestr = "INTEGER"; break;
461 case TYPE_ENUMERATED: typestr = "ENUMERATED"; break;
462 case TYPE_UTC_TIME: typestr = "UTCTIME"; break;
463 case TYPE_GENERALIZED_TIME: typestr = "GENERALIZEDTIME"; break;
464 case TYPE_BOOLEAN: typestr = "BOOLEAN"; break;
465 case TYPE_SEQUENCE: typestr = "SEQUENCE"; break;
466 case TYPE_PRE_SEQUENCE: typestr = "PRE_SEQUENCE"; break;
467 case TYPE_BIT_STRING: typestr = "BIT_STR"; break;
468 case TYPE_OCTET_STRING: typestr = "OCT_STR"; break;
469 case TYPE_TAG: typestr = "TAG"; break;
470 case TYPE_DEFAULT: typestr = "DEFAULT"; break;
471 case TYPE_SIZE: typestr = "SIZE"; break;
472 case TYPE_SEQUENCE_OF: typestr = "SEQ_OF"; break;
473 case TYPE_OBJECT_ID: typestr = "OBJ_ID"; break;
474 case TYPE_ANY: typestr = "ANY"; break;
475 case TYPE_SET: typestr = "SET"; break;
476 case TYPE_SET_OF: typestr = "SET_OF"; break;
477 case TYPE_CHOICE: typestr = "CHOICE"; break;
478 case TYPE_DEFINITIONS: typestr = "DEFINITIONS"; break;
479 case TYPE_UTF8_STRING: typestr = "UTF8_STRING"; break;
480 case TYPE_NUMERIC_STRING: typestr = "NUMERIC_STRING"; break;
481 case TYPE_PRINTABLE_STRING: typestr = "PRINTABLE_STRING"; break;
482 case TYPE_TELETEX_STRING: typestr = "TELETEX_STRING"; break;
483 case TYPE_IA5_STRING: typestr = "IA5_STRING"; break;
484 default: typestr = "ERROR\n"; break;
487 fprintf (fp, "%s", typestr);
489 fprintf (fp, " `%s'", p->name);
492 switch (p->flags.class)
494 case CLASS_UNIVERSAL: fputs ("U", fp); break;
495 case CLASS_PRIVATE: fputs ("P", fp); break;
496 case CLASS_APPLICATION: fputs ("A", fp); break;
497 case CLASS_CONTEXT: fputs ("C", fp); break;
500 if (p->flags.explicit)
501 fputs (",explicit", fp);
502 if (p->flags.implicit)
503 fputs (",implicit", fp);
504 if (p->flags.is_implicit)
505 fputs (",is_implicit", fp);
506 if (p->flags.has_tag)
508 if (p->flags.has_default)
509 fputs (",default", fp);
510 if (p->flags.is_true)
512 if (p->flags.is_false)
513 fputs (",false", fp);
514 if (p->flags.has_list)
516 if (p->flags.has_min_max)
517 fputs (",min_max", fp);
518 if (p->flags.is_optional)
519 fputs (",optional", fp);
520 if (p->flags.one_param)
521 fputs (",1_param", fp);
522 if (p->flags.has_size)
524 if (p->flags.has_defined_by)
525 fputs (",def_by", fp);
526 if (p->flags.has_imports)
527 fputs (",imports", fp);
528 if (p->flags.assignment)
529 fputs (",assign",fp);
531 fputs (",in_set",fp);
532 if (p->flags.in_choice)
533 fputs (",in_choice",fp);
534 if (p->flags.in_array)
535 fputs (",in_array",fp);
536 if (p->flags.not_used)
537 fputs (",not_used",fp);
538 if (p->flags.skip_this)
539 fputs (",[skip]",fp);
541 fputs (",is_any",fp);
543 fprintf (fp, " %d.%d.%d", p->off, p->nhdr, p->len );
548 _ksba_asn_node_dump_all (AsnNode root, FILE *fp)
555 fprintf (fp, "%*s", indent, "");
556 _ksba_asn_node_dump (p, fp);
593 * ksba_asn_tree_dump:
594 * @tree: A Parse Tree
595 * @name: Name of the element or NULL
596 * @fp: dump to this stream
598 * If the first character of the name is a '<' the expanded version of
599 * the tree will be printed.
601 * This function is a debugging aid.
604 ksba_asn_tree_dump (ksba_asn_tree_t tree, const char *name, FILE *fp)
607 int k, expand=0, indent = 0;
609 if (!tree || !tree->parse_tree)
612 if ( name && *name== '<')
620 root = name? _ksba_asn_find_node (tree->parse_tree, name) : tree->parse_tree;
625 root = _ksba_asn_expand_tree (root, NULL);
630 for (k = 0; k < indent; k++)
632 _ksba_asn_node_dump (p, fp);
668 _ksba_asn_release_nodes (root);
672 _ksba_asn_delete_structure (AsnNode root)
677 return gpg_error (GPG_ERR_ELEMENT_NOT_FOUND);
693 _ksba_asn_remove_node (p);
698 p3 = _asn1_find_left (p);
707 p->right->left = NULL;
712 _ksba_asn_remove_node (p);
721 /* check that all identifiers referenced in the tree are available */
723 _ksba_asn_check_identifier (AsnNode node)
729 return gpg_error (GPG_ERR_ELEMENT_NOT_FOUND);
731 for (p = node; p; p = _ksba_asn_walk_tree (node, p))
733 if (p->type == TYPE_IDENTIFIER && p->valuetype == VALTYPE_CSTR)
735 if (strlen (node->name)+strlen(p->value.v_cstr)+2 > DIM(name2))
736 return gpg_error (GPG_ERR_BUG); /* well identifier too long */
737 strcpy (name2, node->name);
739 strcat (name2, p->value.v_cstr);
740 p2 = _ksba_asn_find_node (node, name2);
743 fprintf (stderr,"reference to `%s' not found\n", name2);
744 return gpg_error (GPG_ERR_IDENTIFIER_NOT_FOUND);
746 /* fprintf (stdout,"found reference for `%s' (", name2); */
747 /* print_node (p2, stdout); */
748 /* fputs (")\n", stdout); */
750 else if (p->type == TYPE_OBJECT_ID && p->flags.assignment)
751 { /* an object ID in an assignment */
753 if (p2 && (p2->type == TYPE_CONSTANT))
755 if (p2->valuetype == VALTYPE_CSTR && !isdigit (p2->value.v_cstr[0]))
756 { /* the first constand below is a reference */
757 if (strlen (node->name)
758 +strlen(p->value.v_cstr)+2 > DIM(name2))
759 return gpg_error (GPG_ERR_BUG); /* well identifier too long */
760 strcpy (name2, node->name);
762 strcat (name2, p2->value.v_cstr);
763 p2 = _ksba_asn_find_node (node, name2);
766 fprintf (stderr,"object id reference `%s' not found\n",
768 return gpg_error (GPG_ERR_IDENTIFIER_NOT_FOUND);
770 else if ( p2->type != TYPE_OBJECT_ID
771 || !p2->flags.assignment )
773 fprintf (stderr,"`%s' is not an object id\n", name2);
774 return gpg_error (GPG_ERR_IDENTIFIER_NOT_FOUND);
776 /* fprintf (stdout,"found objid reference for `%s' (", name2); */
777 /* print_node (p2, stdout); */
778 /* fputs (")\n", stdout); */
788 /* Get the next node until root is reached in which case NULL is
791 _ksba_asn_walk_tree (AsnNode root, AsnNode node)
801 else if (node->right)
807 node = find_up (node);
826 _ksba_asn_walk_tree_up_right (AsnNode root, AsnNode node)
836 node = find_up (node);
854 /* walk over the tree and change the value type of all integer types
855 from string to long. */
857 _ksba_asn_change_integer_value (AsnNode node)
862 return gpg_error (GPG_ERR_ELEMENT_NOT_FOUND);
864 for (p = node; p; p = _ksba_asn_walk_tree (node, p))
866 if (p->type == TYPE_INTEGER && p->flags.assignment)
868 if (p->valuetype == VALTYPE_CSTR)
870 long val = strtol (p->value.v_cstr, NULL, 10);
871 _ksba_asn_set_value (p, VALTYPE_LONG, &val, sizeof(val));
881 /* Expand all object ID constants */
883 _ksba_asn_expand_object_id (AsnNode node)
885 AsnNode p, p2, p3, p4, p5;
886 char name_root[129], name2[129*2+1] = "";
888 /* Fixme: Make a cleaner implementation */
890 return gpg_error (GPG_ERR_ELEMENT_NOT_FOUND);
892 return gpg_error (GPG_ERR_INV_VALUE);
893 if (strlen(node->name) >= DIM(name_root)-1)
894 return gpg_error (GPG_ERR_GENERAL);
895 strcpy (name_root, node->name);
898 for (p = node; p; p = _ksba_asn_walk_tree (node, p))
900 if (p->type == TYPE_OBJECT_ID && p->flags.assignment)
903 if (p2 && p2->type == TYPE_CONSTANT)
905 if (p2->valuetype == VALTYPE_CSTR
906 && !isdigit (p2->value.v_cstr[0]))
908 if (strlen(p2->value.v_cstr)+1+strlen(name2) >= DIM(name2)-1)
909 return gpg_error (GPG_ERR_GENERAL);
910 strcpy (name2, name_root);
912 strcat (name2, p2->value.v_cstr);
913 p3 = _ksba_asn_find_node (node, name2);
914 if (!p3 || p3->type != TYPE_OBJECT_ID ||
915 !p3->flags.assignment)
916 return gpg_error (GPG_ERR_ELEMENT_NOT_FOUND);
917 set_down (p, p2->right);
918 _ksba_asn_remove_node (p2);
923 if (p4->type == TYPE_CONSTANT)
925 p5 = add_node (TYPE_CONSTANT);
926 _ksba_asn_set_name (p5, p4->name);
927 _ksba_asn_set_value (p5, VALTYPE_CSTR,
928 p4->value.v_cstr, 0);
931 set_right (p5, p->down);
936 set_right (p5, p2->right);
943 goto restart; /* the most simple way to get it right ;-) */
951 /* Walk the parse tree and set the default tag where appropriate. The
952 node must be of type DEFINITIONS */
954 _ksba_asn_set_default_tag (AsnNode node)
958 return_if_fail (node && node->type == TYPE_DEFINITIONS);
960 for (p = node; p; p = _ksba_asn_walk_tree (node, p))
962 if ( p->type == TYPE_TAG
963 && !p->flags.explicit && !p->flags.implicit)
965 if (node->flags.explicit)
966 p->flags.explicit = 1;
968 p->flags.implicit = 1;
971 /* now mark the nodes which are implicit */
972 for (p = node; p; p = _ksba_asn_walk_tree (node, p))
974 if ( p->type == TYPE_TAG && p->flags.implicit && p->down)
976 if (p->down->type == TYPE_CHOICE)
977 ; /* a CHOICE is per se implicit */
978 else if (p->down->type != TYPE_TAG)
979 p->down->flags.is_implicit = 1;
984 /* Walk the tree and set the is_set and not_used flags for all nodes below
985 a node of type SET. */
987 _ksba_asn_type_set_config (AsnNode node)
991 return_if_fail (node && node->type == TYPE_DEFINITIONS);
993 for (p = node; p; p = _ksba_asn_walk_tree (node, p))
995 if (p->type == TYPE_SET)
997 for (p2 = p->down; p2; p2 = p2->right)
999 if (p2->type != TYPE_TAG)
1001 p2->flags.in_set = 1;
1002 p2->flags.not_used = 1;
1006 else if (p->type == TYPE_CHOICE)
1008 for (p2 = p->down; p2; p2 = p2->right)
1010 p2->flags.in_choice = 1;
1013 else if (p->type == TYPE_SEQUENCE_OF || p->type == TYPE_SET_OF)
1015 for (p2 = p->down; p2; p2 = p2->right)
1016 p2->flags.in_array = 1;
1018 else if (p->type == TYPE_ANY)
1019 { /* Help the DER encoder to track ANY tags */
1020 p->flags.is_any = 1;
1025 /* Create a copy the tree at SRC_ROOT. s is a helper which should be
1026 set to SRC_ROOT by the caller */
1028 copy_tree (AsnNode src_root, AsnNode s)
1030 AsnNode first=NULL, dprev=NULL, d, down, tmp;
1031 AsnNode *link_nextp = NULL;
1033 for (; s; s=s->right )
1039 link_nextp = &d->link_next;
1051 tmp = copy_tree (src_root, down);
1056 link_nextp = &tmp->link_next;
1058 link_nextp = &(*link_nextp)->link_next;
1062 { /* Need to merge it with the existing down */
1065 for (x=d->down; x->right; x = x->right)
1084 resolve_identifier (AsnNode root, AsnNode node, int nestlevel)
1094 return_null_if_fail (root);
1095 return_null_if_fail (node->valuetype == VALTYPE_CSTR);
1097 bufsize = strlen (root->name) + strlen (node->value.v_cstr) + 2;
1098 if (bufsize <= sizeof buf_space)
1102 buf = xtrymalloc (bufsize);
1103 return_null_if_fail (buf);
1105 strcpy (stpcpy (stpcpy (buf, root->name), "."), node->value.v_cstr);
1106 n = _ksba_asn_find_node (root, buf);
1108 /* We do just a simple indirection. */
1109 if (n && n->type == TYPE_IDENTIFIER)
1110 n = resolve_identifier (root, n, nestlevel+1);
1112 if (buf != buf_space)
1120 do_expand_tree (AsnNode src_root, AsnNode s, int depth)
1122 AsnNode first=NULL, dprev=NULL, d, down, tmp;
1123 AsnNode *link_nextp = NULL;
1125 /* On the very first level we do not follow the right pointer so that
1126 we can break out a valid subtree. */
1127 for (; s; s=depth?s->right:NULL )
1129 if (s->type == TYPE_SIZE)
1130 continue; /* this node gets in the way all the time. It
1131 should be an attribute to a node */
1134 if (s->type == TYPE_IDENTIFIER)
1138 d = resolve_identifier (src_root, s, 0);
1141 fprintf (stderr, "RESOLVING IDENTIFIER FAILED\n");
1148 link_nextp = &d->link_next;
1149 if (s->flags.is_optional)
1150 d->flags.is_optional = 1;
1151 if (s->flags.in_choice)
1152 d->flags.in_choice = 1;
1153 if (s->flags.in_array)
1154 d->flags.in_array = 1;
1155 if (s->flags.is_implicit)
1156 d->flags.is_implicit = 1;
1157 if (s->flags.is_any)
1158 d->flags.is_any = 1;
1159 /* we don't want the resolved name - change it back */
1160 _ksba_asn_set_name (d, s->name);
1161 /* copy the default and tag attributes */
1164 for (s2=s->down; s2; s2=s2->right)
1171 link_nextp = &x->link_next;
1172 x->left = *dp? *dp : d;
1176 if (x->type == TYPE_TAG)
1177 d->flags.has_tag =1;
1178 else if (x->type == TYPE_DEFAULT)
1179 d->flags.has_default =1;
1188 link_nextp = &d->link_next;
1203 fprintf (stderr, "ASN.1 TREE TOO TALL!\n");
1208 tmp = do_expand_tree (src_root, down, depth+1);
1213 link_nextp = &tmp->link_next;
1215 link_nextp = &(*link_nextp)->link_next;
1219 { /* Need to merge it with the existing down */
1222 for (x=d->down; x->right; x = x->right)
1240 /* Expand the syntax tree so that all references are resolved and we
1241 are able to store values right in the tree (except for set/sequence
1242 of). This expanded tree is also an requirement for doing the DER
1243 decoding as the resolving of identifiers leads to a lot of
1244 problems. We use more memory of course, but this is negligible
1245 because the entire code will be simpler and faster */
1247 _ksba_asn_expand_tree (AsnNode parse_tree, const char *name)
1251 root = name? find_node (parse_tree, name, 1) : parse_tree;
1252 return do_expand_tree (parse_tree, root, 0);
1256 /* Insert a copy of the entire tree at NODE as the sibling of itself
1257 and return the copy */
1259 _ksba_asn_insert_copy (AsnNode node)
1262 AsnNode *link_nextp;
1264 n = copy_tree (node, node);
1266 return NULL; /* out of core */
1267 return_null_if_fail (n->right == node->right);
1271 /* FIXME: Consider tail pointer for faster insertion. */
1272 link_nextp = &node->link_next;
1274 link_nextp = &(*link_nextp)->link_next;
1281 /* Locate a type value sequence like
1284 type OBJECT IDENTIFIER
1288 below root and return the 'value' node. OIDBUF should contain the
1289 DER encoding of an OID value. idx is the number of OIDs to skip;
1290 this can be used to enumerate structures with the same OID */
1292 _ksba_asn_find_type_value (const unsigned char *image, AsnNode root, int idx,
1293 const void *oidbuf, size_t oidlen)
1297 if (!image || !root)
1300 for (n = root; n; n = _ksba_asn_walk_tree (root, n) )
1302 if ( n->type == TYPE_SEQUENCE
1303 && n->down && n->down->type == TYPE_OBJECT_ID)
1306 if (noid->off != -1 && noid->len == oidlen
1307 && !memcmp (image + noid->off + noid->nhdr, oidbuf, oidlen)