diff options
author | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-11-16 14:48:59 +0100 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@redhat.com> | 2016-11-25 12:03:37 +0100 |
commit | 7dc44ad71e3e3c50140b1d6c3ce5c473268b7abd (patch) | |
tree | 934230567ff963789dab4456956f4c9c31de459b | |
parent | ee7e72a71f0527ca02329fefd18a47ebfe65ffcc (diff) | |
download | gnutls-7dc44ad71e3e3c50140b1d6c3ce5c473268b7abd.tar.gz |
When writing alternative names to certificates ensure we write in ACE format
-rw-r--r-- | lib/errors.c | 2 | ||||
-rw-r--r-- | lib/includes/gnutls/gnutls.h.in | 1 | ||||
-rw-r--r-- | lib/str-unicode.c | 41 | ||||
-rw-r--r-- | lib/str.h | 14 | ||||
-rw-r--r-- | lib/x509/crq.c | 3 | ||||
-rw-r--r-- | lib/x509/email-verify.c | 6 | ||||
-rw-r--r-- | lib/x509/virt-san.c | 40 | ||||
-rw-r--r-- | lib/x509/virt-san.h | 2 | ||||
-rw-r--r-- | lib/x509/x509_dn.c | 5 | ||||
-rw-r--r-- | lib/x509/x509_ext.c | 23 | ||||
-rw-r--r-- | lib/x509/x509_write.c | 8 |
11 files changed, 129 insertions, 16 deletions
diff --git a/lib/errors.c b/lib/errors.c index f23a9f008e..0f8c512ed1 100644 --- a/lib/errors.c +++ b/lib/errors.c @@ -276,6 +276,8 @@ static const gnutls_error_entry error_entries[] = { GNUTLS_E_INVALID_PASSWORD), ERROR_ENTRY(N_("The given string contains invalid UTF-8 characters."), GNUTLS_E_INVALID_UTF8_STRING), + ERROR_ENTRY(N_("The given email string contains non-ASCII characters before '@'."), + GNUTLS_E_INVALID_UTF8_EMAIL), ERROR_ENTRY(N_ ("The Message Authentication Code verification failed."), GNUTLS_E_MAC_VERIFY_FAILED), diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 8ae395890a..ad18559515 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -2827,6 +2827,7 @@ unsigned gnutls_fips140_mode_enabled(void); #define GNUTLS_E_NOT_YET_ACTIVATED -411 #define GNUTLS_E_INVALID_UTF8_STRING -412 #define GNUTLS_E_NO_EMBEDDED_DATA -413 +#define GNUTLS_E_INVALID_UTF8_EMAIL -414 #define GNUTLS_E_UNIMPLEMENTED_FEATURE -1250 diff --git a/lib/str-unicode.c b/lib/str-unicode.c index 4be4b6e2a6..2fe1a61cae 100644 --- a/lib/str-unicode.c +++ b/lib/str-unicode.c @@ -204,6 +204,7 @@ int _gnutls_idna_map(const char *input, unsigned ilen, gnutls_datum_t *out, unsi gnutls_free(istr.data); return ret; } + #else # undef gnutls_idna_map @@ -212,3 +213,43 @@ int _gnutls_idna_map(const char *input, unsigned ilen, gnutls_datum_t *out, unsi return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); } #endif /* HAVE_LIBIDN2 */ + +int _gnutls_idna_email_map(const char *input, unsigned ilen, gnutls_datum_t *output) +{ + const char *p = input; + + while(*p != 0 && *p != '@') { + if (!c_isprint(*p)) + return gnutls_assert_val(GNUTLS_E_INVALID_UTF8_EMAIL); + p++; + } + + if (_gnutls_str_is_print(input, ilen)) { + return _gnutls_set_strdatum(output, input, ilen); + } + + if (*p == '@') { + unsigned name_part = p-input; + int ret; + gnutls_datum_t domain; + + ret = _gnutls_idna_map(p+1, ilen-name_part-1, &domain, 0); + if (ret < 0) + return gnutls_assert_val(ret); + + output->data = gnutls_malloc(name_part+1+domain.size+1); + if (output->data == NULL) { + gnutls_free(domain.data); + return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); + } + memcpy(output->data, input, name_part); + output->data[name_part] = '@'; + memcpy(&output->data[name_part+1], domain.data, domain.size); + output->data[name_part+domain.size+1] = 0; + output->size = name_part+domain.size+1; + gnutls_free(domain.data); + return 0; + } else { + return gnutls_assert_val(GNUTLS_E_INVALID_UTF8_EMAIL); + } +} @@ -27,6 +27,8 @@ #include "gnutls_int.h" #include "errors.h" #include <datum.h> +#include <c-ctype.h> +#include "errors.h" #ifdef HAVE_DCGETTEXT # include "gettext.h" @@ -44,6 +46,8 @@ int gnutls_utf8_password_normalize(const uint8_t *password, unsigned password_le gnutls_utf8_password_normalize((unsigned char*)p, plen, out, \ ignore_errs?(GNUTLS_UTF8_IGNORE_ERRS):0) +int _gnutls_idna_email_map(const char *input, unsigned ilen, gnutls_datum_t *output); + #ifndef HAVE_LIBIDN inline static int __gnutls_idna_map(const char *input, unsigned ilen, gnutls_datum_t *out, unsigned flags) @@ -62,6 +66,16 @@ int __gnutls_idna_map(const char *input, unsigned ilen, gnutls_datum_t *out, uns int _gnutls_idna_map(const char * input, unsigned ilen, gnutls_datum_t *out, unsigned flags); #endif +inline static unsigned _gnutls_str_is_print(const char *str, unsigned size) +{ + unsigned i; + for (i=0;i<size;i++) { + if (!c_isprint(str[i])) + return 0; + } + return 1; +} + void _gnutls_str_cpy(char *dest, size_t dest_tot_size, const char *src); void _gnutls_mem_cpy(char *dest, size_t dest_tot_size, const char *src, size_t src_size); diff --git a/lib/x509/crq.c b/lib/x509/crq.c index 4135db26e7..936e122519 100644 --- a/lib/x509/crq.c +++ b/lib/x509/crq.c @@ -2152,6 +2152,9 @@ gnutls_x509_crq_get_extension_by_oid2(gnutls_x509_crq_t crq, * * %GNUTLS_SAN_OTHERNAME_XMPP: as a UTF8 string * + * Since version 3.5.7 the %GNUTLS_SAN_RFC822NAME, %GNUTLS_SAN_DNSNAME, and + * %GNUTLS_SAN_OTHERNAME_XMPP are converted to ACE format when necessary. + * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * diff --git a/lib/x509/email-verify.c b/lib/x509/email-verify.c index a96d5ca192..d0c5bad762 100644 --- a/lib/x509/email-verify.c +++ b/lib/x509/email-verify.c @@ -58,7 +58,7 @@ gnutls_x509_crt_check_email(gnutls_x509_crt_t cert, gnutls_datum_t out; /* convert the provided email to ACE-Labels domain. */ - ret = gnutls_idna_map(email, strlen(email), &out, 0); + ret = _gnutls_idna_email_map(email, strlen(email), &out); if (ret < 0) { _gnutls_debug_log("unable to convert email %s to IDNA format\n", email); a_email = (char*)email; @@ -94,7 +94,7 @@ gnutls_x509_crt_check_email(gnutls_x509_crt_t cert, continue; } - ret = gnutls_idna_map(rfc822name, rfc822namesize, &out, 0); + ret = _gnutls_idna_email_map(rfc822name, rfc822namesize, &out); if (ret < 0) { _gnutls_debug_log("unable to convert rfc822name %s to IDNA format\n", rfc822name); continue; @@ -142,7 +142,7 @@ gnutls_x509_crt_check_email(gnutls_x509_crt_t cert, goto cleanup; } - ret = gnutls_idna_map (rfc822name, rfc822namesize, &out, 0); + ret = _gnutls_idna_email_map (rfc822name, rfc822namesize, &out); if (ret < 0) { _gnutls_debug_log("unable to convert EMAIL %s to IDNA format\n", rfc822name); ret = 0; diff --git a/lib/x509/virt-san.c b/lib/x509/virt-san.c index 83e5414479..c1918af2d4 100644 --- a/lib/x509/virt-san.c +++ b/lib/x509/virt-san.c @@ -57,15 +57,40 @@ const char * virtual_to_othername_oid(unsigned type) } } -int _gnutls_alt_name_assign_virt_type(struct name_st *name, unsigned type, gnutls_datum_t *san, const char *othername_oid) +int _gnutls_alt_name_assign_virt_type(struct name_st *name, unsigned type, gnutls_datum_t *san, const char *othername_oid, unsigned raw) { gnutls_datum_t encoded = {NULL, 0}; + gnutls_datum_t xmpp = {NULL,0}; int ret; if (type < 1000) { name->type = type; - name->san.data = san->data; - name->san.size = san->size; + if (type == GNUTLS_SAN_DNSNAME && !raw) { + ret = gnutls_idna_map((char*)san->data, san->size, &name->san, 0); + if (ret < 0) { + return gnutls_assert_val(ret); + } + gnutls_free(san->data); + san->data = NULL; + } else if (type == GNUTLS_SAN_RFC822NAME && !raw) { + ret = _gnutls_idna_email_map((char*)san->data, san->size, &name->san); + if (ret < 0) { + return gnutls_assert_val(ret); + } + gnutls_free(san->data); + san->data = NULL; + } else if (type == GNUTLS_SAN_URI && !raw) { + if (!_gnutls_str_is_print((char*)san->data, san->size)) { + _gnutls_debug_log("non-ASCII URIs are not supported\n"); + return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE); + } else { + name->san.data = san->data; + name->san.size = san->size; + } + } else { + name->san.data = san->data; + name->san.size = san->size; + } if (othername_oid) { name->othername_oid.data = (uint8_t *) othername_oid; @@ -83,8 +108,15 @@ int _gnutls_alt_name_assign_virt_type(struct name_st *name, unsigned type, gnutl switch(type) { case GNUTLS_SAN_OTHERNAME_XMPP: + + ret = gnutls_idna_map((char*)san->data, san->size, &xmpp, 0); + if (ret < 0) + return gnutls_assert_val(ret); + ret = _gnutls_x509_encode_string(ASN1_ETYPE_UTF8_STRING, - san->data, san->size, &encoded); + xmpp.data, xmpp.size, &encoded); + + gnutls_free(xmpp.data); if (ret < 0) return gnutls_assert_val(ret); diff --git a/lib/x509/virt-san.h b/lib/x509/virt-san.h index 2c155bd27b..10d78e39f1 100644 --- a/lib/x509/virt-san.h +++ b/lib/x509/virt-san.h @@ -24,6 +24,6 @@ #include "x509_ext_int.h" -int _gnutls_alt_name_assign_virt_type(struct name_st *name, unsigned type, gnutls_datum_t *san, const char *othername_oid); +int _gnutls_alt_name_assign_virt_type(struct name_st *name, unsigned type, gnutls_datum_t *san, const char *othername_oid, unsigned raw); #endif diff --git a/lib/x509/x509_dn.c b/lib/x509/x509_dn.c index 8936a23d08..e093fe9d86 100644 --- a/lib/x509/x509_dn.c +++ b/lib/x509/x509_dn.c @@ -287,6 +287,11 @@ fail: * The input string should be plain ASCII or UTF-8 encoded. On * DN parsing error %GNUTLS_E_PARSING_ERROR is returned. * + * Note that DNs are not expected to hold DNS information, and thus + * no automatic IDNA convertions are attempted when using this function. + * If that is required (e.g., store a domain in CN), process the corresponding + * input with gnutls_idna_map(). + * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ diff --git a/lib/x509/x509_ext.c b/lib/x509/x509_ext.c index d503d5d394..0756ed5996 100644 --- a/lib/x509/x509_ext.c +++ b/lib/x509/x509_ext.c @@ -131,7 +131,8 @@ static int subject_alt_names_set(struct name_st **names, unsigned int *size, unsigned int san_type, - gnutls_datum_t * san, char *othername_oid) + gnutls_datum_t * san, char *othername_oid, + unsigned raw) { void *tmp; int ret; @@ -142,7 +143,7 @@ int subject_alt_names_set(struct name_st **names, } *names = tmp; - ret = _gnutls_alt_name_assign_virt_type(&(*names)[*size], san_type, san, othername_oid); + ret = _gnutls_alt_name_assign_virt_type(&(*names)[*size], san_type, san, othername_oid, raw); if (ret < 0) return gnutls_assert_val(ret); @@ -160,6 +161,9 @@ int subject_alt_names_set(struct name_st **names, * This function will store the specified alternative name in * the @sans. * + * Since version 3.5.7 the %GNUTLS_SAN_RFC822NAME, %GNUTLS_SAN_DNSNAME, and + * %GNUTLS_SAN_OTHERNAME_XMPP are converted to ACE format when necessary. + * * Returns: On success, %GNUTLS_E_SUCCESS (0), otherwise a negative error value. * * Since: 3.3.0 @@ -182,7 +186,7 @@ int gnutls_subject_alt_names_set(gnutls_subject_alt_names_t sans, else ooc = NULL; ret = subject_alt_names_set(&sans->names, &sans->size, - san_type, ©, ooc); + san_type, ©, ooc, 0); if (ret < 0) { gnutls_free(copy.data); return gnutls_assert_val(ret); @@ -257,7 +261,7 @@ int gnutls_x509_ext_import_subject_alt_names(const gnutls_datum_t * ext, ret = subject_alt_names_set(&sans->names, &sans->size, type, &san, - (char *)othername_oid.data); + (char *)othername_oid.data, 1); if (ret < 0) break; @@ -773,15 +777,18 @@ int gnutls_x509_aki_set_id(gnutls_x509_aki_t aki, const gnutls_datum_t * id) * to be stored in the @aki type. When storing multiple names, the serial * should be set on the first call, and subsequent calls should use a %NULL serial. * + * Since version 3.5.7 the %GNUTLS_SAN_RFC822NAME, %GNUTLS_SAN_DNSNAME, and + * %GNUTLS_SAN_OTHERNAME_XMPP are converted to ACE format when necessary. + * * 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 gnutls_datum_t *san, const char *othername_oid, - const gnutls_datum_t * serial) + const gnutls_datum_t *serial) { int ret; gnutls_datum_t t_san, t_othername_oid = { NULL, 0 }; @@ -808,7 +815,7 @@ int gnutls_x509_aki_set_cert_issuer(gnutls_x509_aki_t aki, ret = subject_alt_names_set(&aki->cert_issuer.names, &aki->cert_issuer.size, san_type, &t_san, - (char *)t_othername_oid.data); + (char *)t_othername_oid.data, 0); if (ret < 0) { gnutls_assert(); return ret; @@ -934,7 +941,7 @@ int gnutls_x509_ext_import_authority_key_id(const gnutls_datum_t * ext, ret = subject_alt_names_set(&aki->cert_issuer.names, &aki->cert_issuer.size, type, &san, - (char *)othername_oid.data); + (char *)othername_oid.data, 1); if (ret < 0) break; diff --git a/lib/x509/x509_write.c b/lib/x509/x509_write.c index 5cb2aee3a3..bc6eb2eb81 100644 --- a/lib/x509/x509_write.c +++ b/lib/x509/x509_write.c @@ -574,6 +574,8 @@ gnutls_x509_crt_set_key_usage(gnutls_x509_crt_t crt, unsigned int usage) * The name of the function is unfortunate since it is inconsistent with * gnutls_x509_crt_get_subject_alt_name(). * + * See gnutls_x509_crt_set_subject_alt_name() for more information. + * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. **/ @@ -613,6 +615,9 @@ gnutls_x509_crt_set_subject_alternative_name(gnutls_x509_crt_t crt, * %GNUTLS_SAN_IPADDRESS as a binary IP address (4 or 16 bytes), * %GNUTLS_SAN_OTHERNAME_XMPP as a UTF8 string (since 3.5.0). * + * Since version 3.5.7 the %GNUTLS_SAN_RFC822NAME, %GNUTLS_SAN_DNSNAME, and + * %GNUTLS_SAN_OTHERNAME_XMPP are converted to ACE format when necessary. + * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * @@ -691,6 +696,9 @@ gnutls_x509_crt_set_subject_alt_name(gnutls_x509_crt_t crt, * This function will set the issuer alternative name certificate * extension. It can set the same types as gnutls_x509_crt_set_subject_alt_name(). * + * Since version 3.5.7 the %GNUTLS_SAN_RFC822NAME, %GNUTLS_SAN_DNSNAME, and + * %GNUTLS_SAN_OTHERNAME_XMPP are converted to ACE format when necessary. + * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a * negative error value. * |