Line data Source code
1 : /*
2 : * Copyright (C) 2012 Free Software Foundation, 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 <libtasn1.h>
26 : #include <global.h>
27 : #include <num.h> /* MAX */
28 : #include <tls-sig.h>
29 : #include "str.h"
30 : #include <datum.h>
31 : #include "x509_int.h"
32 : #include <nettle/base64.h>
33 : #include <common.h>
34 : #include <gnutls/abstract.h>
35 : #include <system.h>
36 : #include <locks.h>
37 :
38 : struct gnutls_tdb_int {
39 : gnutls_tdb_store_func store;
40 : gnutls_tdb_store_commitment_func cstore;
41 : gnutls_tdb_verify_func verify;
42 : };
43 :
44 : static int raw_pubkey_to_base64(const gnutls_datum_t * raw,
45 : gnutls_datum_t * b64);
46 : static int verify_pubkey(const char *file, const char *host,
47 : const char *service, const gnutls_datum_t * skey);
48 :
49 : static
50 : int store_commitment(const char *db_name, const char *host,
51 : const char *service, time_t expiration,
52 : gnutls_digest_algorithm_t hash_algo,
53 : const gnutls_datum_t * hash);
54 : static
55 : int store_pubkey(const char *db_name, const char *host,
56 : const char *service, time_t expiration,
57 : const gnutls_datum_t * pubkey);
58 :
59 : static int find_config_file(char *file, size_t max_size);
60 :
61 : extern void *_gnutls_file_mutex;
62 :
63 : struct gnutls_tdb_int default_tdb = {
64 : store_pubkey,
65 : store_commitment,
66 : verify_pubkey
67 : };
68 :
69 :
70 : /**
71 : * gnutls_verify_stored_pubkey:
72 : * @db_name: A file specifying the stored keys (use NULL for the default)
73 : * @tdb: A storage structure or NULL to use the default
74 : * @host: The peer's name
75 : * @service: non-NULL if this key is specific to a service (e.g. http)
76 : * @cert_type: The type of the certificate
77 : * @cert: The raw (der) data of the certificate
78 : * @flags: should be 0.
79 : *
80 : * This function will try to verify a raw public-key or a public-key provided via
81 : * a raw (DER-encoded) certificate using a list of stored public keys.
82 : * The @service field if non-NULL should be a port number.
83 : *
84 : * The @db_name variable if non-null specifies a custom backend for
85 : * the retrieval of entries. If it is NULL then the
86 : * default file backend will be used. In POSIX-like systems the
87 : * file backend uses the $HOME/.gnutls/known_hosts file.
88 : *
89 : * Note that if the custom storage backend is provided the
90 : * retrieval function should return %GNUTLS_E_CERTIFICATE_KEY_MISMATCH
91 : * if the host/service pair is found but key doesn't match,
92 : * %GNUTLS_E_NO_CERTIFICATE_FOUND if no such host/service with
93 : * the given key is found, and 0 if it was found. The storage
94 : * function should return 0 on success.
95 : *
96 : * As of GnuTLS 3.6.6 this function also verifies raw public keys.
97 : *
98 : * Returns: If no associated public key is found
99 : * then %GNUTLS_E_NO_CERTIFICATE_FOUND will be returned. If a key
100 : * is found but does not match %GNUTLS_E_CERTIFICATE_KEY_MISMATCH
101 : * is returned. On success, %GNUTLS_E_SUCCESS (0) is returned,
102 : * or a negative error value on other errors.
103 : *
104 : * Since: 3.0.13
105 : **/
106 : int
107 6 : gnutls_verify_stored_pubkey(const char *db_name,
108 : gnutls_tdb_t tdb,
109 : const char *host,
110 : const char *service,
111 : gnutls_certificate_type_t cert_type,
112 : const gnutls_datum_t * cert,
113 : unsigned int flags)
114 : {
115 6 : gnutls_datum_t pubkey = { NULL, 0 }; // Holds the pubkey in subjectPublicKeyInfo format (DER encoded)
116 6 : int ret;
117 6 : char local_file[MAX_FILENAME];
118 6 : bool need_free;
119 :
120 :
121 6 : if (db_name == NULL && tdb == NULL) {
122 1 : ret = find_config_file(local_file, sizeof(local_file));
123 1 : if (ret < 0)
124 0 : return gnutls_assert_val(ret);
125 : db_name = local_file;
126 : }
127 :
128 6 : if (tdb == NULL)
129 6 : tdb = &default_tdb;
130 :
131 : /* Import the public key depending on the provided certificate type */
132 6 : switch (cert_type) {
133 4 : case GNUTLS_CRT_X509:
134 : /* Extract the pubkey from the cert. This function does a malloc
135 : * deep down the call chain. We are responsible for freeing. */
136 4 : ret = _gnutls_x509_raw_crt_to_raw_pubkey(cert, &pubkey);
137 :
138 4 : if (ret < 0) {
139 0 : _gnutls_free_datum(&pubkey);
140 0 : return gnutls_assert_val(ret);
141 : }
142 :
143 : need_free = true;
144 : break;
145 2 : case GNUTLS_CRT_RAWPK:
146 2 : pubkey.data = cert->data;
147 2 : pubkey.size = cert->size;
148 2 : need_free = false;
149 2 : break;
150 : default:
151 0 : return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE);
152 : }
153 :
154 : // Verify our pubkey against the database
155 6 : ret = tdb->verify(db_name, host, service, &pubkey);
156 6 : if (ret < 0 && ret != GNUTLS_E_CERTIFICATE_KEY_MISMATCH)
157 0 : ret = gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND);
158 :
159 6 : if (need_free) {
160 4 : _gnutls_free_datum(&pubkey);
161 : }
162 :
163 : return ret;
164 : }
165 :
166 2 : static int parse_commitment_line(char *line,
167 : const char *host, size_t host_len,
168 : const char *service, size_t service_len,
169 : time_t now, const gnutls_datum_t * skey)
170 : {
171 2 : char *p, *kp;
172 2 : char *savep = NULL;
173 2 : size_t kp_len, phash_size;
174 2 : time_t expiration;
175 2 : int ret;
176 2 : const mac_entry_st *hash_algo;
177 2 : uint8_t phash[MAX_HASH_SIZE];
178 2 : uint8_t hphash[MAX_HASH_SIZE * 2 + 1];
179 :
180 : /* read host */
181 2 : p = strtok_r(line, "|", &savep);
182 2 : if (p == NULL)
183 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
184 :
185 2 : if (p[0] != '*' && host != NULL && strcmp(p, host) != 0)
186 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
187 :
188 : /* read service */
189 2 : p = strtok_r(NULL, "|", &savep);
190 2 : if (p == NULL)
191 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
192 :
193 2 : if (p[0] != '*' && service != NULL && strcmp(p, service) != 0)
194 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
195 :
196 : /* read expiration */
197 2 : p = strtok_r(NULL, "|", &savep);
198 2 : if (p == NULL)
199 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
200 :
201 2 : expiration = (time_t) atol(p);
202 2 : if (expiration > 0 && now > expiration)
203 0 : return gnutls_assert_val(GNUTLS_E_EXPIRED);
204 :
205 : /* read hash algorithm */
206 2 : p = strtok_r(NULL, "|", &savep);
207 2 : if (p == NULL)
208 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
209 :
210 2 : hash_algo = mac_to_entry(atol(p));
211 2 : if (_gnutls_digest_get_name(hash_algo) == NULL)
212 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
213 :
214 : /* read hash */
215 2 : kp = strtok_r(NULL, "|", &savep);
216 2 : if (kp == NULL)
217 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
218 :
219 2 : p = strpbrk(kp, "\n \r\t|");
220 2 : if (p != NULL)
221 2 : *p = 0;
222 :
223 : /* hash and hex encode */
224 2 : ret =
225 4 : _gnutls_hash_fast((gnutls_digest_algorithm_t)hash_algo->id,
226 2 : skey->data, skey->size, phash);
227 2 : if (ret < 0)
228 0 : return gnutls_assert_val(ret);
229 :
230 2 : phash_size = _gnutls_hash_get_algo_len(hash_algo);
231 :
232 2 : p = _gnutls_bin2hex(phash, phash_size, (void *) hphash,
233 : sizeof(hphash), NULL);
234 2 : if (p == NULL)
235 0 : return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
236 :
237 2 : kp_len = strlen(kp);
238 2 : if (kp_len != phash_size * 2)
239 0 : return
240 0 : gnutls_assert_val(GNUTLS_E_CERTIFICATE_KEY_MISMATCH);
241 :
242 2 : if (memcmp(kp, hphash, kp_len) != 0)
243 0 : return
244 0 : gnutls_assert_val(GNUTLS_E_CERTIFICATE_KEY_MISMATCH);
245 :
246 : /* key found and matches */
247 : return 0;
248 : }
249 :
250 :
251 8 : static int parse_line(char *line,
252 : const char *host, size_t host_len,
253 : const char *service, size_t service_len,
254 : time_t now,
255 : const gnutls_datum_t * rawkey,
256 : const gnutls_datum_t * b64key)
257 : {
258 8 : char *p, *kp;
259 8 : char *savep = NULL;
260 8 : size_t kp_len;
261 8 : time_t expiration;
262 :
263 : /* read version */
264 8 : p = strtok_r(line, "|", &savep);
265 8 : if (p == NULL)
266 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
267 :
268 8 : if (strncmp(p, "c0", 2) == 0)
269 2 : return parse_commitment_line(p + 3, host, host_len,
270 : service, service_len, now,
271 : rawkey);
272 :
273 6 : if (strncmp(p, "g0", 2) != 0)
274 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
275 :
276 : /* read host */
277 6 : p = strtok_r(NULL, "|", &savep);
278 6 : if (p == NULL)
279 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
280 :
281 6 : if (p[0] != '*' && host != NULL && strcmp(p, host) != 0)
282 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
283 :
284 : /* read service */
285 6 : p = strtok_r(NULL, "|", &savep);
286 6 : if (p == NULL)
287 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
288 :
289 6 : if (p[0] != '*' && service != NULL && strcmp(p, service) != 0)
290 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
291 :
292 : /* read expiration */
293 6 : p = strtok_r(NULL, "|", &savep);
294 6 : if (p == NULL)
295 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
296 :
297 6 : expiration = (time_t) atol(p);
298 6 : if (expiration > 0 && now > expiration)
299 0 : return gnutls_assert_val(GNUTLS_E_EXPIRED);
300 :
301 : /* read key */
302 6 : kp = strtok_r(NULL, "|", &savep);
303 6 : if (kp == NULL)
304 0 : return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
305 :
306 6 : p = strpbrk(kp, "\n \r\t|");
307 6 : if (p != NULL)
308 6 : *p = 0;
309 :
310 6 : kp_len = strlen(kp);
311 6 : if (kp_len != b64key->size)
312 2 : return
313 2 : gnutls_assert_val(GNUTLS_E_CERTIFICATE_KEY_MISMATCH);
314 :
315 4 : if (memcmp(kp, b64key->data, b64key->size) != 0)
316 2 : return
317 2 : gnutls_assert_val(GNUTLS_E_CERTIFICATE_KEY_MISMATCH);
318 :
319 : /* key found and matches */
320 : return 0;
321 : }
322 :
323 : /* Returns the base64 key if found
324 : */
325 6 : static int verify_pubkey(const char *file,
326 : const char *host, const char *service,
327 : const gnutls_datum_t * pubkey)
328 : {
329 6 : FILE *fp;
330 6 : char *line = NULL;
331 6 : size_t line_size = 0;
332 6 : int ret, l2, mismatch = 0;
333 6 : size_t host_len = 0, service_len = 0;
334 6 : time_t now = gnutls_time(0);
335 6 : gnutls_datum_t b64key = { NULL, 0 };
336 :
337 6 : ret = raw_pubkey_to_base64(pubkey, &b64key);
338 6 : if (ret < 0)
339 0 : return gnutls_assert_val(ret);
340 :
341 6 : if (host != NULL)
342 6 : host_len = strlen(host);
343 6 : if (service != NULL)
344 6 : service_len = strlen(service);
345 :
346 6 : fp = fopen(file, "rbe");
347 6 : if (fp == NULL) {
348 0 : ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR);
349 0 : goto cleanup;
350 : }
351 :
352 10 : do {
353 10 : l2 = getline(&line, &line_size, fp);
354 10 : if (l2 > 0) {
355 8 : ret =
356 8 : parse_line(line, host, host_len, service,
357 : service_len, now, pubkey, &b64key);
358 8 : if (ret == 0) { /* found */
359 4 : goto cleanup;
360 4 : } else if (ret ==
361 : GNUTLS_E_CERTIFICATE_KEY_MISMATCH)
362 4 : mismatch = 1;
363 : }
364 : }
365 6 : while (l2 >= 0);
366 :
367 2 : if (mismatch)
368 : ret = GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
369 : else
370 0 : ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
371 :
372 6 : cleanup:
373 6 : free(line);
374 6 : if (fp != NULL)
375 6 : fclose(fp);
376 6 : gnutls_free(b64key.data);
377 :
378 6 : return ret;
379 : }
380 :
381 8 : static int raw_pubkey_to_base64(const gnutls_datum_t * raw,
382 : gnutls_datum_t * b64)
383 : {
384 8 : size_t size;
385 :
386 8 : size = BASE64_ENCODE_RAW_LENGTH(raw->size);
387 :
388 8 : b64->data = gnutls_malloc(size);
389 8 : if (b64->data == NULL)
390 0 : return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
391 :
392 8 : base64_encode_raw((void*)b64->data, raw->size, raw->data);
393 8 : b64->size = size;
394 :
395 8 : return 0;
396 : }
397 :
398 : static
399 2 : int store_pubkey(const char *db_name, const char *host,
400 : const char *service, time_t expiration,
401 : const gnutls_datum_t * pubkey)
402 : {
403 2 : FILE *fp = NULL;
404 2 : gnutls_datum_t b64key = { NULL, 0 };
405 2 : int ret;
406 :
407 2 : ret = gnutls_mutex_lock(&_gnutls_file_mutex);
408 2 : if (ret != 0)
409 0 : return gnutls_assert_val(GNUTLS_E_LOCKING_ERROR);
410 :
411 2 : ret = raw_pubkey_to_base64(pubkey, &b64key);
412 2 : if (ret < 0) {
413 0 : gnutls_assert();
414 0 : goto cleanup;
415 : }
416 :
417 2 : fp = fopen(db_name, "abe+");
418 2 : if (fp == NULL) {
419 0 : ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR);
420 0 : goto cleanup;
421 : }
422 :
423 2 : if (service == NULL)
424 0 : service = "*";
425 2 : if (host == NULL)
426 0 : host = "*";
427 :
428 2 : fprintf(fp, "|g0|%s|%s|%lu|%.*s\n", host, service,
429 : (unsigned long) expiration, b64key.size, b64key.data);
430 :
431 2 : ret = 0;
432 :
433 2 : cleanup:
434 2 : if (fp != NULL)
435 2 : fclose(fp);
436 :
437 2 : gnutls_mutex_unlock(&_gnutls_file_mutex);
438 2 : gnutls_free(b64key.data);
439 :
440 2 : return ret;
441 : }
442 :
443 : static
444 2 : int store_commitment(const char *db_name, const char *host,
445 : const char *service, time_t expiration,
446 : gnutls_digest_algorithm_t hash_algo,
447 : const gnutls_datum_t * hash)
448 : {
449 2 : FILE *fp;
450 2 : char buffer[MAX_HASH_SIZE * 2 + 1];
451 :
452 2 : fp = fopen(db_name, "abe+");
453 2 : if (fp == NULL)
454 0 : return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
455 :
456 2 : if (service == NULL)
457 0 : service = "*";
458 2 : if (host == NULL)
459 0 : host = "*";
460 :
461 2 : fprintf(fp, "|c0|%s|%s|%lu|%u|%s\n", host, service,
462 : (unsigned long) expiration, (unsigned) hash_algo,
463 2 : _gnutls_bin2hex(hash->data, hash->size, buffer,
464 : sizeof(buffer), NULL));
465 :
466 2 : fclose(fp);
467 :
468 2 : return 0;
469 : }
470 :
471 : /**
472 : * gnutls_store_pubkey:
473 : * @db_name: A file specifying the stored keys (use NULL for the default)
474 : * @tdb: A storage structure or NULL to use the default
475 : * @host: The peer's name
476 : * @service: non-NULL if this key is specific to a service (e.g. http)
477 : * @cert_type: The type of the certificate
478 : * @cert: The data of the certificate
479 : * @expiration: The expiration time (use 0 to disable expiration)
480 : * @flags: should be 0.
481 : *
482 : * This function will store a raw public-key or a public-key provided via
483 : * a raw (DER-encoded) certificate to the list of stored public keys. The key
484 : * will be considered valid until the provided expiration time.
485 : *
486 : * The @tdb variable if non-null specifies a custom backend for
487 : * the storage of entries. If it is NULL then the
488 : * default file backend will be used.
489 : *
490 : * Unless an alternative @tdb is provided, the storage format is a textual format
491 : * consisting of a line for each host with fields separated by '|'. The contents of
492 : * the fields are a format-identifier which is set to 'g0', the hostname that the
493 : * rest of the data applies to, the numeric port or host name, the expiration
494 : * time in seconds since the epoch (0 for no expiration), and a base64
495 : * encoding of the raw (DER) public key information (SPKI) of the peer.
496 : *
497 : * As of GnuTLS 3.6.6 this function also accepts raw public keys.
498 : *
499 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
500 : * negative error value.
501 : *
502 : * Since: 3.0.13
503 : **/
504 : int
505 2 : gnutls_store_pubkey(const char *db_name,
506 : gnutls_tdb_t tdb,
507 : const char *host,
508 : const char *service,
509 : gnutls_certificate_type_t cert_type,
510 : const gnutls_datum_t * cert,
511 : time_t expiration, unsigned int flags)
512 : {
513 2 : gnutls_datum_t pubkey = { NULL, 0 }; // Holds the pubkey in subjectPublicKeyInfo format (DER encoded)
514 2 : int ret;
515 2 : char local_file[MAX_FILENAME];
516 2 : bool need_free;
517 :
518 :
519 2 : if (db_name == NULL && tdb == NULL) {
520 0 : ret =
521 0 : _gnutls_find_config_path(local_file,
522 : sizeof(local_file));
523 0 : if (ret < 0)
524 0 : return gnutls_assert_val(ret);
525 :
526 0 : _gnutls_debug_log("Configuration path: %s\n", local_file);
527 0 : mkdir(local_file, 0700);
528 :
529 0 : ret = find_config_file(local_file, sizeof(local_file));
530 0 : if (ret < 0)
531 0 : return gnutls_assert_val(ret);
532 : db_name = local_file;
533 : }
534 :
535 2 : if (tdb == NULL)
536 2 : tdb = &default_tdb;
537 :
538 : /* Import the public key depending on the provided certificate type */
539 2 : switch (cert_type) {
540 1 : case GNUTLS_CRT_X509:
541 : /* Extract the pubkey from the cert. This function does a malloc
542 : * deep down the call chain. We are responsible for freeing. */
543 1 : ret = _gnutls_x509_raw_crt_to_raw_pubkey(cert, &pubkey);
544 :
545 1 : if (ret < 0) {
546 0 : _gnutls_free_datum(&pubkey);
547 0 : return gnutls_assert_val(ret);
548 : }
549 :
550 : need_free = true;
551 : break;
552 1 : case GNUTLS_CRT_RAWPK:
553 1 : pubkey.data = cert->data;
554 1 : pubkey.size = cert->size;
555 1 : need_free = false;
556 1 : break;
557 : default:
558 0 : return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE);
559 : }
560 :
561 2 : _gnutls_debug_log("Configuration file: %s\n", db_name);
562 :
563 2 : tdb->store(db_name, host, service, expiration, &pubkey);
564 :
565 2 : if (need_free) {
566 1 : _gnutls_free_datum(&pubkey);
567 : }
568 :
569 : return GNUTLS_E_SUCCESS;
570 : }
571 :
572 : /**
573 : * gnutls_store_commitment:
574 : * @db_name: A file specifying the stored keys (use NULL for the default)
575 : * @tdb: A storage structure or NULL to use the default
576 : * @host: The peer's name
577 : * @service: non-NULL if this key is specific to a service (e.g. http)
578 : * @hash_algo: The hash algorithm type
579 : * @hash: The raw hash
580 : * @expiration: The expiration time (use 0 to disable expiration)
581 : * @flags: should be 0 or %GNUTLS_SCOMMIT_FLAG_ALLOW_BROKEN.
582 : *
583 : * This function will store the provided hash commitment to
584 : * the list of stored public keys. The key with the given
585 : * hash will be considered valid until the provided expiration time.
586 : *
587 : * The @tdb variable if non-null specifies a custom backend for
588 : * the storage of entries. If it is NULL then the
589 : * default file backend will be used.
590 : *
591 : * Note that this function is not thread safe with the default backend.
592 : *
593 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
594 : * negative error value.
595 : *
596 : * Since: 3.0
597 : **/
598 : int
599 2 : gnutls_store_commitment(const char *db_name,
600 : gnutls_tdb_t tdb,
601 : const char *host,
602 : const char *service,
603 : gnutls_digest_algorithm_t hash_algo,
604 : const gnutls_datum_t * hash,
605 : time_t expiration, unsigned int flags)
606 : {
607 2 : int ret;
608 2 : char local_file[MAX_FILENAME];
609 2 : const mac_entry_st *me = hash_to_entry(hash_algo);
610 :
611 2 : if (me == NULL)
612 0 : return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);
613 :
614 2 : if (!(flags & GNUTLS_SCOMMIT_FLAG_ALLOW_BROKEN) && _gnutls_digest_is_secure(me) == 0)
615 0 : return gnutls_assert_val(GNUTLS_E_INSUFFICIENT_SECURITY);
616 :
617 2 : if (_gnutls_hash_get_algo_len(me) != hash->size)
618 0 : return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
619 :
620 2 : if (db_name == NULL && tdb == NULL) {
621 1 : ret =
622 1 : _gnutls_find_config_path(local_file,
623 : sizeof(local_file));
624 1 : if (ret < 0)
625 0 : return gnutls_assert_val(ret);
626 :
627 1 : _gnutls_debug_log("Configuration path: %s\n", local_file);
628 1 : mkdir(local_file, 0700);
629 :
630 1 : ret = find_config_file(local_file, sizeof(local_file));
631 1 : if (ret < 0)
632 0 : return gnutls_assert_val(ret);
633 : db_name = local_file;
634 : }
635 :
636 2 : if (tdb == NULL)
637 2 : tdb = &default_tdb;
638 :
639 2 : _gnutls_debug_log("Configuration file: %s\n", db_name);
640 :
641 2 : tdb->cstore(db_name, host, service, expiration,
642 2 : (gnutls_digest_algorithm_t)me->id, hash);
643 :
644 2 : return 0;
645 : }
646 :
647 : #define CONFIG_FILE "known_hosts"
648 :
649 2 : static int find_config_file(char *file, size_t max_size)
650 : {
651 2 : char path[MAX_FILENAME];
652 2 : int ret;
653 :
654 2 : ret = _gnutls_find_config_path(path, sizeof(path));
655 2 : if (ret < 0)
656 0 : return gnutls_assert_val(ret);
657 :
658 2 : if (path[0] == 0)
659 0 : snprintf(file, max_size, "%s", CONFIG_FILE);
660 : else
661 2 : snprintf(file, max_size, "%s/%s", path, CONFIG_FILE);
662 :
663 : return 0;
664 : }
665 :
666 : /**
667 : * gnutls_tdb_init:
668 : * @tdb: A pointer to the type to be initialized
669 : *
670 : * This function will initialize a public key trust storage structure.
671 : *
672 : * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
673 : * negative error value.
674 : **/
675 0 : int gnutls_tdb_init(gnutls_tdb_t * tdb)
676 : {
677 0 : *tdb = gnutls_calloc(1, sizeof(struct gnutls_tdb_int));
678 :
679 0 : if (!*tdb)
680 0 : return GNUTLS_E_MEMORY_ERROR;
681 :
682 : return 0;
683 : }
684 :
685 : /**
686 : * gnutls_set_store_func:
687 : * @tdb: The trust storage
688 : * @store: The storage function
689 : *
690 : * This function will associate a storage function with the
691 : * trust storage structure. The function is of the following form.
692 : *
693 : * int gnutls_tdb_store_func(const char* db_name, const char* host,
694 : * const char* service, time_t expiration,
695 : * const gnutls_datum_t* pubkey);
696 : *
697 : * The @db_name should be used to pass any private data to this function.
698 : *
699 : **/
700 0 : void gnutls_tdb_set_store_func(gnutls_tdb_t tdb,
701 : gnutls_tdb_store_func store)
702 : {
703 0 : tdb->store = store;
704 0 : }
705 :
706 : /**
707 : * gnutls_set_store_commitment_func:
708 : * @tdb: The trust storage
709 : * @cstore: The commitment storage function
710 : *
711 : * This function will associate a commitment (hash) storage function with the
712 : * trust storage structure. The function is of the following form.
713 : *
714 : * int gnutls_tdb_store_commitment_func(const char* db_name, const char* host,
715 : * const char* service, time_t expiration,
716 : * gnutls_digest_algorithm_t, const gnutls_datum_t* hash);
717 : *
718 : * The @db_name should be used to pass any private data to this function.
719 : *
720 : **/
721 0 : void gnutls_tdb_set_store_commitment_func(gnutls_tdb_t tdb,
722 : gnutls_tdb_store_commitment_func
723 : cstore)
724 : {
725 0 : tdb->cstore = cstore;
726 0 : }
727 :
728 : /**
729 : * gnutls_set_verify_func:
730 : * @tdb: The trust storage
731 : * @verify: The verification function
732 : *
733 : * This function will associate a retrieval function with the
734 : * trust storage structure. The function is of the following form.
735 : *
736 : * int gnutls_tdb_verify_func(const char* db_name, const char* host,
737 : * const char* service, const gnutls_datum_t* pubkey);
738 : *
739 : * The verify function should return zero on a match, %GNUTLS_E_CERTIFICATE_KEY_MISMATCH
740 : * if there is a mismatch and any other negative error code otherwise.
741 : *
742 : * The @db_name should be used to pass any private data to this function.
743 : *
744 : **/
745 0 : void gnutls_tdb_set_verify_func(gnutls_tdb_t tdb,
746 : gnutls_tdb_verify_func verify)
747 : {
748 0 : tdb->verify = verify;
749 0 : }
750 :
751 : /**
752 : * gnutls_tdb_deinit:
753 : * @tdb: The structure to be deinitialized
754 : *
755 : * This function will deinitialize a public key trust storage structure.
756 : **/
757 0 : void gnutls_tdb_deinit(gnutls_tdb_t tdb)
758 : {
759 0 : gnutls_free(tdb);
760 0 : }
|