summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@redhat.com>2016-11-10 16:43:23 +0100
committerNikos Mavrogiannopoulos <nmav@redhat.com>2016-11-11 13:38:37 +0100
commitc2fa842bdcb88d0f7a16be9e49cc87b340cb68e2 (patch)
tree824bfcd9cd5f464699ed2b4983cfded8b726c039
parent6d5c80e2bf7efbc4e99588b8d8ec4f383d34375f (diff)
downloadgnutls-tmp-uninorm-everywhere.tar.gz
x509: when writing fields known to be in UTF-8 form convert to NFCtmp-uninorm-everywhere
This ensures that we always write proper UTF-8 data, uniquely encoded.
-rw-r--r--lib/str-unicode.c46
-rw-r--r--lib/str.h4
-rw-r--r--lib/x509/common.c46
-rw-r--r--lib/x509/common.h3
-rw-r--r--lib/x509/x509_ext.c6
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 <x509_b64.h>
#include "x509_int.h"
#include "extras/hex.h"
+#include "str.h"
#include <common.h>
#include <c-ctype.h>
@@ -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 <x509_b64.h>
#include "x509_ext_int.h"
#include "virt-san.h"
+#include "common.h"
#include <gnutls/x509-ext.h>
#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;
}