Added SILC Server library.
[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 "silc.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 /* Concatenates the `src' into `dest'.  If `src_len' is more than the
174    size of the `dest' (minus NULL at the end) the `src' will be
175    truncated to fit. */
176
177 char *silc_strncat(char *dest, SilcUInt32 dest_size,
178                    const char *src, SilcUInt32 src_len)
179 {
180   int len;
181
182   dest[dest_size - 1] = '\0';
183
184   len = dest_size - 1 - strlen(dest);
185   if (len < src_len) {
186     if (len > 0)
187       strncat(dest, src, len);
188   } else {
189     strncat(dest, src, src_len);
190   }
191
192   return dest;
193 }
194
195 /* Checks that the 'identifier' string is valid identifier string
196    and does not contain any unassigned or prohibited character.  This
197    function is used to check for valid nicknames, channel names,
198    server names, usernames, hostnames, service names, algorithm names,
199    other security property names, and SILC Public Key name. */
200
201 unsigned char *silc_identifier_check(const unsigned char *identifier,
202                                      SilcUInt32 identifier_len,
203                                      SilcStringEncoding identifier_encoding,
204                                      SilcUInt32 max_allowed_length,
205                                      SilcUInt32 *out_len)
206 {
207   unsigned char *utf8s;
208   SilcUInt32 utf8s_len;
209   SilcStringprepStatus status;
210
211   if (!identifier || !identifier_len)
212     return NULL;
213
214   if (max_allowed_length && identifier_len > max_allowed_length)
215     return NULL;
216
217   status = silc_stringprep(identifier, identifier_len,
218                            identifier_encoding, SILC_IDENTIFIER_PREP, 0,
219                            &utf8s, &utf8s_len, SILC_STRING_UTF8);
220   if (status != SILC_STRINGPREP_OK) {
221     SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
222     return NULL;
223   }
224
225   if (out_len)
226     *out_len = utf8s_len;
227
228   return utf8s;
229 }
230
231 /* Same as above but does not allocate memory, just checks the
232    validity of the string. */
233
234 SilcBool silc_identifier_verify(const unsigned char *identifier,
235                             SilcUInt32 identifier_len,
236                             SilcStringEncoding identifier_encoding,
237                             SilcUInt32 max_allowed_length)
238 {
239   SilcStringprepStatus status;
240
241   if (!identifier || !identifier_len)
242     return FALSE;
243
244   if (max_allowed_length && identifier_len > max_allowed_length)
245     return FALSE;
246
247   status = silc_stringprep(identifier, identifier_len,
248                            identifier_encoding, SILC_IDENTIFIER_PREP, 0,
249                            NULL, NULL, SILC_STRING_UTF8);
250   if (status != SILC_STRINGPREP_OK) {
251     SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
252     return FALSE;
253   }
254
255   return TRUE;
256 }
257
258 unsigned char *silc_channel_name_check(const unsigned char *identifier,
259                                        SilcUInt32 identifier_len,
260                                        SilcStringEncoding identifier_encoding,
261                                        SilcUInt32 max_allowed_length,
262                                        SilcUInt32 *out_len)
263 {
264   unsigned char *utf8s;
265   SilcUInt32 utf8s_len;
266   SilcStringprepStatus status;
267
268   if (!identifier || !identifier_len)
269     return NULL;
270
271   if (max_allowed_length && identifier_len > max_allowed_length)
272     return NULL;
273
274   status = silc_stringprep(identifier, identifier_len,
275                            identifier_encoding, SILC_IDENTIFIER_CH_PREP, 0,
276                            &utf8s, &utf8s_len, SILC_STRING_UTF8);
277   if (status != SILC_STRINGPREP_OK) {
278     SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
279     return NULL;
280   }
281
282   if (out_len)
283     *out_len = utf8s_len;
284
285   return utf8s;
286 }
287
288 /* Same as above but does not allocate memory, just checks the
289    validity of the string. */
290
291 SilcBool silc_channel_name_verify(const unsigned char *identifier,
292                               SilcUInt32 identifier_len,
293                               SilcStringEncoding identifier_encoding,
294                               SilcUInt32 max_allowed_length)
295 {
296   SilcStringprepStatus status;
297
298   if (!identifier || !identifier_len)
299     return FALSE;
300
301   if (max_allowed_length && identifier_len > max_allowed_length)
302     return FALSE;
303
304   status = silc_stringprep(identifier, identifier_len,
305                            identifier_encoding, SILC_IDENTIFIER_CH_PREP, 0,
306                            NULL, NULL, SILC_STRING_UTF8);
307   if (status != SILC_STRINGPREP_OK) {
308     SILC_LOG_DEBUG(("silc_stringprep() status error %d", status));
309     return FALSE;
310   }
311
312   return TRUE;
313 }