1 /*
2  * Copyright (C) 2002-2012 Free Software Foundation, Inc.
3  * Copyright (C) 2016-2017 Red Hat, Inc.
4  *
5  * Author: Nikos Mavrogiannopoulos
6  *
7  * This file is part of GnuTLS.
8  *
9  * The GnuTLS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1 of
12  * the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful, but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program.  If not, see <https://www.gnu.org/licenses/>
21  *
22  */
23 
24 #include "gnutls_int.h"
25 #include "errors.h"
26 #include <num.h>
27 #include "str.h"
28 #include <stdarg.h>
29 #include <c-ctype.h>
30 #include <intprops.h>
31 #include <nettle/base64.h>
32 #include "extras/hex.h"
33 
34 /* These functions are like strcat, strcpy. They only
35  * do bound checking (they shouldn't cause buffer overruns),
36  * and they always produce null terminated strings.
37  *
38  * They should be used only with null terminated strings.
39  */
_gnutls_str_cat(char * dest,size_t dest_tot_size,const char * src)40 void _gnutls_str_cat(char *dest, size_t dest_tot_size, const char *src)
41 {
42 	size_t str_size = strlen(src);
43 	size_t dest_size = strlen(dest);
44 
45 	if (dest_tot_size - dest_size > str_size) {
46 		strcat(dest, src);
47 	} else {
48 		if (dest_tot_size - dest_size > 0) {
49 			strncat(dest, src,
50 				(dest_tot_size - dest_size) - 1);
51 			dest[dest_tot_size - 1] = 0;
52 		}
53 	}
54 }
55 
_gnutls_str_cpy(char * dest,size_t dest_tot_size,const char * src)56 void _gnutls_str_cpy(char *dest, size_t dest_tot_size, const char *src)
57 {
58 	size_t str_size = strlen(src);
59 
60 	if (dest_tot_size > str_size) {
61 		strcpy(dest, src);
62 	} else {
63 		if (dest_tot_size > 0) {
64 			memcpy(dest, src, (dest_tot_size) - 1);
65 			dest[dest_tot_size - 1] = 0;
66 		}
67 	}
68 }
69 
_gnutls_buffer_init(gnutls_buffer_st * str)70 void _gnutls_buffer_init(gnutls_buffer_st * str)
71 {
72 	str->data = str->allocd = NULL;
73 	str->max_length = 0;
74 	str->length = 0;
75 }
76 
_gnutls_buffer_clear(gnutls_buffer_st * str)77 void _gnutls_buffer_clear(gnutls_buffer_st * str)
78 {
79 	if (str == NULL || str->allocd == NULL)
80 		return;
81 	gnutls_free(str->allocd);
82 
83 	str->data = NULL;
84 	str->max_length = 0;
85 	str->length = 0;
86 }
87 
88 #define MIN_CHUNK 1024
89 
90 /**
91  * gnutls_buffer_append_data:
92  * @dest: the buffer to append to
93  * @data: the data
94  * @data_size: the size of @data
95  *
96  * Appends the provided @data to the destination buffer.
97  *
98  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
99  *
100  * Since: 3.4.0
101  **/
102 int
gnutls_buffer_append_data(gnutls_buffer_t dest,const void * data,size_t data_size)103 gnutls_buffer_append_data(gnutls_buffer_t dest, const void *data,
104 			   size_t data_size)
105 {
106 	size_t const tot_len = data_size + dest->length;
107 	int ret;
108 
109 	if (unlikely(dest->data != NULL && dest->allocd == NULL))
110 		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
111 
112 	if (data_size == 0)
113 		return 0;
114 
115 	if (unlikely(sizeof(size_t) == 4 &&
116 	    INT_ADD_OVERFLOW (((ssize_t)MAX(data_size, MIN_CHUNK)), ((ssize_t)dest->length)))) {
117 		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
118 	}
119 
120 	ret = _gnutls_buffer_resize(dest, tot_len);
121 	if (ret < 0) {
122 		return ret;
123 	}
124 	assert(dest->data != NULL);
125 
126 	memcpy(&dest->data[dest->length], data, data_size);
127 	dest->length = tot_len;
128 
129 	return 0;
130 }
131 
132 #ifdef AGGRESSIVE_REALLOC
133 
134 /* Use a simpler logic for reallocation; i.e., always call
135  * gnutls_realloc_fast() and do not reclaim the no-longer-used
136  * area which has been removed from the beginning of buffer
137  * with _gnutls_buffer_pop_datum().  This helps hit more
138  * issues when running under valgrind.
139  */
_gnutls_buffer_resize(gnutls_buffer_st * dest,size_t new_size)140 int _gnutls_buffer_resize(gnutls_buffer_st * dest, size_t new_size)
141 {
142 	size_t unused;
143 
144 	if (unlikely(dest->data != NULL && dest->allocd == NULL))
145 		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
146 
147 	unused = MEMSUB(dest->data, dest->allocd);
148 	dest->allocd =
149 	    gnutls_realloc_fast(dest->allocd, new_size + unused);
150 	if (dest->allocd == NULL) {
151 		gnutls_assert();
152 		return GNUTLS_E_MEMORY_ERROR;
153 	}
154 	dest->max_length = new_size + unused;
155 	dest->data = dest->allocd + unused;
156 
157 	return 0;
158 }
159 
160 #else
161 
align_allocd_with_data(gnutls_buffer_st * dest)162 static void align_allocd_with_data(gnutls_buffer_st * dest)
163 {
164 	assert(dest->allocd != NULL);
165 	assert(dest->data != NULL);
166 	if (dest->length)
167 		memmove(dest->allocd, dest->data, dest->length);
168 	dest->data = dest->allocd;
169 }
170 
_gnutls_buffer_resize(gnutls_buffer_st * dest,size_t new_size)171 int _gnutls_buffer_resize(gnutls_buffer_st * dest, size_t new_size)
172 {
173 	if (unlikely(dest->data != NULL && dest->allocd == NULL))
174 		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
175 
176 	if (dest->max_length >= new_size) {
177 		size_t unused = MEMSUB(dest->data, dest->allocd);
178 		if (dest->max_length - unused <= new_size) {
179 			align_allocd_with_data(dest);
180 		}
181 
182 		return 0;
183 	} else {
184 		size_t unused = MEMSUB(dest->data, dest->allocd);
185 		size_t alloc_len =
186 		    MAX(new_size, MIN_CHUNK) + MAX(dest->max_length,
187 						   MIN_CHUNK);
188 
189 		dest->allocd =
190 		    gnutls_realloc_fast(dest->allocd, alloc_len);
191 		if (dest->allocd == NULL) {
192 			gnutls_assert();
193 			return GNUTLS_E_MEMORY_ERROR;
194 		}
195 		dest->max_length = alloc_len;
196 		dest->data = dest->allocd + unused;
197 
198 		align_allocd_with_data(dest);
199 
200 		return 0;
201 	}
202 }
203 
204 #endif
205 
206 /* Appends the provided string. The null termination byte is appended
207  * but not included in length.
208  */
_gnutls_buffer_append_str(gnutls_buffer_st * dest,const char * src)209 int _gnutls_buffer_append_str(gnutls_buffer_st * dest, const char *src)
210 {
211 	int ret;
212 	ret = _gnutls_buffer_append_data(dest, src, strlen(src) + 1);
213 	if (ret >= 0)
214 		dest->length--;
215 
216 	return ret;
217 }
218 
219 /* returns data from a string in a constant buffer.
220  * The data will NOT be valid if buffer is released or
221  * data are appended in the buffer.
222  */
223 void
_gnutls_buffer_pop_datum(gnutls_buffer_st * str,gnutls_datum_t * data,size_t req_size)224 _gnutls_buffer_pop_datum(gnutls_buffer_st * str, gnutls_datum_t * data,
225 			 size_t req_size)
226 {
227 	if (str->length == 0) {
228 		data->data = NULL;
229 		data->size = 0;
230 		return;
231 	}
232 
233 	if (req_size > str->length)
234 		req_size = str->length;
235 
236 	data->data = str->data;
237 	data->size = req_size;
238 
239 	str->data += req_size;
240 	str->length -= req_size;
241 
242 	/* if string becomes empty start from beginning */
243 	if (str->length == 0) {
244 		str->data = str->allocd;
245 	}
246 
247 	return;
248 }
249 
250 /* converts the buffer to a datum if possible. After this call
251  * (failed or not) the buffer should be considered deinitialized.
252  */
_gnutls_buffer_to_datum(gnutls_buffer_st * str,gnutls_datum_t * data,unsigned is_str)253 int _gnutls_buffer_to_datum(gnutls_buffer_st * str, gnutls_datum_t * data, unsigned is_str)
254 {
255 	int ret;
256 
257 	if (str->length == 0) {
258 		data->data = NULL;
259 		data->size = 0;
260 		ret = 0;
261 		goto fail;
262 	}
263 
264 	if (is_str) {
265 		ret = _gnutls_buffer_append_data(str, "\x00", 1);
266 		if (ret < 0) {
267 			gnutls_assert();
268 			goto fail;
269 		}
270 	}
271 
272 	if (str->allocd != str->data) {
273 		data->data = gnutls_malloc(str->length);
274 		if (data->data == NULL) {
275 			gnutls_assert();
276 			ret = GNUTLS_E_MEMORY_ERROR;
277 			goto fail;
278 		}
279 		memcpy(data->data, str->data, str->length);
280 		data->size = str->length;
281 		_gnutls_buffer_clear(str);
282 	} else {
283 		data->data = str->data;
284 		data->size = str->length;
285 		_gnutls_buffer_init(str);
286 	}
287 
288 	if (is_str) {
289 		data->size--;
290 	}
291 
292 	return 0;
293  fail:
294 	_gnutls_buffer_clear(str);
295 	return ret;
296 }
297 
298 /* returns data from a string in a constant buffer. Will
299  * fail with GNUTLS_E_PARSING_ERROR, if the string has not enough data.
300  */
301 int
_gnutls_buffer_pop_data(gnutls_buffer_st * str,void * data,size_t req_size)302 _gnutls_buffer_pop_data(gnutls_buffer_st * str, void *data,
303 			size_t req_size)
304 {
305 	gnutls_datum_t tdata;
306 
307 	_gnutls_buffer_pop_datum(str, &tdata, req_size);
308 	if (tdata.data == NULL || tdata.size != req_size) {
309 		return GNUTLS_E_PARSING_ERROR;
310 	}
311 
312 	memcpy(data, tdata.data, tdata.size);
313 
314 	return 0;
315 }
316 
317 int
_gnutls_buffer_append_printf(gnutls_buffer_st * dest,const char * fmt,...)318 _gnutls_buffer_append_printf(gnutls_buffer_st * dest, const char *fmt, ...)
319 {
320 	va_list args;
321 	int len;
322 	char *str = NULL;
323 
324 	va_start(args, fmt);
325 	len = vasprintf(&str, fmt, args);
326 	va_end(args);
327 
328 	if (len < 0 || !str)
329 		return -1;
330 
331 	len = _gnutls_buffer_append_str(dest, str);
332 
333 	free(str);
334 
335 	return len;
336 }
337 
338 static int
_gnutls_buffer_insert_data(gnutls_buffer_st * dest,int pos,const void * str,size_t str_size)339 _gnutls_buffer_insert_data(gnutls_buffer_st * dest, int pos,
340 			   const void *str, size_t str_size)
341 {
342 	size_t orig_length = dest->length;
343 	int ret;
344 
345 	ret = _gnutls_buffer_resize(dest, dest->length + str_size);	/* resize to make space */
346 	if (ret < 0)
347 		return ret;
348 
349 	assert(dest->data != NULL);
350 
351 	memmove(&dest->data[pos + str_size], &dest->data[pos],
352 		orig_length - pos);
353 
354 	memcpy(&dest->data[pos], str, str_size);
355 	dest->length += str_size;
356 
357 	return 0;
358 }
359 
360 static void
_gnutls_buffer_delete_data(gnutls_buffer_st * dest,int pos,size_t str_size)361 _gnutls_buffer_delete_data(gnutls_buffer_st * dest, int pos,
362 			   size_t str_size)
363 {
364 	memmove(&dest->data[pos], &dest->data[pos + str_size],
365 		dest->length - pos - str_size);
366 
367 	dest->length -= str_size;
368 
369 	return;
370 }
371 
372 
373 int
_gnutls_buffer_append_escape(gnutls_buffer_st * dest,const void * data,size_t data_size,const char * invalid_chars)374 _gnutls_buffer_append_escape(gnutls_buffer_st * dest, const void *data,
375 			     size_t data_size, const char *invalid_chars)
376 {
377 	int rv = -1;
378 	char t[5];
379 	unsigned int pos = dest->length;
380 
381 	rv = _gnutls_buffer_append_data(dest, data, data_size);
382 	if (rv < 0)
383 		return gnutls_assert_val(rv);
384 
385 	while (pos < dest->length) {
386 
387 		if (dest->data[pos] == '\\'
388 			|| strchr(invalid_chars, dest->data[pos])
389 			|| !c_isgraph(dest->data[pos])) {
390 
391 			snprintf(t, sizeof(t), "%%%.2X",
392 				 (unsigned int) dest->data[pos]);
393 
394 			_gnutls_buffer_delete_data(dest, pos, 1);
395 
396 			if (_gnutls_buffer_insert_data(dest, pos, t, 3) < 0) {
397 				rv = -1;
398 				goto cleanup;
399 			}
400 			pos += 3;
401 		} else
402 			pos++;
403 	}
404 
405 	rv = 0;
406 
407       cleanup:
408 	return rv;
409 }
410 
_gnutls_buffer_unescape(gnutls_buffer_st * dest)411 int _gnutls_buffer_unescape(gnutls_buffer_st * dest)
412 {
413 	int rv = -1;
414 	unsigned int pos = 0;
415 
416 	while (pos < dest->length) {
417 		if (dest->data[pos] == '%') {
418 			if (pos + 1 < dest->length && dest->data[pos + 1] == '%') {
419 				// %% -> %
420 				_gnutls_buffer_delete_data(dest, pos, 1);
421 			} else if (pos + 2 < dest->length && c_isxdigit(dest->data[pos + 1]) && c_isxdigit(dest->data[pos + 2])) {
422 				unsigned char x;
423 
424 				hex_decode((char *) dest->data + pos + 1, 2, &x, 1);
425 
426 				_gnutls_buffer_delete_data(dest, pos, 3);
427 				_gnutls_buffer_insert_data(dest, pos, &x, 1);
428 			}
429 		}
430 		pos++;
431 	}
432 
433 	rv = 0;
434 
435 	return rv;
436 }
437 
438 
439 /* Converts the given string (old) to hex. A buffer must be provided
440  * to hold the new hex string. The new string will be null terminated.
441  * If the buffer does not have enough space to hold the string, a
442  * truncated hex string is returned (always null terminated).
443  */
_gnutls_bin2hex(const void * _old,size_t oldlen,char * buffer,size_t buffer_size,const char * separator)444 char *_gnutls_bin2hex(const void *_old, size_t oldlen,
445 		      char *buffer, size_t buffer_size,
446 		      const char *separator)
447 {
448 	unsigned int i, j;
449 	const uint8_t *old = _old;
450 	int step = 2;
451 	const char empty[] = "";
452 
453 	if (separator != NULL && separator[0] != 0)
454 		step = 3;
455 	else
456 		separator = empty;
457 
458 	if (buffer_size < 3) {
459 		gnutls_assert();
460 		return NULL;
461 	}
462 
463 	i = j = 0;
464 	sprintf(&buffer[j], "%.2x", old[i]);
465 	j += 2;
466 	i++;
467 
468 	for (; i < oldlen && j + step < buffer_size; j += step) {
469 		sprintf(&buffer[j], "%s%.2x", separator, old[i]);
470 		i++;
471 	}
472 	buffer[j] = '\0';
473 
474 	return buffer;
475 }
476 
477 /**
478  * gnutls_hex2bin:
479  * @hex_data: string with data in hex format
480  * @hex_size: size of hex data
481  * @bin_data: output array with binary data
482  * @bin_size: when calling should hold maximum size of @bin_data,
483  *	    on return will hold actual length of @bin_data.
484  *
485  * Convert a buffer with hex data to binary data. This function
486  * unlike gnutls_hex_decode() can parse hex data with separators
487  * between numbers. That is, it ignores any non-hex characters.
488  *
489  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
490  *
491  * Since: 2.4.0
492  **/
493 int
gnutls_hex2bin(const char * hex_data,size_t hex_size,void * bin_data,size_t * bin_size)494 gnutls_hex2bin(const char *hex_data,
495 	       size_t hex_size, void *bin_data, size_t * bin_size)
496 {
497 	return _gnutls_hex2bin(hex_data, hex_size, (void *) bin_data,
498 			       bin_size);
499 }
500 
501 int
_gnutls_hex2bin(const char * hex_data,size_t hex_size,uint8_t * bin_data,size_t * bin_size)502 _gnutls_hex2bin(const char *hex_data, size_t hex_size, uint8_t * bin_data,
503 		size_t * bin_size)
504 {
505 	unsigned int i, j;
506 	uint8_t hex2_data[3];
507 	unsigned long val;
508 
509 	hex2_data[2] = 0;
510 
511 	for (i = j = 0; i < hex_size;) {
512 		if (!isxdigit(hex_data[i])) {	/* skip non-hex such as the ':' in 00:FF */
513 			i++;
514 			continue;
515 		}
516 		if (j >= *bin_size) {
517 			gnutls_assert();
518 			return GNUTLS_E_SHORT_MEMORY_BUFFER;
519 		}
520 
521 		if (i+1 >= hex_size)
522 			return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
523 
524 		hex2_data[0] = hex_data[i];
525 		hex2_data[1] = hex_data[i + 1];
526 		i += 2;
527 
528 		val = strtoul((char *) hex2_data, NULL, 16);
529 		if (val == ULONG_MAX) {
530 			gnutls_assert();
531 			return GNUTLS_E_PARSING_ERROR;
532 		}
533 		bin_data[j] = val;
534 		j++;
535 	}
536 	*bin_size = j;
537 
538 	return 0;
539 }
540 
541 /**
542  * gnutls_hex_decode2:
543  * @hex_data: contain the encoded data
544  * @result: the result in an allocated string
545  *
546  * This function will decode the given encoded data, using the hex
547  * encoding used by PSK password files.
548  *
549  * Returns: %GNUTLS_E_PARSING_ERROR on invalid hex data, or 0 on success.
550  **/
551 int
gnutls_hex_decode2(const gnutls_datum_t * hex_data,gnutls_datum_t * result)552 gnutls_hex_decode2(const gnutls_datum_t * hex_data, gnutls_datum_t *result)
553 {
554 	int ret;
555 	int size = hex_data_size(hex_data->size);
556 
557 	result->data = gnutls_malloc(size);
558 	if (result->data == NULL) {
559 		gnutls_assert();
560 		return GNUTLS_E_MEMORY_ERROR;
561 	}
562 
563 	result->size = size;
564 	ret = hex_decode((char *) hex_data->data, hex_data->size,
565 			 result->data, result->size);
566 	if (ret == 0) {
567 		gnutls_assert();
568 		gnutls_free(result->data);
569 		return GNUTLS_E_PARSING_ERROR;
570 	}
571 
572 	return 0;
573 }
574 
575 /**
576  * gnutls_hex_decode:
577  * @hex_data: contain the encoded data
578  * @result: the place where decoded data will be copied
579  * @result_size: holds the size of the result
580  *
581  * This function will decode the given encoded data, using the hex
582  * encoding used by PSK password files.
583  *
584  * Initially @result_size must hold the maximum size available in
585  * @result, and on return it will contain the number of bytes written.
586  *
587  * Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not
588  *   long enough, %GNUTLS_E_PARSING_ERROR on invalid hex data, or 0 on success.
589  **/
590 int
gnutls_hex_decode(const gnutls_datum_t * hex_data,void * result,size_t * result_size)591 gnutls_hex_decode(const gnutls_datum_t * hex_data, void *result,
592 		  size_t * result_size)
593 {
594 	int ret;
595 	size_t size = hex_data_size(hex_data->size);
596 
597 	if (*result_size < size) {
598 		gnutls_assert();
599 		return GNUTLS_E_SHORT_MEMORY_BUFFER;
600 	}
601 
602 	ret = hex_decode((char *) hex_data->data, hex_data->size,
603 			 result, size);
604 	if (ret == 0) {
605 		return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
606 	}
607 	*result_size = size;
608 
609 	return 0;
610 }
611 
612 /**
613  * gnutls_hex_encode:
614  * @data: contain the raw data
615  * @result: the place where hex data will be copied
616  * @result_size: holds the size of the result
617  *
618  * This function will convert the given data to printable data, using
619  * the hex encoding, as used in the PSK password files.
620  *
621  * Note that the size of the result includes the null terminator.
622  *
623  * Returns: %GNUTLS_E_SHORT_MEMORY_BUFFER if the buffer given is not
624  * long enough, or 0 on success.
625  **/
626 int
gnutls_hex_encode(const gnutls_datum_t * data,char * result,size_t * result_size)627 gnutls_hex_encode(const gnutls_datum_t * data, char *result,
628 		  size_t * result_size)
629 {
630 	int ret;
631 	size_t size = hex_str_size(data->size);
632 
633 	if (*result_size < size) {
634 		gnutls_assert();
635 		return GNUTLS_E_SHORT_MEMORY_BUFFER;
636 	}
637 
638 	ret = hex_encode(data->data, data->size, result, *result_size);
639 	if (ret == 0) {
640 		return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
641 	}
642 
643 	*result_size = size;
644 
645 	return 0;
646 }
647 
648 /**
649  * gnutls_hex_encode2:
650  * @data: contain the raw data
651  * @result: the result in an allocated string
652  *
653  * This function will convert the given data to printable data, using
654  * the hex encoding, as used in the PSK password files.
655  *
656  * Note that the size of the result does NOT include the null terminator.
657  *
658  * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code.
659  **/
660 int
gnutls_hex_encode2(const gnutls_datum_t * data,gnutls_datum_t * result)661 gnutls_hex_encode2(const gnutls_datum_t * data, gnutls_datum_t *result)
662 {
663 	int ret;
664 	int size = hex_str_size(data->size);
665 
666 	result->data = gnutls_malloc(size);
667 	if (result->data == NULL) {
668 		gnutls_assert();
669 		return GNUTLS_E_MEMORY_ERROR;
670 	}
671 
672 	ret = hex_encode((char*)data->data, data->size, (char*)result->data, size);
673 	if (ret == 0) {
674 		gnutls_free(result->data);
675 		return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
676 	}
677 
678 	result->size = size-1;
679 
680 	return 0;
681 }
682 
683 static int
hostname_compare_raw(const char * certname,size_t certnamesize,const char * hostname)684 hostname_compare_raw(const char *certname,
685 			 size_t certnamesize, const char *hostname)
686 {
687 	if (certnamesize == strlen(hostname) && memcmp(hostname, certname, certnamesize) == 0)
688 		return 1;
689 	return 0;
690 }
691 
692 static int
hostname_compare_ascii(const char * certname,size_t certnamesize,const char * hostname)693 hostname_compare_ascii(const char *certname,
694 			 size_t certnamesize, const char *hostname)
695 {
696 	for (;
697 	     *certname && *hostname
698 	     && c_toupper(*certname) == c_toupper(*hostname);
699 	     certname++, hostname++, certnamesize--);
700 
701 	/* the strings are the same */
702 	if (certnamesize == 0 && *hostname == '\0')
703 		return 1;
704 
705 	return 0;
706 }
707 
708 /* compare hostname against certificate, taking account of wildcards
709  * return 1 on success or 0 on error
710  *
711  * note: certnamesize is required as X509 certs can contain embedded NULs in
712  * the strings such as CN or subjectAltName.
713  *
714  * Wildcards are taken into account only if they are the leftmost
715  * component, and if the string is ascii only (partial advice from rfc6125)
716  *
717  */
718 int
_gnutls_hostname_compare(const char * certname,size_t certnamesize,const char * hostname,unsigned vflags)719 _gnutls_hostname_compare(const char *certname,
720 			 size_t certnamesize, const char *hostname, unsigned vflags)
721 {
722 	char *p;
723 	unsigned i;
724 
725 	for (i=0;i<certnamesize;i++) {
726 		if (c_isprint(certname[i]) == 0)
727 			return hostname_compare_raw(certname, certnamesize, hostname);
728 	}
729 
730 	if (*certname == '*' && !(vflags & GNUTLS_VERIFY_DO_NOT_ALLOW_WILDCARDS)) {
731 		/* a wildcard certificate */
732 
733 		/* ensure that we have at least two domain components after
734 		 * the wildcard. */
735 		p = strrchr(certname, '.');
736 		if (p == NULL || strchr(certname, '.') == p || p[1] == 0) {
737 			return 0;
738 		}
739 
740 		certname++;
741 		certnamesize--;
742 
743 		while (1) {
744 			if (hostname_compare_ascii(certname, certnamesize, hostname))
745 				return 1;
746 
747 			/* wildcards are only allowed to match a single domain
748 			   component or component fragment */
749 			if (*hostname == '\0' || *hostname == '.')
750 				break;
751 			hostname++;
752 		}
753 
754 		return 0;
755 	} else {
756 		return hostname_compare_ascii(certname, certnamesize, hostname);
757 	}
758 }
759 
760 int
_gnutls_buffer_append_prefix(gnutls_buffer_st * buf,int pfx_size,size_t data_size)761 _gnutls_buffer_append_prefix(gnutls_buffer_st * buf, int pfx_size,
762 			     size_t data_size)
763 {
764 	uint8_t ss[4];
765 
766 	if (pfx_size == 32) {
767 		_gnutls_write_uint32(data_size, ss);
768 		pfx_size = 4;
769 	} else if (pfx_size == 24) {
770 		_gnutls_write_uint24(data_size, ss);
771 		pfx_size = 3;
772 	} else if (pfx_size == 16) {
773 		_gnutls_write_uint16(data_size, ss);
774 		pfx_size = 2;
775 	} else if (pfx_size == 8) {
776 		ss[0] = data_size;
777 		pfx_size = 1;
778 	} else
779 		return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
780 
781 	return _gnutls_buffer_append_data(buf, ss, pfx_size);
782 }
783 
784 /* Reads an uint32 number from the buffer. If check is non zero it will also check whether
785  * the number read, is less than the data in the buffer
786  */
787 int
_gnutls_buffer_pop_prefix32(gnutls_buffer_st * buf,size_t * data_size,int check)788 _gnutls_buffer_pop_prefix32(gnutls_buffer_st * buf, size_t * data_size,
789 			    int check)
790 {
791 	size_t size;
792 
793 	if (buf->length < 4) {
794 		gnutls_assert();
795 		return GNUTLS_E_PARSING_ERROR;
796 	}
797 
798 	size = _gnutls_read_uint32(buf->data);
799 	if (check && size > buf->length - 4) {
800 		gnutls_assert();
801 		return GNUTLS_E_PARSING_ERROR;
802 	}
803 
804 	buf->data += 4;
805 	buf->length -= 4;
806 
807 	*data_size = size;
808 
809 	return 0;
810 }
811 
_gnutls_buffer_pop_prefix8(gnutls_buffer_st * buf,uint8_t * data,int check)812 int _gnutls_buffer_pop_prefix8(gnutls_buffer_st *buf, uint8_t *data, int check)
813 {
814 	if (buf->length < 1) {
815 		gnutls_assert();
816 		return GNUTLS_E_PARSING_ERROR;
817 	}
818 
819 	*data = buf->data[0];
820 
821 	if (check && *data > buf->length - 1) {
822 		gnutls_assert();
823 		return GNUTLS_E_PARSING_ERROR;
824 	}
825 
826 	buf->data++;
827 	buf->length--;
828 
829 	return 0;
830 }
831 
832 int
_gnutls_buffer_pop_prefix24(gnutls_buffer_st * buf,size_t * data_size,int check)833 _gnutls_buffer_pop_prefix24(gnutls_buffer_st * buf, size_t * data_size,
834 			    int check)
835 {
836 	size_t size;
837 
838 	if (buf->length < 3) {
839 		gnutls_assert();
840 		return GNUTLS_E_PARSING_ERROR;
841 	}
842 
843 	size = _gnutls_read_uint24(buf->data);
844 	if (check && size > buf->length - 3) {
845 		gnutls_assert();
846 		return GNUTLS_E_PARSING_ERROR;
847 	}
848 
849 	buf->data += 3;
850 	buf->length -= 3;
851 
852 	*data_size = size;
853 
854 	return 0;
855 }
856 
857 int
_gnutls_buffer_pop_datum_prefix32(gnutls_buffer_st * buf,gnutls_datum_t * data)858 _gnutls_buffer_pop_datum_prefix32(gnutls_buffer_st * buf,
859 				  gnutls_datum_t * data)
860 {
861 	size_t size;
862 	int ret;
863 
864 	ret = _gnutls_buffer_pop_prefix32(buf, &size, 1);
865 	if (ret < 0) {
866 		gnutls_assert();
867 		return ret;
868 	}
869 
870 	if (size > 0) {
871 		size_t osize = size;
872 		_gnutls_buffer_pop_datum(buf, data, size);
873 		if (osize != data->size) {
874 			gnutls_assert();
875 			return GNUTLS_E_PARSING_ERROR;
876 		}
877 	} else {
878 		data->size = 0;
879 		data->data = NULL;
880 	}
881 
882 	return 0;
883 }
884 
885 int
_gnutls_buffer_pop_datum_prefix16(gnutls_buffer_st * buf,gnutls_datum_t * data)886 _gnutls_buffer_pop_datum_prefix16(gnutls_buffer_st * buf,
887 				  gnutls_datum_t * data)
888 {
889 	size_t size;
890 
891 	if (buf->length < 2) {
892 		gnutls_assert();
893 		return GNUTLS_E_PARSING_ERROR;
894 	}
895 
896 	size = _gnutls_read_uint16(buf->data);
897 
898 	buf->data += 2;
899 	buf->length -= 2;
900 
901 	if (size > 0) {
902 		size_t osize = size;
903 		_gnutls_buffer_pop_datum(buf, data, size);
904 		if (osize != data->size) {
905 			gnutls_assert();
906 			return GNUTLS_E_PARSING_ERROR;
907 		}
908 	} else {
909 		data->size = 0;
910 		data->data = NULL;
911 	}
912 
913 	return 0;
914 }
915 
916 int
_gnutls_buffer_pop_datum_prefix8(gnutls_buffer_st * buf,gnutls_datum_t * data)917 _gnutls_buffer_pop_datum_prefix8(gnutls_buffer_st * buf,
918 				 gnutls_datum_t * data)
919 {
920 	size_t size;
921 
922 	if (buf->length < 1) {
923 		gnutls_assert();
924 		return GNUTLS_E_PARSING_ERROR;
925 	}
926 
927 	size = buf->data[0];
928 
929 	buf->data++;
930 	buf->length--;
931 
932 	if (size > 0) {
933 		size_t osize = size;
934 		_gnutls_buffer_pop_datum(buf, data, size);
935 		if (osize != data->size) {
936 			gnutls_assert();
937 			return GNUTLS_E_PARSING_ERROR;
938 		}
939 	} else {
940 		data->size = 0;
941 		data->data = NULL;
942 	}
943 
944 	return 0;
945 }
946 
947 int
_gnutls_buffer_append_data_prefix(gnutls_buffer_st * buf,int pfx_size,const void * data,size_t data_size)948 _gnutls_buffer_append_data_prefix(gnutls_buffer_st * buf,
949 				  int pfx_size, const void *data,
950 				  size_t data_size)
951 {
952 	int ret;
953 
954 	ret = _gnutls_buffer_append_prefix(buf, pfx_size, data_size);
955 	if (ret < 0)
956 		return gnutls_assert_val(ret);
957 
958 	if (data_size > 0) {
959 		ret = _gnutls_buffer_append_data(buf, data, data_size);
960 		if (ret < 0)
961 			return gnutls_assert_val(ret);
962 	}
963 
964 	return 0;
965 }
966 
_gnutls_buffer_append_mpi(gnutls_buffer_st * buf,int pfx_size,bigint_t mpi,int lz)967 int _gnutls_buffer_append_mpi(gnutls_buffer_st * buf, int pfx_size,
968 			      bigint_t mpi, int lz)
969 {
970 	gnutls_datum_t dd;
971 	int ret;
972 
973 	if (lz)
974 		ret = _gnutls_mpi_dprint_lz(mpi, &dd);
975 	else
976 		ret = _gnutls_mpi_dprint(mpi, &dd);
977 
978 	if (ret < 0)
979 		return gnutls_assert_val(ret);
980 
981 	ret =
982 	    _gnutls_buffer_append_data_prefix(buf, pfx_size, dd.data,
983 					      dd.size);
984 
985 	_gnutls_free_datum(&dd);
986 
987 	return ret;
988 }
989 
990 /* Appends an MPI of fixed-size in bytes left-padded with zeros if necessary */
_gnutls_buffer_append_fixed_mpi(gnutls_buffer_st * buf,bigint_t mpi,unsigned size)991 int _gnutls_buffer_append_fixed_mpi(gnutls_buffer_st * buf,
992 				    bigint_t mpi, unsigned size)
993 {
994 	gnutls_datum_t dd;
995 	unsigned pad, i;
996 	int ret;
997 
998 	ret = _gnutls_mpi_dprint(mpi, &dd);
999 	if (ret < 0)
1000 		return gnutls_assert_val(ret);
1001 
1002 	if (size < dd.size) {
1003 		ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
1004 		goto cleanup;
1005 	}
1006 
1007 	pad = size - dd.size;
1008 	for (i=0;i<pad;i++) {
1009 		ret =
1010 		    _gnutls_buffer_append_data(buf, "\x00", 1);
1011 		if (ret < 0) {
1012 			gnutls_assert();
1013 			goto cleanup;
1014 		}
1015 	}
1016 
1017 	/* append the rest */
1018 	ret =
1019 	    _gnutls_buffer_append_data(buf, dd.data, dd.size);
1020 
1021  cleanup:
1022 	_gnutls_free_datum(&dd);
1023 	return ret;
1024 }
1025 
1026 void
_gnutls_buffer_hexprint(gnutls_buffer_st * str,const void * _data,size_t len)1027 _gnutls_buffer_hexprint(gnutls_buffer_st * str,
1028 			const void *_data, size_t len)
1029 {
1030 	size_t j;
1031 	const unsigned char *data = _data;
1032 
1033 	if (len == 0)
1034 		_gnutls_buffer_append_str(str, "00");
1035 	else {
1036 		for (j = 0; j < len; j++)
1037 			_gnutls_buffer_append_printf(str, "%.2x",
1038 						     (unsigned) data[j]);
1039 	}
1040 }
1041 
1042 int
_gnutls_buffer_base64print(gnutls_buffer_st * str,const void * _data,size_t len)1043 _gnutls_buffer_base64print(gnutls_buffer_st * str,
1044 			   const void *_data, size_t len)
1045 {
1046 	const unsigned char *data = _data;
1047 	unsigned b64len = BASE64_ENCODE_RAW_LENGTH(len);
1048 	int ret;
1049 
1050 	ret = _gnutls_buffer_resize(str, str->length+b64len+1);
1051 	if (ret < 0) {
1052 		return gnutls_assert_val(ret);
1053 	}
1054 
1055 	base64_encode_raw((void*)&str->data[str->length], len, data);
1056 	str->length += b64len;
1057 	str->data[str->length] = 0;
1058 
1059 	return 0;
1060 }
1061 
1062 void
_gnutls_buffer_hexdump(gnutls_buffer_st * str,const void * _data,size_t len,const char * spc)1063 _gnutls_buffer_hexdump(gnutls_buffer_st * str, const void *_data,
1064 		       size_t len, const char *spc)
1065 {
1066 	size_t j;
1067 	const unsigned char *data = _data;
1068 
1069 	if (spc)
1070 		_gnutls_buffer_append_str(str, spc);
1071 	for (j = 0; j < len; j++) {
1072 		if (((j + 1) % 16) == 0) {
1073 			_gnutls_buffer_append_printf(str, "%.2x\n",
1074 						     (unsigned) data[j]);
1075 			if (spc && j != (len - 1))
1076 				_gnutls_buffer_append_str(str, spc);
1077 		} else if (j == (len - 1))
1078 			_gnutls_buffer_append_printf(str, "%.2x",
1079 						     (unsigned) data[j]);
1080 		else
1081 			_gnutls_buffer_append_printf(str, "%.2x:",
1082 						     (unsigned) data[j]);
1083 	}
1084 	if ((j % 16) != 0)
1085 		_gnutls_buffer_append_str(str, "\n");
1086 }
1087 
1088 void
_gnutls_buffer_asciiprint(gnutls_buffer_st * str,const char * data,size_t len)1089 _gnutls_buffer_asciiprint(gnutls_buffer_st * str,
1090 			  const char *data, size_t len)
1091 {
1092 	size_t j;
1093 
1094 	for (j = 0; j < len; j++)
1095 		if (c_isprint(data[j]))
1096 			_gnutls_buffer_append_printf(str, "%c",
1097 						     (unsigned char)
1098 						     data[j]);
1099 		else
1100 			_gnutls_buffer_append_printf(str, ".");
1101 }
1102