summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2014-03-19 11:33:12 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2014-03-19 11:33:12 +0100
commit2bd323f728d75c44a2d7398503178b75e5b63263 (patch)
tree8c19e8bbf4b72c2069a82761841d2df42988f56e
parentc04d73d1e2a92084ccfe4f02a99f31d13f6f44d7 (diff)
downloadgnutls-2bd323f728d75c44a2d7398503178b75e5b63263.tar.gz
Added new API to handle X.509 extensions.
This API handles the X.509 extensions in separate, allowing to parse similarly formatted extensions stored in other structures. In addition functions that simplify the extraction of extensions from known structures were added: - gnutls_x509_crq_get_extension_data2() - gnutls_x509_crl_get_extension_data2() - gnutls_x509_crt_get_extension_data2() The old functions were rewritten to use the new API.
-rw-r--r--lib/includes/Makefile.am3
-rw-r--r--lib/includes/gnutls/x509-ext.h189
-rw-r--r--lib/includes/gnutls/x509.h35
-rw-r--r--lib/libgnutls.map54
-rw-r--r--lib/x509/Makefile.am3
-rw-r--r--lib/x509/common.c37
-rw-r--r--lib/x509/common.h3
-rw-r--r--lib/x509/crq.c117
-rw-r--r--lib/x509/extensions.c665
-rw-r--r--lib/x509/name_constraints.c148
-rw-r--r--lib/x509/output.c289
-rw-r--r--lib/x509/x509.c776
-rw-r--r--lib/x509/x509_ext.c3028
-rw-r--r--lib/x509/x509_int.h73
-rw-r--r--lib/x509/x509_write.c557
15 files changed, 4177 insertions, 1800 deletions
diff --git a/lib/includes/Makefile.am b/lib/includes/Makefile.am
index bf32cdb4c8..31449cb1c0 100644
--- a/lib/includes/Makefile.am
+++ b/lib/includes/Makefile.am
@@ -20,7 +20,8 @@
nobase_include_HEADERS = gnutls/x509.h gnutls/pkcs12.h gnutls/compat.h \
gnutls/openpgp.h gnutls/crypto.h gnutls/pkcs11.h \
- gnutls/abstract.h gnutls/dtls.h gnutls/ocsp.h gnutls/tpm.h
+ gnutls/abstract.h gnutls/dtls.h gnutls/ocsp.h gnutls/tpm.h \
+ gnutls/x509-ext.h
if ENABLE_CXX
nobase_include_HEADERS += gnutls/gnutlsxx.h
diff --git a/lib/includes/gnutls/x509-ext.h b/lib/includes/gnutls/x509-ext.h
new file mode 100644
index 0000000000..f1d997ccbf
--- /dev/null
+++ b/lib/includes/gnutls/x509-ext.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2014 Free Software Foundation, 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* Prototypes for direct handling of extension data */
+
+#ifndef GNUTLS_X509_EXT_H
+#define GNUTLS_X509_EXT_H
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* *INDENT-ON* */
+
+typedef struct gnutls_subject_alt_names_st *gnutls_subject_alt_names_t;
+
+int gnutls_subject_alt_names_init(gnutls_subject_alt_names_t *);
+void gnutls_subject_alt_names_deinit(gnutls_subject_alt_names_t sans);
+int gnutls_subject_alt_names_get(gnutls_subject_alt_names_t sans, unsigned int seq,
+ unsigned int *san_type, gnutls_datum_t * san,
+ gnutls_datum_t * othername_oid);
+int gnutls_subject_alt_names_set(gnutls_subject_alt_names_t sans,
+ unsigned int san_type,
+ const gnutls_datum_t * san,
+ const char* othername_oid);
+
+
+int gnutls_x509_ext_get_subject_alt_names(const gnutls_datum_t * ext,
+ gnutls_subject_alt_names_t,
+ unsigned int flags);
+int gnutls_x509_ext_set_subject_alt_names(gnutls_subject_alt_names_t,
+ gnutls_datum_t * ext);
+
+/* They are exactly the same */
+#define gnutls_x509_ext_get_issuer_alt_name gnutls_x509_ext_get_subject_alt_name
+#define gnutls_x509_ext_set_issuer_alt_name gnutls_x509_ext_set_subject_alt_name
+
+typedef struct gnutls_x509_crl_dist_points_st *gnutls_x509_crl_dist_points_t;
+
+int gnutls_x509_crl_dist_points_init(gnutls_x509_crl_dist_points_t *);
+void gnutls_x509_crl_dist_points_deinit(gnutls_x509_crl_dist_points_t);
+int gnutls_x509_crl_dist_points_get(gnutls_x509_crl_dist_points_t, unsigned int seq,
+ unsigned int *type,
+ gnutls_datum_t *dist, unsigned int *reason_flags);
+int gnutls_x509_crl_dist_points_set(gnutls_x509_crl_dist_points_t,
+ gnutls_x509_subject_alt_name_t type,
+ const gnutls_datum_t *dist, unsigned int reason_flags);
+
+int gnutls_x509_ext_get_crl_dist_points(const gnutls_datum_t * ext,
+ gnutls_x509_crl_dist_points_t dp,
+ unsigned int flags);
+int gnutls_x509_ext_set_crl_dist_points(gnutls_x509_crl_dist_points_t dp,
+ gnutls_datum_t * ext);
+
+int gnutls_x509_ext_get_name_constraints(const gnutls_datum_t * ext,
+ gnutls_x509_name_constraints_t nc,
+ unsigned int flags);
+int gnutls_x509_ext_set_name_constraints(gnutls_x509_name_constraints_t nc,
+ gnutls_datum_t * ext);
+
+typedef struct gnutls_x509_aia_st *gnutls_x509_aia_t;
+
+int gnutls_x509_aia_init(gnutls_x509_aia_t *);
+void gnutls_x509_aia_deinit(gnutls_x509_aia_t);
+int gnutls_x509_aia_get(gnutls_x509_aia_t aia, unsigned int seq,
+ gnutls_datum_t *oid,
+ unsigned *san_type,
+ gnutls_datum_t *san);
+int gnutls_x509_aia_set(gnutls_x509_aia_t aia,
+ const char *oid,
+ unsigned san_type,
+ const gnutls_datum_t * san);
+
+int gnutls_x509_ext_get_aia(const gnutls_datum_t * ext,
+ gnutls_x509_aia_t,
+ unsigned int flags);
+int gnutls_x509_ext_set_aia(gnutls_x509_aia_t aia,
+ gnutls_datum_t * ext);
+
+int gnutls_x509_ext_get_subject_key_id(const gnutls_datum_t * ext,
+ gnutls_datum_t * id);
+int gnutls_x509_ext_set_subject_key_id(const gnutls_datum_t * id,
+ gnutls_datum_t * ext);
+
+typedef struct gnutls_x509_aki_st *gnutls_x509_aki_t;
+
+int gnutls_x509_ext_set_authority_key_id(gnutls_x509_aki_t,
+ gnutls_datum_t * ext);
+int gnutls_x509_ext_get_authority_key_id(const gnutls_datum_t * ext,
+ gnutls_x509_aki_t,
+ unsigned int flags);
+
+int gnutls_x509_aki_init(gnutls_x509_aki_t *);
+int gnutls_x509_aki_get_id(gnutls_x509_aki_t, gnutls_datum_t *id);
+int gnutls_x509_aki_get_cert_issuer(gnutls_x509_aki_t aki, unsigned int seq,
+ unsigned int *san_type, gnutls_datum_t * san,
+ gnutls_datum_t *othername_oid,
+ gnutls_datum_t *serial);
+int gnutls_x509_aki_set_id(gnutls_x509_aki_t aki, const gnutls_datum_t *id);
+int gnutls_x509_aki_set_cert_issuer(gnutls_x509_aki_t aki,
+ unsigned int san_type,
+ const gnutls_datum_t * san,
+ const char *othername_oid,
+ const gnutls_datum_t * serial);
+void gnutls_x509_aki_deinit(gnutls_x509_aki_t);
+
+int gnutls_x509_ext_get_private_key_usage_period(const gnutls_datum_t * ext,
+ time_t * activation,
+ time_t * expiration);
+int gnutls_x509_ext_set_private_key_usage_period(time_t activation,
+ time_t expiration,
+ gnutls_datum_t * ext);
+
+int gnutls_x509_ext_get_basic_constraints(const gnutls_datum_t * ext,
+ unsigned int *ca, int *pathlen);
+int gnutls_x509_ext_set_basic_constraints(unsigned int ca, int pathlen,
+ gnutls_datum_t * ext);
+
+typedef struct gnutls_x509_key_purposes_st *gnutls_x509_key_purposes_t;
+
+int gnutls_x509_key_purpose_init(gnutls_x509_key_purposes_t *p);
+void gnutls_x509_key_purpose_deinit(gnutls_x509_key_purposes_t p);
+int gnutls_x509_key_purpose_set(gnutls_x509_key_purposes_t p, const char *oid);
+int gnutls_x509_key_purpose_get(gnutls_x509_key_purposes_t p, unsigned idx, gnutls_datum_t *oid);
+
+int gnutls_x509_ext_get_key_purposes(const gnutls_datum_t * ext,
+ gnutls_x509_key_purposes_t,
+ unsigned int flags);
+int gnutls_x509_ext_set_key_purposes(gnutls_x509_key_purposes_t,
+ gnutls_datum_t * ext);
+
+
+int gnutls_x509_ext_get_key_usage(const gnutls_datum_t * ext,
+ unsigned int *key_usage);
+int gnutls_x509_ext_set_key_usage(unsigned int key_usage,
+ gnutls_datum_t * ext);
+
+int gnutls_x509_ext_get_proxy(const gnutls_datum_t * ext, int *pathlen,
+ char **policyLanguage, char **policy,
+ size_t * sizeof_policy);
+int gnutls_x509_ext_set_proxy(int pathLenConstraint, const char *policyLanguage,
+ const char *policy, size_t sizeof_policy,
+ gnutls_datum_t * ext);
+
+typedef struct gnutls_x509_policies_st *gnutls_x509_policies_t;
+
+int gnutls_x509_policies_init(gnutls_x509_policies_t *);
+void gnutls_x509_policies_deinit(gnutls_x509_policies_t);
+
+int gnutls_x509_policies_get(gnutls_x509_policies_t policies, unsigned int seq,
+ struct gnutls_x509_policy_st *policy);
+int gnutls_x509_policies_set(gnutls_x509_policies_t policies,
+ const struct gnutls_x509_policy_st *policy);
+
+int gnutls_x509_ext_get_policies(const gnutls_datum_t * ext, gnutls_x509_policies_t
+ policies,
+ unsigned int flags);
+int gnutls_x509_ext_set_policies(gnutls_x509_policies_t policies,
+ gnutls_datum_t * ext);
+
+
+/* *INDENT-OFF* */
+#ifdef __cplusplus
+}
+#endif
+/* *INDENT-ON* */
+#endif /* GNUTLS_X509_H */
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h
index 7cc0062c88..f0d6c4e40e 100644
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -87,6 +87,20 @@ extern "C" {
#define GNUTLS_FSAN_SET 0
#define GNUTLS_FSAN_APPEND 1
+#define GNUTLS_X509EXT_OID_SUBJECT_KEY_ID "2.5.29.14"
+#define GNUTLS_X509EXT_OID_KEY_USAGE "2.5.29.15"
+#define GNUTLS_X509EXT_OID_PRIVATE_KEY_USAGE_PERIOD "2.5.29.16"
+#define GNUTLS_X509EXT_OID_SAN "2.5.29.17"
+#define GNUTLS_X509EXT_OID_IAN "2.5.29.18"
+#define GNUTLS_X509EXT_OID_BASIC_CONSTRAINTS "2.5.29.19"
+#define GNUTLS_X509EXT_OID_NAME_CONSTRAINTS "2.5.29.30"
+#define GNUTLS_X509EXT_OID_CRL_DIST_POINTS "2.5.29.31"
+#define GNUTLS_X509EXT_OID_CRT_POLICY "2.5.29.32"
+#define GNUTLS_X509EXT_OID_AUTHORITY_KEY_ID "2.5.29.35"
+#define GNUTLS_X509EXT_OID_EXTENDED_KEY_USAGE "2.5.29.37"
+#define GNUTLS_X509EXT_OID_AUTHORITY_INFO_ACCESS "1.3.6.1.5.5.7.1.1"
+#define GNUTLS_X509EXT_OID_PROXY_CRT_INFO "1.3.6.1.5.5.7.1.14"
+
/* Certificate handling functions.
*/
@@ -221,6 +235,7 @@ typedef enum gnutls_info_access_what_t {
/* use 100-108 for the generalName types, populate as needed */
GNUTLS_IA_URI = 106,
/* quick-access variants that match both OID and name type. */
+ GNUTLS_IA_UNKNOWN = 10000,
GNUTLS_IA_OCSP_URI = 10006,
GNUTLS_IA_CAISSUERS_URI = 10106
} gnutls_info_access_what_t;
@@ -426,7 +441,7 @@ void gnutls_x509_policy_release(struct gnutls_x509_policy_st
*policy);
int gnutls_x509_crt_get_policy(gnutls_x509_crt_t crt, int indx, struct gnutls_x509_policy_st
*policy, unsigned int *critical);
-int gnutls_x509_crt_set_policy(gnutls_x509_crt_t crt, struct gnutls_x509_policy_st
+int gnutls_x509_crt_set_policy(gnutls_x509_crt_t crt, const struct gnutls_x509_policy_st
*policy, unsigned int critical);
int gnutls_x509_dn_oid_known(const char *oid);
@@ -452,6 +467,10 @@ int gnutls_x509_crt_get_extension_info(gnutls_x509_crt_t cert,
int gnutls_x509_crt_get_extension_data(gnutls_x509_crt_t cert,
int indx, void *data,
size_t * sizeof_data);
+int
+gnutls_x509_crt_get_extension_data2(gnutls_x509_crt_t cert,
+ unsigned indx, gnutls_datum_t * data);
+
int gnutls_x509_crt_set_extension_by_oid(gnutls_x509_crt_t crt,
const char *oid,
@@ -495,6 +514,13 @@ int gnutls_x509_crt_set_subject_alt_name(gnutls_x509_crt_t crt,
type, const void *data,
unsigned int data_size,
unsigned int flags);
+
+int gnutls_x509_crt_set_issuer_alt_name(gnutls_x509_crt_t crt,
+ gnutls_x509_subject_alt_name_t
+ type, const void *data,
+ unsigned int data_size,
+ unsigned int flags);
+
int gnutls_x509_crt_sign(gnutls_x509_crt_t crt,
gnutls_x509_crt_t issuer,
gnutls_x509_privkey_t issuer_key);
@@ -684,6 +710,9 @@ int gnutls_x509_crl_get_extension_info(gnutls_x509_crl_t crl,
int gnutls_x509_crl_get_extension_data(gnutls_x509_crl_t crl,
int indx, void *data,
size_t * sizeof_data);
+int
+gnutls_x509_crl_get_extension_data2(gnutls_x509_crl_t crl,
+ unsigned indx, gnutls_datum_t * data);
int gnutls_x509_crl_set_authority_key_id(gnutls_x509_crl_t crl,
const void *id, size_t id_size);
@@ -1108,6 +1137,10 @@ int gnutls_x509_crq_get_key_purpose_oid(gnutls_x509_crq_t crq,
int gnutls_x509_crq_get_extension_data(gnutls_x509_crq_t crq,
int indx, void *data,
size_t * sizeof_data);
+int
+gnutls_x509_crq_get_extension_data2(gnutls_x509_crq_t crq,
+ unsigned indx,
+ gnutls_datum_t * data);
int gnutls_x509_crq_get_extension_info(gnutls_x509_crq_t crq,
int indx, void *oid,
size_t * sizeof_oid,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 9f24a6e8ba..192be4221e 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -954,6 +954,60 @@ GNUTLS_3_1_0 {
gnutls_x509_name_constraints_check;
gnutls_x509_name_constraints_check_crt;
gnutls_srp_set_server_fake_salt_seed;
+ gnutls_x509_crt_get_extension_data2;
+ gnutls_x509_crq_get_extension_data2;
+ gnutls_x509_crl_get_extension_data2;
+ gnutls_subject_alt_names_init;
+ gnutls_subject_alt_names_deinit;
+ gnutls_subject_alt_names_get;
+ gnutls_subject_alt_names_set;
+ gnutls_x509_ext_get_subject_alt_names;
+ gnutls_x509_ext_set_subject_alt_names;
+ gnutls_x509_crl_dist_points_init;
+ gnutls_x509_crl_dist_points_deinit;
+ gnutls_x509_crl_dist_points_get;
+ gnutls_x509_crl_dist_points_set;
+ gnutls_x509_ext_get_crl_dist_points;
+ gnutls_x509_ext_set_crl_dist_points;
+ gnutls_x509_ext_get_name_constraints;
+ gnutls_x509_ext_set_name_constraints;
+ gnutls_x509_aia_init;
+ gnutls_x509_aia_deinit;
+ gnutls_x509_aia_get;
+ gnutls_x509_aia_set;
+ gnutls_x509_ext_get_aia;
+ gnutls_x509_ext_set_aia;
+ gnutls_x509_ext_get_subject_key_id;
+ gnutls_x509_ext_set_subject_key_id;
+ gnutls_x509_ext_set_authority_key_id;
+ gnutls_x509_ext_get_authority_key_id;
+ gnutls_x509_aki_init;
+ gnutls_x509_aki_get_id;
+ gnutls_x509_aki_get_cert_issuer;
+ gnutls_x509_aki_set_id;
+ gnutls_x509_aki_set_cert_issuer;
+ gnutls_x509_aki_deinit;
+ gnutls_x509_ext_get_private_key_usage_period;
+ gnutls_x509_ext_set_private_key_usage_period;
+ gnutls_x509_ext_get_basic_constraints;
+ gnutls_x509_ext_set_basic_constraints;
+ gnutls_x509_ext_get_key_usage;
+ gnutls_x509_ext_set_key_usage;
+ gnutls_x509_ext_get_proxy;
+ gnutls_x509_ext_set_proxy;
+ gnutls_x509_policies_init;
+ gnutls_x509_policies_deinit;
+ gnutls_x509_policies_get;
+ gnutls_x509_policies_set;
+ gnutls_x509_ext_get_policies;
+ gnutls_x509_ext_set_policies;
+ gnutls_x509_crt_set_issuer_alt_name;
+ gnutls_x509_key_purpose_init;
+ gnutls_x509_key_purpose_deinit;
+ gnutls_x509_key_purpose_set;
+ gnutls_x509_key_purpose_get;
+ gnutls_x509_ext_get_key_purposes;
+ gnutls_x509_ext_set_key_purposes;
} GNUTLS_3_0_0;
GNUTLS_PRIVATE {
diff --git a/lib/x509/Makefile.am b/lib/x509/Makefile.am
index b2e5a17a48..082804bf7f 100644
--- a/lib/x509/Makefile.am
+++ b/lib/x509/Makefile.am
@@ -59,7 +59,8 @@ libgnutls_x509_la_SOURCES = \
name_constraints.c \
verify-high.c \
verify-high2.c \
- verify-high.h
+ verify-high.h \
+ x509_ext.c
if ENABLE_OCSP
libgnutls_x509_la_SOURCES += ocsp.c ocsp_output.c
diff --git a/lib/x509/common.c b/lib/x509/common.c
index f19467b27e..5f63dcf615 100644
--- a/lib/x509/common.c
+++ b/lib/x509/common.c
@@ -1850,3 +1850,40 @@ _gnutls_x509_get_raw_dn2(ASN1_TYPE c2, gnutls_datum_t * raw,
cleanup:
return result;
}
+
+int _gnutls_copy_string(gnutls_datum_t* str, uint8_t *out, size_t *out_size)
+{
+unsigned size_to_check;
+
+ size_to_check = str->size + 1;
+
+ if ((unsigned) size_to_check > *out_size) {
+ gnutls_assert();
+ (*out_size) = size_to_check;
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ }
+
+ if (out != NULL) {
+ memcpy(out, str->data, str->size);
+ out[str->size] = 0;
+ }
+ *out_size = str->size;
+
+ return 0;
+}
+
+int _gnutls_copy_data(gnutls_datum_t* str, uint8_t *out, size_t *out_size)
+{
+ if ((unsigned) str->size > *out_size) {
+ gnutls_assert();
+ (*out_size) = str->size;
+ return GNUTLS_E_SHORT_MEMORY_BUFFER;
+ }
+
+ if (out != NULL) {
+ memcpy(out, str->data, str->size);
+ }
+ *out_size = str->size;
+
+ return 0;
+}
diff --git a/lib/x509/common.h b/lib/x509/common.h
index 30ff3a5d63..76c5e80704 100644
--- a/lib/x509/common.h
+++ b/lib/x509/common.h
@@ -195,4 +195,7 @@ int _gnutls_strdatum_to_buf(gnutls_datum_t * d, void *buf,
bool _gnutls_is_same_dn(gnutls_x509_crt_t cert1, gnutls_x509_crt_t cert2);
+int _gnutls_copy_string(gnutls_datum_t* str, uint8_t *out, size_t *out_size);
+int _gnutls_copy_data(gnutls_datum_t* str, uint8_t *out, size_t *out_size);
+
#endif
diff --git a/lib/x509/crq.c b/lib/x509/crq.c
index a40a561295..c3cba0c7cc 100644
--- a/lib/x509/crq.c
+++ b/lib/x509/crq.c
@@ -33,6 +33,7 @@
#include <common.h>
#include <gnutls_x509.h>
#include <x509_b64.h>
+#include <gnutls/x509-ext.h>
#include "x509_int.h"
#include <libtasn1.h>
@@ -1482,11 +1483,49 @@ int
gnutls_x509_crq_get_extension_data(gnutls_x509_crq_t crq, int indx,
void *data, size_t * sizeof_data)
{
- int result, len;
+ int ret;
+ gnutls_datum_t raw;
+
+ ret = gnutls_x509_crq_get_extension_data2(crq, indx, &raw);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = _gnutls_copy_data(&raw, data, sizeof_data);
+ if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER && data == NULL)
+ ret = 0;
+ gnutls_free(raw.data);
+ return ret;
+}
+
+/**
+ * gnutls_x509_crq_get_extension_data2:
+ * @cert: should contain a #gnutls_x509_crq_t structure
+ * @extension_id: An X.509 extension OID.
+ * @indx: Specifies which extension OID to read. Use (0) to get the first one.
+ * @data: will contain the extension DER-encoded data
+ *
+ * This function will return the requested extension data in the
+ * certificate request. The extension data will be allocated using
+ * gnutls_malloc().
+ *
+ * Use gnutls_x509_crq_get_extension_info() to extract the OID.
+ *
+ * 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.
+ *
+ * Since: 3.3.0
+ **/
+int
+gnutls_x509_crq_get_extension_data2(gnutls_x509_crq_t crq,
+ unsigned indx, gnutls_datum_t * data)
+{
+ int ret, result;
char name[ASN1_MAX_NAME_SIZE];
- unsigned char *extensions;
+ unsigned char *extensions = NULL;
size_t extensions_size = 0;
- ASN1_TYPE c2;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
if (!crq) {
gnutls_assert();
@@ -1494,16 +1533,16 @@ gnutls_x509_crq_get_extension_data(gnutls_x509_crq_t crq, int indx,
}
/* read extensionRequest */
- result =
+ ret =
gnutls_x509_crq_get_attribute_by_oid(crq,
"1.2.840.113549.1.9.14",
0, NULL,
&extensions_size);
- if (result != GNUTLS_E_SHORT_MEMORY_BUFFER) {
+ if (ret != GNUTLS_E_SHORT_MEMORY_BUFFER) {
gnutls_assert();
- if (result == 0)
+ if (ret == 0)
return GNUTLS_E_INTERNAL_ERROR;
- return result;
+ return ret;
}
extensions = gnutls_malloc(extensions_size);
@@ -1512,14 +1551,14 @@ gnutls_x509_crq_get_extension_data(gnutls_x509_crq_t crq, int indx,
return GNUTLS_E_MEMORY_ERROR;
}
- result =
+ ret =
gnutls_x509_crq_get_attribute_by_oid(crq,
"1.2.840.113549.1.9.14",
0, extensions,
&extensions_size);
- if (result < 0) {
+ if (ret < 0) {
gnutls_assert();
- return result;
+ goto cleanup;
}
result =
@@ -1527,34 +1566,33 @@ gnutls_x509_crq_get_extension_data(gnutls_x509_crq_t crq, int indx,
&c2);
if (result != ASN1_SUCCESS) {
gnutls_assert();
- gnutls_free(extensions);
- return _gnutls_asn2err(result);
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
}
- result = asn1_der_decoding(&c2, extensions, extensions_size, NULL);
- gnutls_free(extensions);
- if (result != ASN1_SUCCESS) {
+ ret = asn1_der_decoding(&c2, extensions, extensions_size, NULL);
+ if (ret != ASN1_SUCCESS) {
gnutls_assert();
- asn1_delete_structure(&c2);
- return _gnutls_asn2err(result);
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
}
snprintf(name, sizeof(name), "?%u.extnValue", indx + 1);
- len = *sizeof_data;
- result = asn1_read_value(c2, name, data, &len);
- *sizeof_data = len;
-
- asn1_delete_structure(&c2);
-
- if (result == ASN1_ELEMENT_NOT_FOUND)
- return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
- else if (result < 0) {
+ ret = _gnutls_x509_read_value(c2, name, data);
+ if (ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) {
+ ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ goto cleanup;
+ } else if (ret < 0) {
gnutls_assert();
- return _gnutls_asn2err(result);
+ goto cleanup;
}
- return 0;
+ ret = 0;
+ cleanup:
+ asn1_delete_structure(&c2);
+ gnutls_free(extensions);
+ return ret;
}
/**
@@ -1584,9 +1622,9 @@ gnutls_x509_crq_get_key_usage(gnutls_x509_crq_t crq,
unsigned int *critical)
{
int result;
- uint16_t _usage;
uint8_t buf[128];
size_t buf_size = sizeof(buf);
+ gnutls_datum_t bd;
if (crq == NULL) {
gnutls_assert();
@@ -1601,10 +1639,9 @@ gnutls_x509_crq_get_key_usage(gnutls_x509_crq_t crq,
return result;
}
- result = _gnutls_x509_ext_extract_keyUsage(&_usage, buf, buf_size);
-
- *key_usage = _usage;
-
+ bd.data = buf;
+ bd.size = buf_size;
+ result = gnutls_x509_ext_get_key_usage(&bd, key_usage);
if (result < 0) {
gnutls_assert();
return result;
@@ -1644,6 +1681,7 @@ gnutls_x509_crq_get_basic_constraints(gnutls_x509_crq_t crq,
unsigned int tmp_ca;
uint8_t buf[256];
size_t buf_size = sizeof(buf);
+ gnutls_datum_t bd;
if (crq == NULL) {
gnutls_assert();
@@ -1658,10 +1696,9 @@ gnutls_x509_crq_get_basic_constraints(gnutls_x509_crq_t crq,
return result;
}
- result =
- _gnutls_x509_ext_extract_basicConstraints(&tmp_ca,
- pathlen, buf,
- buf_size);
+ bd.data = buf;
+ bd.size = buf_size;
+ result = gnutls_x509_ext_get_basic_constraints(&bd, &tmp_ca, pathlen);
if (ca)
*ca = tmp_ca;
@@ -2032,9 +2069,7 @@ gnutls_x509_crq_set_basic_constraints(gnutls_x509_crq_t crq,
/* generate the extension.
*/
- result =
- _gnutls_x509_ext_gen_basicConstraints(ca, pathLenConstraint,
- &der_data);
+ result = gnutls_x509_ext_set_basic_constraints(ca, pathLenConstraint, &der_data);
if (result < 0) {
gnutls_assert();
return result;
@@ -2079,7 +2114,7 @@ gnutls_x509_crq_set_key_usage(gnutls_x509_crq_t crq, unsigned int usage)
/* generate the extension.
*/
result =
- _gnutls_x509_ext_gen_keyUsage((uint16_t) usage, &der_data);
+ gnutls_x509_ext_set_key_usage(usage, &der_data);
if (result < 0) {
gnutls_assert();
return result;
diff --git a/lib/x509/extensions.c b/lib/x509/extensions.c
index bc16e4d381..f9a521e0d4 100644
--- a/lib/x509/extensions.c
+++ b/lib/x509/extensions.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2003-2014 Free Software Foundation, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
@@ -28,6 +28,8 @@
#include <gnutls_global.h>
#include <libtasn1.h>
#include <common.h>
+#include <gnutls/x509-ext.h>
+#include <gnutls/x509.h>
#include <x509_int.h>
#include <gnutls_datum.h>
@@ -129,35 +131,95 @@ get_extension(ASN1_TYPE asn, const char *root,
}
}
-/* 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.
- */
+static int
+get_indx_extension(ASN1_TYPE asn, const char *root,
+ int indx, gnutls_datum_t * out)
+{
+ char name[ASN1_MAX_NAME_SIZE];
+ int ret;
+
+ out->data = NULL;
+ out->size = 0;
+
+ snprintf(name, sizeof(name), "%s.?%u.extnValue", root, indx+1);
+
+ ret = _gnutls_x509_read_value(asn, name, out);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ return 0;
+}
+
int
_gnutls_x509_crt_get_extension(gnutls_x509_crt_t cert,
const char *extension_id, int indx,
- gnutls_datum_t * ret,
- unsigned int *_critical)
+ gnutls_datum_t * data, unsigned int *critical)
{
return get_extension(cert->cert, "tbsCertificate.extensions",
- extension_id, indx, ret, _critical);
+ extension_id, indx, data, critical);
+}
+
+/**
+ * gnutls_x509_crt_get_extension_data2:
+ * @cert: should contain a #gnutls_x509_crt_t structure
+ * @indx: Specifies which extension OID to read. Use (0) to get the first one.
+ * @data: will contain the extension DER-encoded data
+ *
+ * This function will return the requested by the index extension data in the
+ * certificate. The extension data will be allocated using
+ * gnutls_malloc().
+ *
+ * Use gnutls_x509_crt_get_extension_info() to extract the OID.
+ *
+ * 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_data2(gnutls_x509_crt_t cert,
+ unsigned indx,
+ gnutls_datum_t * data)
+{
+ return get_indx_extension(cert->cert, "tbsCertificate.extensions",
+ indx, data);
}
int
_gnutls_x509_crl_get_extension(gnutls_x509_crl_t crl,
const char *extension_id, int indx,
- gnutls_datum_t * ret,
- unsigned int *_critical)
+ gnutls_datum_t * data,
+ unsigned int *critical)
{
return get_extension(crl->crl, "tbsCertList.crlExtensions",
- extension_id, indx, ret, _critical);
+ extension_id, indx, data, critical);
}
+/**
+ * gnutls_x509_crl_get_extension_data2:
+ * @crl: should contain a #gnutls_x509_crl_t structure
+ * @indx: Specifies which extension OID to read. Use (0) to get the first one.
+ * @data: will contain the extension DER-encoded data
+ *
+ * This function will return the requested by the index extension data in the
+ * certificate revocation list. The extension data will be allocated using
+ * gnutls_malloc().
+ *
+ * Use gnutls_x509_crt_get_extension_info() to extract the OID.
+ *
+ * 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_crl_get_extension_data2(gnutls_x509_crl_t crl,
+ unsigned indx,
+ gnutls_datum_t * data)
+{
+ return get_indx_extension(crl->crl, "tbsCertList.crlExtensions",
+ indx, data);
+}
/* This function will attempt to return the requested extension OID found in
* the given X509v3 certificate.
@@ -165,14 +227,13 @@ _gnutls_x509_crl_get_extension(gnutls_x509_crl_t crl,
* If you have passed the last extension, GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will
* be returned.
*/
-static int
-get_extension_oid(ASN1_TYPE asn, const char *root,
- int indx, void *oid, size_t * sizeof_oid)
+static int get_extension_oid(ASN1_TYPE asn, const char *root,
+ unsigned indx, void *oid, size_t * sizeof_oid)
{
int k, result, len;
char name[ASN1_MAX_NAME_SIZE], name2[ASN1_MAX_NAME_SIZE];
char extnID[MAX_OID_SIZE];
- int indx_counter = 0;
+ unsigned indx_counter = 0;
k = 0;
do {
@@ -358,7 +419,7 @@ set_extension(ASN1_TYPE asn, const char *root,
const char *ext_id,
const gnutls_datum_t * ext_data, unsigned int critical)
{
- int result;
+ int result = 0;
int k, len;
char name[ASN1_MAX_NAME_SIZE], name2[ASN1_MAX_NAME_SIZE];
char extnID[MAX_OID_SIZE];
@@ -544,164 +605,6 @@ _gnutls_x509_crq_set_extension(gnutls_x509_crq_t crq,
return 0;
}
-/* Here we only extract the KeyUsage field, from the DER encoded
- * extension.
- */
-int
-_gnutls_x509_ext_extract_keyUsage(uint16_t * keyUsage,
- uint8_t * 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 _gnutls_asn2err(result);
- }
-
- result = asn1_der_decoding(&ext, extnValue, extnValueLen, NULL);
-
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- asn1_delete_structure(&ext);
- return _gnutls_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(unsigned int *CA,
- int *pathLenConstraint,
- uint8_t * 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 _gnutls_asn2err(result);
- }
-
- result = asn1_der_decoding(&ext, extnValue, extnValueLen, NULL);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- asn1_delete_structure(&ext);
- return _gnutls_asn2err(result);
- }
-
- if (pathLenConstraint) {
- result = _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) {
- gnutls_assert();
- asn1_delete_structure(&ext);
- return _gnutls_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 error codes 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 _gnutls_asn2err(result);
- }
-
- result = asn1_write_value(ext, "cA", str, 1);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- asn1_delete_structure(&ext);
- return _gnutls_asn2err(result);
- }
-
- if (pathLenConstraint < 0) {
- result =
- asn1_write_value(ext, "pathLenConstraint", NULL, 0);
- if (result < 0)
- result = _gnutls_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;
-}
-
/* extract an INTEGER from the DER encoded extension
*/
int
@@ -781,45 +684,6 @@ _gnutls_x509_ext_gen_number(const uint8_t * number, size_t nr_size,
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 _gnutls_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 _gnutls_asn2err(result);
- }
-
- result = _gnutls_x509_der_encode(ext, "", der_ext, 0);
-
- asn1_delete_structure(&ext);
-
- if (result < 0) {
- gnutls_assert();
- return result;
- }
-
- return 0;
-}
-
int
_gnutls_write_general_name(ASN1_TYPE ext, const char *ext_name,
gnutls_x509_subject_alt_name_t type,
@@ -872,8 +736,8 @@ _gnutls_write_general_name(ASN1_TYPE ext, const char *ext_name,
return 0;
}
-static int
-write_new_general_name(ASN1_TYPE ext, const char *ext_name,
+int
+_gnutls_write_new_general_name(ASN1_TYPE ext, const char *ext_name,
gnutls_x509_subject_alt_name_t type,
const void *data, unsigned int data_size)
{
@@ -910,86 +774,49 @@ int
_gnutls_x509_ext_gen_subject_alt_name(gnutls_x509_subject_alt_name_t
type, const void *data,
unsigned int data_size,
- gnutls_datum_t * prev_der_ext,
+ const gnutls_datum_t * prev_der_ext,
gnutls_datum_t * der_ext)
{
- ASN1_TYPE ext = ASN1_TYPE_EMPTY;
- int result;
+ int ret;
+ gnutls_subject_alt_names_t sans = NULL;
+ gnutls_datum_t name;
- result =
- asn1_create_element(_gnutls_get_pkix(), "PKIX1.GeneralNames",
- &ext);
- if (result != ASN1_SUCCESS) {
+ ret = gnutls_subject_alt_names_init(&sans);
+ if (ret < 0) {
gnutls_assert();
- return _gnutls_asn2err(result);
+ return ret;
}
- if (prev_der_ext != NULL && prev_der_ext->data != NULL
- && prev_der_ext->size != 0) {
- result =
- asn1_der_decoding(&ext, prev_der_ext->data,
- prev_der_ext->size, NULL);
+ if (prev_der_ext && prev_der_ext->data != NULL &&
+ prev_der_ext->size != 0) {
- if (result != ASN1_SUCCESS) {
+ ret = gnutls_x509_ext_get_subject_alt_names(prev_der_ext, sans, 0);
+ if (ret < 0) {
gnutls_assert();
- asn1_delete_structure(&ext);
- return _gnutls_asn2err(result);
+ goto cleanup;
}
}
- result = write_new_general_name(ext, "", type, data, data_size);
- 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) {
+ name.data = (void*)data;
+ name.size = data_size;
+ ret = gnutls_subject_alt_names_set(sans, type, &name, NULL);
+ if (ret < 0) {
gnutls_assert();
- return _gnutls_asn2err(result);
+ goto cleanup;
}
- result = asn1_write_value(ext, "", id, id_size);
- if (result != ASN1_SUCCESS) {
+ ret = gnutls_x509_ext_set_subject_alt_names(sans, der_ext);
+ if (ret < 0) {
gnutls_assert();
- asn1_delete_structure(&ext);
- return _gnutls_asn2err(result);
+ goto cleanup;
}
- result = _gnutls_x509_der_encode(ext, "", der_ext, 0);
-
- asn1_delete_structure(&ext);
-
- if (result < 0) {
- gnutls_assert();
- return result;
- }
+ ret = 0;
+cleanup:
+ if (sans != NULL)
+ gnutls_subject_alt_names_deinit(sans);
- return 0;
+ return ret;
}
/* generate the AuthorityKeyID in a DER encoded extension
@@ -998,273 +825,31 @@ 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 _gnutls_asn2err(result);
- }
-
- result = asn1_write_value(ext, "keyIdentifier", id, id_size);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- asn1_delete_structure(&ext);
- return _gnutls_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,
- unsigned int data_size,
- 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];
+ gnutls_x509_aki_t aki;
+ int ret;
+ gnutls_datum_t l_id;
- 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 = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- result = asn1_write_value(ext, "", "NEW", 1);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- if (reason_flags) {
- result =
- asn1_write_value(ext, "?LAST.reasons", reasons, 9);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto cleanup;
- }
- } else {
- result = asn1_write_value(ext, "?LAST.reasons", NULL, 0);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto cleanup;
- }
- }
-
- result = asn1_write_value(ext, "?LAST.cRLIssuer", NULL, 0);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_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 = _gnutls_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
+ ret = gnutls_x509_aki_init(&aki);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
- result =
- write_new_general_name(ext, "?LAST.distributionPoint.fullName",
- type, data, data_size);
- if (result < 0) {
+ l_id.data = (void*)id;
+ l_id.size = id_size;
+ ret = gnutls_x509_aki_set_id(aki, &l_id);
+ if (ret < 0) {
gnutls_assert();
goto cleanup;
}
- result = _gnutls_x509_der_encode(ext, "", der_ext, 0);
-
- if (result < 0) {
+ ret = gnutls_x509_ext_set_authority_key_id(aki, der_ext);
+ if (ret < 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,
- uint8_t * 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 _gnutls_asn2err(result);
- }
-
- result = asn1_der_decoding(&ext, extnValue, extnValueLen, NULL);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- asn1_delete_structure(&ext);
- return _gnutls_asn2err(result);
- }
-
- if (pathLenConstraint) {
- result = _gnutls_x509_read_uint(ext, "pCPathLenConstraint",
- (unsigned int *)
- pathLenConstraint);
- if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
- *pathLenConstraint = -1;
- else if (result != GNUTLS_E_SUCCESS) {
- asn1_delete_structure(&ext);
- return _gnutls_asn2err(result);
- }
- }
-
- result = _gnutls_x509_read_value(ext, "proxyPolicy.policyLanguage",
- &value);
- if (result < 0) {
- gnutls_assert();
- asn1_delete_structure(&ext);
- return result;
- }
-
- if (policyLanguage)
- *policyLanguage = gnutls_strdup((char *) value.data);
-
- result =
- _gnutls_x509_read_value(ext, "proxyPolicy.policy", &value);
- 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 = (char *) value.data;
- if (sizeof_policy)
- *sizeof_policy = value.size;
- }
-
- asn1_delete_structure(&ext);
+ ret = 0;
- 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 _gnutls_asn2err(result);
- }
-
- if (pathLenConstraint < 0) {
- result =
- asn1_write_value(ext, "pCPathLenConstraint", NULL, 0);
- if (result != ASN1_SUCCESS)
- result = _gnutls_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 != ASN1_SUCCESS) {
- gnutls_assert();
- asn1_delete_structure(&ext);
- return _gnutls_asn2err(result);
- }
-
- result = asn1_write_value(ext, "proxyPolicy.policy",
- policy, sizeof_policy);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- asn1_delete_structure(&ext);
- return _gnutls_asn2err(result);
- }
-
- result = _gnutls_x509_der_encode(ext, "", der_ext, 0);
-
- asn1_delete_structure(&ext);
-
- if (result < 0) {
- gnutls_assert();
- return result;
- }
-
- return 0;
+ cleanup:
+ gnutls_x509_aki_deinit(aki);
+ return ret;
}
diff --git a/lib/x509/name_constraints.c b/lib/x509/name_constraints.c
index cf96d94535..1f006361b3 100644
--- a/lib/x509/name_constraints.c
+++ b/lib/x509/name_constraints.c
@@ -27,22 +27,13 @@
#include <gnutls_errors.h>
#include <common.h>
#include <gnutls_x509.h>
+#include <gnutls/x509-ext.h>
#include <x509_b64.h>
#include <x509_int.h>
#include <libtasn1.h>
/* Name constraints is limited to DNS names.
*/
-typedef struct gnutls_name_constraints_st {
- struct name_constraints_node_st * permitted;
- struct name_constraints_node_st * excluded;
-} gnutls_name_constraints_st;
-
-typedef struct name_constraints_node_st {
- unsigned type;
- gnutls_datum_t name;
- struct name_constraints_node_st *next;
-} name_constraints_node_st;
static unsigned is_nc_empty(struct gnutls_name_constraints_st* nc)
{
@@ -51,7 +42,7 @@ static unsigned is_nc_empty(struct gnutls_name_constraints_st* nc)
return 0;
}
-static int extract_name_constraints(ASN1_TYPE c2, const char *vstr,
+int _gnutls_extract_name_constraints(ASN1_TYPE c2, const char *vstr,
name_constraints_node_st ** _nc)
{
int ret;
@@ -149,9 +140,8 @@ int gnutls_x509_crt_get_name_constraints(gnutls_x509_crt_t crt,
unsigned int flags,
unsigned int *critical)
{
- int result, ret;
+ int ret;
gnutls_datum_t der = { NULL, 0 };
- ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
if (crt == NULL) {
gnutls_assert();
@@ -167,30 +157,7 @@ int gnutls_x509_crt_get_name_constraints(gnutls_x509_crt_t crt,
if (der.size == 0 || der.data == NULL)
return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
- result = asn1_create_element
- (_gnutls_get_pkix(), "PKIX1.NameConstraints", &c2);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- result = asn1_der_decoding(&c2, der.data, der.size, NULL);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- if (!(flags & GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND) || (nc->permitted == NULL && nc->excluded == NULL)) {
- ret = extract_name_constraints(c2, "permittedSubtrees", &nc->permitted);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
- }
-
- ret = extract_name_constraints(c2, "excludedSubtrees", &nc->excluded);
+ ret = gnutls_x509_ext_get_name_constraints(&der, nc, flags);
if (ret < 0) {
gnutls_assert();
goto cleanup;
@@ -200,7 +167,6 @@ int gnutls_x509_crt_get_name_constraints(gnutls_x509_crt_t crt,
cleanup:
_gnutls_free_datum(&der);
- asn1_delete_structure(&c2);
return ret;
@@ -368,106 +334,15 @@ int gnutls_x509_crt_set_name_constraints(gnutls_x509_crt_t crt,
gnutls_x509_name_constraints_t nc,
unsigned int critical)
{
-int ret, result;
-gnutls_datum_t der_data;
-uint8_t null = 0;
-ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
-struct name_constraints_node_st * tmp;
-
- if (nc->permitted == NULL && nc->excluded == NULL)
- return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
-
- result = asn1_create_element
- (_gnutls_get_pkix(), "PKIX1.NameConstraints", &c2);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- return _gnutls_asn2err(result);
- }
-
- if (nc->permitted == NULL) {
- asn1_write_value(c2, "permittedSubtrees", NULL, 0);
- } else {
- tmp = nc->permitted;
- do {
- result = asn1_write_value(c2, "permittedSubtrees", "NEW", 1);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- result = asn1_write_value(c2, "permittedSubtrees.?LAST.maximum", NULL, 0);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- result = asn1_write_value(c2, "permittedSubtrees.?LAST.minimum", &null, 1);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- ret = _gnutls_write_general_name(c2, "permittedSubtrees.?LAST.base",
- tmp->type, tmp->name.data, tmp->name.size);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
- tmp = tmp->next;
- } while(tmp != NULL);
- }
-
- if (nc->excluded == NULL) {
- asn1_write_value(c2, "excludedSubtrees", NULL, 0);
- } else {
- tmp = nc->excluded;
- do {
- result = asn1_write_value(c2, "excludedSubtrees", "NEW", 1);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- result = asn1_write_value(c2, "excludedSubtrees.?LAST.maximum", NULL, 0);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- result = asn1_write_value(c2, "excludedSubtrees.?LAST.minimum", &null, 1);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- ret = _gnutls_write_general_name(c2, "excludedSubtrees.?LAST.base",
- tmp->type, tmp->name.data, tmp->name.size);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
- tmp = tmp->next;
- } while(tmp != NULL);
-
- }
+int ret;
+gnutls_datum_t der;
- ret = _gnutls_x509_der_encode(c2, "", &der_data, 0);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
+ ret = gnutls_x509_ext_set_name_constraints(nc, &der);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
ret =
- _gnutls_x509_crt_set_extension(crt, "2.5.29.30", &der_data, critical);
-
- _gnutls_free_datum(&der_data);
-
+ _gnutls_x509_crt_set_extension(crt, "2.5.29.30", &der, critical);
if (ret < 0) {
gnutls_assert();
goto cleanup;
@@ -477,9 +352,8 @@ struct name_constraints_node_st * tmp;
crt->use_extensions = 1;
cleanup:
- asn1_delete_structure(&c2);
+ _gnutls_free_datum(&der);
return ret;
-
}
static
diff --git a/lib/x509/output.c b/lib/x509/output.c
index 0c5d0fcaa6..46bd03e489 100644
--- a/lib/x509/output.c
+++ b/lib/x509/output.c
@@ -76,50 +76,48 @@ static char *ip_to_string(void *_ip, int ip_size, char *string,
}
static void
-add_altname(gnutls_buffer_st * str, const char *prefix,
- unsigned int alt_type, char *name, size_t name_size)
+print_name(gnutls_buffer_st *str, const char *prefix, unsigned type, gnutls_datum_t *name)
{
- char str_ip[64];
- char *p;
-
- if ((alt_type == GNUTLS_SAN_DNSNAME
- || alt_type == GNUTLS_SAN_RFC822NAME
- || alt_type == GNUTLS_SAN_URI) && strlen(name) != name_size) {
- adds(str, _("warning: altname contains an embedded NUL, "
- "replacing with '!'\n"));
- while (strlen(name) < name_size)
- name[strlen(name)] = '!';
+char *sname = (char*)name->data;
+char str_ip[64];
+char *p;
+
+ if ((type == GNUTLS_SAN_DNSNAME
+ || type == GNUTLS_SAN_RFC822NAME
+ || type == GNUTLS_SAN_URI) && sname != NULL && strlen(sname) != name->size) {
+ adds(str,
+ _("warning: generalName contains an embedded NUL, "
+ "replacing with '!'\n"));
+ while (strlen(sname) < name->size)
+ name->data[strlen(sname)] = '!';
}
- switch (alt_type) {
+ switch (type) {
case GNUTLS_SAN_DNSNAME:
- addf(str, "%s\t\t\tDNSname: %.*s\n", prefix,
- (int) name_size, name);
+ addf(str, _("%sDNSname: %.*s\n"), prefix, name->size, NON_NULL(name->data));
break;
case GNUTLS_SAN_RFC822NAME:
- addf(str, "%s\t\t\tRFC822name: %.*s\n", prefix,
- (int) name_size, name);
+ addf(str, _("%sRFC822Name: %.*s\n"), prefix, name->size, NON_NULL(name->data));
break;
case GNUTLS_SAN_URI:
- addf(str, "%s\t\t\tURI: %.*s\n", prefix, (int) name_size,
- name);
+ addf(str, _("%sURI: %.*s\n"), prefix, name->size, NON_NULL(name->data));
break;
case GNUTLS_SAN_IPADDRESS:
- p = ip_to_string(name, name_size, str_ip, sizeof(str_ip));
+ p = ip_to_string(name->data, name->size, str_ip, sizeof(str_ip));
if (p == NULL)
p = ERROR_STR;
- addf(str, "%s\t\t\tIPAddress: %s\n", prefix, p);
+ addf(str, "%sIPAddress: %s\n", prefix, p);
break;
case GNUTLS_SAN_DN:
- addf(str, "%s\t\t\tdirectoryName: %.*s\n", prefix,
- (int) name_size, name);
+ addf(str, _("%sdirectoryName: %.*s\n"), prefix, name->size, NON_NULL(name->data));
break;
default:
- addf(str, "error: unknown altname\n");
+ addf(str, _("%sUnknown name: "), prefix);
+ _gnutls_buffer_hexprint(str, name->data, name->size);
break;
}
}
@@ -159,6 +157,7 @@ static void print_proxy(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
}
}
+
static void print_nc(gnutls_buffer_st * str, const char* prefix, gnutls_x509_crt_t cert)
{
gnutls_x509_name_constraints_t nc;
@@ -166,6 +165,7 @@ static void print_nc(gnutls_buffer_st * str, const char* prefix, gnutls_x509_crt
unsigned critical, idx = 0;
gnutls_datum_t name;
unsigned type;
+ char new_prefix[16];
ret = gnutls_x509_name_constraints_init(&nc);
if (ret < 0)
@@ -175,6 +175,8 @@ static void print_nc(gnutls_buffer_st * str, const char* prefix, gnutls_x509_crt
if (ret < 0)
goto cleanup;
+ snprintf(new_prefix, sizeof(new_prefix), "%s\t\t\t\t", prefix);
+
do {
ret = gnutls_x509_name_constraints_get_permitted(nc, idx++, &type, &name);
@@ -182,17 +184,7 @@ static void print_nc(gnutls_buffer_st * str, const char* prefix, gnutls_x509_crt
if (idx == 1)
addf(str, _("%s\t\t\tPermitted:\n"), prefix);
- if (type == GNUTLS_SAN_DNSNAME) {
- addf(str, _("%s\t\t\t\tDNSname:%s\n"), prefix, NON_NULL(name.data));
- } else if (type == GNUTLS_SAN_RFC822NAME) {
- addf(str, _("%s\t\t\t\tRFC822Name:%s\n"), prefix, NON_NULL(name.data));
- } else if (type == GNUTLS_SAN_URI) {
- addf(str, _("%s\t\t\t\tURI:%s\n"), prefix, NON_NULL(name.data));
- } else if (type == GNUTLS_SAN_DN) {
- addf(str, _("%s\t\t\t\tdirectoryName:"), prefix);
- _gnutls_buffer_hexprint(str, name.data, name.size);
- adds(str, _(" \n"));
- }
+ print_name(str, new_prefix, type, &name);
}
} while (ret == 0);
@@ -204,17 +196,7 @@ static void print_nc(gnutls_buffer_st * str, const char* prefix, gnutls_x509_crt
if (idx == 1)
addf(str, _("%s\t\t\tExcluded:\n"), prefix);
- if (type == GNUTLS_SAN_DNSNAME) {
- addf(str, _("%s\t\t\t\tDNSname:%s\n"), prefix, NON_NULL(name.data));
- } else if (type == GNUTLS_SAN_RFC822NAME) {
- addf(str, _("%s\t\t\t\tRFC822Name:%s\n"), prefix, NON_NULL(name.data));
- } else if (type == GNUTLS_SAN_URI) {
- addf(str, _("%s\t\t\t\tURI:%s\n"), prefix, NON_NULL(name.data));
- } else if (type == GNUTLS_SAN_DN) {
- addf(str, _("%s\t\t\t\tdirectoryName:"), prefix);
- _gnutls_buffer_hexprint(str, name.data, name.size);
- adds(str, _(" \n"));
- }
+ print_name(str, new_prefix, type, &name);
}
} while (ret == 0);
@@ -222,77 +204,50 @@ cleanup:
gnutls_x509_name_constraints_deinit(nc);
}
-static void print_aia(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
+static void print_aia(gnutls_buffer_st * str, const gnutls_datum_t *der)
{
int err;
- int seq = 0;
- gnutls_datum_t data = { NULL, 0 };
+ int seq;
+ gnutls_datum_t san = { NULL, 0 }, oid = {NULL, 0};
+ gnutls_x509_aia_t aia;
+ unsigned int san_type;
+
+ err = gnutls_x509_aia_init(&aia);
+ if (err < 0)
+ return;
+
+ err = gnutls_x509_ext_get_aia(der, aia, 0);
+ if (err < 0) {
+ addf(str, "error: get_aia: %s\n",
+ gnutls_strerror(err));
+ return;
+ }
- for (;;) {
- err = gnutls_x509_crt_get_authority_info_access
- (cert, seq, GNUTLS_IA_ACCESSMETHOD_OID, &data, NULL);
+ for (seq=0;;seq++) {
+ err = gnutls_x509_aia_get(aia, seq, &oid, &san_type, &san);
if (err == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
- return;
- if (err < 0) {
- addf(str, "error: get_aia: %s\n",
- gnutls_strerror(err));
goto cleanup;
- }
-
- addf(str, _("\t\t\tAccess Method: %.*s"), data.size,
- data.data);
- if (data.size == sizeof(GNUTLS_OID_AD_OCSP)
- && memcmp(data.data, GNUTLS_OID_AD_OCSP,
- data.size) == 0)
- adds(str, " (id-ad-ocsp)\n");
- else if (data.size == sizeof(GNUTLS_OID_AD_CAISSUERS) &&
- memcmp(data.data, GNUTLS_OID_AD_CAISSUERS,
- data.size) == 0)
- adds(str, " (id-ad-caIssuers)\n");
- else
- adds(str, " (UNKNOWN)\n");
-
- gnutls_free(data.data);
- data.data = NULL;
-
- err = gnutls_x509_crt_get_authority_info_access
- (cert, seq, GNUTLS_IA_ACCESSLOCATION_GENERALNAME_TYPE,
- &data, NULL);
if (err < 0) {
- addf(str, "error: get_aia type: %s\n",
+ addf(str, "error: aia_get: %s\n",
gnutls_strerror(err));
goto cleanup;
}
- if (data.size == sizeof("uniformResourceIdentifier") &&
- memcmp(data.data, "uniformResourceIdentifier",
- data.size) == 0) {
-
- gnutls_free(data.data);
- data.data = NULL;
-
- adds(str, "\t\t\tAccess Location URI: ");
- err = gnutls_x509_crt_get_authority_info_access
- (cert, seq, GNUTLS_IA_URI, &data, NULL);
- if (err < 0) {
- addf(str, "error: get_aia uri: %s\n",
- gnutls_strerror(err));
- goto cleanup;
- }
- addf(str, "%.*s\n", data.size, data.data);
- } else
- adds(str,
- "\t\t\tUnsupported accessLocation type\n");
-
- gnutls_free(data.data);
- data.data = NULL;
+ if (strcmp((char*)oid.data, GNUTLS_OID_AD_OCSP) == 0)
+ addf(str, _("\t\t\tAccess Method: %s (%s)\n"), GNUTLS_OID_AD_OCSP, "id-ad-ocsp");
+ else if (strcmp((char*)oid.data, GNUTLS_OID_AD_CAISSUERS) == 0)
+ addf(str, _("\t\t\tAccess Method: %s (%s)\n"), GNUTLS_OID_AD_CAISSUERS, "id-ad-caIssuers");
+ else {
+ addf(str, _("\t\t\tAccess Method: %s (%s)\n"), (char*)oid.data, "UNKNOWN");
+ }
- seq++;
+ adds(str, "\t\t\tAccess Location ");
+ print_name(str, "", san_type, &san);
}
return;
cleanup:
- gnutls_free(data.data);
+ gnutls_x509_aia_deinit(aia);
}
static void print_ski(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
@@ -355,6 +310,7 @@ print_aki_gn_serial(gnutls_buffer_st * str, int type, cert_type_t cert)
char serial[128];
size_t size = 0, serial_size = sizeof(serial);
unsigned int alt_type;
+ gnutls_datum_t t;
int err;
if (type == TYPE_CRT)
@@ -419,7 +375,10 @@ print_aki_gn_serial(gnutls_buffer_st * str, int type, cert_type_t cert)
return;
}
- add_altname(str, "", alt_type, buffer, size);
+ t.data = (void*)buffer;
+ t.size = size;
+ print_name(str, "\t\t\t", alt_type, &t);
+
adds(str, "\t\t\tserial: ");
_gnutls_buffer_hexprint(str, serial, serial_size);
adds(str, "\n");
@@ -591,8 +550,7 @@ static void print_crldist(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
{
char *buffer = NULL;
size_t size;
- char str_ip[64];
- char *p;
+ gnutls_datum_t t;
int err;
int indx;
@@ -626,49 +584,10 @@ static void print_crldist(gnutls_buffer_st * str, gnutls_x509_crt_t cert)
return;
}
- if ((err == GNUTLS_SAN_DNSNAME
- || err == GNUTLS_SAN_RFC822NAME
- || err == GNUTLS_SAN_URI) && strlen(buffer) != size) {
- adds(str,
- _
- ("warning: distributionPoint contains an embedded NUL, "
- "replacing with '!'\n"));
- while (strlen(buffer) < size)
- buffer[strlen(buffer)] = '!';
- }
-
- switch (err) {
- case GNUTLS_SAN_DNSNAME:
- addf(str, "\t\t\tDNSname: %.*s\n", (int) size,
- buffer);
- break;
-
- case GNUTLS_SAN_RFC822NAME:
- addf(str, "\t\t\tRFC822name: %.*s\n", (int) size,
- buffer);
- break;
-
- case GNUTLS_SAN_URI:
- addf(str, "\t\t\tURI: %.*s\n", (int) size, buffer);
- break;
-
- case GNUTLS_SAN_IPADDRESS:
- p = ip_to_string(buffer, size, str_ip,
- sizeof(str_ip));
- if (p == NULL)
- p = ERROR_STR;
- addf(str, "\t\t\tIPAddress: %s\n", p);
- break;
-
- case GNUTLS_SAN_DN:
- addf(str, "\t\t\tdirectoryName: %.*s\n",
- (int) size, buffer);
- break;
+ t.data = (void*)buffer;
+ t.size = size;
+ print_name(str, "\t\t\t", err, &t);
- default:
- addf(str, "error: unknown SAN\n");
- break;
- }
gnutls_free(buffer);
}
}
@@ -804,6 +723,7 @@ print_altname(gnutls_buffer_st * str, const char *prefix,
unsigned int altname_type, cert_type_t cert)
{
unsigned int altname_idx;
+ gnutls_datum_t t;
for (altname_idx = 0;; altname_idx++) {
char *buffer = NULL;
@@ -968,8 +888,14 @@ print_altname(gnutls_buffer_st * str, const char *prefix,
addf(str, "\n");
}
gnutls_free(oid);
- } else
- add_altname(str, prefix, err, buffer, size);
+ } else {
+ char pfx[16];
+ t.data = (void*)buffer;
+ t.size = size;
+
+ snprintf(pfx, sizeof(pfx), "%s\t\t\t", prefix);
+ print_name(str, pfx, err, &t);
+ }
gnutls_free(buffer);
}
@@ -1048,6 +974,7 @@ print_extensions(gnutls_buffer_st * str, const char *prefix, int type,
int ski_idx = 0;
int aki_idx = 0, nc_idx = 0;
int crldist_idx = 0, pkey_usage_period_idx = 0;
+ gnutls_datum_t der = {NULL, 0};
char pfx[16];
for (i = 0;; i++) {
@@ -1288,7 +1215,28 @@ print_extensions(gnutls_buffer_st * str, const char *prefix, int type,
critical ? _("critical") : _("not critical"));
if (type == TYPE_CRT)
- print_aia(str, cert.crt);
+ err =
+ gnutls_x509_crt_get_extension_data2
+ (cert.crt, i, &der);
+ else if (type == TYPE_CRQ)
+ err =
+ gnutls_x509_crq_get_extension_data2
+ (cert.crq, i, &der);
+ else {
+ gnutls_assert();
+ return;
+ }
+
+ if (err < 0) {
+ addf(str,
+ "error: get_extension_data2: %s\n",
+ gnutls_strerror(err));
+ continue;
+ }
+
+ print_aia(str, &der);
+
+ _gnutls_free_datum(&der);
} else if (strcmp(oid, "2.5.29.30") == 0) {
if (nc_idx) {
addf(str,
@@ -1303,8 +1251,6 @@ print_extensions(gnutls_buffer_st * str, const char *prefix, int type,
if (type == TYPE_CRT)
print_nc(str, prefix, cert.crt);
} else {
- char *buffer;
- size_t extlen = 0;
addf(str, _("%s\t\tUnknown extension %s (%s):\n"),
prefix, oid,
@@ -1312,12 +1258,12 @@ print_extensions(gnutls_buffer_st * str, const char *prefix, int type,
if (type == TYPE_CRT)
err =
- gnutls_x509_crt_get_extension_data
- (cert.crt, i, NULL, &extlen);
+ gnutls_x509_crt_get_extension_data2
+ (cert.crt, i, &der);
else if (type == TYPE_CRQ)
err =
- gnutls_x509_crq_get_extension_data
- (cert.crq, i, NULL, &extlen);
+ gnutls_x509_crq_get_extension_data2
+ (cert.crq, i, &der);
else {
gnutls_assert();
return;
@@ -1325,45 +1271,20 @@ print_extensions(gnutls_buffer_st * str, const char *prefix, int type,
if (err < 0) {
addf(str,
- "error: get_extension_data: %s\n",
- gnutls_strerror(err));
- continue;
- }
-
- buffer = gnutls_malloc(extlen);
- if (!buffer) {
- addf(str, "error: malloc: %s\n",
- gnutls_strerror
- (GNUTLS_E_MEMORY_ERROR));
- continue;
- }
-
- if (type == TYPE_CRT)
- err =
- gnutls_x509_crt_get_extension_data
- (cert.crt, i, buffer, &extlen);
- else if (type == TYPE_CRQ)
- err =
- gnutls_x509_crq_get_extension_data
- (cert.crq, i, buffer, &extlen);
-
- if (err < 0) {
- gnutls_free(buffer);
- addf(str,
"error: get_extension_data2: %s\n",
gnutls_strerror(err));
continue;
}
addf(str, _("%s\t\t\tASCII: "), prefix);
- _gnutls_buffer_asciiprint(str, buffer, extlen);
+ _gnutls_buffer_asciiprint(str, (char*)der.data, der.size);
addf(str, "\n");
addf(str, _("%s\t\t\tHexdump: "), prefix);
- _gnutls_buffer_hexprint(str, buffer, extlen);
+ _gnutls_buffer_hexprint(str, (char*)der.data, der.size);
adds(str, "\n");
- gnutls_free(buffer);
+ _gnutls_free_datum(&der);
}
}
}
diff --git a/lib/x509/x509.c b/lib/x509/x509.c
index 08ea4f9c1e..d80b4770f8 100644
--- a/lib/x509/x509.c
+++ b/lib/x509/x509.c
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2003-2012 Free Software Foundation, Inc.
- * Author: Nikos Mavrogiannopoulos, Simon Josefsson, Howard Chu
+ * Copyright (C) 2003-2014 Free Software Foundation, Inc.
+ * Authors: Nikos Mavrogiannopoulos, Simon Josefsson, Howard Chu
*
* This file is part of GnuTLS.
*
@@ -27,6 +27,7 @@
#include <gnutls_global.h>
#include <gnutls_errors.h>
#include <common.h>
+#include <gnutls/x509-ext.h>
#include <gnutls_x509.h>
#include <x509_b64.h>
#include <x509_int.h>
@@ -45,7 +46,7 @@
int gnutls_x509_crt_init(gnutls_x509_crt_t * cert)
{
gnutls_x509_crt_t tmp;
-
+
FAIL_IF_LIB_ERROR;
tmp =
@@ -713,9 +714,8 @@ gnutls_x509_crt_get_private_key_usage_period(gnutls_x509_crt_t cert,
time_t * expiration,
unsigned int *critical)
{
- int result, ret;
+ int ret;
gnutls_datum_t der = { NULL, 0 };
- ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
if (cert == NULL) {
gnutls_assert();
@@ -733,32 +733,16 @@ gnutls_x509_crt_get_private_key_usage_period(gnutls_x509_crt_t cert,
gnutls_assert_val
(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
- result = asn1_create_element
- (_gnutls_get_pkix(), "PKIX1.PrivateKeyUsagePeriod", &c2);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- result = asn1_der_decoding(&c2, der.data, der.size, NULL);
- if (result != ASN1_SUCCESS) {
+ ret = gnutls_x509_ext_get_private_key_usage_period(&der, activation, expiration);
+ if (ret < 0) {
gnutls_assert();
- ret = _gnutls_asn2err(result);
goto cleanup;
}
- if (activation)
- *activation = _gnutls_x509_get_time(c2, "notBefore", 1);
-
- if (expiration)
- *expiration = _gnutls_x509_get_time(c2, "notAfter", 1);
-
ret = 0;
cleanup:
_gnutls_free_datum(&der);
- asn1_delete_structure(&c2);
return ret;
}
@@ -822,112 +806,51 @@ 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;
+ int result;
+ gnutls_datum_t id = {NULL,0};
+ gnutls_datum_t der = {NULL, 0};
if (cert == NULL) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
-
- if (ret)
- memset(ret, 0, *ret_size);
- else
+ if (ret == NULL)
*ret_size = 0;
if ((result =
- _gnutls_x509_crt_get_extension(cert, "2.5.29.14", 0, &id,
+ _gnutls_x509_crt_get_extension(cert, "2.5.29.14", 0, &der,
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) {
+ result = gnutls_x509_ext_get_subject_key_id(&der, &id);
+ if (result < 0) {
gnutls_assert();
- _gnutls_free_datum(&id);
- return _gnutls_asn2err(result);
+ goto cleanup;
}
- result = asn1_der_decoding(&c2, id.data, id.size, NULL);
- _gnutls_free_datum(&id);
-
- if (result != ASN1_SUCCESS) {
+ result = _gnutls_copy_data(&id, ret, ret_size);
+ if (result < 0) {
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;
+ goto cleanup;
}
- if (result != ASN1_SUCCESS) {
- if (result != ASN1_MEM_ERROR)
- gnutls_assert();
- return _gnutls_asn2err(result);
- }
+ result = 0;
- return 0;
+ cleanup:
+ gnutls_free(der.data);
+ gnutls_free(id.data);
+ return result;
}
-static int
-_get_authority_key_id(gnutls_x509_crt_t cert, ASN1_TYPE * c2,
- unsigned int *critical)
+inline static int is_type_printable(int type)
{
- 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;
+ if (type == GNUTLS_SAN_DNSNAME || type == GNUTLS_SAN_RFC822NAME ||
+ type == GNUTLS_SAN_URI)
+ return 1;
+ else
+ return 0;
}
/**
@@ -963,42 +886,69 @@ gnutls_x509_crt_get_authority_key_gn_serial(gnutls_x509_crt_t cert,
size_t * serial_size,
unsigned int *critical)
{
- int ret, result, len;
- ASN1_TYPE c2;
+ int ret;
+ gnutls_datum_t der, san, iserial;
+ gnutls_x509_aki_t aki = NULL;
+ unsigned san_type;
- ret = _get_authority_key_id(cert, &c2, critical);
- if (ret < 0)
+ if (cert == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if ((ret =
+ _gnutls_x509_crt_get_extension(cert, "2.5.29.35", 0, &der,
+ critical)) < 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 (der.size == 0 || der.data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
- if (serial) {
- len = *serial_size;
- result =
- asn1_read_value(c2, "authorityCertSerialNumber",
- serial, &len);
+ ret = gnutls_x509_aki_init(&aki);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- *serial_size = len;
+ ret = gnutls_x509_ext_get_authority_key_id(&der, aki, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- if (result < 0) {
- ret = _gnutls_asn2err(result);
- goto fail;
- }
+ ret = gnutls_x509_aki_get_cert_issuer(aki, seq, &san_type, &san, NULL, &iserial);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ if (is_type_printable(san_type))
+ ret = _gnutls_copy_string(&san, alt, alt_size);
+ else
+ ret = _gnutls_copy_data(&san, alt, alt_size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
}
- ret = 0;
+ if (alt_type)
+ *alt_type = san_type;
- fail:
- asn1_delete_structure(&c2);
+ ret = _gnutls_copy_data(&iserial, serial, serial_size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- return ret;
+ ret = 0;
+ cleanup:
+ if (aki != NULL)
+ gnutls_x509_aki_deinit(aki);
+ gnutls_free(der.data);
+ return ret;
}
/**
@@ -1024,31 +974,67 @@ 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;
+ int ret;
+ gnutls_datum_t der, l_id;
+ gnutls_x509_aki_t aki = NULL;
- ret = _get_authority_key_id(cert, &c2, critical);
- if (ret < 0)
+ if (cert == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ if ((ret =
+ _gnutls_x509_crt_get_extension(cert, "2.5.29.35", 0, &der,
+ critical)) < 0) {
return gnutls_assert_val(ret);
+ }
- len = *id_size;
- result = asn1_read_value(c2, "keyIdentifier", id, &len);
+ if (der.size == 0 || der.data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
- *id_size = len;
- asn1_delete_structure(&c2);
+ ret = gnutls_x509_aki_init(&aki);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- if (result == ASN1_VALUE_NOT_FOUND
- || result == ASN1_ELEMENT_NOT_FOUND)
- return
- gnutls_assert_val(GNUTLS_E_X509_UNSUPPORTED_EXTENSION);
+ ret = gnutls_x509_ext_get_authority_key_id(&der, aki, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
- if (result != ASN1_SUCCESS) {
- if (result != ASN1_MEM_ERROR)
- gnutls_assert();
- return _gnutls_asn2err(result);
+ ret = gnutls_x509_aki_get_id(aki, &l_id);
+
+ if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ gnutls_datum_t serial;
+ ret = gnutls_x509_aki_get_cert_issuer(aki, 0, NULL, NULL, NULL, &serial);
+ if (ret >= 0) {
+ ret = gnutls_assert_val(GNUTLS_E_X509_UNSUPPORTED_EXTENSION);
+ } else {
+ ret = gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+ }
}
- return 0;
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = _gnutls_copy_data(&l_id, id, id_size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ if (aki != NULL)
+ gnutls_x509_aki_deinit(aki);
+ gnutls_free(der.data);
+ return ret;
}
/**
@@ -1095,15 +1081,6 @@ gnutls_x509_crt_get_pk_algorithm(gnutls_x509_crt_t cert,
}
-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.
@@ -1262,7 +1239,7 @@ _gnutls_parse_general_name(ASN1_TYPE src, const char *src_name,
{
int ret;
gnutls_datum_t res = {NULL,0};
- unsigned size_to_check, type;
+ unsigned type;
ret = _gnutls_parse_general_name2(src, src_name, seq, &res, ret_type, othername_oid);
if (ret < 0)
@@ -1271,22 +1248,16 @@ _gnutls_parse_general_name(ASN1_TYPE src, const char *src_name,
type = ret;
if (is_type_printable(type)) {
- size_to_check = res.size + 1;
+ ret = _gnutls_copy_string(&res, name, name_size);
} else {
- size_to_check = res.size;
+ ret = _gnutls_copy_data(&res, name, name_size);
}
- if ((unsigned) size_to_check > *name_size) {
+ if (ret < 0) {
gnutls_assert();
- (*name_size) = size_to_check;
- ret = GNUTLS_E_SHORT_MEMORY_BUFFER;
goto cleanup;
}
- if (name != NULL) {
- memcpy(name, res.data, res.size);
- }
- *name_size = res.size;
ret = type;
cleanup:
gnutls_free(res.data);
@@ -1295,28 +1266,28 @@ cleanup:
static int
get_alt_name(gnutls_x509_crt_t cert, const char *extension_id,
- unsigned int seq, void *alt,
+ unsigned int seq, uint8_t *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;
+ int ret;
+ gnutls_datum_t dnsname = {NULL, 0};
+ gnutls_datum_t res;
+ gnutls_subject_alt_names_t sans = NULL;
+ unsigned int type;
if (cert == NULL) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
- if (alt)
- memset(alt, 0, *alt_size);
- else
+ if (alt == NULL)
*alt_size = 0;
- if ((result =
+ if ((ret =
_gnutls_x509_crt_get_extension(cert, extension_id, 0,
&dnsname, critical)) < 0) {
- return result;
+ return ret;
}
if (dnsname.size == 0 || dnsname.data == NULL) {
@@ -1324,44 +1295,45 @@ get_alt_name(gnutls_x509_crt_t cert, const char *extension_id,
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 {
+ ret = gnutls_subject_alt_names_init(&sans);
+ if (ret < 0) {
gnutls_assert();
- return GNUTLS_E_INTERNAL_ERROR;
+ goto cleanup;
}
- if (result != ASN1_SUCCESS) {
+ ret = gnutls_x509_ext_get_subject_alt_names(&dnsname, sans, 0);
+ if (ret < 0) {
gnutls_assert();
- _gnutls_free_datum(&dnsname);
- return _gnutls_asn2err(result);
+ goto cleanup;
}
- result = asn1_der_decoding(&c2, dnsname.data, dnsname.size, NULL);
- _gnutls_free_datum(&dnsname);
-
- if (result != ASN1_SUCCESS) {
+ ret = gnutls_subject_alt_names_get(sans, seq, &type, &res, NULL);
+ if (ret < 0) {
gnutls_assert();
- asn1_delete_structure(&c2);
- return _gnutls_asn2err(result);
+ goto cleanup;
}
- result =
- _gnutls_parse_general_name(c2, "", seq, alt, alt_size,
- alt_type, othername_oid);
+ if (alt_type)
+ *alt_type = type;
- asn1_delete_structure(&c2);
+ if (is_type_printable(type)) {
+ ret = _gnutls_copy_string(&res, alt, alt_size);
+ } else {
+ ret = _gnutls_copy_data(&res, alt, alt_size);
+ }
- if (result < 0) {
+ if (ret < 0) {
gnutls_assert();
- return result;
+ goto cleanup;
}
- return result;
+ ret = type;
+cleanup:
+ gnutls_free(dnsname.data);
+ if (sans != NULL)
+ gnutls_subject_alt_names_deinit(sans);
+
+ return ret;
}
/**
@@ -1646,15 +1618,10 @@ gnutls_x509_crt_get_basic_constraints(gnutls_x509_crt_t cert,
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
- result =
- _gnutls_x509_ext_extract_basicConstraints(&tmp_ca,
- pathlen,
- basicConstraints.
- data,
- basicConstraints.
- size);
+ result = gnutls_x509_ext_get_basic_constraints(&basicConstraints, &tmp_ca, pathlen);
if (ca)
*ca = tmp_ca;
+
_gnutls_free_datum(&basicConstraints);
if (result < 0) {
@@ -1718,7 +1685,6 @@ gnutls_x509_crt_get_key_usage(gnutls_x509_crt_t cert,
{
int result;
gnutls_datum_t keyUsage;
- uint16_t _usage;
if (cert == NULL) {
gnutls_assert();
@@ -1736,12 +1702,9 @@ gnutls_x509_crt_get_key_usage(gnutls_x509_crt_t cert,
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
- result = _gnutls_x509_ext_extract_keyUsage(&_usage, keyUsage.data,
- keyUsage.size);
+ result = gnutls_x509_ext_get_key_usage(&keyUsage, key_usage);
_gnutls_free_datum(&keyUsage);
- *key_usage = _usage;
-
if (result < 0) {
gnutls_assert();
return result;
@@ -1794,13 +1757,10 @@ gnutls_x509_crt_get_proxy(gnutls_x509_crt_t cert,
return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
}
- result = _gnutls_x509_ext_extract_proxyCertInfo(pathlen,
+ result = gnutls_x509_ext_get_proxy(&proxyCertInfo, pathlen,
policyLanguage,
policy,
- sizeof_policy,
- proxyCertInfo.data,
- proxyCertInfo.
- size);
+ sizeof_policy);
_gnutls_free_datum(&proxyCertInfo);
if (result < 0) {
gnutls_assert();
@@ -1828,79 +1788,6 @@ void gnutls_x509_policy_release(struct gnutls_x509_policy_st *policy)
gnutls_free(policy->qualifier[i].data);
}
-static int decode_user_notice(const void *data, size_t size,
- gnutls_datum_t * txt)
-{
- ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
- int ret, len;
- char choice_type[64];
- char name[128];
- gnutls_datum_t td, utd;
-
- ret = asn1_create_element
- (_gnutls_get_pkix(), "PKIX1.UserNotice", &c2);
- if (ret != ASN1_SUCCESS) {
- gnutls_assert();
- ret = GNUTLS_E_PARSING_ERROR;
- goto cleanup;
- }
-
- ret = asn1_der_decoding(&c2, data, size, NULL);
- if (ret != ASN1_SUCCESS) {
- gnutls_assert();
- ret = GNUTLS_E_PARSING_ERROR;
- goto cleanup;
- }
-
- len = sizeof(choice_type);
- ret = asn1_read_value(c2, "explicitText", choice_type, &len);
- if (ret != ASN1_SUCCESS) {
- gnutls_assert();
- ret = GNUTLS_E_PARSING_ERROR;
- goto cleanup;
- }
-
- if (strcmp(choice_type, "utf8String") != 0
- && strcmp(choice_type, "IA5String") != 0
- && strcmp(choice_type, "bmpString") != 0
- && strcmp(choice_type, "visibleString") != 0) {
- gnutls_assert();
- ret = GNUTLS_E_PARSING_ERROR;
- goto cleanup;
- }
-
- snprintf(name, sizeof(name), "explicitText.%s", choice_type);
-
- ret = _gnutls_x509_read_value(c2, name, &td);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
-
- if (strcmp(choice_type, "bmpString") == 0) { /* convert to UTF-8 */
- ret = _gnutls_ucs2_to_utf8(td.data, td.size, &utd);
- _gnutls_free_datum(&td);
- if (ret < 0) {
- gnutls_assert();
- goto cleanup;
- }
-
- td.data = utd.data;
- td.size = utd.size;
- } else {
- /* _gnutls_x509_read_value allows that */
- td.data[td.size] = 0;
- }
-
- txt->data = (void *) td.data;
- txt->size = td.size;
- ret = 0;
-
- cleanup:
- asn1_delete_structure(&c2);
- return ret;
-
-}
/**
* gnutls_x509_crt_get_policy:
@@ -1925,12 +1812,9 @@ gnutls_x509_crt_get_policy(gnutls_x509_crt_t crt, int indx,
struct gnutls_x509_policy_st *policy,
unsigned int *critical)
{
- ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
- char tmpstr[128];
- char tmpoid[MAX_OID_SIZE];
gnutls_datum_t tmpd = { NULL, 0 };
- int ret, len;
- unsigned i;
+ int ret;
+ gnutls_x509_policies_t policies = NULL;
if (crt == NULL) {
gnutls_assert();
@@ -1939,130 +1823,43 @@ gnutls_x509_crt_get_policy(gnutls_x509_crt_t crt, int indx,
memset(policy, 0, sizeof(*policy));
+ ret = gnutls_x509_policies_init(&policies);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
if ((ret =
_gnutls_x509_crt_get_extension(crt, "2.5.29.32", 0, &tmpd,
critical)) < 0) {
- return ret;
+ goto cleanup;
}
if (tmpd.size == 0 || tmpd.data == NULL) {
gnutls_assert();
- return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
- }
-
- ret = asn1_create_element
- (_gnutls_get_pkix(), "PKIX1.certificatePolicies", &c2);
- if (ret != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(ret);
+ ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
goto cleanup;
}
- ret = asn1_der_decoding(&c2, tmpd.data, tmpd.size, NULL);
- if (ret != ASN1_SUCCESS) {
+ ret = gnutls_x509_ext_get_policies(&tmpd, policies, 0);
+ if (ret < 0) {
gnutls_assert();
- ret = _gnutls_asn2err(ret);
goto cleanup;
}
- _gnutls_free_datum(&tmpd);
-
- indx++;
- /* create a string like "?1"
- */
- snprintf(tmpstr, sizeof(tmpstr), "?%u.policyIdentifier", indx);
-
- ret = _gnutls_x509_read_value(c2, tmpstr, &tmpd);
-
- if (ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
- ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ ret = gnutls_x509_policies_get(policies, indx, policy);
if (ret < 0) {
gnutls_assert();
goto cleanup;
}
- policy->oid = (void *) tmpd.data;
- tmpd.data = NULL;
-
- for (i = 0; i < GNUTLS_MAX_QUALIFIERS; i++) {
- gnutls_datum_t td;
- snprintf(tmpstr, sizeof(tmpstr),
- "?%u.policyQualifiers.?%u.policyQualifierId",
- indx, i + 1);
-
- len = sizeof(tmpoid);
- ret = asn1_read_value(c2, tmpstr, tmpoid, &len);
-
- if (ret == ASN1_ELEMENT_NOT_FOUND)
- break; /* finished */
-
- if (ret != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(ret);
- goto cleanup;
- }
-
- if (strcmp(tmpoid, "1.3.6.1.5.5.7.2.1") == 0) {
- snprintf(tmpstr, sizeof(tmpstr),
- "?%u.policyQualifiers.?%u.qualifier",
- indx, i + 1);
-
- ret =
- _gnutls_x509_read_string(c2, tmpstr, &td,
- ASN1_ETYPE_IA5_STRING);
- if (ret < 0) {
- gnutls_assert();
- goto full_cleanup;
- }
-
- policy->qualifier[i].data = (void *) td.data;
- policy->qualifier[i].size = td.size;
- td.data = NULL;
- policy->qualifier[i].type =
- GNUTLS_X509_QUALIFIER_URI;
- } else if (strcmp(tmpoid, "1.3.6.1.5.5.7.2.2") == 0) {
- gnutls_datum_t txt;
-
- snprintf(tmpstr, sizeof(tmpstr),
- "?%u.policyQualifiers.?%u.qualifier",
- indx, i + 1);
-
- ret = _gnutls_x509_read_value(c2, tmpstr, &td);
- if (ret < 0) {
- gnutls_assert();
- goto full_cleanup;
- }
-
- ret = decode_user_notice(td.data, td.size, &txt);
- gnutls_free(td.data);
- td.data = NULL;
-
- if (ret < 0) {
- gnutls_assert();
- goto full_cleanup;
- }
-
- policy->qualifier[i].data = (void *) txt.data;
- policy->qualifier[i].size = txt.size;
- policy->qualifier[i].type =
- GNUTLS_X509_QUALIFIER_NOTICE;
- } else
- policy->qualifier[i].type =
- GNUTLS_X509_QUALIFIER_UNKNOWN;
-
- policy->qualifiers++;
-
- }
+ _gnutls_x509_policies_erase(policies, indx);
ret = 0;
- goto cleanup;
-
- full_cleanup:
- gnutls_x509_policy_release(policy);
- cleanup:
+ cleanup:
+ if (policies != NULL)
+ gnutls_x509_policies_deinit(policies);
_gnutls_free_datum(&tmpd);
- asn1_delete_structure(&c2);
+
return ret;
}
@@ -2179,7 +1976,7 @@ gnutls_x509_crt_get_extension_oid(gnutls_x509_crt_t cert, int indx,
* 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.
+ * gnutls_x509_crt_get_extension() 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
@@ -2248,7 +2045,7 @@ gnutls_x509_crt_get_extension_info(gnutls_x509_crt_t cert, int indx,
* @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
+ * certificate. The extension data will be stored in the
* provided buffer.
*
* Use gnutls_x509_crt_get_extension_info() to extract the OID and
@@ -3017,8 +2814,8 @@ gnutls_x509_crt_verify_hash(gnutls_x509_crt_t crt, unsigned int flags,
* 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.
+ * @san: is the place where the distribution point will be copied to
+ * @san_size: holds the size of ret.
* @reason_flags: Revocation reasons. An ORed sequence of flags from %gnutls_x509_crl_reason_flags_t.
* @critical: will be non-zero if the extension is marked as critical (may be null)
*
@@ -3036,103 +2833,69 @@ gnutls_x509_crt_verify_hash(gnutls_x509_crt_t crt, unsigned int flags,
**/
int
gnutls_x509_crt_get_crl_dist_points(gnutls_x509_crt_t cert,
- unsigned int seq, void *ret,
- size_t * ret_size,
+ unsigned int seq, void *san,
+ size_t * san_size,
unsigned int *reason_flags,
unsigned int *critical)
{
- int result;
+ int ret;
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];
+ gnutls_x509_crl_dist_points_t cdp = NULL;
+ gnutls_datum_t t_san;
if (cert == NULL) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
- if (*ret_size > 0 && ret)
- memset(ret, 0, *ret_size);
- else
- *ret_size = 0;
+ ret = gnutls_x509_crl_dist_points_init(&cdp);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
if (reason_flags)
*reason_flags = 0;
- result =
+ ret =
_gnutls_x509_crt_get_extension(cert, "2.5.29.31", 0,
&dist_points, critical);
- if (result < 0) {
- return result;
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
}
if (dist_points.size == 0 || dist_points.data == NULL) {
gnutls_assert();
- return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ goto cleanup;
}
- result = asn1_create_element
- (_gnutls_get_pkix(), "PKIX1.CRLDistributionPoints", &c2);
- if (result != ASN1_SUCCESS) {
+ ret = gnutls_x509_ext_get_crl_dist_points(&dist_points, cdp, 0);
+ if (ret < 0) {
gnutls_assert();
- _gnutls_free_datum(&dist_points);
- return _gnutls_asn2err(result);
+ goto cleanup;
}
- result =
- asn1_der_decoding(&c2, dist_points.data, dist_points.size,
- NULL);
- _gnutls_free_datum(&dist_points);
-
- if (result != ASN1_SUCCESS) {
+ ret = gnutls_x509_crl_dist_points_get(cdp, seq, &type, &t_san, reason_flags);
+ if (ret < 0) {
gnutls_assert();
- asn1_delete_structure(&c2);
- return _gnutls_asn2err(result);
+ goto cleanup;
}
- /* 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;
+ ret = _gnutls_copy_string(&t_san, san, san_size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
}
- 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);
- }
+ ret = type;
- asn1_delete_structure(&c2);
+ cleanup:
+ _gnutls_free_datum(&dist_points);
+ if (cdp != NULL)
+ gnutls_x509_crl_dist_points_deinit(cdp);
- return type;
+ return ret;
}
/**
@@ -3161,10 +2924,10 @@ 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;
+ int ret;
+ gnutls_datum_t ext;
+ gnutls_x509_key_purposes_t p = NULL;
+ gnutls_datum_t out;
if (cert == NULL) {
gnutls_assert();
@@ -3176,57 +2939,48 @@ gnutls_x509_crt_get_key_purpose_oid(gnutls_x509_crt_t cert,
else
*oid_size = 0;
- if ((result =
- _gnutls_x509_crt_get_extension(cert, "2.5.29.37", 0, &id,
+ if ((ret =
+ _gnutls_x509_crt_get_extension(cert, "2.5.29.37", 0, &ext,
critical)) < 0) {
- return result;
+ return ret;
}
- if (id.size == 0 || id.data == NULL) {
+ if (ext.size == 0 || ext.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) {
+ ret = gnutls_x509_key_purpose_init(&p);
+ if (ret < 0) {
gnutls_assert();
- _gnutls_free_datum(&id);
- return _gnutls_asn2err(result);
+ goto cleanup;
}
-
- result = asn1_der_decoding(&c2, id.data, id.size, NULL);
- _gnutls_free_datum(&id);
-
- if (result != ASN1_SUCCESS) {
+
+ ret = gnutls_x509_ext_get_key_purposes(&ext, p, 0);
+ if (ret < 0) {
gnutls_assert();
- asn1_delete_structure(&c2);
- return _gnutls_asn2err(result);
+ goto cleanup;
}
- 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;
+ ret = gnutls_x509_key_purpose_get(p, indx, &out);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
}
-
- if (result != ASN1_SUCCESS) {
+
+ ret = _gnutls_copy_data(&out, oid, oid_size);
+ if (ret < 0) {
gnutls_assert();
- return _gnutls_asn2err(result);
+ goto cleanup;
}
- return 0;
+ ret = 0;
+ cleanup:
+ gnutls_free(ext.data);
+ if (p!=NULL)
+ gnutls_x509_key_purpose_deinit(p);
+ return ret;
}
/**
@@ -3701,7 +3455,7 @@ gnutls_x509_crt_get_issuer_unique_id(gnutls_x509_crt_t crt, char *buf,
}
static int
-_gnutls_parse_aia(ASN1_TYPE src,
+legacy_parse_aia(ASN1_TYPE src,
unsigned int seq, int what, gnutls_datum_t * data)
{
int len;
@@ -3728,7 +3482,7 @@ _gnutls_parse_aia(ASN1_TYPE src,
if (oid == NULL)
oid = GNUTLS_OID_AD_OCSP;
{
- char tmpoid[20];
+ char tmpoid[MAX_OID_SIZE];
snprintf(nptr, sizeof(nptr), "?%u.accessMethod",
seq);
len = sizeof(tmpoid);
@@ -3805,18 +3559,12 @@ _gnutls_parse_aia(ASN1_TYPE src,
* @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)
*
+ * Note that a simpler API to access the authority info data is provided
+ * by gnutls_x509_aia_get() and gnutls_x509_ext_get_aia().
+ *
* 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:
- *
- * <informalexample><programlisting>
- * AuthorityInfoAccessSyntax ::=
- * SEQUENCE SIZE (1..MAX) OF AccessDescription
- *
- * AccessDescription ::= SEQUENCE {
- * accessMethod OBJECT IDENTIFIER,
- * accessLocation GeneralName }
- * </programlisting></informalexample>
+ * AIA extension holds a sequence of AccessDescription (AD) data.
*
* The @seq input parameter is used to indicate which member of the
* sequence the caller is interested in. The first member is 0, the
@@ -3912,7 +3660,7 @@ gnutls_x509_crt_get_authority_info_access(gnutls_x509_crt_t crt,
return _gnutls_asn2err(ret);
}
- ret = _gnutls_parse_aia(c2, seq, what, data);
+ ret = legacy_parse_aia(c2, seq, what, data);
asn1_delete_structure(&c2);
if (ret < 0)
diff --git a/lib/x509/x509_ext.c b/lib/x509/x509_ext.c
new file mode 100644
index 0000000000..70d232f736
--- /dev/null
+++ b/lib/x509/x509_ext.c
@@ -0,0 +1,3028 @@
+/*
+ * Copyright (C) 2014 Free Software Foundation
+ *
+ * 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 <http://www.gnu.org/licenses/>
+ *
+ */
+
+/* This file contains functions to handle X.509 certificate extensions (the x509-ext API)
+ */
+
+#include <gnutls_int.h>
+
+#include <gnutls_datum.h>
+#include <gnutls_errors.h>
+#include <common.h>
+#include <gnutls_x509.h>
+#include <x509_b64.h>
+#include <c-ctype.h>
+#include <gnutls/x509-ext.h>
+
+struct name_st {
+ unsigned int type;
+ gnutls_datum_t san;
+ gnutls_datum_t othername_oid;
+};
+
+#define MAX_ENTRIES 64
+struct gnutls_subject_alt_names_st {
+ struct name_st *names;
+ unsigned int size;
+};
+
+/**
+ * gnutls_subject_alt_names_init:
+ * @sans: The alternative names structure
+ *
+ * This function will initialize an alternative names structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_subject_alt_names_init(gnutls_subject_alt_names_t * sans)
+{
+ *sans = gnutls_calloc(1, sizeof(struct gnutls_subject_alt_names_st));
+ if (*sans == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ return 0;
+}
+
+static void subject_alt_names_deinit(gnutls_subject_alt_names_t sans)
+{
+ unsigned int i;
+
+ for (i = 0; i < sans->size; i++) {
+ gnutls_free(sans->names[i].san.data);
+ gnutls_free(sans->names[i].othername_oid.data);
+ }
+ gnutls_free(sans->names);
+}
+
+/**
+ * gnutls_subject_alt_names_deinit:
+ * @sans: The alternative names structure
+ *
+ * This function will deinitialize an alternative names structure.
+ *
+ * Since: 3.3.0
+ **/
+void gnutls_subject_alt_names_deinit(gnutls_subject_alt_names_t sans)
+{
+ subject_alt_names_deinit(sans);
+ gnutls_free(sans);
+}
+
+/**
+ * gnutls_subject_alt_names_get:
+ * @sans: The alternative names structure
+ * @seq: The index of the name to get
+ * @san_type: Will hold the type of the name (of %gnutls_subject_alt_names_t)
+ * @san: The alternative name data (should be treated as constant)
+ * @othername_oid: The object identifier if @san_type is %GNUTLS_SAN_OTHERNAME (should be treated as constant)
+ *
+ * This function will return a specific alternative name as stored in
+ * the @sans structure. The returned values should be treated as constant
+ * and valid for the lifetime of @sans.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+ * if the index is out of bounds, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_subject_alt_names_get(gnutls_subject_alt_names_t sans,
+ unsigned int seq, unsigned int *san_type,
+ gnutls_datum_t * san,
+ gnutls_datum_t * othername_oid)
+{
+ if (seq >= sans->size)
+ return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+
+ if (san) {
+ memcpy(san, &sans->names[seq].san, sizeof(gnutls_datum_t));
+ }
+
+ if (san_type)
+ *san_type = sans->names[seq].type;
+
+ if (sans->names[seq].type == GNUTLS_SAN_OTHERNAME) {
+ othername_oid->data = sans->names[seq].othername_oid.data;
+ othername_oid->size = sans->names[seq].othername_oid.size;
+ }
+
+ return 0;
+}
+
+/* This is the same as gnutls_subject_alt_names_set() but will not
+ * copy the strings */
+static
+int subject_alt_names_set(struct name_st **names,
+ unsigned int *size,
+ unsigned int san_type,
+ const gnutls_datum_t * san, char *othername_oid)
+{
+ void *tmp;
+
+ tmp = gnutls_realloc(*names, (*size + 1) * sizeof((*names)[0]));
+ if (tmp == NULL) {
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ }
+ *names = tmp;
+
+ (*names)[*size].type = san_type;
+ (*names)[*size].san.data = san->data;
+ (*names)[*size].san.size = san->size;
+
+ if (othername_oid) {
+ (*names)[*size].othername_oid.data = (uint8_t *) othername_oid;
+ (*names)[*size].othername_oid.size = strlen(othername_oid);
+ } else {
+ (*names)[*size].othername_oid.data = NULL;
+ (*names)[*size].othername_oid.size = 0;
+ }
+
+ (*size)++;
+ return 0;
+}
+
+/**
+ * gnutls_subject_alt_names_set:
+ * @sans: The alternative names structure
+ * @san_type: The type of the name (of %gnutls_subject_alt_names_t)
+ * @san: The alternative name data
+ * @othername_oid: The object identifier if @san_type is %GNUTLS_SAN_OTHERNAME
+ *
+ * This function will store the specified alternative name in
+ * the @sans structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0), otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_subject_alt_names_set(gnutls_subject_alt_names_t sans,
+ unsigned int san_type,
+ const gnutls_datum_t * san,
+ const char *othername_oid)
+{
+ int ret;
+ gnutls_datum_t copy;
+ char *ooc;
+
+ ret = _gnutls_set_datum(&copy, san->data, san->size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ if (othername_oid != NULL)
+ ooc = gnutls_strdup(othername_oid);
+ else
+ ooc = NULL;
+ ret = subject_alt_names_set(&sans->names, &sans->size,
+ san_type, &copy, ooc);
+ if (ret < 0) {
+ gnutls_free(copy.data);
+ return gnutls_assert_val(ret);
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_x509_ext_get_subject_alt_names:
+ * @ext: The DER-encoded extension data
+ * @sans: The alternative names structure
+ * @flags: should be zero
+ *
+ * This function will export the alternative names in the provided DER-encoded
+ * SubjectAltName PKIX extension, to a %gnutls_subject_alt_names_t structure. The structure
+ * must have been initialized.
+ *
+ * This function will succeed even if there no subject alternative names
+ * in the structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_get_subject_alt_names(const gnutls_datum_t * ext,
+ gnutls_subject_alt_names_t sans,
+ unsigned int flags)
+{
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ int result, ret;
+ unsigned int i;
+ gnutls_datum_t san, othername_oid;
+ unsigned type;
+
+ result =
+ asn1_create_element(_gnutls_get_pkix(), "PKIX1.GeneralNames", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ result = asn1_der_decoding(&c2, ext->data, ext->size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ i = 0;
+ do {
+ san.data = NULL;
+ othername_oid.data = NULL;
+
+ ret = _gnutls_parse_general_name2(c2, "", i, &san, &type, 0);
+ if (ret < 0)
+ break;
+
+ if (type == GNUTLS_SAN_OTHERNAME) {
+ ret =
+ _gnutls_parse_general_name2(c2, "", i,
+ &othername_oid,
+ NULL, 1);
+ if (ret < 0)
+ break;
+ }
+
+ ret = subject_alt_names_set(&sans->names, &sans->size,
+ type, &san,
+ (char *)othername_oid.data);
+ if (ret < 0)
+ break;
+
+ i++;
+ } while (ret >= 0);
+
+ sans->size = i;
+ if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ gnutls_free(san.data);
+ gnutls_free(othername_oid.data);
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ asn1_delete_structure(&c2);
+ return ret;
+}
+
+/**
+ * gnutls_x509_ext_set_subject_alt_names:
+ * @sans: The alternative names structure
+ * @ext: The DER-encoded extension data; must be freed using gnutls_free().
+ *
+ * This function will convert the provided alternative names structure to a
+ * DER-encoded SubjectAltName PKIX extension. The output data in @ext will be allocated using
+ * gnutls_malloc().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_set_subject_alt_names(gnutls_subject_alt_names_t sans,
+ gnutls_datum_t * ext)
+{
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ int result, ret;
+ unsigned i;
+
+ result =
+ asn1_create_element(_gnutls_get_pkix(), "PKIX1.GeneralNames", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ for (i = 0; i < sans->size; i++) {
+ if (sans->names[i].type == GNUTLS_SAN_OTHERNAME) {
+ ret = gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
+ goto cleanup;
+ }
+ ret =
+ _gnutls_write_new_general_name(c2, "", sans->names[i].type,
+ sans->names[i].san.data,
+ sans->names[i].san.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
+
+ ret = _gnutls_x509_der_encode(c2, "", ext, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ asn1_delete_structure(&c2);
+ return ret;
+}
+
+/**
+ * gnutls_x509_ext_get_name_constraints:
+ * @ext: a DER encoded extension
+ * @nc: The nameconstraints intermediate structure
+ * @flags: zero or %GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND
+ *
+ * This function will return an intermediate structure containing
+ * the name constraints of the provided NameConstraints extension. That
+ * structure can be used in combination with gnutls_x509_name_constraints_check()
+ * to verify whether a server's name is in accordance with the constraints.
+ *
+ * When the @flags is set to %GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND, then if
+ * the @nc structure is empty
+ * this function will behave identically as if the flag was not set.
+ * Otherwise if there are elements in the @nc structure then only the
+ * excluded constraints will be appended to the constraints.
+ *
+ * Note that @nc must be initialized prior to calling this function.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+ * if the extension is not present, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_get_name_constraints(const gnutls_datum_t * ext,
+ gnutls_x509_name_constraints_t nc,
+ unsigned int flags)
+{
+ int result, ret;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+
+ result = asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.NameConstraints", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ result = asn1_der_decoding(&c2, ext->data, ext->size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if (!(flags & GNUTLS_NAME_CONSTRAINTS_FLAG_APPEND)
+ || (nc->permitted == NULL && nc->excluded == NULL)) {
+ ret =
+ _gnutls_extract_name_constraints(c2, "permittedSubtrees",
+ &nc->permitted);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
+
+ ret =
+ _gnutls_extract_name_constraints(c2, "excludedSubtrees",
+ &nc->excluded);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ asn1_delete_structure(&c2);
+
+ return ret;
+}
+
+/**
+ * gnutls_x509_ext_set_name_constraints:
+ * @nc: The nameconstraints structure
+ * @ext: The DER-encoded extension data; must be freed using gnutls_free().
+ *
+ * This function will convert the provided name constraints structure to a
+ * DER-encoded PKIX NameConstraints (2.5.29.30) extension. The output data in
+ * @ext will be allocated usin gnutls_malloc().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_set_name_constraints(gnutls_x509_name_constraints_t nc,
+ gnutls_datum_t * ext)
+{
+ int ret, result;
+ uint8_t null = 0;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ struct name_constraints_node_st *tmp;
+
+ if (nc->permitted == NULL && nc->excluded == NULL)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ result = asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.NameConstraints", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ if (nc->permitted == NULL) {
+ asn1_write_value(c2, "permittedSubtrees", NULL, 0);
+ } else {
+ tmp = nc->permitted;
+ do {
+ result =
+ asn1_write_value(c2, "permittedSubtrees", "NEW", 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result =
+ asn1_write_value(c2,
+ "permittedSubtrees.?LAST.maximum",
+ NULL, 0);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result =
+ asn1_write_value(c2,
+ "permittedSubtrees.?LAST.minimum",
+ &null, 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ ret =
+ _gnutls_write_general_name(c2,
+ "permittedSubtrees.?LAST.base",
+ tmp->type,
+ tmp->name.data,
+ tmp->name.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ tmp = tmp->next;
+ } while (tmp != NULL);
+ }
+
+ if (nc->excluded == NULL) {
+ asn1_write_value(c2, "excludedSubtrees", NULL, 0);
+ } else {
+ tmp = nc->excluded;
+ do {
+ result =
+ asn1_write_value(c2, "excludedSubtrees", "NEW", 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result =
+ asn1_write_value(c2,
+ "excludedSubtrees.?LAST.maximum",
+ NULL, 0);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result =
+ asn1_write_value(c2,
+ "excludedSubtrees.?LAST.minimum",
+ &null, 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ ret =
+ _gnutls_write_general_name(c2,
+ "excludedSubtrees.?LAST.base",
+ tmp->type,
+ tmp->name.data,
+ tmp->name.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ tmp = tmp->next;
+ } while (tmp != NULL);
+
+ }
+
+ ret = _gnutls_x509_der_encode(c2, "", ext, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ asn1_delete_structure(&c2);
+ return ret;
+}
+
+/**
+ * gnutls_x509_ext_get_subject_key_id:
+ * @ext: a DER encoded extension
+ * @id: will contain the subject key ID
+ *
+ * This function will return the subject key ID stored in the provided
+ * SubjectKeyIdentifier extension. The ID will be allocated using
+ * gnutls_malloc().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+ * if the extension is not present, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_get_subject_key_id(const gnutls_datum_t * ext,
+ gnutls_datum_t * id)
+{
+ int result, ret;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+
+ if (ext->size == 0 || ext->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();
+ return _gnutls_asn2err(result);
+ }
+
+ result = asn1_der_decoding(&c2, ext->data, ext->size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ ret = _gnutls_x509_read_value(c2, "", id);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ asn1_delete_structure(&c2);
+
+ return ret;
+
+}
+
+/**
+ * gnutls_x509_ext_set_subject_key_id:
+ * @id: The key identifier
+ * @ext: The DER-encoded extension data; must be freed using gnutls_free().
+ *
+ * This function will convert the provided key identifier to a
+ * DER-encoded PKIX SubjectKeyIdentifier extension.
+ * The output data in @ext will be allocated using
+ * gnutls_malloc().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_set_subject_key_id(const gnutls_datum_t * id,
+ gnutls_datum_t * ext)
+{
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ int ret, result;
+
+ result =
+ asn1_create_element(_gnutls_get_pkix(),
+ "PKIX1.SubjectKeyIdentifier", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ result = asn1_write_value(c2, "", id->data, id->size);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ ret = _gnutls_x509_der_encode(c2, "", ext, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ asn1_delete_structure(&c2);
+ return ret;
+}
+
+struct gnutls_x509_aki_st {
+ gnutls_datum_t id;
+ struct gnutls_subject_alt_names_st cert_issuer;
+ gnutls_datum_t serial;
+};
+
+/**
+ * gnutls_x509_aki_init:
+ * @aki: The authority key ID structure
+ *
+ * This function will initialize an authority key ID structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_aki_init(gnutls_x509_aki_t * aki)
+{
+ *aki = gnutls_calloc(1, sizeof(struct gnutls_x509_aki_st));
+ if (*aki == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ return 0;
+}
+
+/**
+ * gnutls_x509_aki_deinit:
+ * @aki: The authority key identifier structure
+ *
+ * This function will deinitialize an authority key identifier structure.
+ *
+ * Since: 3.3.0
+ **/
+void gnutls_x509_aki_deinit(gnutls_x509_aki_t aki)
+{
+ gnutls_free(aki->serial.data);
+ gnutls_free(aki->id.data);
+ subject_alt_names_deinit(&aki->cert_issuer);
+ gnutls_free(aki);
+}
+
+/**
+ * gnutls_x509_aki_get_id:
+ * @aki: The authority key ID structure
+ * @id: Will hold the identifier
+ *
+ * This function will return the key identifier as stored in
+ * the @aki structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+ * if the index is out of bounds, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_aki_get_id(gnutls_x509_aki_t aki, gnutls_datum_t * id)
+{
+ if (aki->id.size == 0)
+ return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+
+ memcpy(id, &aki->id, sizeof(gnutls_datum_t));
+ return 0;
+}
+
+/**
+ * gnutls_x509_aki_set_id:
+ * @aki: The authority key ID structure
+ * @id: the key identifier
+ *
+ * This function will set the keyIdentifier to be stored in the @aki
+ * structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_aki_set_id(gnutls_x509_aki_t aki, const gnutls_datum_t * id)
+{
+ return _gnutls_set_datum(&aki->id, id->data, id->size);
+}
+
+/**
+ * gnutls_x509_aki_set_cert_issuer:
+ * @aki: The authority key ID structure
+ * @san_type: the type of the name (of %gnutls_subject_alt_names_t), may be null
+ * @san: The alternative name data
+ * @othername_oid: The object identifier if @san_type is %GNUTLS_SAN_OTHERNAME
+ * @serial: The authorityCertSerialNumber number (may be null)
+ *
+ * This function will set the authorityCertIssuer name and the authorityCertSerialNumber
+ * to be stored in the @aki structure. When storing multiple names, the serial
+ * should be set on the first call, and subsequent calls should use a %NULL serial.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_aki_set_cert_issuer(gnutls_x509_aki_t aki,
+ unsigned int san_type,
+ const gnutls_datum_t * san,
+ const char *othername_oid,
+ const gnutls_datum_t * serial)
+{
+ int ret;
+ gnutls_datum_t t_san, t_othername_oid = { NULL, 0 };
+
+ ret = _gnutls_set_datum(&aki->serial, serial->data, serial->size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ aki->cert_issuer.names[aki->cert_issuer.size].type = san_type;
+
+ ret = _gnutls_set_datum(&t_san, san->data, san->size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ if (othername_oid) {
+ t_othername_oid.data = (uint8_t *) gnutls_strdup(othername_oid);
+ if (t_othername_oid.data == NULL) {
+ gnutls_free(t_san.data);
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ }
+ t_othername_oid.size = strlen(othername_oid);
+ }
+
+ ret =
+ subject_alt_names_set(&aki->cert_issuer.names,
+ &aki->cert_issuer.size, san_type, &t_san,
+ (char *)t_othername_oid.data);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_x509_aki_get_cert_issuer:
+ * @aki: The authority key ID structure
+ * @seq: The index of the name to get
+ * @san_type: Will hold the type of the name (of %gnutls_subject_alt_names_t), may be null
+ * @san: The alternative name data (may be null and should be treated as constant)
+ * @othername_oid: The object identifier if @san_type is %GNUTLS_SAN_OTHERNAME (should be treated as constant)
+ * @serial: The authorityCertSerialNumber number (may be null)
+ *
+ * This function will return a specific authorityCertIssuer name as stored in
+ * the @aki structure, as well as the authorityCertSerialNumber.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+ * if the index is out of bounds, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_aki_get_cert_issuer(gnutls_x509_aki_t aki, unsigned int seq,
+ unsigned int *san_type,
+ gnutls_datum_t * san,
+ gnutls_datum_t * othername_oid,
+ gnutls_datum_t * serial)
+{
+ if (seq >= aki->cert_issuer.size)
+ return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+
+ if (aki->serial.size == 0)
+ return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+
+ if (serial)
+ memcpy(serial, &aki->serial, sizeof(gnutls_datum_t));
+
+ if (san) {
+ memcpy(san, &aki->cert_issuer.names[seq].san,
+ sizeof(gnutls_datum_t));
+ }
+
+ if (othername_oid != NULL
+ && aki->cert_issuer.names[seq].type == GNUTLS_SAN_OTHERNAME) {
+ othername_oid->data =
+ aki->cert_issuer.names[seq].othername_oid.data;
+ othername_oid->size =
+ aki->cert_issuer.names[seq].othername_oid.size;
+ }
+
+ if (san_type)
+ *san_type = aki->cert_issuer.names[seq].type;
+
+ return 0;
+
+}
+
+/**
+ * gnutls_x509_ext_get_authority_key_id:
+ * @ext: a DER encoded extension
+ * @aki: An initialized authority key identifier structure
+ * @flags: should be zero
+ *
+ * This function will return the subject key ID stored in the provided
+ * AuthorityKeyIdentifier extension.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+ * if the extension is not present, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_get_authority_key_id(const gnutls_datum_t * ext,
+ gnutls_x509_aki_t aki,
+ unsigned int flags)
+{
+ int ret;
+ unsigned i;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ gnutls_datum_t san, othername_oid;
+ unsigned type;
+
+ ret = asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.AuthorityKeyIdentifier", &c2);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(ret);
+ }
+
+ ret = asn1_der_decoding(&c2, ext->data, ext->size, NULL);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+
+ /* Read authorityCertIssuer */
+ i = 0;
+ do {
+ san.data = NULL;
+ othername_oid.data = NULL;
+
+ ret = _gnutls_parse_general_name2(c2, "authorityCertIssuer", i,
+ &san, &type, 0);
+ if (ret < 0)
+ break;
+
+ if (type == GNUTLS_SAN_OTHERNAME) {
+ ret =
+ _gnutls_parse_general_name2(c2,
+ "authorityCertIssuer",
+ i,
+ &othername_oid,
+ NULL, 1);
+ if (ret < 0)
+ break;
+ }
+
+ ret = subject_alt_names_set(&aki->cert_issuer.names,
+ &aki->cert_issuer.size,
+ type, &san,
+ (char *)othername_oid.data);
+ if (ret < 0)
+ break;
+
+ i++;
+ } while (ret >= 0);
+
+ aki->cert_issuer.size = i;
+ if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+ && ret != GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) {
+ gnutls_assert();
+ gnutls_free(san.data);
+ gnutls_free(othername_oid.data);
+ goto cleanup;
+ }
+
+ /* Read the serial number */
+ ret =
+ _gnutls_x509_read_value(c2, "authorityCertSerialNumber",
+ &aki->serial);
+ if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+ && ret != GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ /* Read the key identifier */
+ ret = _gnutls_x509_read_value(c2, "keyIdentifier", &aki->id);
+ if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+ && ret != GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ asn1_delete_structure(&c2);
+
+ return ret;
+}
+
+/**
+ * gnutls_x509_ext_set_authority_key_id:
+ * @aki: An initialized authority key identifier structure
+ * @ext: The DER-encoded extension data; must be freed using gnutls_free().
+ *
+ * This function will convert the provided key identifier to a
+ * DER-encoded PKIX AuthorityKeyIdentifier extension.
+ * The output data in @ext will be allocated using
+ * gnutls_malloc().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_set_authority_key_id(gnutls_x509_aki_t aki,
+ gnutls_datum_t * ext)
+{
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ unsigned i;
+ int result, ret;
+
+ result =
+ asn1_create_element(_gnutls_get_pkix(),
+ "PKIX1.AuthorityKeyIdentifier", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ if (aki->id.data != NULL) {
+ result =
+ asn1_write_value(c2, "keyIdentifier", aki->id.data,
+ aki->id.size);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+ } else {
+ asn1_write_value(c2, "keyIdentifier", NULL, 0);
+ }
+
+ if (aki->serial.data != NULL) {
+ result =
+ asn1_write_value(c2, "authorityCertSerialNumber",
+ aki->serial.data, aki->serial.size);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+ } else {
+ asn1_write_value(c2, "authorityCertSerialNumber", NULL, 0);
+ }
+
+ if (aki->cert_issuer.size == 0) {
+ asn1_write_value(c2, "authorityCertIssuer", NULL, 0);
+ } else {
+ for (i = 0; i < aki->cert_issuer.size; i++) {
+ ret =
+ _gnutls_write_new_general_name(c2,
+ "authorityCertIssuer",
+ aki->cert_issuer.
+ names[i].type,
+ aki->
+ cert_issuer.names[i].
+ san.data,
+ aki->cert_issuer.
+ names[i].san.size);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
+ }
+
+ ret = _gnutls_x509_der_encode(c2, "", ext, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ asn1_delete_structure(&c2);
+ return ret;
+
+}
+
+/**
+ * gnutls_x509_ext_get_key_usage:
+ * @ext: the DER encoded extension data
+ * @key_usage: where the key usage bits will be stored
+ *
+ * This function will return certificate's key usage, by reading the DER
+ * data of 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.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_get_key_usage(const gnutls_datum_t * ext,
+ unsigned int *key_usage)
+{
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ int len, result;
+ uint8_t str[2];
+
+ str[0] = str[1] = 0;
+ *key_usage = 0;
+
+ if ((result = asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.KeyUsage", &c2)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ result = asn1_der_decoding(&c2, ext->data, ext->size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ asn1_delete_structure(&c2);
+ return _gnutls_asn2err(result);
+ }
+
+ len = sizeof(str);
+ result = asn1_read_value(c2, "", str, &len);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ asn1_delete_structure(&c2);
+ return 0;
+ }
+
+ *key_usage = str[0] | (str[1] << 8);
+
+ asn1_delete_structure(&c2);
+
+ return 0;
+}
+
+/**
+ * gnutls_x509_ext_set_key_usage:
+ * @usage: an ORed sequence of the GNUTLS_KEY_* elements.
+ * @ext: The DER-encoded extension data; must be freed using gnutls_free().
+ *
+ * This function will convert the keyUsage bit string to a DER
+ * encoded PKIX extension. The @ext data will be allocated using
+ * gnutls_malloc().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_set_key_usage(unsigned int usage, gnutls_datum_t * ext)
+{
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ int result;
+ uint8_t str[2];
+
+ result = asn1_create_element(_gnutls_get_pkix(), "PKIX1.KeyUsage", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ str[0] = usage & 0xff;
+ str[1] = usage >> 8;
+
+ result = asn1_write_value(c2, "", str, 9);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ asn1_delete_structure(&c2);
+ return _gnutls_asn2err(result);
+ }
+
+ result = _gnutls_x509_der_encode(c2, "", ext, 0);
+
+ asn1_delete_structure(&c2);
+
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_x509_ext_get_private_key_usage_period:
+ * @ext: the DER encoded extension data
+ * @activation: Will hold the activation time
+ * @expiration: Will hold the expiration time
+ *
+ * This function will return the expiration and activation
+ * times of the private key as written in the
+ * PKIX extension 2.5.29.16.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_get_private_key_usage_period(const gnutls_datum_t * ext,
+ time_t * activation,
+ time_t * expiration)
+{
+ int result, ret;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+
+ result = asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.PrivateKeyUsagePeriod", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = asn1_der_decoding(&c2, ext->data, ext->size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if (activation)
+ *activation = _gnutls_x509_get_time(c2, "notBefore", 1);
+
+ if (expiration)
+ *expiration = _gnutls_x509_get_time(c2, "notAfter", 1);
+
+ ret = 0;
+
+ cleanup:
+ asn1_delete_structure(&c2);
+
+ return ret;
+}
+
+/**
+ * gnutls_x509_ext_set_private_key_usage_period:
+ * @activation: The activation time
+ * @expiration: The expiration time
+ * @ext: The DER-encoded extension data; must be freed using gnutls_free().
+ *
+ * This function will convert the periods provided to a private key
+ * usage DER encoded extension (2.5.29.16).
+ (
+ * The @ext data will be allocated using
+ * gnutls_malloc().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_set_private_key_usage_period(time_t activation,
+ time_t expiration,
+ gnutls_datum_t * ext)
+{
+ int result;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+
+ result =
+ asn1_create_element(_gnutls_get_pkix(),
+ "PKIX1.PrivateKeyUsagePeriod", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ result = _gnutls_x509_set_time(c2, "notBefore", activation, 1);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ result = _gnutls_x509_set_time(c2, "notAfter", expiration, 1);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ result = _gnutls_x509_der_encode(c2, "", ext, 0);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ cleanup:
+ asn1_delete_structure(&c2);
+
+ return result;
+
+}
+
+/**
+ * gnutls_x509_ext_get_basic_constraints:
+ * @ext: the DER encoded extension data
+ * @ca: will be non zero if the CA status is true
+ * @pathlen: the path length constraint; will be set to -1 for no limit
+ *
+ * This function will return the CA status and path length constraint
+ * as written in the PKIX extension 2.5.29.19.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_get_basic_constraints(const gnutls_datum_t * ext,
+ unsigned int *ca, int *pathlen)
+{
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ char str[128];
+ int len, result;
+
+ if ((result = asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.BasicConstraints",
+ &c2)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ result = asn1_der_decoding(&c2, ext->data, ext->size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if (pathlen) {
+ result = _gnutls_x509_read_uint(c2, "pathLenConstraint",
+ (unsigned int *)
+ pathlen);
+ if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
+ *pathlen = -1;
+ else if (result != GNUTLS_E_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+ }
+
+ /* the default value of cA is false.
+ */
+ len = sizeof(str) - 1;
+ result = asn1_read_value(c2, "cA", str, &len);
+ if (result == ASN1_SUCCESS && strcmp(str, "TRUE") == 0)
+ *ca = 1;
+ else
+ *ca = 0;
+
+ result = 0;
+ cleanup:
+ asn1_delete_structure(&c2);
+
+ return result;
+
+}
+
+/**
+ * gnutls_x509_ext_set_basic_constraints:
+ * @ca: non-zero for a CA
+ * @pathlen: The path length constraint (set to -1 for no constraint)
+ * @ext: The DER-encoded extension data; must be freed using gnutls_free().
+ *
+ * This function will convert the parameters provided to a basic constraints
+ * DER encoded extension (2.5.29.19).
+ (
+ * The @ext data will be allocated using
+ * gnutls_malloc().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_set_basic_constraints(unsigned int ca, int pathlen,
+ gnutls_datum_t * ext)
+{
+ ASN1_TYPE c2 = 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", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = asn1_write_value(c2, "cA", str, 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if (pathlen < 0) {
+ result = asn1_write_value(c2, "pathLenConstraint", NULL, 0);
+ if (result < 0)
+ result = _gnutls_asn2err(result);
+ } else
+ result =
+ _gnutls_x509_write_uint32(c2, "pathLenConstraint", pathlen);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ result = _gnutls_x509_der_encode(c2, "", ext, 0);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ result = 0;
+
+ cleanup:
+ asn1_delete_structure(&c2);
+ return result;
+
+}
+
+/**
+ * gnutls_x509_ext_get_proxy:
+ * @ext: the DER encoded extension data
+ * @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 return the information from a proxy certificate
+ * extension. 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 value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_get_proxy(const gnutls_datum_t * ext, int *pathlen,
+ char **policyLanguage, char **policy,
+ size_t * sizeof_policy)
+{
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ int result;
+ gnutls_datum_t value = { NULL, 0 };
+
+ if ((result = asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.ProxyCertInfo",
+ &c2)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ result = asn1_der_decoding(&c2, ext->data, ext->size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if (pathlen) {
+ result = _gnutls_x509_read_uint(c2, "pCPathLenConstraint",
+ (unsigned int *)
+ pathlen);
+ if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
+ *pathlen = -1;
+ else if (result != GNUTLS_E_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+ }
+
+ result = _gnutls_x509_read_value(c2, "proxyPolicy.policyLanguage",
+ &value);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if (policyLanguage) {
+ *policyLanguage = (char *)value.data;
+ } else {
+ gnutls_free(value.data);
+ value.data = NULL;
+ }
+
+ result = _gnutls_x509_read_value(c2, "proxyPolicy.policy", &value);
+ if (result == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) {
+ if (policy)
+ *policy = NULL;
+ if (sizeof_policy)
+ *sizeof_policy = 0;
+ } else if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ } else {
+ if (policy) {
+ *policy = (char *)value.data;
+ }
+ if (sizeof_policy)
+ *sizeof_policy = value.size;
+ }
+
+ result = 0;
+ cleanup:
+ gnutls_free(value.data);
+ asn1_delete_structure(&c2);
+
+ return result;
+}
+
+/**
+ * gnutls_x509_ext_set_proxy:
+ * @pathLenConstraint: non-negative error codes indicate maximum length of path,
+ * and negative error codes indicate that the pathLenConstraints field should
+ * not be present.
+ * @policyLanguage: OID describing the language of @policy.
+ * @policy: uint8_t byte array with policy language, can be %NULL
+ * @sizeof_policy: size of @policy.
+ * @ext: The DER-encoded extension data; must be freed using gnutls_free().
+ *
+ * This function will convert the parameters provided to a proxyCertInfo extension.
+ *
+ * The @ext data will be allocated using
+ * gnutls_malloc().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_set_proxy(int pathLenConstraint, const char *policyLanguage,
+ const char *policy, size_t sizeof_policy,
+ gnutls_datum_t * ext)
+{
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ int result;
+
+ result = asn1_create_element(_gnutls_get_pkix(),
+ "PKIX1.ProxyCertInfo", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ if (pathLenConstraint < 0) {
+ result = asn1_write_value(c2, "pCPathLenConstraint", NULL, 0);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+ } else {
+ result =
+ _gnutls_x509_write_uint32(c2, "pCPathLenConstraint",
+ pathLenConstraint);
+
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
+
+ result = asn1_write_value(c2, "proxyPolicy.policyLanguage",
+ policyLanguage, 1);
+ if (result < 0) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = asn1_write_value(c2, "proxyPolicy.policy",
+ policy, sizeof_policy);
+ if (result < 0) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result = _gnutls_x509_der_encode(c2, "", ext, 0);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ result = 0;
+ cleanup:
+ asn1_delete_structure(&c2);
+ return result;
+
+}
+
+static int decode_user_notice(const void *data, size_t size,
+ gnutls_datum_t * txt)
+{
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ int ret, len;
+ char choice_type[64];
+ char name[128];
+ gnutls_datum_t td, utd;
+
+ ret = asn1_create_element(_gnutls_get_pkix(), "PKIX1.UserNotice", &c2);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = GNUTLS_E_PARSING_ERROR;
+ goto cleanup;
+ }
+
+ ret = asn1_der_decoding(&c2, data, size, NULL);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = GNUTLS_E_PARSING_ERROR;
+ goto cleanup;
+ }
+
+ len = sizeof(choice_type);
+ ret = asn1_read_value(c2, "explicitText", choice_type, &len);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = GNUTLS_E_PARSING_ERROR;
+ goto cleanup;
+ }
+
+ if (strcmp(choice_type, "utf8String") != 0
+ && strcmp(choice_type, "IA5String") != 0
+ && strcmp(choice_type, "bmpString") != 0
+ && strcmp(choice_type, "visibleString") != 0) {
+ gnutls_assert();
+ ret = GNUTLS_E_PARSING_ERROR;
+ goto cleanup;
+ }
+
+ snprintf(name, sizeof(name), "explicitText.%s", choice_type);
+
+ ret = _gnutls_x509_read_value(c2, name, &td);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ if (strcmp(choice_type, "bmpString") == 0) { /* convert to UTF-8 */
+ ret = _gnutls_ucs2_to_utf8(td.data, td.size, &utd);
+ _gnutls_free_datum(&td);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ td.data = utd.data;
+ td.size = utd.size;
+ } else {
+ /* _gnutls_x509_read_value allows that */
+ td.data[td.size] = 0;
+ }
+
+ txt->data = (void *)td.data;
+ txt->size = td.size;
+ ret = 0;
+
+ cleanup:
+ asn1_delete_structure(&c2);
+ return ret;
+
+}
+
+struct gnutls_x509_policies_st {
+ struct gnutls_x509_policy_st policy[MAX_ENTRIES];
+ unsigned int size;
+};
+
+/**
+ * gnutls_x509_policies_init:
+ * @policies: The authority key ID structure
+ *
+ * This function will initialize an authority key ID structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_policies_init(gnutls_x509_policies_t * policies)
+{
+ *policies = gnutls_calloc(1, sizeof(struct gnutls_x509_policies_st));
+ if (*policies == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ return 0;
+}
+
+/**
+ * gnutls_x509_policies_deinit:
+ * @policies: The authority key identifier structure
+ *
+ * This function will deinitialize an authority key identifier structure.
+ *
+ * Since: 3.3.0
+ **/
+void gnutls_x509_policies_deinit(gnutls_x509_policies_t policies)
+{
+ unsigned i;
+
+ for (i = 0; i < policies->size; i++)
+ gnutls_x509_policy_release(&policies->policy[i]);
+ gnutls_free(policies);
+}
+
+/**
+ * gnutls_x509_policies_get:
+ * @policies: The policies structure
+ * @seq: The index of the name to get
+ * @policy: Will hold the policy
+ *
+ * This function will return a specific policy as stored in
+ * the @policies structure. The returned values should be treated as constant
+ * and valid for the lifetime of @policies.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+ * if the index is out of bounds, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_policies_get(gnutls_x509_policies_t policies,
+ unsigned int seq,
+ struct gnutls_x509_policy_st *policy)
+{
+ if (seq >= policies->size)
+ return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+
+ if (policy) {
+ memcpy(policy, &policies->policy[seq],
+ sizeof(struct gnutls_x509_policy_st));
+ }
+
+ return 0;
+}
+
+void _gnutls_x509_policies_erase(gnutls_x509_policies_t policies,
+ unsigned int seq)
+{
+ if (seq >= policies->size)
+ return;
+
+ memset(&policies->policy[seq], 0, sizeof(struct gnutls_x509_policy_st));
+}
+
+/**
+ * gnutls_x509_policies_set:
+ * @policies: An initialized policies structure
+ * @seq: The index of the name to get
+ * @policy: Contains the policy to set
+ *
+ * This function will store the specified policy in
+ * the provided @policies structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0), otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_policies_set(gnutls_x509_policies_t policies,
+ const struct gnutls_x509_policy_st *policy)
+{
+ unsigned i;
+
+ if (policies->size + 1 > MAX_ENTRIES)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ policies->policy[policies->size].oid = gnutls_strdup(policy->oid);
+ if (policies->policy[policies->size].oid == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ for (i = 0; i < policy->qualifiers; i++) {
+ policies->policy[policies->size].qualifier[i].type =
+ policy->qualifier[i].type;
+ policies->policy[policies->size].qualifier[i].size =
+ policy->qualifier[i].size;
+ policies->policy[policies->size].qualifier[i].data =
+ gnutls_malloc(policy->qualifier[i].size + 1);
+ if (policies->policy[policies->size].qualifier[i].data == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ memcpy(policies->policy[policies->size].qualifier[i].data,
+ policy->qualifier[i].data, policy->qualifier[i].size);
+ policies->policy[policies->size].qualifier[i].data[policy->
+ qualifier[i].
+ size] = 0;
+ }
+
+ policies->policy[policies->size].qualifiers = policy->qualifiers;
+ policies->size++;
+
+ return 0;
+}
+
+/**
+ * gnutls_x509_ext_get_policies:
+ * @ext: the DER encoded extension data
+ * @policies: A pointer to an initialized policies structures.
+ * @flags: should be zero
+ *
+ * This function will extract the certificate policy extension (2.5.29.32)
+ * and store it the provided structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_get_policies(const gnutls_datum_t * ext,
+ gnutls_x509_policies_t policies,
+ unsigned int flags)
+{
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ char tmpstr[128];
+ char tmpoid[MAX_OID_SIZE];
+ gnutls_datum_t tmpd = { NULL, 0 };
+ int ret, len;
+ unsigned i, j, current = 0;
+
+ ret = asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.certificatePolicies", &c2);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+
+ ret = asn1_der_decoding(&c2, ext->data, ext->size, NULL);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+
+ for (j = 0;; j++) {
+ if (j >= MAX_ENTRIES)
+ break;
+
+ memset(&policies->policy[j], 0,
+ sizeof(struct gnutls_x509_policy_st));
+
+ /* create a string like "?1"
+ */
+ snprintf(tmpstr, sizeof(tmpstr), "?%u.policyIdentifier", j + 1);
+ current = j;
+
+ ret = _gnutls_x509_read_value(c2, tmpstr, &tmpd);
+ if (ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
+ break;
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto full_cleanup;
+ }
+
+ policies->policy[j].oid = (void *)tmpd.data;
+ tmpd.data = NULL;
+
+ for (i = 0; i < GNUTLS_MAX_QUALIFIERS; i++) {
+ gnutls_datum_t td;
+
+ snprintf(tmpstr, sizeof(tmpstr),
+ "?%u.policyQualifiers.?%u.policyQualifierId",
+ j + 1, i + 1);
+
+ len = sizeof(tmpoid);
+ ret = asn1_read_value(c2, tmpstr, tmpoid, &len);
+
+ if (ret == ASN1_ELEMENT_NOT_FOUND)
+ break; /* finished */
+
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+
+ if (strcmp(tmpoid, "1.3.6.1.5.5.7.2.1") == 0) {
+ snprintf(tmpstr, sizeof(tmpstr),
+ "?%u.policyQualifiers.?%u.qualifier",
+ j + 1, i + 1);
+
+ ret =
+ _gnutls_x509_read_string(c2, tmpstr, &td,
+ ASN1_ETYPE_IA5_STRING);
+ if (ret < 0) {
+ gnutls_assert();
+ goto full_cleanup;
+ }
+
+ policies->policy[j].qualifier[i].data =
+ (void *)td.data;
+ policies->policy[j].qualifier[i].size = td.size;
+ td.data = NULL;
+ policies->policy[j].qualifier[i].type =
+ GNUTLS_X509_QUALIFIER_URI;
+ } else if (strcmp(tmpoid, "1.3.6.1.5.5.7.2.2") == 0) {
+ gnutls_datum_t txt;
+
+ snprintf(tmpstr, sizeof(tmpstr),
+ "?%u.policyQualifiers.?%u.qualifier",
+ j + 1, i + 1);
+
+ ret = _gnutls_x509_read_value(c2, tmpstr, &td);
+ if (ret < 0) {
+ gnutls_assert();
+ goto full_cleanup;
+ }
+
+ ret =
+ decode_user_notice(td.data, td.size, &txt);
+ gnutls_free(td.data);
+ td.data = NULL;
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto full_cleanup;
+ }
+
+ policies->policy[j].qualifier[i].data =
+ (void *)txt.data;
+ policies->policy[j].qualifier[i].size =
+ txt.size;
+ policies->policy[j].qualifier[i].type =
+ GNUTLS_X509_QUALIFIER_NOTICE;
+ } else
+ policies->policy[j].qualifier[i].type =
+ GNUTLS_X509_QUALIFIER_UNKNOWN;
+
+ policies->policy[j].qualifiers++;
+ }
+
+ }
+
+ policies->size = j;
+
+ ret = 0;
+ goto cleanup;
+
+ full_cleanup:
+ for (j = 0; j < current; j++)
+ gnutls_x509_policy_release(&policies->policy[j]);
+
+ cleanup:
+ _gnutls_free_datum(&tmpd);
+ asn1_delete_structure(&c2);
+ return ret;
+
+}
+
+static int encode_user_notice(const gnutls_datum_t * txt,
+ gnutls_datum_t * der_data)
+{
+ int result;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+
+ if ((result =
+ asn1_create_element(_gnutls_get_pkix(),
+ "PKIX1.UserNotice", &c2)) != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ /* delete noticeRef */
+ result = asn1_write_value(c2, "noticeRef", NULL, 0);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ result = asn1_write_value(c2, "explicitText", "utf8String", 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ result =
+ asn1_write_value(c2, "explicitText.utf8String", txt->data,
+ txt->size);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto error;
+ }
+
+ result = _gnutls_x509_der_encode(c2, "", der_data, 0);
+ if (result < 0) {
+ gnutls_assert();
+ goto error;
+ }
+
+ result = 0;
+
+ error:
+ asn1_delete_structure(&c2);
+ return result;
+
+}
+
+/**
+ * gnutls_x509_ext_set_policies:
+ * @policies: A pointer to an initialized policies structure.
+ * @ext: The DER-encoded extension data; must be freed using gnutls_free().
+ *
+ * This function will convert the provided policies, to a certificate policy
+ * DER encoded extension (2.5.29.32).
+ *
+ * The @ext data will be allocated using gnutls_malloc().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_set_policies(gnutls_x509_policies_t policies,
+ gnutls_datum_t * ext)
+{
+ int result;
+ unsigned i, j;
+ gnutls_datum_t der_data, tmpd;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ const char *oid;
+
+ result =
+ asn1_create_element(_gnutls_get_pkix(),
+ "PKIX1.certificatePolicies", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ for (j = 0; j < policies->size; j++) {
+ /* 1. write a new policy */
+ result = asn1_write_value(c2, "", "NEW", 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ /* 2. Add the OID.
+ */
+ result =
+ asn1_write_value(c2, "?LAST.policyIdentifier",
+ policies->policy[j].oid, 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ for (i = 0;
+ i < MIN(policies->policy[j].qualifiers,
+ GNUTLS_MAX_QUALIFIERS); i++) {
+ result =
+ asn1_write_value(c2, "?LAST.policyQualifiers",
+ "NEW", 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if (policies->policy[j].qualifier[i].type ==
+ GNUTLS_X509_QUALIFIER_URI)
+ oid = "1.3.6.1.5.5.7.2.1";
+ else if (policies->policy[j].qualifier[i].type ==
+ GNUTLS_X509_QUALIFIER_NOTICE)
+ oid = "1.3.6.1.5.5.7.2.2";
+ else {
+ result =
+ gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ goto cleanup;
+ }
+
+ result =
+ asn1_write_value(c2,
+ "?LAST.policyQualifiers.?LAST.policyQualifierId",
+ oid, 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if (policies->policy[j].qualifier[i].type ==
+ GNUTLS_X509_QUALIFIER_URI) {
+ tmpd.data =
+ (void *)policies->policy[j].qualifier[i].
+ data;
+ tmpd.size =
+ policies->policy[j].qualifier[i].size;
+ result =
+ _gnutls_x509_write_string(c2,
+ "?LAST.policyQualifiers.?LAST.qualifier",
+ &tmpd,
+ ASN1_ETYPE_IA5_STRING);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ } else if (policies->policy[j].qualifier[i].type ==
+ GNUTLS_X509_QUALIFIER_NOTICE) {
+ tmpd.data =
+ (void *)policies->policy[j].qualifier[i].
+ data;
+ tmpd.size =
+ policies->policy[j].qualifier[i].size;
+
+ if (tmpd.size > 200) {
+ gnutls_assert();
+ result = GNUTLS_E_INVALID_REQUEST;
+ goto cleanup;
+ }
+
+ result = encode_user_notice(&tmpd, &der_data);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ result =
+ _gnutls_x509_write_value(c2,
+ "?LAST.policyQualifiers.?LAST.qualifier",
+ &der_data);
+ _gnutls_free_datum(&der_data);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
+ }
+ }
+
+ result = _gnutls_x509_der_encode(c2, "", ext, 0);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ cleanup:
+ asn1_delete_structure(&c2);
+
+ return result;
+}
+
+struct crl_dist_point_st {
+ unsigned int type;
+ gnutls_datum_t san;
+ unsigned int reasons;
+};
+
+struct gnutls_x509_crl_dist_points_st {
+ struct crl_dist_point_st *points;
+ unsigned int size;
+};
+
+/**
+ * gnutls_x509_crl_dist_points_init:
+ * @cdp: The CRL distribution points structure
+ *
+ * This function will initialize a CRL distribution points structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_crl_dist_points_init(gnutls_x509_crl_dist_points_t * cdp)
+{
+ *cdp = gnutls_calloc(1, sizeof(struct gnutls_x509_crl_dist_points_st));
+ if (*cdp == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ return 0;
+}
+
+/**
+ * gnutls_x509_crl_dist_points_deinit:
+ * @cdp: The CRL distribution points structure
+ *
+ * This function will deinitialize a CRL distribution points structure.
+ *
+ * Since: 3.3.0
+ **/
+void gnutls_x509_crl_dist_points_deinit(gnutls_x509_crl_dist_points_t cdp)
+{
+ unsigned i;
+
+ for (i = 0; i < cdp->size; i++) {
+ gnutls_free(cdp->points[i].san.data);
+ }
+ gnutls_free(cdp->points);
+ gnutls_free(cdp);
+}
+
+/**
+ * gnutls_x509_crl_dist_points_get:
+ * @cdp: The CRL distribution points structure
+ * @seq: specifies the sequence number of the distribution point (0 for the first one, 1 for the second etc.)
+ * @type: The name type of the corresponding name (gnutls_x509_subject_alt_name_t)
+ * @san: The distribution point names (to be treated as constant)
+ * @reasons: Revocation reasons. An ORed sequence of flags from %gnutls_x509_crl_reason_flags_t.
+ *
+ * This function retrieves the individual CRL distribution points (2.5.29.31),
+ * contained in provided structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+ * if the index is out of bounds, otherwise a negative error value.
+ **/
+
+int gnutls_x509_crl_dist_points_get(gnutls_x509_crl_dist_points_t cdp,
+ unsigned int seq, unsigned int *type,
+ gnutls_datum_t * san, unsigned int *reasons)
+{
+ if (seq >= cdp->size)
+ return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+
+ if (reasons)
+ *reasons = cdp->points[seq].reasons;
+
+ if (type)
+ *type = cdp->points[seq].type;
+
+ if (san) {
+ san->data = cdp->points[seq].san.data;
+ san->size = cdp->points[seq].san.size;
+ }
+
+ return 0;
+}
+
+static
+int crl_dist_points_set(gnutls_x509_crl_dist_points_t cdp,
+ gnutls_x509_subject_alt_name_t type,
+ const gnutls_datum_t * san, unsigned int reasons)
+{
+ void *tmp;
+
+ /* new dist point */
+ tmp =
+ gnutls_realloc(cdp->points,
+ (cdp->size + 1) * sizeof(cdp->points[0]));
+ if (tmp == NULL) {
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ }
+ cdp->points = tmp;
+
+ cdp->points[cdp->size].type = type;
+ cdp->points[cdp->size].san.data = san->data;
+ cdp->points[cdp->size].san.size = san->size;
+ cdp->points[cdp->size].reasons = reasons;
+
+ cdp->size++;
+ return 0;
+
+}
+
+/**
+ * gnutls_x509_crl_dist_points_set:
+ * @cdp: The CRL distribution points structure
+ * @type: The type of the name (of %gnutls_subject_alt_names_t)
+ * @san: The point name data
+ * @reasons: Revocation reasons. An ORed sequence of flags from %gnutls_x509_crl_reason_flags_t.
+ *
+ * This function will store the specified CRL distibution point value
+ * the @cdp structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0), otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_crl_dist_points_set(gnutls_x509_crl_dist_points_t cdp,
+ gnutls_x509_subject_alt_name_t type,
+ const gnutls_datum_t * san,
+ unsigned int reasons)
+{
+ int ret;
+ gnutls_datum_t t_san;
+
+ ret = _gnutls_set_datum(&t_san, san->data, san->size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ ret = crl_dist_points_set(cdp, type, &t_san, reasons);
+ if (ret < 0) {
+ gnutls_free(t_san.data);
+ return gnutls_assert_val(ret);
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_x509_ext_get_crl_dist_points:
+ * @ext: the DER encoded extension data
+ * @cdp: A pointer to an initialized CRL distribution points structure.
+ * @flags: should be zero
+ *
+ * This function will extract the CRL distribution points extension (2.5.29.31)
+ * and store it into the provided structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_get_crl_dist_points(const gnutls_datum_t * ext,
+ gnutls_x509_crl_dist_points_t cdp,
+ unsigned int flags)
+{
+ int result;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ char name[ASN1_MAX_NAME_SIZE];
+ int len, ret;
+ uint8_t reasons[2];
+ unsigned i, type, rflags, j;
+ gnutls_datum_t san;
+
+ result = asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.CRLDistributionPoints", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ result = asn1_der_decoding(&c2, ext->data, ext->size, NULL);
+
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ /* Return the different names from the first CRLDistr. point.
+ * The whole thing is a mess.
+ */
+
+ i = 0;
+ do {
+ san.data = NULL;
+
+ snprintf(name, sizeof(name), "?%u.reasons", (unsigned)i + 1);
+
+ len = sizeof(reasons);
+ result = asn1_read_value(c2, name, reasons, &len);
+
+ if (result != ASN1_VALUE_NOT_FOUND &&
+ result != ASN1_ELEMENT_NOT_FOUND &&
+ result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ break;
+ }
+
+ if (result == ASN1_VALUE_NOT_FOUND
+ || result == ASN1_ELEMENT_NOT_FOUND)
+ rflags = 0;
+ else
+ rflags = reasons[0] | (reasons[1] << 8);
+
+ snprintf(name, sizeof(name),
+ "?%u.distributionPoint.fullName", (unsigned)i + 1);
+
+ j = 0;
+ do {
+ ret =
+ _gnutls_parse_general_name2(c2, name, j, &san,
+ &type, 0);
+ if (j > 0
+ && ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ ret = 0;
+ break;
+ }
+ if (ret < 0)
+ break;
+
+ ret = crl_dist_points_set(cdp, type, &san, rflags);
+ if (ret < 0)
+ break;
+
+ j++;
+ } while (ret >= 0);
+
+ i++;
+ } while (ret >= 0);
+
+ if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ gnutls_assert();
+ gnutls_free(san.data);
+ goto cleanup;
+ }
+
+ ret = 0;
+ cleanup:
+ asn1_delete_structure(&c2);
+ return ret;
+}
+
+/**
+ * gnutls_x509_ext_set_crl_dist_points:
+ * @cdp: A pointer to an initialized CRL distribution points structure.
+ * @ext: The DER-encoded extension data; must be freed using gnutls_free().
+ *
+ * This function will convert the provided policies, to a certificate policy
+ * DER encoded extension (2.5.29.31).
+ *
+ * The @ext data will be allocated using gnutls_malloc().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_set_crl_dist_points(gnutls_x509_crl_dist_points_t cdp,
+ gnutls_datum_t * ext)
+{
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ int result;
+ uint8_t reasons[2];
+ unsigned i;
+
+ result =
+ asn1_create_element(_gnutls_get_pkix(),
+ "PKIX1.CRLDistributionPoints", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ for (i = 0; i < cdp->size; i++) {
+
+ if (i == 0
+ || cdp->points[i].reasons != cdp->points[i - 1].reasons) {
+ result = asn1_write_value(c2, "", "NEW", 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ if (cdp->points[i].reasons) {
+ reasons[0] = cdp->points[i].reasons & 0xff;
+ reasons[1] = cdp->points[i].reasons >> 8;
+
+ result =
+ asn1_write_value(c2, "?LAST.reasons",
+ reasons, 2);
+ } else {
+ result =
+ asn1_write_value(c2, "?LAST.reasons", NULL,
+ 0);
+ }
+
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ result =
+ asn1_write_value(c2, "?LAST.cRLIssuer", NULL, 0);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+ /* When used as type CHOICE.
+ */
+ result =
+ asn1_write_value(c2, "?LAST.distributionPoint",
+ "fullName", 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ result = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+ }
+
+ result =
+ _gnutls_write_new_general_name(c2,
+ "?LAST.distributionPoint.fullName",
+ cdp->points[i].type,
+ cdp->points[i].san.data,
+ cdp->points[i].san.size);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
+
+ result = _gnutls_x509_der_encode(c2, "", ext, 0);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ result = 0;
+
+ cleanup:
+ asn1_delete_structure(&c2);
+
+ return result;
+
+}
+
+struct gnutls_x509_aia_st {
+ struct {
+ gnutls_datum_t oid;
+ unsigned int san_type;
+ gnutls_datum_t san;
+ } *aia;
+ unsigned int size;
+};
+
+/**
+ * gnutls_x509_aia_init:
+ * @aia: The authority info access structure
+ *
+ * This function will initialize a CRL distribution points structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_aia_init(gnutls_x509_aia_t * aia)
+{
+ *aia = gnutls_calloc(1, sizeof(struct gnutls_x509_aia_st));
+ if (*aia == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ return 0;
+}
+
+/**
+ * gnutls_x509_aia_deinit:
+ * @aia: The authority info access structure
+ *
+ * This function will deinitialize a CRL distribution points structure.
+ *
+ * Since: 3.3.0
+ **/
+void gnutls_x509_aia_deinit(gnutls_x509_aia_t aia)
+{
+ unsigned i;
+
+ for (i = 0; i < aia->size; i++) {
+ gnutls_free(aia->aia[i].san.data);
+ gnutls_free(aia->aia[i].oid.data);
+ }
+ gnutls_free(aia->aia);
+ gnutls_free(aia);
+}
+
+/**
+ * gnutls_x509_aia_get:
+ * @aia: The authority info access structure
+ * @seq: specifies the sequence number of the access descriptor (0 for the first one, 1 for the second etc.)
+ * @oid: the type of available data; to be treated as constant.
+ * @san_type: Will hold the type of the name of %gnutls_subject_alt_names_t (may be null).
+ * @san: the access location name; to be treated as constant (may be null).
+ *
+ * This function reads from the Authority Information Access structure.
+ *
+ * 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.
+ *
+ * Typically @oid is %GNUTLS_OID_AD_CAISSUERS or %GNUTLS_OID_AD_OCSP.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_aia_get(gnutls_x509_aia_t aia, unsigned int seq,
+ gnutls_datum_t *oid,
+ unsigned *san_type,
+ gnutls_datum_t *san)
+{
+ if (seq >= aia->size)
+ return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+
+ if (san_type)
+ *san_type = aia->aia[seq].san_type;
+ if (san) {
+ san->data = aia->aia[seq].san.data;
+ san->size = aia->aia[seq].san.size;
+ }
+
+ if (oid) {
+ oid->data = aia->aia[seq].oid.data;
+ oid->size = aia->aia[seq].oid.size;
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_x509_aia_set:
+ * @aia: The authority info access structure
+ * @oid: the type of data.
+ * @san_type: The type of the name (of %gnutls_subject_alt_names_t)
+ * @san: The alternative name data
+ * @othername_oid: The object identifier if @san_type is %GNUTLS_SAN_OTHERNAME
+ *
+ * This function will store the specified alternative name in
+ * the @aia structure.
+ *
+ * Typically the value for @oid should be %GNUTLS_OID_AD_OCSP, or
+ * %GNUTLS_OID_AD_CAISSUERS.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0), otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_aia_set(gnutls_x509_aia_t aia,
+ const char *oid,
+ unsigned san_type,
+ const gnutls_datum_t * san)
+{
+ int ret;
+ void *tmp;
+ unsigned indx;
+
+ tmp = gnutls_realloc(aia->aia, (aia->size + 1) * sizeof(aia->aia[0]));
+ if (tmp == NULL) {
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ }
+ aia->aia = tmp;
+ indx = aia->size;
+
+ aia->aia[indx].san_type = san_type;
+ if (oid) {
+ aia->aia[indx].oid.data = (void*)gnutls_strdup(oid);
+ aia->aia[indx].oid.size = strlen(oid);
+ } else {
+ aia->aia[indx].oid.data = NULL;
+ aia->aia[indx].oid.size = 0;
+ }
+
+ ret = _gnutls_set_datum(&aia->aia[indx].san, san->data, san->size);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ aia->size++;
+
+ return 0;
+}
+
+
+static int parse_aia(ASN1_TYPE c2, gnutls_x509_aia_t aia)
+{
+ int len;
+ char nptr[ASN1_MAX_NAME_SIZE];
+ int ret, result;
+ char tmpoid[MAX_OID_SIZE];
+ void * tmp;
+ unsigned i, indx;
+
+ for (i = 1;; i++) {
+ snprintf(nptr, sizeof(nptr), "?%u.accessMethod", i);
+
+ len = sizeof(tmpoid);
+ result = asn1_read_value(c2, nptr, tmpoid, &len);
+ if (result == ASN1_VALUE_NOT_FOUND
+ || result == ASN1_ELEMENT_NOT_FOUND) {
+ ret = GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ break;
+ }
+
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ indx = aia->size;
+ tmp = gnutls_realloc(aia->aia, (aia->size + 1) * sizeof(aia->aia[0]));
+ if (tmp == NULL) {
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+ }
+ aia->aia = tmp;
+
+ aia->aia[indx].oid.data = (void*)gnutls_strdup(tmpoid);
+ aia->aia[indx].oid.size = strlen(tmpoid);
+
+ snprintf(nptr, sizeof(nptr), "?%u.accessLocation", i);
+
+ ret = _gnutls_parse_general_name2(c2, nptr, -1, &aia->aia[indx].san,
+ &aia->aia[indx].san_type, 0);
+ if (ret < 0)
+ break;
+
+ aia->size++;
+ }
+ while (ret >= 0);
+
+ if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ return ret;
+ }
+
+ return 0;
+}
+
+/**
+ * gnutls_x509_ext_get_aia:
+ * @ext: The DER-encoded extension data
+ * @aia: The authority info access structure
+ * @flags: should be zero
+ *
+ * This function extracts the Authority Information Access (AIA)
+ * extension from the provided DER-encoded data; see RFC 5280 section 4.2.2.1
+ * for more information on the extension. The
+ * AIA extension holds a sequence of AccessDescription (AD) data.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_get_aia(const gnutls_datum_t * ext,
+ gnutls_x509_aia_t aia,
+ unsigned int flags)
+{
+ int ret;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+
+ if (ext->size == 0 || ext->data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
+ }
+
+ ret = asn1_create_element(_gnutls_get_pkix(),
+ "PKIX1.AuthorityInfoAccessSyntax", &c2);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(ret);
+ }
+
+ ret = asn1_der_decoding(&c2, ext->data, ext->size, NULL);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+
+ ret = parse_aia(c2, aia);
+ if (ret < 0) {
+ gnutls_assert();
+ }
+
+ cleanup:
+ asn1_delete_structure(&c2);
+
+ return ret;
+
+}
+
+/**
+ * gnutls_x509_ext_set_aia:
+ * @aia: The authority info access structure
+ * @ext: The DER-encoded extension data; must be freed using gnutls_free().
+ *
+ * This function will DER encode the Authority Information Access (AIA)
+ * extension; see RFC 5280 section 4.2.2.1 for more information on the
+ * extension.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_set_aia(gnutls_x509_aia_t aia,
+ gnutls_datum_t * ext)
+{
+ int ret, result;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ unsigned int i;
+
+ ret = asn1_create_element(_gnutls_get_pkix(),
+ "PKIX1.AuthorityInfoAccessSyntax", &c2);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(ret);
+ }
+
+ /* 1. create a new element.
+ */
+ for (i=0;i<aia->size;i++) {
+ result = asn1_write_value(c2, "", "NEW", 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ /* 2. Add the OID.
+ */
+ result = asn1_write_value(c2, "?LAST.accessMethod", aia->aia[i].oid.data, 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ ret =
+ _gnutls_write_general_name(c2,
+ "?LAST.accessLocation",
+ aia->aia[i].san_type,
+ aia->aia[i].san.data,
+ aia->aia[i].san.size);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
+
+ ret = _gnutls_x509_der_encode(c2, "", ext, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ cleanup:
+ asn1_delete_structure(&c2);
+
+ return ret;
+}
+
+
+struct gnutls_x509_key_purposes_st {
+ gnutls_datum_t oid[MAX_ENTRIES];
+ unsigned int size;
+};
+
+/**
+ * gnutls_subject_alt_names_init:
+ * @p: The key purposes structure
+ *
+ * This function will initialize an alternative names structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_key_purpose_init(gnutls_x509_key_purposes_t * p)
+{
+ *p = gnutls_calloc(1, sizeof(struct gnutls_x509_key_purposes_st));
+ if (*p == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ return 0;
+}
+
+static void key_purposes_deinit(gnutls_x509_key_purposes_t p)
+{
+ unsigned int i;
+
+ for (i = 0; i < p->size; i++) {
+ gnutls_free(p->oid[i].data);
+ }
+}
+
+/**
+ * gnutls_x509_key_purpose_deinit:
+ * @p: The key purposes structure
+ *
+ * This function will deinitialize an alternative names structure.
+ *
+ * Since: 3.3.0
+ **/
+void gnutls_x509_key_purpose_deinit(gnutls_x509_key_purposes_t p)
+{
+ key_purposes_deinit(p);
+ gnutls_free(p);
+}
+
+/**
+ * gnutls_x509_key_purpose_set:
+ * @p: The key purposes structure
+ * @oid: The object identifier of the key purpose
+ *
+ * This function will store the specified key purpose in the
+ * purposes structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0), otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_key_purpose_set(gnutls_x509_key_purposes_t p, const char *oid)
+{
+ if (p->size + 1 > MAX_ENTRIES)
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+
+ p->oid[p->size].data = (void*)gnutls_strdup(oid);
+ if (p->oid[p->size].data == NULL)
+ return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
+
+ p->oid[p->size].size = strlen(oid);
+ p->size++;
+
+ return 0;
+}
+
+/**
+ * gnutls_x509_key_purpose_get:
+ * @p: The key purposes structure
+ * @idx: The index of the key purpose to retrieve
+ * @oid: Will hold the object identifier of the key purpose (to be treated as constant)
+ *
+ * This function will retrieve the specified by the index key purpose in the
+ * purposes structure.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
+ * if the index is out of bounds, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_key_purpose_get(gnutls_x509_key_purposes_t p, unsigned idx, gnutls_datum_t *oid)
+{
+ if (idx >= p->size)
+ return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
+
+ oid->data = p->oid[idx].data;
+ oid->size = p->oid[idx].size;
+
+ return 0;
+}
+
+/**
+ * gnutls_x509_ext_get_key_purposes:
+ * @ext: The DER-encoded extension data
+ * @p: The key purposes structure
+ * @flags: should be zero
+ *
+ * This function will extract the key purposes in the provided DER-encoded
+ * ExtKeyUsageSyntax PKIX extension, to a %gnutls_x509_key_purposes_t structure.
+ * The structure must be initialized.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_get_key_purposes(const gnutls_datum_t * ext,
+ gnutls_x509_key_purposes_t p,
+ unsigned int flags)
+{
+ char tmpstr[ASN1_MAX_NAME_SIZE];
+ int result, ret;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ gnutls_datum_t oid = {NULL, 0};
+ unsigned i;
+
+ result = asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.ExtKeyUsageSyntax", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ result = asn1_der_decoding(&c2, ext->data, ext->size, NULL);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ key_purposes_deinit(p);
+ i = 0;
+ p->size = 0;
+
+ for (;i<MAX_ENTRIES;i++) {
+ /* create a string like "?1"
+ */
+ snprintf(tmpstr, sizeof(tmpstr), "?%u", i+1);
+
+ ret = _gnutls_x509_read_value(c2, tmpstr, &oid);
+ if (ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND) {
+ ret = 0;
+ break;
+ }
+
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ p->oid[i].data = oid.data;
+ p->oid[i].size = oid.size;
+
+ oid.data = NULL;
+ p->size++;
+ }
+
+ ret = 0;
+ cleanup:
+ gnutls_free(oid.data);
+ asn1_delete_structure(&c2);
+
+ return ret;
+
+}
+
+/**
+ * gnutls_x509_ext_set_key_purposes:
+ * @p: The key purposes structure
+ * @ext: The DER-encoded extension data; must be freed using gnutls_free().
+ *
+ * This function will convert the key purposes structure to a
+ * DER-encoded PKIX ExtKeyUsageSyntax (2.5.29.37) extension. The output data in
+ * @ext will be allocated usin gnutls_malloc().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int gnutls_x509_ext_set_key_purposes(gnutls_x509_key_purposes_t p,
+ gnutls_datum_t * ext)
+{
+ int result, ret;
+ ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ unsigned i;
+
+ result = asn1_create_element
+ (_gnutls_get_pkix(), "PKIX1.ExtKeyUsageSyntax", &c2);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ /* generate the extension.
+ */
+ for (i=0;i<p->size;i++) {
+ /* 1. create a new element.
+ */
+ result = asn1_write_value(c2, "", "NEW", 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+
+ /* 2. Add the OID.
+ */
+ result = asn1_write_value(c2, "?LAST", p->oid[i].data, 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(result);
+ goto cleanup;
+ }
+ }
+
+ ret = _gnutls_x509_der_encode(c2, "", ext, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
+ ret = 0;
+
+ cleanup:
+ asn1_delete_structure(&c2);
+ return ret;
+}
diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h
index 568bf3c19a..5d7630ad2c 100644
--- a/lib/x509/x509_int.h
+++ b/lib/x509/x509_int.h
@@ -24,6 +24,7 @@
#define X509_H
#include <gnutls/x509.h>
+#include <gnutls/x509-ext.h>
#include <gnutls/abstract.h>
#include <libtasn1.h>
@@ -139,6 +140,11 @@ _gnutls_parse_general_name2(ASN1_TYPE src, const char *src_name,
int seq, gnutls_datum_t *dname,
unsigned int *ret_type, int othername_oid);
+int
+_gnutls_write_new_general_name(ASN1_TYPE ext, const char *ext_name,
+ gnutls_x509_subject_alt_name_t type,
+ const void *data, unsigned int data_size);
+
/* dsa.c */
@@ -173,11 +179,6 @@ int _gnutls_asn1_encode_privkey(gnutls_pk_algorithm_t pk, ASN1_TYPE * c2,
gnutls_pk_params_st * params);
/* extensions.c */
-int _gnutls_x509_crl_get_extension(gnutls_x509_crl_t crl,
- const char *extension_id, int indx,
- gnutls_datum_t * ret,
- unsigned int *_critical);
-
int _gnutls_x509_crl_get_extension_oid(gnutls_x509_crl_t crl,
int indx, void *oid,
size_t * sizeof_oid);
@@ -187,20 +188,20 @@ int _gnutls_x509_crl_set_extension(gnutls_x509_crl_t crl,
const gnutls_datum_t * ext_data,
unsigned int critical);
-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
+_gnutls_x509_crl_get_extension(gnutls_x509_crl_t crl,
+ const char *extension_id, int indx,
+ gnutls_datum_t * data,
+ unsigned int *critical);
+
+int
+_gnutls_x509_crt_get_extension(gnutls_x509_crt_t cert,
+ const char *extension_id, int indx,
+ gnutls_datum_t * data, unsigned int *critical);
+
int _gnutls_x509_crt_get_extension_oid(gnutls_x509_crt_t cert,
int indx, void *ret,
size_t * ret_size);
-int _gnutls_x509_ext_extract_keyUsage(uint16_t * keyUsage,
- uint8_t * extnValue,
- int extnValueLen);
-int _gnutls_x509_ext_extract_basicConstraints(unsigned int *CA,
- int *pathLenConstraint,
- uint8_t * extnValue,
- int extnValueLen);
int _gnutls_x509_crt_set_extension(gnutls_x509_crt_t cert,
const char *extension_id,
const gnutls_datum_t * ext_data,
@@ -220,35 +221,13 @@ _gnutls_write_general_name(ASN1_TYPE ext, const char *ext_name,
gnutls_x509_subject_alt_name_t type,
const void *data, unsigned int data_size);
-int _gnutls_x509_ext_gen_basicConstraints(int CA, int pathLenConstraint,
- gnutls_datum_t * der_ext);
-int _gnutls_x509_ext_gen_keyUsage(uint16_t usage,
- gnutls_datum_t * der_ext);
int _gnutls_x509_ext_gen_subject_alt_name(gnutls_x509_subject_alt_name_t
type, const void *data,
unsigned int data_size,
- gnutls_datum_t * prev_der_ext,
+ const gnutls_datum_t * prev_der_ext,
gnutls_datum_t * der_ext);
-int _gnutls_x509_ext_gen_crl_dist_points(gnutls_x509_subject_alt_name_t
- type, const void *data,
- unsigned int data_size,
- unsigned int reason_flags,
- gnutls_datum_t * der_ext);
-int _gnutls_x509_ext_gen_key_id(const void *id, size_t id_size,
- gnutls_datum_t * der_data);
int _gnutls_x509_ext_gen_auth_key_id(const void *id, size_t id_size,
gnutls_datum_t * der_data);
-int _gnutls_x509_ext_extract_proxyCertInfo(int *pathLenConstraint,
- char **policyLanguage,
- char **policy,
- size_t * sizeof_policy,
- uint8_t * extnValue,
- int extnValueLen);
-int _gnutls_x509_ext_gen_proxyCertInfo(int pathLenConstraint,
- const char *policyLanguage,
- const char *policy,
- size_t sizeof_policy,
- gnutls_datum_t * der_ext);
/* mpi.c */
int _gnutls_x509_crq_get_mpis(gnutls_x509_crq_t cert,
@@ -403,4 +382,20 @@ _gnutls_x509_crt_check_revocation(gnutls_x509_crt_t cert,
int crl_list_length,
gnutls_verify_output_function func);
+typedef struct gnutls_name_constraints_st {
+ struct name_constraints_node_st * permitted;
+ struct name_constraints_node_st * excluded;
+} gnutls_name_constraints_st;
+
+typedef struct name_constraints_node_st {
+ unsigned type;
+ gnutls_datum_t name;
+ struct name_constraints_node_st *next;
+} name_constraints_node_st;
+
+int _gnutls_extract_name_constraints(ASN1_TYPE c2, const char *vstr,
+ name_constraints_node_st ** _nc);
+
+void _gnutls_x509_policies_erase(gnutls_x509_policies_t policies, unsigned int seq);
+
#endif
diff --git a/lib/x509/x509_write.c b/lib/x509/x509_write.c
index 0a9c024106..4caaca673a 100644
--- a/lib/x509/x509_write.c
+++ b/lib/x509/x509_write.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2003-2012 Free Software Foundation, Inc.
+ * Copyright (C) 2003-2014 Free Software Foundation, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
@@ -30,6 +30,7 @@
#include <gnutls_errors.h>
#include <common.h>
#include <gnutls_x509.h>
+#include <gnutls/x509-ext.h>
#include <x509_b64.h>
#include "x509_int.h"
#include <libtasn1.h>
@@ -441,9 +442,7 @@ gnutls_x509_crt_set_basic_constraints(gnutls_x509_crt_t crt,
/* generate the extension.
*/
- result =
- _gnutls_x509_ext_gen_basicConstraints(ca, pathLenConstraint,
- &der_data);
+ result = gnutls_x509_ext_set_basic_constraints(ca, pathLenConstraint, &der_data);
if (result < 0) {
gnutls_assert();
return result;
@@ -505,7 +504,7 @@ gnutls_x509_crt_set_key_usage(gnutls_x509_crt_t crt, unsigned int usage)
/* generate the extension.
*/
result =
- _gnutls_x509_ext_gen_keyUsage((uint16_t) usage, &der_data);
+ gnutls_x509_ext_set_key_usage(usage, &der_data);
if (result < 0) {
gnutls_assert();
return result;
@@ -658,6 +657,89 @@ gnutls_x509_crt_set_subject_alt_name(gnutls_x509_crt_t crt,
}
/**
+ * gnutls_x509_crt_set_issuer_alt_name:
+ * @crt: a certificate of type #gnutls_x509_crt_t
+ * @type: is one of the gnutls_x509_subject_alt_name_t enumerations
+ * @data: The data to be set
+ * @data_size: The size of data to be set
+ * @flags: GNUTLS_FSAN_SET to clear previous data or GNUTLS_FSAN_APPEND to append.
+ *
+ * This function will set the issuer alternative name certificate
+ * extension. It can set the same types as gnutls_x509_crt_set_subject_alt_name().
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.3.0
+ **/
+int
+gnutls_x509_crt_set_issuer_alt_name(gnutls_x509_crt_t crt,
+ gnutls_x509_subject_alt_name_t type,
+ const void *data,
+ unsigned int data_size,
+ unsigned int flags)
+{
+ int result;
+ gnutls_datum_t der_data = { NULL, 0 };
+ gnutls_datum_t prev_der_data = { NULL, 0 };
+ unsigned int critical = 0;
+
+ if (crt == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ /* Check if the extension already exists.
+ */
+
+ if (flags == GNUTLS_FSAN_APPEND) {
+ result =
+ _gnutls_x509_crt_get_extension(crt, "2.5.29.18", 0,
+ &prev_der_data,
+ &critical);
+ if (result < 0
+ && result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ gnutls_assert();
+ return result;
+ }
+ }
+
+ /* generate the extension.
+ */
+ result =
+ _gnutls_x509_ext_gen_subject_alt_name(type, data, data_size,
+ &prev_der_data,
+ &der_data);
+
+ if (flags == GNUTLS_FSAN_APPEND)
+ _gnutls_free_datum(&prev_der_data);
+
+ if (result < 0) {
+ gnutls_assert();
+ goto finish;
+ }
+
+ result =
+ _gnutls_x509_crt_set_extension(crt, "2.5.29.18", &der_data,
+ critical);
+
+ _gnutls_free_datum(&der_data);
+
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ crt->use_extensions = 1;
+
+ return 0;
+
+ finish:
+ _gnutls_free_datum(&prev_der_data);
+ return result;
+}
+
+/**
* gnutls_x509_crt_set_proxy:
* @crt: a certificate of type #gnutls_x509_crt_t
* @pathLenConstraint: non-negative error codes indicate maximum length of path,
@@ -688,10 +770,10 @@ gnutls_x509_crt_set_proxy(gnutls_x509_crt_t crt,
/* generate the extension.
*/
- result = _gnutls_x509_ext_gen_proxyCertInfo(pathLenConstraint,
- policyLanguage,
- policy, sizeof_policy,
- &der_data);
+ result = gnutls_x509_ext_set_proxy(pathLenConstraint,
+ policyLanguage,
+ policy, sizeof_policy,
+ &der_data);
if (result < 0) {
gnutls_assert();
return result;
@@ -730,34 +812,14 @@ gnutls_x509_crt_set_private_key_usage_period(gnutls_x509_crt_t crt,
{
int result;
gnutls_datum_t der_data;
- ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
if (crt == NULL) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
- result =
- asn1_create_element(_gnutls_get_pkix(),
- "PKIX1.PrivateKeyUsagePeriod", &c2);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- return _gnutls_asn2err(result);
- }
-
- result = _gnutls_x509_set_time(c2, "notBefore", activation, 1);
- if (result < 0) {
- gnutls_assert();
- goto cleanup;
- }
-
- result = _gnutls_x509_set_time(c2, "notAfter", expiration, 1);
- if (result < 0) {
- gnutls_assert();
- goto cleanup;
- }
-
- result = _gnutls_x509_der_encode(c2, "", &der_data, 0);
+ result = gnutls_x509_ext_set_private_key_usage_period(activation,
+ expiration, &der_data);
if (result < 0) {
gnutls_assert();
goto cleanup;
@@ -770,9 +832,7 @@ gnutls_x509_crt_set_private_key_usage_period(gnutls_x509_crt_t crt,
crt->use_extensions = 1;
- cleanup:
- asn1_delete_structure(&c2);
-
+ cleanup:
return result;
}
@@ -1008,52 +1068,70 @@ gnutls_x509_crt_set_crl_dist_points2(gnutls_x509_crt_t crt,
unsigned int data_size,
unsigned int reason_flags)
{
- int result;
+ int ret;
gnutls_datum_t der_data = { NULL, 0 };
- gnutls_datum_t oldname = { NULL, 0 };
+ gnutls_datum_t old_der = { NULL, 0 };
unsigned int critical;
+ gnutls_x509_crl_dist_points_t cdp = NULL;
+ gnutls_datum_t san;
if (crt == NULL) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
+ ret = gnutls_x509_crl_dist_points_init(&cdp);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
/* Check if the extension already exists.
*/
- result =
- _gnutls_x509_crt_get_extension(crt, "2.5.29.31", 0, &oldname,
+ ret =
+ _gnutls_x509_crt_get_extension(crt, "2.5.29.31", 0, &old_der,
&critical);
- _gnutls_free_datum(&oldname);
+ if (ret >= 0 && old_der.data != NULL) {
+ ret = gnutls_x509_ext_get_crl_dist_points(&old_der, cdp, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+ }
- if (result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ san.data = (void*)data;
+ san.size = data_size;
+ ret = gnutls_x509_crl_dist_points_set(cdp, type, &san, reason_flags);
+ if (ret < 0) {
gnutls_assert();
- return GNUTLS_E_INVALID_REQUEST;
+ goto cleanup;
}
/* generate the extension.
*/
- result =
- _gnutls_x509_ext_gen_crl_dist_points(type, data, data_size,
- reason_flags, &der_data);
- if (result < 0) {
+ ret =
+ gnutls_x509_ext_set_crl_dist_points(cdp, &der_data);
+ if (ret < 0) {
gnutls_assert();
- return result;
+ goto cleanup;
}
- result =
+ ret =
_gnutls_x509_crt_set_extension(crt, "2.5.29.31", &der_data, 0);
- _gnutls_free_datum(&der_data);
-
- if (result < 0) {
+ if (ret < 0) {
gnutls_assert();
- return result;
+ goto cleanup;
}
crt->use_extensions = 1;
+ ret = 0;
+ cleanup:
+ _gnutls_free_datum(&der_data);
+ _gnutls_free_datum(&old_der);
+ if (cdp != NULL)
+ gnutls_x509_crl_dist_points_deinit(cdp);
- return 0;
+ return ret;
}
@@ -1125,6 +1203,7 @@ gnutls_x509_crt_set_subject_key_id(gnutls_x509_crt_t cert,
{
int result;
gnutls_datum_t old_id, der_data;
+ gnutls_datum_t d_id;
unsigned int critical;
if (cert == NULL) {
@@ -1147,7 +1226,10 @@ gnutls_x509_crt_set_subject_key_id(gnutls_x509_crt_t cert,
/* generate the extension.
*/
- result = _gnutls_x509_ext_gen_key_id(id, id_size, &der_data);
+ d_id.data = (void*)id;
+ d_id.size = id_size;
+
+ result = gnutls_x509_ext_set_subject_key_id(&d_id, &der_data);
if (result < 0) {
gnutls_assert();
return result;
@@ -1250,84 +1332,63 @@ int
gnutls_x509_crt_set_key_purpose_oid(gnutls_x509_crt_t cert,
const void *oid, unsigned int critical)
{
- int result;
- gnutls_datum_t old_id, der_data;
- ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ int ret;
+ gnutls_datum_t old_id = {NULL,0};
+ gnutls_datum_t der = {NULL,0};
+ gnutls_x509_key_purposes_t p = NULL;
if (cert == NULL) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
- result = asn1_create_element
- (_gnutls_get_pkix(), "PKIX1.ExtKeyUsageSyntax", &c2);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- return _gnutls_asn2err(result);
- }
+ ret = gnutls_x509_key_purpose_init(&p);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
/* Check if the extension already exists.
*/
- result =
+ ret =
_gnutls_x509_crt_get_extension(cert, "2.5.29.37", 0, &old_id,
NULL);
- if (result >= 0) {
- /* decode it.
- */
- result =
- asn1_der_decoding(&c2, old_id.data, old_id.size, NULL);
- _gnutls_free_datum(&old_id);
-
- if (result != ASN1_SUCCESS) {
+ if (ret >= 0) {
+ ret = gnutls_x509_ext_get_key_purposes(&old_id, p, 0);
+ if (ret < 0) {
gnutls_assert();
- asn1_delete_structure(&c2);
- return _gnutls_asn2err(result);
+ goto cleanup;
}
-
- }
-
- /* generate the extension.
- */
- /* 1. create a new element.
- */
- result = asn1_write_value(c2, "", "NEW", 1);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- asn1_delete_structure(&c2);
- return _gnutls_asn2err(result);
}
- /* 2. Add the OID.
- */
- result = asn1_write_value(c2, "?LAST", oid, 1);
- if (result != ASN1_SUCCESS) {
+ ret = gnutls_x509_key_purpose_set(p, oid);
+ if (ret < 0) {
gnutls_assert();
- asn1_delete_structure(&c2);
- return _gnutls_asn2err(result);
+ goto cleanup;
}
- result = _gnutls_x509_der_encode(c2, "", &der_data, 0);
- asn1_delete_structure(&c2);
-
- if (result != ASN1_SUCCESS) {
+ ret = gnutls_x509_ext_set_key_purposes(p, &der);
+ if (ret < 0) {
gnutls_assert();
- return _gnutls_asn2err(result);
+ goto cleanup;
}
- result = _gnutls_x509_crt_set_extension(cert, "2.5.29.37",
- &der_data, critical);
-
- _gnutls_free_datum(&der_data);
-
- if (result < 0) {
+ ret = _gnutls_x509_crt_set_extension(cert, "2.5.29.37",
+ &der, critical);
+ if (ret < 0) {
gnutls_assert();
- return result;
+ goto cleanup;
}
cert->use_extensions = 1;
- return 0;
+ ret = 0;
+ cleanup:
+ _gnutls_free_datum(&der);
+ _gnutls_free_datum(&old_id);
+ if (p != NULL)
+ gnutls_x509_key_purpose_deinit(p);
+
+ return ret;
}
@@ -1376,18 +1437,6 @@ gnutls_x509_crt_privkey_sign(gnutls_x509_crt_t crt,
return 0;
}
-static const char *what_to_oid(int what)
-{
- switch (what) {
- case GNUTLS_IA_OCSP_URI:
- return GNUTLS_OID_AD_OCSP;
- case GNUTLS_IA_CAISSUERS_URI:
- return GNUTLS_OID_AD_CAISSUERS;
- default:
- return NULL;
- }
-}
-
/**
* gnutls_x509_crt_set_authority_info_access:
* @crt: Holds the certificate
@@ -1413,151 +1462,68 @@ int
gnutls_x509_crt_set_authority_info_access(gnutls_x509_crt_t crt,
int what, gnutls_datum_t * data)
{
- int ret, result;
- gnutls_datum_t aia = { NULL, 0 };
- gnutls_datum_t der_data = { NULL, 0 };
- ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
+ int ret;
+ gnutls_datum_t der = { NULL, 0 };
+ gnutls_datum_t new_der = { NULL, 0 };
+ gnutls_x509_aia_t aia_ctx = NULL;
const char *oid;
unsigned int c;
if (crt == NULL)
return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
- oid = what_to_oid(what);
- if (oid == NULL)
- return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
-
- ret = asn1_create_element(_gnutls_get_pkix(),
- "PKIX1.AuthorityInfoAccessSyntax", &c2);
- if (ret != ASN1_SUCCESS) {
+ ret = gnutls_x509_aia_init(&aia_ctx);
+ if (ret < 0) {
gnutls_assert();
- return _gnutls_asn2err(ret);
+ return ret;
}
- ret = _gnutls_x509_crt_get_extension(crt, GNUTLS_OID_AIA, 0, &aia,
+ ret = _gnutls_x509_crt_get_extension(crt, GNUTLS_OID_AIA, 0, &der,
&c);
if (ret >= 0) { /* decode it */
- ret = asn1_der_decoding(&c2, aia.data, aia.size, NULL);
- if (ret != ASN1_SUCCESS) {
+ ret = gnutls_x509_ext_get_aia(&der, aia_ctx, 0);
+ if (ret < 0) {
gnutls_assert();
- ret = _gnutls_asn2err(ret);
goto cleanup;
}
}
- /* generate the extension.
- */
- /* 1. create a new element.
- */
- result = asn1_write_value(c2, "", "NEW", 1);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- /* 2. Add the OID.
- */
- result = asn1_write_value(c2, "?LAST.accessMethod", oid, 1);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- ret = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- /* accessLocation is a choice */
- result =
- asn1_write_value(c2, "?LAST.accessLocation",
- "uniformResourceIdentifier", 1);
- if (result != ASN1_SUCCESS) {
+ if (what == GNUTLS_IA_OCSP_URI)
+ oid = GNUTLS_OID_AD_OCSP;
+ else if (what == GNUTLS_IA_CAISSUERS_URI)
+ oid = GNUTLS_OID_AD_CAISSUERS;
+ else
+ return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
+ ret = gnutls_x509_aia_set(aia_ctx, oid, GNUTLS_SAN_URI, data);
+ if (ret < 0) {
gnutls_assert();
- ret = _gnutls_asn2err(result);
goto cleanup;
}
- result =
- asn1_write_value(c2,
- "?LAST.accessLocation.uniformResourceIdentifier",
- data->data, data->size);
- if (result != ASN1_SUCCESS) {
+ ret = gnutls_x509_ext_set_aia(aia_ctx, &new_der);
+ if (ret < 0) {
gnutls_assert();
- ret = _gnutls_asn2err(result);
goto cleanup;
}
- ret = _gnutls_x509_der_encode(c2, "", &der_data, 0);
+ ret = _gnutls_x509_crt_set_extension(crt, GNUTLS_OID_AIA,
+ &new_der, 0);
if (ret < 0) {
gnutls_assert();
goto cleanup;
}
- ret = _gnutls_x509_crt_set_extension(crt, GNUTLS_OID_AIA,
- &der_data, 0);
- if (ret < 0)
- gnutls_assert();
-
crt->use_extensions = 1;
cleanup:
- _gnutls_free_datum(&der_data);
- _gnutls_free_datum(&aia);
- asn1_delete_structure(&c2);
+ if (aia_ctx != NULL)
+ gnutls_x509_aia_deinit(aia_ctx);
+ _gnutls_free_datum(&new_der);
+ _gnutls_free_datum(&der);
return ret;
}
-static int encode_user_notice(const gnutls_datum_t * txt,
- gnutls_datum_t * der_data)
-{
- int result;
- ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
-
- if ((result =
- asn1_create_element(_gnutls_get_pkix(),
- "PKIX1.UserNotice",
- &c2)) != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto error;
- }
-
- /* delete noticeRef */
- result = asn1_write_value(c2, "noticeRef", NULL, 0);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto error;
- }
-
- result = asn1_write_value(c2, "explicitText", "utf8String", 1);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto error;
- }
-
- result =
- asn1_write_value(c2, "explicitText.utf8String", txt->data,
- txt->size);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto error;
- }
-
- result = _gnutls_x509_der_encode(c2, "", der_data, 0);
- if (result < 0) {
- gnutls_assert();
- goto error;
- }
-
- result = 0;
-
- error:
- asn1_delete_structure(&c2);
- return result;
-
-}
/**
* gnutls_x509_crt_set_policy:
@@ -1579,156 +1545,63 @@ static int encode_user_notice(const gnutls_datum_t * txt,
**/
int
gnutls_x509_crt_set_policy(gnutls_x509_crt_t crt,
- struct gnutls_x509_policy_st *policy,
+ const struct gnutls_x509_policy_st *policy,
unsigned int critical)
{
- int result;
- unsigned i;
- gnutls_datum_t der_data, tmpd, prev_der_data = { NULL, 0 };
- ASN1_TYPE c2 = ASN1_TYPE_EMPTY;
- const char *oid;
+ int ret;
+ gnutls_datum_t der_data = {NULL, 0}, prev_der_data = { NULL, 0 };
+ gnutls_x509_policies_t policies = NULL;
if (crt == NULL) {
gnutls_assert();
return GNUTLS_E_INVALID_REQUEST;
}
- result = _gnutls_x509_crt_get_extension(crt, "2.5.29.32", 0,
- &prev_der_data, NULL);
- if (result < 0 && result != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ ret = gnutls_x509_policies_init(&policies);
+ if (ret < 0) {
gnutls_assert();
- return result;
+ return ret;
}
- result =
- asn1_create_element(_gnutls_get_pkix(),
- "PKIX1.certificatePolicies", &c2);
- if (result != ASN1_SUCCESS) {
+ ret = _gnutls_x509_crt_get_extension(crt, "2.5.29.32", 0,
+ &prev_der_data, NULL);
+ if (ret < 0 && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
gnutls_assert();
- result = _gnutls_asn2err(result);
goto cleanup;
}
- if (prev_der_data.data != NULL) {
- result =
- asn1_der_decoding(&c2, prev_der_data.data,
- prev_der_data.size, NULL);
- if (result != ASN1_SUCCESS) {
+ if (ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ ret = gnutls_x509_ext_get_policies(&prev_der_data,
+ policies, 0);
+ if (ret < 0) {
gnutls_assert();
- result = _gnutls_asn2err(result);
goto cleanup;
}
}
- /* 1. write a new policy */
- result = asn1_write_value(c2, "", "NEW", 1);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- /* 2. Add the OID.
- */
- result =
- asn1_write_value(c2, "?LAST.policyIdentifier", policy->oid, 1);
- if (result != ASN1_SUCCESS) {
+ ret = gnutls_x509_policies_set(policies, policy);
+ if (ret < 0) {
gnutls_assert();
- result = _gnutls_asn2err(result);
goto cleanup;
}
- for (i = 0; i < MIN(policy->qualifiers, GNUTLS_MAX_QUALIFIERS);
- i++) {
- result =
- asn1_write_value(c2, "?LAST.policyQualifiers", "NEW",
- 1);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- if (policy->qualifier[i].type == GNUTLS_X509_QUALIFIER_URI)
- oid = "1.3.6.1.5.5.7.2.1";
- else if (policy->qualifier[i].type ==
- GNUTLS_X509_QUALIFIER_NOTICE)
- oid = "1.3.6.1.5.5.7.2.2";
- else {
- result =
- gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
- goto cleanup;
- }
-
- result =
- asn1_write_value(c2,
- "?LAST.policyQualifiers.?LAST.policyQualifierId",
- oid, 1);
- if (result != ASN1_SUCCESS) {
- gnutls_assert();
- result = _gnutls_asn2err(result);
- goto cleanup;
- }
-
- if (policy->qualifier[i].type == GNUTLS_X509_QUALIFIER_URI) {
- tmpd.data = (void *) policy->qualifier[i].data;
- tmpd.size = policy->qualifier[i].size;
-
- result =
- _gnutls_x509_write_string(c2,
- "?LAST.policyQualifiers.?LAST.qualifier",
- &tmpd,
- ASN1_ETYPE_IA5_STRING);
- if (result < 0) {
- gnutls_assert();
- goto cleanup;
- }
- } else if (policy->qualifier[i].type ==
- GNUTLS_X509_QUALIFIER_NOTICE) {
- tmpd.data = (void *) policy->qualifier[i].data;
- tmpd.size = policy->qualifier[i].size;
-
- if (tmpd.size > 200) {
- gnutls_assert();
- result = GNUTLS_E_INVALID_REQUEST;
- goto cleanup;
- }
-
- result = encode_user_notice(&tmpd, &der_data);
- if (result < 0) {
- gnutls_assert();
- goto cleanup;
- }
-
- result =
- _gnutls_x509_write_value(c2,
- "?LAST.policyQualifiers.?LAST.qualifier",
- &der_data);
- _gnutls_free_datum(&der_data);
- if (result < 0) {
- gnutls_assert();
- goto cleanup;
- }
- }
- }
-
- result = _gnutls_x509_der_encode(c2, "", &der_data, 0);
- if (result < 0) {
+ ret = gnutls_x509_ext_set_policies(policies, &der_data);
+ if (ret < 0) {
gnutls_assert();
goto cleanup;
}
- result = _gnutls_x509_crt_set_extension(crt, "2.5.29.32",
+ ret = _gnutls_x509_crt_set_extension(crt, "2.5.29.32",
&der_data, 0);
- _gnutls_free_datum(&der_data);
-
crt->use_extensions = 1;
- cleanup:
- asn1_delete_structure(&c2);
+ cleanup:
+ if (policies != NULL)
+ gnutls_x509_policies_deinit(policies);
_gnutls_free_datum(&prev_der_data);
+ _gnutls_free_datum(&der_data);
- return result;
+ return ret;
}