1 /*
2  * Copyright (C) 2017 Red Hat, 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 "extv.h"
26 #include "handshake.h"
27 #include "tls13/certificate.h"
28 #include "auth/cert.h"
29 #include "mbuffers.h"
30 #include "ext/status_request.h"
31 
32 static int parse_cert_extension(void *ctx, unsigned tls_id, const uint8_t *data, unsigned data_size);
33 static int parse_cert_list(gnutls_session_t session, uint8_t * data, size_t data_size);
34 
_gnutls13_recv_certificate(gnutls_session_t session)35 int _gnutls13_recv_certificate(gnutls_session_t session)
36 {
37 	int ret;
38 	gnutls_buffer_st buf;
39 	unsigned optional = 0;
40 
41 	if (!session->internals.initial_negotiation_completed &&
42 	    session->internals.hsk_flags & HSK_PSK_SELECTED)
43 		return 0;
44 
45 	if (session->security_parameters.entity == GNUTLS_SERVER) {
46 		/* if we didn't request a certificate, there will not be any */
47 		if (session->internals.send_cert_req == 0)
48 			return 0;
49 
50 		if (session->internals.send_cert_req != GNUTLS_CERT_REQUIRE)
51 			optional = 1;
52 	}
53 
54 	ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_CERTIFICATE_PKT, 0, &buf);
55 	if (ret < 0) {
56 		if (ret == GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET && session->internals.send_cert_req)
57 			return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND);
58 
59 		return gnutls_assert_val(ret);
60 	}
61 
62 	if (buf.length == 0) {
63 		gnutls_assert();
64 		ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
65 		goto cleanup;
66 	}
67 
68 	if (session->internals.initial_negotiation_completed &&
69 	    session->internals.post_handshake_cr_context.size > 0) {
70 		gnutls_datum_t context;
71 
72 		/* verify whether the context matches */
73 		ret = _gnutls_buffer_pop_datum_prefix8(&buf, &context);
74 		if (ret < 0) {
75 			gnutls_assert();
76 			goto cleanup;
77 		}
78 
79 		if (context.size != session->internals.post_handshake_cr_context.size ||
80 		    memcmp(context.data, session->internals.post_handshake_cr_context.data,
81 		           context.size) != 0) {
82 			ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
83 			gnutls_assert();
84 			goto cleanup;
85 		}
86 	} else {
87 		if (buf.data[0] != 0) {
88 			/* The context field must be empty during handshake */
89 			gnutls_assert();
90 			ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
91 			goto cleanup;
92 		}
93 
94 		/* buf.length is positive */
95 		buf.data++;
96 		buf.length--;
97 	}
98 
99 	_gnutls_handshake_log("HSK[%p]: parsing certificate message\n", session);
100 
101 	ret = parse_cert_list(session, buf.data, buf.length);
102 	if (ret < 0) {
103 		if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND) {
104 			if (optional)
105 				ret = 0;
106 			else if (session->security_parameters.entity ==
107 				 GNUTLS_SERVER)
108 				ret = GNUTLS_E_CERTIFICATE_REQUIRED;
109 		}
110 		gnutls_assert();
111 		goto cleanup;
112 	}
113 
114 	session->internals.hsk_flags |= HSK_CRT_VRFY_EXPECTED;
115 
116 	ret = 0;
117 cleanup:
118 
119 	_gnutls_buffer_clear(&buf);
120 	return ret;
121 }
122 
123 struct ocsp_req_ctx_st {
124 	gnutls_pcert_st *pcert;
125 	unsigned cert_index;
126 	gnutls_session_t session;
127 	gnutls_certificate_credentials_t cred;
128 };
129 
130 static
append_status_request(void * _ctx,gnutls_buffer_st * buf)131 int append_status_request(void *_ctx, gnutls_buffer_st *buf)
132 {
133 	struct ocsp_req_ctx_st *ctx = _ctx;
134 	gnutls_session_t session = ctx->session;
135 	int ret;
136 	gnutls_datum_t resp;
137 	unsigned free_resp = 0;
138 
139 	assert(session->internals.selected_ocsp_func != NULL ||
140 	       session->internals.selected_ocsp_length != 0);
141 
142 	/* The global ocsp callback function can only be used to return
143 	 * a single certificate request */
144 	if (session->internals.selected_ocsp_length == 1 && ctx->cert_index != 0)
145 		return 0;
146 
147 	if (session->internals.selected_ocsp_length > 0) {
148 		if (ctx->cert_index < session->internals.selected_ocsp_length) {
149 			if ((session->internals.selected_ocsp[ctx->cert_index].exptime != 0 &&
150 			    gnutls_time(0) >= session->internals.selected_ocsp[ctx->cert_index].exptime) ||
151 			    session->internals.selected_ocsp[ctx->cert_index].response.data == NULL) {
152 				return 0;
153 			}
154 
155 			resp.data = session->internals.selected_ocsp[ctx->cert_index].response.data;
156 			resp.size = session->internals.selected_ocsp[ctx->cert_index].response.size;
157 			ret = 0;
158 		} else {
159 			return 0;
160 		}
161 	} else if (session->internals.selected_ocsp_func) {
162 		if (ctx->cert_index == 0) {
163 			ret = session->internals.selected_ocsp_func(session, session->internals.selected_ocsp_func_ptr, &resp);
164 			free_resp = 1;
165 		} else {
166 			return 0;
167 		}
168 	} else
169 		return 0;
170 
171 	if (ret == GNUTLS_E_NO_CERTIFICATE_STATUS || resp.data == 0) {
172 		return 0;
173 	} else if (ret < 0) {
174 		return gnutls_assert_val(ret);
175 	}
176 
177 	ret = _gnutls_buffer_append_data(buf, "\x01", 1);
178 	if (ret < 0) {
179 		gnutls_assert();
180 		goto cleanup;
181 	}
182 
183 	ret = _gnutls_buffer_append_data_prefix(buf, 24, resp.data, resp.size);
184 	if (ret < 0) {
185 		gnutls_assert();
186 		goto cleanup;
187 	}
188 
189 	ret = 0;
190  cleanup:
191 	if (free_resp)
192 		gnutls_free(resp.data);
193 	return ret;
194 }
195 
_gnutls13_send_certificate(gnutls_session_t session,unsigned again)196 int _gnutls13_send_certificate(gnutls_session_t session, unsigned again)
197 {
198 	int ret;
199 	gnutls_pcert_st *apr_cert_list = NULL;
200 	gnutls_privkey_t apr_pkey = NULL;
201 	int apr_cert_list_length = 0;
202 	mbuffer_st *bufel = NULL;
203 	gnutls_buffer_st buf;
204 	unsigned pos_mark, ext_pos_mark;
205 	unsigned i;
206 	struct ocsp_req_ctx_st ctx;
207 	gnutls_certificate_credentials_t cred;
208 
209 	if (again == 0) {
210 		if (!session->internals.initial_negotiation_completed &&
211 		    session->internals.hsk_flags & HSK_PSK_SELECTED)
212 			return 0;
213 
214 		if (session->security_parameters.entity == GNUTLS_SERVER &&
215 		    session->internals.resumed)
216 			return 0;
217 
218 		cred = (gnutls_certificate_credentials_t)
219 		    _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
220 		if (cred == NULL) {
221 			gnutls_assert();
222 			return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
223 		}
224 
225 		if (session->security_parameters.entity == GNUTLS_CLIENT &&
226 		    !(session->internals.hsk_flags & HSK_CRT_ASKED)) {
227 			return 0;
228 		}
229 
230 		ret = _gnutls_get_selected_cert(session, &apr_cert_list,
231 						&apr_cert_list_length, &apr_pkey);
232 		if (ret < 0)
233 			return gnutls_assert_val(ret);
234 
235 		ret = _gnutls_buffer_init_handshake_mbuffer(&buf);
236 		if (ret < 0)
237 			return gnutls_assert_val(ret);
238 
239 		if (session->security_parameters.entity == GNUTLS_CLIENT) {
240 			ret = _gnutls_buffer_append_data_prefix(&buf, 8,
241 								session->internals.post_handshake_cr_context.data,
242 								session->internals.post_handshake_cr_context.size);
243 			if (ret < 0) {
244 				gnutls_assert();
245 				goto cleanup;
246 			}
247 
248 		} else {
249 			ret = _gnutls_buffer_append_prefix(&buf, 8, 0);
250 			if (ret < 0) {
251 				gnutls_assert();
252 				goto cleanup;
253 			}
254 		}
255 
256 		/* mark total size */
257 		pos_mark = buf.length;
258 		ret = _gnutls_buffer_append_prefix(&buf, 24, 0);
259 		if (ret < 0) {
260 			gnutls_assert();
261 			goto cleanup;
262 		}
263 
264 		for (i=0;i<(unsigned)apr_cert_list_length;i++) {
265 			ret = _gnutls_buffer_append_data_prefix(&buf, 24,
266 								apr_cert_list[i].cert.data,
267 								apr_cert_list[i].cert.size);
268 			if (ret < 0) {
269 				gnutls_assert();
270 				goto cleanup;
271 			}
272 
273 #ifdef ENABLE_OCSP
274 			if ((session->internals.selected_ocsp_length > 0 ||
275 			     session->internals.selected_ocsp_func) &&
276 			     (((session->internals.hsk_flags & HSK_OCSP_REQUESTED) && IS_SERVER(session)) ||
277 			     ((session->internals.hsk_flags & HSK_CLIENT_OCSP_REQUESTED) && !IS_SERVER(session)))) {
278 				/* append status response if available */
279 				ret = _gnutls_extv_append_init(&buf);
280 				if (ret < 0) {
281 					gnutls_assert();
282 					goto cleanup;
283 				}
284 				ext_pos_mark = ret;
285 
286 				ctx.pcert = &apr_cert_list[i];
287 				ctx.cert_index = i;
288 				ctx.session = session;
289 				ctx.cred = cred;
290 				ret = _gnutls_extv_append(&buf, STATUS_REQUEST_TLS_ID,
291 							  &ctx, append_status_request);
292 				if (ret < 0) {
293 					gnutls_assert();
294 					goto cleanup;
295 				}
296 
297 				ret = _gnutls_extv_append_final(&buf, ext_pos_mark, 0);
298 				if (ret < 0) {
299 					gnutls_assert();
300 					goto cleanup;
301 				}
302 			} else
303 #endif
304 			{
305 				ret = _gnutls_buffer_append_prefix(&buf, 16, 0);
306 				if (ret < 0) {
307 					gnutls_assert();
308 					goto cleanup;
309 				}
310 			}
311 		}
312 
313 		_gnutls_write_uint24(buf.length-pos_mark-3, &buf.data[pos_mark]);
314 
315 		bufel = _gnutls_buffer_to_mbuffer(&buf);
316 	}
317 
318 	return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_CERTIFICATE_PKT);
319 
320  cleanup:
321 	_gnutls_buffer_clear(&buf);
322 	return ret;
323 }
324 
325 typedef struct crt_cert_ctx_st {
326 	gnutls_session_t session;
327 	gnutls_datum_t *ocsp;
328 	unsigned idx;
329 } crt_cert_ctx_st;
330 
parse_cert_extension(void * _ctx,unsigned tls_id,const uint8_t * data,unsigned data_size)331 static int parse_cert_extension(void *_ctx, unsigned tls_id, const uint8_t *data, unsigned data_size)
332 {
333 	crt_cert_ctx_st *ctx = _ctx;
334 	gnutls_session_t session = ctx->session;
335 	int ret;
336 
337 	if (tls_id == STATUS_REQUEST_TLS_ID) {
338 #ifdef ENABLE_OCSP
339 		if (!_gnutls_hello_ext_is_present(session, ext_mod_status_request.gid)) {
340 			gnutls_assert();
341 			goto unexpected;
342 		}
343 
344 		_gnutls_handshake_log("Found OCSP response on cert %d\n", ctx->idx);
345 
346 		ret = _gnutls_parse_ocsp_response(session, data, data_size, ctx->ocsp);
347 		if (ret < 0)
348 			return gnutls_assert_val(ret);
349 #endif
350 	} else {
351 		goto unexpected;
352 	}
353 
354 	return 0;
355 
356  unexpected:
357 	_gnutls_debug_log("received unexpected certificate extension (%d)\n", (int)tls_id);
358 	return gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
359 }
360 
361 static int
parse_cert_list(gnutls_session_t session,uint8_t * data,size_t data_size)362 parse_cert_list(gnutls_session_t session, uint8_t * data, size_t data_size)
363 {
364 	int ret;
365 	size_t len;
366 	uint8_t *p = data;
367 	cert_auth_info_t info;
368 	gnutls_certificate_credentials_t cred;
369 	size_t size;
370 	int i;
371 	unsigned npeer_certs, npeer_ocsp, j;
372 	crt_cert_ctx_st ctx;
373 	gnutls_datum_t *peer_certs = NULL;
374 	gnutls_datum_t *peer_ocsp = NULL;
375 	unsigned nentries = 0;
376 
377 	cred = (gnutls_certificate_credentials_t)
378 	    _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
379 	if (cred == NULL) {
380 		gnutls_assert();
381 		return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
382 	}
383 
384 	if ((ret =
385 	     _gnutls_auth_info_init(session, GNUTLS_CRD_CERTIFICATE,
386 				   sizeof(cert_auth_info_st), 1)) < 0) {
387 		gnutls_assert();
388 		return ret;
389 	}
390 
391 	if (data == NULL || data_size == 0) {
392 		/* no certificate was sent */
393 		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
394 	}
395 
396 	info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
397 	if (info == NULL)
398 		return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
399 
400 	DECR_LEN(data_size, 3);
401 	size = _gnutls_read_uint24(p);
402 	p += 3;
403 
404 	if (size != data_size)
405 		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
406 
407 	if (size == 0)
408 		return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND);
409 
410 	i = data_size;
411 
412 	while (i > 0) {
413 		DECR_LEN(data_size, 3);
414 		len = _gnutls_read_uint24(p);
415 		if (len == 0)
416 			return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
417 
418 		DECR_LEN(data_size, len);
419 		p += len + 3;
420 		i -= len + 3;
421 
422 		DECR_LEN(data_size, 2);
423 		len = _gnutls_read_uint16(p);
424 		DECR_LEN(data_size, len);
425 
426 		i -= len + 2;
427 		p += len + 2;
428 
429 		nentries++;
430 	}
431 
432 	if (data_size != 0)
433 		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
434 
435 	/* this is unnecessary - keeping to avoid a regression due to a re-org
436 	 * of the loop above */
437 	if (nentries == 0)
438 		return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
439 
440 	npeer_ocsp = 0;
441 	npeer_certs = 0;
442 
443 	/* Ok we now allocate the memory to hold the
444 	 * certificate list
445 	 */
446 	peer_certs = gnutls_calloc(nentries, sizeof(gnutls_datum_t));
447 	if (peer_certs == NULL)
448 		return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
449 
450 	peer_ocsp = gnutls_calloc(nentries, sizeof(gnutls_datum_t));
451 	if (peer_ocsp == NULL) {
452 		ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
453 		goto cleanup;
454 	}
455 
456 	p = data+3;
457 
458 	/* Now we start parsing the list (again).
459 	 * We don't use DECR_LEN since the list has
460 	 * been parsed before.
461 	 */
462 
463 	ctx.session = session;
464 
465 	for (j = 0; j < nentries; j++) {
466 		len = _gnutls_read_uint24(p);
467 		p += 3;
468 
469 		ret = _gnutls_set_datum(&peer_certs[j], p, len);
470 		if (ret < 0) {
471 			gnutls_assert();
472 			ret = GNUTLS_E_CERTIFICATE_ERROR;
473 			goto cleanup;
474 		}
475 		npeer_certs++;
476 
477 		p += len;
478 
479 		len = _gnutls_read_uint16(p);
480 
481 		ctx.ocsp = &peer_ocsp[j];
482 		ctx.idx = j;
483 
484 		ret = _gnutls_extv_parse(&ctx, parse_cert_extension, p, len+2);
485 		if (ret < 0) {
486 			gnutls_assert();
487 			goto cleanup;
488 		}
489 
490 		p += len+2;
491 		npeer_ocsp++;
492 	}
493 
494 	/* The OCSP entries match the certificate entries, although
495 	 * the contents of each OCSP entry may be NULL.
496 	 */
497 	for(j=0;j<info->ncerts;j++)
498 		gnutls_free(info->raw_certificate_list[j].data);
499 	gnutls_free(info->raw_certificate_list);
500 
501 	for(j=0;j<info->nocsp;j++)
502 		gnutls_free(info->raw_ocsp_list[j].data);
503 	gnutls_free(info->raw_ocsp_list);
504 
505 
506 	info->raw_certificate_list = peer_certs;
507 	info->ncerts = npeer_certs;
508 
509 	info->raw_ocsp_list = peer_ocsp;
510 	info->nocsp = npeer_ocsp;
511 
512 	return 0;
513 
514  cleanup:
515 	for(j=0;j<npeer_certs;j++)
516 		gnutls_free(peer_certs[j].data);
517 
518 	for(j=0;j<npeer_ocsp;j++)
519 		gnutls_free(peer_ocsp[j].data);
520 	gnutls_free(peer_certs);
521 	gnutls_free(peer_ocsp);
522 	return ret;
523 
524 }
525 
526