|
Packit |
549fdc |
/*
|
|
Packit |
549fdc |
* Copyright (C) 2003-2014 Free Software Foundation, Inc.
|
|
Packit |
549fdc |
* Copyright (C) 2013 Nikos Mavrogiannopoulos
|
|
Packit |
549fdc |
* Copyright (C) 2014 Red Hat
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Author: Nikos Mavrogiannopoulos
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This file is part of GnuTLS.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* The GnuTLS is free software; you can redistribute it and/or
|
|
Packit |
549fdc |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit |
549fdc |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
549fdc |
* the License, or (at your option) any later version.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This library is distributed in the hope that it will be useful, but
|
|
Packit |
549fdc |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
549fdc |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
549fdc |
* Lesser General Public License for more details.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* You should have received a copy of the GNU Lesser General Public License
|
|
Packit |
549fdc |
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* All functions which relate to X.509 certificate verification stuff are
|
|
Packit |
549fdc |
* included here
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
#include "gnutls_int.h"
|
|
Packit |
549fdc |
#include "errors.h"
|
|
Packit |
549fdc |
#include <libtasn1.h>
|
|
Packit |
549fdc |
#include <global.h>
|
|
Packit |
549fdc |
#include <num.h> /* MAX */
|
|
Packit |
549fdc |
#include <tls-sig.h>
|
|
Packit |
549fdc |
#include <str.h>
|
|
Packit |
549fdc |
#include <datum.h>
|
|
Packit |
549fdc |
#include <x509_int.h>
|
|
Packit |
549fdc |
#include <common.h>
|
|
Packit |
549fdc |
#include <pk.h>
|
|
Packit |
549fdc |
#include "supported_exts.h"
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Checks if two certs have the same name and the same key. Return 1 on match.
|
|
Packit |
549fdc |
* If @is_ca is zero then this function is identical to gnutls_x509_crt_equals()
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
unsigned
|
|
Packit |
549fdc |
_gnutls_check_if_same_key(gnutls_x509_crt_t cert1,
|
|
Packit |
549fdc |
gnutls_x509_crt_t cert2,
|
|
Packit |
549fdc |
unsigned is_ca)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int ret;
|
|
Packit |
549fdc |
unsigned result;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (is_ca == 0)
|
|
Packit |
549fdc |
return gnutls_x509_crt_equals(cert1, cert2);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = _gnutls_is_same_dn(cert1, cert2);
|
|
Packit |
549fdc |
if (ret == 0)
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (cert1->raw_spki.size > 0 && (cert1->raw_spki.size == cert2->raw_spki.size) &&
|
|
Packit |
549fdc |
(memcmp(cert1->raw_spki.data, cert2->raw_spki.data, cert1->raw_spki.size) == 0))
|
|
Packit |
549fdc |
result = 1;
|
|
Packit |
549fdc |
else
|
|
Packit |
549fdc |
result = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return result;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
unsigned
|
|
Packit |
549fdc |
_gnutls_check_if_same_key2(gnutls_x509_crt_t cert1,
|
|
Packit |
549fdc |
gnutls_datum_t * cert2bin)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int ret;
|
|
Packit |
549fdc |
gnutls_x509_crt_t cert2;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = gnutls_x509_crt_init(&cert2);
|
|
Packit |
549fdc |
if (ret < 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = gnutls_x509_crt_import(cert2, cert2bin, GNUTLS_X509_FMT_DER);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_x509_crt_deinit(cert2);
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = _gnutls_check_if_same_key(cert1, cert2, 1);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
gnutls_x509_crt_deinit(cert2);
|
|
Packit |
549fdc |
return ret;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* checks whether there are present unknown/unsupported critical extensions.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns true if they are present.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
static unsigned check_for_unknown_exts(gnutls_x509_crt_t cert)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
unsigned i;
|
|
Packit |
549fdc |
char oid[MAX_OID_SIZE];
|
|
Packit |
549fdc |
size_t oid_size;
|
|
Packit |
549fdc |
unsigned critical;
|
|
Packit |
549fdc |
int ret;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i=0;;i++) {
|
|
Packit |
549fdc |
oid_size = sizeof(oid);
|
|
Packit |
549fdc |
oid[0] = 0;
|
|
Packit |
549fdc |
critical = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = gnutls_x509_crt_get_extension_info(cert, i, oid, &oid_size, &critical);
|
|
Packit |
549fdc |
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
} else if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
/* could not decode? */
|
|
Packit |
549fdc |
_gnutls_debug_log("Could not decode extension %d\n", i);
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (critical == 0)
|
|
Packit |
549fdc |
continue;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (is_ext_oid_supported(oid, oid_size) == NULL) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
_gnutls_debug_log("Unsupported critical extension: %s\n", oid);
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Checks if the issuer of a certificate is a
|
|
Packit |
549fdc |
* Certificate Authority, or if the certificate is the same
|
|
Packit |
549fdc |
* as the issuer (and therefore it doesn't need to be a CA).
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns true or false, if the issuer is a CA,
|
|
Packit |
549fdc |
* or not.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
static unsigned
|
|
Packit |
549fdc |
check_if_ca(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer,
|
|
Packit |
549fdc |
unsigned int *max_path, unsigned int flags)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
gnutls_datum_t cert_signed_data = { NULL, 0 };
|
|
Packit |
549fdc |
gnutls_datum_t issuer_signed_data = { NULL, 0 };
|
|
Packit |
549fdc |
gnutls_datum_t cert_signature = { NULL, 0 };
|
|
Packit |
549fdc |
gnutls_datum_t issuer_signature = { NULL, 0 };
|
|
Packit |
549fdc |
int pathlen = -1, ret;
|
|
Packit |
549fdc |
unsigned result;
|
|
Packit |
549fdc |
unsigned int ca_status = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Check if the issuer is the same with the
|
|
Packit |
549fdc |
* certificate. This is added in order for trusted
|
|
Packit |
549fdc |
* certificates to be able to verify themselves.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
_gnutls_x509_get_signed_data(issuer->cert, &issuer->der, "tbsCertificate",
|
|
Packit |
549fdc |
&issuer_signed_data);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
goto fail;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
_gnutls_x509_get_signed_data(cert->cert, &cert->der, "tbsCertificate",
|
|
Packit |
549fdc |
&cert_signed_data);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
goto fail;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
_gnutls_x509_get_signature(issuer->cert, "signature",
|
|
Packit |
549fdc |
&issuer_signature);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
goto fail;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
_gnutls_x509_get_signature(cert->cert, "signature",
|
|
Packit |
549fdc |
&cert_signature);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
goto fail;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* If the subject certificate is the same as the issuer
|
|
Packit |
549fdc |
* return true.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME))
|
|
Packit |
549fdc |
if (cert_signed_data.size == issuer_signed_data.size) {
|
|
Packit |
549fdc |
if ((memcmp
|
|
Packit |
549fdc |
(cert_signed_data.data,
|
|
Packit |
549fdc |
issuer_signed_data.data,
|
|
Packit |
549fdc |
cert_signed_data.size) == 0)
|
|
Packit |
549fdc |
&& (cert_signature.size ==
|
|
Packit |
549fdc |
issuer_signature.size)
|
|
Packit |
549fdc |
&&
|
|
Packit |
549fdc |
(memcmp
|
|
Packit |
549fdc |
(cert_signature.data, issuer_signature.data,
|
|
Packit |
549fdc |
cert_signature.size) == 0)) {
|
|
Packit |
549fdc |
result = 1;
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
gnutls_x509_crt_get_basic_constraints(issuer, NULL, &ca_status,
|
|
Packit |
549fdc |
&pathlen);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
ca_status = 0;
|
|
Packit |
549fdc |
pathlen = -1;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (ca_status != 0 && pathlen != -1) {
|
|
Packit |
549fdc |
if ((unsigned) pathlen < *max_path)
|
|
Packit |
549fdc |
*max_path = pathlen;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (ca_status != 0) {
|
|
Packit |
549fdc |
result = 1;
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
/* Handle V1 CAs that do not have a basicConstraint, but accept
|
|
Packit |
549fdc |
these certs only if the appropriate flags are set. */
|
|
Packit |
549fdc |
else if ((ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) &&
|
|
Packit |
549fdc |
((flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT) ||
|
|
Packit |
549fdc |
(!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT) &&
|
|
Packit |
549fdc |
(gnutls_x509_crt_check_issuer(issuer, issuer) != 0)))) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
result = 1;
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
fail:
|
|
Packit |
549fdc |
result = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
cleanup:
|
|
Packit |
549fdc |
_gnutls_free_datum(&cert_signed_data);
|
|
Packit |
549fdc |
_gnutls_free_datum(&issuer_signed_data);
|
|
Packit |
549fdc |
_gnutls_free_datum(&cert_signature);
|
|
Packit |
549fdc |
_gnutls_free_datum(&issuer_signature);
|
|
Packit |
549fdc |
return result;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* This function checks if cert's issuer is issuer.
|
|
Packit |
549fdc |
* This does a straight (DER) compare of the issuer/subject DN fields in
|
|
Packit |
549fdc |
* the given certificates, as well as check the authority key ID.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns 1 if they match and (0) if they don't match.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
static unsigned is_issuer(gnutls_x509_crt_t cert, gnutls_x509_crt_t issuer)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
uint8_t id1[MAX_KEY_ID_SIZE];
|
|
Packit |
549fdc |
uint8_t id2[MAX_KEY_ID_SIZE];
|
|
Packit |
549fdc |
size_t id1_size;
|
|
Packit |
549fdc |
size_t id2_size;
|
|
Packit |
549fdc |
int ret;
|
|
Packit |
549fdc |
unsigned result;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (_gnutls_x509_compare_raw_dn
|
|
Packit |
549fdc |
(&cert->raw_issuer_dn, &issuer->raw_dn) != 0)
|
|
Packit |
549fdc |
result = 1;
|
|
Packit |
549fdc |
else
|
|
Packit |
549fdc |
result = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (result != 0) {
|
|
Packit |
549fdc |
/* check if the authority key identifier matches the subject key identifier
|
|
Packit |
549fdc |
* of the issuer */
|
|
Packit |
549fdc |
id1_size = sizeof(id1);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
gnutls_x509_crt_get_authority_key_id(cert, id1,
|
|
Packit |
549fdc |
&id1_size, NULL);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
/* If there is no authority key identifier in the
|
|
Packit |
549fdc |
* certificate, assume they match */
|
|
Packit |
549fdc |
result = 1;
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
id2_size = sizeof(id2);
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
gnutls_x509_crt_get_subject_key_id(issuer, id2,
|
|
Packit |
549fdc |
&id2_size, NULL);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
/* If there is no subject key identifier in the
|
|
Packit |
549fdc |
* issuer certificate, assume they match */
|
|
Packit |
549fdc |
result = 1;
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (id1_size == id2_size
|
|
Packit |
549fdc |
&& memcmp(id1, id2, id1_size) == 0)
|
|
Packit |
549fdc |
result = 1;
|
|
Packit |
549fdc |
else
|
|
Packit |
549fdc |
result = 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
cleanup:
|
|
Packit |
549fdc |
return result;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Check if the given certificate is the issuer of the CRL.
|
|
Packit |
549fdc |
* Returns 1 on success and 0 otherwise.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
static unsigned is_crl_issuer(gnutls_x509_crl_t crl, gnutls_x509_crt_t issuer)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
if (_gnutls_x509_compare_raw_dn
|
|
Packit |
549fdc |
(&crl->raw_issuer_dn, &issuer->raw_dn) != 0)
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
else
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Checks if the DN of two certificates is the same.
|
|
Packit |
549fdc |
* Returns 1 if they match and (0) if they don't match. Otherwise
|
|
Packit |
549fdc |
* a negative error code is returned to indicate error.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
unsigned _gnutls_is_same_dn(gnutls_x509_crt_t cert1, gnutls_x509_crt_t cert2)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
if (_gnutls_x509_compare_raw_dn(&cert1->raw_dn, &cert2->raw_dn) !=
|
|
Packit |
549fdc |
0)
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
else
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Finds an issuer of the certificate. If multiple issuers
|
|
Packit |
549fdc |
* are present, returns one that is activated and not expired.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
static inline gnutls_x509_crt_t
|
|
Packit |
549fdc |
find_issuer(gnutls_x509_crt_t cert,
|
|
Packit |
549fdc |
const gnutls_x509_crt_t * trusted_cas, int tcas_size)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int i;
|
|
Packit |
549fdc |
gnutls_x509_crt_t issuer = NULL;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* this is serial search.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
for (i = 0; i < tcas_size; i++) {
|
|
Packit |
549fdc |
if (is_issuer(cert, trusted_cas[i]) != 0) {
|
|
Packit |
549fdc |
if (issuer == NULL) {
|
|
Packit |
549fdc |
issuer = trusted_cas[i];
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
time_t now = gnutls_time(0);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (now <
|
|
Packit |
549fdc |
gnutls_x509_crt_get_expiration_time
|
|
Packit |
549fdc |
(trusted_cas[i])
|
|
Packit |
549fdc |
&& now >=
|
|
Packit |
549fdc |
gnutls_x509_crt_get_activation_time
|
|
Packit |
549fdc |
(trusted_cas[i])) {
|
|
Packit |
549fdc |
issuer = trusted_cas[i];
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return issuer;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static unsigned int check_time_status(gnutls_x509_crt_t crt, time_t now)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int status = 0;
|
|
Packit |
549fdc |
time_t t;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
t = gnutls_x509_crt_get_activation_time(crt);
|
|
Packit |
549fdc |
if (t == (time_t) - 1 || now < t) {
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_NOT_ACTIVATED;
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
return status;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
t = gnutls_x509_crt_get_expiration_time(crt);
|
|
Packit |
549fdc |
if (t == (time_t) - 1 || now > t) {
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_EXPIRED;
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
return status;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
unsigned _gnutls_is_broken_sig_allowed(const gnutls_sign_entry_st *se, unsigned int flags)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
gnutls_digest_algorithm_t hash;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* we have a catch all */
|
|
Packit |
549fdc |
if ((flags & GNUTLS_VERIFY_ALLOW_BROKEN) == GNUTLS_VERIFY_ALLOW_BROKEN)
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* the first two are for backwards compatibility */
|
|
Packit |
549fdc |
if ((se->id == GNUTLS_SIGN_RSA_MD2)
|
|
Packit |
549fdc |
&& (flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2))
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
if ((se->id == GNUTLS_SIGN_RSA_MD5)
|
|
Packit |
549fdc |
&& (flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5))
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
hash = se->hash;
|
|
Packit |
549fdc |
if (hash == GNUTLS_DIG_SHA1 && (flags & GNUTLS_VERIFY_ALLOW_SIGN_WITH_SHA1))
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
#define CASE_SEC_PARAM(profile, level) \
|
|
Packit |
549fdc |
case profile: \
|
|
Packit |
549fdc |
sym_bits = gnutls_sec_param_to_symmetric_bits(level); \
|
|
Packit |
549fdc |
hash = gnutls_sign_get_hash_algorithm(sigalg); \
|
|
Packit |
549fdc |
entry = mac_to_entry(hash); \
|
|
Packit |
549fdc |
if (hash <= 0 || entry == NULL) { \
|
|
Packit |
549fdc |
_gnutls_cert_log("cert", crt); \
|
|
Packit |
549fdc |
_gnutls_debug_log(#level": certificate's signature hash is unknown\n"); \
|
|
Packit |
549fdc |
return gnutls_assert_val(0); \
|
|
Packit |
549fdc |
} \
|
|
Packit |
549fdc |
if (entry->output_size*8/2 < sym_bits) { \
|
|
Packit |
549fdc |
_gnutls_cert_log("cert", crt); \
|
|
Packit |
549fdc |
_gnutls_debug_log(#level": certificate's signature hash strength is unacceptable (is %u bits, needed %u)\n", entry->output_size*8/2, sym_bits); \
|
|
Packit |
549fdc |
return gnutls_assert_val(0); \
|
|
Packit |
549fdc |
} \
|
|
Packit |
549fdc |
sp = gnutls_pk_bits_to_sec_param(pkalg, bits); \
|
|
Packit |
549fdc |
if (sp < level) { \
|
|
Packit |
549fdc |
_gnutls_cert_log("cert", crt); \
|
|
Packit |
549fdc |
_gnutls_debug_log(#level": certificate's security level is unacceptable\n"); \
|
|
Packit |
549fdc |
return gnutls_assert_val(0); \
|
|
Packit |
549fdc |
} \
|
|
Packit |
549fdc |
if (issuer) { \
|
|
Packit |
549fdc |
sp = gnutls_pk_bits_to_sec_param(issuer_pkalg, issuer_bits); \
|
|
Packit |
549fdc |
if (sp < level) { \
|
|
Packit |
549fdc |
_gnutls_cert_log("issuer", issuer); \
|
|
Packit |
549fdc |
_gnutls_debug_log(#level": certificate's issuer security level is unacceptable\n"); \
|
|
Packit |
549fdc |
return gnutls_assert_val(0); \
|
|
Packit |
549fdc |
} \
|
|
Packit |
549fdc |
} \
|
|
Packit |
549fdc |
break;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Checks whether the provided certificates are acceptable
|
|
Packit |
549fdc |
* according to verification profile specified.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* @crt: a certificate
|
|
Packit |
549fdc |
* @issuer: the certificates issuer (allowed to be NULL)
|
|
Packit |
549fdc |
* @sigalg: the signature algorithm used
|
|
Packit |
549fdc |
* @flags: the specified verification flags
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
static unsigned is_level_acceptable(
|
|
Packit |
549fdc |
gnutls_x509_crt_t crt, gnutls_x509_crt_t issuer,
|
|
Packit |
549fdc |
gnutls_sign_algorithm_t sigalg, unsigned flags)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
gnutls_certificate_verification_profiles_t profile = GNUTLS_VFLAGS_TO_PROFILE(flags);
|
|
Packit |
549fdc |
const mac_entry_st *entry;
|
|
Packit |
549fdc |
int issuer_pkalg = 0, pkalg, ret;
|
|
Packit |
549fdc |
unsigned bits = 0, issuer_bits = 0, sym_bits = 0;
|
|
Packit |
549fdc |
gnutls_pk_params_st params;
|
|
Packit |
549fdc |
gnutls_sec_param_t sp;
|
|
Packit |
549fdc |
int hash;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (profile == 0)
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
pkalg = gnutls_x509_crt_get_pk_algorithm(crt, &bits);
|
|
Packit |
549fdc |
if (pkalg < 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (issuer) {
|
|
Packit |
549fdc |
issuer_pkalg = gnutls_x509_crt_get_pk_algorithm(issuer, &issuer_bits);
|
|
Packit |
549fdc |
if (issuer_pkalg < 0)
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
switch (profile) {
|
|
Packit |
549fdc |
CASE_SEC_PARAM(GNUTLS_PROFILE_VERY_WEAK, GNUTLS_SEC_PARAM_VERY_WEAK);
|
|
Packit |
549fdc |
CASE_SEC_PARAM(GNUTLS_PROFILE_LOW, GNUTLS_SEC_PARAM_LOW);
|
|
Packit |
549fdc |
CASE_SEC_PARAM(GNUTLS_PROFILE_LEGACY, GNUTLS_SEC_PARAM_LEGACY);
|
|
Packit |
549fdc |
CASE_SEC_PARAM(GNUTLS_PROFILE_MEDIUM, GNUTLS_SEC_PARAM_MEDIUM);
|
|
Packit |
549fdc |
CASE_SEC_PARAM(GNUTLS_PROFILE_HIGH, GNUTLS_SEC_PARAM_HIGH);
|
|
Packit |
549fdc |
CASE_SEC_PARAM(GNUTLS_PROFILE_ULTRA, GNUTLS_SEC_PARAM_ULTRA);
|
|
Packit |
549fdc |
case GNUTLS_PROFILE_SUITEB128:
|
|
Packit |
549fdc |
case GNUTLS_PROFILE_SUITEB192: {
|
|
Packit |
549fdc |
unsigned curve, issuer_curve;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* check suiteB params validity: rfc5759 */
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (gnutls_x509_crt_get_version(crt) != 3) {
|
|
Packit |
549fdc |
_gnutls_debug_log("SUITEB: certificate uses an unacceptable version number\n");
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (sigalg != GNUTLS_SIGN_ECDSA_SHA256 && sigalg != GNUTLS_SIGN_ECDSA_SHA384) {
|
|
Packit |
549fdc |
_gnutls_debug_log("SUITEB: certificate is not signed using ECDSA-SHA256 or ECDSA-SHA384\n");
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (pkalg != GNUTLS_PK_EC) {
|
|
Packit |
549fdc |
_gnutls_debug_log("SUITEB: certificate does not contain ECC parameters\n");
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (issuer_pkalg != GNUTLS_PK_EC) {
|
|
Packit |
549fdc |
_gnutls_debug_log("SUITEB: certificate's issuer does not have ECC parameters\n");
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = _gnutls_x509_crt_get_mpis(crt, ¶ms);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
_gnutls_debug_log("SUITEB: cannot read certificate params\n");
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
curve = params.curve;
|
|
Packit |
549fdc |
gnutls_pk_params_release(¶ms);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (curve != GNUTLS_ECC_CURVE_SECP256R1 &&
|
|
Packit |
549fdc |
curve != GNUTLS_ECC_CURVE_SECP384R1) {
|
|
Packit |
549fdc |
_gnutls_debug_log("SUITEB: certificate's ECC params do not contain SECP256R1 or SECP384R1\n");
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (profile == GNUTLS_PROFILE_SUITEB192) {
|
|
Packit |
549fdc |
if (curve != GNUTLS_ECC_CURVE_SECP384R1) {
|
|
Packit |
549fdc |
_gnutls_debug_log("SUITEB192: certificate does not use SECP384R1\n");
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (issuer != NULL) {
|
|
Packit |
549fdc |
if (gnutls_x509_crt_get_version(issuer) != 3) {
|
|
Packit |
549fdc |
_gnutls_debug_log("SUITEB: certificate's issuer uses an unacceptable version number\n");
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = _gnutls_x509_crt_get_mpis(issuer, ¶ms);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
_gnutls_debug_log("SUITEB: cannot read certificate params\n");
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
issuer_curve = params.curve;
|
|
Packit |
549fdc |
gnutls_pk_params_release(¶ms);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (issuer_curve != GNUTLS_ECC_CURVE_SECP256R1 &&
|
|
Packit |
549fdc |
issuer_curve != GNUTLS_ECC_CURVE_SECP384R1) {
|
|
Packit |
549fdc |
_gnutls_debug_log("SUITEB: certificate's issuer ECC params do not contain SECP256R1 or SECP384R1\n");
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (issuer_curve < curve) {
|
|
Packit |
549fdc |
_gnutls_debug_log("SUITEB: certificate's issuer ECC params are weaker than the certificate's\n");
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (sigalg == GNUTLS_SIGN_ECDSA_SHA256 &&
|
|
Packit |
549fdc |
issuer_curve == GNUTLS_ECC_CURVE_SECP384R1) {
|
|
Packit |
549fdc |
_gnutls_debug_log("SUITEB: certificate is signed with ECDSA-SHA256 when using SECP384R1\n");
|
|
Packit |
549fdc |
return gnutls_assert_val(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
break;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
typedef struct verify_state_st {
|
|
Packit |
549fdc |
time_t now;
|
|
Packit |
549fdc |
unsigned int max_path;
|
|
Packit |
549fdc |
gnutls_x509_name_constraints_t nc;
|
|
Packit |
549fdc |
gnutls_x509_tlsfeatures_t tls_feat;
|
|
Packit |
549fdc |
gnutls_verify_output_function *func;
|
|
Packit |
549fdc |
} verify_state_st;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
#define MARK_INVALID(x) { gnutls_assert(); \
|
|
Packit |
549fdc |
out |= (x|GNUTLS_CERT_INVALID); \
|
|
Packit |
549fdc |
result = 0; }
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static int _gnutls_x509_verify_data(gnutls_sign_algorithm_t sign,
|
|
Packit |
549fdc |
const gnutls_datum_t * data,
|
|
Packit |
549fdc |
const gnutls_datum_t * signature,
|
|
Packit |
549fdc |
gnutls_x509_crt_t cert,
|
|
Packit |
549fdc |
gnutls_x509_crt_t issuer,
|
|
Packit |
549fdc |
unsigned vflags);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/*
|
|
Packit |
549fdc |
* Verifies the given certificate against a certificate list of
|
|
Packit |
549fdc |
* trusted CAs.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns only 0 or 1. If 1 it means that the certificate
|
|
Packit |
549fdc |
* was successfuly verified.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* 'flags': an OR of the gnutls_certificate_verify_flags enumeration.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Output will hold some extra information about the verification
|
|
Packit |
549fdc |
* procedure.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
static unsigned
|
|
Packit |
549fdc |
verify_crt(gnutls_x509_crt_t cert,
|
|
Packit |
549fdc |
const gnutls_x509_crt_t * trusted_cas,
|
|
Packit |
549fdc |
int tcas_size, unsigned int flags,
|
|
Packit |
549fdc |
unsigned int *output,
|
|
Packit |
549fdc |
verify_state_st *vparams,
|
|
Packit |
549fdc |
unsigned end_cert)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
gnutls_datum_t cert_signed_data = { NULL, 0 };
|
|
Packit |
549fdc |
gnutls_datum_t cert_signature = { NULL, 0 };
|
|
Packit |
549fdc |
gnutls_x509_crt_t issuer = NULL;
|
|
Packit |
549fdc |
int issuer_version;
|
|
Packit |
549fdc |
unsigned result = 1;
|
|
Packit |
549fdc |
unsigned int out = 0, usage;
|
|
Packit |
549fdc |
int sigalg, ret;
|
|
Packit |
549fdc |
const gnutls_sign_entry_st *se;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (output)
|
|
Packit |
549fdc |
*output = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (vparams->max_path == 0) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
|
|
Packit |
549fdc |
/* bail immediately, to avoid inconistency */
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
vparams->max_path--;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (tcas_size >= 1)
|
|
Packit |
549fdc |
issuer = find_issuer(cert, trusted_cas, tcas_size);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
_gnutls_x509_get_signed_data(cert->cert, &cert->der, "tbsCertificate",
|
|
Packit |
549fdc |
&cert_signed_data);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
MARK_INVALID(0);
|
|
Packit |
549fdc |
cert_signed_data.data = NULL;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
_gnutls_x509_get_signature(cert->cert, "signature",
|
|
Packit |
549fdc |
&cert_signature);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
MARK_INVALID(0);
|
|
Packit |
549fdc |
cert_signature.data = NULL;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
_gnutls_x509_get_signature_algorithm(cert->cert,
|
|
Packit |
549fdc |
"signatureAlgorithm");
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
MARK_INVALID(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
sigalg = ret;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
se = _gnutls_sign_to_entry(sigalg);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* issuer is not in trusted certificate
|
|
Packit |
549fdc |
* authorities.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
if (issuer == NULL) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_SIGNER_NOT_FOUND);
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
if (vparams->nc != NULL) {
|
|
Packit |
549fdc |
/* append the issuer's constraints */
|
|
Packit |
549fdc |
ret = gnutls_x509_crt_get_name_constraints(issuer, vparams->nc,
|
|
Packit |
549fdc |
GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND, NULL);
|
|
Packit |
549fdc |
if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
|
|
Packit |
549fdc |
goto nc_done;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* only check name constraints in server certificates, not CAs */
|
|
Packit |
549fdc |
if (end_cert != 0) {
|
|
Packit |
549fdc |
ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_DNSNAME, cert);
|
|
Packit |
549fdc |
if (ret == 0) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
|
|
Packit |
549fdc |
goto nc_done;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_RFC822NAME, cert);
|
|
Packit |
549fdc |
if (ret == 0) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
|
|
Packit |
549fdc |
goto nc_done;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_DN, cert);
|
|
Packit |
549fdc |
if (ret == 0) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
|
|
Packit |
549fdc |
goto nc_done;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_URI, cert);
|
|
Packit |
549fdc |
if (ret == 0) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
|
|
Packit |
549fdc |
goto nc_done;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = gnutls_x509_name_constraints_check_crt(vparams->nc, GNUTLS_SAN_IPADDRESS, cert);
|
|
Packit |
549fdc |
if (ret == 0) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
|
|
Packit |
549fdc |
goto nc_done;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
nc_done:
|
|
Packit |
549fdc |
if (vparams->tls_feat != NULL) {
|
|
Packit |
549fdc |
/* append the issuer's constraints */
|
|
Packit |
549fdc |
ret = gnutls_x509_crt_get_tlsfeatures(issuer, vparams->tls_feat, GNUTLS_EXT_FLAG_APPEND, NULL);
|
|
Packit |
549fdc |
if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
|
|
Packit |
549fdc |
goto feat_done;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = gnutls_x509_tlsfeatures_check_crt(vparams->tls_feat, cert);
|
|
Packit |
549fdc |
if (ret == 0) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
|
|
Packit |
549fdc |
goto feat_done;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
feat_done:
|
|
Packit |
549fdc |
issuer_version = gnutls_x509_crt_get_version(issuer);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (issuer_version < 0) {
|
|
Packit |
549fdc |
MARK_INVALID(0);
|
|
Packit |
549fdc |
} else if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN) &&
|
|
Packit |
549fdc |
((flags & GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT)
|
|
Packit |
549fdc |
|| issuer_version != 1)) {
|
|
Packit |
549fdc |
if (check_if_ca(cert, issuer, &vparams->max_path, flags) != 1) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_SIGNER_NOT_CA);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
gnutls_x509_crt_get_key_usage(issuer, &usage, NULL);
|
|
Packit |
549fdc |
if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
MARK_INVALID(0);
|
|
Packit |
549fdc |
} else if (!(usage & GNUTLS_KEY_KEY_CERT_SIGN)) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (sigalg < 0) {
|
|
Packit |
549fdc |
MARK_INVALID(0);
|
|
Packit |
549fdc |
} else if (cert_signed_data.data != NULL &&
|
|
Packit |
549fdc |
cert_signature.data != NULL) {
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
_gnutls_x509_verify_data(sigalg,
|
|
Packit |
549fdc |
&cert_signed_data,
|
|
Packit |
549fdc |
&cert_signature,
|
|
Packit |
549fdc |
cert,
|
|
Packit |
549fdc |
issuer, flags);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (ret == GNUTLS_E_PK_SIG_VERIFY_FAILED) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_SIGNATURE_FAILURE);
|
|
Packit |
549fdc |
} else if (ret == GNUTLS_E_CONSTRAINT_ERROR) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE);
|
|
Packit |
549fdc |
} else if (ret < 0) {
|
|
Packit |
549fdc |
MARK_INVALID(0);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* we always check the issuer for unsupported critical extensions */
|
|
Packit |
549fdc |
if (issuer && check_for_unknown_exts(issuer) != 0) {
|
|
Packit |
549fdc |
if (!(flags & GNUTLS_VERIFY_IGNORE_UNKNOWN_CRIT_EXTENSIONS)) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* we only check the end-certificate for critical extensions; that
|
|
Packit |
549fdc |
* way do not perform this check twice on the certificates when
|
|
Packit |
549fdc |
* verifying a large list */
|
|
Packit |
549fdc |
if (end_cert && check_for_unknown_exts(cert) != 0) {
|
|
Packit |
549fdc |
if (!(flags & GNUTLS_VERIFY_IGNORE_UNKNOWN_CRIT_EXTENSIONS)) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_UNKNOWN_CRIT_EXTENSIONS);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (sigalg >= 0 && se) {
|
|
Packit |
549fdc |
if (is_level_acceptable(cert, issuer, sigalg, flags) == 0) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_INSECURE_ALGORITHM);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* If the certificate is not self signed check if the algorithms
|
|
Packit |
549fdc |
* used are secure. If the certificate is self signed it doesn't
|
|
Packit |
549fdc |
* really matter.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
if (_gnutls_sign_is_secure2(se, GNUTLS_SIGN_FLAG_SECURE_FOR_CERTS) == 0 &&
|
|
Packit |
549fdc |
_gnutls_is_broken_sig_allowed(se, flags) == 0 &&
|
|
Packit |
549fdc |
is_issuer(cert, cert) == 0) {
|
|
Packit |
549fdc |
MARK_INVALID(GNUTLS_CERT_INSECURE_ALGORITHM);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Check activation/expiration times
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
if (!(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) {
|
|
Packit |
549fdc |
/* check the time of the issuer first */
|
|
Packit |
549fdc |
if (issuer != NULL &&
|
|
Packit |
549fdc |
!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS)) {
|
|
Packit |
549fdc |
out |= check_time_status(issuer, vparams->now);
|
|
Packit |
549fdc |
if (out != 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
result = 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
out |= check_time_status(cert, vparams->now);
|
|
Packit |
549fdc |
if (out != 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
result = 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
cleanup:
|
|
Packit |
549fdc |
if (output)
|
|
Packit |
549fdc |
*output |= out;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (vparams->func) {
|
|
Packit |
549fdc |
if (result == 0) {
|
|
Packit |
549fdc |
out |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
vparams->func(cert, issuer, NULL, out);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
_gnutls_free_datum(&cert_signed_data);
|
|
Packit |
549fdc |
_gnutls_free_datum(&cert_signature);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return result;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_crt_check_issuer:
|
|
Packit |
549fdc |
* @cert: is the certificate to be checked
|
|
Packit |
549fdc |
* @issuer: is the certificate of a possible issuer
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will check if the given certificate was issued by the
|
|
Packit |
549fdc |
* given issuer. It checks the DN fields and the authority
|
|
Packit |
549fdc |
* key identifier and subject key identifier fields match.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* If the same certificate is provided at the @cert and @issuer fields,
|
|
Packit |
549fdc |
* it will check whether the certificate is self-signed.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: It will return true (1) if the given certificate is issued
|
|
Packit |
549fdc |
* by the given issuer, and false (0) if not.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
unsigned
|
|
Packit |
549fdc |
gnutls_x509_crt_check_issuer(gnutls_x509_crt_t cert,
|
|
Packit |
549fdc |
gnutls_x509_crt_t issuer)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
return is_issuer(cert, issuer);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Verify X.509 certificate chain.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Note that the return value is an OR of GNUTLS_CERT_* elements.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function verifies a X.509 certificate list. The certificate
|
|
Packit |
549fdc |
* list should lead to a trusted certificate in order to be trusted.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
unsigned int
|
|
Packit |
549fdc |
_gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
|
|
Packit |
549fdc |
int clist_size,
|
|
Packit |
549fdc |
const gnutls_x509_crt_t * trusted_cas,
|
|
Packit |
549fdc |
int tcas_size,
|
|
Packit |
549fdc |
unsigned int flags,
|
|
Packit |
549fdc |
const char *purpose,
|
|
Packit |
549fdc |
gnutls_verify_output_function func)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int i = 0, ret;
|
|
Packit |
549fdc |
unsigned int status = 0, output;
|
|
Packit |
549fdc |
time_t now = gnutls_time(0);
|
|
Packit |
549fdc |
verify_state_st vparams;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (clist_size > 1) {
|
|
Packit |
549fdc |
/* Check if the last certificate in the path is self signed.
|
|
Packit |
549fdc |
* In that case ignore it (a certificate is trusted only if it
|
|
Packit |
549fdc |
* leads to a trusted party by us, not the server's).
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This prevents from verifying self signed certificates against
|
|
Packit |
549fdc |
* themselves. This (although not bad) caused verification
|
|
Packit |
549fdc |
* failures on some root self signed certificates that use the
|
|
Packit |
549fdc |
* MD2 algorithm.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
if (gnutls_x509_crt_check_issuer
|
|
Packit |
549fdc |
(certificate_list[clist_size - 1],
|
|
Packit |
549fdc |
certificate_list[clist_size - 1]) != 0) {
|
|
Packit |
549fdc |
clist_size--;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* We want to shorten the chain by removing the cert that matches
|
|
Packit |
549fdc |
* one of the certs we trust and all the certs after that i.e. if
|
|
Packit |
549fdc |
* cert chain is A signed-by B signed-by C signed-by D (signed-by
|
|
Packit |
549fdc |
* self-signed E but already removed above), and we trust B, remove
|
|
Packit |
549fdc |
* B, C and D. */
|
|
Packit |
549fdc |
if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME))
|
|
Packit |
549fdc |
i = 0; /* also replace the first one */
|
|
Packit |
549fdc |
else
|
|
Packit |
549fdc |
i = 1; /* do not replace the first one */
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (; i < clist_size; i++) {
|
|
Packit |
549fdc |
int j;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (j = 0; j < tcas_size; j++) {
|
|
Packit |
549fdc |
/* we check for a certificate that may not be identical with the one
|
|
Packit |
549fdc |
* sent by the client, but will have the same name and key. That is
|
|
Packit |
549fdc |
* because it can happen that a CA certificate is upgraded from intermediate
|
|
Packit |
549fdc |
* CA to self-signed CA at some point. */
|
|
Packit |
549fdc |
if (_gnutls_check_if_same_key
|
|
Packit |
549fdc |
(certificate_list[i], trusted_cas[j], i) != 0) {
|
|
Packit |
549fdc |
/* explicit time check for trusted CA that we remove from
|
|
Packit |
549fdc |
* list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) &&
|
|
Packit |
549fdc |
!(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) {
|
|
Packit |
549fdc |
status |=
|
|
Packit |
549fdc |
check_time_status(trusted_cas[j],
|
|
Packit |
549fdc |
now);
|
|
Packit |
549fdc |
if (status != 0) {
|
|
Packit |
549fdc |
if (func)
|
|
Packit |
549fdc |
func(certificate_list[i], trusted_cas[j], NULL, status);
|
|
Packit |
549fdc |
return status;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (func)
|
|
Packit |
549fdc |
func(certificate_list[i],
|
|
Packit |
549fdc |
trusted_cas[j], NULL, status);
|
|
Packit |
549fdc |
clist_size = i;
|
|
Packit |
549fdc |
break;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
/* clist_size may have been changed which gets out of loop */
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (clist_size == 0) {
|
|
Packit |
549fdc |
/* The certificate is already present in the trusted certificate list.
|
|
Packit |
549fdc |
* Nothing to verify. */
|
|
Packit |
549fdc |
return status;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
memset(&vparams, 0, sizeof(vparams));
|
|
Packit |
549fdc |
vparams.now = now;
|
|
Packit |
549fdc |
vparams.max_path = MAX_VERIFY_DEPTH;
|
|
Packit |
549fdc |
vparams.func = func;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = gnutls_x509_name_constraints_init(&vparams.nc);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
return status;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = gnutls_x509_tlsfeatures_init(&vparams.tls_feat);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Verify the last certificate in the certificate path
|
|
Packit |
549fdc |
* against the trusted CA certificate list.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* If no CAs are present returns CERT_INVALID. Thus works
|
|
Packit |
549fdc |
* in self signed etc certificates.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
output = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = verify_crt(certificate_list[clist_size - 1],
|
|
Packit |
549fdc |
trusted_cas, tcas_size, flags,
|
|
Packit |
549fdc |
&output,
|
|
Packit |
549fdc |
&vparams,
|
|
Packit |
549fdc |
clist_size==1?1:0);
|
|
Packit |
549fdc |
if (ret != 1) {
|
|
Packit |
549fdc |
/* if the last certificate in the certificate
|
|
Packit |
549fdc |
* list is invalid, then the certificate is not
|
|
Packit |
549fdc |
* trusted.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
status |= output;
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Verify the certificate path (chain)
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
for (i = clist_size - 1; i > 0; i--) {
|
|
Packit |
549fdc |
output = 0;
|
|
Packit |
549fdc |
if (i - 1 < 0)
|
|
Packit |
549fdc |
break;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (purpose != NULL) {
|
|
Packit |
549fdc |
ret = _gnutls_check_key_purpose(certificate_list[i], purpose, 1);
|
|
Packit |
549fdc |
if (ret != 1) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_PURPOSE_MISMATCH;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (func)
|
|
Packit |
549fdc |
func(certificate_list[i-1],
|
|
Packit |
549fdc |
certificate_list[i], NULL, status);
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* note that here we disable this V1 CA flag. So that no version 1
|
|
Packit |
549fdc |
* certificates can exist in a supplied chain.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
if (!(flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT)) {
|
|
Packit |
549fdc |
flags |= GNUTLS_VERIFY_DO_NOT_ALLOW_X509_V1_CA_CRT;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if ((ret =
|
|
Packit |
549fdc |
verify_crt(certificate_list[i - 1],
|
|
Packit |
549fdc |
&certificate_list[i], 1,
|
|
Packit |
549fdc |
flags, &output,
|
|
Packit |
549fdc |
&vparams,
|
|
Packit |
549fdc |
i==1?1:0)) != 1) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
status |= output;
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
cleanup:
|
|
Packit |
549fdc |
gnutls_x509_name_constraints_deinit(vparams.nc);
|
|
Packit |
549fdc |
gnutls_x509_tlsfeatures_deinit(vparams.tls_feat);
|
|
Packit |
549fdc |
return status;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
#define PURPOSE_NSSGC "2.16.840.1.113730.4.1"
|
|
Packit |
549fdc |
#define PURPOSE_VSGC "2.16.840.1.113733.1.8.1"
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Returns true if the provided purpose is in accordance with the certificate.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
unsigned _gnutls_check_key_purpose(gnutls_x509_crt_t cert, const char *purpose, unsigned no_any)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
char oid[MAX_OID_SIZE];
|
|
Packit |
549fdc |
size_t oid_size;
|
|
Packit |
549fdc |
int ret;
|
|
Packit |
549fdc |
unsigned critical = 0;
|
|
Packit |
549fdc |
unsigned check_obsolete_oids = 0;
|
|
Packit |
549fdc |
unsigned i;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* The check_obsolete_oids hack is because of certain very old CA certificates
|
|
Packit |
549fdc |
* around which instead of having the GNUTLS_KP_TLS_WWW_SERVER have some old
|
|
Packit |
549fdc |
* OIDs for that purpose. Assume these OIDs equal GNUTLS_KP_TLS_WWW_SERVER in
|
|
Packit |
549fdc |
* CA certs */
|
|
Packit |
549fdc |
if (strcmp(purpose, GNUTLS_KP_TLS_WWW_SERVER) == 0) {
|
|
Packit |
549fdc |
unsigned ca_status;
|
|
Packit |
549fdc |
ret =
|
|
Packit |
549fdc |
gnutls_x509_crt_get_basic_constraints(cert, NULL, &ca_status,
|
|
Packit |
549fdc |
NULL);
|
|
Packit |
549fdc |
if (ret < 0)
|
|
Packit |
549fdc |
ca_status = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (ca_status)
|
|
Packit |
549fdc |
check_obsolete_oids = 1;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i=0;;i++) {
|
|
Packit |
549fdc |
oid_size = sizeof(oid);
|
|
Packit |
549fdc |
ret = gnutls_x509_crt_get_key_purpose_oid(cert, i, oid, &oid_size, &critical);
|
|
Packit |
549fdc |
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
|
|
Packit |
549fdc |
if (i==0) {
|
|
Packit |
549fdc |
/* no key purpose in certificate, assume ANY */
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
break;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
} else if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
break;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (check_obsolete_oids) {
|
|
Packit |
549fdc |
if (strcmp(oid, PURPOSE_NSSGC) == 0) {
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
} else if (strcmp(oid, PURPOSE_VSGC) == 0) {
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (strcmp(oid, purpose) == 0 || (no_any == 0 && strcmp(oid, GNUTLS_KP_ANY) == 0)) {
|
|
Packit |
549fdc |
return 1;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
_gnutls_debug_log("looking for key purpose '%s', but have '%s'\n", purpose, oid);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
#ifdef ENABLE_PKCS11
|
|
Packit |
549fdc |
/* Verify X.509 certificate chain using a PKCS #11 token.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Note that the return value is an OR of GNUTLS_CERT_* elements.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Unlike the non-PKCS#11 version, this function accepts a key purpose
|
|
Packit |
549fdc |
* (from GNUTLS_KP_...). That is because in the p11-kit trust modules
|
|
Packit |
549fdc |
* anchors are mixed and get assigned a purpose.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function verifies a X.509 certificate list. The certificate
|
|
Packit |
549fdc |
* list should lead to a trusted certificate in order to be trusted.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
unsigned int
|
|
Packit |
549fdc |
_gnutls_pkcs11_verify_crt_status(const char* url,
|
|
Packit |
549fdc |
const gnutls_x509_crt_t * certificate_list,
|
|
Packit |
549fdc |
unsigned clist_size,
|
|
Packit |
549fdc |
const char *purpose,
|
|
Packit |
549fdc |
unsigned int flags,
|
|
Packit |
549fdc |
gnutls_verify_output_function func)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int ret;
|
|
Packit |
549fdc |
unsigned int status = 0, i;
|
|
Packit |
549fdc |
gnutls_x509_crt_t issuer = NULL;
|
|
Packit |
549fdc |
gnutls_datum_t raw_issuer = {NULL, 0};
|
|
Packit |
549fdc |
time_t now = gnutls_time(0);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (clist_size > 1) {
|
|
Packit |
549fdc |
/* Check if the last certificate in the path is self signed.
|
|
Packit |
549fdc |
* In that case ignore it (a certificate is trusted only if it
|
|
Packit |
549fdc |
* leads to a trusted party by us, not the server's).
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This prevents from verifying self signed certificates against
|
|
Packit |
549fdc |
* themselves. This (although not bad) caused verification
|
|
Packit |
549fdc |
* failures on some root self signed certificates that use the
|
|
Packit |
549fdc |
* MD2 algorithm.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
if (gnutls_x509_crt_check_issuer
|
|
Packit |
549fdc |
(certificate_list[clist_size - 1],
|
|
Packit |
549fdc |
certificate_list[clist_size - 1]) != 0) {
|
|
Packit |
549fdc |
clist_size--;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* We want to shorten the chain by removing the cert that matches
|
|
Packit |
549fdc |
* one of the certs we trust and all the certs after that i.e. if
|
|
Packit |
549fdc |
* cert chain is A signed-by B signed-by C signed-by D (signed-by
|
|
Packit |
549fdc |
* self-signed E but already removed above), and we trust B, remove
|
|
Packit |
549fdc |
* B, C and D. */
|
|
Packit |
549fdc |
if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME))
|
|
Packit |
549fdc |
i = 0; /* also replace the first one */
|
|
Packit |
549fdc |
else
|
|
Packit |
549fdc |
i = 1; /* do not replace the first one */
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (; i < clist_size; i++) {
|
|
Packit |
549fdc |
unsigned vflags;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (i == 0) /* in the end certificate do full comparison */
|
|
Packit |
549fdc |
vflags = GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
|
|
Packit |
549fdc |
GNUTLS_PKCS11_OBJ_FLAG_COMPARE|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED;
|
|
Packit |
549fdc |
else
|
|
Packit |
549fdc |
vflags = GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
|
|
Packit |
549fdc |
GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (gnutls_pkcs11_crt_is_known (url, certificate_list[i], vflags) != 0) {
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) &&
|
|
Packit |
549fdc |
!(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) {
|
|
Packit |
549fdc |
status |=
|
|
Packit |
549fdc |
check_time_status(certificate_list[i], now);
|
|
Packit |
549fdc |
if (status != 0) {
|
|
Packit |
549fdc |
if (func)
|
|
Packit |
549fdc |
func(certificate_list[i], certificate_list[i], NULL, status);
|
|
Packit |
549fdc |
return status;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
if (func)
|
|
Packit |
549fdc |
func(certificate_list[i],
|
|
Packit |
549fdc |
certificate_list[i], NULL, status);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
clist_size = i;
|
|
Packit |
549fdc |
break;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
/* clist_size may have been changed which gets out of loop */
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (clist_size == 0) {
|
|
Packit |
549fdc |
/* The certificate is already present in the trusted certificate list.
|
|
Packit |
549fdc |
* Nothing to verify. */
|
|
Packit |
549fdc |
return status;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* check for blacklists */
|
|
Packit |
549fdc |
for (i = 0; i < clist_size; i++) {
|
|
Packit |
549fdc |
if (gnutls_pkcs11_crt_is_known (url, certificate_list[i],
|
|
Packit |
549fdc |
GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
|
|
Packit |
549fdc |
GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED) != 0) {
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_REVOKED;
|
|
Packit |
549fdc |
if (func)
|
|
Packit |
549fdc |
func(certificate_list[i], certificate_list[i], NULL, status);
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* check against issuer */
|
|
Packit |
549fdc |
ret = gnutls_pkcs11_get_raw_issuer(url, certificate_list[clist_size - 1],
|
|
Packit |
549fdc |
&raw_issuer, GNUTLS_X509_FMT_DER,
|
|
Packit |
549fdc |
GNUTLS_PKCS11_OBJ_FLAG_OVERWRITE_TRUSTMOD_EXT|GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && clist_size > 2) {
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* check if the last certificate in the chain is present
|
|
Packit |
549fdc |
* in our trusted list, and if yes, verify against it. */
|
|
Packit |
549fdc |
ret = gnutls_pkcs11_crt_is_known(url, certificate_list[clist_size - 1],
|
|
Packit |
549fdc |
GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED|GNUTLS_PKCS11_OBJ_FLAG_COMPARE);
|
|
Packit |
549fdc |
if (ret != 0) {
|
|
Packit |
549fdc |
return _gnutls_verify_crt_status(certificate_list, clist_size,
|
|
Packit |
549fdc |
&certificate_list[clist_size - 1], 1, flags,
|
|
Packit |
549fdc |
purpose, func);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_SIGNER_NOT_FOUND;
|
|
Packit |
549fdc |
/* verify the certificate list against 0 trusted CAs in order
|
|
Packit |
549fdc |
* to get, any additional flags from the certificate list (e.g.,
|
|
Packit |
549fdc |
* insecure algorithms or expired */
|
|
Packit |
549fdc |
status |= _gnutls_verify_crt_status(certificate_list, clist_size,
|
|
Packit |
549fdc |
NULL, 0, flags, purpose, func);
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = gnutls_x509_crt_init(&issuer);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_SIGNER_NOT_FOUND;
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = gnutls_x509_crt_import(issuer, &raw_issuer, GNUTLS_X509_FMT_DER);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_SIGNER_NOT_FOUND;
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* check if the raw issuer is blacklisted (it can happen if
|
|
Packit |
549fdc |
* the issuer is both in the trusted list and the blacklisted)
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
if (gnutls_pkcs11_crt_is_known (url, issuer,
|
|
Packit |
549fdc |
GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
|
|
Packit |
549fdc |
GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED) != 0) {
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_SIGNER_NOT_FOUND; /* if the signer is revoked - it is as if it doesn't exist */
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* security modules that provide trust, bundle all certificates (of all purposes)
|
|
Packit |
549fdc |
* together. In software that doesn't specify any purpose assume the default to
|
|
Packit |
549fdc |
* be www-server. */
|
|
Packit |
549fdc |
ret = _gnutls_check_key_purpose(issuer, purpose==NULL?GNUTLS_KP_TLS_WWW_SERVER:purpose, 0);
|
|
Packit |
549fdc |
if (ret != 1) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
status |= GNUTLS_CERT_SIGNER_NOT_FOUND;
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
status = _gnutls_verify_crt_status(certificate_list, clist_size,
|
|
Packit |
549fdc |
&issuer, 1, flags, purpose, func);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
cleanup:
|
|
Packit |
549fdc |
gnutls_free(raw_issuer.data);
|
|
Packit |
549fdc |
if (issuer != NULL)
|
|
Packit |
549fdc |
gnutls_x509_crt_deinit(issuer);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return status;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
#endif
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static int
|
|
Packit |
549fdc |
_gnutls_x509_validate_sign_params(gnutls_pk_algorithm_t pk_algorithm,
|
|
Packit |
549fdc |
ASN1_TYPE cert,
|
|
Packit |
549fdc |
const char *name,
|
|
Packit |
549fdc |
gnutls_x509_spki_st *sig_params)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
/* The signature parameter validation is only needed for RSA-PSS */
|
|
Packit |
549fdc |
if (pk_algorithm == GNUTLS_PK_RSA_PSS) {
|
|
Packit |
549fdc |
int result;
|
|
Packit |
549fdc |
gnutls_x509_spki_st params;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
result = _gnutls_x509_read_sign_params(cert, name, ¶ms);
|
|
Packit |
549fdc |
if (result < 0) {
|
|
Packit |
549fdc |
/* If parameters field is absent, no parameter
|
|
Packit |
549fdc |
* validation is needed */
|
|
Packit |
549fdc |
if (result != GNUTLS_E_ASN1_ELEMENT_NOT_FOUND &&
|
|
Packit |
549fdc |
result != GNUTLS_E_ASN1_VALUE_NOT_FOUND) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return result;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
/* Check if the underlying hash algorithms are same. */
|
|
Packit |
549fdc |
if (sig_params->rsa_pss_dig != params.rsa_pss_dig) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_CONSTRAINT_ERROR;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* The salt length used to generate the
|
|
Packit |
549fdc |
* signature must be equal to or larger than
|
|
Packit |
549fdc |
* the one in the key parameter. */
|
|
Packit |
549fdc |
if (sig_params->salt_size < params.salt_size) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return GNUTLS_E_CONSTRAINT_ERROR;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* verifies if the certificate is properly signed.
|
|
Packit |
549fdc |
* returns GNUTLS_E_PK_VERIFY_SIG_FAILED on failure and 1 on success.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* 'data' is the signed data
|
|
Packit |
549fdc |
* 'signature' is the signature!
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
static int
|
|
Packit |
549fdc |
_gnutls_x509_verify_data(gnutls_sign_algorithm_t sign,
|
|
Packit |
549fdc |
const gnutls_datum_t * data,
|
|
Packit |
549fdc |
const gnutls_datum_t * signature,
|
|
Packit |
549fdc |
gnutls_x509_crt_t cert,
|
|
Packit |
549fdc |
gnutls_x509_crt_t issuer,
|
|
Packit |
549fdc |
unsigned vflags)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
gnutls_pk_params_st params;
|
|
Packit |
549fdc |
gnutls_pk_algorithm_t issuer_pk;
|
|
Packit |
549fdc |
int ret;
|
|
Packit |
549fdc |
gnutls_x509_spki_st sign_params;
|
|
Packit |
549fdc |
const gnutls_sign_entry_st *se;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Read the MPI parameters from the issuer's certificate.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
ret = _gnutls_x509_crt_get_mpis(issuer, ¶ms);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return ret;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
issuer_pk = gnutls_x509_crt_get_pk_algorithm(issuer, NULL);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
se = _gnutls_sign_to_entry(sign);
|
|
Packit |
549fdc |
if (se == NULL)
|
|
Packit |
549fdc |
return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (cert != NULL) {
|
|
Packit |
549fdc |
ret = _gnutls_x509_read_sign_params(cert->cert,
|
|
Packit |
549fdc |
"signatureAlgorithm",
|
|
Packit |
549fdc |
&sign_params);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = _gnutls_x509_validate_sign_params(issuer_pk,
|
|
Packit |
549fdc |
issuer->cert,
|
|
Packit |
549fdc |
"tbsCertificate."
|
|
Packit |
549fdc |
"subjectPublicKeyInfo."
|
|
Packit |
549fdc |
"algorithm",
|
|
Packit |
549fdc |
&sign_params);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
memcpy(&sign_params, ¶ms.spki,
|
|
Packit |
549fdc |
sizeof(gnutls_x509_spki_st));
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
sign_params.pk = se->pk;
|
|
Packit |
549fdc |
if (sign_params.pk == GNUTLS_PK_RSA_PSS)
|
|
Packit |
549fdc |
sign_params.rsa_pss_dig = se->hash;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
ret = pubkey_verify_data(se, hash_to_entry(se->hash), data, signature, ¶ms,
|
|
Packit |
549fdc |
&sign_params, vflags);
|
|
Packit |
549fdc |
if (ret < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
cleanup:
|
|
Packit |
549fdc |
/* release all allocated MPIs
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
gnutls_pk_params_release(¶ms);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return ret;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_crt_list_verify:
|
|
Packit |
549fdc |
* @cert_list: is the certificate list to be verified
|
|
Packit |
549fdc |
* @cert_list_length: holds the number of certificate in cert_list
|
|
Packit |
549fdc |
* @CA_list: is the CA list which will be used in verification
|
|
Packit |
549fdc |
* @CA_list_length: holds the number of CA certificate in CA_list
|
|
Packit |
549fdc |
* @CRL_list: holds a list of CRLs.
|
|
Packit |
549fdc |
* @CRL_list_length: the length of CRL list.
|
|
Packit |
549fdc |
* @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations.
|
|
Packit |
549fdc |
* @verify: will hold the certificate verification output.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will try to verify the given certificate list and
|
|
Packit |
549fdc |
* return its status. The details of the verification are the same
|
|
Packit |
549fdc |
* as in gnutls_x509_trust_list_verify_crt2().
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* You must check the peer's name in order to check if the verified
|
|
Packit |
549fdc |
* certificate belongs to the actual peer.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* The certificate verification output will be put in @verify and will
|
|
Packit |
549fdc |
* be one or more of the gnutls_certificate_status_t enumerated
|
|
Packit |
549fdc |
* elements bitwise or'd. For a more detailed verification status use
|
|
Packit |
549fdc |
* gnutls_x509_crt_verify() per list element.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
|
|
Packit |
549fdc |
* negative error value.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_x509_crt_list_verify(const gnutls_x509_crt_t * cert_list,
|
|
Packit |
549fdc |
unsigned cert_list_length,
|
|
Packit |
549fdc |
const gnutls_x509_crt_t * CA_list,
|
|
Packit |
549fdc |
unsigned CA_list_length,
|
|
Packit |
549fdc |
const gnutls_x509_crl_t * CRL_list,
|
|
Packit |
549fdc |
unsigned CRL_list_length, unsigned int flags,
|
|
Packit |
549fdc |
unsigned int *verify)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
unsigned i;
|
|
Packit |
549fdc |
int ret;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (cert_list == NULL || cert_list_length == 0)
|
|
Packit |
549fdc |
return GNUTLS_E_NO_CERTIFICATE_FOUND;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Verify certificate
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
*verify =
|
|
Packit |
549fdc |
_gnutls_verify_crt_status(cert_list, cert_list_length,
|
|
Packit |
549fdc |
CA_list, CA_list_length,
|
|
Packit |
549fdc |
flags, NULL, NULL);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* Check for revoked certificates in the chain.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
for (i = 0; i < cert_list_length; i++) {
|
|
Packit |
549fdc |
ret = gnutls_x509_crt_check_revocation(cert_list[i],
|
|
Packit |
549fdc |
CRL_list,
|
|
Packit |
549fdc |
CRL_list_length);
|
|
Packit |
549fdc |
if (ret == 1) { /* revoked */
|
|
Packit |
549fdc |
*verify |= GNUTLS_CERT_REVOKED;
|
|
Packit |
549fdc |
*verify |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_crt_verify:
|
|
Packit |
549fdc |
* @cert: is the certificate to be verified
|
|
Packit |
549fdc |
* @CA_list: is one certificate that is considered to be trusted one
|
|
Packit |
549fdc |
* @CA_list_length: holds the number of CA certificate in CA_list
|
|
Packit |
549fdc |
* @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations.
|
|
Packit |
549fdc |
* @verify: will hold the certificate verification output.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will try to verify the given certificate and return
|
|
Packit |
549fdc |
* its status. Note that a verification error does not imply a negative
|
|
Packit |
549fdc |
* return status. In that case the @verify status is set.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* The details of the verification are the same
|
|
Packit |
549fdc |
* as in gnutls_x509_trust_list_verify_crt2().
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
|
|
Packit |
549fdc |
* negative error value.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_x509_crt_verify(gnutls_x509_crt_t cert,
|
|
Packit |
549fdc |
const gnutls_x509_crt_t * CA_list,
|
|
Packit |
549fdc |
unsigned CA_list_length, unsigned int flags,
|
|
Packit |
549fdc |
unsigned int *verify)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
/* Verify certificate
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
*verify =
|
|
Packit |
549fdc |
_gnutls_verify_crt_status(&cert, 1,
|
|
Packit |
549fdc |
CA_list, CA_list_length,
|
|
Packit |
549fdc |
flags, NULL, NULL);
|
|
Packit |
549fdc |
return 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_crl_check_issuer:
|
|
Packit |
549fdc |
* @crl: is the CRL to be checked
|
|
Packit |
549fdc |
* @issuer: is the certificate of a possible issuer
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will check if the given CRL was issued by the given
|
|
Packit |
549fdc |
* issuer certificate.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: true (1) if the given CRL was issued by the given issuer,
|
|
Packit |
549fdc |
* and false (0) if not.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
unsigned
|
|
Packit |
549fdc |
gnutls_x509_crl_check_issuer(gnutls_x509_crl_t crl,
|
|
Packit |
549fdc |
gnutls_x509_crt_t issuer)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
return is_crl_issuer(crl, issuer);
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
static inline gnutls_x509_crt_t
|
|
Packit |
549fdc |
find_crl_issuer(gnutls_x509_crl_t crl,
|
|
Packit |
549fdc |
const gnutls_x509_crt_t * trusted_cas, int tcas_size)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
int i;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* this is serial search.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
for (i = 0; i < tcas_size; i++) {
|
|
Packit |
549fdc |
if (is_crl_issuer(crl, trusted_cas[i]) != 0)
|
|
Packit |
549fdc |
return trusted_cas[i];
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
return NULL;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/**
|
|
Packit |
549fdc |
* gnutls_x509_crl_verify:
|
|
Packit |
549fdc |
* @crl: is the crl to be verified
|
|
Packit |
549fdc |
* @trusted_cas: is a certificate list that is considered to be trusted one
|
|
Packit |
549fdc |
* @tcas_size: holds the number of CA certificates in CA_list
|
|
Packit |
549fdc |
* @flags: Flags that may be used to change the verification algorithm. Use OR of the gnutls_certificate_verify_flags enumerations.
|
|
Packit |
549fdc |
* @verify: will hold the crl verification output.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* This function will try to verify the given crl and return its verification status.
|
|
Packit |
549fdc |
* See gnutls_x509_crt_list_verify() for a detailed description of
|
|
Packit |
549fdc |
* return values. Note that since GnuTLS 3.1.4 this function includes
|
|
Packit |
549fdc |
* the time checks.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Note that value in @verify is set only when the return value of this
|
|
Packit |
549fdc |
* function is success (i.e, failure to trust a CRL a certificate does not imply
|
|
Packit |
549fdc |
* a negative return value).
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Before GnuTLS 3.5.7 this function would return zero or a positive
|
|
Packit |
549fdc |
* number on success.
|
|
Packit |
549fdc |
*
|
|
Packit |
549fdc |
* Returns: On success, %GNUTLS_E_SUCCESS (0), otherwise a
|
|
Packit |
549fdc |
* negative error value.
|
|
Packit |
549fdc |
**/
|
|
Packit |
549fdc |
int
|
|
Packit |
549fdc |
gnutls_x509_crl_verify(gnutls_x509_crl_t crl,
|
|
Packit |
549fdc |
const gnutls_x509_crt_t * trusted_cas,
|
|
Packit |
549fdc |
unsigned tcas_size, unsigned int flags,
|
|
Packit |
549fdc |
unsigned int *verify)
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
/* CRL is ignored for now */
|
|
Packit |
549fdc |
gnutls_datum_t crl_signed_data = { NULL, 0 };
|
|
Packit |
549fdc |
gnutls_datum_t crl_signature = { NULL, 0 };
|
|
Packit |
549fdc |
gnutls_x509_crt_t issuer = NULL;
|
|
Packit |
549fdc |
int result, sigalg;
|
|
Packit |
549fdc |
time_t now = gnutls_time(0);
|
|
Packit |
549fdc |
time_t nextu;
|
|
Packit |
549fdc |
unsigned int usage;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (verify)
|
|
Packit |
549fdc |
*verify = 0;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (tcas_size >= 1)
|
|
Packit |
549fdc |
issuer = find_crl_issuer(crl, trusted_cas, tcas_size);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
result =
|
|
Packit |
549fdc |
_gnutls_x509_get_signed_data(crl->crl, &crl->der, "tbsCertList",
|
|
Packit |
549fdc |
&crl_signed_data);
|
|
Packit |
549fdc |
if (result < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
if (verify)
|
|
Packit |
549fdc |
*verify |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
result =
|
|
Packit |
549fdc |
_gnutls_x509_get_signature(crl->crl, "signature",
|
|
Packit |
549fdc |
&crl_signature);
|
|
Packit |
549fdc |
if (result < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
if (verify)
|
|
Packit |
549fdc |
*verify |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
sigalg =
|
|
Packit |
549fdc |
_gnutls_x509_get_signature_algorithm(crl->crl,
|
|
Packit |
549fdc |
"signatureAlgorithm");
|
|
Packit |
549fdc |
if (sigalg < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
if (verify)
|
|
Packit |
549fdc |
*verify |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
/* issuer is not in trusted certificate
|
|
Packit |
549fdc |
* authorities.
|
|
Packit |
549fdc |
*/
|
|
Packit |
549fdc |
if (issuer == NULL) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
if (verify)
|
|
Packit |
549fdc |
*verify |=
|
|
Packit |
549fdc |
GNUTLS_CERT_SIGNER_NOT_FOUND |
|
|
Packit |
549fdc |
GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
} else {
|
|
Packit |
549fdc |
if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN)) {
|
|
Packit |
549fdc |
if (gnutls_x509_crt_get_ca_status(issuer, NULL) != 1) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
if (verify)
|
|
Packit |
549fdc |
*verify |=
|
|
Packit |
549fdc |
GNUTLS_CERT_SIGNER_NOT_CA |
|
|
Packit |
549fdc |
GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
result =
|
|
Packit |
549fdc |
gnutls_x509_crt_get_key_usage(issuer, &usage, NULL);
|
|
Packit |
549fdc |
if (result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
|
|
Packit |
549fdc |
if (result < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
if (verify)
|
|
Packit |
549fdc |
*verify |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
} else if (!(usage & GNUTLS_KEY_CRL_SIGN)) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
if (verify)
|
|
Packit |
549fdc |
*verify |=
|
|
Packit |
549fdc |
GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE
|
|
Packit |
549fdc |
| GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
result =
|
|
Packit |
549fdc |
_gnutls_x509_verify_data(sigalg,
|
|
Packit |
549fdc |
&crl_signed_data, &crl_signature,
|
|
Packit |
549fdc |
NULL,
|
|
Packit |
549fdc |
issuer, flags);
|
|
Packit |
549fdc |
if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
/* error. ignore it */
|
|
Packit |
549fdc |
if (verify)
|
|
Packit |
549fdc |
*verify |= GNUTLS_CERT_SIGNATURE_FAILURE;
|
|
Packit |
549fdc |
result = 0;
|
|
Packit |
549fdc |
} else if (result == GNUTLS_E_CONSTRAINT_ERROR) {
|
|
Packit |
549fdc |
if (verify)
|
|
Packit |
549fdc |
*verify |= GNUTLS_CERT_SIGNER_CONSTRAINTS_FAILURE;
|
|
Packit |
549fdc |
result = 0;
|
|
Packit |
549fdc |
} else if (result < 0) {
|
|
Packit |
549fdc |
gnutls_assert();
|
|
Packit |
549fdc |
if (verify)
|
|
Packit |
549fdc |
*verify |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
goto cleanup;
|
|
Packit |
549fdc |
} else if (result >= 0) {
|
|
Packit |
549fdc |
result = 0; /* everything ok */
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
{
|
|
Packit |
549fdc |
sigalg = gnutls_x509_crl_get_signature_algorithm(crl);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (((sigalg == GNUTLS_SIGN_RSA_MD2) &&
|
|
Packit |
549fdc |
!(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2)) ||
|
|
Packit |
549fdc |
((sigalg == GNUTLS_SIGN_RSA_MD5) &&
|
|
Packit |
549fdc |
!(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5))) {
|
|
Packit |
549fdc |
if (verify)
|
|
Packit |
549fdc |
*verify |= GNUTLS_CERT_INSECURE_ALGORITHM;
|
|
Packit |
549fdc |
result = 0;
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
}
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
if (gnutls_x509_crl_get_this_update(crl) > now && verify)
|
|
Packit |
549fdc |
*verify |= GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
nextu = gnutls_x509_crl_get_next_update(crl);
|
|
Packit |
549fdc |
if (nextu != -1 && nextu < now && verify)
|
|
Packit |
549fdc |
*verify |= GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
cleanup:
|
|
Packit |
549fdc |
if (verify && *verify != 0)
|
|
Packit |
549fdc |
*verify |= GNUTLS_CERT_INVALID;
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
_gnutls_free_datum(&crl_signed_data);
|
|
Packit |
549fdc |
_gnutls_free_datum(&crl_signature);
|
|
Packit |
549fdc |
|
|
Packit |
549fdc |
return result;
|
|
Packit |
549fdc |
}
|