Line data Source code
1 : /*
2 : * Copyright (C) 2017 - 2018 ARPA2 project
3 : *
4 : * Author: Tom Vrancken (dev@tomvrancken.nl)
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 <gnutls/gnutls.h>
25 : #include "datum.h"
26 : #include "auth/cert.h"
27 : #include "x509.h"
28 : #include "cert-cred.h"
29 : #include "read-file.h"
30 : #include <stdint.h>
31 :
32 :
33 : /**
34 : * gnutls_certificate_set_rawpk_key_mem:
35 : * @cred: is a #gnutls_certificate_credentials_t type.
36 : * @spki: contains a raw public key in
37 : * PKIX.SubjectPublicKeyInfo format.
38 : * @pkey: contains a raw private key.
39 : * @format: encoding of the keys. DER or PEM.
40 : * @pass: an optional password to unlock the private key pkey.
41 : * @key_usage: An ORed sequence of %GNUTLS_KEY_* flags.
42 : * @names: is an array of DNS names belonging to the public-key (NULL if none).
43 : * @names_length: holds the length of the names list.
44 : * @flags: an ORed sequence of #gnutls_pkcs_encrypt_flags_t.
45 : * These apply to the private key pkey.
46 : *
47 : * This function sets a public/private keypair in the
48 : * #gnutls_certificate_credentials_t type to be used for authentication
49 : * and/or encryption. @spki and @privkey should match otherwise set
50 : * signatures cannot be validated. In case of no match this function
51 : * returns %GNUTLS_E_CERTIFICATE_KEY_MISMATCH. This function should
52 : * be called once for the client because there is currently no mechanism
53 : * to determine which raw public-key to select for the peer when there
54 : * are multiple present. Multiple raw public keys for the server can be
55 : * distinghuished by setting the @names.
56 : *
57 : * Note here that @spki is a raw public-key as defined
58 : * in RFC7250. It means that there is no surrounding certificate that
59 : * holds the public key and that there is therefore no direct mechanism
60 : * to prove the authenticity of this key. The keypair can be used during
61 : * a TLS handshake but its authenticity should be established via a
62 : * different mechanism (e.g. TOFU or known fingerprint).
63 : *
64 : * The supported formats are basic unencrypted key, PKCS8, PKCS12,
65 : * and the openssl format and will be autodetected.
66 : *
67 : * If the raw public-key and the private key are given in PEM encoding
68 : * then the strings that hold their values must be null terminated.
69 : *
70 : * Key usage (as defined by X.509 extension (2.5.29.15)) can be explicitly
71 : * set because there is no certificate structure around the key to define
72 : * this value. See for more info gnutls_x509_crt_get_key_usage().
73 : *
74 : * Note that, this function by default returns zero on success and a
75 : * negative value on error. Since 3.5.6, when the flag %GNUTLS_CERTIFICATE_API_V2
76 : * is set using gnutls_certificate_set_flags() it returns an index
77 : * (greater or equal to zero). That index can be used in other functions
78 : * to refer to the added key-pair.
79 : *
80 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, in case the
81 : * key pair does not match %GNUTLS_E_CERTIFICATE_KEY_MISMATCH is returned,
82 : * in other erroneous cases a different negative error code is returned.
83 : *
84 : * Since: 3.6.6
85 : **/
86 51 : int gnutls_certificate_set_rawpk_key_mem(gnutls_certificate_credentials_t cred,
87 : const gnutls_datum_t* spki,
88 : const gnutls_datum_t* pkey,
89 : gnutls_x509_crt_fmt_t format,
90 : const char* pass,
91 : unsigned int key_usage,
92 : const char **names,
93 : unsigned int names_length,
94 : unsigned int flags)
95 : {
96 51 : int ret;
97 51 : gnutls_privkey_t privkey;
98 51 : gnutls_pcert_st* pcert;
99 51 : gnutls_str_array_t str_names;
100 51 : unsigned int i;
101 :
102 51 : if (pkey == NULL || spki == NULL) {
103 2 : return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
104 : }
105 :
106 : /* Import our private key. This function does all the necessary
107 : * inits, checks and imports. */
108 49 : ret = _gnutls_read_key_mem(cred, pkey->data, pkey->size,
109 : format, pass, flags, &privkey);
110 49 : if (ret < 0) {
111 0 : return gnutls_assert_val(ret);
112 : }
113 :
114 : /* We now convert our raw public key to a parsed certificate (pcert) structure */
115 49 : pcert = gnutls_calloc(1, sizeof(*pcert));
116 49 : if (pcert == NULL) {
117 0 : gnutls_privkey_deinit(privkey);
118 :
119 0 : return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
120 : }
121 : // Import our raw public key to the pcert structure
122 49 : ret = gnutls_pcert_import_rawpk_raw(pcert, spki,
123 : format, key_usage, 0);
124 49 : if (ret < 0) {
125 0 : gnutls_privkey_deinit(privkey);
126 :
127 0 : return gnutls_assert_val(ret);
128 : }
129 :
130 : /* Process the names, if any */
131 49 : _gnutls_str_array_init(&str_names);
132 :
133 49 : if (names != NULL && names_length > 0) {
134 0 : for (i = 0; i < names_length; i++) {
135 0 : ret =
136 0 : _gnutls_str_array_append_idna(&str_names, names[i],
137 0 : strlen(names[i]));
138 0 : if (ret < 0) {
139 0 : gnutls_privkey_deinit(privkey);
140 0 : _gnutls_str_array_clear(&str_names);
141 :
142 0 : return gnutls_assert_val(ret);
143 : }
144 : }
145 : }
146 :
147 : /* Now that we have converted the key material to our internal structures
148 : * we can now add them to the credentials structure */
149 49 : ret = _gnutls_certificate_credential_append_keypair(cred, privkey, str_names, pcert, 1);
150 : // Check for errors
151 49 : if (ret < 0) {
152 0 : gnutls_privkey_deinit(privkey);
153 0 : gnutls_pcert_deinit(pcert);
154 0 : gnutls_free(pcert);
155 :
156 0 : return gnutls_assert_val(ret);
157 : }
158 : // Successfully added a certificate
159 49 : cred->ncerts++;
160 :
161 : /* Check whether the key pair matches.
162 : * After this point we do not deinitialize anything on failure to avoid
163 : * double freeing. We intentionally keep everything as the credentials state
164 : * is documented to be in undefined state. */
165 49 : if ((ret = _gnutls_check_key_cert_match(cred)) < 0) {
166 0 : return gnutls_assert_val(ret);
167 : }
168 :
169 49 : CRED_RET_SUCCESS(cred);
170 : }
171 :
172 :
173 : /**
174 : * gnutls_certificate_set_rawpk_key_file:
175 : * @cred: is a #gnutls_certificate_credentials_t type.
176 : * @rawpkfile: contains a raw public key in
177 : * PKIX.SubjectPublicKeyInfo format.
178 : * @privkeyfile: contains a file path to a private key.
179 : * @format: encoding of the keys. DER or PEM.
180 : * @pass: an optional password to unlock the private key privkeyfile.
181 : * @key_usage: an ORed sequence of %GNUTLS_KEY_* flags.
182 : * @names: is an array of DNS names belonging to the public-key (NULL if none).
183 : * @names_length: holds the length of the names list.
184 : * @privkey_flags: an ORed sequence of #gnutls_pkcs_encrypt_flags_t.
185 : * These apply to the private key pkey.
186 : * @pkcs11_flags: one of gnutls_pkcs11_obj_flags. These apply to URLs.
187 : *
188 : * This function sets a public/private keypair read from file in the
189 : * #gnutls_certificate_credentials_t type to be used for authentication
190 : * and/or encryption. @spki and @privkey should match otherwise set
191 : * signatures cannot be validated. In case of no match this function
192 : * returns %GNUTLS_E_CERTIFICATE_KEY_MISMATCH. This function should
193 : * be called once for the client because there is currently no mechanism
194 : * to determine which raw public-key to select for the peer when there
195 : * are multiple present. Multiple raw public keys for the server can be
196 : * distinghuished by setting the @names.
197 : *
198 : * Note here that @spki is a raw public-key as defined
199 : * in RFC7250. It means that there is no surrounding certificate that
200 : * holds the public key and that there is therefore no direct mechanism
201 : * to prove the authenticity of this key. The keypair can be used during
202 : * a TLS handshake but its authenticity should be established via a
203 : * different mechanism (e.g. TOFU or known fingerprint).
204 : *
205 : * The supported formats are basic unencrypted key, PKCS8, PKCS12,
206 : * and the openssl format and will be autodetected.
207 : *
208 : * If the raw public-key and the private key are given in PEM encoding
209 : * then the strings that hold their values must be null terminated.
210 : *
211 : * Key usage (as defined by X.509 extension (2.5.29.15)) can be explicitly
212 : * set because there is no certificate structure around the key to define
213 : * this value. See for more info gnutls_x509_crt_get_key_usage().
214 : *
215 : * Note that, this function by default returns zero on success and a
216 : * negative value on error. Since 3.5.6, when the flag %GNUTLS_CERTIFICATE_API_V2
217 : * is set using gnutls_certificate_set_flags() it returns an index
218 : * (greater or equal to zero). That index can be used in other functions
219 : * to refer to the added key-pair.
220 : *
221 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, in case the
222 : * key pair does not match %GNUTLS_E_CERTIFICATE_KEY_MISMATCH is returned,
223 : * in other erroneous cases a different negative error code is returned.
224 : *
225 : * Since: 3.6.6
226 : */
227 6 : int gnutls_certificate_set_rawpk_key_file(gnutls_certificate_credentials_t cred,
228 : const char* rawpkfile,
229 : const char* privkeyfile,
230 : gnutls_x509_crt_fmt_t format,
231 : const char *pass,
232 : unsigned int key_usage,
233 : const char **names,
234 : unsigned int names_length,
235 : unsigned int privkey_flags,
236 : unsigned int pkcs11_flags)
237 : {
238 6 : int ret;
239 6 : gnutls_privkey_t privkey;
240 6 : gnutls_pubkey_t pubkey;
241 6 : gnutls_pcert_st* pcert;
242 6 : gnutls_str_array_t str_names;
243 6 : unsigned int i;
244 :
245 6 : if (rawpkfile == NULL || privkeyfile == NULL) {
246 2 : return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_CREDENTIALS);
247 : }
248 :
249 : /* Import our private key. This function does all the necessary
250 : * inits, checks and imports. */
251 4 : ret = _gnutls_read_key_file(cred, privkeyfile, format, pass, privkey_flags, &privkey);
252 4 : if (ret < 0) {
253 0 : return gnutls_assert_val(ret);
254 : }
255 :
256 4 : pcert = gnutls_calloc(1, sizeof(*pcert));
257 4 : if (pcert == NULL) {
258 0 : gnutls_privkey_deinit(privkey);
259 :
260 0 : return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
261 : }
262 :
263 : /* Check whether we are importing our raw public-key from a URL
264 : * or from a regular file.
265 : */
266 4 : if (gnutls_url_is_supported(rawpkfile)) {
267 :
268 0 : ret = gnutls_pubkey_init(&pubkey);
269 0 : if (ret < 0) {
270 0 : gnutls_privkey_deinit(privkey);
271 :
272 0 : return gnutls_assert_val(ret);
273 : }
274 :
275 0 : ret = gnutls_pubkey_import_url(pubkey, rawpkfile, pkcs11_flags);
276 0 : if (ret < 0) {
277 0 : gnutls_privkey_deinit(privkey);
278 0 : gnutls_pubkey_deinit(pubkey);
279 :
280 0 : return gnutls_assert_val(ret);
281 : }
282 :
283 0 : ret = gnutls_pcert_import_rawpk(pcert, pubkey, 0);
284 0 : if (ret < 0) {
285 0 : gnutls_privkey_deinit(privkey);
286 0 : gnutls_pubkey_deinit(pubkey);
287 :
288 0 : return gnutls_assert_val(ret);
289 : }
290 :
291 : } else {
292 4 : gnutls_datum_t rawpubkey; // to hold rawpk data from file
293 4 : size_t key_size;
294 :
295 : /* Read our raw public-key into memory from file */
296 4 : rawpubkey.data = (void*) read_file(rawpkfile,
297 : RF_BINARY | RF_SENSITIVE,
298 : &key_size);
299 4 : if (rawpubkey.data == NULL) {
300 0 : gnutls_privkey_deinit(privkey);
301 :
302 0 : return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
303 : }
304 4 : rawpubkey.size = key_size; // Implicit type casting
305 :
306 : /* We now convert our raw public key that we've loaded into memory to
307 : * a parsed certificate (pcert) structure. Note that rawpubkey will
308 : * be copied into pcert. Therefore we can directly cleanup rawpubkey.
309 : */
310 4 : ret = gnutls_pcert_import_rawpk_raw(pcert, &rawpubkey,
311 : format, key_usage, 0);
312 :
313 4 : zeroize_key(rawpubkey.data, rawpubkey.size);
314 4 : free(rawpubkey.data);
315 4 : rawpubkey.size = 0;
316 :
317 4 : if (ret < 0) {
318 0 : gnutls_privkey_deinit(privkey);
319 :
320 0 : return gnutls_assert_val(ret);
321 : }
322 :
323 : }
324 :
325 : /* Process the names, if any */
326 4 : _gnutls_str_array_init(&str_names);
327 :
328 4 : if (names != NULL && names_length > 0) {
329 0 : for (i = 0; i < names_length; i++) {
330 0 : ret =
331 0 : _gnutls_str_array_append_idna(&str_names, names[i],
332 0 : strlen(names[i]));
333 0 : if (ret < 0) {
334 0 : gnutls_privkey_deinit(privkey);
335 0 : _gnutls_str_array_clear(&str_names);
336 :
337 0 : return gnutls_assert_val(ret);
338 : }
339 : }
340 : }
341 :
342 : /* Now that we have converted the key material to our internal structures
343 : * we can now add them to the credentials structure */
344 4 : ret = _gnutls_certificate_credential_append_keypair(cred, privkey, str_names, pcert, 1);
345 4 : if (ret < 0) {
346 0 : gnutls_privkey_deinit(privkey);
347 0 : gnutls_pcert_deinit(pcert);
348 0 : gnutls_free(pcert);
349 :
350 0 : return gnutls_assert_val(ret);
351 : }
352 : // Successfully added a certificate
353 4 : cred->ncerts++;
354 :
355 : /* Check whether the key pair matches.
356 : * After this point we do not deinitialize anything on failure to avoid
357 : * double freeing. We intentionally keep everything as the credentials state
358 : * is documented to be in undefined state. */
359 4 : if ((ret = _gnutls_check_key_cert_match(cred)) < 0) {
360 0 : return gnutls_assert_val(ret);
361 : }
362 :
363 4 : CRED_RET_SUCCESS(cred);
364 : }
365 :
|