/* * Copyright (C) 2003-2016 Free Software Foundation, Inc. * Copyright (C) 2012-2016 Nikos Mavrogiannopoulos * Copyright (C) 2017 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * * 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 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 program. If not, see * */ #include "gnutls_int.h" #include #include "errors.h" #include #include #include "x509_int.h" #include "attributes.h" /* Functions to parse and set the PKIX1 Attributes structure. */ /* Overwrite the given attribute (using the index) * index here starts from one. */ static int overwrite_attribute(ASN1_TYPE asn, const char *root, unsigned indx, const gnutls_datum_t * ext_data) { char name[MAX_NAME_SIZE], name2[MAX_NAME_SIZE]; int result; snprintf(name, sizeof(name), "%s.?%u", root, indx); _gnutls_str_cpy(name2, sizeof(name2), name); _gnutls_str_cat(name2, sizeof(name2), ".values.?LAST"); result = _gnutls_x509_write_value(asn, name2, ext_data); if (result < 0) { gnutls_assert(); return result; } return 0; } /* Parses an Attribute list in the asn1_struct, and searches for the * given OID. The index indicates the attribute value to be returned. * * If raw==0 only printable data are returned, or * GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE. * * asn1_attr_name must be a string in the form * "certificationRequestInfo.attributes" * */ int _x509_parse_attribute(ASN1_TYPE asn1_struct, const char *attr_name, const char *given_oid, unsigned indx, int raw, gnutls_datum_t * out) { int k1, result; char tmpbuffer1[MAX_NAME_SIZE]; char tmpbuffer3[MAX_NAME_SIZE]; char value[200]; gnutls_datum_t td; char oid[MAX_OID_SIZE]; int len; k1 = 0; do { k1++; /* create a string like "attribute.?1" */ if (attr_name[0] != 0) snprintf(tmpbuffer1, sizeof(tmpbuffer1), "%s.?%u", attr_name, k1); else snprintf(tmpbuffer1, sizeof(tmpbuffer1), "?%u", k1); len = sizeof(value) - 1; result = asn1_read_value(asn1_struct, tmpbuffer1, value, &len); if (result == ASN1_ELEMENT_NOT_FOUND) { gnutls_assert(); break; } if (result != ASN1_VALUE_NOT_FOUND) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } /* Move to the attribute type and values */ /* Read the OID */ _gnutls_str_cpy(tmpbuffer3, sizeof(tmpbuffer3), tmpbuffer1); _gnutls_str_cat(tmpbuffer3, sizeof(tmpbuffer3), ".type"); len = sizeof(oid) - 1; result = asn1_read_value(asn1_struct, tmpbuffer3, oid, &len); if (result == ASN1_ELEMENT_NOT_FOUND) break; else if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } if (strcmp(oid, given_oid) == 0) { /* Found the OID */ /* Read the Value */ snprintf(tmpbuffer3, sizeof(tmpbuffer3), "%s.values.?%u", tmpbuffer1, indx + 1); len = sizeof(value) - 1; result = _gnutls_x509_read_value(asn1_struct, tmpbuffer3, &td); if (result != ASN1_SUCCESS) { gnutls_assert(); result = _gnutls_asn2err(result); goto cleanup; } if (raw == 0) { result = _gnutls_x509_dn_to_string (oid, td.data, td.size, out); _gnutls_free_datum(&td); if (result < 0) { gnutls_assert(); goto cleanup; } return 0; } else { /* raw!=0 */ out->data = td.data; out->size = td.size; return 0; } } } while (1); gnutls_assert(); result = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; cleanup: return result; } /* This function will attempt to set the requested attribute in * the given X509v3 certificate. * * Critical will be either 0 or 1. */ static int add_attribute(ASN1_TYPE asn, const char *root, const char *attribute_id, const gnutls_datum_t * ext_data) { int result; char name[MAX_NAME_SIZE]; snprintf(name, sizeof(name), "%s", root); /* Add a new attribute in the list. */ result = asn1_write_value(asn, name, "NEW", 1); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } snprintf(name, sizeof(name), "%s.?LAST.type", root); result = asn1_write_value(asn, name, attribute_id, 1); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } snprintf(name, sizeof(name), "%s.?LAST.values", root); result = asn1_write_value(asn, name, "NEW", 1); if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } snprintf(name, sizeof(name), "%s.?LAST.values.?LAST", root); result = _gnutls_x509_write_value(asn, name, ext_data); if (result < 0) { gnutls_assert(); return result; } return 0; } int _x509_set_attribute(ASN1_TYPE asn, const char *root, const char *ext_id, const gnutls_datum_t * ext_data) { int result; int k, len; char name[MAX_NAME_SIZE], name2[MAX_NAME_SIZE]; char extnID[MAX_OID_SIZE]; /* Find the index of the given attribute. */ k = 0; do { k++; snprintf(name, sizeof(name), "%s.?%u", root, k); len = sizeof(extnID) - 1; result = asn1_read_value(asn, name, extnID, &len); /* move to next */ if (result == ASN1_ELEMENT_NOT_FOUND) { break; } do { _gnutls_str_cpy(name2, sizeof(name2), name); _gnutls_str_cat(name2, sizeof(name2), ".type"); len = sizeof(extnID) - 1; result = asn1_read_value(asn, name2, extnID, &len); if (result == ASN1_ELEMENT_NOT_FOUND) { gnutls_assert(); break; } else if (result != ASN1_SUCCESS) { gnutls_assert(); return _gnutls_asn2err(result); } /* Handle Extension */ if (strcmp(extnID, ext_id) == 0) { /* attribute was found */ return overwrite_attribute(asn, root, k, ext_data); } } while (0); } while (1); if (result == ASN1_ELEMENT_NOT_FOUND) { return add_attribute(asn, root, ext_id, ext_data); } else { gnutls_assert(); return _gnutls_asn2err(result); } return 0; }