5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2004 - 2008 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 "silcruntime.h"
21 #include "stringprep.h"
23 /* We use GNU Libidn which has stringprep to do the magic. Only bad thing
24 is that its interface is idiotic. We have our own API here in case
25 we'll implement it ourselves later. */
27 /* Prohibited characters as defined by the protocol in Appendix C */
28 const Stringprep_table_element silc_appendix_c[] =
30 {0x000021}, {0x00002A}, {0x00002C}, {0x00003F}, {0x000040},
34 /* Prohibited characters as defined by the protocol in Appendix D */
35 const Stringprep_table_element silc_appendix_d[] =
38 {0x0000AC}, {0x0000AE}, {0x0000AF}, {0x0000B0}, {0x0000B1}, {0x0000B4},
39 {0x0000B6}, {0x0000B8}, {0x0000D7}, {0x0000F7},
40 {0x0002C2, 0x0002C5}, {0x0002D2, 0x0002FF},
41 {0x000374}, {0x000375}, {0x000384}, {0x000385}, {0x0003F6}, {0x000482},
42 {0x00060E}, {0x00060F}, {0x0006E9}, {0x0006FD}, {0x0006FE}, {0x0009F2},
43 {0x0009F3}, {0x0009FA}, {0x000AF1}, {0x000B70},
44 {0x000BF3, 0x000BFA}, {0x000E3F},
45 {0x000F01, 0x000F03}, {0x000F13, 0x000F17}, {0x000F1A, 0x000F1F},
46 {0x000F34}, {0x000F36}, {0x000F38}, {0x000FBE}, {0x000FBF},
47 {0x000FC0, 0x000FC5}, {0x000FC7, 0x000FCF}, {0x0017DB}, {0x001940},
48 {0x0019E0, 0x0019FF}, {0x001FBD}, {0x001FBF, 0x001FC1},
49 {0x001FCD, 0x001FCF}, {0x001FDD, 0x001FDF}, {0x001FED, 0x001FEF},
50 {0x001FFD}, {0x001FFE}, {0x002044}, {0x002052}, {0x00207A, 0x00207C},
51 {0x00208A, 0x00208C}, {0x0020A0, 0x0020B1}, {0x002100, 0x00214F},
52 {0x002150, 0x00218F}, {0x002190, 0x0021FF}, {0x002200, 0x0022FF},
53 {0x002300, 0x0023FF}, {0x002400, 0x00243F}, {0x002440, 0x00245F},
54 {0x002460, 0x0024FF}, {0x002500, 0x00257F}, {0x002580, 0x00259F},
55 {0x0025A0, 0x0025FF}, {0x002600, 0x0026FF}, {0x002700, 0x0027BF},
56 {0x0027C0, 0x0027EF}, {0x0027F0, 0x0027FF}, {0x002800, 0x0028FF},
57 {0x002900, 0x00297F}, {0x002980, 0x0029FF}, {0x002A00, 0x002AFF},
58 {0x002B00, 0x002BFF}, {0x002E9A}, {0x002EF4, 0x002EFF},
59 {0x002FF0, 0x002FFF}, {0x00303B, 0x00303D}, {0x003040},
60 {0x003095, 0x003098}, {0x00309F, 0x0030A0}, {0x0030FF, 0x003104},
61 {0x00312D, 0x003130}, {0x00318F}, {0x0031B8, 0x0031FF},
62 {0x00321D, 0x00321F}, {0x003244, 0x00325F}, {0x00327C, 0x00327E},
63 {0x0032B1, 0x0032BF}, {0x0032CC, 0x0032CF}, {0x0032FF},
64 {0x003377, 0x00337A}, {0x0033DE, 0x0033DF}, {0x0033FF},
66 {0x009FA6, 0x009FFF}, {0x00A48D, 0x00A48F}, {0x00A4A2, 0x00A4A3},
67 {0x00A4B4}, {0x00A4C1}, {0x00A4C5}, {0x00A4C7, 0x00ABFF},
68 {0x00D7A4, 0x00D7FF}, {0x00FA2E, 0x00FAFF}, {0x00FFE0, 0x00FFEE},
69 {0x00FFFC}, {0x010000, 0x01007F}, {0x010080, 0x0100FF},
70 {0x010100, 0x01013F}, {0x01D000, 0x01D0FF}, {0x01D100, 0x01D1FF},
71 {0x01D300, 0x01D35F}, {0x01D400, 0x01D7FF},
76 /* Default SILC Identifier String profile defined by the protocol */
77 const Stringprep_profile stringprep_silc_identifier_prep[] =
79 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1},
80 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2},
81 {STRINGPREP_NFKC, 0, 0},
82 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_1},
83 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_2},
84 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_1},
85 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2},
86 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_3},
87 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_4},
88 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_5},
89 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_6},
90 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_7},
91 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8},
92 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9},
93 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9},
94 {STRINGPREP_PROHIBIT_TABLE, 0, silc_appendix_c},
95 {STRINGPREP_PROHIBIT_TABLE, 0, silc_appendix_d},
96 {STRINGPREP_UNASSIGNED_TABLE, 0, stringprep_rfc3454_A_1},
100 /* Default channel name string profile defined by the protocol */
101 const Stringprep_profile stringprep_silc_identifier_ch_prep[] =
103 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1},
104 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2},
105 {STRINGPREP_NFKC, 0, 0},
106 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_1},
107 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_1_2},
108 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_1},
109 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_2_2},
110 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_3},
111 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_4},
112 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_5},
113 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_6},
114 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_7},
115 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_8},
116 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9},
117 {STRINGPREP_PROHIBIT_TABLE, 0, stringprep_rfc3454_C_9},
118 {STRINGPREP_PROHIBIT_TABLE, 0, silc_appendix_d},
119 {STRINGPREP_UNASSIGNED_TABLE, 0, stringprep_rfc3454_A_1},
123 /* Identifier string case folding and normalizing */
124 const Stringprep_profile stringprep_silc_identifierc_prep[] =
126 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_1},
127 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2},
128 {STRINGPREP_NFKC, 0, 0},
132 /* Case folding and normalizing */
133 const Stringprep_profile stringprep_silc_casefold_prep[] =
135 {STRINGPREP_MAP_TABLE, 0, stringprep_rfc3454_B_2},
136 {STRINGPREP_NFKC, 0, 0},
141 /* Prepares string according to the profile */
144 silc_stringprep(const unsigned char *bin, SilcUInt32 bin_len,
145 SilcStringEncoding bin_encoding,
146 const char *profile_name,
147 SilcStringprepFlags flags,
148 unsigned char **out, SilcUInt32 *out_len,
149 SilcStringEncoding out_encoding)
151 Stringprep_profile_flags f = 0;
152 const Stringprep_profile *profile;
153 unsigned char *utf8s;
154 SilcUInt32 utf8s_len;
157 SILC_LOG_DEBUG(("Preparing string"));
159 if (!bin || !bin_len || !profile_name)
160 return SILC_STRINGPREP_ERR;
162 /* Convert string to UTF-8 */
163 utf8s_len = silc_utf8_encoded_len(bin, bin_len, bin_encoding);
165 return SILC_STRINGPREP_ERR_ENCODING;
166 utf8s = silc_calloc(utf8s_len + 1, sizeof(*utf8s));
168 return SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
169 silc_utf8_encode(bin, bin_len, bin_encoding, utf8s, utf8s_len);
172 if (!strcmp(profile_name, SILC_IDENTIFIER_PREP))
173 profile = stringprep_silc_identifier_prep;
174 else if (!strcmp(profile_name, SILC_IDENTIFIER_CH_PREP))
175 profile = stringprep_silc_identifier_ch_prep;
176 else if (!strcmp(profile_name, SILC_IDENTIFIERC_PREP))
177 profile = stringprep_silc_identifierc_prep;
178 else if (!strcmp(profile_name, SILC_CASEFOLD_PREP))
179 profile = stringprep_silc_casefold_prep;
181 return SILC_STRINGPREP_ERR_UNSUP_PROFILE;
183 /* Translate flags */
184 if (!(flags & SILC_STRINGPREP_ALLOW_UNASSIGNED))
185 f |= STRINGPREP_NO_UNASSIGNED;
188 ret = stringprep((char *)utf8s, utf8s_len, f, profile);
189 SILC_LOG_DEBUG(("stringprep() return %d", ret));
191 /* Since the stringprep() doesn't allocate returned buffer, and
192 stringprep_profile() doesn't do it correctly, we can't know how
193 much space we must have for the conversion. Allocate more if it
194 fails, and try again. */
195 if (ret == STRINGPREP_TOO_SMALL_BUFFER) {
196 utf8s = silc_realloc(utf8s, sizeof(*utf8s) * ((utf8s_len * 2) + 1));
198 return SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
199 memset(utf8s + utf8s_len + 1, 0, utf8s_len);
200 ret = stringprep((char *)utf8s, utf8s_len * 2, f, profile);
201 SILC_LOG_DEBUG(("stringprep() return %d", ret));
206 ret = SILC_STRINGPREP_OK;
209 case STRINGPREP_CONTAINS_UNASSIGNED:
210 ret = SILC_STRINGPREP_ERR_UNASSIGNED;
213 case STRINGPREP_CONTAINS_PROHIBITED:
214 ret = SILC_STRINGPREP_ERR_PROHIBITED;
217 case STRINGPREP_BIDI_BOTH_L_AND_RAL:
218 ret = SILC_STRINGPREP_ERR_BIDI_RAL_WITH_L;
221 case STRINGPREP_BIDI_LEADTRAIL_NOT_RAL:
222 ret = SILC_STRINGPREP_ERR_BIDI_RAL;
225 case STRINGPREP_BIDI_CONTAINS_PROHIBITED:
226 ret = SILC_STRINGPREP_ERR_BIDI_PROHIBITED;
229 case STRINGPREP_UNKNOWN_PROFILE:
230 ret = SILC_STRINGPREP_ERR_UNSUP_PROFILE;
233 case STRINGPREP_MALLOC_ERROR:
234 ret = SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
238 ret = SILC_STRINGPREP_ERR;
242 /* Convert to desired output character encoding */
243 if (ret == SILC_STRINGPREP_OK) {
244 if (out && out_len) {
245 if (out_encoding != SILC_STRING_UTF8) {
246 *out_len = silc_utf8_decoded_len(utf8s, strlen(utf8s), out_encoding);
248 *out = silc_calloc(*out_len + 1, sizeof(**out));
250 silc_utf8_decode(utf8s, strlen(utf8s), out_encoding, *out,
253 ret = SILC_STRINGPREP_ERR_OUT_OF_MEMORY;
256 ret = SILC_STRINGPREP_ERR_ENCODING;
259 *out_len = strlen(utf8s);
260 *out = silc_memdup(utf8s, *out_len);
267 return (SilcStringprepStatus)ret;