Line data Source code
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 "handshake.h"
26 : #include "auth/cert.h"
27 : #include "ext/signature.h"
28 : #include "algorithms.h"
29 : #include "tls13-sig.h"
30 : #include "mbuffers.h"
31 : #include "tls13/certificate_verify.h"
32 :
33 : #define SRV_CTX "TLS 1.3, server CertificateVerify"
34 : static const gnutls_datum_t srv_ctx = {
35 : (void*)SRV_CTX, sizeof(SRV_CTX)-1
36 : };
37 :
38 : #define CLI_CTX "TLS 1.3, client CertificateVerify"
39 : static const gnutls_datum_t cli_ctx = {
40 : (void*)CLI_CTX, sizeof(CLI_CTX)-1
41 : };
42 :
43 5748 : int _gnutls13_recv_certificate_verify(gnutls_session_t session)
44 : {
45 5748 : int ret;
46 5748 : gnutls_buffer_st buf;
47 5748 : const gnutls_sign_entry_st *se;
48 5748 : gnutls_datum_t sig_data;
49 5748 : gnutls_certificate_credentials_t cred;
50 5748 : unsigned vflags;
51 5748 : gnutls_pcert_st peer_cert;
52 5748 : cert_auth_info_t info = _gnutls_get_auth_info(session, GNUTLS_CRD_CERTIFICATE);
53 5748 : bool server = 0;
54 5748 : gnutls_certificate_type_t cert_type;
55 :
56 5748 : memset(&peer_cert, 0, sizeof(peer_cert));
57 :
58 : /* this message is only expected if we have received
59 : * a certificate message */
60 5748 : if (!(session->internals.hsk_flags & HSK_CRT_VRFY_EXPECTED))
61 : return 0;
62 :
63 572 : if (session->security_parameters.entity == GNUTLS_SERVER)
64 77 : server = 1;
65 :
66 572 : cred = (gnutls_certificate_credentials_t)
67 572 : _gnutls_get_cred(session, GNUTLS_CRD_CERTIFICATE);
68 572 : if (unlikely(cred == NULL))
69 0 : return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
70 572 : if (unlikely(info == NULL))
71 0 : return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
72 :
73 572 : ret = _gnutls_recv_handshake(session, GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY, 0, &buf);
74 572 : if (ret < 0)
75 4 : return gnutls_assert_val(ret);
76 :
77 568 : _gnutls_handshake_log("HSK[%p]: Parsing certificate verify\n", session);
78 :
79 568 : if (buf.length < 2) {
80 0 : gnutls_assert();
81 0 : ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
82 0 : goto cleanup;
83 : }
84 :
85 568 : se = _gnutls_tls_aid_to_sign_entry(buf.data[0], buf.data[1], get_version(session));
86 568 : if (se == NULL) {
87 0 : _gnutls_handshake_log("Found unsupported signature (%d.%d)\n", (int)buf.data[0], (int)buf.data[1]);
88 0 : ret = gnutls_assert_val(GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER);
89 0 : goto cleanup;
90 : }
91 :
92 568 : if (server)
93 77 : gnutls_sign_algorithm_set_client(session, se->id);
94 : else
95 491 : gnutls_sign_algorithm_set_server(session, se->id);
96 :
97 568 : buf.data+=2;
98 568 : buf.length-=2;
99 :
100 : /* we check during verification whether the algorithm is enabled */
101 :
102 568 : ret = _gnutls_buffer_pop_datum_prefix16(&buf, &sig_data);
103 568 : if (ret < 0) {
104 0 : gnutls_assert();
105 0 : goto cleanup;
106 : }
107 :
108 568 : if (sig_data.size == 0) {
109 0 : gnutls_assert();
110 0 : ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER;
111 0 : goto cleanup;
112 : }
113 :
114 : /* We verify the certificate of the peer. Therefore we need to
115 : * retrieve the negotiated certificate type for the peer. */
116 568 : cert_type = get_certificate_type(session, GNUTLS_CTYPE_PEERS);
117 :
118 : /* Verify the signature */
119 568 : ret = _gnutls_get_auth_info_pcert(&peer_cert, cert_type, info);
120 568 : if (ret < 0) {
121 0 : gnutls_assert();
122 0 : goto cleanup;
123 : }
124 :
125 568 : vflags = cred->verify_flags | session->internals.additional_verify_flags;
126 :
127 1059 : ret = _gnutls13_handshake_verify_data(session, vflags, &peer_cert,
128 : server?(&cli_ctx):(&srv_ctx),
129 : &sig_data, se);
130 568 : if (ret < 0) {
131 2 : gnutls_assert();
132 2 : goto cleanup;
133 : }
134 :
135 566 : if (buf.length > 0) {
136 0 : gnutls_assert();
137 0 : ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
138 0 : goto cleanup;
139 : }
140 :
141 : ret = 0;
142 568 : cleanup:
143 568 : gnutls_pcert_deinit(&peer_cert);
144 568 : _gnutls_buffer_clear(&buf);
145 568 : return ret;
146 : }
147 :
148 5775 : int _gnutls13_send_certificate_verify(gnutls_session_t session, unsigned again)
149 : {
150 5775 : int ret;
151 5775 : gnutls_pcert_st *apr_cert_list;
152 5775 : gnutls_privkey_t apr_pkey;
153 5775 : int apr_cert_list_length;
154 5775 : mbuffer_st *bufel = NULL;
155 5775 : gnutls_buffer_st buf;
156 5775 : gnutls_datum_t sig = {NULL, 0};
157 5775 : gnutls_sign_algorithm_t algo;
158 5775 : const gnutls_sign_entry_st *se;
159 5775 : bool server = 0;
160 :
161 5775 : if (again == 0) {
162 5775 : if (!session->internals.initial_negotiation_completed &&
163 5773 : session->internals.hsk_flags & HSK_PSK_SELECTED)
164 : return 0;
165 :
166 4184 : if (session->security_parameters.entity == GNUTLS_SERVER &&
167 3713 : session->internals.resumed)
168 : return 0;
169 :
170 4184 : if (session->security_parameters.entity == GNUTLS_SERVER)
171 3713 : server = 1;
172 :
173 4184 : ret = _gnutls_get_selected_cert(session, &apr_cert_list,
174 : &apr_cert_list_length, &apr_pkey);
175 4184 : if (ret < 0)
176 0 : return gnutls_assert_val(ret);
177 :
178 4184 : if (apr_cert_list_length == 0) {
179 424 : if (server) {
180 0 : return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
181 : } else {
182 : /* for client, this means either we
183 : * didn't get a cert request or we are
184 : * declining authentication; in either
185 : * case we don't send a cert verify */
186 : return 0;
187 : }
188 : }
189 :
190 3760 : if (server) {
191 3713 : algo = _gnutls_session_get_sign_algo(session, &apr_cert_list[0], apr_pkey, 0, GNUTLS_KX_UNKNOWN);
192 3713 : if (algo == GNUTLS_SIGN_UNKNOWN)
193 0 : return gnutls_assert_val(GNUTLS_E_INCOMPATIBLE_SIG_WITH_KEY);
194 :
195 3713 : gnutls_sign_algorithm_set_server(session, algo);
196 : } else {
197 : /* for client, signature algorithm is already
198 : * determined from Certificate Request */
199 47 : algo = gnutls_sign_algorithm_get_client(session);
200 47 : if (unlikely(algo == GNUTLS_SIGN_UNKNOWN))
201 0 : return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
202 : }
203 :
204 3760 : se = _gnutls_sign_to_entry(algo);
205 :
206 3807 : ret = _gnutls13_handshake_sign_data(session, &apr_cert_list[0], apr_pkey,
207 : server?(&srv_ctx):(&cli_ctx),
208 : &sig, se);
209 3760 : if (ret < 0)
210 0 : return gnutls_assert_val(ret);
211 :
212 7520 : ret = _gnutls_buffer_init_handshake_mbuffer(&buf);
213 3760 : if (ret < 0) {
214 0 : gnutls_assert();
215 0 : goto cleanup;
216 : }
217 :
218 3760 : ret = _gnutls_buffer_append_data(&buf, se->aid.id, 2);
219 3760 : if (ret < 0) {
220 0 : gnutls_assert();
221 0 : goto cleanup;
222 : }
223 :
224 3760 : ret = _gnutls_buffer_append_data_prefix(&buf, 16, sig.data, sig.size);
225 3760 : if (ret < 0) {
226 0 : gnutls_assert();
227 0 : goto cleanup;
228 : }
229 :
230 3760 : bufel = _gnutls_buffer_to_mbuffer(&buf);
231 :
232 3760 : gnutls_free(sig.data);
233 : }
234 :
235 3760 : return _gnutls_send_handshake(session, bufel, GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY);
236 :
237 0 : cleanup:
238 0 : gnutls_free(sig.data);
239 0 : _gnutls_buffer_clear(&buf);
240 0 : return ret;
241 : }
|