/*
* Copyright (C) 2003-2012 Free Software Foundation, Inc.
* Author: Nikos Mavrogiannopoulos, Simon Josefsson, Howard Chu
*
* This file is part of GnuTLS.
*
* The GnuTLS 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 3 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 program. If not, see
*
*/
/* Functions on X.509 Certificate parsing
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/**
* gnutls_x509_crt_init:
* @cert: The structure to be initialized
*
* This function will initialize an X.509 certificate structure.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
**/
int
gnutls_x509_crt_init (gnutls_x509_crt_t * cert)
{
gnutls_x509_crt_t tmp = gnutls_calloc (1, sizeof (gnutls_x509_crt_int));
int result;
if (!tmp)
return GNUTLS_E_MEMORY_ERROR;
result = asn1_create_element (_gnutls_get_pkix (),
"PKIX1.Certificate", &tmp->cert);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
gnutls_free (tmp);
return _gnutls_asn2err (result);
}
/* If you add anything here, be sure to check if it has to be added
to gnutls_x509_crt_import as well. */
*cert = tmp;
return 0; /* success */
}
/*-
* _gnutls_x509_crt_cpy - This function copies a gnutls_x509_crt_t structure
* @dest: The structure where to copy
* @src: The structure to be copied
*
* This function will copy an X.509 certificate structure.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
-*/
int
_gnutls_x509_crt_cpy (gnutls_x509_crt_t dest, gnutls_x509_crt_t src)
{
int ret;
size_t der_size=0;
uint8_t *der;
gnutls_datum_t tmp;
ret = gnutls_x509_crt_export (src, GNUTLS_X509_FMT_DER, NULL, &der_size);
if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
{
gnutls_assert ();
return ret;
}
der = gnutls_malloc (der_size);
if (der == NULL)
{
gnutls_assert ();
return GNUTLS_E_MEMORY_ERROR;
}
ret = gnutls_x509_crt_export (src, GNUTLS_X509_FMT_DER, der, &der_size);
if (ret < 0)
{
gnutls_assert ();
gnutls_free (der);
return ret;
}
tmp.data = der;
tmp.size = der_size;
ret = gnutls_x509_crt_import (dest, &tmp, GNUTLS_X509_FMT_DER);
gnutls_free (der);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
return 0;
}
/**
* gnutls_x509_crt_deinit:
* @cert: The structure to be deinitialized
*
* This function will deinitialize a certificate structure.
**/
void
gnutls_x509_crt_deinit (gnutls_x509_crt_t cert)
{
if (!cert)
return;
if (cert->cert)
asn1_delete_structure (&cert->cert);
gnutls_free (cert);
}
/**
* gnutls_x509_crt_import:
* @cert: The structure to store the parsed certificate.
* @data: The DER or PEM encoded certificate.
* @format: One of DER or PEM
*
* This function will convert the given DER or PEM encoded Certificate
* to the native gnutls_x509_crt_t format. The output will be stored
* in @cert.
*
* If the Certificate is PEM encoded it should have a header of "X509
* CERTIFICATE", or "CERTIFICATE".
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
**/
int
gnutls_x509_crt_import (gnutls_x509_crt_t cert,
const gnutls_datum_t * data,
gnutls_x509_crt_fmt_t format)
{
int result = 0, need_free = 0;
gnutls_datum_t _data;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
_data.data = data->data;
_data.size = data->size;
/* If the Certificate is in PEM format then decode it
*/
if (format == GNUTLS_X509_FMT_PEM)
{
uint8_t *out;
/* Try the first header */
result =
_gnutls_fbase64_decode (PEM_X509_CERT2, data->data, data->size, &out);
if (result <= 0)
{
/* try for the second header */
result =
_gnutls_fbase64_decode (PEM_X509_CERT, data->data,
data->size, &out);
if (result <= 0)
{
if (result == 0)
result = GNUTLS_E_INTERNAL_ERROR;
gnutls_assert ();
return result;
}
}
_data.data = out;
_data.size = result;
need_free = 1;
}
if (cert->cert)
{
/* Any earlier asn1_der_decoding will modify the ASN.1
structure, so we need to replace it with a fresh
structure. */
asn1_delete_structure (&cert->cert);
result = asn1_create_element (_gnutls_get_pkix (),
"PKIX1.Certificate", &cert->cert);
if (result != ASN1_SUCCESS)
{
result = _gnutls_asn2err (result);
gnutls_assert ();
goto cleanup;
}
}
result = asn1_der_decoding (&cert->cert, _data.data, _data.size, NULL);
if (result != ASN1_SUCCESS)
{
result = _gnutls_asn2err (result);
gnutls_assert ();
goto cleanup;
}
/* Since we do not want to disable any extension
*/
cert->use_extensions = 1;
if (need_free)
_gnutls_free_datum (&_data);
return 0;
cleanup:
if (need_free)
_gnutls_free_datum (&_data);
return result;
}
/**
* gnutls_x509_crt_get_issuer_dn:
* @cert: should contain a #gnutls_x509_crt_t structure
* @buf: a pointer to a structure to hold the name (may be null)
* @buf_size: initially holds the size of @buf
*
* This function will copy the name of the Certificate issuer in the
* provided buffer. The name will be in the form
* "C=xxxx,O=yyyy,CN=zzzz" as described in RFC4514. The output string
* will be ASCII or UTF-8 encoded, depending on the certificate data.
*
* If @buf is null then only the size will be filled.
*
* Returns: GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is not
* long enough, and in that case the @buf_size will be updated with
* the required size. On success 0 is returned.
**/
int
gnutls_x509_crt_get_issuer_dn (gnutls_x509_crt_t cert, char *buf,
size_t * buf_size)
{
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
return _gnutls_x509_parse_dn (cert->cert,
"tbsCertificate.issuer.rdnSequence", buf,
buf_size);
}
/**
* gnutls_x509_crt_get_issuer_dn_by_oid:
* @cert: should contain a #gnutls_x509_crt_t structure
* @oid: holds an Object Identified in null terminated string
* @indx: In case multiple same OIDs exist in the RDN, this specifies which to send. Use (0) to get the first one.
* @raw_flag: If non (0) returns the raw DER data of the DN part.
* @buf: a pointer to a structure to hold the name (may be null)
* @buf_size: initially holds the size of @buf
*
* This function will extract the part of the name of the Certificate
* issuer specified by the given OID. The output, if the raw flag is not
* used, will be encoded as described in RFC4514. Thus a string that is
* ASCII or UTF-8 encoded, depending on the certificate data.
*
* Some helper macros with popular OIDs can be found in gnutls/x509.h
* If raw flag is (0), this function will only return known OIDs as
* text. Other OIDs will be DER encoded, as described in RFC4514 --
* in hex format with a '#' prefix. You can check about known OIDs
* using gnutls_x509_dn_oid_known().
*
* If @buf is null then only the size will be filled. If the @raw_flag
* is not specified the output is always null terminated, although the
* @buf_size will not include the null character.
*
* Returns: GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is not
* long enough, and in that case the @buf_size will be updated
* with the required size. On success 0 is returned.
**/
int
gnutls_x509_crt_get_issuer_dn_by_oid (gnutls_x509_crt_t cert,
const char *oid, int indx,
unsigned int raw_flag, void *buf,
size_t * buf_size)
{
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
return _gnutls_x509_parse_dn_oid (cert->cert,
"tbsCertificate.issuer.rdnSequence",
oid, indx, raw_flag, buf, buf_size);
}
/**
* gnutls_x509_crt_get_issuer_dn_oid:
* @cert: should contain a #gnutls_x509_crt_t structure
* @indx: This specifies which OID to return. Use (0) to get the first one.
* @oid: a pointer to a buffer to hold the OID (may be null)
* @oid_size: initially holds the size of @oid
*
* This function will extract the OIDs of the name of the Certificate
* issuer specified by the given index.
*
* If @oid is null then only the size will be filled. The @oid
* returned will be null terminated, although @oid_size will not
* account for the trailing null.
*
* Returns: GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is not
* long enough, and in that case the @oid_size will be updated
* with the required size. On success 0 is returned.
**/
int
gnutls_x509_crt_get_issuer_dn_oid (gnutls_x509_crt_t cert,
int indx, void *oid, size_t * oid_size)
{
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
return _gnutls_x509_get_dn_oid (cert->cert,
"tbsCertificate.issuer.rdnSequence",
indx, oid, oid_size);
}
/**
* gnutls_x509_crt_get_dn:
* @cert: should contain a #gnutls_x509_crt_t structure
* @buf: a pointer to a structure to hold the name (may be null)
* @buf_size: initially holds the size of @buf
*
* This function will copy the name of the Certificate in the provided
* buffer. The name will be in the form "C=xxxx,O=yyyy,CN=zzzz" as
* described in RFC4514. The output string will be ASCII or UTF-8
* encoded, depending on the certificate data.
*
* If @buf is null then only the size will be filled.
*
* Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is not
* long enough, and in that case the @buf_size will be updated
* with the required size. On success 0 is returned.
**/
int
gnutls_x509_crt_get_dn (gnutls_x509_crt_t cert, char *buf,
size_t * buf_size)
{
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
return _gnutls_x509_parse_dn (cert->cert,
"tbsCertificate.subject.rdnSequence", buf,
buf_size);
}
/**
* gnutls_x509_crt_get_dn_by_oid:
* @cert: should contain a #gnutls_x509_crt_t structure
* @oid: holds an Object Identified in null terminated string
* @indx: In case multiple same OIDs exist in the RDN, this specifies which to send. Use (0) to get the first one.
* @raw_flag: If non (0) returns the raw DER data of the DN part.
* @buf: a pointer where the DN part will be copied (may be null).
* @buf_size: initially holds the size of @buf
*
* This function will extract the part of the name of the Certificate
* subject specified by the given OID. The output, if the raw flag is
* not used, will be encoded as described in RFC4514. Thus a string
* that is ASCII or UTF-8 encoded, depending on the certificate data.
*
* Some helper macros with popular OIDs can be found in gnutls/x509.h
* If raw flag is (0), this function will only return known OIDs as
* text. Other OIDs will be DER encoded, as described in RFC4514 --
* in hex format with a '#' prefix. You can check about known OIDs
* using gnutls_x509_dn_oid_known().
*
* If @buf is null then only the size will be filled. If the @raw_flag
* is not specified the output is always null terminated, although the
* @buf_size will not include the null character.
*
* Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is
* not long enough, and in that case the *buf_size will be updated
* with the required size. On success 0 is returned.
**/
int
gnutls_x509_crt_get_dn_by_oid (gnutls_x509_crt_t cert, const char *oid,
int indx, unsigned int raw_flag,
void *buf, size_t * buf_size)
{
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
return _gnutls_x509_parse_dn_oid (cert->cert,
"tbsCertificate.subject.rdnSequence",
oid, indx, raw_flag, buf, buf_size);
}
/**
* gnutls_x509_crt_get_dn_oid:
* @cert: should contain a #gnutls_x509_crt_t structure
* @indx: This specifies which OID to return. Use (0) to get the first one.
* @oid: a pointer to a buffer to hold the OID (may be null)
* @oid_size: initially holds the size of @oid
*
* This function will extract the OIDs of the name of the Certificate
* subject specified by the given index.
*
* If @oid is null then only the size will be filled. The @oid
* returned will be null terminated, although @oid_size will not
* account for the trailing null.
*
* Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is
* not long enough, and in that case the @oid_size will be updated
* with the required size. On success 0 is returned.
**/
int
gnutls_x509_crt_get_dn_oid (gnutls_x509_crt_t cert,
int indx, void *oid, size_t * oid_size)
{
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
return _gnutls_x509_get_dn_oid (cert->cert,
"tbsCertificate.subject.rdnSequence",
indx, oid, oid_size);
}
/**
* gnutls_x509_crt_get_signature_algorithm:
* @cert: should contain a #gnutls_x509_crt_t structure
*
* This function will return a value of the #gnutls_sign_algorithm_t
* enumeration that is the signature algorithm that has been used to
* sign this certificate.
*
* Returns: a #gnutls_sign_algorithm_t value, or a negative error code on
* error.
**/
int
gnutls_x509_crt_get_signature_algorithm (gnutls_x509_crt_t cert)
{
return _gnutls_x509_get_signature_algorithm(cert->cert, "signatureAlgorithm.algorithm");
}
/**
* gnutls_x509_crt_get_signature:
* @cert: should contain a #gnutls_x509_crt_t structure
* @sig: a pointer where the signature part will be copied (may be null).
* @sizeof_sig: initially holds the size of @sig
*
* This function will extract the signature field of a certificate.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value. and a negative error code on error.
**/
int
gnutls_x509_crt_get_signature (gnutls_x509_crt_t cert,
char *sig, size_t * sizeof_sig)
{
int result;
unsigned int bits;
int len;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
len = 0;
result = asn1_read_value (cert->cert, "signature", NULL, &len);
if (result != ASN1_MEM_ERROR)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
bits = len;
if (bits % 8 != 0)
{
gnutls_assert ();
return GNUTLS_E_CERTIFICATE_ERROR;
}
len = bits / 8;
if (*sizeof_sig < (unsigned int) len)
{
*sizeof_sig = len;
return GNUTLS_E_SHORT_MEMORY_BUFFER;
}
result = asn1_read_value (cert->cert, "signature", sig, &len);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
return 0;
}
/**
* gnutls_x509_crt_get_version:
* @cert: should contain a #gnutls_x509_crt_t structure
*
* This function will return the version of the specified Certificate.
*
* Returns: version of certificate, or a negative error code on error.
**/
int
gnutls_x509_crt_get_version (gnutls_x509_crt_t cert)
{
uint8_t version[8];
int len, result;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
len = sizeof (version);
if ((result =
asn1_read_value (cert->cert, "tbsCertificate.version", version,
&len)) != ASN1_SUCCESS)
{
if (result == ASN1_ELEMENT_NOT_FOUND)
return 1; /* the DEFAULT version */
gnutls_assert ();
return _gnutls_asn2err (result);
}
return (int) version[0] + 1;
}
/**
* gnutls_x509_crt_get_activation_time:
* @cert: should contain a #gnutls_x509_crt_t structure
*
* This function will return the time this Certificate was or will be
* activated.
*
* Returns: activation time, or (time_t)-1 on error.
**/
time_t
gnutls_x509_crt_get_activation_time (gnutls_x509_crt_t cert)
{
if (cert == NULL)
{
gnutls_assert ();
return (time_t) - 1;
}
return _gnutls_x509_get_time (cert->cert,
"tbsCertificate.validity.notBefore");
}
/**
* gnutls_x509_crt_get_expiration_time:
* @cert: should contain a #gnutls_x509_crt_t structure
*
* This function will return the time this Certificate was or will be
* expired.
*
* Returns: expiration time, or (time_t)-1 on error.
**/
time_t
gnutls_x509_crt_get_expiration_time (gnutls_x509_crt_t cert)
{
if (cert == NULL)
{
gnutls_assert ();
return (time_t) - 1;
}
return _gnutls_x509_get_time (cert->cert,
"tbsCertificate.validity.notAfter");
}
/**
* gnutls_x509_crt_get_serial:
* @cert: should contain a #gnutls_x509_crt_t structure
* @result: The place where the serial number will be copied
* @result_size: Holds the size of the result field.
*
* This function will return the X.509 certificate's serial number.
* This is obtained by the X509 Certificate serialNumber field. Serial
* is not always a 32 or 64bit number. Some CAs use large serial
* numbers, thus it may be wise to handle it as something uint8_t.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
**/
int
gnutls_x509_crt_get_serial (gnutls_x509_crt_t cert, void *result,
size_t * result_size)
{
int ret, len;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
len = *result_size;
ret =
asn1_read_value (cert->cert, "tbsCertificate.serialNumber", result, &len);
*result_size = len;
if (ret != ASN1_SUCCESS)
{
gnutls_assert ();
return _gnutls_asn2err (ret);
}
return 0;
}
/**
* gnutls_x509_crt_get_subject_key_id:
* @cert: should contain a #gnutls_x509_crt_t structure
* @ret: The place where the identifier will be copied
* @ret_size: Holds the size of the result field.
* @critical: will be non (0) if the extension is marked as critical (may be null)
*
* This function will return the X.509v3 certificate's subject key
* identifier. This is obtained by the X.509 Subject Key identifier
* extension field (2.5.29.14).
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
**/
int
gnutls_x509_crt_get_subject_key_id (gnutls_x509_crt_t cert, void *ret,
size_t * ret_size, unsigned int *critical)
{
int result, len;
gnutls_datum_t id;
ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
if (ret)
memset (ret, 0, *ret_size);
else
*ret_size = 0;
if ((result =
_gnutls_x509_crt_get_extension (cert, "2.5.29.14", 0, &id,
critical)) < 0)
{
return result;
}
if (id.size == 0 || id.data == NULL)
{
gnutls_assert ();
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
result = asn1_create_element
(_gnutls_get_pkix (), "PKIX1.SubjectKeyIdentifier", &c2);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
_gnutls_free_datum (&id);
return _gnutls_asn2err (result);
}
result = asn1_der_decoding (&c2, id.data, id.size, NULL);
_gnutls_free_datum (&id);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
asn1_delete_structure (&c2);
return _gnutls_asn2err (result);
}
len = *ret_size;
result = asn1_read_value (c2, "", ret, &len);
*ret_size = len;
asn1_delete_structure (&c2);
if (result == ASN1_VALUE_NOT_FOUND || result == ASN1_ELEMENT_NOT_FOUND)
{
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
if (result != ASN1_SUCCESS)
{
if (result != ASN1_MEM_ERROR)
gnutls_assert ();
return _gnutls_asn2err (result);
}
return 0;
}
static int
_get_authority_key_id (gnutls_x509_crt_t cert, ASN1_TYPE *c2,
unsigned int *critical)
{
int ret;
gnutls_datum_t id;
*c2 = ASN1_TYPE_EMPTY;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
if ((ret =
_gnutls_x509_crt_get_extension (cert, "2.5.29.35", 0, &id,
critical)) < 0)
{
return gnutls_assert_val(ret);
}
if (id.size == 0 || id.data == NULL)
{
gnutls_assert ();
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
ret = asn1_create_element
(_gnutls_get_pkix (), "PKIX1.AuthorityKeyIdentifier", c2);
if (ret != ASN1_SUCCESS)
{
gnutls_assert ();
_gnutls_free_datum (&id);
return _gnutls_asn2err (ret);
}
ret = asn1_der_decoding (c2, id.data, id.size, NULL);
_gnutls_free_datum (&id);
if (ret != ASN1_SUCCESS)
{
gnutls_assert ();
asn1_delete_structure (c2);
return _gnutls_asn2err (ret);
}
return 0;
}
/**
* gnutls_x509_crt_get_authority_key_gn_serial:
* @cert: should contain a #gnutls_x509_crt_t structure
* @seq: specifies the sequence number of the alt name (0 for the first one, 1 for the second etc.)
* @alt: is the place where the alternative name will be copied to
* @alt_size: holds the size of alt.
* @alt_type: holds the type of the alternative name (one of gnutls_x509_subject_alt_name_t).
* @serial: buffer to store the serial number (may be null)
* @serial_size: Holds the size of the serial field (may be null)
* @critical: will be non (0) if the extension is marked as critical (may be null)
*
* This function will return the X.509 authority key
* identifier when stored as a general name (authorityCertIssuer)
* and serial number.
*
* Because more than one general names might be stored
* @seq can be used as a counter to request them all until
* %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
*
* Returns: Returns 0 on success, or an error code.
*
* Since: 3.0.0
**/
int
gnutls_x509_crt_get_authority_key_gn_serial (gnutls_x509_crt_t cert, unsigned int seq, void *alt,
size_t * alt_size, unsigned int *alt_type,
void* serial, size_t *serial_size,
unsigned int *critical)
{
int ret, result, len;
ASN1_TYPE c2;
ret = _get_authority_key_id(cert, &c2, critical);
if (ret < 0)
return gnutls_assert_val(ret);
ret =
_gnutls_parse_general_name (c2, "authorityCertIssuer", seq, alt, alt_size, alt_type,
0);
if (ret < 0)
{
ret = gnutls_assert_val(ret);
goto fail;
}
if (serial)
{
len = *serial_size;
result = asn1_read_value (c2, "authorityCertSerialNumber", serial, &len);
*serial_size = len;
if (result < 0)
{
ret = _gnutls_asn2err(result);
goto fail;
}
}
ret = 0;
fail:
asn1_delete_structure (&c2);
return ret;
}
/**
* gnutls_x509_crt_get_authority_key_id:
* @cert: should contain a #gnutls_x509_crt_t structure
* @id: The place where the identifier will be copied
* @id_size: Holds the size of the id field.
* @critical: will be non (0) if the extension is marked as critical (may be null)
*
* This function will return the X.509v3 certificate authority's key
* identifier. This is obtained by the X.509 Authority Key
* identifier extension field (2.5.29.35). Note that this function
* only returns the keyIdentifier field of the extension and
* %GNUTLS_E_X509_UNSUPPORTED_EXTENSION, if the extension contains
* the name and serial number of the certificate. In that case
* gnutls_x509_crt_get_authority_key_gn_serial() may be used.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.
**/
int
gnutls_x509_crt_get_authority_key_id (gnutls_x509_crt_t cert, void *id,
size_t * id_size,
unsigned int *critical)
{
int ret, result, len;
ASN1_TYPE c2;
ret = _get_authority_key_id(cert, &c2, critical);
if (ret < 0)
return gnutls_assert_val(ret);
len = *id_size;
result = asn1_read_value (c2, "keyIdentifier", id, &len);
*id_size = len;
asn1_delete_structure (&c2);
if (result == ASN1_VALUE_NOT_FOUND || result == ASN1_ELEMENT_NOT_FOUND)
return gnutls_assert_val(GNUTLS_E_X509_UNSUPPORTED_EXTENSION);
if (result != ASN1_SUCCESS)
{
if (result != ASN1_MEM_ERROR)
gnutls_assert ();
return _gnutls_asn2err (result);
}
return 0;
}
/**
* gnutls_x509_crt_get_pk_algorithm:
* @cert: should contain a #gnutls_x509_crt_t structure
* @bits: if bits is non null it will hold the size of the parameters' in bits
*
* This function will return the public key algorithm of an X.509
* certificate.
*
* If bits is non null, it should have enough size to hold the parameters
* size in bits. For RSA the bits returned is the modulus.
* For DSA the bits returned are of the public
* exponent.
*
* Returns: a member of the #gnutls_pk_algorithm_t enumeration on
* success, or a negative error code on error.
**/
int
gnutls_x509_crt_get_pk_algorithm (gnutls_x509_crt_t cert, unsigned int *bits)
{
int result;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
if (bits)
*bits = 0;
result =
_gnutls_x509_get_pk_algorithm (cert->cert,
"tbsCertificate.subjectPublicKeyInfo",
bits);
if (result < 0)
{
gnutls_assert ();
return result;
}
return result;
}
inline static int
is_type_printable (int type)
{
if (type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_RFC822NAME ||
type == GNUTLS_SAN_URI)
return 1;
else
return 0;
}
#define XMPP_OID "1.3.6.1.5.5.7.8.5"
/* returns the type and the name on success.
* Type is also returned as a parameter in case of an error.
*/
int
_gnutls_parse_general_name (ASN1_TYPE src, const char *src_name,
int seq, void *name, size_t * name_size,
unsigned int *ret_type, int othername_oid)
{
int len;
char nptr[ASN1_MAX_NAME_SIZE];
int result;
char choice_type[128];
gnutls_x509_subject_alt_name_t type;
seq++; /* 0->1, 1->2 etc */
if (src_name[0] != 0)
snprintf (nptr, sizeof (nptr), "%s.?%u", src_name, seq);
else
snprintf (nptr, sizeof (nptr), "?%u", seq);
len = sizeof (choice_type);
result = asn1_read_value (src, nptr, choice_type, &len);
if (result == ASN1_VALUE_NOT_FOUND || result == ASN1_ELEMENT_NOT_FOUND)
{
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
type = _gnutls_x509_san_find_type (choice_type);
if (type == (gnutls_x509_subject_alt_name_t) - 1)
{
gnutls_assert ();
return GNUTLS_E_X509_UNKNOWN_SAN;
}
if (ret_type)
*ret_type = type;
if (type == GNUTLS_SAN_OTHERNAME)
{
if (othername_oid)
_gnutls_str_cat (nptr, sizeof (nptr), ".otherName.type-id");
else
_gnutls_str_cat (nptr, sizeof (nptr), ".otherName.value");
len = *name_size;
result = asn1_read_value (src, nptr, name, &len);
*name_size = len;
if (result == ASN1_MEM_ERROR)
return GNUTLS_E_SHORT_MEMORY_BUFFER;
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
if (othername_oid)
{
if ((unsigned)len > strlen (XMPP_OID) && strcmp (name, XMPP_OID) == 0)
type = GNUTLS_SAN_OTHERNAME_XMPP;
}
else
{
char oid[42];
if (src_name[0] != 0)
snprintf (nptr, sizeof (nptr), "%s.?%u.otherName.type-id",
src_name, seq);
else
snprintf (nptr, sizeof (nptr), "?%u.otherName.type-id", seq);
len = sizeof (oid);
result = asn1_read_value (src, nptr, oid, &len);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
if ((unsigned)len > strlen (XMPP_OID) && strcmp (oid, XMPP_OID) == 0)
{
ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
size_t orig_name_size = *name_size;
result = asn1_create_element
(_gnutls_get_pkix (), "PKIX1.UTF8String", &c2);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
result = asn1_der_decoding (&c2, name, *name_size, NULL);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
asn1_delete_structure (&c2);
return _gnutls_asn2err (result);
}
len = *name_size;
result = asn1_read_value (c2, "", name, &len);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
asn1_delete_structure (&c2);
*name_size = len + 1;
return _gnutls_asn2err (result);
}
asn1_delete_structure (&c2);
if ((unsigned)len + 1 > orig_name_size)
{
gnutls_assert ();
*name_size = len + 1;
return GNUTLS_E_SHORT_MEMORY_BUFFER;
}
*name_size = len;
/* null terminate it */
((char *) name)[*name_size] = 0;
}
}
}
else if (type == GNUTLS_SAN_DN)
{
_gnutls_str_cat (nptr, sizeof (nptr), ".directoryName");
result = _gnutls_x509_parse_dn (src, nptr, name, name_size);
if (result < 0)
{
gnutls_assert ();
return result;
}
}
else if (othername_oid)
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
else
{
size_t orig_name_size = *name_size;
_gnutls_str_cat (nptr, sizeof (nptr), ".");
_gnutls_str_cat (nptr, sizeof (nptr), choice_type);
len = *name_size;
result = asn1_read_value (src, nptr, name, &len);
*name_size = len;
if (result == ASN1_MEM_ERROR)
{
if (is_type_printable (type))
(*name_size)++;
return GNUTLS_E_SHORT_MEMORY_BUFFER;
}
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
if (is_type_printable (type))
{
if ((unsigned)len + 1 > orig_name_size)
{
gnutls_assert ();
(*name_size)++;
return GNUTLS_E_SHORT_MEMORY_BUFFER;
}
/* null terminate it */
((char *) name)[*name_size] = 0;
}
}
return type;
}
static int
get_alt_name (gnutls_x509_crt_t cert, const char *extension_id,
unsigned int seq, void *alt,
size_t * alt_size, unsigned int *alt_type,
unsigned int *critical, int othername_oid)
{
int result;
gnutls_datum_t dnsname;
ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
if (alt)
memset (alt, 0, *alt_size);
else
*alt_size = 0;
if ((result =
_gnutls_x509_crt_get_extension (cert, extension_id, 0, &dnsname,
critical)) < 0)
{
return result;
}
if (dnsname.size == 0 || dnsname.data == NULL)
{
gnutls_assert ();
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
if (strcmp ("2.5.29.17", extension_id) == 0)
result = asn1_create_element (_gnutls_get_pkix (),
"PKIX1.SubjectAltName", &c2);
else if (strcmp ("2.5.29.18", extension_id) == 0)
result = asn1_create_element (_gnutls_get_pkix (),
"PKIX1.IssuerAltName", &c2);
else
{
gnutls_assert ();
return GNUTLS_E_INTERNAL_ERROR;
}
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
_gnutls_free_datum (&dnsname);
return _gnutls_asn2err (result);
}
result = asn1_der_decoding (&c2, dnsname.data, dnsname.size, NULL);
_gnutls_free_datum (&dnsname);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
asn1_delete_structure (&c2);
return _gnutls_asn2err (result);
}
result =
_gnutls_parse_general_name (c2, "", seq, alt, alt_size, alt_type,
othername_oid);
asn1_delete_structure (&c2);
if (result < 0)
{
gnutls_assert ();
return result;
}
return result;
}
/**
* gnutls_x509_crt_get_subject_alt_name:
* @cert: should contain a #gnutls_x509_crt_t structure
* @seq: specifies the sequence number of the alt name (0 for the first one, 1 for the second etc.)
* @san: is the place where the alternative name will be copied to
* @san_size: holds the size of san.
* @critical: will be non (0) if the extension is marked as critical (may be null)
*
* This function retrieves the Alternative Name (2.5.29.17), contained
* in the given certificate in the X509v3 Certificate Extensions.
*
* When the SAN type is otherName, it will extract the data in the
* otherName's value field, and %GNUTLS_SAN_OTHERNAME is returned.
* You may use gnutls_x509_crt_get_subject_alt_othername_oid() to get
* the corresponding OID and the "virtual" SAN types (e.g.,
* %GNUTLS_SAN_OTHERNAME_XMPP).
*
* If an otherName OID is known, the data will be decoded. Otherwise
* the returned data will be DER encoded, and you will have to decode
* it yourself. Currently, only the RFC 3920 id-on-xmppAddr SAN is
* recognized.
*
* Returns: the alternative subject name type on success, one of the
* enumerated #gnutls_x509_subject_alt_name_t. It will return
* %GNUTLS_E_SHORT_MEMORY_BUFFER if @san_size is not large enough to
* hold the value. In that case @san_size will be updated with the
* required size. If the certificate does not have an Alternative
* name with the specified sequence number then
* %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
**/
int
gnutls_x509_crt_get_subject_alt_name (gnutls_x509_crt_t cert,
unsigned int seq, void *san,
size_t * san_size,
unsigned int *critical)
{
return get_alt_name (cert, "2.5.29.17", seq, san, san_size, NULL, critical,
0);
}
/**
* gnutls_x509_crt_get_issuer_alt_name:
* @cert: should contain a #gnutls_x509_crt_t structure
* @seq: specifies the sequence number of the alt name (0 for the first one, 1 for the second etc.)
* @ian: is the place where the alternative name will be copied to
* @ian_size: holds the size of ian.
* @critical: will be non (0) if the extension is marked as critical (may be null)
*
* This function retrieves the Issuer Alternative Name (2.5.29.18),
* contained in the given certificate in the X509v3 Certificate
* Extensions.
*
* When the SAN type is otherName, it will extract the data in the
* otherName's value field, and %GNUTLS_SAN_OTHERNAME is returned.
* You may use gnutls_x509_crt_get_subject_alt_othername_oid() to get
* the corresponding OID and the "virtual" SAN types (e.g.,
* %GNUTLS_SAN_OTHERNAME_XMPP).
*
* If an otherName OID is known, the data will be decoded. Otherwise
* the returned data will be DER encoded, and you will have to decode
* it yourself. Currently, only the RFC 3920 id-on-xmppAddr Issuer
* AltName is recognized.
*
* Returns: the alternative issuer name type on success, one of the
* enumerated #gnutls_x509_subject_alt_name_t. It will return
* %GNUTLS_E_SHORT_MEMORY_BUFFER if @ian_size is not large enough
* to hold the value. In that case @ian_size will be updated with
* the required size. If the certificate does not have an
* Alternative name with the specified sequence number then
* %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
*
* Since: 2.10.0
**/
int
gnutls_x509_crt_get_issuer_alt_name (gnutls_x509_crt_t cert,
unsigned int seq, void *ian,
size_t * ian_size,
unsigned int *critical)
{
return get_alt_name (cert, "2.5.29.18", seq, ian, ian_size, NULL, critical,
0);
}
/**
* gnutls_x509_crt_get_subject_alt_name2:
* @cert: should contain a #gnutls_x509_crt_t structure
* @seq: specifies the sequence number of the alt name (0 for the first one, 1 for the second etc.)
* @san: is the place where the alternative name will be copied to
* @san_size: holds the size of ret.
* @san_type: holds the type of the alternative name (one of gnutls_x509_subject_alt_name_t).
* @critical: will be non (0) if the extension is marked as critical (may be null)
*
* This function will return the alternative names, contained in the
* given certificate. It is the same as
* gnutls_x509_crt_get_subject_alt_name() except for the fact that it
* will return the type of the alternative name in @san_type even if
* the function fails for some reason (i.e. the buffer provided is
* not enough).
*
* Returns: the alternative subject name type on success, one of the
* enumerated #gnutls_x509_subject_alt_name_t. It will return
* %GNUTLS_E_SHORT_MEMORY_BUFFER if @san_size is not large enough
* to hold the value. In that case @san_size will be updated with
* the required size. If the certificate does not have an
* Alternative name with the specified sequence number then
* %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
**/
int
gnutls_x509_crt_get_subject_alt_name2 (gnutls_x509_crt_t cert,
unsigned int seq, void *san,
size_t * san_size,
unsigned int *san_type,
unsigned int *critical)
{
return get_alt_name (cert, "2.5.29.17", seq, san, san_size, san_type,
critical, 0);
}
/**
* gnutls_x509_crt_get_issuer_alt_name2:
* @cert: should contain a #gnutls_x509_crt_t structure
* @seq: specifies the sequence number of the alt name (0 for the first one, 1 for the second etc.)
* @ian: is the place where the alternative name will be copied to
* @ian_size: holds the size of ret.
* @ian_type: holds the type of the alternative name (one of gnutls_x509_subject_alt_name_t).
* @critical: will be non (0) if the extension is marked as critical (may be null)
*
* This function will return the alternative names, contained in the
* given certificate. It is the same as
* gnutls_x509_crt_get_issuer_alt_name() except for the fact that it
* will return the type of the alternative name in @ian_type even if
* the function fails for some reason (i.e. the buffer provided is
* not enough).
*
* Returns: the alternative issuer name type on success, one of the
* enumerated #gnutls_x509_subject_alt_name_t. It will return
* %GNUTLS_E_SHORT_MEMORY_BUFFER if @ian_size is not large enough
* to hold the value. In that case @ian_size will be updated with
* the required size. If the certificate does not have an
* Alternative name with the specified sequence number then
* %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
*
* Since: 2.10.0
*
**/
int
gnutls_x509_crt_get_issuer_alt_name2 (gnutls_x509_crt_t cert,
unsigned int seq, void *ian,
size_t * ian_size,
unsigned int *ian_type,
unsigned int *critical)
{
return get_alt_name (cert, "2.5.29.18", seq, ian, ian_size, ian_type,
critical, 0);
}
/**
* gnutls_x509_crt_get_subject_alt_othername_oid:
* @cert: should contain a #gnutls_x509_crt_t structure
* @seq: specifies the sequence number of the alt name (0 for the first one, 1 for the second etc.)
* @oid: is the place where the otherName OID will be copied to
* @oid_size: holds the size of ret.
*
* This function will extract the type OID of an otherName Subject
* Alternative Name, contained in the given certificate, and return
* the type as an enumerated element.
*
* This function is only useful if
* gnutls_x509_crt_get_subject_alt_name() returned
* %GNUTLS_SAN_OTHERNAME.
*
* If @oid is null then only the size will be filled. The @oid
* returned will be null terminated, although @oid_size will not
* account for the trailing null.
*
* Returns: the alternative subject name type on success, one of the
* enumerated gnutls_x509_subject_alt_name_t. For supported OIDs, it
* will return one of the virtual (GNUTLS_SAN_OTHERNAME_*) types,
* e.g. %GNUTLS_SAN_OTHERNAME_XMPP, and %GNUTLS_SAN_OTHERNAME for
* unknown OIDs. It will return %GNUTLS_E_SHORT_MEMORY_BUFFER if
* @ian_size is not large enough to hold the value. In that case
* @ian_size will be updated with the required size. If the
* certificate does not have an Alternative name with the specified
* sequence number and with the otherName type then
* %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
**/
int
gnutls_x509_crt_get_subject_alt_othername_oid (gnutls_x509_crt_t cert,
unsigned int seq,
void *oid, size_t * oid_size)
{
return get_alt_name (cert, "2.5.29.17", seq, oid, oid_size, NULL, NULL, 1);
}
/**
* gnutls_x509_crt_get_issuer_alt_othername_oid:
* @cert: should contain a #gnutls_x509_crt_t structure
* @seq: specifies the sequence number of the alt name (0 for the first one, 1 for the second etc.)
* @ret: is the place where the otherName OID will be copied to
* @ret_size: holds the size of ret.
*
* This function will extract the type OID of an otherName Subject
* Alternative Name, contained in the given certificate, and return
* the type as an enumerated element.
*
* If @oid is null then only the size will be filled. The @oid
* returned will be null terminated, although @oid_size will not
* account for the trailing null.
*
* This function is only useful if
* gnutls_x509_crt_get_issuer_alt_name() returned
* %GNUTLS_SAN_OTHERNAME.
*
* Returns: the alternative issuer name type on success, one of the
* enumerated gnutls_x509_subject_alt_name_t. For supported OIDs, it
* will return one of the virtual (GNUTLS_SAN_OTHERNAME_*) types,
* e.g. %GNUTLS_SAN_OTHERNAME_XMPP, and %GNUTLS_SAN_OTHERNAME for
* unknown OIDs. It will return %GNUTLS_E_SHORT_MEMORY_BUFFER if
* @ret_size is not large enough to hold the value. In that case
* @ret_size will be updated with the required size. If the
* certificate does not have an Alternative name with the specified
* sequence number and with the otherName type then
* %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
*
* Since: 2.10.0
**/
int
gnutls_x509_crt_get_issuer_alt_othername_oid (gnutls_x509_crt_t cert,
unsigned int seq,
void *ret, size_t * ret_size)
{
return get_alt_name (cert, "2.5.29.18", seq, ret, ret_size, NULL, NULL, 1);
}
/**
* gnutls_x509_crt_get_basic_constraints:
* @cert: should contain a #gnutls_x509_crt_t structure
* @critical: will be non (0) if the extension is marked as critical
* @ca: pointer to output integer indicating CA status, may be NULL,
* value is 1 if the certificate CA flag is set, 0 otherwise.
* @pathlen: pointer to output integer indicating path length (may be
* NULL), non-negative error codes indicate a present pathLenConstraint
* field and the actual value, -1 indicate that the field is absent.
*
* This function will read the certificate's basic constraints, and
* return the certificates CA status. It reads the basicConstraints
* X.509 extension (2.5.29.19).
*
* Returns: If the certificate is a CA a positive value will be
* returned, or (0) if the certificate does not have CA flag set. A
* negative error code may be returned in case of errors. If the
* certificate does not contain the basicConstraints extension
* GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned.
**/
int
gnutls_x509_crt_get_basic_constraints (gnutls_x509_crt_t cert,
unsigned int *critical,
unsigned int *ca, int *pathlen)
{
int result;
gnutls_datum_t basicConstraints;
unsigned int tmp_ca;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
if ((result =
_gnutls_x509_crt_get_extension (cert, "2.5.29.19", 0,
&basicConstraints, critical)) < 0)
{
return result;
}
if (basicConstraints.size == 0 || basicConstraints.data == NULL)
{
gnutls_assert ();
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
result =
_gnutls_x509_ext_extract_basicConstraints (&tmp_ca,
pathlen,
basicConstraints.data,
basicConstraints.size);
if (ca)
*ca = tmp_ca;
_gnutls_free_datum (&basicConstraints);
if (result < 0)
{
gnutls_assert ();
return result;
}
return tmp_ca;
}
/**
* gnutls_x509_crt_get_ca_status:
* @cert: should contain a #gnutls_x509_crt_t structure
* @critical: will be non (0) if the extension is marked as critical
*
* This function will return certificates CA status, by reading the
* basicConstraints X.509 extension (2.5.29.19). If the certificate is
* a CA a positive value will be returned, or (0) if the certificate
* does not have CA flag set.
*
* Use gnutls_x509_crt_get_basic_constraints() if you want to read the
* pathLenConstraint field too.
*
* Returns: A negative error code may be returned in case of parsing error.
* If the certificate does not contain the basicConstraints extension
* %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned.
**/
int
gnutls_x509_crt_get_ca_status (gnutls_x509_crt_t cert, unsigned int *critical)
{
int pathlen;
unsigned int ca;
return gnutls_x509_crt_get_basic_constraints (cert, critical, &ca,
&pathlen);
}
/**
* gnutls_x509_crt_get_key_usage:
* @cert: should contain a #gnutls_x509_crt_t structure
* @key_usage: where the key usage bits will be stored
* @critical: will be non (0) if the extension is marked as critical
*
* This function will return certificate's key usage, by reading the
* keyUsage X.509 extension (2.5.29.15). The key usage value will ORed
* values of the: %GNUTLS_KEY_DIGITAL_SIGNATURE,
* %GNUTLS_KEY_NON_REPUDIATION, %GNUTLS_KEY_KEY_ENCIPHERMENT,
* %GNUTLS_KEY_DATA_ENCIPHERMENT, %GNUTLS_KEY_KEY_AGREEMENT,
* %GNUTLS_KEY_KEY_CERT_SIGN, %GNUTLS_KEY_CRL_SIGN,
* %GNUTLS_KEY_ENCIPHER_ONLY, %GNUTLS_KEY_DECIPHER_ONLY.
*
* Returns: the certificate key usage, or a negative error code in case of
* parsing error. If the certificate does not contain the keyUsage
* extension %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be
* returned.
**/
int
gnutls_x509_crt_get_key_usage (gnutls_x509_crt_t cert,
unsigned int *key_usage,
unsigned int *critical)
{
int result;
gnutls_datum_t keyUsage;
uint16_t _usage;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
if ((result =
_gnutls_x509_crt_get_extension (cert, "2.5.29.15", 0, &keyUsage,
critical)) < 0)
{
return result;
}
if (keyUsage.size == 0 || keyUsage.data == NULL)
{
gnutls_assert ();
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
result = _gnutls_x509_ext_extract_keyUsage (&_usage, keyUsage.data,
keyUsage.size);
_gnutls_free_datum (&keyUsage);
*key_usage = _usage;
if (result < 0)
{
gnutls_assert ();
return result;
}
return 0;
}
/**
* gnutls_x509_crt_get_proxy:
* @cert: should contain a #gnutls_x509_crt_t structure
* @critical: will be non (0) if the extension is marked as critical
* @pathlen: pointer to output integer indicating path length (may be
* NULL), non-negative error codes indicate a present pCPathLenConstraint
* field and the actual value, -1 indicate that the field is absent.
* @policyLanguage: output variable with OID of policy language
* @policy: output variable with policy data
* @sizeof_policy: output variable size of policy data
*
* This function will get information from a proxy certificate. It
* reads the ProxyCertInfo X.509 extension (1.3.6.1.5.5.7.1.14).
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
* otherwise a negative error code is returned.
**/
int
gnutls_x509_crt_get_proxy (gnutls_x509_crt_t cert,
unsigned int *critical,
int *pathlen,
char **policyLanguage,
char **policy, size_t * sizeof_policy)
{
int result;
gnutls_datum_t proxyCertInfo;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
if ((result =
_gnutls_x509_crt_get_extension (cert, "1.3.6.1.5.5.7.1.14", 0,
&proxyCertInfo, critical)) < 0)
{
return result;
}
if (proxyCertInfo.size == 0 || proxyCertInfo.data == NULL)
{
gnutls_assert ();
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
result = _gnutls_x509_ext_extract_proxyCertInfo (pathlen,
policyLanguage,
policy,
sizeof_policy,
proxyCertInfo.data,
proxyCertInfo.size);
_gnutls_free_datum (&proxyCertInfo);
if (result < 0)
{
gnutls_assert ();
return result;
}
return 0;
}
/**
* gnutls_x509_crt_get_extension_by_oid:
* @cert: should contain a #gnutls_x509_crt_t structure
* @oid: holds an Object Identified in null terminated string
* @indx: In case multiple same OIDs exist in the extensions, this specifies which to send. Use (0) to get the first one.
* @buf: a pointer to a structure to hold the name (may be null)
* @buf_size: initially holds the size of @buf
* @critical: will be non (0) if the extension is marked as critical
*
* This function will return the extension specified by the OID in the
* certificate. The extensions will be returned as binary data DER
* encoded, in the provided buffer.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
* otherwise a negative error code is returned. If the certificate does not
* contain the specified extension
* GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned.
**/
int
gnutls_x509_crt_get_extension_by_oid (gnutls_x509_crt_t cert,
const char *oid, int indx,
void *buf, size_t * buf_size,
unsigned int *critical)
{
int result;
gnutls_datum_t output;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
if ((result =
_gnutls_x509_crt_get_extension (cert, oid, indx, &output,
critical)) < 0)
{
gnutls_assert ();
return result;
}
if (output.size == 0 || output.data == NULL)
{
gnutls_assert ();
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
if (output.size > (unsigned int) *buf_size)
{
*buf_size = output.size;
_gnutls_free_datum (&output);
return GNUTLS_E_SHORT_MEMORY_BUFFER;
}
*buf_size = output.size;
if (buf)
memcpy (buf, output.data, output.size);
_gnutls_free_datum (&output);
return 0;
}
/**
* gnutls_x509_crt_get_extension_oid:
* @cert: should contain a #gnutls_x509_crt_t structure
* @indx: Specifies which extension OID to send. Use (0) to get the first one.
* @oid: a pointer to a structure to hold the OID (may be null)
* @oid_size: initially holds the size of @oid
*
* This function will return the requested extension OID in the certificate.
* The extension OID will be stored as a string in the provided buffer.
*
* The @oid returned will be null terminated, although @oid_size will not
* account for the trailing null.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
* otherwise a negative error code is returned. If you have reached the
* last extension available %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
* will be returned.
**/
int
gnutls_x509_crt_get_extension_oid (gnutls_x509_crt_t cert, int indx,
void *oid, size_t * oid_size)
{
int result;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
result = _gnutls_x509_crt_get_extension_oid (cert, indx, oid, oid_size);
if (result < 0)
{
return result;
}
return 0;
}
/**
* gnutls_x509_crt_get_extension_info:
* @cert: should contain a #gnutls_x509_crt_t structure
* @indx: Specifies which extension OID to send. Use (0) to get the first one.
* @oid: a pointer to a structure to hold the OID
* @oid_size: initially holds the maximum size of @oid, on return
* holds actual size of @oid.
* @critical: output variable with critical flag, may be NULL.
*
* This function will return the requested extension OID in the
* certificate, and the critical flag for it. The extension OID will
* be stored as a string in the provided buffer. Use
* gnutls_x509_crt_get_extension_data() to extract the data.
*
* If the buffer provided is not long enough to hold the output, then
* @oid_size is updated and %GNUTLS_E_SHORT_MEMORY_BUFFER will be
* returned. The @oid returned will be null terminated, although
* @oid_size will not account for the trailing null.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
* otherwise a negative error code is returned. If you have reached the
* last extension available %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
* will be returned.
**/
int
gnutls_x509_crt_get_extension_info (gnutls_x509_crt_t cert, int indx,
void *oid, size_t * oid_size,
unsigned int *critical)
{
int result;
char str_critical[10];
char name[ASN1_MAX_NAME_SIZE];
int len;
if (!cert)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
snprintf (name, sizeof (name), "tbsCertificate.extensions.?%u.extnID",
indx + 1);
len = *oid_size;
result = asn1_read_value (cert->cert, name, oid, &len);
*oid_size = len;
if (result == ASN1_ELEMENT_NOT_FOUND)
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
else if (result != ASN1_SUCCESS)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
snprintf (name, sizeof (name), "tbsCertificate.extensions.?%u.critical",
indx + 1);
len = sizeof (str_critical);
result = asn1_read_value (cert->cert, name, str_critical, &len);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
if (critical)
{
if (str_critical[0] == 'T')
*critical = 1;
else
*critical = 0;
}
return 0;
}
/**
* gnutls_x509_crt_get_extension_data:
* @cert: should contain a #gnutls_x509_crt_t structure
* @indx: Specifies which extension OID to send. Use (0) to get the first one.
* @data: a pointer to a structure to hold the data (may be null)
* @sizeof_data: initially holds the size of @oid
*
* This function will return the requested extension data in the
* certificate. The extension data will be stored as a string in the
* provided buffer.
*
* Use gnutls_x509_crt_get_extension_info() to extract the OID and
* critical flag. Use gnutls_x509_crt_get_extension_by_oid() instead,
* if you want to get data indexed by the extension OID rather than
* sequence.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
* otherwise a negative error code is returned. If you have reached the
* last extension available %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
* will be returned.
**/
int
gnutls_x509_crt_get_extension_data (gnutls_x509_crt_t cert, int indx,
void *data, size_t * sizeof_data)
{
int result, len;
char name[ASN1_MAX_NAME_SIZE];
if (!cert)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
snprintf (name, sizeof (name), "tbsCertificate.extensions.?%u.extnValue",
indx + 1);
len = *sizeof_data;
result = asn1_read_value (cert->cert, name, data, &len);
*sizeof_data = len;
if (result == ASN1_ELEMENT_NOT_FOUND)
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
else if (result < 0)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
return 0;
}
static int
_gnutls_x509_crt_get_raw_dn2 (gnutls_x509_crt_t cert,
const char *whom, gnutls_datum_t * start)
{
ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
int result, len1;
int start1, end1;
gnutls_datum_t signed_data = { NULL, 0 };
/* get the issuer of 'cert'
*/
if ((result =
asn1_create_element (_gnutls_get_pkix (), "PKIX1.TBSCertificate",
&c2)) != ASN1_SUCCESS)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
result =
_gnutls_x509_get_signed_data (cert->cert, "tbsCertificate", &signed_data);
if (result < 0)
{
gnutls_assert ();
goto cleanup;
}
result = asn1_der_decoding (&c2, signed_data.data, signed_data.size, NULL);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
asn1_delete_structure (&c2);
result = _gnutls_asn2err (result);
goto cleanup;
}
result =
asn1_der_decoding_startEnd (c2, signed_data.data, signed_data.size,
whom, &start1, &end1);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
result = _gnutls_asn2err (result);
goto cleanup;
}
len1 = end1 - start1 + 1;
_gnutls_set_datum (start, &signed_data.data[start1], len1);
result = 0;
cleanup:
asn1_delete_structure (&c2);
_gnutls_free_datum (&signed_data);
return result;
}
/**
* gnutls_x509_crt_get_raw_issuer_dn:
* @cert: should contain a #gnutls_x509_crt_t structure
* @start: will hold the starting point of the DN
*
* This function will return a pointer to the DER encoded DN structure
* and the length.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value.or a negative error code on error.
*
**/
int
gnutls_x509_crt_get_raw_issuer_dn (gnutls_x509_crt_t cert,
gnutls_datum_t * start)
{
return _gnutls_x509_crt_get_raw_dn2 (cert, "issuer", start);
}
/**
* gnutls_x509_crt_get_raw_dn:
* @cert: should contain a #gnutls_x509_crt_t structure
* @start: will hold the starting point of the DN
*
* This function will return a pointer to the DER encoded DN structure and
* the length.
*
* Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
* negative error value. or a negative error code on error.
*
**/
int
gnutls_x509_crt_get_raw_dn (gnutls_x509_crt_t cert, gnutls_datum_t * start)
{
return _gnutls_x509_crt_get_raw_dn2 (cert, "subject", start);
}
static int
get_dn (gnutls_x509_crt_t cert, const char *whom, gnutls_x509_dn_t * dn)
{
*dn = asn1_find_node (cert->cert, whom);
if (!*dn)
return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND;
return 0;
}
/**
* gnutls_x509_crt_get_subject:
* @cert: should contain a #gnutls_x509_crt_t structure
* @dn: output variable with pointer to uint8_t DN.
*
* Return the Certificate's Subject DN as an uint8_t data type. You
* may use gnutls_x509_dn_get_rdn_ava() to decode the DN.
*
* Note that @dn should be treated as constant. Because points
* into the @cert object, you may not deallocate @cert
* and continue to access @dn.
*
* Returns: Returns 0 on success, or an error code.
**/
int
gnutls_x509_crt_get_subject (gnutls_x509_crt_t cert, gnutls_x509_dn_t * dn)
{
return get_dn (cert, "tbsCertificate.subject.rdnSequence", dn);
}
/**
* gnutls_x509_crt_get_issuer:
* @cert: should contain a #gnutls_x509_crt_t structure
* @dn: output variable with pointer to uint8_t DN
*
* Return the Certificate's Issuer DN as an uint8_t data type. You may
* use gnutls_x509_dn_get_rdn_ava() to decode the DN.
*
* Note that @dn should be treated as constant. Because points
* into the @cert object, you may not deallocate @cert
* and continue to access @dn.
*
* Returns: Returns 0 on success, or an error code.
**/
int
gnutls_x509_crt_get_issuer (gnutls_x509_crt_t cert, gnutls_x509_dn_t * dn)
{
return get_dn (cert, "tbsCertificate.issuer.rdnSequence", dn);
}
/**
* gnutls_x509_dn_get_rdn_ava:
* @dn: input variable with uint8_t DN pointer
* @irdn: index of RDN
* @iava: index of AVA.
* @ava: Pointer to structure which will hold output information.
*
* Get pointers to data within the DN.
*
* Note that @ava will contain pointers into the @dn structure, so you
* should not modify any data or deallocate it. Note also that the DN
* in turn points into the original certificate structure, and thus
* you may not deallocate the certificate and continue to access @dn.
*
* Returns: Returns 0 on success, or an error code.
**/
int
gnutls_x509_dn_get_rdn_ava (gnutls_x509_dn_t dn,
int irdn, int iava, gnutls_x509_ava_st * ava)
{
ASN1_TYPE rdn, elem;
long len;
int lenlen, remlen, ret;
char rbuf[ASN1_MAX_NAME_SIZE];
unsigned char cls, *ptr;
iava++;
irdn++; /* 0->1, 1->2 etc */
snprintf (rbuf, sizeof (rbuf), "rdnSequence.?%d.?%d", irdn, iava);
rdn = asn1_find_node (dn, rbuf);
if (!rdn)
{
gnutls_assert ();
return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND;
}
snprintf (rbuf, sizeof (rbuf), "?%d.type", iava);
elem = asn1_find_node (rdn, rbuf);
if (!elem)
{
gnutls_assert ();
return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND;
}
ava->oid.data = elem->value;
ava->oid.size = elem->value_len;
snprintf (rbuf, sizeof (rbuf), "?%d.value", iava);
elem = asn1_find_node (rdn, rbuf);
if (!elem)
{
gnutls_assert ();
return GNUTLS_E_ASN1_ELEMENT_NOT_FOUND;
}
/* The value still has the previous tag's length bytes, plus the
* current value's tag and length bytes. Decode them.
*/
ptr = elem->value;
remlen = elem->value_len;
len = asn1_get_length_der (ptr, remlen, &lenlen);
if (len < 0)
{
gnutls_assert ();
return GNUTLS_E_ASN1_DER_ERROR;
}
ptr += lenlen;
remlen -= lenlen;
ret = asn1_get_tag_der (ptr, remlen, &cls, &lenlen, &ava->value_tag);
if (ret)
{
gnutls_assert ();
return _gnutls_asn2err (ret);
}
ptr += lenlen;
remlen -= lenlen;
{
signed long tmp;
tmp = asn1_get_length_der (ptr, remlen, &lenlen);
if (tmp < 0)
{
gnutls_assert ();
return GNUTLS_E_ASN1_DER_ERROR;
}
ava->value.size = tmp;
}
ava->value.data = ptr + lenlen;
return 0;
}
/**
* gnutls_x509_crt_get_fingerprint:
* @cert: should contain a #gnutls_x509_crt_t structure
* @algo: is a digest algorithm
* @buf: a pointer to a structure to hold the fingerprint (may be null)
* @buf_size: initially holds the size of @buf
*
* This function will calculate and copy the certificate's fingerprint
* in the provided buffer.
*
* If the buffer is null then only the size will be filled.
*
* Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is
* not long enough, and in that case the *buf_size will be updated
* with the required size. On success 0 is returned.
**/
int
gnutls_x509_crt_get_fingerprint (gnutls_x509_crt_t cert,
gnutls_digest_algorithm_t algo,
void *buf, size_t * buf_size)
{
uint8_t *cert_buf;
int cert_buf_size;
int result;
gnutls_datum_t tmp;
if (buf_size == 0 || cert == NULL)
{
return GNUTLS_E_INVALID_REQUEST;
}
cert_buf_size = 0;
asn1_der_coding (cert->cert, "", NULL, &cert_buf_size, NULL);
cert_buf = gnutls_malloc (cert_buf_size);
if (cert_buf == NULL)
{
gnutls_assert ();
return GNUTLS_E_MEMORY_ERROR;
}
result = asn1_der_coding (cert->cert, "", cert_buf, &cert_buf_size, NULL);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
gnutls_free (cert_buf);
return _gnutls_asn2err (result);
}
tmp.data = cert_buf;
tmp.size = cert_buf_size;
result = gnutls_fingerprint (algo, &tmp, buf, buf_size);
gnutls_free (cert_buf);
return result;
}
/**
* gnutls_x509_crt_export:
* @cert: Holds the certificate
* @format: the format of output params. One of PEM or DER.
* @output_data: will contain a certificate PEM or DER encoded
* @output_data_size: holds the size of output_data (and will be
* replaced by the actual size of parameters)
*
* This function will export the certificate to DER or PEM format.
*
* If the buffer provided is not long enough to hold the output, then
* *output_data_size is updated and GNUTLS_E_SHORT_MEMORY_BUFFER will
* be returned.
*
* If the structure is PEM encoded, it will have a header
* of "BEGIN CERTIFICATE".
*
* Returns: In case of failure a negative error code will be
* returned, and 0 on success.
**/
int
gnutls_x509_crt_export (gnutls_x509_crt_t cert,
gnutls_x509_crt_fmt_t format, void *output_data,
size_t * output_data_size)
{
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
return _gnutls_x509_export_int (cert->cert, format, "CERTIFICATE",
output_data, output_data_size);
}
int
_gnutls_get_key_id (gnutls_pk_algorithm_t pk, gnutls_pk_params_st * params,
unsigned char *output_data,
size_t * output_data_size)
{
int ret = 0;
gnutls_datum_t der = { NULL, 0 };
const gnutls_digest_algorithm_t hash = GNUTLS_DIG_SHA1;
unsigned int digest_len = _gnutls_hash_get_algo_len(hash);
if (output_data == NULL || *output_data_size < digest_len)
{
gnutls_assert ();
*output_data_size = digest_len;
return GNUTLS_E_SHORT_MEMORY_BUFFER;
}
ret = _gnutls_x509_encode_PKI_params(&der, pk, params);
if (ret < 0)
return gnutls_assert_val(ret);
ret = _gnutls_hash_fast(hash, der.data, der.size, output_data);
if (ret < 0)
{
gnutls_assert ();
goto cleanup;
}
*output_data_size = digest_len;
ret = 0;
cleanup:
_gnutls_free_datum (&der);
return ret;
}
/**
* gnutls_x509_crt_get_key_id:
* @crt: Holds the certificate
* @flags: should be 0 for now
* @output_data: will contain the key ID
* @output_data_size: holds the size of output_data (and will be
* replaced by the actual size of parameters)
*
* This function will return a unique ID the depends on the public
* key parameters. This ID can be used in checking whether a
* certificate corresponds to the given private key.
*
* If the buffer provided is not long enough to hold the output, then
* *output_data_size is updated and GNUTLS_E_SHORT_MEMORY_BUFFER will
* be returned. The output will normally be a SHA-1 hash output,
* which is 20 bytes.
*
* Returns: In case of failure a negative error code will be
* returned, and 0 on success.
**/
int
gnutls_x509_crt_get_key_id (gnutls_x509_crt_t crt, unsigned int flags,
unsigned char *output_data,
size_t * output_data_size)
{
int pk, ret = 0;
gnutls_pk_params_st params;
if (crt == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
pk = gnutls_x509_crt_get_pk_algorithm (crt, NULL);
if (pk < 0)
{
gnutls_assert ();
return pk;
}
ret = _gnutls_x509_crt_get_mpis (crt, ¶ms);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret = _gnutls_get_key_id(pk, ¶ms, output_data, output_data_size);
gnutls_pk_params_release(¶ms);
return ret;
}
#ifdef ENABLE_PKI
/* This is exactly as gnutls_x509_crt_check_revocation() except that
* it calls func.
*/
int
_gnutls_x509_crt_check_revocation (gnutls_x509_crt_t cert,
const gnutls_x509_crl_t * crl_list,
int crl_list_length,
gnutls_verify_output_function func)
{
uint8_t serial[128];
uint8_t cert_serial[128];
size_t serial_size, cert_serial_size;
int ncerts, ret, i, j;
gnutls_datum_t dn1, dn2;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
for (j = 0; j < crl_list_length; j++)
{ /* do for all the crls */
/* Step 1. check if issuer's DN match
*/
ret = gnutls_x509_crl_get_raw_issuer_dn (crl_list[j], &dn1);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret = gnutls_x509_crt_get_raw_issuer_dn (cert, &dn2);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret = _gnutls_x509_compare_raw_dn (&dn1, &dn2);
_gnutls_free_datum (&dn1);
_gnutls_free_datum (&dn2);
if (ret == 0)
{
/* issuers do not match so don't even
* bother checking.
*/
continue;
}
/* Step 2. Read the certificate's serial number
*/
cert_serial_size = sizeof (cert_serial);
ret = gnutls_x509_crt_get_serial (cert, cert_serial, &cert_serial_size);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
/* Step 3. cycle through the CRL serials and compare with
* certificate serial we have.
*/
ncerts = gnutls_x509_crl_get_crt_count (crl_list[j]);
if (ncerts < 0)
{
gnutls_assert ();
return ncerts;
}
for (i = 0; i < ncerts; i++)
{
serial_size = sizeof (serial);
ret =
gnutls_x509_crl_get_crt_serial (crl_list[j], i, serial,
&serial_size, NULL);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
if (serial_size == cert_serial_size)
{
if (memcmp (serial, cert_serial, serial_size) == 0)
{
/* serials match */
if (func) func(cert, NULL, crl_list[j], GNUTLS_CERT_REVOKED|GNUTLS_CERT_INVALID);
return 1; /* revoked! */
}
}
}
if (func) func(cert, NULL, crl_list[j], 0);
}
return 0; /* not revoked. */
}
/**
* gnutls_x509_crt_check_revocation:
* @cert: should contain a #gnutls_x509_crt_t structure
* @crl_list: should contain a list of gnutls_x509_crl_t structures
* @crl_list_length: the length of the crl_list
*
* This function will return check if the given certificate is
* revoked. It is assumed that the CRLs have been verified before.
*
* Returns: 0 if the certificate is NOT revoked, and 1 if it is. A
* negative error code is returned on error.
**/
int
gnutls_x509_crt_check_revocation (gnutls_x509_crt_t cert,
const gnutls_x509_crl_t * crl_list,
int crl_list_length)
{
return _gnutls_x509_crt_check_revocation(cert, crl_list, crl_list_length, NULL);
}
/**
* gnutls_x509_crt_get_verify_algorithm:
* @crt: Holds the certificate
* @signature: contains the signature
* @hash: The result of the call with the hash algorithm used for signature
*
* This function will read the certifcate and the signed data to
* determine the hash algorithm used to generate the signature.
*
* Deprecated: Use gnutls_pubkey_get_verify_algorithm() instead.
*
* Returns: the 0 if the hash algorithm is found. A negative error code is
* returned on error.
*
* Since: 2.8.0
**/
int
gnutls_x509_crt_get_verify_algorithm (gnutls_x509_crt_t crt,
const gnutls_datum_t * signature,
gnutls_digest_algorithm_t * hash)
{
gnutls_pk_params_st issuer_params;
int ret;
if (crt == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
ret = _gnutls_x509_crt_get_mpis (crt, &issuer_params);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret = _gnutls_x509_verify_algorithm ((gnutls_mac_algorithm_t *) hash,
signature,
gnutls_x509_crt_get_pk_algorithm (crt,
NULL),
&issuer_params);
/* release allocated mpis */
gnutls_pk_params_release(&issuer_params);
return ret;
}
/**
* gnutls_x509_crt_get_preferred_hash_algorithm:
* @crt: Holds the certificate
* @hash: The result of the call with the hash algorithm used for signature
* @mand: If non (0) it means that the algorithm MUST use this hash. May be NULL.
*
* This function will read the certifcate and return the appropriate digest
* algorithm to use for signing with this certificate. Some certificates (i.e.
* DSA might not be able to sign without the preferred algorithm).
*
* Deprecated: Please use gnutls_pubkey_get_preferred_hash_algorithm().
*
* Returns: the 0 if the hash algorithm is found. A negative error code is
* returned on error.
*
* Since: 2.12.0
**/
int
gnutls_x509_crt_get_preferred_hash_algorithm (gnutls_x509_crt_t crt,
gnutls_digest_algorithm_t *
hash, unsigned int *mand)
{
gnutls_pk_params_st issuer_params;
int ret;
if (crt == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
ret = _gnutls_x509_crt_get_mpis (crt, &issuer_params);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret =
_gnutls_pk_get_hash_algorithm (gnutls_x509_crt_get_pk_algorithm
(crt, NULL), &issuer_params,
hash, mand);
/* release allocated mpis */
gnutls_pk_params_release(&issuer_params);
return ret;
}
/**
* gnutls_x509_crt_verify_data:
* @crt: Holds the certificate
* @flags: should be 0 for now
* @data: holds the data to be signed
* @signature: contains the signature
*
* This function will verify the given signed data, using the
* parameters from the certificate.
*
* Deprecated. Please use gnutls_pubkey_verify_data().
*
* Returns: In case of a verification failure %GNUTLS_E_PK_SIG_VERIFY_FAILED
* is returned, and a positive code on success.
**/
int
gnutls_x509_crt_verify_data (gnutls_x509_crt_t crt, unsigned int flags,
const gnutls_datum_t * data,
const gnutls_datum_t * signature)
{
int result;
if (crt == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
result = _gnutls_x509_verify_data (GNUTLS_DIG_UNKNOWN, data, signature, crt);
if (result < 0)
{
gnutls_assert ();
return result;
}
return result;
}
/**
* gnutls_x509_crt_verify_hash:
* @crt: Holds the certificate
* @flags: should be 0 for now
* @hash: holds the hash digest to be verified
* @signature: contains the signature
*
* This function will verify the given signed digest, using the
* parameters from the certificate.
*
* Deprecated. Please use gnutls_pubkey_verify_data().
*
* Returns: In case of a verification failure %GNUTLS_E_PK_SIG_VERIFY_FAILED
* is returned, and a positive code on success.
**/
int
gnutls_x509_crt_verify_hash (gnutls_x509_crt_t crt, unsigned int flags,
const gnutls_datum_t * hash,
const gnutls_datum_t * signature)
{
int result;
if (crt == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
result = _gnutls_x509_verify_hashed_data (hash, signature, crt);
if (result < 0)
{
gnutls_assert ();
return result;
}
return result;
}
/**
* gnutls_x509_crt_get_crl_dist_points:
* @cert: should contain a #gnutls_x509_crt_t structure
* @seq: specifies the sequence number of the distribution point (0 for the first one, 1 for the second etc.)
* @ret: is the place where the distribution point will be copied to
* @ret_size: holds the size of ret.
* @reason_flags: Revocation reasons flags.
* @critical: will be non (0) if the extension is marked as critical (may be null)
*
* This function retrieves the CRL distribution points (2.5.29.31),
* contained in the given certificate in the X509v3 Certificate
* Extensions.
*
* @reason_flags should be an ORed sequence of
* %GNUTLS_CRL_REASON_UNUSED, %GNUTLS_CRL_REASON_KEY_COMPROMISE,
* %GNUTLS_CRL_REASON_CA_COMPROMISE,
* %GNUTLS_CRL_REASON_AFFILIATION_CHANGED,
* %GNUTLS_CRL_REASON_SUPERSEEDED,
* %GNUTLS_CRL_REASON_CESSATION_OF_OPERATION,
* %GNUTLS_CRL_REASON_CERTIFICATE_HOLD,
* %GNUTLS_CRL_REASON_PRIVILEGE_WITHDRAWN,
* %GNUTLS_CRL_REASON_AA_COMPROMISE, or (0) for all possible reasons.
*
* Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER and updates @ret_size if
* @ret_size is not enough to hold the distribution point, or the
* type of the distribution point if everything was ok. The type is
* one of the enumerated %gnutls_x509_subject_alt_name_t. If the
* certificate does not have an Alternative name with the specified
* sequence number then %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is
* returned.
**/
int
gnutls_x509_crt_get_crl_dist_points (gnutls_x509_crt_t cert,
unsigned int seq, void *ret,
size_t * ret_size,
unsigned int *reason_flags,
unsigned int *critical)
{
int result;
gnutls_datum_t dist_points = { NULL, 0 };
ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
char name[ASN1_MAX_NAME_SIZE];
int len;
gnutls_x509_subject_alt_name_t type;
uint8_t reasons[2];
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
if (*ret_size > 0 && ret)
memset (ret, 0, *ret_size);
else
*ret_size = 0;
if (reason_flags)
*reason_flags = 0;
result =
_gnutls_x509_crt_get_extension (cert, "2.5.29.31", 0, &dist_points,
critical);
if (result < 0)
{
return result;
}
if (dist_points.size == 0 || dist_points.data == NULL)
{
gnutls_assert ();
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
result = asn1_create_element
(_gnutls_get_pkix (), "PKIX1.CRLDistributionPoints", &c2);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
_gnutls_free_datum (&dist_points);
return _gnutls_asn2err (result);
}
result = asn1_der_decoding (&c2, dist_points.data, dist_points.size, NULL);
_gnutls_free_datum (&dist_points);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
asn1_delete_structure (&c2);
return _gnutls_asn2err (result);
}
/* Return the different names from the first CRLDistr. point.
* The whole thing is a mess.
*/
_gnutls_str_cpy (name, sizeof (name), "?1.distributionPoint.fullName");
result = _gnutls_parse_general_name (c2, name, seq, ret, ret_size, NULL, 0);
if (result < 0)
{
asn1_delete_structure (&c2);
return result;
}
type = result;
/* Read the CRL reasons.
*/
if (reason_flags)
{
_gnutls_str_cpy (name, sizeof (name), "?1.reasons");
reasons[0] = reasons[1] = 0;
len = sizeof (reasons);
result = asn1_read_value (c2, name, reasons, &len);
if (result != ASN1_VALUE_NOT_FOUND && result != ASN1_SUCCESS)
{
gnutls_assert ();
asn1_delete_structure (&c2);
return _gnutls_asn2err (result);
}
*reason_flags = reasons[0] | (reasons[1] << 8);
}
asn1_delete_structure (&c2);
return type;
}
/**
* gnutls_x509_crt_get_key_purpose_oid:
* @cert: should contain a #gnutls_x509_crt_t structure
* @indx: This specifies which OID to return. Use (0) to get the first one.
* @oid: a pointer to a buffer to hold the OID (may be null)
* @oid_size: initially holds the size of @oid
* @critical: output flag to indicate criticality of extension
*
* This function will extract the key purpose OIDs of the Certificate
* specified by the given index. These are stored in the Extended Key
* Usage extension (2.5.29.37) See the GNUTLS_KP_* definitions for
* human readable names.
*
* If @oid is null then only the size will be filled. The @oid
* returned will be null terminated, although @oid_size will not
* account for the trailing null.
*
* Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the provided buffer is
* not long enough, and in that case the *oid_size will be updated
* with the required size. On success 0 is returned.
**/
int
gnutls_x509_crt_get_key_purpose_oid (gnutls_x509_crt_t cert,
int indx, void *oid, size_t * oid_size,
unsigned int *critical)
{
char tmpstr[ASN1_MAX_NAME_SIZE];
int result, len;
gnutls_datum_t id;
ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
if (cert == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
if (oid)
memset (oid, 0, *oid_size);
else
*oid_size = 0;
if ((result =
_gnutls_x509_crt_get_extension (cert, "2.5.29.37", 0, &id,
critical)) < 0)
{
return result;
}
if (id.size == 0 || id.data == NULL)
{
gnutls_assert ();
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
result = asn1_create_element
(_gnutls_get_pkix (), "PKIX1.ExtKeyUsageSyntax", &c2);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
_gnutls_free_datum (&id);
return _gnutls_asn2err (result);
}
result = asn1_der_decoding (&c2, id.data, id.size, NULL);
_gnutls_free_datum (&id);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
asn1_delete_structure (&c2);
return _gnutls_asn2err (result);
}
indx++;
/* create a string like "?1"
*/
snprintf (tmpstr, sizeof (tmpstr), "?%u", indx);
len = *oid_size;
result = asn1_read_value (c2, tmpstr, oid, &len);
*oid_size = len;
asn1_delete_structure (&c2);
if (result == ASN1_VALUE_NOT_FOUND || result == ASN1_ELEMENT_NOT_FOUND)
{
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
return 0;
}
/**
* gnutls_x509_crt_get_pk_rsa_raw:
* @crt: Holds the certificate
* @m: will hold the modulus
* @e: will hold the public exponent
*
* This function will export the RSA public key's parameters found in
* the given structure. The new parameters will be allocated using
* gnutls_malloc() and will be stored in the appropriate datum.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
**/
int
gnutls_x509_crt_get_pk_rsa_raw (gnutls_x509_crt_t crt,
gnutls_datum_t * m, gnutls_datum_t * e)
{
int ret;
gnutls_pk_params_st params;
if (crt == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
ret = gnutls_x509_crt_get_pk_algorithm (crt, NULL);
if (ret != GNUTLS_PK_RSA)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
ret = _gnutls_x509_crt_get_mpis (crt, ¶ms);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
ret = _gnutls_mpi_dprint_lz (params.params[0], m);
if (ret < 0)
{
gnutls_assert ();
goto cleanup;
}
ret = _gnutls_mpi_dprint_lz (params.params[1], e);
if (ret < 0)
{
gnutls_assert ();
_gnutls_free_datum (m);
goto cleanup;
}
ret = 0;
cleanup:
gnutls_pk_params_release(¶ms);
return ret;
}
/**
* gnutls_x509_crt_get_pk_dsa_raw:
* @crt: Holds the certificate
* @p: will hold the p
* @q: will hold the q
* @g: will hold the g
* @y: will hold the y
*
* This function will export the DSA public key's parameters found in
* the given certificate. The new parameters will be allocated using
* gnutls_malloc() and will be stored in the appropriate datum.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
**/
int
gnutls_x509_crt_get_pk_dsa_raw (gnutls_x509_crt_t crt,
gnutls_datum_t * p, gnutls_datum_t * q,
gnutls_datum_t * g, gnutls_datum_t * y)
{
int ret;
gnutls_pk_params_st params;
if (crt == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
ret = gnutls_x509_crt_get_pk_algorithm (crt, NULL);
if (ret != GNUTLS_PK_DSA)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
ret = _gnutls_x509_crt_get_mpis (crt, ¶ms);
if (ret < 0)
{
gnutls_assert ();
return ret;
}
/* P */
ret = _gnutls_mpi_dprint_lz (params.params[0], p);
if (ret < 0)
{
gnutls_assert ();
goto cleanup;
}
/* Q */
ret = _gnutls_mpi_dprint_lz (params.params[1], q);
if (ret < 0)
{
gnutls_assert ();
_gnutls_free_datum (p);
goto cleanup;
}
/* G */
ret = _gnutls_mpi_dprint_lz (params.params[2], g);
if (ret < 0)
{
gnutls_assert ();
_gnutls_free_datum (p);
_gnutls_free_datum (q);
goto cleanup;
}
/* Y */
ret = _gnutls_mpi_dprint_lz (params.params[3], y);
if (ret < 0)
{
gnutls_assert ();
_gnutls_free_datum (p);
_gnutls_free_datum (g);
_gnutls_free_datum (q);
goto cleanup;
}
ret = 0;
cleanup:
gnutls_pk_params_release(¶ms);
return ret;
}
#endif
/**
* gnutls_x509_crt_list_import2:
* @certs: The structures to store the parsed certificate. Must not be initialized.
* @size: It will contain the size of the list.
* @data: The PEM encoded certificate.
* @format: One of DER or PEM.
* @flags: must be (0) or an OR'd sequence of gnutls_certificate_import_flags.
*
* This function will convert the given PEM encoded certificate list
* to the native gnutls_x509_crt_t format. The output will be stored
* in @certs. They will be automatically initialized.
*
* If the Certificate is PEM encoded it should have a header of "X509
* CERTIFICATE", or "CERTIFICATE".
*
* Returns: the number of certificates read or a negative error value.
*
* Since: 3.0.0
**/
int
gnutls_x509_crt_list_import2 (gnutls_x509_crt_t ** certs,
unsigned int * size,
const gnutls_datum_t * data,
gnutls_x509_crt_fmt_t format, unsigned int flags)
{
unsigned int init = 1024;
int ret;
*certs = gnutls_malloc(sizeof(gnutls_x509_crt_t)*init);
if (*certs == NULL)
{
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
ret = gnutls_x509_crt_list_import(*certs, &init, data, format, GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED);
if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
{
*certs = gnutls_realloc_fast(*certs, sizeof(gnutls_x509_crt_t)*init);
if (*certs == NULL)
{
gnutls_assert();
return GNUTLS_E_MEMORY_ERROR;
}
ret = gnutls_x509_crt_list_import(*certs, &init, data, format, flags);
}
if (ret < 0)
{
gnutls_free(*certs);
*certs = NULL;
return ret;
}
*size = init;
return 0;
}
static int check_if_sorted(gnutls_x509_crt_t * crt, int nr)
{
char prev_dn[MAX_DN];
char dn[MAX_DN];
size_t prev_dn_size, dn_size;
int i, ret;
/* check if the X.509 list is ordered */
if (nr > 1)
{
for (i=0;i0)
{
dn_size = sizeof(dn);
ret = gnutls_x509_crt_get_dn(crt[i], dn, &dn_size);
if (ret < 0)
{
ret = gnutls_assert_val(ret);
goto cleanup;
}
if (dn_size != prev_dn_size || memcmp(dn, prev_dn, dn_size) != 0)
{
ret = gnutls_assert_val(GNUTLS_E_CERTIFICATE_LIST_UNSORTED);
goto cleanup;
}
}
prev_dn_size = sizeof(prev_dn);
ret = gnutls_x509_crt_get_issuer_dn(crt[i], prev_dn, &prev_dn_size);
if (ret < 0)
{
ret = gnutls_assert_val(ret);
goto cleanup;
}
}
}
ret = 0;
cleanup:
return ret;
}
/**
* gnutls_x509_crt_list_import:
* @certs: The structures to store the parsed certificate. Must not be initialized.
* @cert_max: Initially must hold the maximum number of certs. It will be updated with the number of certs available.
* @data: The PEM encoded certificate.
* @format: One of DER or PEM.
* @flags: must be (0) or an OR'd sequence of gnutls_certificate_import_flags.
*
* This function will convert the given PEM encoded certificate list
* to the native gnutls_x509_crt_t format. The output will be stored
* in @certs. They will be automatically initialized.
*
* The flag %GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED will cause
* import to fail if the certificates in the provided buffer are more
* than the available structures. The %GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED
* flag will cause the function to fail if the provided list is not
* sorted from subject to issuer.
*
* If the Certificate is PEM encoded it should have a header of "X509
* CERTIFICATE", or "CERTIFICATE".
*
* Returns: the number of certificates read or a negative error value.
**/
int
gnutls_x509_crt_list_import (gnutls_x509_crt_t * certs,
unsigned int *cert_max,
const gnutls_datum_t * data,
gnutls_x509_crt_fmt_t format, unsigned int flags)
{
int size;
const char *ptr;
gnutls_datum_t tmp;
int ret, nocopy = 0;
unsigned int count = 0, j;
if (format == GNUTLS_X509_FMT_DER)
{
if (*cert_max < 1)
{
*cert_max = 1;
return GNUTLS_E_SHORT_MEMORY_BUFFER;
}
count = 1; /* import only the first one */
ret = gnutls_x509_crt_init (&certs[0]);
if (ret < 0)
{
gnutls_assert ();
goto error;
}
ret = gnutls_x509_crt_import (certs[0], data, format);
if (ret < 0)
{
gnutls_assert ();
goto error;
}
*cert_max = 1;
return 1;
}
/* move to the certificate
*/
ptr = memmem (data->data, data->size,
PEM_CERT_SEP, sizeof (PEM_CERT_SEP) - 1);
if (ptr == NULL)
ptr = memmem (data->data, data->size,
PEM_CERT_SEP2, sizeof (PEM_CERT_SEP2) - 1);
if (ptr == NULL)
return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND);
count = 0;
do
{
if (count >= *cert_max)
{
if (!(flags & GNUTLS_X509_CRT_LIST_IMPORT_FAIL_IF_EXCEED))
break;
else
nocopy = 1;
}
if (!nocopy)
{
ret = gnutls_x509_crt_init (&certs[count]);
if (ret < 0)
{
gnutls_assert ();
goto error;
}
tmp.data = (void *) ptr;
tmp.size = data->size - (ptr - (char *) data->data);
ret =
gnutls_x509_crt_import (certs[count], &tmp, GNUTLS_X509_FMT_PEM);
if (ret < 0)
{
gnutls_assert ();
goto error;
}
}
/* now we move ptr after the pem header
*/
ptr++;
/* find the next certificate (if any)
*/
size = data->size - (ptr - (char *) data->data);
if (size > 0)
{
char *ptr2;
ptr2 = memmem (ptr, size, PEM_CERT_SEP, sizeof (PEM_CERT_SEP) - 1);
if (ptr2 == NULL)
ptr2 = memmem (ptr, size, PEM_CERT_SEP2,
sizeof (PEM_CERT_SEP2) - 1);
ptr = ptr2;
}
else
ptr = NULL;
count++;
}
while (ptr != NULL);
*cert_max = count;
if (flags & GNUTLS_X509_CRT_LIST_FAIL_IF_UNSORTED)
{
ret = check_if_sorted(certs, *cert_max);
if (ret < 0)
{
gnutls_assert();
goto error;
}
}
if (nocopy == 0)
return count;
else
return GNUTLS_E_SHORT_MEMORY_BUFFER;
error:
for (j = 0; j < count; j++)
gnutls_x509_crt_deinit (certs[j]);
return ret;
}
/**
* gnutls_x509_crt_get_subject_unique_id:
* @crt: Holds the certificate
* @buf: user allocated memory buffer, will hold the unique id
* @buf_size: size of user allocated memory buffer (on input), will hold
* actual size of the unique ID on return.
*
* This function will extract the subjectUniqueID value (if present) for
* the given certificate.
*
* If the user allocated memory buffer is not large enough to hold the
* full subjectUniqueID, then a GNUTLS_E_SHORT_MEMORY_BUFFER error will be
* returned, and buf_size will be set to the actual length.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
**/
int
gnutls_x509_crt_get_subject_unique_id (gnutls_x509_crt_t crt, char *buf,
size_t * buf_size)
{
int result;
gnutls_datum_t datum = { NULL, 0 };
result =
_gnutls_x509_read_value (crt->cert, "tbsCertificate.subjectUniqueID",
&datum, 2);
if (datum.size > *buf_size)
{ /* then we're not going to fit */
*buf_size = datum.size;
buf[0] = '\0';
result = GNUTLS_E_SHORT_MEMORY_BUFFER;
}
else
{
*buf_size = datum.size;
memcpy (buf, datum.data, datum.size);
}
_gnutls_free_datum (&datum);
return result;
}
/**
* gnutls_x509_crt_get_issuer_unique_id:
* @crt: Holds the certificate
* @buf: user allocated memory buffer, will hold the unique id
* @buf_size: size of user allocated memory buffer (on input), will hold
* actual size of the unique ID on return.
*
* This function will extract the issuerUniqueID value (if present) for
* the given certificate.
*
* If the user allocated memory buffer is not large enough to hold the
* full subjectUniqueID, then a GNUTLS_E_SHORT_MEMORY_BUFFER error will be
* returned, and buf_size will be set to the actual length.
*
* Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
*
* Since: 2.12.0
**/
int
gnutls_x509_crt_get_issuer_unique_id (gnutls_x509_crt_t crt, char *buf,
size_t * buf_size)
{
int result;
gnutls_datum_t datum = { NULL, 0 };
result =
_gnutls_x509_read_value (crt->cert, "tbsCertificate.issuerUniqueID",
&datum, 2);
if (datum.size > *buf_size)
{ /* then we're not going to fit */
*buf_size = datum.size;
buf[0] = '\0';
result = GNUTLS_E_SHORT_MEMORY_BUFFER;
}
else
{
*buf_size = datum.size;
memcpy (buf, datum.data, datum.size);
}
_gnutls_free_datum (&datum);
return result;
}
static int
_gnutls_parse_aia (ASN1_TYPE src,
unsigned int seq,
int what,
gnutls_datum_t * data)
{
int len;
char nptr[ASN1_MAX_NAME_SIZE];
int result;
gnutls_datum_t d;
const char *oid = NULL;
seq++; /* 0->1, 1->2 etc */
switch (what)
{
case GNUTLS_IA_ACCESSMETHOD_OID:
snprintf (nptr, sizeof (nptr), "?%u.accessMethod", seq);
break;
case GNUTLS_IA_ACCESSLOCATION_GENERALNAME_TYPE:
snprintf (nptr, sizeof (nptr), "?%u.accessLocation", seq);
break;
case GNUTLS_IA_CAISSUERS_URI:
oid = GNUTLS_OID_AD_CAISSUERS;
/* fall through */
case GNUTLS_IA_OCSP_URI:
if (oid == NULL)
oid = GNUTLS_OID_AD_OCSP;
{
char tmpoid[20];
snprintf (nptr, sizeof (nptr), "?%u.accessMethod", seq);
len = sizeof (tmpoid);
result = asn1_read_value (src, nptr, tmpoid, &len);
if (result == ASN1_VALUE_NOT_FOUND || result == ASN1_ELEMENT_NOT_FOUND)
return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
if ((unsigned)len != strlen (oid) + 1 || memcmp (tmpoid, oid, len) != 0)
return gnutls_assert_val(GNUTLS_E_UNKNOWN_ALGORITHM);
}
/* fall through */
case GNUTLS_IA_URI:
snprintf (nptr, sizeof (nptr),
"?%u.accessLocation.uniformResourceIdentifier", seq);
break;
default:
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
}
len = 0;
result = asn1_read_value (src, nptr, NULL, &len);
if (result == ASN1_VALUE_NOT_FOUND || result == ASN1_ELEMENT_NOT_FOUND)
return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
if (result != ASN1_MEM_ERROR)
{
gnutls_assert ();
return _gnutls_asn2err (result);
}
d.size = len;
d.data = gnutls_malloc (d.size);
if (d.data == NULL)
return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
result = asn1_read_value (src, nptr, d.data, &len);
if (result != ASN1_SUCCESS)
{
gnutls_assert ();
gnutls_free (d.data);
return _gnutls_asn2err (result);
}
if (data)
{
data->data = d.data;
data->size = d.size;
}
else
gnutls_free (d.data);
return 0;
}
/**
* gnutls_x509_crt_get_authority_info_access:
* @crt: Holds the certificate
* @seq: specifies the sequence number of the access descriptor (0 for the first one, 1 for the second etc.)
* @what: what data to get, a #gnutls_info_access_what_t type.
* @data: output data to be freed with gnutls_free().
* @critical: pointer to output integer that is set to non-0 if the extension is marked as critical (may be %NULL)
*
* This function extracts the Authority Information Access (AIA)
* extension, see RFC 5280 section 4.2.2.1 for more information. The
* AIA extension holds a sequence of AccessDescription (AD) data:
*
*
* AuthorityInfoAccessSyntax ::=
* SEQUENCE SIZE (1..MAX) OF AccessDescription
*
* AccessDescription ::= SEQUENCE {
* accessMethod OBJECT IDENTIFIER,
* accessLocation GeneralName }
*
*
* The @seq input parameter is used to indicate which member of the
* sequence the caller is interested in. The first member is 0, the
* second member 1 and so on. When the @seq value is out of bounds,
* %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned.
*
* The type of data returned in @data is specified via @what which
* should be #gnutls_info_access_what_t values.
*
* If @what is %GNUTLS_IA_ACCESSMETHOD_OID then @data will hold the
* accessMethod OID (e.g., "1.3.6.1.5.5.7.48.1").
*
* If @what is %GNUTLS_IA_ACCESSLOCATION_GENERALNAME_TYPE, @data will
* hold the accessLocation GeneralName type (e.g.,
* "uniformResourceIdentifier").
*
* If @what is %GNUTLS_IA_URI, @data will hold the accessLocation URI
* data. Requesting this @what value leads to an error if the
* accessLocation is not of the "uniformResourceIdentifier" type.
*
* If @what is %GNUTLS_IA_OCSP_URI, @data will hold the OCSP URI.
* Requesting this @what value leads to an error if the accessMethod
* is not 1.3.6.1.5.5.7.48.1 aka OSCP, or if accessLocation is not of
* the "uniformResourceIdentifier" type.
*
* If @what is %GNUTLS_IA_CAISSUERS_URI, @data will hold the caIssuers
* URI. Requesting this @what value leads to an error if the
* accessMethod is not 1.3.6.1.5.5.7.48.2 aka caIssuers, or if
* accessLocation is not of the "uniformResourceIdentifier" type.
*
* More @what values may be allocated in the future as needed.
*
* If @data is NULL, the function does the same without storing the
* output data, that is, it will set @critical and do error checking
* as usual.
*
* The value of the critical flag is returned in *@critical. Supply a
* NULL @critical if you want the function to make sure the extension
* is non-critical, as required by RFC 5280.
*
* Returns: %GNUTLS_E_SUCCESS on success, %GNUTLS_E_INVALID_REQUEST on
* invalid @crt, %GNUTLS_E_CONSTRAINT_ERROR if the extension is
* incorrectly marked as critical (use a non-NULL @critical to
* override), %GNUTLS_E_UNKNOWN_ALGORITHM if the requested OID does
* not match (e.g., when using %GNUTLS_IA_OCSP_URI), otherwise a
* negative error code.
*
* Since: 3.0.0
**/
int
gnutls_x509_crt_get_authority_info_access (gnutls_x509_crt_t crt,
unsigned int seq,
int what,
gnutls_datum_t * data,
unsigned int *critical)
{
int ret;
gnutls_datum_t aia;
ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
if (crt == NULL)
{
gnutls_assert ();
return GNUTLS_E_INVALID_REQUEST;
}
if ((ret = _gnutls_x509_crt_get_extension (crt, GNUTLS_OID_AIA, 0, &aia,
critical)) < 0)
return ret;
if (aia.size == 0 || aia.data == NULL)
{
gnutls_assert ();
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
if (critical && *critical)
return GNUTLS_E_CONSTRAINT_ERROR;
ret = asn1_create_element (_gnutls_get_pkix (),
"PKIX1.AuthorityInfoAccessSyntax", &c2);
if (ret != ASN1_SUCCESS)
{
gnutls_assert ();
_gnutls_free_datum (&aia);
return _gnutls_asn2err (ret);
}
ret = asn1_der_decoding (&c2, aia.data, aia.size, NULL);
/* asn1_print_structure (stdout, c2, "", ASN1_PRINT_ALL); */
_gnutls_free_datum (&aia);
if (ret != ASN1_SUCCESS)
{
gnutls_assert ();
asn1_delete_structure (&c2);
return _gnutls_asn2err (ret);
}
ret = _gnutls_parse_aia (c2, seq, what, data);
asn1_delete_structure (&c2);
if (ret < 0)
gnutls_assert ();
return ret;
}