From c2fa842bdcb88d0f7a16be9e49cc87b340cb68e2 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Thu, 10 Nov 2016 16:43:23 +0100 Subject: x509: when writing fields known to be in UTF-8 form convert to NFC This ensures that we always write proper UTF-8 data, uniquely encoded. --- lib/str-unicode.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ lib/str.h | 4 +++- lib/x509/common.c | 46 ++++++++++++++++++++++++++++++++++++++++------ lib/x509/common.h | 3 +++ lib/x509/x509_ext.c | 6 +++--- 5 files changed, 95 insertions(+), 10 deletions(-) diff --git a/lib/str-unicode.c b/lib/str-unicode.c index 7bda8cab07..20e9ca10bd 100644 --- a/lib/str-unicode.c +++ b/lib/str-unicode.c @@ -103,4 +103,50 @@ uint8_t *_gnutls_normalize_u8_password(const uint8_t *password) return NULL; } +uint8_t *_gnutls_normalize_u8_nfc(const uint8_t *str, size_t str_size) +{ + size_t nrm_size = 0; + size_t out_size = 0; + uint8_t *out = NULL; + uint8_t *nrm = NULL; + + if (str_size == 0) { + return (uint8_t*)strdup(""); + } + + /* check for invalid UTF-8 */ + if (u8_check(str, str_size) != NULL) { + gnutls_assert(); + return NULL; + } + + /* normalize to NFC */ + nrm = u8_normalize(UNINORM_NFC, str, str_size, NULL, &nrm_size); + if (nrm == NULL) { + gnutls_assert(); + goto fail; + } + + out_size = nrm_size; + + /* copy to output with null terminator */ + out = gnutls_malloc(out_size+1); + if (out == NULL) { + gnutls_assert(); + goto fail; + } + + memcpy(out, nrm, out_size); + out[out_size] = 0; + + gnutls_free(nrm); + + return out; + + fail: + gnutls_free(out); + gnutls_free(nrm); + return NULL; +} + #endif diff --git a/lib/str.h b/lib/str.h index 4e497b630a..780245b733 100644 --- a/lib/str.h +++ b/lib/str.h @@ -38,8 +38,10 @@ #if defined(HAVE_LIBUNISTRING) uint8_t *_gnutls_normalize_u8_password(const uint8_t *password); +uint8_t *_gnutls_normalize_u8_nfc(const uint8_t *str, size_t str_size); #else -# define _gnutls_normalize_u8_password(password) ((uint8_t*)strdup((char*)password)) +# define _gnutls_normalize_u8_password(password) ((uint8_t*)gnutls_strdup((char*)password)) +# define _gnutls_normalize_u8_nfc(str, str_size) ((uint8_t*)gnutls_strdup((char*)str)) #endif void _gnutls_str_cpy(char *dest, size_t dest_tot_size, const char *src); diff --git a/lib/x509/common.c b/lib/x509/common.c index 6d72338d42..b75cb7055e 100644 --- a/lib/x509/common.c +++ b/lib/x509/common.c @@ -31,6 +31,7 @@ #include #include "x509_int.h" #include "extras/hex.h" +#include "str.h" #include #include @@ -1327,6 +1328,30 @@ static int is_printable(char p) return 0; } +/* ensures that the UTF8 string we write is properly encoded */ +int _gnutls_x509_write_utf8_value(ASN1_TYPE asn_struct, const char *where, + const uint8_t *data, size_t data_size) +{ + int ret, result; + uint8_t *nrm = _gnutls_normalize_u8_nfc(data, data_size); + + if (nrm == NULL) + return gnutls_assert_val(GNUTLS_E_INVALID_UTF8_PASSWORD); + + result = asn1_write_value(asn_struct, where, nrm, strlen((char*)nrm)); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + ret = _gnutls_asn2err(result); + goto cleanup; + } + + ret = 0; + + cleanup: + gnutls_free(nrm); + return ret; +} + static int write_complex_string(ASN1_TYPE asn_struct, const char *where, const struct oid_to_string *oentry, const uint8_t * data, size_t data_size) @@ -1335,7 +1360,7 @@ static int write_complex_string(ASN1_TYPE asn_struct, const char *where, ASN1_TYPE c2; int result; const char *string_type; - unsigned int i; + unsigned int i, utf8_flag = 0; result = asn1_create_element(_gnutls_get_pkix(), oentry->asn_desc, &c2); @@ -1354,6 +1379,7 @@ static int write_complex_string(ASN1_TYPE asn_struct, const char *where, for (i = 0; i < data_size; i++) { if (!is_printable(data[i])) { string_type = "utf8String"; + utf8_flag = 1; break; } } @@ -1370,11 +1396,19 @@ static int write_complex_string(ASN1_TYPE asn_struct, const char *where, _gnutls_str_cpy(tmp, sizeof(tmp), string_type); - result = asn1_write_value(c2, tmp, data, data_size); - if (result != ASN1_SUCCESS) { - gnutls_assert(); - result = _gnutls_asn2err(result); - goto error; + if (utf8_flag) { + result = _gnutls_x509_write_utf8_value(c2, tmp, data, data_size); + if (result < 0) { + gnutls_assert(); + goto error; + } + } else { + result = asn1_write_value(c2, tmp, data, data_size); + if (result != ASN1_SUCCESS) { + gnutls_assert(); + result = _gnutls_asn2err(result); + goto error; + } } result = diff --git a/lib/x509/common.h b/lib/x509/common.h index 6716939255..73d202d173 100644 --- a/lib/x509/common.h +++ b/lib/x509/common.h @@ -143,6 +143,9 @@ int _gnutls_x509_read_string(ASN1_TYPE c, const char *root, int _gnutls_x509_write_value(ASN1_TYPE c, const char *root, const gnutls_datum_t * data); +int _gnutls_x509_write_utf8_value(ASN1_TYPE asn_struct, const char *where, + const uint8_t *data, size_t data_size); + int _gnutls_x509_write_string(ASN1_TYPE c, const char *root, const gnutls_datum_t * data, unsigned int etype); diff --git a/lib/x509/x509_ext.c b/lib/x509/x509_ext.c index d503d5d394..2fa655eff4 100644 --- a/lib/x509/x509_ext.c +++ b/lib/x509/x509_ext.c @@ -30,6 +30,7 @@ #include #include "x509_ext_int.h" #include "virt-san.h" +#include "common.h" #include #define MAX_ENTRIES 64 @@ -1975,11 +1976,10 @@ static int encode_user_notice(const gnutls_datum_t * txt, } result = - asn1_write_value(c2, "explicitText.utf8String", txt->data, + _gnutls_x509_write_utf8_value(c2, "explicitText.utf8String", txt->data, txt->size); - if (result != ASN1_SUCCESS) { + if (result < 0) { gnutls_assert(); - result = _gnutls_asn2err(result); goto error; } -- cgit v1.2.1