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 
encode(uint8_t * result,const uint8_t * rdata,unsigned left)61 inline static int encode(uint8_t * result, const uint8_t * rdata, unsigned left)
62 {
63 
64 	int data_len;
65 	int c, ret = 4;
66 	uint8_t data[3];
67 
68 	if (left > 3)
69 		data_len = 3;
70 	else
71 		data_len = left;
72 
73 	data[0] = data[1] = data[2] = 0;
74 	memcpy(data, rdata, data_len);
75 
76 	switch (data_len) {
77 	case 3:
78 		result[0] = b64table[((data[0] & 0xfc) >> 2)];
79 		result[1] =
80 		    b64table[(((((data[0] & 0x03) & 0xff) << 4) & 0xff) |
81 			      ((data[1] & 0xf0) >> 4))];
82 		result[2] =
83 		    b64table[((((data[1] & 0x0f) << 2) & 0xff) |
84 			      ((data[2] & 0xc0) >> 6))];
85 		result[3] = b64table[(data[2] & 0x3f) & 0xff];
86 		break;
87 	case 2:
88 		if ((c = ((data[0] & 0xf0) >> 4)) != 0) {
89 			result[0] = b64table[c];
90 			result[1] =
91 			    b64table[((((data[0] & 0x0f) << 2) & 0xff) |
92 				      ((data[1] & 0xc0) >> 6))];
93 			result[2] = b64table[(data[1] & 0x3f) & 0xff];
94 			result[3] = '\0';
95 			ret -= 1;
96 		} else {
97 			if ((c =
98 			     ((data[0] & 0x0f) << 2) | ((data[1] & 0xc0) >>
99 							6)) != 0) {
100 				result[0] = b64table[c];
101 				result[1] = b64table[data[1] & 0x3f];
102 				result[2] = '\0';
103 				result[3] = '\0';
104 				ret -= 2;
105 			} else {
106 				result[0] = b64table[data[0] & 0x3f];
107 				result[1] = '\0';
108 				result[2] = '\0';
109 				result[3] = '\0';
110 				ret -= 3;
111 			}
112 		}
113 		break;
114 	case 1:
115 		if ((c = ((data[0] & 0xc0) >> 6)) != 0) {
116 			result[0] = b64table[c];
117 			result[1] = b64table[(data[0] & 0x3f) & 0xff];
118 			result[2] = '\0';
119 			result[3] = '\0';
120 			ret -= 2;
121 		} else {
122 			result[0] = b64table[(data[0] & 0x3f) & 0xff];
123 			result[1] = '\0';
124 			result[2] = '\0';
125 			result[3] = '\0';
126 			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
_gnutls_sbase64_encode(uint8_t * data,size_t data_size,char ** result)141 _gnutls_sbase64_encode(uint8_t * data, size_t data_size, char **result)
142 {
143 	unsigned i, j;
144 	int ret, tmp;
145 	uint8_t tmpres[4];
146 	unsigned mod = data_size % 3;
147 
148 	ret = mod;
149 	if (ret != 0)
150 		ret = 4;
151 	else
152 		ret = 0;
153 
154 	ret += (data_size * 4) / 3;
155 
156 	(*result) = gnutls_calloc(1, ret + 1);
157 	if ((*result) == NULL)
158 		return GNUTLS_E_MEMORY_ERROR;
159 
160 	i = j = 0;
161 /* encode the bytes that are not a multiple of 3
162  */
163 	if (mod > 0) {
164 		tmp = encode(tmpres, &data[0], mod);
165 		if (tmp < 0) {
166 			gnutls_free((*result));
167 			return tmp;
168 		}
169 
170 		memcpy(&(*result)[0], tmpres, tmp);
171 		i = mod;
172 		j = tmp;
173 
174 	}
175 /* encode the rest
176  */
177 	for (; i < data_size; i += 3, j += 4) {
178 		tmp = encode(tmpres, &data[i], data_size - i);
179 		if (tmp < 0) {
180 			gnutls_free((*result));
181 			return tmp;
182 		}
183 		memcpy(&(*result)[j], tmpres, tmp);
184 	}
185 
186 	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)
decode(uint8_t * result,const uint8_t * data)194 inline static int decode(uint8_t * result, const uint8_t * data)
195 {
196 	uint8_t a1, a2;
197 	int ret = 3;
198 
199 	memset(result, 0, 3);
200 
201 	a1 = TOASCII(data[3]);
202 	a2 = TOASCII(data[2]);
203 	if (a1 != 0xff)
204 		result[2] = a1 & 0xff;
205 	else
206 		return GNUTLS_E_BASE64_DECODING_ERROR;
207 	if (a2 != 0xff)
208 		result[2] |= ((a2 & 0x03) << 6) & 0xff;
209 
210 	a1 = a2;
211 	a2 = TOASCII(data[1]);
212 	if (a1 != 0xff)
213 		result[1] = ((a1 & 0x3c) >> 2);
214 	if (a2 != 0xff)
215 		result[1] |= ((a2 & 0x0f) << 4);
216 	else if (a1 == 0xff || result[1] == 0)
217 		ret--;
218 
219 	a1 = a2;
220 	a2 = TOASCII(data[0]);
221 	if (a1 != 0xff)
222 		result[0] = (((a1 & 0x30) >> 4) & 0xff);
223 	if (a2 != 0xff)
224 		result[0] |= ((a2 << 2) & 0xff);
225 	else if (a1 == 0xff || result[0] == 0)
226 		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
_gnutls_sbase64_decode(char * data,size_t idata_size,uint8_t ** result)237 _gnutls_sbase64_decode(char *data, size_t idata_size, uint8_t ** result)
238 {
239 	unsigned i, j;
240 	int ret, left;
241 	int data_size, tmp;
242 	uint8_t datrev[4];
243 	uint8_t tmpres[3];
244 
245 	data_size = (idata_size / 4) * 4;
246 	left = idata_size % 4;
247 
248 	ret = (data_size / 4) * 3;
249 
250 	if (left > 0)
251 		ret += 3;
252 
253 	(*result) = gnutls_malloc(ret + 1);
254 	if ((*result) == NULL)
255 		return GNUTLS_E_MEMORY_ERROR;
256 
257 	/* the first "block" is treated with special care */
258 	tmp = 0;
259 	if (left > 0) {
260 		memset(datrev, 0, 4);
261 		memcpy(&datrev[4 - left], data, left);
262 
263 		tmp = decode(tmpres, datrev);
264 		if (tmp < 0) {
265 			gnutls_free((*result));
266 			return tmp;
267 		}
268 
269 		memcpy(*result, &tmpres[3 - tmp], tmp);
270 		if (tmp < 3)
271 			ret -= (3 - tmp);
272 	}
273 
274 	/* rest data */
275 	for (i = left, j = tmp; i < idata_size; i += 4) {
276 		tmp = decode(tmpres, (uint8_t *) & data[i]);
277 		if (tmp < 0) {
278 			gnutls_free((*result));
279 			return tmp;
280 		}
281 		memcpy(&(*result)[j], tmpres, tmp);
282 		if (tmp < 3)
283 			ret -= (3 - tmp);
284 		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
gnutls_srp_base64_encode(const gnutls_datum_t * data,char * result,size_t * result_size)308 gnutls_srp_base64_encode(const gnutls_datum_t * data, char *result,
309 			 size_t * result_size)
310 {
311 	char *res;
312 	int size;
313 
314 	size = _gnutls_sbase64_encode(data->data, data->size, &res);
315 	if (size < 0)
316 		return size;
317 
318 	if (result == NULL || *result_size < (size_t) size) {
319 		gnutls_free(res);
320 		*result_size = size;
321 		return GNUTLS_E_SHORT_MEMORY_BUFFER;
322 	} else {
323 		memcpy(result, res, size);
324 		gnutls_free(res);
325 		*result_size = size;
326 	}
327 
328 	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
gnutls_srp_base64_encode2(const gnutls_datum_t * data,gnutls_datum_t * result)349 gnutls_srp_base64_encode2(const gnutls_datum_t * data,
350 			       gnutls_datum_t * result)
351 {
352 	char *res;
353 	int size;
354 
355 	size = _gnutls_sbase64_encode(data->data, data->size, &res);
356 	if (size < 0)
357 		return size;
358 
359 	if (result == NULL) {
360 		gnutls_free(res);
361 		return GNUTLS_E_INVALID_REQUEST;
362 	} else {
363 		result->data = (uint8_t *) res;
364 		result->size = size;
365 	}
366 
367 	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
gnutls_srp_base64_decode(const gnutls_datum_t * b64_data,char * result,size_t * result_size)388 gnutls_srp_base64_decode(const gnutls_datum_t * b64_data, char *result,
389 			 size_t * result_size)
390 {
391 	uint8_t *res;
392 	int size;
393 
394 	size =
395 	    _gnutls_sbase64_decode((char *) b64_data->data, b64_data->size,
396 				   &res);
397 	if (size < 0)
398 		return size;
399 
400 	if (result == NULL || *result_size < (size_t) size) {
401 		gnutls_free(res);
402 		*result_size = size;
403 		return GNUTLS_E_SHORT_MEMORY_BUFFER;
404 	} else {
405 		memcpy(result, res, size);
406 		gnutls_free(res);
407 		*result_size = size;
408 	}
409 
410 	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
gnutls_srp_base64_decode2(const gnutls_datum_t * b64_data,gnutls_datum_t * result)430 gnutls_srp_base64_decode2(const gnutls_datum_t * b64_data,
431 			       gnutls_datum_t * result)
432 {
433 	uint8_t *ret;
434 	int size;
435 
436 	size =
437 	    _gnutls_sbase64_decode((char *) b64_data->data, b64_data->size,
438 				   &ret);
439 	if (size < 0)
440 		return size;
441 
442 	if (result == NULL) {
443 		gnutls_free(ret);
444 		return GNUTLS_E_INVALID_REQUEST;
445 	} else {
446 		result->data = ret;
447 		result->size = size;
448 	}
449 
450 	return 0;
451 }
452 
453 #endif				/* ENABLE_SRP */
454