/* If OPTIONAL fields have not been initialized then * disable them. */ static void disable_optional_stuff(gnutls_x509_crt_t cert) { asn1_data_node_st n; asn1_node node; unsigned remove_subject_unique_id = 1; unsigned remove_issuer_unique_id = 1; node = asn1_find_node(cert->cert, "tbsCertificate.issuerUniqueID"); if (node) { if (asn1_read_node_value(node, &n) == ASN1_SUCCESS && n.value_len != 0) remove_issuer_unique_id = 0; } node = asn1_find_node(cert->cert, "tbsCertificate.subjectUniqueID"); if (node) { if (asn1_read_node_value(node, &n) == ASN1_SUCCESS && n.value_len != 0) remove_subject_unique_id = 0; } if (remove_issuer_unique_id) asn1_write_value(cert->cert, "tbsCertificate.issuerUniqueID", NULL, 0); if (remove_subject_unique_id) asn1_write_value(cert->cert, "tbsCertificate.subjectUniqueID", NULL, 0); if (cert->use_extensions == 0) { _gnutls_debug_log("Disabling X.509 extensions.\n"); asn1_write_value(cert->cert, "tbsCertificate.extensions", NULL, 0); } return; }
/** * asn1_delete_element: * @structure: pointer to the structure that contains the element you * want to delete. * @element_name: element's name you want to delete. * * Deletes the element named *@element_name inside *@structure. * * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if * the @element_name was not found. **/ asn1_retCode asn1_delete_element (ASN1_TYPE structure, const char *element_name) { ASN1_TYPE p2, p3, source_node; source_node = asn1_find_node (structure, element_name); if (source_node == ASN1_TYPE_EMPTY) return ASN1_ELEMENT_NOT_FOUND; p2 = source_node->right; p3 = _asn1_find_left (source_node); if (!p3) { p3 = _asn1_find_up (source_node); if (p3) _asn1_set_down (p3, p2); else if (source_node->right) source_node->right->left = NULL; } else _asn1_set_right (p3, p2); return asn1_delete_structure (&source_node); }
/** * asn1_number_of_elements: * @element: pointer to the root of an ASN1 structure. * @name: the name of a sub-structure of ROOT. * @num: pointer to an integer where the result will be stored * * Counts the number of elements of a sub-structure called NAME with * names equal to "?1","?2", ... * * Returns: %ASN1_SUCCESS if successful, %ASN1_ELEMENT_NOT_FOUND if * @name is not known, %ASN1_GENERIC_ERROR if pointer @num is %NULL. **/ asn1_retCode asn1_number_of_elements (ASN1_TYPE element, const char *name, int *num) { ASN1_TYPE node, p; if (num == NULL) return ASN1_GENERIC_ERROR; *num = 0; node = asn1_find_node (element, name); if (node == NULL) return ASN1_ELEMENT_NOT_FOUND; p = node->down; while (p) { if ((p->name) && (p->name[0] == '?')) (*num)++; p = p->right; } return ASN1_SUCCESS; }
static ASN1_TYPE _asn1_copy_structure2 (ASN1_TYPE root, const char *source_name) { ASN1_TYPE source_node; source_node = asn1_find_node (root, source_name); return _asn1_copy_structure3 (source_node); }
/** * asn1_copy_node: * @dst: Destination ASN1_TYPE node. * @dst_name: Field name in destination node. * @src: Source ASN1_TYPE node. * @src_name: Field name in source node. * * Create a deep copy of a ASN1_TYPE variable. * * Returns: Return %ASN1_SUCCESS on success. **/ asn1_retCode asn1_copy_node (ASN1_TYPE dst, const char *dst_name, ASN1_TYPE src, const char *src_name) { /* FIXME: rewrite using copy_structure(). * It seems quite hard to do. */ int result; ASN1_TYPE dst_node; void *data = NULL; int size = 0; result = asn1_der_coding (src, src_name, NULL, &size, NULL); if (result != ASN1_MEM_ERROR) return result; data = _asn1_malloc (size); if (data == NULL) return ASN1_MEM_ERROR; result = asn1_der_coding (src, src_name, data, &size, NULL); if (result != ASN1_SUCCESS) { _asn1_free (data); return result; } dst_node = asn1_find_node (dst, dst_name); if (dst_node == NULL) { _asn1_free (data); return ASN1_ELEMENT_NOT_FOUND; } result = asn1_der_decoding (&dst_node, data, size, NULL); _asn1_free (data); return result; }
/** * asn1_print_structure: * @out: pointer to the output file (e.g. stdout). * @structure: pointer to the structure that you want to visit. * @name: an element of the structure * @mode: specify how much of the structure to print, can be * %ASN1_PRINT_NAME, %ASN1_PRINT_NAME_TYPE, * %ASN1_PRINT_NAME_TYPE_VALUE, or %ASN1_PRINT_ALL. * * Prints on the @out file descriptor the structure's tree starting * from the @name element inside the structure @structure. **/ void asn1_print_structure (FILE * out, ASN1_TYPE structure, const char *name, int mode) { ASN1_TYPE p, root; int k, indent = 0, len, len2, len3; if (out == NULL) return; root = asn1_find_node (structure, name); if (root == NULL) return; p = root; while (p) { if (mode == ASN1_PRINT_ALL) { for (k = 0; k < indent; k++) fprintf (out, " "); fprintf (out, "name:"); if (p->name) fprintf (out, "%s ", p->name); else fprintf (out, "NULL "); } else { switch (type_field (p->type)) { case TYPE_CONSTANT: case TYPE_TAG: case TYPE_SIZE: break; default: for (k = 0; k < indent; k++) fprintf (out, " "); fprintf (out, "name:"); if (p->name) fprintf (out, "%s ", p->name); else fprintf (out, "NULL "); } } if (mode != ASN1_PRINT_NAME) { switch (type_field (p->type)) { case TYPE_CONSTANT: if (mode == ASN1_PRINT_ALL) fprintf (out, "type:CONST"); break; case TYPE_TAG: if (mode == ASN1_PRINT_ALL) fprintf (out, "type:TAG"); break; case TYPE_SIZE: if (mode == ASN1_PRINT_ALL) fprintf (out, "type:SIZE"); break; case TYPE_DEFAULT: fprintf (out, "type:DEFAULT"); break; case TYPE_NULL: fprintf (out, "type:NULL"); break; case TYPE_IDENTIFIER: fprintf (out, "type:IDENTIFIER"); break; case TYPE_INTEGER: fprintf (out, "type:INTEGER"); break; case TYPE_ENUMERATED: fprintf (out, "type:ENUMERATED"); break; case TYPE_TIME: fprintf (out, "type:TIME"); break; case TYPE_BOOLEAN: fprintf (out, "type:BOOLEAN"); break; case TYPE_SEQUENCE: fprintf (out, "type:SEQUENCE"); break; case TYPE_BIT_STRING: fprintf (out, "type:BIT_STR"); break; case TYPE_OCTET_STRING: fprintf (out, "type:OCT_STR"); break; case TYPE_GENERALSTRING: fprintf (out, "type:GENERALSTRING"); break; case TYPE_SEQUENCE_OF: fprintf (out, "type:SEQ_OF"); break; case TYPE_OBJECT_ID: fprintf (out, "type:OBJ_ID"); break; case TYPE_ANY: fprintf (out, "type:ANY"); break; case TYPE_SET: fprintf (out, "type:SET"); break; case TYPE_SET_OF: fprintf (out, "type:SET_OF"); break; case TYPE_CHOICE: fprintf (out, "type:CHOICE"); break; case TYPE_DEFINITIONS: fprintf (out, "type:DEFINITIONS"); break; default: break; } } if ((mode == ASN1_PRINT_NAME_TYPE_VALUE) || (mode == ASN1_PRINT_ALL)) { switch (type_field (p->type)) { case TYPE_CONSTANT: if (mode == ASN1_PRINT_ALL) if (p->value) fprintf (out, " value:%s", p->value); break; case TYPE_TAG: if (mode == ASN1_PRINT_ALL) if (p->value) fprintf (out, " value:%s", p->value); break; case TYPE_SIZE: if (mode == ASN1_PRINT_ALL) if (p->value) fprintf (out, " value:%s", p->value); break; case TYPE_DEFAULT: if (p->value) fprintf (out, " value:%s", p->value); else if (p->type & CONST_TRUE) fprintf (out, " value:TRUE"); else if (p->type & CONST_FALSE) fprintf (out, " value:FALSE"); break; case TYPE_IDENTIFIER: if (p->value) fprintf (out, " value:%s", p->value); break; case TYPE_INTEGER: if (p->value) { len2 = -1; len = asn1_get_length_der (p->value, p->value_len, &len2); fprintf (out, " value:0x"); if (len > 0) for (k = 0; k < len; k++) fprintf (out, "%02x", (p->value)[k + len2]); } break; case TYPE_ENUMERATED: if (p->value) { len2 = -1; len = asn1_get_length_der (p->value, p->value_len, &len2); fprintf (out, " value:0x"); if (len > 0) for (k = 0; k < len; k++) fprintf (out, "%02x", (p->value)[k + len2]); } break; case TYPE_TIME: if (p->value) fprintf (out, " value:%s", p->value); break; case TYPE_BOOLEAN: if (p->value) { if (p->value[0] == 'T') fprintf (out, " value:TRUE"); else if (p->value[0] == 'F') fprintf (out, " value:FALSE"); } break; case TYPE_BIT_STRING: if (p->value) { len2 = -1; len = asn1_get_length_der (p->value, p->value_len, &len2); if (len > 0) { fprintf (out, " value(%i):", (len - 1) * 8 - (p->value[len2])); for (k = 1; k < len; k++) fprintf (out, "%02x", (p->value)[k + len2]); } } break; case TYPE_OCTET_STRING: if (p->value) { len2 = -1; len = asn1_get_length_der (p->value, p->value_len, &len2); fprintf (out, " value:"); if (len > 0) for (k = 0; k < len; k++) fprintf (out, "%02x", (p->value)[k + len2]); } break; case TYPE_GENERALSTRING: if (p->value) { len2 = -1; len = asn1_get_length_der (p->value, p->value_len, &len2); fprintf (out, " value:"); if (len > 0) for (k = 0; k < len; k++) fprintf (out, "%02x", (p->value)[k + len2]); } break; case TYPE_OBJECT_ID: if (p->value) fprintf (out, " value:%s", p->value); break; case TYPE_ANY: if (p->value) { len3 = -1; len2 = asn1_get_length_der (p->value, p->value_len, &len3); fprintf (out, " value:"); if (len2 > 0) for (k = 0; k < len2; k++) fprintf (out, "%02x", (p->value)[k + len3]); } break; case TYPE_SET: case TYPE_SET_OF: case TYPE_CHOICE: case TYPE_DEFINITIONS: case TYPE_SEQUENCE_OF: case TYPE_SEQUENCE: case TYPE_NULL: break; default: break; } } if (mode == ASN1_PRINT_ALL) { if (p->type & 0x1FFFFF00) { fprintf (out, " attr:"); if (p->type & CONST_UNIVERSAL) fprintf (out, "UNIVERSAL,"); if (p->type & CONST_PRIVATE) fprintf (out, "PRIVATE,"); if (p->type & CONST_APPLICATION) fprintf (out, "APPLICATION,"); if (p->type & CONST_EXPLICIT) fprintf (out, "EXPLICIT,"); if (p->type & CONST_IMPLICIT) fprintf (out, "IMPLICIT,"); if (p->type & CONST_TAG) fprintf (out, "TAG,"); if (p->type & CONST_DEFAULT) fprintf (out, "DEFAULT,"); if (p->type & CONST_TRUE) fprintf (out, "TRUE,"); if (p->type & CONST_FALSE) fprintf (out, "FALSE,"); if (p->type & CONST_LIST) fprintf (out, "LIST,"); if (p->type & CONST_MIN_MAX) fprintf (out, "MIN_MAX,"); if (p->type & CONST_OPTION) fprintf (out, "OPTION,"); if (p->type & CONST_1_PARAM) fprintf (out, "1_PARAM,"); if (p->type & CONST_SIZE) fprintf (out, "SIZE,"); if (p->type & CONST_DEFINED_BY) fprintf (out, "DEF_BY,"); if (p->type & CONST_GENERALIZED) fprintf (out, "GENERALIZED,"); if (p->type & CONST_UTC) fprintf (out, "UTC,"); if (p->type & CONST_SET) fprintf (out, "SET,"); if (p->type & CONST_NOT_USED) fprintf (out, "NOT_USED,"); if (p->type & CONST_ASSIGN) fprintf (out, "ASSIGNMENT,"); } } if (mode == ASN1_PRINT_ALL) { fprintf (out, "\n"); } else { switch (type_field (p->type)) { case TYPE_CONSTANT: case TYPE_TAG: case TYPE_SIZE: break; default: fprintf (out, "\n"); } } if (p->down) { p = p->down; indent += 2; } else if (p == root) { p = NULL; break; } else if (p->right) p = p->right; else { while (1) { p = _asn1_find_up (p); if (p == root) { p = NULL; break; } indent -= 2; if (p->right) { p = p->right; break; } } } } }
asn1_retCode _asn1_check_identifier (ASN1_TYPE node) { ASN1_TYPE p, p2; char name2[ASN1_MAX_NAME_SIZE * 2 + 2]; if (node == NULL) return ASN1_ELEMENT_NOT_FOUND; p = node; while (p) { if (type_field (p->type) == TYPE_IDENTIFIER) { _asn1_str_cpy (name2, sizeof (name2), node->name); _asn1_str_cat (name2, sizeof (name2), "."); _asn1_str_cat (name2, sizeof (name2), (char *) p->value); p2 = asn1_find_node (node, name2); if (p2 == NULL) { _asn1_strcpy (_asn1_identifierMissing, p->value); return ASN1_IDENTIFIER_NOT_FOUND; } } else if ((type_field (p->type) == TYPE_OBJECT_ID) && (p->type & CONST_DEFAULT)) { p2 = p->down; if (p2 && (type_field (p2->type) == TYPE_DEFAULT)) { _asn1_str_cpy (name2, sizeof (name2), node->name); _asn1_str_cat (name2, sizeof (name2), "."); _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); _asn1_strcpy (_asn1_identifierMissing, p2->value); p2 = asn1_find_node (node, name2); if (!p2 || (type_field (p2->type) != TYPE_OBJECT_ID) || !(p2->type & CONST_ASSIGN)) return ASN1_IDENTIFIER_NOT_FOUND; else _asn1_identifierMissing[0] = 0; } } else if ((type_field (p->type) == TYPE_OBJECT_ID) && (p->type & CONST_ASSIGN)) { p2 = p->down; if (p2 && (type_field (p2->type) == TYPE_CONSTANT)) { if (p2->value && !isdigit (p2->value[0])) { _asn1_str_cpy (name2, sizeof (name2), node->name); _asn1_str_cat (name2, sizeof (name2), "."); _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); _asn1_strcpy (_asn1_identifierMissing, p2->value); p2 = asn1_find_node (node, name2); if (!p2 || (type_field (p2->type) != TYPE_OBJECT_ID) || !(p2->type & CONST_ASSIGN)) return ASN1_IDENTIFIER_NOT_FOUND; else _asn1_identifierMissing[0] = 0; } } } if (p->down) { p = p->down; } else if (p->right) p = p->right; else { while (1) { p = _asn1_find_up (p); if (p == node) { p = NULL; break; } if (p->right) { p = p->right; break; } } } } return ASN1_SUCCESS; }
asn1_retCode _asn1_expand_object_id (ASN1_TYPE node) { ASN1_TYPE p, p2, p3, p4, p5; char name_root[ASN1_MAX_NAME_SIZE], name2[2 * ASN1_MAX_NAME_SIZE + 1]; int move, tlen; if (node == NULL) return ASN1_ELEMENT_NOT_FOUND; _asn1_str_cpy (name_root, sizeof (name_root), node->name); p = node; move = DOWN; while (!((p == node) && (move == UP))) { if (move != UP) { if ((type_field (p->type) == TYPE_OBJECT_ID) && (p->type & CONST_ASSIGN)) { p2 = p->down; if (p2 && (type_field (p2->type) == TYPE_CONSTANT)) { if (p2->value && !isdigit (p2->value[0])) { _asn1_str_cpy (name2, sizeof (name2), name_root); _asn1_str_cat (name2, sizeof (name2), "."); _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); p3 = asn1_find_node (node, name2); if (!p3 || (type_field (p3->type) != TYPE_OBJECT_ID) || !(p3->type & CONST_ASSIGN)) return ASN1_ELEMENT_NOT_FOUND; _asn1_set_down (p, p2->right); _asn1_remove_node (p2); p2 = p; p4 = p3->down; while (p4) { if (type_field (p4->type) == TYPE_CONSTANT) { p5 = _asn1_add_node_only (TYPE_CONSTANT); _asn1_set_name (p5, p4->name); tlen = _asn1_strlen (p4->value); if (tlen > 0) _asn1_set_value (p5, p4->value, tlen + 1); if (p2 == p) { _asn1_set_right (p5, p->down); _asn1_set_down (p, p5); } else { _asn1_set_right (p5, p2->right); _asn1_set_right (p2, p5); } p2 = p5; } p4 = p4->right; } move = DOWN; continue; } } } move = DOWN; } else move = RIGHT; if (move == DOWN) { if (p->down) p = p->down; else move = RIGHT; } if (p == node) { move = UP; continue; } if (move == RIGHT) { if (p->right) p = p->right; else move = UP; } if (move == UP) p = _asn1_find_up (p); } /*******************************/ /* expand DEFAULT */ /*******************************/ p = node; move = DOWN; while (!((p == node) && (move == UP))) { if (move != UP) { if ((type_field (p->type) == TYPE_OBJECT_ID) && (p->type & CONST_DEFAULT)) { p2 = p->down; if (p2 && (type_field (p2->type) == TYPE_DEFAULT)) { _asn1_str_cpy (name2, sizeof (name2), name_root); _asn1_str_cat (name2, sizeof (name2), "."); _asn1_str_cat (name2, sizeof (name2), (char *) p2->value); p3 = asn1_find_node (node, name2); if (!p3 || (type_field (p3->type) != TYPE_OBJECT_ID) || !(p3->type & CONST_ASSIGN)) return ASN1_ELEMENT_NOT_FOUND; p4 = p3->down; name2[0] = 0; while (p4) { if (type_field (p4->type) == TYPE_CONSTANT) { if (name2[0]) _asn1_str_cat (name2, sizeof (name2), "."); _asn1_str_cat (name2, sizeof (name2), (char *) p4->value); } p4 = p4->right; } tlen = strlen (name2); if (tlen > 0) _asn1_set_value (p2, name2, tlen + 1); } } move = DOWN; } else move = RIGHT; if (move == DOWN) { if (p->down) p = p->down; else move = RIGHT; } if (p == node) { move = UP; continue; } if (move == RIGHT) { if (p->right) p = p->right; else move = UP; } if (move == UP) p = _asn1_find_up (p); } return ASN1_SUCCESS; }
/** * gnutls_x509_crl_iter_crt_serial: * @crl: should contain a #gnutls_x509_crl_t structure * @iter: A pointer to an iterator (initially the iterator should be %NULL) * @serial: where the serial number will be copied * @serial_size: initially holds the size of serial * @t: if non null, will hold the time this certificate was revoked * * This function performs the same as gnutls_x509_crl_get_crt_serial(), * but reads sequentially and keeps state in the iterator * between calls. That allows it to provide better performance in sequences * with many elements (50000+). * * When past the last element is accessed %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE * is returned and the iterator is reset. * * After use, the iterator must be deinitialized using gnutls_x509_crl_iter_deinit(). * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ int gnutls_x509_crl_iter_crt_serial(gnutls_x509_crl_t crl, gnutls_x509_crl_iter_t *iter, unsigned char *serial, size_t * serial_size, time_t * t) { int result, _serial_size; char serial_name[ASN1_MAX_NAME_SIZE]; char date_name[ASN1_MAX_NAME_SIZE]; if (crl == NULL || iter == NULL) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } if (*iter == NULL) { *iter = gnutls_calloc(1, sizeof(struct gnutls_x509_crl_iter)); if (*iter == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); } if ((*iter)->rcache == NULL) { (*iter)->rcache = asn1_find_node (crl->crl, "tbsCertList.revokedCertificates.?1"); (*iter)->rcache_idx = 1; } else { snprintf(serial_name, sizeof(serial_name), "?%d", (*iter)->rcache_idx); (*iter)->rcache = asn1_find_node ((*iter)->rcache, serial_name); } if ((*iter)->rcache == NULL) { /* reset */ (*iter)->rcache = NULL; return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE); } snprintf(serial_name, sizeof(serial_name), "?%d.userCertificate", (*iter)->rcache_idx); _serial_size = *serial_size; result = asn1_read_value((*iter)->rcache, serial_name, serial, &_serial_size); *serial_size = _serial_size; if (result != ASN1_SUCCESS) { gnutls_assert(); if (result == ASN1_ELEMENT_NOT_FOUND) { /* reset */ (*iter)->rcache = NULL; return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } return _gnutls_asn2err(result); } if (t) { snprintf(date_name, sizeof(date_name), "?%d.revocationDate", (*iter)->rcache_idx); *t = _gnutls_x509_get_time((*iter)->rcache, date_name, 0); } (*iter)->rcache_idx++; return 0; }
/** * gnutls_x509_dn_get_rdn_ava: * @dn: a pointer to DN * @irdn: index of RDN * @iava: index of AVA. * @ava: Pointer to structure which will hold output information. * * Get pointers to data within the DN. The format of the @ava structure * is shown below. * * struct gnutls_x509_ava_st { * gnutls_datum_t oid; * gnutls_datum_t value; * unsigned long value_tag; * }; * * The X.509 distinguished name is a sequence of sequences of strings * and this is what the @irdn and @iava indexes model. * * Note that @ava will contain pointers into the @dn structure which * in turns points to the original certificate. Thus you should not * modify any data or deallocate any of those. * * This is a low-level function that requires the caller to do the * value conversions when necessary (e.g. from UCS-2). * * Returns: Returns 0 on success, or an error code. **/ int gnutls_x509_dn_get_rdn_ava(gnutls_x509_dn_t dn, int irdn, int iava, gnutls_x509_ava_st * ava) { ASN1_TYPE rdn, elem; ASN1_DATA_NODE vnode; long len; int lenlen, remlen, ret; char rbuf[MAX_NAME_SIZE]; unsigned char cls; const unsigned char *ptr; iava++; irdn++; /* 0->1, 1->2 etc */ snprintf(rbuf, sizeof(rbuf), "rdnSequence.?%d.?%d", irdn, iava); rdn = asn1_find_node(dn->asn, rbuf); if (!rdn) { gnutls_assert(); return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND; } snprintf(rbuf, sizeof(rbuf), "?%d.type", iava); elem = asn1_find_node(rdn, rbuf); if (!elem) { gnutls_assert(); return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND; } ret = asn1_read_node_value(elem, &vnode); if (ret != ASN1_SUCCESS) { gnutls_assert(); return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND; } ava->oid.data = (void *) vnode.value; ava->oid.size = vnode.value_len; snprintf(rbuf, sizeof(rbuf), "?%d.value", iava); elem = asn1_find_node(rdn, rbuf); if (!elem) { gnutls_assert(); return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND; } ret = asn1_read_node_value(elem, &vnode); if (ret != ASN1_SUCCESS) { gnutls_assert(); return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND; } /* The value still has the previous tag's length bytes, plus the * current value's tag and length bytes. Decode them. */ ptr = vnode.value; remlen = vnode.value_len; len = asn1_get_length_der(ptr, remlen, &lenlen); if (len < 0) { gnutls_assert(); return GNUTLS_E_ASN1_DER_ERROR; } ptr += lenlen; remlen -= lenlen; ret = asn1_get_tag_der(ptr, remlen, &cls, &lenlen, &ava->value_tag); if (ret) { gnutls_assert(); return _gnutls_asn2err(ret); } ptr += lenlen; remlen -= lenlen; { signed long tmp; tmp = asn1_get_length_der(ptr, remlen, &lenlen); if (tmp < 0) { gnutls_assert(); return GNUTLS_E_ASN1_DER_ERROR; } ava->value.size = tmp; } ava->value.data = (void *) (ptr + lenlen); return 0; }