Merged silc_1_0_branch to trunk.
[silc.git] / lib / silcutil / silcstrutil.c
1 /*
2
3   silcstrutil.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 - 2005 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* $Id$ */
20
21 #include "silcincludes.h"
22 #include "silcstrutil.h"
23
24 static unsigned char pem_enc[64] =
25 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
26
27 /* Encodes data into PEM encoding. Returns NULL terminated PEM encoded
28    data string. */
29
30 char *silc_pem_encode(unsigned char *data, SilcUInt32 len)
31 {
32   int i, j;
33   SilcUInt32 bits, c, char_count;
34   char *pem;
35
36   char_count = 0;
37   bits = 0;
38   j = 0;
39
40   pem = silc_calloc(((len * 8 + 5) / 6) + 5, sizeof(*pem));
41
42   for (i = 0; i < len; i++) {
43     c = data[i];
44     bits += c;
45     char_count++;
46
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];
52       bits = 0;
53       char_count = 0;
54     } else {
55       bits <<= 8;
56     }
57   }
58
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];
63
64     if (char_count == 1) {
65       pem[j++] = '=';
66       pem[j] = '=';
67     } else {
68       pem[j++] = pem_enc[(bits >> 6) & 0x3f];
69       pem[j] = '=';
70     }
71   }
72
73   return pem;
74 }
75
76 /* Same as above but puts newline ('\n') every 72 characters. */
77
78 char *silc_pem_encode_file(unsigned char *data, SilcUInt32 data_len)
79 {
80   int i, j;
81   SilcUInt32 len, cols;
82   char *pem, *pem2;
83
84   pem = silc_pem_encode(data, data_len);
85   len = strlen(pem);
86
87   pem2 = silc_calloc(len + (len / 72) + 1, sizeof(*pem2));
88
89   for (i = 0, j = 0, cols = 1; i < len; i++, cols++) {
90     if (cols == 72) {
91       pem2[i] = '\n';
92       cols = 0;
93       len++;
94       continue;
95     }
96
97     pem2[i] = pem[j++];
98   }
99
100   silc_free(pem);
101   return pem2;
102 }
103
104 /* Decodes PEM into data. Returns the decoded data. */
105
106 unsigned char *silc_pem_decode(unsigned char *pem, SilcUInt32 pem_len,
107                                SilcUInt32 *ret_len)
108 {
109   int i, j;
110   SilcUInt32 len, c, char_count, bits;
111   unsigned char *data;
112   static char ialpha[256], decoder[256];
113
114   for (i = 64 - 1; i >= 0; i--) {
115     ialpha[pem_enc[i]] = 1;
116     decoder[pem_enc[i]] = i;
117   }
118
119   char_count = 0;
120   bits = 0;
121   j = 0;
122
123   if (!pem_len)
124     len = strlen(pem);
125   else
126     len = pem_len;
127
128   data = silc_calloc(((len * 6) / 8), sizeof(*data));
129
130   for (i = 0; i < len; i++) {
131     c = pem[i];
132
133     if (c == '=')
134       break;
135
136     if (c > 127 || !ialpha[c])
137       continue;
138
139     bits += decoder[c];
140     char_count++;
141
142     if (char_count == 4) {
143       data[j++] = bits >> 16;
144       data[j++] = (bits >> 8) & 0xff;
145       data[j++] = bits & 0xff;
146       bits = 0;
147       char_count = 0;
148     } else {
149       bits <<= 6;
150     }
151   }
152
153   switch(char_count) {
154   case 1:
155     silc_free(data);
156     return NULL;
157     break;
158   case 2:
159     data[j++] = bits >> 10;
160     break;
161   case 3:
162     data[j++] = bits >> 16;
163     data[j++] = (bits >> 8) & 0xff;
164     break;
165   }
166
167   if (ret_len)
168     *ret_len = j;
169
170   return data;
171 }
172
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
180
181 #define MIME_GET_FIELD(mime, mime_len, field, field_len,                \
182                        dest, dest_size)                                 \
183 do {                                                                    \
184   if (dest) {                                                           \
185     char *f = strstr(mime, field);                                      \
186     if (f) {                                                            \
187       int parse_len;                                                    \
188       f += field_len;                                                   \
189       parse_len = (mime_len - (f - (char *)mime));                      \
190       for (i = 0; i < parse_len; i++) {                                 \
191         if ((i == dest_size) ||                                         \
192             ((f[i] == '\n') &&                                          \
193                ((i == parse_len - 1) ||                                 \
194                   ((f[i+1] != ' ') && (f[i+1] != '\t')))) ||            \
195             ((f[i] == '\r') &&                                          \
196                ((i == parse_len - 1) || (f[i+1] == '\n')) &&            \
197                ((i >= parse_len - 2) ||                                 \
198                   ((f[i+2] != ' ') && (f[i+2] != '\t')))))              \
199           break;                                                        \
200         dest[i] = f[i];                                                 \
201       }                                                                 \
202     }                                                                   \
203   }                                                                     \
204 } while(0)
205
206 /* Parses MIME object and MIME header in it. */
207
208 bool
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)
214 {
215   int i;
216   unsigned char *tmp;
217
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'))
225       break;
226   }
227   if (i >= mime_len)
228     return FALSE;
229
230   if (mime_data_ptr)
231     *mime_data_ptr = (unsigned char *)mime + i +
232             (mime[i] == '\n' ? 2 : 4);
233   if (mime_data_len)
234     *mime_data_len = mime_len - (i + (mime[i] == '\n' ? 2 : 4));
235
236   /* Check for mandatory Content-Type field */
237   tmp = strstr(mime, MIME_CONTENT_TYPE);
238   if (!tmp || (tmp - mime) >= i)
239     return FALSE;
240
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);
251
252   return TRUE;
253 }
254
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
257    truncated to fit. */
258
259 char *silc_strncat(char *dest, SilcUInt32 dest_size,
260                    const char *src, SilcUInt32 src_len)
261 {
262   int len;
263
264   dest[dest_size - 1] = '\0';
265
266   len = dest_size - 1 - strlen(dest);
267   if (len < src_len) {
268     if (len > 0)
269       strncat(dest, src, len);
270   } else {
271     strncat(dest, src, src_len);
272   }
273
274   return dest;
275 }
276
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. */
282
283 unsigned char *silc_identifier_check(const unsigned char *identifier,
284                                      SilcUInt32 identifier_len,
285                                      SilcStringEncoding identifier_encoding,
286                                      SilcUInt32 max_allowed_length,
287                                      SilcUInt32 *out_len)
288 {
289   unsigned char *utf8s;
290   SilcUInt32 utf8s_len;
291   SilcStringprepStatus status;
292
293   if (!identifier || !identifier_len)
294     return NULL;
295
296   if (max_allowed_length && identifier_len > max_allowed_length)
297     return NULL;
298
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));
304     return NULL;
305   }
306
307   if (out_len)
308     *out_len = utf8s_len;
309
310   return utf8s;
311 }
312
313 /* Same as above but does not allocate memory, just checks the
314    validity of the string. */
315
316 bool silc_identifier_verify(const unsigned char *identifier,
317                             SilcUInt32 identifier_len,
318                             SilcStringEncoding identifier_encoding,
319                             SilcUInt32 max_allowed_length)
320 {
321   SilcStringprepStatus status;
322
323   if (!identifier || !identifier_len)
324     return FALSE;
325
326   if (max_allowed_length && identifier_len > max_allowed_length)
327     return FALSE;
328
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));
334     return FALSE;
335   }
336
337   return TRUE;
338 }
339
340 unsigned char *silc_channel_name_check(const unsigned char *identifier,
341                                        SilcUInt32 identifier_len,
342                                        SilcStringEncoding identifier_encoding,
343                                        SilcUInt32 max_allowed_length,
344                                        SilcUInt32 *out_len)
345 {
346   unsigned char *utf8s;
347   SilcUInt32 utf8s_len;
348   SilcStringprepStatus status;
349
350   if (!identifier || !identifier_len)
351     return NULL;
352
353   if (max_allowed_length && identifier_len > max_allowed_length)
354     return NULL;
355
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));
361     return NULL;
362   }
363
364   if (out_len)
365     *out_len = utf8s_len;
366
367   return utf8s;
368 }
369
370 /* Same as above but does not allocate memory, just checks the
371    validity of the string. */
372
373 bool silc_channel_name_verify(const unsigned char *identifier,
374                               SilcUInt32 identifier_len,
375                               SilcStringEncoding identifier_encoding,
376                               SilcUInt32 max_allowed_length)
377 {
378   SilcStringprepStatus status;
379
380   if (!identifier || !identifier_len)
381     return FALSE;
382
383   if (max_allowed_length && identifier_len > max_allowed_length)
384     return FALSE;
385
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));
391     return FALSE;
392   }
393
394   return TRUE;
395 }