5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2004 - 2005 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
20 #include "silcincludes.h"
21 #include "silcstringprep.h"
22 #include <stringprep.h>
24 /* We use GNU Libidn which has stringprep to do the magic. Only bad thing
25 is that its interface is idiotic. We have our own API here in case
26 we'll implement it ourselves later. */
28 /* Prohibited characters as defined by the protocol in Appendix B */
29 const Stringprep_table_element silc_appendix_b[] =
31 {0x000021}, {0x00002A}, {0x00002C}, {0x00003F}, {0x000040},
33 {0x0000AC}, {0x0000AE}, {0x0000AF}, {0x0000B0}, {0x0000B1}, {0x0000B4},
34 {0x0000B6}, {0x0000B8}, {0x0000D7}, {0x0000F7},
35 {0x0002C2, 0x0002C5}, {0x0002D2, 0x0002FF},
36 {0x000374}, {0x000375}, {0x000384}, {0x000385}, {0x0003F6}, {0x000482},
37 {0x00060E}, {0x00060F}, {0x0006E9}, {0x0006FD}, {0x0006FE}, {0x0009F2},
38 {0x0009F3}, {0x0009FA}, {0x000AF1}, {0x000B70},
39 {0x000BF3, 0x000BFA}, {0x000E3F},
40 {0x000F01, 0x000F03}, {0x000F13, 0x000F17}, {0x000F1A, 0x000F1F},
41 {0x000F34}, {0x000F36}, {0x000F38}, {0x000FBE}, {0x000FBF},
42 {0x000FC0, 0x000FC5}, {0x000FC7, 0x000FCF}, {0x0017DB}, {0x001940},
43 {0x0019E0, 0x0019FF}, {0x001FBD}, {0x001FBF, 0x001FC1},
44 {0x001FCD, 0x001FCF}, {0x001FDD, 0x001FDF}, {0x001FED, 0x001FEF},
45 {0x001FFD}, {0x001FFE}, {0x002044}, {0x002052}, {0x00207A, 0x00207C},
46 {0x00208A, 0x00208C}, {0x0020A0, 0x0020B1}, {0x002100, 0x00214F},
47 {0x002150, 0x00218F}, {0x002190, 0x0021FF}, {0x002200, 0x0022FF},
48 {0x002300, 0x0023FF}, {0x002400, 0x00243F}, {0x002440, 0x00245F},
49 {0x002460, 0x0024FF}, {0x002500, 0x00257F}, {0x002580, 0x00259F},
50 {0x0025A0, 0x0025FF}, {0x002600, 0x0026FF}, {0x002700, 0x0027BF},
51 {0x0027C0, 0x0027EF}, {0x0027F0, 0x0027FF}, {0x002800, 0x0028FF},
52 {0x002900, 0x00297F}, {0x002980, 0x0029FF}, {0x002A00, 0x002AFF},
53 {0x002B00, 0x002BFF}, {0x002E9A}, {0x002EF4, 0x002EFF},
54 {0x002FF0, 0x002FFF}, {0x00303B, 0x00303D}, {0x003040},
55 {0x003095, 0x003098}, {0x00309F, 0x0030A0}, {0x0030FF, 0x003104},
56 {0x00312D, 0x003130}, {0x00318F}, {0x0031B8, 0x0031FF},
57 {0x00321D, 0x00321F}, {0x003244, 0x00325F}, {0x00327C, 0x00327E},
58 {0x0032B1, 0x0032BF}, {0x0032CC, 0x0032CF}, {0x0032FF},
59 {0x003377, 0x00337A}, {0x0033DE, 0x0033DF}, {0x0033FF},
61 {0x009FA6, 0x009FFF}, {0x00A48D, 0x00A48F}, {0x00A4A2, 0x00A4A3},
62 {0x00A4B4}, {0x00A4C1}, {0x00A4C5}, {0x00A4C7, 0x00ABFF},
63 {0x00D7A4, 0x00D7FF}, {0x00FA2E, 0x00FAFF}, {0x00FFE0, 0x00FFEE},
64 {0x00FFFC}, {0x010000, 0x01007F}, {0x010080, 0x0100FF},
65 {0x010100, 0x01013F}, {0x01D000, 0x01D0FF}, {0x01D100, 0x01D1FF},
66 {0x01D300, 0x01D35F}, {0x01D400, 0x01D7FF},
71 /* Default SILC Identifier String profile defined by the protocol */
72 const Stringprep_profile stringprep_silc_identifier_prep[] =
74 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1},
75 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2},
76 {STRINGPREP_NFKC, 0, 0},
77 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_1},
78 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_2},
79 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_1},
80 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2},
81 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_3},
82 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_4},
83 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_5},
84 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_6},
85 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_7},
86 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8},
87 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9},
88 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9},
89 {STRINGPREP_PROHIBIT_TABLE, 0, silc_appendix_b},
90 {STRINGPREP_UNASSIGNED_TABLE, 0, stringprep_rfc3454_A_1},
94 /* Identifier string case folding and normalizing */
95 const Stringprep_profile stringprep_silc_identifierc_prep[] =
97 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1},
98 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2},
99 {STRINGPREP_NFKC, 0, 0},
103 /* Case folding and normalizing */
104 const Stringprep_profile stringprep_silc_casefold_prep[] =
106 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2},
107 {STRINGPREP_NFKC, 0, 0},
112 /* Prepares string according to the profile */
115 silc_stringprep(const unsigned char *bin, SilcUInt32 bin_len,
116 SilcStringEncoding bin_encoding,
117 const char *profile_name,
118 SilcStringprepFlags flags,
119 unsigned char **out, SilcUInt32 *out_len,
120 SilcStringEncoding out_encoding)
122 Stringprep_profile_flags f = 0;
123 const Stringprep_profile *profile;
124 unsigned char *utf8s;
125 SilcUInt32 utf8s_len;
128 SILC_LOG_DEBUG(("Preparing string"));
130 if (!bin || !bin_len || !profile_name)
131 return SILC_STRINGPREP_ERR;
133 /* Convert string to UTF-8 */
134 utf8s_len = silc_utf8_encoded_len(bin, bin_len, bin_encoding);
136 return SILC_STRINGPREP_ERR_ENCODING;
137 utf8s = silc_calloc(utf8s_len + 1, sizeof(*utf8s));
139 return SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
140 silc_utf8_encode(bin, bin_len, bin_encoding, utf8s, utf8s_len);
143 if (!strcmp(profile_name, SILC_IDENTIFIER_PREP))
144 profile = stringprep_silc_identifier_prep;
145 else if (!strcmp(profile_name, SILC_IDENTIFIERC_PREP))
146 profile = stringprep_silc_identifierc_prep;
147 else if (!strcmp(profile_name, SILC_CASEFOLD_PREP))
148 profile = stringprep_silc_casefold_prep;
150 return SILC_STRINGPREP_ERR_UNSUP_PROFILE;
152 /* Translate flags */
153 if (!(flags & SILC_STRINGPREP_ALLOW_UNASSIGNED))
154 f |= STRINGPREP_NO_UNASSIGNED;
157 ret = stringprep((char *)utf8s, utf8s_len + 1, f, profile);
158 SILC_LOG_DEBUG(("stringprep() return %d", ret));
160 /* Since the stringprep() doesn't allocate returned buffer, and
161 stringprep_profile() doesn't do it correctly, we can't know how
162 much space we must have for the conversion. Allocate more if it
163 fails, and try again. */
164 if (ret == STRINGPREP_TOO_SMALL_BUFFER) {
165 utf8s = silc_realloc(utf8s, sizeof(*utf8s) * (utf8s_len * 2));
167 return SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
168 memset(utf8s + utf8s_len, 0, utf8s_len);
169 ret = stringprep((char *)utf8s, utf8s_len * 2, f, profile);
170 SILC_LOG_DEBUG(("stringprep() return %d", ret));
175 ret = SILC_STRINGPREP_OK;
178 case STRINGPREP_CONTAINS_UNASSIGNED:
179 ret = SILC_STRINGPREP_ERR_UNASSIGNED;
182 case STRINGPREP_CONTAINS_PROHIBITED:
183 ret = SILC_STRINGPREP_ERR_PROHIBITED;
186 case STRINGPREP_BIDI_BOTH_L_AND_RAL:
187 ret = SILC_STRINGPREP_ERR_BIDI_RAL_WITH_L;
190 case STRINGPREP_BIDI_LEADTRAIL_NOT_RAL:
191 ret = SILC_STRINGPREP_ERR_BIDI_RAL;
194 case STRINGPREP_BIDI_CONTAINS_PROHIBITED:
195 ret = SILC_STRINGPREP_ERR_BIDI_PROHIBITED;
198 case STRINGPREP_UNKNOWN_PROFILE:
199 ret = SILC_STRINGPREP_ERR_UNSUP_PROFILE;
202 case STRINGPREP_MALLOC_ERROR:
203 ret = SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
207 ret = SILC_STRINGPREP_ERR;
211 /* Convert to desired output character encoding */
212 if (ret == SILC_STRINGPREP_OK) {
213 if (out && out_len) {
214 if (out_encoding != SILC_STRING_UTF8) {
215 *out_len = silc_utf8_decoded_len(utf8s, strlen(utf8s), out_encoding);
217 *out = silc_calloc(*out_len + 1, sizeof(**out));
219 silc_utf8_decode(utf8s, strlen(utf8s), out_encoding, *out,
222 ret = SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
225 ret = SILC_STRINGPREP_ERR_ENCODING;
228 *out_len = strlen(utf8s);
229 *out = silc_memdup(utf8s, *out_len);
236 return (SilcStringprepStatus)ret;