5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2002 - 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.
21 #include "silcincludes.h"
22 #include "silcstrutil.h"
24 static unsigned char pem_enc[64] =
25 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
27 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
30 char *silc_pem_encode(unsigned char *data, SilcUInt32 len)
33 SilcUInt32 bits, c, char_count;
40 pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
42 for (i = 0; i < len; i++) {
47 if (char_count == 3) {
48 pem[j++] = pem_enc[bits >> 18];
49 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
50 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
51 pem[j++] = pem_enc[bits & 0x3f];
59 if (char_count != 0) {
60 bits <<= 16 - (8 * char_count);
61 pem[j++] = pem_enc[bits >> 18];
62 pem[j++] = pem_enc[(bits >> 12) & 0x3f];
64 if (char_count == 1) {
68 pem[j++] = pem_enc[(bits >> 6) & 0x3f];
76 /* Same as above but puts newline ('\n') every 72 characters. */
78 char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len)
84 pem = silc_pem_encode(data, data_len);
87 pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
89 for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
104 /* Decodes PEM into data. Returns the decoded data. */
106 unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
110 SilcUInt32 len, c, char_count, bits;
112 static char ialpha[256], decoder[256];
114 for (i = 64 - 1; i >= 0; i--) {
115 ialpha[pem_enc[i]] = 1;
116 decoder[pem_enc[i]] = i;
128 data = silc_calloc(((len * 6) / 8), sizeof(*data));
130 for (i = 0; i < len; i++) {
136 if (c > 127 || !ialpha[c])
142 if (char_count == 4) {
143 data[j++] = bits >> 16;
144 data[j++] = (bits >> 8) & 0xff;
145 data[j++] = bits & 0xff;
159 data[j++] = bits >> 10;
162 data[j++] = bits >> 16;
163 data[j++] = (bits >> 8) & 0xff;
173 /* Mime constants and macros */
174 #define MIME_VERSION "MIME-Version: "
175 #define MIME_VERSION_LEN 14
176 #define MIME_CONTENT_TYPE "Content-Type: "
177 #define MIME_CONTENT_TYPE_LEN 14
178 #define MIME_TRANSFER_ENCODING "Content-Transfer-Encoding: "
179 #define MIME_TRANSFER_ENCODING_LEN 27
181 #define MIME_GET_FIELD(mime, mime_len, field, field_len, \
185 char *f = strstr(mime, field); \
189 parse_len = (mime_len - (f - (char *)mime)); \
190 for (i = 0; i < parse_len; i++) { \
191 if ((i == dest_size) || \
193 ((i == parse_len - 1) || \
194 ((f[i+1] != ' ') && (f[i+1] != '\t')))) || \
196 ((i == parse_len - 1) || (f[i+1] == '\n')) && \
197 ((i >= parse_len - 2) || \
198 ((f[i+2] != ' ') && (f[i+2] != '\t'))))) \
206 /* Parses MIME object and MIME header in it. */
209 silc_mime_parse(const unsigned char *mime, SilcUInt32 mime_len,
210 char *version, SilcUInt32 version_size,
211 char *content_type, SilcUInt32 content_type_size,
212 char *transfer_encoding, SilcUInt32 transfer_encoding_size,
213 unsigned char **mime_data_ptr, SilcUInt32 *mime_data_len)
218 /* Get the pointer to the data area in the object */
219 for (i = 0; i < mime_len; i++) {
220 if ((mime_len >= i + 4 &&
221 mime[i ] == '\r' && mime[i + 1] == '\n' &&
222 mime[i + 2] == '\r' && mime[i + 3] == '\n') ||
223 (mime_len >= i + 2 &&
224 mime[i ] == '\n' && mime[i + 1] == '\n'))
231 *mime_data_ptr = (unsigned char *)mime + i +
232 (mime[i] == '\n' ? 2 : 4);
234 *mime_data_len = mime_len - (i + (mime[i] == '\n' ? 2 : 4));
236 /* Check for mandatory Content-Type field */
237 tmp = strstr(mime, MIME_CONTENT_TYPE);
238 if (!tmp || (tmp - mime) >= i)
241 /* Get MIME version, Content-Type and Transfer Encoding fields */
242 MIME_GET_FIELD(mime, mime_len,
243 MIME_VERSION, MIME_VERSION_LEN,
244 version, version_size);
245 MIME_GET_FIELD(mime, mime_len,
246 MIME_CONTENT_TYPE, MIME_CONTENT_TYPE_LEN,
247 content_type, content_type_size);
248 MIME_GET_FIELD(mime, mime_len,
249 MIME_TRANSFER_ENCODING, MIME_TRANSFER_ENCODING_LEN,
250 transfer_encoding, transfer_encoding_size);
255 /* Concatenates the `src' into `dest'. If `src_len' is more than the
256 size of the `dest' (minus NULL at the end) the `src' will be
259 char *silc_strncat(char *dest, SilcUInt32 dest_size,
260 const char *src, SilcUInt32 src_len)
264 dest[dest_size - 1] = '\0';
266 len = dest_size - 1 - strlen(dest);
269 strncat(dest, src, len);
271 strncat(dest, src, src_len);
277 /* Checks that the 'identifier' string is valid identifier string
278 and does not contain any unassigned or prohibited character. This
279 function is used to check for valid nicknames, channel names,
280 server names, usernames, hostnames, service names, algorithm names,
281 other security property names, and SILC Public Key name. */
283 unsigned char *silc_identifier_check(const unsigned char *identifier,
284 SilcUInt32 identifier_len,
285 SilcStringEncoding identifier_encoding,
286 SilcUInt32 max_allowed_length,
289 unsigned char *utf8s;
290 SilcUInt32 utf8s_len;
291 SilcStringprepStatus status;
293 if (!identifier || !identifier_len)
296 if (max_allowed_length && identifier_len > max_allowed_length)
299 status = silc_stringprep(identifier, identifier_len,
300 identifier_encoding, SILC_IDENTIFIER_PREP, 0,
301 &utf8s, &utf8s_len, SILC_STRING_UTF8);
302 if (status != SILC_STRINGPREP_OK) {
303 SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
308 *out_len = utf8s_len;
313 /* Same as above but does not allocate memory, just checks the
314 validity of the string. */
316 bool silc_identifier_verify(const unsigned char *identifier,
317 SilcUInt32 identifier_len,
318 SilcStringEncoding identifier_encoding,
319 SilcUInt32 max_allowed_length)
321 SilcStringprepStatus status;
323 if (!identifier || !identifier_len)
326 if (max_allowed_length && identifier_len > max_allowed_length)
329 status = silc_stringprep(identifier, identifier_len,
330 identifier_encoding, SILC_IDENTIFIER_PREP, 0,
331 NULL, NULL, SILC_STRING_UTF8);
332 if (status != SILC_STRINGPREP_OK) {
333 SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
340 unsigned char *silc_channel_name_check(const unsigned char *identifier,
341 SilcUInt32 identifier_len,
342 SilcStringEncoding identifier_encoding,
343 SilcUInt32 max_allowed_length,
346 unsigned char *utf8s;
347 SilcUInt32 utf8s_len;
348 SilcStringprepStatus status;
350 if (!identifier || !identifier_len)
353 if (max_allowed_length && identifier_len > max_allowed_length)
356 status = silc_stringprep(identifier, identifier_len,
357 identifier_encoding, SILC_IDENTIFIER_CH_PREP, 0,
358 &utf8s, &utf8s_len, SILC_STRING_UTF8);
359 if (status != SILC_STRINGPREP_OK) {
360 SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
365 *out_len = utf8s_len;
370 /* Same as above but does not allocate memory, just checks the
371 validity of the string. */
373 bool silc_channel_name_verify(const unsigned char *identifier,
374 SilcUInt32 identifier_len,
375 SilcStringEncoding identifier_encoding,
376 SilcUInt32 max_allowed_length)
378 SilcStringprepStatus status;
380 if (!identifier || !identifier_len)
383 if (max_allowed_length && identifier_len > max_allowed_length)
386 status = silc_stringprep(identifier, identifier_len,
387 identifier_encoding, SILC_IDENTIFIER_CH_PREP, 0,
388 NULL, NULL, SILC_STRING_UTF8);
389 if (status != SILC_STRINGPREP_OK) {
390 SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));