This commit is contained in:
Christian Grothoff committed 2008-11-16 04:47:42 +00:00
1 parent 3b9bb09488
commit 26766bf6f7
11 files changed
+2 -1174

No files matched your search

-6
View File
@@ -700,12 +700,6 @@ extern "C"
time_t MHD_gtls_certificate_expiration_time_peers (MHD_gtls_session_t
session);
int MHD_gtls_certificate_verify_peers2 (MHD_gtls_session_t session,
unsigned int *status);
/* this is obsolete (?). */
int MHD_gtls_certificate_verify_peers (MHD_gtls_session_t session);
int MHD_gtls_pem_base64_encode (const char *msg,
const MHD_gnutls_datum_t * data,
char *result, size_t * result_size);
-86
View File
@@ -429,92 +429,6 @@ MHD__gnutls_x509_get_raw_crt_expiration_time (const MHD_gnutls_datum_t * cert)
return result;
}
/**
* MHD_gtls_certificate_verify_peers2 - This function returns the peer's certificate verification status
* @session: is a gnutls session
* @status: is the output of the verification
*
* This function will try to verify the peer's certificate and return
* its status (trusted, invalid etc.). The value of @status should
* be one or more of the MHD_gnutls_certificate_status_t enumerated
* elements bitwise or'd. To avoid denial of service attacks some
* default upper limits regarding the certificate key size and chain
* size are set. To override them use
* MHD__gnutls_certificate_set_verify_limits().
*
* Note that you must also check the peer's name in order to check if
* the verified certificate belongs to the actual peer.
*
* This is the same as MHD_gnutls_x509_crt_list_verify() and uses the
* loaded CAs in the credentials as trusted CAs.
*
* Note that some commonly used X.509 Certificate Authorities are
* still using Version 1 certificates. If you want to accept them,
* you need to call MHD__gnutls_certificate_set_verify_flags() with, e.g.,
* %GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT parameter.
*
* Returns: a negative error code on error and zero on success.
**/
int
MHD_gtls_certificate_verify_peers2 (MHD_gtls_session_t session,
unsigned int *status)
{
cert_auth_info_t info;
CHECK_AUTH (MHD_GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST);
info = MHD_gtls_get_auth_info (session);
if (info == NULL)
{
return GNUTLS_E_NO_CERTIFICATE_FOUND;
}
if (info->raw_certificate_list == NULL || info->ncerts == 0)
return GNUTLS_E_NO_CERTIFICATE_FOUND;
switch (MHD_gnutls_certificate_type_get (session))
{
case MHD_GNUTLS_CRT_X509:
return MHD__gnutls_x509_cert_verify_peers (session, status);
default:
return GNUTLS_E_INVALID_REQUEST;
}
}
/**
* MHD_gtls_certificate_verify_peers - This function returns the peer's certificate verification status
* @session: is a gnutls session
*
* This function will try to verify the peer's certificate and return
* its status (trusted, invalid etc.). However you must also check
* the peer's name in order to check if the verified certificate
* belongs to the actual peer.
*
* The return value should be one or more of the
* MHD_gnutls_certificate_status_t enumerated elements bitwise or'd, or a
* negative value on error.
*
* This is the same as MHD_gnutls_x509_crt_list_verify().
*
* Deprecated: Use MHD_gtls_certificate_verify_peers2() instead.
**/
int
MHD_gtls_certificate_verify_peers (MHD_gtls_session_t session)
{
unsigned int status;
int ret;
ret = MHD_gtls_certificate_verify_peers2 (session, &status);
if (ret < 0)
{
MHD_gnutls_assert ();
return ret;
}
return status;
}
/**
* MHD_gtls_certificate_expiration_time_peers - This function returns the peer's certificate expiration time
* @session: is a gnutls session
-110
View File
@@ -48,7 +48,6 @@
/* x509 */
#include "common.h"
#include "x509.h"
#include "verify.h"
#include "mpi.h"
#include "privkey.h"
@@ -89,115 +88,6 @@ check_bits (MHD_gnutls_x509_crt_t crt, unsigned int max_bits)
} \
MHD_gnutls_free( peer_certificate_list)
/*-
* MHD__gnutls_x509_cert_verify_peers - This function returns the peer's certificate status
* @session: is a gnutls session
*
* This function will try to verify the peer's certificate and return its status (TRUSTED, REVOKED etc.).
* The return value (status) should be one of the MHD_gnutls_certificate_status_t enumerated elements.
* However you must also check the peer's name in order to check if the verified certificate belongs to the
* actual peer. Returns a negative error code in case of an error, or GNUTLS_E_NO_CERTIFICATE_FOUND if no certificate was sent.
*
-*/
int
MHD__gnutls_x509_cert_verify_peers (MHD_gtls_session_t session,
unsigned int *status)
{
cert_auth_info_t info;
MHD_gtls_cert_credentials_t cred;
MHD_gnutls_x509_crt_t *peer_certificate_list;
int peer_certificate_list_size, i, x, ret;
CHECK_AUTH (MHD_GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST);
info = MHD_gtls_get_auth_info (session);
if (info == NULL)
{
MHD_gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
cred = (MHD_gtls_cert_credentials_t)
MHD_gtls_get_cred (session->key, MHD_GNUTLS_CRD_CERTIFICATE, NULL);
if (cred == NULL)
{
MHD_gnutls_assert ();
return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
}
if (info->raw_certificate_list == NULL || info->ncerts == 0)
return GNUTLS_E_NO_CERTIFICATE_FOUND;
if (info->ncerts > cred->verify_depth && cred->verify_depth > 0)
{
MHD_gnutls_assert ();
return GNUTLS_E_CONSTRAINT_ERROR;
}
/* generate a list of MHD_gnutls_certs based on the auth info
* raw certs.
*/
peer_certificate_list_size = info->ncerts;
peer_certificate_list =
MHD_gnutls_calloc (peer_certificate_list_size,
sizeof (MHD_gnutls_x509_crt_t));
if (peer_certificate_list == NULL)
{
MHD_gnutls_assert ();
return GNUTLS_E_MEMORY_ERROR;
}
for (i = 0; i < peer_certificate_list_size; i++)
{
ret = MHD_gnutls_x509_crt_init (&peer_certificate_list[i]);
if (ret < 0)
{
MHD_gnutls_assert ();
CLEAR_CERTS;
return ret;
}
ret =
MHD_gnutls_x509_crt_import (peer_certificate_list[i],
&info->raw_certificate_list[i],
GNUTLS_X509_FMT_DER);
if (ret < 0)
{
MHD_gnutls_assert ();
CLEAR_CERTS;
return ret;
}
ret = check_bits (peer_certificate_list[i], cred->verify_bits);
if (ret < 0)
{
MHD_gnutls_assert ();
CLEAR_CERTS;
return ret;
}
}
/* Verify certificate
*/
ret =
MHD_gnutls_x509_crt_list_verify (peer_certificate_list,
peer_certificate_list_size,
cred->x509_ca_list, cred->x509_ncas,
cred->x509_crl_list, cred->x509_ncrls,
cred->verify_flags, status);
CLEAR_CERTS;
if (ret < 0)
{
MHD_gnutls_assert ();
return ret;
}
return 0;
}
/*
* Read certificates and private keys, from memory etc.
*/
-1
View File
@@ -23,6 +23,5 @@ extensions.c extensions.h \
mpi.c mpi.h \
pkcs12.h \
x509_privkey.c privkey.h \
x509_verify.c verify.h \
x509.c x509.h
+2 -196
View File
@@ -218,7 +218,7 @@ MHD_gnutls_x509_dn_oid_known (const char *oid)
/* Returns 1 if the data defined by the OID are of a choice
* type.
*/
int
static int
MHD__gnutls_x509_oid_data_choice (const char *oid)
{
int i = 0;
@@ -815,7 +815,7 @@ MHD__gnutls_x509_export_int (ASN1_TYPE MHD__asn1_data,
* octet string. Otherwise put something like BMPString, PrintableString
* etc.
*/
int
static int
MHD__gnutls_x509_decode_octet_string (const char *string_type,
const opaque * der,
size_t der_size,
@@ -1029,200 +1029,6 @@ cleanup:MHD_gnutls_free (data);
}
/* DER Encodes the src ASN1_TYPE and stores it to
* dest in dest_name. Useful to encode something and store it
* as OCTET. If str is non null then the data are encoded as
* an OCTET STRING.
*/
int
MHD__gnutls_x509_der_encode_and_copy (ASN1_TYPE src,
const char *src_name,
ASN1_TYPE dest,
const char *dest_name, int str)
{
int result;
MHD_gnutls_datum_t encoded;
result = MHD__gnutls_x509_der_encode (src, src_name, &encoded, str);
if (result < 0)
{
MHD_gnutls_assert ();
return result;
}
/* Write the data.
*/
result =
MHD__asn1_write_value (dest, dest_name, encoded.data, encoded.size);
MHD__gnutls_free_datum (&encoded);
if (result != ASN1_SUCCESS)
{
MHD_gnutls_assert ();
return MHD_gtls_asn2err (result);
}
return 0;
}
/* Writes the value of the datum in the given ASN1_TYPE. If str is non
* zero it encodes it as OCTET STRING.
*/
int
MHD__gnutls_x509_write_value (ASN1_TYPE c,
const char *root,
const MHD_gnutls_datum_t * data, int str)
{
int result;
int asize;
ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
MHD_gnutls_datum_t val;
asize = data->size + 16;
val.data = MHD_gnutls_malloc (asize);
if (val.data == NULL)
{
MHD_gnutls_assert ();
result = GNUTLS_E_MEMORY_ERROR;
goto cleanup;
}
if (str)
{
/* Convert it to OCTET STRING
*/
if ((result =
MHD__asn1_create_element (MHD__gnutls_get_pkix (),
"PKIX1.pkcs-7-Data",
&c2)) != ASN1_SUCCESS)
{
MHD_gnutls_assert ();
result = MHD_gtls_asn2err (result);
goto cleanup;
}
result = MHD__asn1_write_value (c2, "", data->data, data->size);
if (result != ASN1_SUCCESS)
{
MHD_gnutls_assert ();
result = MHD_gtls_asn2err (result);
goto cleanup;
}
result = MHD__gnutls_x509_der_encode (c2, "", &val, 0);
if (result < 0)
{
MHD_gnutls_assert ();
goto cleanup;
}
}
else
{
val.data = data->data;
val.size = data->size;
}
/* Write the data.
*/
result = MHD__asn1_write_value (c, root, val.data, val.size);
if (val.data != data->data)
MHD__gnutls_free_datum (&val);
if (result != ASN1_SUCCESS)
{
MHD_gnutls_assert ();
return MHD_gtls_asn2err (result);
}
return 0;
cleanup:if (val.data != data->data)
MHD__gnutls_free_datum (&val);
return result;
}
/* Encodes and copies the private key parameters into a
* subjectPublicKeyInfo structure.
*
*/
int
MHD__gnutls_x509_encode_and_copy_PKI_params (ASN1_TYPE dst,
const char *dst_name,
enum
MHD_GNUTLS_PublicKeyAlgorithm
pk_algorithm, mpi_t * params,
int params_size)
{
const char *pk;
MHD_gnutls_datum_t der = { NULL,
0
};
int result;
char name[128];
pk = MHD_gtls_x509_pk_to_oid (pk_algorithm);
if (pk == NULL)
{
MHD_gnutls_assert ();
return GNUTLS_E_UNKNOWN_PK_ALGORITHM;
}
/* write the OID
*/
MHD_gtls_str_cpy (name, sizeof (name), dst_name);
MHD_gtls_str_cat (name, sizeof (name), ".algorithm.algorithm");
result = MHD__asn1_write_value (dst, name, pk, 1);
if (result != ASN1_SUCCESS)
{
MHD_gnutls_assert ();
return MHD_gtls_asn2err (result);
}
if (pk_algorithm == MHD_GNUTLS_PK_RSA)
{
/* disable parameters, which are not used in RSA.
*/
MHD_gtls_str_cpy (name, sizeof (name), dst_name);
MHD_gtls_str_cat (name, sizeof (name), ".algorithm.parameters");
result = MHD__asn1_write_value (dst, name, NULL, 0);
if (result != ASN1_SUCCESS)
{
MHD_gnutls_assert ();
return MHD_gtls_asn2err (result);
}
result = MHD__gnutls_x509_write_rsa_params (params, params_size, &der);
if (result < 0)
{
MHD_gnutls_assert ();
return result;
}
/* Write the DER parameters. (in bits)
*/
MHD_gtls_str_cpy (name, sizeof (name), dst_name);
MHD_gtls_str_cat (name, sizeof (name), ".subjectPublicKey");
result = MHD__asn1_write_value (dst, name, der.data, der.size * 8);
MHD__gnutls_free_datum (&der);
if (result != ASN1_SUCCESS)
{
MHD_gnutls_assert ();
return MHD_gtls_asn2err (result);
}
}
else
return GNUTLS_E_UNIMPLEMENTED_FEATURE;
return 0;
}
/* Reads and returns the PK algorithm of the given certificate-like
* ASN.1 structure. src_name should be something like "tbsCertificate.subjectPublicKeyInfo".
*/
-16
View File
@@ -58,10 +58,6 @@
#define SIG_GOST_R3410_94_OID "1.2.643.2.2.4"
#define SIG_GOST_R3410_2001_OID "1.2.643.2.2.3"
int MHD__gnutls_x509_decode_octet_string (const char *string_type,
const opaque * der, size_t der_size,
opaque * output,
size_t * output_size);
int MHD__gnutls_x509_oid_data2string (const char *OID, void *value,
int value_size, char *res,
size_t * res_size);
@@ -70,7 +66,6 @@ int MHD__gnutls_x509_data2hex (const opaque * data, size_t data_size,
const char *MHD__gnutls_x509_oid2ldap_string (const char *OID);
int MHD__gnutls_x509_oid_data_choice (const char *OID);
int MHD__gnutls_x509_oid_data_printable (const char *OID);
time_t MHD__gnutls_x509_get_time (ASN1_TYPE c2, const char *when);
@@ -78,9 +73,6 @@ time_t MHD__gnutls_x509_get_time (ASN1_TYPE c2, const char *when);
MHD_gnutls_x509_subject_alt_name_t MHD__gnutls_x509_san_find_type (char
*str_type);
int MHD__gnutls_x509_der_encode_and_copy (ASN1_TYPE src, const char *src_name,
ASN1_TYPE dest,
const char *dest_name, int str);
int MHD__gnutls_x509_der_encode (ASN1_TYPE src, const char *src_name,
MHD_gnutls_datum_t * res, int str);
@@ -91,8 +83,6 @@ int MHD__gnutls_x509_export_int (ASN1_TYPE MHD__asn1_data,
int MHD__gnutls_x509_read_value (ASN1_TYPE c, const char *root,
MHD_gnutls_datum_t * ret, int str);
int MHD__gnutls_x509_write_value (ASN1_TYPE c, const char *root,
const MHD_gnutls_datum_t * data, int str);
int MHD__gnutls_x509_decode_and_read_attribute (ASN1_TYPE MHD__asn1_struct,
const char *where, char *oid,
@@ -103,12 +93,6 @@ int MHD__gnutls_x509_decode_and_read_attribute (ASN1_TYPE MHD__asn1_struct,
int MHD__gnutls_x509_get_pk_algorithm (ASN1_TYPE src, const char *src_name,
unsigned int *bits);
int MHD__gnutls_x509_encode_and_copy_PKI_params (ASN1_TYPE dst,
const char *dst_name,
enum
MHD_GNUTLS_PublicKeyAlgorithm
pk_algorithm, mpi_t * params,
int params_size);
int MHD__gnutls_asn1_copy_node (ASN1_TYPE * dst, const char *dst_name,
ASN1_TYPE src, const char *src_name);
-33
View File
@@ -1,33 +0,0 @@
/*
* Copyright (C) 2003, 2004, 2005 Free Software Foundation
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of GNUTLS.
*
* The GNUTLS library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA
*
*/
#include "x509.h"
int MHD_gnutls_x509_crt_is_issuer (MHD_gnutls_x509_crt_t cert,
MHD_gnutls_x509_crt_t issuer);
int MHD__gnutls_x509_privkey_verify_signature (const MHD_gnutls_datum_t * tbs,
const MHD_gnutls_datum_t *
signature,
MHD_gnutls_x509_privkey_t
issuer);
-1
View File
@@ -37,7 +37,6 @@
#include <libtasn1.h>
#include <mpi.h>
#include <privkey.h>
#include <verify.h>
/**
* MHD_gnutls_x509_crt_init - This function initializes a MHD_gnutls_x509_crt_t structure
-9
View File
@@ -300,15 +300,6 @@ extern "C"
GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5 = 32
} MHD_gnutls_certificate_verify_flags;
int MHD_gnutls_x509_crt_list_verify (const MHD_gnutls_x509_crt_t *
cert_list, int cert_list_length,
const MHD_gnutls_x509_crt_t * CA_list,
int CA_list_length,
const MHD_gnutls_x509_crl_t * CRL_list,
int CRL_list_length,
unsigned int flags,
unsigned int *verify);
int MHD_gnutls_x509_crt_check_revocation (MHD_gnutls_x509_crt_t cert,
const MHD_gnutls_x509_crl_t *
crl_list, int crl_list_length);
-1
View File
@@ -35,7 +35,6 @@
#include <dn.h>
#include <mpi.h>
#include <extensions.h>
#include <verify.h>
static int MHD__gnutls_asn1_encode_rsa (ASN1_TYPE * c2, mpi_t * params);
int MHD__gnutls_asn1_encode_dsa (ASN1_TYPE * c2, mpi_t * params);
-715
View File
@@ -1,715 +0,0 @@
/*
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of GNUTLS.
*
* The GNUTLS library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA
*
*/
/* All functions which relate to X.509 certificate verification stuff are
* included here
*/
#include <gnutls_int.h>
#include <gnutls_errors.h>
#include <gnutls_cert.h>
#include <libtasn1.h>
#include <gnutls_global.h>
#include <gnutls_num.h> /* MAX */
#include <gnutls_sig.h>
#include <gnutls_str.h>
#include <gnutls_datum.h>
#include <dn.h>
#include <x509.h>
#include <mpi.h>
#include <common.h>
#include <verify.h>
static int MHD__gnutls_verify_certificate2 (MHD_gnutls_x509_crt_t cert,
const MHD_gnutls_x509_crt_t *
trusted_cas, int tcas_size,
unsigned int flags,
unsigned int *output);
static int MHD__gnutls_x509_verify_signature (const MHD_gnutls_datum_t * signed_data,
const MHD_gnutls_datum_t * signature,
MHD_gnutls_x509_crt_t issuer);
/* Checks if the issuer of a certificate is a
* Certificate Authority, or if the certificate is the same
* as the issuer (and therefore it doesn't need to be a CA).
*
* Returns true or false, if the issuer is a CA,
* or not.
*/
static int
check_if_ca (MHD_gnutls_x509_crt_t cert,
MHD_gnutls_x509_crt_t issuer, unsigned int flags)
{
MHD_gnutls_datum_t cert_signed_data = { NULL,
0
};
MHD_gnutls_datum_t issuer_signed_data = { NULL,
0
};
MHD_gnutls_datum_t cert_signature = { NULL,
0
};
MHD_gnutls_datum_t issuer_signature = { NULL,
0
};
int result;
/* Check if the issuer is the same with the
* certificate. This is added in order for trusted
* certificates to be able to verify themselves.
*/
result = MHD__gnutls_x509_get_signed_data (issuer->cert, "tbsCertificate",
&issuer_signed_data);
if (result < 0)
{
MHD_gnutls_assert ();
goto cleanup;
}
result = MHD__gnutls_x509_get_signed_data (cert->cert, "tbsCertificate",
&cert_signed_data);
if (result < 0)
{
MHD_gnutls_assert ();
goto cleanup;
}
result = MHD__gnutls_x509_get_signature (issuer->cert, "signature",
&issuer_signature);
if (result < 0)
{
MHD_gnutls_assert ();
goto cleanup;
}
result =
MHD__gnutls_x509_get_signature (cert->cert, "signature", &cert_signature);
if (result < 0)
{
MHD_gnutls_assert ();
goto cleanup;
}
/* If the subject certificate is the same as the issuer
* return true.
*/
if (!(flags & GNUTLS_VERIFY_DO_NOT_ALLOW_SAME))
if (cert_signed_data.size == issuer_signed_data.size)
{
if ((memcmp (cert_signed_data.data, issuer_signed_data.data,
cert_signed_data.size) == 0) && (cert_signature.size
==
issuer_signature.size)
&&
(memcmp
(cert_signature.data, issuer_signature.data,
cert_signature.size) == 0))
{
result = 1;
goto cleanup;
}
}
if (MHD_gnutls_x509_crt_get_ca_status (issuer, NULL) == 1)
{
result = 1;
goto cleanup;
}
else
MHD_gnutls_assert ();
result = 0;
cleanup:MHD__gnutls_free_datum (&cert_signed_data);
MHD__gnutls_free_datum (&issuer_signed_data);
MHD__gnutls_free_datum (&cert_signature);
MHD__gnutls_free_datum (&issuer_signature);
return result;
}
/* This function checks if 'certs' issuer is 'issuer_cert'.
* This does a straight (DER) compare of the issuer/subject fields in
* the given certificates.
*
* Returns 1 if they match and zero if they don't match. Otherwise
* a negative value is returned to indicate error.
*/
static int
is_issuer (MHD_gnutls_x509_crt_t cert, MHD_gnutls_x509_crt_t issuer_cert)
{
MHD_gnutls_datum_t dn1 = { NULL,
0
}, dn2 =
{
NULL, 0};
int ret;
ret = MHD_gnutls_x509_crt_get_raw_issuer_dn (cert, &dn1);
if (ret < 0)
{
MHD_gnutls_assert ();
goto cleanup;
}
ret = MHD_gnutls_x509_crt_get_raw_dn (issuer_cert, &dn2);
if (ret < 0)
{
MHD_gnutls_assert ();
goto cleanup;
}
ret = MHD__gnutls_x509_compare_raw_dn (&dn1, &dn2);
cleanup:MHD__gnutls_free_datum (&dn1);
MHD__gnutls_free_datum (&dn2);
return ret;
}
static inline MHD_gnutls_x509_crt_t
find_issuer (MHD_gnutls_x509_crt_t cert,
const MHD_gnutls_x509_crt_t * trusted_cas, int tcas_size)
{
int i;
/* this is serial search.
*/
for (i = 0; i < tcas_size; i++)
{
if (is_issuer (cert, trusted_cas[i]) == 1)
return trusted_cas[i];
}
MHD_gnutls_assert ();
return NULL;
}
/*
* Verifies the given certificate again a certificate list of
* trusted CAs.
*
* Returns only 0 or 1. If 1 it means that the certificate
* was successfuly verified.
*
* 'flags': an OR of the MHD_gnutls_certificate_verify_flags enumeration.
*
* Output will hold some extra information about the verification
* procedure.
*/
static int
MHD__gnutls_verify_certificate2 (MHD_gnutls_x509_crt_t cert,
const MHD_gnutls_x509_crt_t * trusted_cas,
int tcas_size,
unsigned int flags, unsigned int *output)
{
MHD_gnutls_datum_t cert_signed_data = { NULL,
0
};
MHD_gnutls_datum_t cert_signature = { NULL,
0
};
MHD_gnutls_x509_crt_t issuer;
int ret, issuer_version, result;
if (output)
*output = 0;
if (tcas_size >= 1)
issuer = find_issuer (cert, trusted_cas, tcas_size);
else
{
MHD_gnutls_assert ();
if (output)
*output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID;
return 0;
}
/* issuer is not in trusted certificate
* authorities.
*/
if (issuer == NULL)
{
if (output)
*output |= GNUTLS_CERT_SIGNER_NOT_FOUND | GNUTLS_CERT_INVALID;
MHD_gnutls_assert ();
return 0;
}
issuer_version = MHD_gnutls_x509_crt_get_version (issuer);
if (issuer_version < 0)
{
MHD_gnutls_assert ();
return issuer_version;
}
if (!(flags & GNUTLS_VERIFY_DISABLE_CA_SIGN) && !((flags
&
GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT)
&& issuer_version == 1))
{
if (check_if_ca (cert, issuer, flags) == 0)
{
MHD_gnutls_assert ();
if (output)
*output |= GNUTLS_CERT_SIGNER_NOT_CA | GNUTLS_CERT_INVALID;
return 0;
}
}
result = MHD__gnutls_x509_get_signed_data (cert->cert, "tbsCertificate",
&cert_signed_data);
if (result < 0)
{
MHD_gnutls_assert ();
goto cleanup;
}
result =
MHD__gnutls_x509_get_signature (cert->cert, "signature", &cert_signature);
if (result < 0)
{
MHD_gnutls_assert ();
goto cleanup;
}
ret = MHD__gnutls_x509_verify_signature (&cert_signed_data, &cert_signature,
issuer);
if (ret < 0)
{
MHD_gnutls_assert ();
}
else if (ret == 0)
{
MHD_gnutls_assert ();
/* error. ignore it */
if (output)
*output |= GNUTLS_CERT_INVALID;
ret = 0;
}
/* If the certificate is not self signed check if the algorithms
* used are secure. If the certificate is self signed it doesn't
* really matter.
*/
if (is_issuer (cert, cert) == 0)
{
int sigalg;
sigalg = MHD_gnutls_x509_crt_get_signature_algorithm (cert);
if (((sigalg == GNUTLS_SIGN_RSA_MD2) && !(flags
&
GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD2))
|| ((sigalg == GNUTLS_SIGN_RSA_MD5)
&& !(flags & GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5)))
{
if (output)
*output |= GNUTLS_CERT_INSECURE_ALGORITHM | GNUTLS_CERT_INVALID;
}
}
result = ret;
cleanup:MHD__gnutls_free_datum (&cert_signed_data);
MHD__gnutls_free_datum (&cert_signature);
return result;
}
/**
* MHD_gnutls_x509_crt_check_issuer - This function checks if the certificate given has the given issuer
* @cert: is the certificate to be checked
* @issuer: is the certificate of a possible issuer
*
* This function will check if the given certificate was issued by the
* given issuer. It will return true (1) if the given certificate is issued
* by the given issuer, and false (0) if not.
*
* A negative value is returned in case of an error.
*
**/
static int
MHD_gnutls_x509_crt_check_issuer (MHD_gnutls_x509_crt_t cert,
MHD_gnutls_x509_crt_t issuer)
{
return is_issuer (cert, issuer);
}
/* The algorithm used is:
* 1. Check last certificate in the chain. If it is not verified return.
* 2. Check if any certificates in the chain are revoked. If yes return.
* 3. Try to verify the rest of certificates in the chain. If not verified return.
* 4. Return 0.
*
* Note that the return value is an OR of GNUTLS_CERT_* elements.
*
* This function verifies a X.509 certificate list. The certificate list should
* lead to a trusted CA in order to be trusted.
*/
static unsigned int
MHD__gnutls_x509_verify_certificate (const MHD_gnutls_x509_crt_t *
certificate_list, int clist_size,
const MHD_gnutls_x509_crt_t *
trusted_cas, int tcas_size,
const MHD_gnutls_x509_crl_t * CRLs,
int crls_size, unsigned int flags)
{
int i = 0, ret;
unsigned int status = 0, output;
/* Verify the last certificate in the certificate path
* against the trusted CA certificate list.
*
* If no CAs are present returns CERT_INVALID. Thus works
* in self signed etc certificates.
*/
ret = MHD__gnutls_verify_certificate2 (certificate_list[clist_size - 1],
trusted_cas, tcas_size, flags,
&output);
if (ret == 0)
{
/* if the last certificate in the certificate
* list is invalid, then the certificate is not
* trusted.
*/
MHD_gnutls_assert ();
status |= output;
status |= GNUTLS_CERT_INVALID;
return status;
}
/* 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).
*/
if (MHD_gnutls_x509_crt_check_issuer (certificate_list[clist_size - 1],
certificate_list[clist_size - 1]) > 0
&& clist_size > 0)
{
clist_size--;
}
/* Verify the certificate path (chain)
*/
for (i = clist_size - 1; i > 0; i--)
{
if (i - 1 < 0)
break;
/* note that here we disable this V1 CA flag. So that no version 1
* certificates can exist in a supplied chain.
*/
if (!(flags & GNUTLS_VERIFY_ALLOW_ANY_X509_V1_CA_CRT))
flags ^= GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT;
if ((ret = MHD__gnutls_verify_certificate2 (certificate_list[i - 1],
&certificate_list[i], 1,
flags, NULL)) == 0)
{
status |= GNUTLS_CERT_INVALID;
return status;
}
}
return 0;
}
/* Reads the digest information.
* we use DER here, although we should use BER. It works fine
* anyway.
*/
static int
decode_ber_digest_info (const MHD_gnutls_datum_t * info,
enum MHD_GNUTLS_HashAlgorithm *hash,
opaque * digest, int *digest_size)
{
ASN1_TYPE dinfo = ASN1_TYPE_EMPTY;
int result;
char str[1024];
int len;
if ((result = MHD__asn1_create_element (MHD__gnutls_getMHD__gnutls_asn (),
"GNUTLS.DigestInfo",
&dinfo)) != ASN1_SUCCESS)
{
MHD_gnutls_assert ();
return MHD_gtls_asn2err (result);
}
result = MHD__asn1_der_decoding (&dinfo, info->data, info->size, NULL);
if (result != ASN1_SUCCESS)
{
MHD_gnutls_assert ();
MHD__asn1_delete_structure (&dinfo);
return MHD_gtls_asn2err (result);
}
len = sizeof (str) - 1;
result =
MHD__asn1_read_value (dinfo, "digestAlgorithm.algorithm", str, &len);
if (result != ASN1_SUCCESS)
{
MHD_gnutls_assert ();
MHD__asn1_delete_structure (&dinfo);
return MHD_gtls_asn2err (result);
}
*hash = MHD_gtls_x509_oid2mac_algorithm (str);
if (*hash == MHD_GNUTLS_MAC_UNKNOWN)
{
MHD__gnutls_x509_log ("verify.c: HASH OID: %s\n", str);
MHD_gnutls_assert ();
MHD__asn1_delete_structure (&dinfo);
return GNUTLS_E_UNKNOWN_ALGORITHM;
}
len = sizeof (str) - 1;
result =
MHD__asn1_read_value (dinfo, "digestAlgorithm.parameters", str, &len);
/* To avoid permitting garbage in the parameters field, either the
parameters field is not present, or it contains 0x05 0x00. */
if (!
(result == ASN1_ELEMENT_NOT_FOUND
|| (result == ASN1_SUCCESS && len == 2 && str[0] == 0x05
&& str[1] == 0x00)))
{
MHD_gnutls_assert ();
MHD__asn1_delete_structure (&dinfo);
return GNUTLS_E_ASN1_GENERIC_ERROR;
}
result = MHD__asn1_read_value (dinfo, "digest", digest, digest_size);
if (result != ASN1_SUCCESS)
{
MHD_gnutls_assert ();
MHD__asn1_delete_structure (&dinfo);
return MHD_gtls_asn2err (result);
}
MHD__asn1_delete_structure (&dinfo);
return 0;
}
/* if hash==MD5 then we do RSA-MD5
* if hash==SHA then we do RSA-SHA
* params[0] is modulus
* params[1] is public key
*/
static int
_pkcs1_rsa_verify_sig (const MHD_gnutls_datum_t * text,
const MHD_gnutls_datum_t * signature,
mpi_t * params, int params_len)
{
enum MHD_GNUTLS_HashAlgorithm hash = MHD_GNUTLS_MAC_UNKNOWN;
int ret;
opaque digest[MAX_HASH_SIZE], md[MAX_HASH_SIZE];
int digest_size;
GNUTLS_HASH_HANDLE hd;
MHD_gnutls_datum_t decrypted;
ret =
MHD_gtls_pkcs1_rsa_decrypt (&decrypted, signature, params, params_len, 1);
if (ret < 0)
{
MHD_gnutls_assert ();
return ret;
}
/* decrypted is a BER encoded data of type DigestInfo
*/
digest_size = sizeof (digest);
if ((ret = decode_ber_digest_info (&decrypted, &hash, digest, &digest_size))
!= 0)
{
MHD_gnutls_assert ();
MHD__gnutls_free_datum (&decrypted);
return ret;
}
MHD__gnutls_free_datum (&decrypted);
if (digest_size != MHD_gnutls_hash_get_algo_len (hash))
{
MHD_gnutls_assert ();
return GNUTLS_E_ASN1_GENERIC_ERROR;
}
hd = MHD_gtls_hash_init (hash);
if (hd == NULL)
{
MHD_gnutls_assert ();
return GNUTLS_E_HASH_FAILED;
}
MHD_gnutls_hash (hd, text->data, text->size);
MHD_gnutls_hash_deinit (hd, md);
if (memcmp (md, digest, digest_size) != 0)
{
MHD_gnutls_assert ();
return GNUTLS_E_PK_SIG_VERIFY_FAILED;
}
return 0;
}
/* Verifies the signature data, and returns 0 if not verified,
* or 1 otherwise.
*/
static int
verify_sig (const MHD_gnutls_datum_t * tbs,
const MHD_gnutls_datum_t * signature,
enum MHD_GNUTLS_PublicKeyAlgorithm pk,
mpi_t * issuer_params, int issuer_params_size)
{
switch (pk)
{
case MHD_GNUTLS_PK_RSA:
if (_pkcs1_rsa_verify_sig
(tbs, signature, issuer_params, issuer_params_size) != 0)
{
MHD_gnutls_assert ();
return 0;
}
return 1;
break;
default:
MHD_gnutls_assert ();
return GNUTLS_E_INTERNAL_ERROR;
}
}
/* verifies if the certificate is properly signed.
* returns 0 on failure and 1 on success.
*
* 'tbs' is the signed data
* 'signature' is the signature!
*/
static int
MHD__gnutls_x509_verify_signature (const MHD_gnutls_datum_t * tbs,
const MHD_gnutls_datum_t * signature,
MHD_gnutls_x509_crt_t issuer)
{
mpi_t issuer_params[MAX_PUBLIC_PARAMS_SIZE];
int ret, issuer_params_size, i;
/* Read the MPI parameters from the issuer's certificate.
*/
issuer_params_size = MAX_PUBLIC_PARAMS_SIZE;
ret =
MHD__gnutls_x509_crt_get_mpis (issuer, issuer_params,
&issuer_params_size);
if (ret < 0)
{
MHD_gnutls_assert ();
return ret;
}
ret =
verify_sig (tbs, signature,
MHD_gnutls_x509_crt_get_pk_algorithm (issuer, NULL),
issuer_params, issuer_params_size);
if (ret < 0)
{
MHD_gnutls_assert ();
}
/* release all allocated MPIs
*/
for (i = 0; i < issuer_params_size; i++)
{
MHD_gtls_mpi_release (&issuer_params[i]);
}
return ret;
}
/**
* MHD_gnutls_x509_crt_list_verify - This function verifies the given certificate list
* @cert_list: is the certificate list to be verified
* @cert_list_length: holds the number of certificate in cert_list
* @CA_list: is the CA list which will be used in verification
* @CA_list_length: holds the number of CA certificate in CA_list
* @CRL_list: holds a list of CRLs.
* @CRL_list_length: the length of CRL list.
* @flags: Flags that may be used to change the verification algorithm. Use OR of the MHD_gnutls_certificate_verify_flags enumerations.
* @verify: will hold the certificate verification output.
*
* This function will try to verify the given certificate list and return its status.
* Note that expiration and activation dates are not checked
* by this function, you should check them using the appropriate functions.
*
* If no flags are specified (0), this function will use the
* basicConstraints (2.5.29.19) PKIX extension. This means that only a certificate
* authority is allowed to sign a certificate.
*
* You must also check the peer's name in order to check if the verified
* certificate belongs to the actual peer.
*
* The certificate verification output will be put in @verify and will be
* one or more of the MHD_gnutls_certificate_status_t enumerated elements bitwise or'd.
* For a more detailed verification status use MHD_gnutls_x509_crt_verify() per list
* element.
*
* GNUTLS_CERT_INVALID: the certificate chain is not valid.
*
* GNUTLS_CERT_REVOKED: a certificate in the chain has been revoked.
*
* Returns 0 on success and a negative value in case of an error.
*
**/
int
MHD_gnutls_x509_crt_list_verify (const MHD_gnutls_x509_crt_t * cert_list,
int cert_list_length,
const MHD_gnutls_x509_crt_t * CA_list,
int CA_list_length,
const MHD_gnutls_x509_crl_t * CRL_list,
int CRL_list_length,
unsigned int flags, unsigned int *verify)
{
if (cert_list == NULL || cert_list_length == 0)
return GNUTLS_E_NO_CERTIFICATE_FOUND;
/* Verify certificate
*/
*verify = MHD__gnutls_x509_verify_certificate (cert_list, cert_list_length,
CA_list, CA_list_length,
CRL_list, CRL_list_length,
flags);
return 0;
}