summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/includes/gnutls/x509.h21
-rw-r--r--lib/libgnutls.map3
-rw-r--r--lib/x509/crq.c111
-rw-r--r--lib/x509/extensions.c55
-rw-r--r--lib/x509/x509_ext.c14
-rw-r--r--lib/x509/x509_int.h9
-rw-r--r--lib/x509/x509_write.c176
7 files changed, 377 insertions, 12 deletions
diff --git a/lib/includes/gnutls/x509.h b/lib/includes/gnutls/x509.h
index bee392592d..a75d1ba9b7 100644
--- a/lib/includes/gnutls/x509.h
+++ b/lib/includes/gnutls/x509.h
@@ -563,12 +563,26 @@ int gnutls_x509_crt_set_subject_alt_name(gnutls_x509_crt_t crt,
unsigned int data_size,
unsigned int flags);
+int
+gnutls_x509_crt_set_subject_alt_othername(gnutls_x509_crt_t crt,
+ const char *oid,
+ 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_set_issuer_alt_othername(gnutls_x509_crt_t crt,
+ const char *oid,
+ 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);
@@ -1228,6 +1242,13 @@ int gnutls_x509_crq_set_subject_alt_name(gnutls_x509_crq_t crq,
unsigned int data_size,
unsigned int flags);
+int
+gnutls_x509_crq_set_subject_alt_othername(gnutls_x509_crq_t crq,
+ const char *oid,
+ const void *data,
+ unsigned int data_size,
+ unsigned int flags);
+
int gnutls_x509_crq_set_key_usage(gnutls_x509_crq_t crq,
unsigned int usage);
int gnutls_x509_crq_set_basic_constraints(gnutls_x509_crq_t crq,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 7885153be3..87827cb622 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -1072,6 +1072,9 @@ GNUTLS_3_4
gnutls_decode_ber_digest_info;
gnutls_encode_ber_digest_info;
gnutls_pkcs7_get_embedded_data;
+ gnutls_x509_crq_set_subject_alt_othername;
+ gnutls_x509_crt_set_subject_alt_othername;
+ gnutls_x509_crt_set_issuer_alt_othername;
local:
*;
};
diff --git a/lib/x509/crq.c b/lib/x509/crq.c
index 5004f0f600..9263595866 100644
--- a/lib/x509/crq.c
+++ b/lib/x509/crq.c
@@ -2089,7 +2089,116 @@ gnutls_x509_crq_set_subject_alt_name(gnutls_x509_crq_t crq,
/* generate the extension.
*/
- result = _gnutls_x509_ext_gen_subject_alt_name(nt, data, data_size,
+ result = _gnutls_x509_ext_gen_subject_alt_name(nt, NULL, data, data_size,
+ &prev_der_data,
+ &der_data);
+ gnutls_free(prev_der_data.data);
+ if (result < 0) {
+ gnutls_assert();
+ goto finish;
+ }
+
+ result =
+ _gnutls_x509_crq_set_extension(crq, "2.5.29.17", &der_data,
+ critical);
+
+ _gnutls_free_datum(&der_data);
+
+ if (result < 0) {
+ gnutls_assert();
+ return result;
+ }
+
+ return 0;
+
+ finish:
+ return result;
+}
+
+/**
+ * gnutls_x509_crq_set_subject_alt_othername:
+ * @crq: a certificate request of type #gnutls_x509_crq_t
+ * @oid: is the othername OID
+ * @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 subject alternative name certificate
+ * extension. It can set the following types:
+ *
+ * The values set must be binary values and must be properly DER encoded.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.5.0
+ **/
+int
+gnutls_x509_crq_set_subject_alt_othername(gnutls_x509_crq_t crq,
+ const char *oid,
+ const void *data,
+ unsigned int data_size,
+ unsigned int flags)
+{
+ int result = 0;
+ gnutls_datum_t der_data = { NULL, 0 };
+ gnutls_datum_t prev_der_data = { NULL, 0 };
+ unsigned int critical = 0;
+ size_t prev_data_size = 0;
+
+ if (crq == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ /* Check if the extension already exists.
+ */
+ if (flags == GNUTLS_FSAN_APPEND) {
+ result =
+ gnutls_x509_crq_get_extension_by_oid(crq, "2.5.29.17",
+ 0, NULL,
+ &prev_data_size,
+ &critical);
+ prev_der_data.size = prev_data_size;
+
+ switch (result) {
+ case GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE:
+ /* Replacing non-existing data means the same as set data. */
+ break;
+
+ case GNUTLS_E_SUCCESS:
+ prev_der_data.data =
+ gnutls_malloc(prev_der_data.size);
+ if (prev_der_data.data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ result =
+ gnutls_x509_crq_get_extension_by_oid(crq,
+ "2.5.29.17",
+ 0,
+ prev_der_data.
+ data,
+ &prev_data_size,
+ &critical);
+ if (result < 0) {
+ gnutls_assert();
+ gnutls_free(prev_der_data.data);
+ return result;
+ }
+ break;
+
+ default:
+ gnutls_assert();
+ return result;
+ }
+ }
+
+ /* generate the extension.
+ */
+ result = _gnutls_x509_ext_gen_subject_alt_name(GNUTLS_SAN_OTHERNAME, oid, data, data_size,
&prev_der_data,
&der_data);
gnutls_free(prev_der_data.data);
diff --git a/lib/x509/extensions.c b/lib/x509/extensions.c
index 148766dc68..b8918af0a5 100644
--- a/lib/x509/extensions.c
+++ b/lib/x509/extensions.c
@@ -767,12 +767,63 @@ _gnutls_write_new_general_name(ASN1_TYPE ext, const char *ext_name,
return 0;
}
+int
+_gnutls_write_new_othername(ASN1_TYPE ext, const char *ext_name,
+ const char *oid,
+ const void *data, unsigned int data_size)
+{
+ int result;
+ char name[128];
+ char name2[128];
+
+ result = asn1_write_value(ext, ext_name, "NEW", 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ if (ext_name[0] == 0) { /* no dot */
+ _gnutls_str_cpy(name, sizeof(name), "?LAST");
+ } else {
+ _gnutls_str_cpy(name, sizeof(name), ext_name);
+ _gnutls_str_cat(name, sizeof(name), ".?LAST");
+ }
+
+ result = asn1_write_value(ext, name, "otherName", 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(result);
+ }
+
+ snprintf(name2, sizeof(name2), "%s.otherName.type-id", name);
+
+ result = asn1_write_value(ext, name2, oid, 1);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ asn1_delete_structure(&ext);
+ return _gnutls_asn2err(result);
+ }
+
+ snprintf(name2, sizeof(name2), "%s.otherName.value", name);
+
+ result = asn1_write_value(ext, name2, data, data_size);
+ if (result != ASN1_SUCCESS) {
+ gnutls_assert();
+ asn1_delete_structure(&ext);
+ return _gnutls_asn2err(result);
+ }
+
+ return 0;
+}
+
/* Convert the given name to GeneralNames in a DER encoded extension.
* This is the same as subject alternative name.
*/
int
_gnutls_x509_ext_gen_subject_alt_name(gnutls_x509_subject_alt_name_t
- type, const void *data,
+ type,
+ const char *othername_oid,
+ const void *data,
unsigned int data_size,
const gnutls_datum_t * prev_der_ext,
gnutls_datum_t * der_ext)
@@ -799,7 +850,7 @@ _gnutls_x509_ext_gen_subject_alt_name(gnutls_x509_subject_alt_name_t
name.data = (void*)data;
name.size = data_size;
- ret = gnutls_subject_alt_names_set(sans, type, &name, NULL);
+ ret = gnutls_subject_alt_names_set(sans, type, &name, othername_oid);
if (ret < 0) {
gnutls_assert();
goto cleanup;
diff --git a/lib/x509/x509_ext.c b/lib/x509/x509_ext.c
index 3373e97aef..889d854845 100644
--- a/lib/x509/x509_ext.c
+++ b/lib/x509/x509_ext.c
@@ -318,13 +318,15 @@ int gnutls_x509_ext_export_subject_alt_names(gnutls_subject_alt_names_t sans,
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_othername(c2, "", (char*)sans->names[i].othername_oid.data,
+ sans->names[i].san.data, sans->names[i].san.size);
+ } else {
+ ret =
+ _gnutls_write_new_general_name(c2, "", sans->names[i].type,
+ sans->names[i].san.data,
+ sans->names[i].san.size);
}
- 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;
diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h
index 9d666ee55d..af07c5297c 100644
--- a/lib/x509/x509_int.h
+++ b/lib/x509/x509_int.h
@@ -191,6 +191,11 @@ _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);
+int
+_gnutls_write_new_othername(ASN1_TYPE ext, const char *ext_name,
+ const char *oid,
+ const void *data, unsigned int data_size);
+
/* dsa.c */
@@ -271,7 +276,9 @@ _gnutls_write_general_name(ASN1_TYPE ext, const char *ext_name,
const void *data, unsigned int data_size);
int _gnutls_x509_ext_gen_subject_alt_name(gnutls_x509_subject_alt_name_t
- type, const void *data,
+ type,
+ const char *othername_oid,
+ const void *data,
unsigned int data_size,
const gnutls_datum_t * prev_der_ext,
gnutls_datum_t * der_ext);
diff --git a/lib/x509/x509_write.c b/lib/x509/x509_write.c
index 92f724b305..d2dd3d8258 100644
--- a/lib/x509/x509_write.c
+++ b/lib/x509/x509_write.c
@@ -629,7 +629,7 @@ gnutls_x509_crt_set_subject_alt_name(gnutls_x509_crt_t crt,
/* generate the extension.
*/
result =
- _gnutls_x509_ext_gen_subject_alt_name(type, data, data_size,
+ _gnutls_x509_ext_gen_subject_alt_name(type, NULL, data, data_size,
&prev_der_data,
&der_data);
@@ -712,7 +712,179 @@ gnutls_x509_crt_set_issuer_alt_name(gnutls_x509_crt_t crt,
/* generate the extension.
*/
result =
- _gnutls_x509_ext_gen_subject_alt_name(type, data, data_size,
+ _gnutls_x509_ext_gen_subject_alt_name(type, NULL, 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_subject_alt_othername:
+ * @crt: a certificate of type #gnutls_x509_crt_t
+ * @oid: The other name OID
+ * @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 an "othername" to the subject alternative name certificate
+ * extension.
+ *
+ * The values set are set as binary values and are expected to have the proper DER encoding.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.5.0
+ **/
+int
+gnutls_x509_crt_set_subject_alt_othername(gnutls_x509_crt_t crt,
+ const char *oid,
+ 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.17", 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(GNUTLS_SAN_OTHERNAME, oid,
+ 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.17", &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_issuer_alt_othername:
+ * @crt: a certificate of type #gnutls_x509_crt_t
+ * @oid: The other name OID
+ * @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 an "othername" to the issuer alternative name certificate
+ * extension.
+ *
+ * The values set are set as binary values and are expected to have the proper DER encoding.
+ *
+ * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
+ * negative error value.
+ *
+ * Since: 3.5.0
+ **/
+int
+gnutls_x509_crt_set_issuer_alt_othername(gnutls_x509_crt_t crt,
+ const char *oid,
+ 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(GNUTLS_SAN_OTHERNAME, oid,
+ data, data_size,
&prev_der_data,
&der_data);