/* * 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 #include #include #include #include #include #include #include #include /* 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 MHD__gnutls_x509_crt_get_extension (MHD_gnutls_x509_crt_t cert, const char *extension_id, int indx, MHD_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]; MHD_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 = MHD__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 = MHD__asn1_read_value (cert->cert, name2, extnID, &len); if (result == ASN1_ELEMENT_NOT_FOUND) { MHD_gnutls_assert (); break; } else if (result != ASN1_SUCCESS) { MHD_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 = MHD__asn1_read_value (cert->cert, name2, str_critical, &len); if (result == ASN1_ELEMENT_NOT_FOUND) { MHD_gnutls_assert (); break; } else if (result != ASN1_SUCCESS) { MHD_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 = MHD__gnutls_x509_read_value (cert->cert, name2, &value, 0); if (result < 0) { MHD_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 { MHD_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 MHD__gnutls_x509_crt_get_extension_oid (MHD_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 = MHD__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 = MHD__asn1_read_value (cert->cert, name2, extnID, &len); if (result == ASN1_ELEMENT_NOT_FOUND) { MHD_gnutls_assert (); break; } else if (result != ASN1_SUCCESS) { MHD_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; MHD_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 { MHD_gnutls_assert (); return MHD_gtls_asn2err (result); } } /* Here we only extract the KeyUsage field, from the DER encoded * extension. */ int MHD__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 = MHD__asn1_create_element (MHD__gnutls_get_pkix (), "PKIX1.KeyUsage", &ext)) != ASN1_SUCCESS) { MHD_gnutls_assert (); return MHD_gtls_asn2err (result); } result = MHD__asn1_der_decoding (&ext, extnValue, extnValueLen, NULL); if (result != ASN1_SUCCESS) { MHD_gnutls_assert (); MHD__asn1_delete_structure (&ext); return MHD_gtls_asn2err (result); } len = sizeof (str); result = MHD__asn1_read_value (ext, "", str, &len); if (result != ASN1_SUCCESS) { MHD_gnutls_assert (); MHD__asn1_delete_structure (&ext); return 0; } *keyUsage = str[0] | (str[1] << 8); MHD__asn1_delete_structure (&ext); return 0; } /* extract the basicConstraints from the DER encoded extension */ int MHD__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 = MHD__asn1_create_element (MHD__gnutls_get_pkix (), "PKIX1.BasicConstraints", &ext)) != ASN1_SUCCESS) { MHD_gnutls_assert (); return MHD_gtls_asn2err (result); } result = MHD__asn1_der_decoding (&ext, extnValue, extnValueLen, NULL); if (result != ASN1_SUCCESS) { MHD_gnutls_assert (); MHD__asn1_delete_structure (&ext); return MHD_gtls_asn2err (result); } if (pathLenConstraint) { result = MHD__gnutls_x509_read_uint (ext, "pathLenConstraint", (unsigned int *) pathLenConstraint); if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) *pathLenConstraint = -1; else if (result != GNUTLS_E_SUCCESS) { MHD_gnutls_assert (); MHD__asn1_delete_structure (&ext); return MHD_gtls_asn2err (result); } } /* the default value of cA is false. */ len = sizeof (str) - 1; result = MHD__asn1_read_value (ext, "cA", str, &len); if (result == ASN1_SUCCESS && strcmp (str, "TRUE") == 0) *CA = 1; else *CA = 0; MHD__asn1_delete_structure (&ext); return 0; }