1 /*
2  * Copyright (C) 2011-2012 Free Software Foundation, Inc.
3  * Copyright (C) 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 /* This file contains the code for the Elliptic Curve Point Formats extension.
25  */
26 
27 #include "ext/ec_point_formats.h"
28 #include "str.h"
29 #include "state.h"
30 #include <gnutls/gnutls.h>
31 
32 
33 static int _gnutls_supported_ec_point_formats_recv_params(gnutls_session_t session,
34 						const uint8_t * data,
35 						size_t data_size);
36 static int _gnutls_supported_ec_point_formats_send_params(gnutls_session_t session,
37 						gnutls_buffer_st * extdata);
38 
39 
40 const hello_ext_entry_st ext_mod_supported_ec_point_formats = {
41 	.name = "Supported EC Point Formats",
42 	.tls_id = 11,
43 	.gid = GNUTLS_EXTENSION_SUPPORTED_EC_POINT_FORMATS,
44 	.client_parse_point = GNUTLS_EXT_TLS,
45 	.server_parse_point = GNUTLS_EXT_TLS,
46 	.validity = GNUTLS_EXT_FLAG_TLS | GNUTLS_EXT_FLAG_DTLS |
47 		    GNUTLS_EXT_FLAG_CLIENT_HELLO | GNUTLS_EXT_FLAG_TLS12_SERVER_HELLO,
48 	.recv_func = _gnutls_supported_ec_point_formats_recv_params,
49 	.send_func = _gnutls_supported_ec_point_formats_send_params,
50 	.pack_func = NULL,
51 	.unpack_func = NULL,
52 	.deinit_func = NULL
53 };
54 
55 
56 /* Receive point formats
57  */
58 static int
_gnutls_supported_ec_point_formats_recv_params(gnutls_session_t session,const uint8_t * data,size_t data_size)59 _gnutls_supported_ec_point_formats_recv_params(gnutls_session_t session,
60 				     const uint8_t * data,
61 				     size_t data_size)
62 {
63 	size_t len, i;
64 	int uncompressed = 0;
65 
66 	if (session->security_parameters.entity == GNUTLS_CLIENT) {
67 		if (data_size < 1)
68 			return
69 			    gnutls_assert_val
70 			    (GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
71 
72 		len = data[0];
73 		if (len < 1)
74 			return
75 			    gnutls_assert_val
76 			    (GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
77 
78 		DECR_LEN(data_size, len + 1);
79 
80 		for (i = 1; i <= len; i++)
81 			if (data[i] == 0) {	/* uncompressed */
82 				uncompressed = 1;
83 				break;
84 			}
85 
86 		if (uncompressed == 0)
87 			return
88 			    gnutls_assert_val
89 			    (GNUTLS_E_UNKNOWN_PK_ALGORITHM);
90 	} else {
91 		/* only sanity check here. We only support uncompressed points
92 		 * and a client must support it thus nothing to check.
93 		 */
94 		if (data_size < 1)
95 			return
96 			    gnutls_assert_val
97 			    (GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION);
98 	}
99 
100 	return 0;
101 }
102 
103 /* returns data_size or a negative number on failure
104  */
105 static int
_gnutls_supported_ec_point_formats_send_params(gnutls_session_t session,gnutls_buffer_st * extdata)106 _gnutls_supported_ec_point_formats_send_params(gnutls_session_t session,
107 				     gnutls_buffer_st * extdata)
108 {
109 	const uint8_t p[2] = { 0x01, 0x00 };	/* only support uncompressed point format */
110 	int ret;
111 
112 	if (session->security_parameters.entity == GNUTLS_SERVER
113 	    && !_gnutls_session_is_ecc(session))
114 		return 0;
115 
116 	if (session->internals.priorities->groups.size > 0) {
117 		ret = _gnutls_buffer_append_data(extdata, p, 2);
118 		if (ret < 0)
119 			return gnutls_assert_val(ret);
120 
121 		return 2;
122 	}
123 	return 0;
124 }
125