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 C */
29 const Stringprep_table_element silc_appendix_c[] =
31 {0x000021}, {0x00002A}, {0x00002C}, {0x00003F}, {0x000040},
35 /* Prohibited characters as defined by the protocol in Appendix D */
36 const Stringprep_table_element silc_appendix_d[] =
39 {0x0000AC}, {0x0000AE}, {0x0000AF}, {0x0000B0}, {0x0000B1}, {0x0000B4},
40 {0x0000B6}, {0x0000B8}, {0x0000D7}, {0x0000F7},
41 {0x0002C2, 0x0002C5}, {0x0002D2, 0x0002FF},
42 {0x000374}, {0x000375}, {0x000384}, {0x000385}, {0x0003F6}, {0x000482},
43 {0x00060E}, {0x00060F}, {0x0006E9}, {0x0006FD}, {0x0006FE}, {0x0009F2},
44 {0x0009F3}, {0x0009FA}, {0x000AF1}, {0x000B70},
45 {0x000BF3, 0x000BFA}, {0x000E3F},
46 {0x000F01, 0x000F03}, {0x000F13, 0x000F17}, {0x000F1A, 0x000F1F},
47 {0x000F34}, {0x000F36}, {0x000F38}, {0x000FBE}, {0x000FBF},
48 {0x000FC0, 0x000FC5}, {0x000FC7, 0x000FCF}, {0x0017DB}, {0x001940},
49 {0x0019E0, 0x0019FF}, {0x001FBD}, {0x001FBF, 0x001FC1},
50 {0x001FCD, 0x001FCF}, {0x001FDD, 0x001FDF}, {0x001FED, 0x001FEF},
51 {0x001FFD}, {0x001FFE}, {0x002044}, {0x002052}, {0x00207A, 0x00207C},
52 {0x00208A, 0x00208C}, {0x0020A0, 0x0020B1}, {0x002100, 0x00214F},
53 {0x002150, 0x00218F}, {0x002190, 0x0021FF}, {0x002200, 0x0022FF},
54 {0x002300, 0x0023FF}, {0x002400, 0x00243F}, {0x002440, 0x00245F},
55 {0x002460, 0x0024FF}, {0x002500, 0x00257F}, {0x002580, 0x00259F},
56 {0x0025A0, 0x0025FF}, {0x002600, 0x0026FF}, {0x002700, 0x0027BF},
57 {0x0027C0, 0x0027EF}, {0x0027F0, 0x0027FF}, {0x002800, 0x0028FF},
58 {0x002900, 0x00297F}, {0x002980, 0x0029FF}, {0x002A00, 0x002AFF},
59 {0x002B00, 0x002BFF}, {0x002E9A}, {0x002EF4, 0x002EFF},
60 {0x002FF0, 0x002FFF}, {0x00303B, 0x00303D}, {0x003040},
61 {0x003095, 0x003098}, {0x00309F, 0x0030A0}, {0x0030FF, 0x003104},
62 {0x00312D, 0x003130}, {0x00318F}, {0x0031B8, 0x0031FF},
63 {0x00321D, 0x00321F}, {0x003244, 0x00325F}, {0x00327C, 0x00327E},
64 {0x0032B1, 0x0032BF}, {0x0032CC, 0x0032CF}, {0x0032FF},
65 {0x003377, 0x00337A}, {0x0033DE, 0x0033DF}, {0x0033FF},
67 {0x009FA6, 0x009FFF}, {0x00A48D, 0x00A48F}, {0x00A4A2, 0x00A4A3},
68 {0x00A4B4}, {0x00A4C1}, {0x00A4C5}, {0x00A4C7, 0x00ABFF},
69 {0x00D7A4, 0x00D7FF}, {0x00FA2E, 0x00FAFF}, {0x00FFE0, 0x00FFEE},
70 {0x00FFFC}, {0x010000, 0x01007F}, {0x010080, 0x0100FF},
71 {0x010100, 0x01013F}, {0x01D000, 0x01D0FF}, {0x01D100, 0x01D1FF},
72 {0x01D300, 0x01D35F}, {0x01D400, 0x01D7FF},
77 /* Default SILC Identifier String profile defined by the protocol */
78 const Stringprep_profile stringprep_silc_identifier_prep[] =
80 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1},
81 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2},
82 {STRINGPREP_NFKC, 0, 0},
83 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_1},
84 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_2},
85 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_1},
86 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2},
87 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_3},
88 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_4},
89 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_5},
90 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_6},
91 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_7},
92 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8},
93 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9},
94 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9},
95 {STRINGPREP_PROHIBIT_TABLE, 0, silc_appendix_c},
96 {STRINGPREP_PROHIBIT_TABLE, 0, silc_appendix_d},
97 {STRINGPREP_UNASSIGNED_TABLE, 0, stringprep_rfc3454_A_1},
101 /* Default channel name string profile defined by the protocol */
102 const Stringprep_profile stringprep_silc_identifier_ch_prep[] =
104 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1},
105 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2},
106 {STRINGPREP_NFKC, 0, 0},
107 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_1},
108 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_2},
109 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_1},
110 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2},
111 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_3},
112 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_4},
113 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_5},
114 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_6},
115 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_7},
116 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8},
117 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9},
118 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9},
119 {STRINGPREP_PROHIBIT_TABLE, 0, silc_appendix_d},
120 {STRINGPREP_UNASSIGNED_TABLE, 0, stringprep_rfc3454_A_1},
124 /* Identifier string case folding and normalizing */
125 const Stringprep_profile stringprep_silc_identifierc_prep[] =
127 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1},
128 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2},
129 {STRINGPREP_NFKC, 0, 0},
133 /* Case folding and normalizing */
134 const Stringprep_profile stringprep_silc_casefold_prep[] =
136 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2},
137 {STRINGPREP_NFKC, 0, 0},
142 /* Prepares string according to the profile */
145 silc_stringprep(const unsigned char *bin, SilcUInt32 bin_len,
146 SilcStringEncoding bin_encoding,
147 const char *profile_name,
148 SilcStringprepFlags flags,
149 unsigned char **out, SilcUInt32 *out_len,
150 SilcStringEncoding out_encoding)
152 Stringprep_profile_flags f = 0;
153 const Stringprep_profile *profile;
154 unsigned char *utf8s;
155 SilcUInt32 utf8s_len;
158 SILC_LOG_DEBUG(("Preparing string"));
160 if (!bin || !bin_len || !profile_name)
161 return SILC_STRINGPREP_ERR;
163 /* Convert string to UTF-8 */
164 utf8s_len = silc_utf8_encoded_len(bin, bin_len, bin_encoding);
166 return SILC_STRINGPREP_ERR_ENCODING;
167 utf8s = silc_calloc(utf8s_len + 1, sizeof(*utf8s));
169 return SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
170 silc_utf8_encode(bin, bin_len, bin_encoding, utf8s, utf8s_len);
173 if (!strcmp(profile_name, SILC_IDENTIFIER_PREP))
174 profile = stringprep_silc_identifier_prep;
175 else if (!strcmp(profile_name, SILC_IDENTIFIER_CH_PREP))
176 profile = stringprep_silc_identifier_ch_prep;
177 else if (!strcmp(profile_name, SILC_IDENTIFIERC_PREP))
178 profile = stringprep_silc_identifierc_prep;
179 else if (!strcmp(profile_name, SILC_CASEFOLD_PREP))
180 profile = stringprep_silc_casefold_prep;
182 return SILC_STRINGPREP_ERR_UNSUP_PROFILE;
184 /* Translate flags */
185 if (!(flags & SILC_STRINGPREP_ALLOW_UNASSIGNED))
186 f |= STRINGPREP_NO_UNASSIGNED;
189 ret = stringprep((char *)utf8s, utf8s_len + 1, f, profile);
190 SILC_LOG_DEBUG(("stringprep() return %d", ret));
192 /* Since the stringprep() doesn't allocate returned buffer, and
193 stringprep_profile() doesn't do it correctly, we can't know how
194 much space we must have for the conversion. Allocate more if it
195 fails, and try again. */
196 if (ret == STRINGPREP_TOO_SMALL_BUFFER) {
197 utf8s = silc_realloc(utf8s, sizeof(*utf8s) * (utf8s_len * 2));
199 return SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
200 memset(utf8s + utf8s_len, 0, utf8s_len);
201 ret = stringprep((char *)utf8s, utf8s_len * 2, f, profile);
202 SILC_LOG_DEBUG(("stringprep() return %d", ret));
207 ret = SILC_STRINGPREP_OK;
210 case STRINGPREP_CONTAINS_UNASSIGNED:
211 ret = SILC_STRINGPREP_ERR_UNASSIGNED;
214 case STRINGPREP_CONTAINS_PROHIBITED:
215 ret = SILC_STRINGPREP_ERR_PROHIBITED;
218 case STRINGPREP_BIDI_BOTH_L_AND_RAL:
219 ret = SILC_STRINGPREP_ERR_BIDI_RAL_WITH_L;
222 case STRINGPREP_BIDI_LEADTRAIL_NOT_RAL:
223 ret = SILC_STRINGPREP_ERR_BIDI_RAL;
226 case STRINGPREP_BIDI_CONTAINS_PROHIBITED:
227 ret = SILC_STRINGPREP_ERR_BIDI_PROHIBITED;
230 case STRINGPREP_UNKNOWN_PROFILE:
231 ret = SILC_STRINGPREP_ERR_UNSUP_PROFILE;
234 case STRINGPREP_MALLOC_ERROR:
235 ret = SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
239 ret = SILC_STRINGPREP_ERR;
243 /* Convert to desired output character encoding */
244 if (ret == SILC_STRINGPREP_OK) {
245 if (out && out_len) {
246 if (out_encoding != SILC_STRING_UTF8) {
247 *out_len = silc_utf8_decoded_len(utf8s, strlen(utf8s), out_encoding);
249 *out = silc_calloc(*out_len + 1, sizeof(**out));
251 silc_utf8_decode(utf8s, strlen(utf8s), out_encoding, *out,
254 ret = SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
257 ret = SILC_STRINGPREP_ERR_ENCODING;
260 *out_len = strlen(utf8s);
261 *out = silc_memdup(utf8s, *out_len);
268 return (SilcStringprepStatus)ret;