summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-11-16 14:48:59 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2016-11-25 12:03:37 +0100
commit7dc44ad71e3e3c50140b1d6c3ce5c473268b7abd (patch)
tree934230567ff963789dab4456956f4c9c31de459b
parentee7e72a71f0527ca02329fefd18a47ebfe65ffcc (diff)
downloadgnutls-7dc44ad71e3e3c50140b1d6c3ce5c473268b7abd.tar.gz
When writing alternative names to certificates ensure we write in ACE format
-rw-r--r--lib/errors.c2
-rw-r--r--lib/includes/gnutls/gnutls.h.in1
-rw-r--r--lib/str-unicode.c41
-rw-r--r--lib/str.h14
-rw-r--r--lib/x509/crq.c3
-rw-r--r--lib/x509/email-verify.c6
-rw-r--r--lib/x509/virt-san.c40
-rw-r--r--lib/x509/virt-san.h2
-rw-r--r--lib/x509/x509_dn.c5
-rw-r--r--lib/x509/x509_ext.c23
-rw-r--r--lib/x509/x509_write.c8
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);
+ }
+}
diff --git a/lib/str.h b/lib/str.h
index 0029a88a41..e9ae3f0204 100644
--- a/lib/str.h
+++ b/lib/str.h
@@ -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, &copy, ooc);
+ san_type, &copy, 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.
*