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;