mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
1096 lines
26 KiB
C
1096 lines
26 KiB
C
/*
|
|
* Copyright (C) 2003, 2004, 2005, 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
|
|
*
|
|
*/
|
|
|
|
/* Functions that relate to the X.509 extension parsing.
|
|
*/
|
|
|
|
#include <gnutls_int.h>
|
|
#include <gnutls_errors.h>
|
|
#include <gnutls_global.h>
|
|
#include <mpi.h>
|
|
#include <libtasn1.h>
|
|
#include <common.h>
|
|
#include <x509.h>
|
|
#include <extensions.h>
|
|
#include <gnutls_datum.h>
|
|
|
|
/* This function will attempt to return the requested extension found in
|
|
* the given X509v3 certificate. The return value is allocated and stored into
|
|
* ret.
|
|
*
|
|
* Critical will be either 0 or 1.
|
|
*
|
|
* If the extension does not exist, GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will
|
|
* be returned.
|
|
*/
|
|
int
|
|
_gnutls_x509_crt_get_extension (gnutls_x509_crt_t cert,
|
|
const char *extension_id, int indx,
|
|
gnutls_datum_t * ret, unsigned int *_critical)
|
|
{
|
|
int k, result, len;
|
|
char name[MAX_NAME_SIZE], name2[MAX_NAME_SIZE];
|
|
char str[1024];
|
|
char str_critical[10];
|
|
int critical = 0;
|
|
char extnID[128];
|
|
gnutls_datum_t value;
|
|
int indx_counter = 0;
|
|
|
|
ret->data = NULL;
|
|
ret->size = 0;
|
|
|
|
k = 0;
|
|
do
|
|
{
|
|
k++;
|
|
|
|
snprintf (name, sizeof (name), "tbsCertificate.extensions.?%u", k);
|
|
|
|
len = sizeof (str) - 1;
|
|
result = asn1_read_value (cert->cert, name, str, &len);
|
|
|
|
/* move to next
|
|
*/
|
|
|
|
if (result == ASN1_ELEMENT_NOT_FOUND)
|
|
{
|
|
break;
|
|
}
|
|
|
|
do
|
|
{
|
|
|
|
mhd_gtls_str_cpy (name2, sizeof (name2), name);
|
|
mhd_gtls_str_cat (name2, sizeof (name2), ".extnID");
|
|
|
|
len = sizeof (extnID) - 1;
|
|
result = asn1_read_value (cert->cert, name2, extnID, &len);
|
|
|
|
if (result == ASN1_ELEMENT_NOT_FOUND)
|
|
{
|
|
gnutls_assert ();
|
|
break;
|
|
}
|
|
else if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
/* Handle Extension
|
|
*/
|
|
if (strcmp (extnID, extension_id) == 0 && indx == indx_counter++)
|
|
{
|
|
/* extension was found
|
|
*/
|
|
|
|
/* read the critical status.
|
|
*/
|
|
mhd_gtls_str_cpy (name2, sizeof (name2), name);
|
|
mhd_gtls_str_cat (name2, sizeof (name2), ".critical");
|
|
|
|
len = sizeof (str_critical);
|
|
result =
|
|
asn1_read_value (cert->cert, name2, str_critical, &len);
|
|
|
|
if (result == ASN1_ELEMENT_NOT_FOUND)
|
|
{
|
|
gnutls_assert ();
|
|
break;
|
|
}
|
|
else if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
if (str_critical[0] == 'T')
|
|
critical = 1;
|
|
else
|
|
critical = 0;
|
|
|
|
/* read the value.
|
|
*/
|
|
mhd_gtls_str_cpy (name2, sizeof (name2), name);
|
|
mhd_gtls_str_cat (name2, sizeof (name2), ".extnValue");
|
|
|
|
result = _gnutls_x509_read_value (cert->cert, name2, &value, 0);
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
return result;
|
|
}
|
|
|
|
ret->data = value.data;
|
|
ret->size = value.size;
|
|
|
|
if (_critical)
|
|
*_critical = critical;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
}
|
|
while (0);
|
|
}
|
|
while (1);
|
|
|
|
if (result == ASN1_ELEMENT_NOT_FOUND)
|
|
{
|
|
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
|
|
}
|
|
else
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
}
|
|
|
|
/* This function will attempt to return the requested extension OID found in
|
|
* the given X509v3 certificate.
|
|
*
|
|
* If you have passed the last extension, 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 * sizeof_oid)
|
|
{
|
|
int k, result, len;
|
|
char name[MAX_NAME_SIZE], name2[MAX_NAME_SIZE];
|
|
char str[1024];
|
|
char extnID[128];
|
|
int indx_counter = 0;
|
|
|
|
k = 0;
|
|
do
|
|
{
|
|
k++;
|
|
|
|
snprintf (name, sizeof (name), "tbsCertificate.extensions.?%u", k);
|
|
|
|
len = sizeof (str) - 1;
|
|
result = asn1_read_value (cert->cert, name, str, &len);
|
|
|
|
/* move to next
|
|
*/
|
|
|
|
if (result == ASN1_ELEMENT_NOT_FOUND)
|
|
{
|
|
break;
|
|
}
|
|
|
|
do
|
|
{
|
|
|
|
mhd_gtls_str_cpy (name2, sizeof (name2), name);
|
|
mhd_gtls_str_cat (name2, sizeof (name2), ".extnID");
|
|
|
|
len = sizeof (extnID) - 1;
|
|
result = asn1_read_value (cert->cert, name2, extnID, &len);
|
|
|
|
if (result == ASN1_ELEMENT_NOT_FOUND)
|
|
{
|
|
gnutls_assert ();
|
|
break;
|
|
}
|
|
else if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
/* Handle Extension
|
|
*/
|
|
if (indx == indx_counter++)
|
|
{
|
|
len = strlen (extnID) + 1;
|
|
|
|
if (*sizeof_oid < (unsigned) len)
|
|
{
|
|
*sizeof_oid = len;
|
|
gnutls_assert ();
|
|
return GNUTLS_E_SHORT_MEMORY_BUFFER;
|
|
}
|
|
|
|
memcpy (oid, extnID, len);
|
|
*sizeof_oid = len - 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
}
|
|
while (0);
|
|
}
|
|
while (1);
|
|
|
|
if (result == ASN1_ELEMENT_NOT_FOUND)
|
|
{
|
|
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
|
|
}
|
|
else
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
}
|
|
|
|
/* This function will attempt to set the requested extension in
|
|
* the given X509v3 certificate.
|
|
*
|
|
* Critical will be either 0 or 1.
|
|
*/
|
|
static int
|
|
set_extension (ASN1_TYPE asn, const char *extension_id,
|
|
const gnutls_datum_t * ext_data, unsigned int critical)
|
|
{
|
|
int result;
|
|
const char *str;
|
|
|
|
/* Add a new extension in the list.
|
|
*/
|
|
result = asn1_write_value (asn, "tbsCertificate.extensions", "NEW", 1);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
result =
|
|
asn1_write_value (asn, "tbsCertificate.extensions.?LAST.extnID",
|
|
extension_id, 1);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
if (critical == 0)
|
|
str = "FALSE";
|
|
else
|
|
str = "TRUE";
|
|
|
|
|
|
result =
|
|
asn1_write_value (asn, "tbsCertificate.extensions.?LAST.critical",
|
|
str, 1);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
result =
|
|
_gnutls_x509_write_value (asn,
|
|
"tbsCertificate.extensions.?LAST.extnValue",
|
|
ext_data, 0);
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
return result;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Overwrite the given extension (using the index)
|
|
* index here starts from one.
|
|
*/
|
|
static int
|
|
overwrite_extension (ASN1_TYPE asn, unsigned int indx,
|
|
const gnutls_datum_t * ext_data, unsigned int critical)
|
|
{
|
|
char name[MAX_NAME_SIZE], name2[MAX_NAME_SIZE];
|
|
const char *str;
|
|
int result;
|
|
|
|
snprintf (name, sizeof (name), "tbsCertificate.extensions.?%u", indx);
|
|
|
|
if (critical == 0)
|
|
str = "FALSE";
|
|
else
|
|
str = "TRUE";
|
|
|
|
mhd_gtls_str_cpy (name2, sizeof (name2), name);
|
|
mhd_gtls_str_cat (name2, sizeof (name2), ".critical");
|
|
|
|
result = asn1_write_value (asn, name2, str, 1);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
mhd_gtls_str_cpy (name2, sizeof (name2), name);
|
|
mhd_gtls_str_cat (name2, sizeof (name2), ".extnValue");
|
|
|
|
result = _gnutls_x509_write_value (asn, name2, ext_data, 0);
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
return result;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* This function will attempt to overwrite the requested extension with
|
|
* the given one.
|
|
*
|
|
* Critical will be either 0 or 1.
|
|
*/
|
|
int
|
|
_gnutls_x509_crt_set_extension (gnutls_x509_crt_t cert,
|
|
const char *ext_id,
|
|
const gnutls_datum_t * ext_data,
|
|
unsigned int critical)
|
|
{
|
|
int result;
|
|
int k, len;
|
|
char name[MAX_NAME_SIZE], name2[MAX_NAME_SIZE];
|
|
char extnID[128];
|
|
|
|
/* Find the index of the given extension.
|
|
*/
|
|
k = 0;
|
|
do
|
|
{
|
|
k++;
|
|
|
|
snprintf (name, sizeof (name), "tbsCertificate.extensions.?%u", k);
|
|
|
|
len = sizeof (extnID) - 1;
|
|
result = asn1_read_value (cert->cert, name, extnID, &len);
|
|
|
|
/* move to next
|
|
*/
|
|
|
|
if (result == ASN1_ELEMENT_NOT_FOUND)
|
|
{
|
|
break;
|
|
}
|
|
|
|
do
|
|
{
|
|
|
|
mhd_gtls_str_cpy (name2, sizeof (name2), name);
|
|
mhd_gtls_str_cat (name2, sizeof (name2), ".extnID");
|
|
|
|
len = sizeof (extnID) - 1;
|
|
result = asn1_read_value (cert->cert, name2, extnID, &len);
|
|
|
|
if (result == ASN1_ELEMENT_NOT_FOUND)
|
|
{
|
|
gnutls_assert ();
|
|
break;
|
|
}
|
|
else if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
/* Handle Extension
|
|
*/
|
|
if (strcmp (extnID, ext_id) == 0)
|
|
{
|
|
/* extension was found
|
|
*/
|
|
return overwrite_extension (cert->cert, k, ext_data, critical);
|
|
}
|
|
|
|
|
|
}
|
|
while (0);
|
|
}
|
|
while (1);
|
|
|
|
if (result == ASN1_ELEMENT_NOT_FOUND)
|
|
{
|
|
return set_extension (cert->cert, ext_id, ext_data, critical);
|
|
}
|
|
else
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Here we only extract the KeyUsage field, from the DER encoded
|
|
* extension.
|
|
*/
|
|
int
|
|
_gnutls_x509_ext_extract_keyUsage (uint16_t * keyUsage,
|
|
opaque * extnValue, int extnValueLen)
|
|
{
|
|
ASN1_TYPE ext = ASN1_TYPE_EMPTY;
|
|
int len, result;
|
|
uint8_t str[2];
|
|
|
|
str[0] = str[1] = 0;
|
|
*keyUsage = 0;
|
|
|
|
if ((result = asn1_create_element
|
|
(_gnutls_get_pkix (), "PKIX1.KeyUsage", &ext)) != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
result = asn1_der_decoding (&ext, extnValue, extnValueLen, NULL);
|
|
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
len = sizeof (str);
|
|
result = asn1_read_value (ext, "", str, &len);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return 0;
|
|
}
|
|
|
|
*keyUsage = str[0] | (str[1] << 8);
|
|
|
|
asn1_delete_structure (&ext);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* extract the basicConstraints from the DER encoded extension
|
|
*/
|
|
int
|
|
_gnutls_x509_ext_extract_basicConstraints (int *CA,
|
|
int *pathLenConstraint,
|
|
opaque * extnValue,
|
|
int extnValueLen)
|
|
{
|
|
ASN1_TYPE ext = ASN1_TYPE_EMPTY;
|
|
char str[128];
|
|
int len, result;
|
|
|
|
if ((result = asn1_create_element
|
|
(_gnutls_get_pkix (), "PKIX1.BasicConstraints", &ext)) != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
result = asn1_der_decoding (&ext, extnValue, extnValueLen, NULL);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
if (pathLenConstraint)
|
|
{
|
|
result = _gnutls_x509_read_uint (ext, "pathLenConstraint",
|
|
pathLenConstraint);
|
|
if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
|
|
*pathLenConstraint = -1;
|
|
else if (result != GNUTLS_E_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
}
|
|
|
|
/* the default value of cA is false.
|
|
*/
|
|
len = sizeof (str) - 1;
|
|
result = asn1_read_value (ext, "cA", str, &len);
|
|
if (result == ASN1_SUCCESS && strcmp (str, "TRUE") == 0)
|
|
*CA = 1;
|
|
else
|
|
*CA = 0;
|
|
|
|
asn1_delete_structure (&ext);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* generate the basicConstraints in a DER encoded extension
|
|
* Use 0 or 1 (TRUE) for CA.
|
|
* Use negative values for pathLenConstraint to indicate that the field
|
|
* should not be present, >= 0 to indicate set values.
|
|
*/
|
|
int
|
|
_gnutls_x509_ext_gen_basicConstraints (int CA,
|
|
int pathLenConstraint,
|
|
gnutls_datum_t * der_ext)
|
|
{
|
|
ASN1_TYPE ext = ASN1_TYPE_EMPTY;
|
|
const char *str;
|
|
int result;
|
|
|
|
if (CA == 0)
|
|
str = "FALSE";
|
|
else
|
|
str = "TRUE";
|
|
|
|
result =
|
|
asn1_create_element (_gnutls_get_pkix (), "PKIX1.BasicConstraints", &ext);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
result = asn1_write_value (ext, "cA", str, 1);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
if (pathLenConstraint < 0)
|
|
{
|
|
result = asn1_write_value (ext, "pathLenConstraint", NULL, 0);
|
|
if (result < 0)
|
|
result = mhd_gtls_asn2err (result);
|
|
}
|
|
else
|
|
result = _gnutls_x509_write_uint32 (ext, "pathLenConstraint",
|
|
pathLenConstraint);
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return result;
|
|
}
|
|
|
|
result = _gnutls_x509_der_encode (ext, "", der_ext, 0);
|
|
|
|
asn1_delete_structure (&ext);
|
|
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
return result;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* generate the keyUsage in a DER encoded extension
|
|
* Use an ORed SEQUENCE of GNUTLS_KEY_* for usage.
|
|
*/
|
|
int
|
|
_gnutls_x509_ext_gen_keyUsage (uint16_t usage, gnutls_datum_t * der_ext)
|
|
{
|
|
ASN1_TYPE ext = ASN1_TYPE_EMPTY;
|
|
int result;
|
|
uint8_t str[2];
|
|
|
|
result = asn1_create_element (_gnutls_get_pkix (), "PKIX1.KeyUsage", &ext);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
str[0] = usage & 0xff;
|
|
str[1] = usage >> 8;
|
|
|
|
result = asn1_write_value (ext, "", str, 9);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
result = _gnutls_x509_der_encode (ext, "", der_ext, 0);
|
|
|
|
asn1_delete_structure (&ext);
|
|
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
return result;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
write_new_general_name (ASN1_TYPE ext, const char *ext_name,
|
|
gnutls_x509_subject_alt_name_t type,
|
|
const char *data_string)
|
|
{
|
|
const char *str;
|
|
int result;
|
|
char name[128];
|
|
|
|
result = asn1_write_value (ext, ext_name, "NEW", 1);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
case GNUTLS_SAN_DNSNAME:
|
|
str = "dNSName";
|
|
break;
|
|
case GNUTLS_SAN_RFC822NAME:
|
|
str = "rfc822Name";
|
|
break;
|
|
case GNUTLS_SAN_URI:
|
|
str = "uniformResourceIdentifier";
|
|
break;
|
|
case GNUTLS_SAN_IPADDRESS:
|
|
str = "iPAddress";
|
|
break;
|
|
default:
|
|
gnutls_assert ();
|
|
return GNUTLS_E_INTERNAL_ERROR;
|
|
}
|
|
|
|
if (ext_name[0] == 0)
|
|
{ /* no dot */
|
|
mhd_gtls_str_cpy (name, sizeof (name), "?LAST");
|
|
}
|
|
else
|
|
{
|
|
mhd_gtls_str_cpy (name, sizeof (name), ext_name);
|
|
mhd_gtls_str_cat (name, sizeof (name), ".?LAST");
|
|
}
|
|
|
|
result = asn1_write_value (ext, name, str, 1);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
mhd_gtls_str_cat (name, sizeof (name), ".");
|
|
mhd_gtls_str_cat (name, sizeof (name), str);
|
|
|
|
result = asn1_write_value (ext, name, data_string, strlen (data_string));
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Convert the given name to GeneralNames in a DER encoded extension.
|
|
* This is the same as subject alternative name.
|
|
*/
|
|
int
|
|
_gnutls_x509_ext_gen_subject_alt_name (gnutls_x509_subject_alt_name_t
|
|
type, const char *data_string,
|
|
gnutls_datum_t * der_ext)
|
|
{
|
|
ASN1_TYPE ext = ASN1_TYPE_EMPTY;
|
|
int result;
|
|
|
|
result =
|
|
asn1_create_element (_gnutls_get_pkix (), "PKIX1.GeneralNames", &ext);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
result = write_new_general_name (ext, "", type, data_string);
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return result;
|
|
}
|
|
|
|
result = _gnutls_x509_der_encode (ext, "", der_ext, 0);
|
|
|
|
asn1_delete_structure (&ext);
|
|
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
return result;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* generate the SubjectKeyID in a DER encoded extension
|
|
*/
|
|
int
|
|
_gnutls_x509_ext_gen_key_id (const void *id, size_t id_size,
|
|
gnutls_datum_t * der_ext)
|
|
{
|
|
ASN1_TYPE ext = ASN1_TYPE_EMPTY;
|
|
int result;
|
|
|
|
result =
|
|
asn1_create_element (_gnutls_get_pkix (),
|
|
"PKIX1.SubjectKeyIdentifier", &ext);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
result = asn1_write_value (ext, "", id, id_size);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
result = _gnutls_x509_der_encode (ext, "", der_ext, 0);
|
|
|
|
asn1_delete_structure (&ext);
|
|
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
return result;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* generate the AuthorityKeyID in a DER encoded extension
|
|
*/
|
|
int
|
|
_gnutls_x509_ext_gen_auth_key_id (const void *id, size_t id_size,
|
|
gnutls_datum_t * der_ext)
|
|
{
|
|
ASN1_TYPE ext = ASN1_TYPE_EMPTY;
|
|
int result;
|
|
|
|
result =
|
|
asn1_create_element (_gnutls_get_pkix (),
|
|
"PKIX1.AuthorityKeyIdentifier", &ext);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
result = asn1_write_value (ext, "keyIdentifier", id, id_size);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
asn1_write_value (ext, "authorityCertIssuer", NULL, 0);
|
|
asn1_write_value (ext, "authorityCertSerialNumber", NULL, 0);
|
|
|
|
result = _gnutls_x509_der_encode (ext, "", der_ext, 0);
|
|
|
|
asn1_delete_structure (&ext);
|
|
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
return result;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Creates and encodes the CRL Distribution points. data_string should be a name
|
|
* and type holds the type of the name.
|
|
* reason_flags should be an or'ed sequence of GNUTLS_CRL_REASON_*.
|
|
*
|
|
*/
|
|
int
|
|
_gnutls_x509_ext_gen_crl_dist_points (gnutls_x509_subject_alt_name_t
|
|
type, const void *data_string,
|
|
unsigned int reason_flags,
|
|
gnutls_datum_t * der_ext)
|
|
{
|
|
ASN1_TYPE ext = ASN1_TYPE_EMPTY;
|
|
gnutls_datum_t gnames = { NULL, 0 };
|
|
int result;
|
|
uint8_t reasons[2];
|
|
|
|
reasons[0] = reason_flags & 0xff;
|
|
reasons[1] = reason_flags >> 8;
|
|
|
|
result =
|
|
asn1_create_element (_gnutls_get_pkix (),
|
|
"PKIX1.CRLDistributionPoints", &ext);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
result = mhd_gtls_asn2err (result);
|
|
goto cleanup;
|
|
}
|
|
|
|
result = asn1_write_value (ext, "", "NEW", 1);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
result = mhd_gtls_asn2err (result);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (reason_flags)
|
|
{
|
|
result = asn1_write_value (ext, "?LAST.reasons", reasons, 9);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
result = mhd_gtls_asn2err (result);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = asn1_write_value (ext, "?LAST.reasons", NULL, 0);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
result = mhd_gtls_asn2err (result);
|
|
goto cleanup;
|
|
}
|
|
}
|
|
|
|
result = asn1_write_value (ext, "?LAST.cRLIssuer", NULL, 0);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
result = mhd_gtls_asn2err (result);
|
|
goto cleanup;
|
|
}
|
|
|
|
/* When used as type CHOICE.
|
|
*/
|
|
result = asn1_write_value (ext, "?LAST.distributionPoint", "fullName", 1);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
result = mhd_gtls_asn2err (result);
|
|
goto cleanup;
|
|
}
|
|
|
|
#if 0
|
|
/* only needed in old code (where defined as SEQUENCE OF) */
|
|
asn1_write_value (ext,
|
|
"?LAST.distributionPoint.nameRelativeToCRLIssuer",
|
|
NULL, 0);
|
|
#endif
|
|
|
|
result =
|
|
write_new_general_name (ext, "?LAST.distributionPoint.fullName",
|
|
type, data_string);
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
goto cleanup;
|
|
}
|
|
|
|
result = _gnutls_x509_der_encode (ext, "", der_ext, 0);
|
|
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
goto cleanup;
|
|
}
|
|
|
|
result = 0;
|
|
|
|
cleanup:
|
|
_gnutls_free_datum (&gnames);
|
|
asn1_delete_structure (&ext);
|
|
|
|
return result;
|
|
}
|
|
|
|
/* extract the proxyCertInfo from the DER encoded extension
|
|
*/
|
|
int
|
|
_gnutls_x509_ext_extract_proxyCertInfo (int *pathLenConstraint,
|
|
char **policyLanguage,
|
|
char **policy,
|
|
size_t * sizeof_policy,
|
|
opaque * extnValue, int extnValueLen)
|
|
{
|
|
ASN1_TYPE ext = ASN1_TYPE_EMPTY;
|
|
int result;
|
|
gnutls_datum_t value;
|
|
|
|
if ((result = asn1_create_element
|
|
(_gnutls_get_pkix (), "PKIX1.ProxyCertInfo", &ext)) != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
result = asn1_der_decoding (&ext, extnValue, extnValueLen, NULL);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
if (pathLenConstraint)
|
|
{
|
|
result = _gnutls_x509_read_uint (ext, "pCPathLenConstraint",
|
|
pathLenConstraint);
|
|
if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
|
|
*pathLenConstraint = -1;
|
|
else if (result != GNUTLS_E_SUCCESS)
|
|
{
|
|
asn1_delete_structure (&ext);
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
}
|
|
|
|
result = _gnutls_x509_read_value (ext, "proxyPolicy.policyLanguage",
|
|
&value, 0);
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return result;
|
|
}
|
|
|
|
if (policyLanguage)
|
|
*policyLanguage = gnutls_strdup (value.data);
|
|
|
|
result = _gnutls_x509_read_value (ext, "proxyPolicy.policy", &value, 0);
|
|
if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
|
|
{
|
|
if (policy)
|
|
*policy = NULL;
|
|
if (sizeof_policy)
|
|
*sizeof_policy = 0;
|
|
}
|
|
else if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
if (policy)
|
|
*policy = value.data;
|
|
if (sizeof_policy)
|
|
*sizeof_policy = value.size;
|
|
}
|
|
|
|
asn1_delete_structure (&ext);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* generate the proxyCertInfo in a DER encoded extension
|
|
*/
|
|
int
|
|
_gnutls_x509_ext_gen_proxyCertInfo (int pathLenConstraint,
|
|
const char *policyLanguage,
|
|
const char *policy,
|
|
size_t sizeof_policy,
|
|
gnutls_datum_t * der_ext)
|
|
{
|
|
ASN1_TYPE ext = ASN1_TYPE_EMPTY;
|
|
int result;
|
|
|
|
result = asn1_create_element (_gnutls_get_pkix (),
|
|
"PKIX1.ProxyCertInfo", &ext);
|
|
if (result != ASN1_SUCCESS)
|
|
{
|
|
gnutls_assert ();
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
if (pathLenConstraint < 0)
|
|
{
|
|
result = asn1_write_value (ext, "pCPathLenConstraint", NULL, 0);
|
|
if (result < 0)
|
|
result = mhd_gtls_asn2err (result);
|
|
}
|
|
else
|
|
result = _gnutls_x509_write_uint32 (ext, "pCPathLenConstraint",
|
|
pathLenConstraint);
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return result;
|
|
}
|
|
|
|
result = asn1_write_value (ext, "proxyPolicy.policyLanguage",
|
|
policyLanguage, 1);
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
result = asn1_write_value (ext, "proxyPolicy.policy",
|
|
policy, sizeof_policy);
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
asn1_delete_structure (&ext);
|
|
return mhd_gtls_asn2err (result);
|
|
}
|
|
|
|
result = _gnutls_x509_der_encode (ext, "", der_ext, 0);
|
|
|
|
asn1_delete_structure (&ext);
|
|
|
|
if (result < 0)
|
|
{
|
|
gnutls_assert ();
|
|
return result;
|
|
}
|
|
|
|
return 0;
|
|
}
|