static int trust_list_get_issuer(gnutls_x509_trust_list_t list, gnutls_x509_crt_t cert, gnutls_x509_crt_t * issuer, unsigned int flags) { int ret; unsigned int i; uint32_t hash; hash = hash_pjw_bare(cert->raw_issuer_dn.data, cert->raw_issuer_dn.size); hash %= list->size; for (i = 0; i < list->node[hash].trusted_ca_size; i++) { ret = gnutls_x509_crt_check_issuer(cert, list->node[hash]. trusted_cas[i]); if (ret != 0) { if (flags & GNUTLS_TL_GET_COPY) { *issuer = crt_cpy(list->node[hash].trusted_cas[i]); } else { *issuer = list->node[hash].trusted_cas[i]; } return 0; } } return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; }
static int trust_list_get_issuer_by_dn(gnutls_x509_trust_list_t list, const gnutls_datum_t *dn, gnutls_x509_crt_t * issuer, unsigned int flags) { int ret; unsigned int i; uint32_t hash; hash = hash_pjw_bare(dn->data, dn->size); hash %= list->size; for (i = 0; i < list->node[hash].trusted_ca_size; i++) { ret = _gnutls_x509_compare_raw_dn(dn, &list->node[hash].trusted_cas[i]->raw_dn); if (ret != 0) { *issuer = crt_cpy(list->node[hash].trusted_cas[i]); return 0; } } return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; }
/** * gnutls_x509_trust_list_verify_named_crt: * @list: The structure of the list * @cert: is the certificate to be verified * @name: is the certificate's name * @name_size: is the certificate's name size * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations. * @voutput: will hold the certificate verification output. * @func: If non-null will be called on each chain element verification with the output. * * This function will try to find a certificate that is associated with the provided * name --see gnutls_x509_trust_list_add_named_crt(). If a match is found the * certificate is considered valid. In addition to that this function will also * check CRLs. The @voutput parameter will hold an OR'ed sequence of * %gnutls_certificate_status_t flags. * * Additionally a certificate verification profile can be specified * from the ones in %gnutls_certificate_verification_profiles_t by * ORing the result of GNUTLS_PROFILE_TO_VFLAGS() to the verification * flags. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.0.0 **/ int gnutls_x509_trust_list_verify_named_crt(gnutls_x509_trust_list_t list, gnutls_x509_crt_t cert, const void *name, size_t name_size, unsigned int flags, unsigned int *voutput, gnutls_verify_output_function func) { int ret; unsigned int i; uint32_t hash; hash = hash_pjw_bare(cert->raw_issuer_dn.data, cert->raw_issuer_dn.size); hash %= list->size; ret = check_if_in_blacklist(&cert, 1, list->blacklisted, list->blacklisted_size); if (ret != 0) { *voutput = 0; *voutput |= GNUTLS_CERT_REVOKED; *voutput |= GNUTLS_CERT_INVALID; return 0; } *voutput = GNUTLS_CERT_INVALID | GNUTLS_CERT_SIGNER_NOT_FOUND; for (i = 0; i < list->node[hash].named_cert_size; i++) { if (_gnutls_check_if_same_cert(cert, list->node[hash].named_certs[i].cert) != 0) { /* check if name matches */ if (list->node[hash].named_certs[i].name_size == name_size && memcmp(list->node[hash].named_certs[i].name, name, name_size) == 0) { *voutput = 0; break; } } } if (*voutput != 0 || (flags & GNUTLS_VERIFY_DISABLE_CRL_CHECKS)) return 0; /* Check revocation of individual certificates. * start with the last one that we already have its hash */ ret = _gnutls_x509_crt_check_revocation(cert, list->node[hash].crls, list->node[hash].crl_size, func); if (ret == 1) { /* revoked */ *voutput |= GNUTLS_CERT_REVOKED; *voutput |= GNUTLS_CERT_INVALID; return 0; } return 0; }
static int trust_list_get_issuer_by_dn(gnutls_x509_trust_list_t list, const gnutls_datum_t *dn, const gnutls_datum_t *spki, gnutls_x509_crt_t * issuer, unsigned int flags) { int ret; unsigned int i, j; uint32_t hash; uint8_t tmp[256]; size_t tmp_size; if (dn) { hash = hash_pjw_bare(dn->data, dn->size); hash %= list->size; for (i = 0; i < list->node[hash].trusted_ca_size; i++) { ret = _gnutls_x509_compare_raw_dn(dn, &list->node[hash].trusted_cas[i]->raw_dn); if (ret != 0) { if (spki && spki->size > 0) { tmp_size = sizeof(tmp); ret = gnutls_x509_crt_get_subject_key_id(list->node[hash].trusted_cas[i], tmp, &tmp_size, NULL); if (ret < 0) continue; if (spki->size != tmp_size || memcmp(spki->data, tmp, spki->size) != 0) continue; } *issuer = crt_cpy(list->node[hash].trusted_cas[i]); return 0; } } } else if (spki) { /* search everything! */ for (i = 0; i < list->size; i++) { for (j = 0; j < list->node[i].trusted_ca_size; j++) { tmp_size = sizeof(tmp); ret = gnutls_x509_crt_get_subject_key_id(list->node[i].trusted_cas[j], tmp, &tmp_size, NULL); if (ret < 0) continue; if (spki->size != tmp_size || memcmp(spki->data, tmp, spki->size) != 0) continue; *issuer = crt_cpy(list->node[i].trusted_cas[j]); return 0; } } } return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; }
/** * gnutls_x509_trust_list_add_crls: * @list: The structure of the list * @crl_list: A list of CRLs * @crl_size: The length of the CRL list * @flags: if GNUTLS_TL_VERIFY_CRL is given the CRLs will be verified before being added. * @verification_flags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL * * This function will add the given certificate revocation lists * to the trusted list. The list of CRLs must not be deinitialized * during this structure's lifetime. * * This function must be called after gnutls_x509_trust_list_add_cas() * to allow verifying the CRLs for validity. * * Returns: The number of added elements is returned. * * Since: 3.0 **/ int gnutls_x509_trust_list_add_crls(gnutls_x509_trust_list_t list, const gnutls_x509_crl_t * crl_list, int crl_size, unsigned int flags, unsigned int verification_flags) { int ret, i, j = 0; unsigned int vret = 0; uint32_t hash; /* Probably we can optimize things such as removing duplicates * etc. */ if (crl_size == 0 || crl_list == NULL) return 0; for (i = 0; i < crl_size; i++) { hash = hash_pjw_bare(crl_list[i]->raw_issuer_dn.data, crl_list[i]->raw_issuer_dn.size); hash %= list->size; if (flags & GNUTLS_TL_VERIFY_CRL) { ret = gnutls_x509_crl_verify(crl_list[i], list->node[hash]. trusted_cas, list->node[hash]. trusted_ca_size, verification_flags, &vret); if (ret < 0 || vret != 0) continue; } list->node[hash].crls = gnutls_realloc_fast(list->node[hash].crls, (list->node[hash].crl_size + 1) * sizeof(list->node[hash]. trusted_cas[0])); if (list->node[hash].crls == NULL) { gnutls_assert(); return i; } list->node[hash].crls[list->node[hash].crl_size] = crl_list[i]; list->node[hash].crl_size++; j++; } return j; }
asn1_node _asn1_set_name (asn1_node node, const char *name) { unsigned int nsize; if (node == NULL) return node; if (name == NULL) { node->name[0] = 0; node->name_hash = hash_pjw_bare (node->name, 0); return node; } nsize = _asn1_str_cpy (node->name, sizeof (node->name), name); node->name_hash = hash_pjw_bare (node->name, nsize); return node; }
/** * gnutls_x509_trust_list_remove_cas: * @list: The structure of the list * @clist: A list of CAs * @clist_size: The length of the CA list * * This function will remove the given certificate authorities * from the trusted list. * * Note that this function can accept certificates and authorities * not yet known. In that case they will be kept in a separate * black list that will be used during certificate verification. * Unlike gnutls_x509_trust_list_add_cas() there is no deinitialization * restriction for certificate list provided in this function. * * Returns: The number of removed elements is returned. * * Since: 3.1.10 **/ int gnutls_x509_trust_list_remove_cas(gnutls_x509_trust_list_t list, const gnutls_x509_crt_t * clist, int clist_size) { int i, r = 0; unsigned j; uint32_t hash; for (i = 0; i < clist_size; i++) { hash = hash_pjw_bare(clist[i]->raw_dn.data, clist[i]->raw_dn.size); hash %= list->size; for (j = 0; j < list->node[hash].trusted_ca_size; j++) { if (_gnutls_check_if_same_cert (clist[i], list->node[hash].trusted_cas[j]) != 0) { gnutls_x509_crt_deinit(list->node[hash]. trusted_cas[j]); list->node[hash].trusted_cas[j] = list->node[hash].trusted_cas[list-> node [hash]. trusted_ca_size - 1]; list->node[hash].trusted_ca_size--; r++; break; } } /* Add the CA (or plain) certificate to the black list as well. * This will prevent a subordinate CA from being valid, and * ensure that a server certificate will also get rejected. */ list->blacklisted = gnutls_realloc_fast(list->blacklisted, (list->blacklisted_size + 1) * sizeof(list->blacklisted[0])); if (list->blacklisted == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); list->blacklisted[list->blacklisted_size] = crt_cpy(clist[i]); if (list->blacklisted[list->blacklisted_size] != NULL) list->blacklisted_size++; } return r; }
/* Takes a certificate list and shortens it if there are * intermedia certificates already trusted by us. * * Returns the new size of the list or a negative number on error. */ static int shorten_clist(gnutls_x509_trust_list_t list, gnutls_x509_crt_t * certificate_list, unsigned int clist_size) { unsigned int j, i; uint32_t hash; if (clist_size > 1) { /* Check if the last certificate in the path is self signed. * In that case ignore it (a certificate is trusted only if it * leads to a trusted party by us, not the server's). * * This prevents from verifying self signed certificates against * themselves. This (although not bad) caused verification * failures on some root self signed certificates that use the * MD2 algorithm. */ if (gnutls_x509_crt_check_issuer (certificate_list[clist_size - 1], certificate_list[clist_size - 1]) != 0) { clist_size--; } } /* We want to shorten the chain by removing the cert that matches * one of the certs we trust and all the certs after that i.e. if * cert chain is A signed-by B signed-by C signed-by D (signed-by * self-signed E but already removed above), and we trust B, remove * B, C and D. */ for (i = 1; i < clist_size; i++) { hash = hash_pjw_bare(certificate_list[i]->raw_issuer_dn.data, certificate_list[i]->raw_issuer_dn.size); hash %= list->size; for (j = 0; j < list->node[hash].trusted_ca_size; j++) { if (_gnutls_check_if_same_cert (certificate_list[i], list->node[hash].trusted_cas[j]) != 0) { /* cut the list at the point of first the trusted certificate */ clist_size = i + 1; break; } } /* clist_size may have been changed which gets out of loop */ } return clist_size; }
asn1_node _asn1_cpy_name (asn1_node dst, asn1_node src) { if (dst == NULL) return dst; if (src == NULL) { dst->name[0] = 0; dst->name_hash = hash_pjw_bare (dst->name, 0); return dst; } _asn1_str_cpy (dst->name, sizeof (dst->name), src->name); dst->name_hash = src->name_hash; return dst; }
/* return 1 if @cert is in @list, 0 if not */ int _gnutls_trustlist_inlist(gnutls_x509_trust_list_t list, gnutls_x509_crt_t cert) { int ret; unsigned int i; uint32_t hash; hash = hash_pjw_bare(cert->raw_dn.data, cert->raw_dn.size); hash %= list->size; for (i = 0; i < list->node[hash].trusted_ca_size; i++) { ret = _gnutls_check_if_same_cert(cert, list->node[hash]. trusted_cas[i]); if (ret != 0) return 1; } return 0; }
/** * gnutls_x509_trust_list_add_named_crt: * @list: The structure of the list * @cert: A certificate * @name: An identifier for the certificate * @name_size: The size of the identifier * @flags: should be 0. * * This function will add the given certificate to the trusted * list and associate it with a name. The certificate will not be * be used for verification with gnutls_x509_trust_list_verify_crt() * but with gnutls_x509_trust_list_verify_named_crt() or * gnutls_x509_trust_list_verify_crt2() - the latter only since * GnuTLS 3.4.0 and if a hostname is provided. * * In principle this function can be used to set individual "server" * certificates that are trusted by the user for that specific server * but for no other purposes. * * The certificate must not be deinitialized during the lifetime * of the trusted list. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * * Since: 3.0.0 **/ int gnutls_x509_trust_list_add_named_crt(gnutls_x509_trust_list_t list, gnutls_x509_crt_t cert, const void *name, size_t name_size, unsigned int flags) { uint32_t hash; if (name_size >= MAX_SERVER_NAME_SIZE) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); hash = hash_pjw_bare(cert->raw_issuer_dn.data, cert->raw_issuer_dn.size); hash %= list->size; list->node[hash].named_certs = gnutls_realloc_fast(list->node[hash].named_certs, (list->node[hash].named_cert_size + 1) * sizeof(list->node[hash].named_certs[0])); if (list->node[hash].named_certs == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); list->node[hash].named_certs[list->node[hash].named_cert_size]. cert = cert; memcpy(list->node[hash]. named_certs[list->node[hash].named_cert_size].name, name, name_size); list->node[hash].named_certs[list->node[hash]. named_cert_size].name_size = name_size; list->node[hash].named_cert_size++; return 0; }
/** * gnutls_x509_trust_list_add_cas: * @list: The structure of the list * @clist: A list of CAs * @clist_size: The length of the CA list * @flags: should be 0 or an or'ed sequence of %GNUTLS_TL options. * * This function will add the given certificate authorities * to the trusted list. The list of CAs must not be deinitialized * during this structure's lifetime. * * If the flag %GNUTLS_TL_NO_DUPLICATES is specified, then * the provided @clist entries that are duplicates will not be * added to the list and will be deinitialized. * * Returns: The number of added elements is returned. * * Since: 3.0.0 **/ int gnutls_x509_trust_list_add_cas(gnutls_x509_trust_list_t list, const gnutls_x509_crt_t * clist, unsigned clist_size, unsigned int flags) { unsigned i, j; uint32_t hash; int ret; unsigned exists; for (i = 0; i < clist_size; i++) { exists = 0; hash = hash_pjw_bare(clist[i]->raw_dn.data, clist[i]->raw_dn.size); hash %= list->size; /* avoid duplicates */ if (flags & GNUTLS_TL_NO_DUPLICATES || flags & GNUTLS_TL_NO_DUPLICATE_KEY) { for (j=0;j<list->node[hash].trusted_ca_size;j++) { if (flags & GNUTLS_TL_NO_DUPLICATES) ret = _gnutls_check_if_same_cert(list->node[hash].trusted_cas[j], clist[i]); else ret = _gnutls_check_if_same_key(list->node[hash].trusted_cas[j], clist[i], 1); if (ret != 0) { exists = 1; break; } } if (exists != 0) { gnutls_x509_crt_deinit(list->node[hash].trusted_cas[j]); list->node[hash].trusted_cas[j] = clist[i]; continue; } } list->node[hash].trusted_cas = gnutls_realloc_fast(list->node[hash].trusted_cas, (list->node[hash].trusted_ca_size + 1) * sizeof(list->node[hash]. trusted_cas[0])); if (list->node[hash].trusted_cas == NULL) { gnutls_assert(); return i; } if (gnutls_x509_crt_get_version(clist[i]) >= 3 && gnutls_x509_crt_get_ca_status(clist[i], NULL) <= 0) { gnutls_datum_t dn; gnutls_assert(); if (gnutls_x509_crt_get_dn2(clist[i], &dn) >= 0) { _gnutls_audit_log(NULL, "There was a non-CA certificate in the trusted list: %s.\n", dn.data); gnutls_free(dn.data); } } list->node[hash].trusted_cas[list->node[hash]. trusted_ca_size] = clist[i]; list->node[hash].trusted_ca_size++; if (flags & GNUTLS_TL_USE_IN_TLS) { ret = add_new_ca_to_rdn_seq(list, clist[i]); if (ret < 0) { gnutls_assert(); return i; } } } return i; }
/** * gnutls_x509_trust_list_verify_crt2: * @list: The structure of the list * @cert_list: is the certificate list to be verified * @cert_list_size: is the certificate list size * @data: an array of typed data * @elements: the number of data elements * @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations. * @voutput: will hold the certificate verification output. * @func: If non-null will be called on each chain element verification with the output. * * This function will attempt to verify the given certificate and return * its status. The @voutput parameter will hold an OR'ed sequence of * %gnutls_certificate_status_t flags. When a chain of @cert_list_size with * more than one certificates is provided, the verification status will apply * to the first certificate in the chain that failed verification. The * verification process starts from the end of the chain (from CA to end * certificate). * * Additionally a certificate verification profile can be specified * from the ones in %gnutls_certificate_verification_profiles_t by * ORing the result of GNUTLS_PROFILE_TO_VFLAGS() to the verification * flags. * * The acceptable @data types are %GNUTLS_DT_DNS_HOSTNAME and %GNUTLS_DT_KEY_PURPOSE_OID. * The former accepts as data a null-terminated hostname, and the latter a null-terminated * object identifier (e.g., %GNUTLS_KP_TLS_WWW_SERVER). * If a DNS hostname is provided then this function will compare * the hostname in the certificate against the given. If names do not match the * %GNUTLS_CERT_UNEXPECTED_OWNER status flag will be set. In addition it * will consider certificates provided with gnutls_x509_trust_list_add_named_crt(). * * If a key purpose OID is provided and the end-certificate contains the extended key * usage PKIX extension, it will be required to match the provided OID * or be marked for any purpose, otherwise verification will fail with * %GNUTLS_CERT_PURPOSE_MISMATCH status. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. Note that verification failure will not result to an * error code, only @voutput will be updated. * * Since: 3.3.8 **/ int gnutls_x509_trust_list_verify_crt2(gnutls_x509_trust_list_t list, gnutls_x509_crt_t * cert_list, unsigned int cert_list_size, gnutls_typed_vdata_st *data, unsigned int elements, unsigned int flags, unsigned int *voutput, gnutls_verify_output_function func) { int ret; unsigned int i; uint32_t hash; gnutls_x509_crt_t sorted[DEFAULT_MAX_VERIFY_DEPTH]; const char *hostname = NULL, *purpose = NULL; unsigned hostname_size = 0; if (cert_list == NULL || cert_list_size < 1) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); for (i=0;i<elements;i++) { if (data[i].type == GNUTLS_DT_DNS_HOSTNAME) { hostname = (void*)data[i].data; if (data[i].size > 0) { hostname_size = data[i].size; } } else if (data[i].type == GNUTLS_DT_KEY_PURPOSE_OID) { purpose = (void*)data[i].data; } } if (hostname) { /* shortcut using the named certs - if any */ unsigned vtmp = 0; if (hostname_size == 0) hostname_size = strlen(hostname); ret = gnutls_x509_trust_list_verify_named_crt(list, cert_list[0], hostname, hostname_size, flags, &vtmp, func); if (ret == 0 && vtmp == 0) { *voutput = vtmp; return 0; } } if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_UNSORTED_CHAIN)) cert_list = _gnutls_sort_clist(sorted, cert_list, &cert_list_size, NULL); cert_list_size = shorten_clist(list, cert_list, cert_list_size); if (cert_list_size <= 0) return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR); hash = hash_pjw_bare(cert_list[cert_list_size - 1]->raw_issuer_dn. data, cert_list[cert_list_size - 1]->raw_issuer_dn.size); hash %= list->size; ret = check_if_in_blacklist(cert_list, cert_list_size, list->blacklisted, list->blacklisted_size); if (ret != 0) { *voutput = 0; *voutput |= GNUTLS_CERT_REVOKED; *voutput |= GNUTLS_CERT_INVALID; return 0; } *voutput = _gnutls_verify_crt_status(cert_list, cert_list_size, list->node[hash].trusted_cas, list-> node[hash].trusted_ca_size, flags, purpose, func); #define LAST_DN cert_list[cert_list_size-1]->raw_dn #define LAST_IDN cert_list[cert_list_size-1]->raw_issuer_dn if ((*voutput) & GNUTLS_CERT_SIGNER_NOT_FOUND && (LAST_DN.size != LAST_IDN.size || memcmp(LAST_DN.data, LAST_IDN.data, LAST_IDN.size) != 0)) { /* if we couldn't find the issuer, try to see if the last * certificate is in the trusted list and try to verify against * (if it is not self signed) */ hash = hash_pjw_bare(cert_list[cert_list_size - 1]->raw_dn. data, cert_list[cert_list_size - 1]->raw_dn.size); hash %= list->size; *voutput = _gnutls_verify_crt_status(cert_list, cert_list_size, list->node[hash].trusted_cas, list-> node[hash].trusted_ca_size, flags, purpose, func); } #ifdef ENABLE_PKCS11 if ((*voutput & GNUTLS_CERT_SIGNER_NOT_FOUND) && list->pkcs11_token) { /* use the token for verification */ *voutput = _gnutls_pkcs11_verify_crt_status(list->pkcs11_token, cert_list, cert_list_size, purpose, flags, func); if (*voutput != 0) { gnutls_assert(); } } #endif /* End-certificate, key purpose and hostname checks. */ if (purpose) { ret = _gnutls_check_key_purpose(cert_list[0], purpose, 0); if (ret != 1) { gnutls_assert(); *voutput |= GNUTLS_CERT_PURPOSE_MISMATCH|GNUTLS_CERT_INVALID; } } if (hostname) { ret = gnutls_x509_crt_check_hostname2(cert_list[0], hostname, flags); if (ret == 0) *voutput |= GNUTLS_CERT_UNEXPECTED_OWNER|GNUTLS_CERT_INVALID; } /* CRL checks follow */ if (*voutput != 0 || (flags & GNUTLS_VERIFY_DISABLE_CRL_CHECKS)) return 0; /* Check revocation of individual certificates. * start with the last one that we already have its hash */ ret = _gnutls_x509_crt_check_revocation(cert_list [cert_list_size - 1], list->node[hash].crls, list->node[hash].crl_size, func); if (ret == 1) { /* revoked */ *voutput |= GNUTLS_CERT_REVOKED; *voutput |= GNUTLS_CERT_INVALID; return 0; } for (i = 0; i < cert_list_size - 1; i++) { hash = hash_pjw_bare(cert_list[i]->raw_issuer_dn.data, cert_list[i]->raw_issuer_dn.size); hash %= list->size; ret = _gnutls_x509_crt_check_revocation(cert_list[i], list->node[hash]. crls, list->node[hash]. crl_size, func); if (ret < 0) { gnutls_assert(); } else if (ret == 1) { /* revoked */ *voutput |= GNUTLS_CERT_REVOKED; *voutput |= GNUTLS_CERT_INVALID; return 0; } } return 0; }
/** * asn1_find_node: * @pointer: NODE_ASN element pointer. * @name: null terminated string with the element's name to find. * * Searches for an element called @name starting from @pointer. The * name is composed by differents identifiers separated by dots. When * *@pointer has a name, the first identifier must be the name of * *@pointer, otherwise it must be the name of one child of *@pointer. * * Returns: the search result, or %NULL if not found. **/ asn1_node asn1_find_node (asn1_node pointer, const char *name) { asn1_node p; char *n_end, n[ASN1_MAX_NAME_SIZE + 1]; const char *n_start; unsigned int nsize; unsigned int nhash; if (pointer == NULL) return NULL; if (name == NULL) return NULL; p = pointer; n_start = name; if (p->name[0] != 0) { /* has *pointer got a name ? */ n_end = strchr (n_start, '.'); /* search the first dot */ if (n_end) { nsize = n_end - n_start; memcpy (n, n_start, nsize); n[nsize] = 0; n_start = n_end; n_start++; nhash = hash_pjw_bare (n, nsize); } else { nsize = _asn1_str_cpy (n, sizeof (n), n_start); nhash = hash_pjw_bare (n, nsize); n_start = NULL; } while (p) { if ((p->name) && nhash == p->name_hash && (!strcmp (p->name, n))) break; else p = p->right; } /* while */ if (p == NULL) return NULL; } else { /* *pointer doesn't have a name */ if (n_start[0] == 0) return p; } while (n_start) { /* Has the end of NAME been reached? */ n_end = strchr (n_start, '.'); /* search the next dot */ if (n_end) { nsize = n_end - n_start; memcpy (n, n_start, nsize); n[nsize] = 0; n_start = n_end; n_start++; nhash = hash_pjw_bare (n, nsize); } else { nsize = _asn1_str_cpy (n, sizeof (n), n_start); nhash = hash_pjw_bare (n, nsize); n_start = NULL; } if (p->down == NULL) return NULL; p = p->down; /* The identifier "?LAST" indicates the last element in the right chain. */ if (!strcmp (n, "?LAST")) { if (p == NULL) return NULL; while (p->right) p = p->right; } else { /* no "?LAST" */ while (p) { if (p->name_hash == nhash && !strcmp (p->name, n)) break; else p = p->right; } if (p == NULL) return NULL; } } /* while */ return p; }
/** * gnutls_x509_trust_list_add_crls: * @list: The list * @crl_list: A list of CRLs * @crl_size: The length of the CRL list * @flags: flags from %gnutls_trust_list_flags_t * @verification_flags: gnutls_certificate_verify_flags if flags specifies GNUTLS_TL_VERIFY_CRL * * This function will add the given certificate revocation lists * to the trusted list. The CRLs in @crl_list must not be deinitialized * during the lifetime of @list. * * This function must be called after gnutls_x509_trust_list_add_cas() * to allow verifying the CRLs for validity. If the flag %GNUTLS_TL_NO_DUPLICATES * is given, then the final CRL list will not contain duplicate entries. * * If the flag %GNUTLS_TL_NO_DUPLICATES is given, gnutls_x509_trust_list_deinit() must be * called with parameter @all being 1. * * If flag %GNUTLS_TL_VERIFY_CRL is given the CRLs will be verified before being added, * and if verification fails, they will be skipped. * * Returns: The number of added elements is returned; that includes * duplicate entries. * * Since: 3.0 **/ int gnutls_x509_trust_list_add_crls(gnutls_x509_trust_list_t list, const gnutls_x509_crl_t * crl_list, unsigned crl_size, unsigned int flags, unsigned int verification_flags) { int ret; unsigned x, i, j = 0; unsigned int vret = 0; uint32_t hash; gnutls_x509_crl_t *tmp; /* Probably we can optimize things such as removing duplicates * etc. */ if (crl_size == 0 || crl_list == NULL) return 0; for (i = 0; i < crl_size; i++) { hash = hash_pjw_bare(crl_list[i]->raw_issuer_dn.data, crl_list[i]->raw_issuer_dn.size); hash %= list->size; if (flags & GNUTLS_TL_VERIFY_CRL) { ret = gnutls_x509_crl_verify(crl_list[i], list->node[hash]. trusted_cas, list->node[hash]. trusted_ca_size, verification_flags, &vret); if (ret < 0 || vret != 0) { _gnutls_debug_log("CRL verification failed, not adding it\n"); if (flags & GNUTLS_TL_NO_DUPLICATES) gnutls_x509_crl_deinit(crl_list[i]); if (flags & GNUTLS_TL_FAIL_ON_INVALID_CRL) return gnutls_assert_val(GNUTLS_E_CRL_VERIFICATION_ERROR); continue; } } /* If the CRL added overrides a previous one, then overwrite * the old one */ if (flags & GNUTLS_TL_NO_DUPLICATES) { for (x=0;x<list->node[hash].crl_size;x++) { if (crl_list[i]->raw_issuer_dn.size == list->node[hash].crls[x]->raw_issuer_dn.size && memcmp(crl_list[i]->raw_issuer_dn.data, list->node[hash].crls[x]->raw_issuer_dn.data, crl_list[i]->raw_issuer_dn.size) == 0) { if (gnutls_x509_crl_get_this_update(crl_list[i]) >= gnutls_x509_crl_get_this_update(list->node[hash].crls[x])) { gnutls_x509_crl_deinit(list->node[hash].crls[x]); list->node[hash].crls[x] = crl_list[i]; goto next; } else { /* The new is older, discard it */ gnutls_x509_crl_deinit(crl_list[i]); goto next; } } } } tmp = gnutls_realloc(list->node[hash].crls, (list->node[hash].crl_size + 1) * sizeof(list->node[hash]. crls[0])); if (tmp == NULL) { ret = i; gnutls_assert(); if (flags & GNUTLS_TL_NO_DUPLICATES) while (i < crl_size) gnutls_x509_crl_deinit(crl_list[i++]); return ret; } list->node[hash].crls = tmp; list->node[hash].crls[list->node[hash].crl_size] = crl_list[i]; list->node[hash].crl_size++; next: j++; } return j; }