diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2016-01-08 11:05:36 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2016-01-08 12:21:35 +0100 |
commit | 3e8ba29e3fa535e106fa3a3205dc7b3e04956489 (patch) | |
tree | 40fee5b9306d7c3a95ad86c5c7b949a5aa722d48 | |
parent | d1a9c629ace34bf715b590446ae83d82164e778e (diff) | |
download | gnutls-3e8ba29e3fa535e106fa3a3205dc7b3e04956489.tar.gz |
x509: introduced functions to set an othername alternative name
That is, added, gnutls_x509_crt_set_subject_alt_othername,
gnutls_x509_crt_set_issuer_alt_othername, gnutls_x509_crq_set_subject_alt_othername
Relates #62
-rw-r--r-- | lib/includes/gnutls/x509.h | 21 | ||||
-rw-r--r-- | lib/libgnutls.map | 3 | ||||
-rw-r--r-- | lib/x509/crq.c | 111 | ||||
-rw-r--r-- | lib/x509/extensions.c | 55 | ||||
-rw-r--r-- | lib/x509/x509_ext.c | 14 | ||||
-rw-r--r-- | lib/x509/x509_int.h | 9 | ||||
-rw-r--r-- | lib/x509/x509_write.c | 176 |
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); |