From 826e706109e83e4f50f0c6a8dfe548f9937b6cd5 Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Mon, 28 Mar 2005 21:45:59 +0000 Subject: [PATCH] Fixed SILC_STRING_LDAP_DN encode/decode. Added SILC_STRING_UTF8_ESCAPE. --- CHANGES | 7 + lib/silcclient/silcclient.h | 2 +- lib/silcutil/silcstrutil.h | 3 +- lib/silcutil/silcutf8.c | 176 +++++++++++++++----------- lib/silcutil/tests/test_silcstrutil.c | 30 +++++ 5 files changed, 143 insertions(+), 75 deletions(-) diff --git a/CHANGES b/CHANGES index aba7caaf..5ad09448 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +Tue Mar 29 00:45:11 EEST 2005 Pekka Riikonen + + * Fixed SILC_STRING_LDAP_DN encoding and decoding. Affected + file lib/silcutil/silcutf8.c. + + * Added SILC_STRING_UTF8_ESCAPE to lib/silcutil/silcstrutil.h. + Mon Mar 28 22:46:23 CEST 2005 Jochen Eisinger * Make public key in getkey reply mandatory. Affected file diff --git a/lib/silcclient/silcclient.h b/lib/silcclient/silcclient.h index edcf2906..8a02c2a6 100644 --- a/lib/silcclient/silcclient.h +++ b/lib/silcclient/silcclient.h @@ -853,7 +853,7 @@ typedef struct { /* If this is set to TRUE, the silcclient library will not register and deregister the cipher, pkcs, hash and hmac algorithms. The application - itself will need to handle that. */ + itself will need to handle that. */ bool dont_register_crypto_library; } SilcClientParams; diff --git a/lib/silcutil/silcstrutil.h b/lib/silcutil/silcstrutil.h index 6525df50..fe1243f9 100644 --- a/lib/silcutil/silcstrutil.h +++ b/lib/silcutil/silcstrutil.h @@ -4,7 +4,7 @@ Author: Pekka Riikonen - Copyright (C) 2002 - 2004 Pekka Riikonen + Copyright (C) 2002 - 2005 Pekka Riikonen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -61,6 +61,7 @@ typedef enum { SILC_STRING_TELETEX = 10, /* Teletex ASCII string */ SILC_STRING_NUMERICAL = 11, /* Numerical ASCII string (digits) */ SILC_STRING_LDAP_DN = 12, /* Strings for LDAP DNs, RFC 2253 */ + SILC_STRING_UTF8_ESCAPE = 12, /* Escaped UTF-8 as defined in RFC 2253 */ SILC_STRING_LANGUAGE = 6, /* _Deprecated_, use SILC_STRING_LOCALE. */ } SilcStringEncoding; diff --git a/lib/silcutil/silcutf8.c b/lib/silcutil/silcutf8.c index 6c4168c1..372d900b 100644 --- a/lib/silcutil/silcutf8.c +++ b/lib/silcutil/silcutf8.c @@ -46,6 +46,49 @@ SilcUInt32 silc_utf8_encode(const unsigned char *bin, SilcUInt32 bin_len, return bin_len; } + /* The SILC_STRING_LDAP_DN is alredy UTF-8 but it may be escaped. We + remove the escaping and we're done. */ + if (bin_encoding == SILC_STRING_LDAP_DN || + bin_encoding == SILC_STRING_UTF8_ESCAPE) { + unsigned char cv; + + for (i = 0; i < bin_len; i++) { + if (bin[i] == '\\') { + if (i + 1 >= bin_len) + return 0; + + /* If escaped character is any of the following no processing is + needed, otherwise it is a hex value and we need to read it. */ + cv = bin[i + 1]; + if (cv != ',' && cv != '+' && cv != '"' && cv != '\\' && cv != '<' && + cv != '>' && cv != ';' && cv != ' ' && cv != '#') { + unsigned int hexval; + if (i + 2 >= bin_len) + return 0; + if (sscanf(&bin[i + 1], "%02X", &hexval) != 1) + return 0; + if (utf8) { + if (enclen + 1 > utf8_size) + return 0; + utf8[enclen] = (unsigned char)hexval; + } + + i += 2; + enclen++; + } + } else { + if (utf8) { + if (enclen + 1 > utf8_size) + return 0; + utf8[enclen] = bin[i]; + } + enclen++; + } + } + + return enclen; + } + if (bin_encoding == SILC_STRING_LOCALE) { #if defined(HAVE_ICONV) && defined(HAVE_NL_LANGINFO) && defined(CODESET) char *fromconv, *icp, *ocp; @@ -121,31 +164,6 @@ SilcUInt32 silc_utf8_encode(const unsigned char *bin, SilcUInt32 bin_len, return 0; charval = bin[i]; break; - case SILC_STRING_LDAP_DN: - /* Remove any escaping */ - if (bin[i] == '\\') { - unsigned char cv; - if (i + 1 >= bin_len) - return 0; - - /* If escaped character is any of the following no processing is - needed, otherwise it is a hex value and we need to read it. */ - cv = bin[++i]; - if (cv != ',' && cv != '+' && cv != '"' && cv != '\\' && cv != '<' && - cv != '>' && cv != ';' && cv != ' ' && cv != '#') { - unsigned int hexval; - if (i + 1 >= bin_len) - return 0; - if (sscanf(&bin[++i], "%02X", &hexval) != 1) - return 0; - cv = (unsigned char)hexval; - } - - charval = cv; - break; - } - charval = bin[i]; - break; default: return 0; break; @@ -231,7 +249,7 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, SilcStringEncoding bin_encoding, unsigned char *bin, SilcUInt32 bin_size) { - SilcUInt32 enclen = 0, i, charval; + SilcUInt32 enclen = 0, i, charval, bytes; if (!utf8 || !utf8_len) return 0; @@ -277,6 +295,7 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, for (i = 0; i < utf8_len; i++) { if ((utf8[i] & 0x80) == 0x00) { charval = utf8[i] & 0x7f; + bytes = 1; } else if ((utf8[i] & 0xe0) == 0xc0) { if (i + 1 >= utf8_len) return 0; @@ -288,6 +307,7 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, charval |= utf8[i] & 0x3f; if (charval < 0x80) return 0; + bytes = 2; } else if ((utf8[i] & 0xf0) == 0xe0) { if (i + 2 >= utf8_len) return 0; @@ -307,6 +327,7 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, charval |= utf8[i] & 0x3f; if (charval < 0x800) return 0; + bytes = 3; } else if ((utf8[i] & 0xf8) == 0xf0) { if (i + 3 >= utf8_len) return 0; @@ -322,6 +343,7 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, charval |= utf8[i] & 0x3f; if (charval < 0x10000) return 0; + bytes = 4; } else if ((utf8[i] & 0xfc) == 0xf8) { if (i + 4 >= utf8_len) return 0; @@ -339,6 +361,7 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, charval |= utf8[i] & 0x3f; if (charval < 0x200000) return 0; + bytes = 5; } else if ((utf8[i] & 0xfe) == 0xfc) { if (i + 5 >= utf8_len) return 0; @@ -358,6 +381,7 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, charval |= utf8[i] & 0x3f; if (charval < 0x4000000) return 0; + bytes = 6; } else { return 0; } @@ -414,64 +438,70 @@ SilcUInt32 silc_utf8_decode(const unsigned char *utf8, SilcUInt32 utf8_len, break; case SILC_STRING_LDAP_DN: { - /* XXX multibyte handling */ - unsigned char cv = (unsigned char)charval; + int k; + unsigned char cv; - /* If string starts with space or # escape it */ - if (!enclen && (cv == '#' || cv == ' ')) { - if (bin) { - if (enclen + 2 > bin_size) - return 0; - bin[enclen] = '\\'; - bin[enclen + 1] = cv; + /* Non-printable UTF-8 characters will be escaped, printable will + be as is. We take the bytes directly from the original data. */ + for (k = 0; k < bytes; k++) { + cv = utf8[(i - (bytes - 1)) + k]; + + /* If string starts with space or # escape it */ + if (!enclen && (cv == '#' || cv == ' ')) { + if (bin) { + if (enclen + 2 > bin_size) + return 0; + bin[enclen] = '\\'; + bin[enclen + 1] = cv; + } + enclen += 2; + continue; } - enclen += 2; - break; - } - /* If string ends with space escape it */ - if (i == utf8_len - 1 && cv == ' ') { - if (bin) { - if (enclen + 2 > bin_size) - return 0; - bin[enclen] = '\\'; - bin[enclen + 1] = cv; + /* If string ends with space escape it */ + if (i == utf8_len - 1 && cv == ' ') { + if (bin) { + if (enclen + 2 > bin_size) + return 0; + bin[enclen] = '\\'; + bin[enclen + 1] = cv; + } + enclen += 2; + continue; } - enclen += 2; - break; - } - /* If character is any of following then escape */ - if (cv == ',' || cv == '+' || cv == '"' || cv == '\\' || cv == '<' || - cv == '>' || cv == ';') { - if (bin) { - if (enclen + 2 > bin_size) - return 0; - bin[enclen] = '\\'; - bin[enclen + 1] = cv; + /* If character is any of following then escape */ + if (cv == ',' || cv == '+' || cv == '"' || cv == '\\' || cv == '<' || + cv == '>' || cv == ';') { + if (bin) { + if (enclen + 2 > bin_size) + return 0; + bin[enclen] = '\\'; + bin[enclen + 1] = cv; + } + enclen += 2; + continue; + } + + /* If character is not printable escape it with hex character */ + if (!isprint((int)cv)) { + if (bin) { + if (enclen + 3 > bin_size) + return 0; + bin[enclen] = '\\'; + snprintf(bin + enclen + 1, 3, "%02X", cv); + } + enclen += 3; + continue; } - enclen += 2; - break; - } - /* If character is not printable escape it with hex character */ - if (!isprint((int)cv)) { if (bin) { - if (enclen + 2 > bin_size) + if (enclen + 1 > bin_size) return 0; - bin[enclen] = '\\'; - snprintf(bin + enclen + 1, 3, "%02X", cv); + bin[enclen] = cv; } - enclen += 2; - break; + enclen++; } - - if (bin) { - if (enclen + 1 > bin_size) - return 0; - bin[enclen] = cv; - } - enclen++; } break; default: diff --git a/lib/silcutil/tests/test_silcstrutil.c b/lib/silcutil/tests/test_silcstrutil.c index 1e537a63..670cd3e1 100644 --- a/lib/silcutil/tests/test_silcstrutil.c +++ b/lib/silcutil/tests/test_silcstrutil.c @@ -51,6 +51,8 @@ utf8fail(30, "\xf0\x20\xf9\x20\xfa\x20\xfb\x20", 8); int main(int argc, char **argv) { bool success = FALSE; + unsigned char *s1, *s3, *s4; + int l; if (argc > 1 && !strcmp(argv[1], "-d")) { silc_debug = 1; @@ -75,6 +77,34 @@ int main(int argc, char **argv) utf8failc(27); utf8failc(28); utf8failc(29); utf8failc(30); + /* LDAP DN simple test */ + s1 = "#&?*Pekka, Riikonen, \xc4\x8d "; + SILC_LOG_DEBUG(("s1 = %s", s1)); + + /* To LDAP DN */ + l = silc_utf8_decoded_len(s1, strlen(s1), SILC_STRING_LDAP_DN); + if (!l) + goto err; + s3 = silc_calloc(l + 1, sizeof(*s3)); + silc_utf8_decode(s1, strlen(s1), SILC_STRING_LDAP_DN, s3, l); + SILC_LOG_DEBUG(("ldapdn = %s", s3)); + + /* To UTF-8 */ + l = silc_utf8_encoded_len(s3, strlen(s3), SILC_STRING_LDAP_DN); + if (!l) + goto err; + s4 = silc_calloc(l + 1, sizeof(*s4)); + silc_utf8_encode(s3, strlen(s3), SILC_STRING_LDAP_DN, s4, l); + SILC_LOG_DEBUG(("utf8 = %s", s4)); + + if (memcmp(s4, s1, strlen(s4))) { + SILC_LOG_DEBUG(("UTF-8 mismatch")); + goto err; + } + + silc_free(s3); + silc_free(s4); + success = TRUE; err: -- 2.24.0