summaryrefslogtreecommitdiffstats
path: root/lib/x509/attributes.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/x509/attributes.c')
-rw-r--r--lib/x509/attributes.c299
1 files changed, 299 insertions, 0 deletions
diff --git a/lib/x509/attributes.c b/lib/x509/attributes.c
new file mode 100644
index 0000000..3aab65b
--- /dev/null
+++ b/lib/x509/attributes.c
@@ -0,0 +1,299 @@
+/*
+ * 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 <https://www.gnu.org/licenses/>
+ *
+ */
+
+#include "gnutls_int.h"
+
+#include <datum.h>
+#include "errors.h"
+#include <common.h>
+#include <x509.h>
+#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_node 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_node 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.?%d",
+ attr_name, k1);
+ else
+ snprintf(tmpbuffer1, sizeof(tmpbuffer1), "?%d",
+ 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_node 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_node 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.?%d", 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;
+}