Line data Source code
1 : /*
2 : * Copyright (C) 2001-2012 Free Software Foundation, Inc.
3 : *
4 : * Author: Nikos Mavrogiannopoulos
5 : *
6 : * This file is part of GnuTLS.
7 : *
8 : * The GnuTLS is free software; you can redistribute it and/or
9 : * modify it under the terms of the GNU Lesser General Public License
10 : * as published by the Free Software Foundation; either version 2.1 of
11 : * the License, or (at your option) any later version.
12 : *
13 : * This library is distributed in the hope that it will be useful, but
14 : * WITHOUT ANY WARRANTY; without even the implied warranty of
15 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 : * Lesser General Public License for more details.
17 : *
18 : * You should have received a copy of the GNU Lesser General Public License
19 : * along with this program. If not, see <https://www.gnu.org/licenses/>
20 : *
21 : */
22 :
23 : #include "gnutls_int.h"
24 : #include "errors.h"
25 : #include <datum.h>
26 : #include <auth/srp_passwd.h>
27 :
28 : #ifdef ENABLE_SRP
29 :
30 : /* this is a modified base64 for srp !!!
31 : * It seems that everybody makes their own base64 conversion.
32 : */
33 : static const uint8_t b64table[] =
34 : "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
35 :
36 : static const uint8_t asciitable[128] = {
37 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
38 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
39 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
40 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
41 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
42 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
43 : 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
44 : 0xff, 0xff, 0xff, 0xff, 0x3e, 0x3f,
45 : 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
46 : 0x06, 0x07, 0x08, 0x09, 0xff, 0xff,
47 : 0xff, 0xff, 0xff, 0xff, 0xff, 0x0a,
48 : 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
49 : 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
50 : 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c,
51 : 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
52 : 0x23, 0xff, 0xff, 0xff, 0xff, 0xff,
53 : 0xff, 0x24, 0x25, 0x26, 0x27, 0x28,
54 : 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
55 : 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34,
56 : 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a,
57 : 0x3b, 0x3c, 0x3d, 0xff, 0xff, 0xff,
58 : 0xff, 0xff
59 : };
60 :
61 13 : inline static int encode(uint8_t * result, const uint8_t * rdata, unsigned left)
62 : {
63 :
64 13 : int data_len;
65 13 : int c, ret = 4;
66 13 : uint8_t data[3];
67 :
68 13 : if (left > 3)
69 : data_len = 3;
70 : else
71 4 : data_len = left;
72 :
73 13 : data[0] = data[1] = data[2] = 0;
74 13 : memcpy(data, rdata, data_len);
75 :
76 13 : switch (data_len) {
77 11 : case 3:
78 11 : result[0] = b64table[((data[0] & 0xfc) >> 2)];
79 11 : result[1] =
80 11 : b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
81 11 : ((data[1] & 0xf0) >> 4))];
82 11 : result[2] =
83 11 : b64table[((((data[1] & 0x0f) << 2) & 0xff) |
84 11 : ((data[2] & 0xc0) >> 6))];
85 11 : result[3] = b64table[(data[2] & 0x3f) & 0xff];
86 11 : break;
87 0 : case 2:
88 0 : if ((c = ((data[0] & 0xf0) >> 4)) != 0) {
89 0 : result[0] = b64table[c];
90 0 : result[1] =
91 0 : b64table[((((data[0] & 0x0f) << 2) & 0xff) |
92 0 : ((data[1] & 0xc0) >> 6))];
93 0 : result[2] = b64table[(data[1] & 0x3f) & 0xff];
94 0 : result[3] = '\0';
95 0 : ret -= 1;
96 : } else {
97 0 : if ((c =
98 0 : ((data[0] & 0x0f) << 2) | ((data[1] & 0xc0) >>
99 : 6)) != 0) {
100 0 : result[0] = b64table[c];
101 0 : result[1] = b64table[data[1] & 0x3f];
102 0 : result[2] = '\0';
103 0 : result[3] = '\0';
104 0 : ret -= 2;
105 : } else {
106 0 : result[0] = b64table[data[0] & 0x3f];
107 0 : result[1] = '\0';
108 0 : result[2] = '\0';
109 0 : result[3] = '\0';
110 0 : ret -= 3;
111 : }
112 : }
113 : break;
114 2 : case 1:
115 2 : if ((c = ((data[0] & 0xc0) >> 6)) != 0) {
116 1 : result[0] = b64table[c];
117 1 : result[1] = b64table[(data[0] & 0x3f) & 0xff];
118 1 : result[2] = '\0';
119 1 : result[3] = '\0';
120 1 : ret -= 2;
121 : } else {
122 1 : result[0] = b64table[(data[0] & 0x3f) & 0xff];
123 1 : result[1] = '\0';
124 1 : result[2] = '\0';
125 1 : result[3] = '\0';
126 1 : ret -= 3;
127 : }
128 : break;
129 : default:
130 : return GNUTLS_E_BASE64_ENCODING_ERROR;
131 : }
132 :
133 : return ret;
134 :
135 : }
136 :
137 : /* encodes data and puts the result into result (locally allocated)
138 : * The result_size is the return value
139 : */
140 : static int
141 2 : _gnutls_sbase64_encode(uint8_t * data, size_t data_size, char **result)
142 : {
143 2 : unsigned i, j;
144 2 : int ret, tmp;
145 2 : uint8_t tmpres[4];
146 2 : unsigned mod = data_size % 3;
147 :
148 2 : ret = mod;
149 2 : if (ret != 0)
150 : ret = 4;
151 : else
152 0 : ret = 0;
153 :
154 2 : ret += (data_size * 4) / 3;
155 :
156 2 : (*result) = gnutls_calloc(1, ret + 1);
157 2 : if ((*result) == NULL)
158 : return GNUTLS_E_MEMORY_ERROR;
159 :
160 2 : i = j = 0;
161 : /* encode the bytes that are not a multiple of 3
162 : */
163 2 : if (mod > 0) {
164 2 : tmp = encode(tmpres, &data[0], mod);
165 2 : if (tmp < 0) {
166 0 : gnutls_free((*result));
167 0 : return tmp;
168 : }
169 :
170 2 : memcpy(&(*result)[0], tmpres, tmp);
171 2 : i = mod;
172 2 : j = tmp;
173 :
174 : }
175 : /* encode the rest
176 : */
177 13 : for (; i < data_size; i += 3, j += 4) {
178 11 : tmp = encode(tmpres, &data[i], data_size - i);
179 11 : if (tmp < 0) {
180 0 : gnutls_free((*result));
181 0 : return tmp;
182 : }
183 11 : memcpy(&(*result)[j], tmpres, tmp);
184 : }
185 :
186 2 : return strlen(*result);
187 : }
188 :
189 :
190 : /* data must be 4 bytes
191 : * result should be 3 bytes
192 : */
193 : #define TOASCII(c) (c < 127 ? asciitable[c] : 0xff)
194 3856 : inline static int decode(uint8_t * result, const uint8_t * data)
195 : {
196 3856 : uint8_t a1, a2;
197 3856 : int ret = 3;
198 :
199 3856 : memset(result, 0, 3);
200 :
201 3856 : a1 = TOASCII(data[3]);
202 3856 : a2 = TOASCII(data[2]);
203 3856 : if (a1 != 0xff)
204 3855 : result[2] = a1 & 0xff;
205 : else
206 : return GNUTLS_E_BASE64_DECODING_ERROR;
207 3855 : if (a2 != 0xff)
208 3841 : result[2] |= ((a2 & 0x03) << 6) & 0xff;
209 :
210 3855 : a1 = a2;
211 3855 : a2 = TOASCII(data[1]);
212 3855 : if (a1 != 0xff)
213 3841 : result[1] = ((a1 & 0x3c) >> 2);
214 3855 : if (a2 != 0xff)
215 3809 : result[1] |= ((a2 & 0x0f) << 4);
216 46 : else if (a1 == 0xff || result[1] == 0)
217 46 : ret--;
218 :
219 3855 : a1 = a2;
220 3855 : a2 = TOASCII(data[0]);
221 3855 : if (a1 != 0xff)
222 3809 : result[0] = (((a1 & 0x30) >> 4) & 0xff);
223 3855 : if (a2 != 0xff)
224 3759 : result[0] |= ((a2 << 2) & 0xff);
225 96 : else if (a1 == 0xff || result[0] == 0)
226 96 : ret--;
227 :
228 : return ret;
229 : }
230 :
231 : /* decodes data and puts the result into result (locally allocated)
232 : * The result_size is the return value.
233 : * That function does not ignore newlines tabs etc. You should remove them
234 : * before calling it.
235 : */
236 : int
237 101 : _gnutls_sbase64_decode(char *data, size_t idata_size, uint8_t ** result)
238 : {
239 101 : unsigned i, j;
240 101 : int ret, left;
241 101 : int data_size, tmp;
242 101 : uint8_t datrev[4];
243 101 : uint8_t tmpres[3];
244 :
245 101 : data_size = (idata_size / 4) * 4;
246 101 : left = idata_size % 4;
247 :
248 101 : ret = (data_size / 4) * 3;
249 :
250 101 : if (left > 0)
251 97 : ret += 3;
252 :
253 101 : (*result) = gnutls_malloc(ret + 1);
254 101 : if ((*result) == NULL)
255 : return GNUTLS_E_MEMORY_ERROR;
256 :
257 : /* the first "block" is treated with special care */
258 101 : tmp = 0;
259 101 : if (left > 0) {
260 97 : memset(datrev, 0, 4);
261 97 : memcpy(&datrev[4 - left], data, left);
262 :
263 97 : tmp = decode(tmpres, datrev);
264 97 : if (tmp < 0) {
265 1 : gnutls_free((*result));
266 1 : return tmp;
267 : }
268 :
269 96 : memcpy(*result, &tmpres[3 - tmp], tmp);
270 96 : if (tmp < 3)
271 96 : ret -= (3 - tmp);
272 : }
273 :
274 : /* rest data */
275 3859 : for (i = left, j = tmp; i < idata_size; i += 4) {
276 3759 : tmp = decode(tmpres, (uint8_t *) & data[i]);
277 3759 : if (tmp < 0) {
278 0 : gnutls_free((*result));
279 0 : return tmp;
280 : }
281 3759 : memcpy(&(*result)[j], tmpres, tmp);
282 3759 : if (tmp < 3)
283 0 : ret -= (3 - tmp);
284 3759 : j += 3;
285 : }
286 :
287 : return ret;
288 : }
289 :
290 : /**
291 : * gnutls_srp_base64_encode:
292 : * @data: contain the raw data
293 : * @result: the place where base64 data will be copied
294 : * @result_size: holds the size of the result
295 : *
296 : * This function will convert the given data to printable data, using
297 : * the base64 encoding, as used in the libsrp. This is the encoding
298 : * used in SRP password files. If the provided buffer is not long
299 : * enough GNUTLS_E_SHORT_MEMORY_BUFFER is returned.
300 : *
301 : * Warning! This base64 encoding is not the "standard" encoding, so
302 : * do not use it for non-SRP purposes.
303 : *
304 : * Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not
305 : * long enough, or 0 on success.
306 : **/
307 : int
308 0 : gnutls_srp_base64_encode(const gnutls_datum_t * data, char *result,
309 : size_t * result_size)
310 : {
311 0 : char *res;
312 0 : int size;
313 :
314 0 : size = _gnutls_sbase64_encode(data->data, data->size, &res);
315 0 : if (size < 0)
316 : return size;
317 :
318 0 : if (result == NULL || *result_size < (size_t) size) {
319 0 : gnutls_free(res);
320 0 : *result_size = size;
321 0 : return GNUTLS_E_SHORT_MEMORY_BUFFER;
322 : } else {
323 0 : memcpy(result, res, size);
324 0 : gnutls_free(res);
325 0 : *result_size = size;
326 : }
327 :
328 0 : return 0;
329 : }
330 :
331 : /**
332 : * gnutls_srp_base64_encode2:
333 : * @data: contains the raw data
334 : * @result: will hold the newly allocated encoded data
335 : *
336 : * This function will convert the given data to printable data, using
337 : * the base64 encoding. This is the encoding used in SRP password
338 : * files. This function will allocate the required memory to hold
339 : * the encoded data.
340 : *
341 : * You should use gnutls_free() to free the returned data.
342 : *
343 : * Warning! This base64 encoding is not the "standard" encoding, so
344 : * do not use it for non-SRP purposes.
345 : *
346 : * Returns: 0 on success, or an error code.
347 : **/
348 : int
349 2 : gnutls_srp_base64_encode2(const gnutls_datum_t * data,
350 : gnutls_datum_t * result)
351 : {
352 2 : char *res;
353 2 : int size;
354 :
355 2 : size = _gnutls_sbase64_encode(data->data, data->size, &res);
356 2 : if (size < 0)
357 : return size;
358 :
359 2 : if (result == NULL) {
360 0 : gnutls_free(res);
361 0 : return GNUTLS_E_INVALID_REQUEST;
362 : } else {
363 2 : result->data = (uint8_t *) res;
364 2 : result->size = size;
365 : }
366 :
367 2 : return 0;
368 : }
369 :
370 : /**
371 : * gnutls_srp_base64_decode:
372 : * @b64_data: contain the encoded data
373 : * @result: the place where decoded data will be copied
374 : * @result_size: holds the size of the result
375 : *
376 : * This function will decode the given encoded data, using the base64
377 : * encoding found in libsrp.
378 : *
379 : * Note that @b64_data should be null terminated.
380 : *
381 : * Warning! This base64 encoding is not the "standard" encoding, so
382 : * do not use it for non-SRP purposes.
383 : *
384 : * Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not
385 : * long enough, or 0 on success.
386 : **/
387 : int
388 0 : gnutls_srp_base64_decode(const gnutls_datum_t * b64_data, char *result,
389 : size_t * result_size)
390 : {
391 0 : uint8_t *res;
392 0 : int size;
393 :
394 0 : size =
395 0 : _gnutls_sbase64_decode((char *) b64_data->data, b64_data->size,
396 : &res);
397 0 : if (size < 0)
398 : return size;
399 :
400 0 : if (result == NULL || *result_size < (size_t) size) {
401 0 : gnutls_free(res);
402 0 : *result_size = size;
403 0 : return GNUTLS_E_SHORT_MEMORY_BUFFER;
404 : } else {
405 0 : memcpy(result, res, size);
406 0 : gnutls_free(res);
407 0 : *result_size = size;
408 : }
409 :
410 0 : return 0;
411 : }
412 :
413 : /**
414 : * gnutls_srp_base64_decode2:
415 : * @b64_data: contains the encoded data
416 : * @result: the place where decoded data lie
417 : *
418 : * This function will decode the given encoded data. The decoded data
419 : * will be allocated, and stored into result. It will decode using
420 : * the base64 algorithm as used in libsrp.
421 : *
422 : * You should use gnutls_free() to free the returned data.
423 : *
424 : * Warning! This base64 encoding is not the "standard" encoding, so
425 : * do not use it for non-SRP purposes.
426 : *
427 : * Returns: 0 on success, or an error code.
428 : **/
429 : int
430 65 : gnutls_srp_base64_decode2(const gnutls_datum_t * b64_data,
431 : gnutls_datum_t * result)
432 : {
433 65 : uint8_t *ret;
434 65 : int size;
435 :
436 65 : size =
437 65 : _gnutls_sbase64_decode((char *) b64_data->data, b64_data->size,
438 : &ret);
439 65 : if (size < 0)
440 : return size;
441 :
442 64 : if (result == NULL) {
443 0 : gnutls_free(ret);
444 0 : return GNUTLS_E_INVALID_REQUEST;
445 : } else {
446 64 : result->data = ret;
447 64 : result->size = size;
448 : }
449 :
450 64 : return 0;
451 : }
452 :
453 : #endif /* ENABLE_SRP */
|