text update
[gnutls.git] / lib / verify-ssh.c
blob8d6562f705a76ae7f4be4304b433f2aec4191e26
1 /*
2 * Copyright (C) 2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
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 3 of
11 * the License, or (at your option) any later version.
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.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
23 #include <gnutls_int.h>
24 #include <gnutls_errors.h>
25 #include <libtasn1.h>
26 #include <gnutls_global.h>
27 #include <gnutls_num.h> /* MAX */
28 #include <gnutls_sig.h>
29 #include <gnutls_str.h>
30 #include <gnutls_datum.h>
31 #include <hash.h>
32 #include "x509_int.h"
33 #include <common.h>
34 #include <base64.h>
35 #include <gnutls/abstract.h>
36 #include <system.h>
38 static int raw_pubkey_to_base64(gnutls_datum_t* pubkey);
39 static int x509_crt_to_raw_pubkey(const gnutls_datum_t * cert, gnutls_datum_t *rpubkey);
40 static int pgp_crt_to_raw_pubkey(const gnutls_datum_t * cert, gnutls_datum_t *rpubkey);
41 static int find_stored_pubkey(const char* file, const char* application,
42 const char* host, const char* service,
43 const gnutls_datum_t* skey);
44 static int find_config_file(char* file, size_t max_size);
45 #define MAX_FILENAME 512
47 /**
48 * gnutls_verify_stored_pubkey:
49 * @file: A file specifying the stored keys (use NULL for the default)
50 * @application: non-NULL with an application name if this key is application-specific
51 * @host: The peer's name
52 * @service: non-NULL if this key is specific to a service (e.g. http)
53 * @cert_type: The type of the certificate
54 * @cert: The raw (der) data of the certificate
55 * @flags: should be 0.
57 * This function will try to verify the provided certificate using
58 * a list of stored public keys. The @service field if non-NULL should
59 * be a port number.
61 * Returns: If no associated public key is found
62 * then %GNUTLS_E_NO_CERTIFICATE_FOUND will be returned. If a key
63 * is found but does not match %GNUTLS_E_CERTIFICATE_KEY_MISMATCH
64 * is returned. On success, %GNUTLS_E_SUCCESS (0) is returned,
65 * or a negative error value on other errors.
67 * Since: 3.0.0
68 **/
69 int
70 gnutls_verify_stored_pubkey(const char* file,
71 const char* application,
72 const char* host,
73 const char* service,
74 gnutls_certificate_type_t cert_type,
75 const gnutls_datum_t * cert, unsigned int flags)
77 gnutls_datum_t pubkey = { NULL, 0 };
78 int ret;
79 char local_file[MAX_FILENAME];
81 if (cert_type != GNUTLS_CRT_X509 && cert_type != GNUTLS_CRT_OPENPGP)
82 return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE);
84 if (file == NULL)
86 ret = find_config_file(local_file, sizeof(local_file));
87 if (ret < 0)
88 return gnutls_assert_val(ret);
89 file = local_file;
92 if (cert_type == GNUTLS_CRT_X509)
93 ret = x509_crt_to_raw_pubkey(cert, &pubkey);
94 else
95 ret = pgp_crt_to_raw_pubkey(cert, &pubkey);
97 if (ret < 0)
99 gnutls_assert();
100 goto cleanup;
103 ret = raw_pubkey_to_base64(&pubkey);
104 if (ret < 0)
106 gnutls_assert();
107 goto cleanup;
110 ret = find_stored_pubkey(file, application, host, service, &pubkey);
111 if (ret < 0)
112 return gnutls_assert_val(GNUTLS_E_NO_CERTIFICATE_FOUND);
115 cleanup:
116 gnutls_free(pubkey.data);
117 return ret;
120 static int parse_line(char* line, const char* application,
121 size_t application_len,
122 const char* host, size_t host_len,
123 const char* service, size_t service_len,
124 const gnutls_datum_t *skey)
126 char* p, *kp;
127 char* savep = NULL;
128 size_t kp_len;
130 /* read version */
131 p = strtok_r(line, "|", &savep);
132 if (p == NULL)
133 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
135 if (strncmp(p, "g0", 2) != 0)
136 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
138 /* read application */
139 p = strtok_r(NULL, "|", &savep);
140 if (p == NULL)
141 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
143 if (p[0] != '*' && strcmp(p, application)!=0)
144 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
146 /* read host */
147 p = strtok_r(NULL, "|", &savep);
148 if (p == NULL)
149 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
151 if (p[0] != '*' && strcmp(p, host) != 0)
152 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
154 /* read service */
155 p = strtok_r(NULL, "|", &savep);
156 if (p == NULL)
157 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
159 if (p[0] != '*' && strcmp(p, service) != 0)
160 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
162 /* read service */
163 kp = strtok_r(NULL, "|", &savep);
164 if (kp == NULL)
165 return gnutls_assert_val(GNUTLS_E_PARSING_ERROR);
167 p = strpbrk(kp, "\n \r\t|");
168 if (p != NULL) *p = 0;
170 kp_len = strlen(kp);
171 if (kp_len != skey->size)
172 return gnutls_assert_val(GNUTLS_E_CERTIFICATE_KEY_MISMATCH);
174 if (memcmp(kp, skey->data, skey->size) != 0)
175 return gnutls_assert_val(GNUTLS_E_CERTIFICATE_KEY_MISMATCH);
177 /* key found and matches */
178 return 0;
181 /* Returns the base64 key if found
183 static int find_stored_pubkey(const char* file, const char* application,
184 const char* host, const char* service,
185 const gnutls_datum_t* skey)
187 FILE* fd;
188 char* line = NULL;
189 size_t line_size = 0;
190 int ret, l2, mismatch = 0;
191 size_t application_len = 0, host_len = 0, service_len = 0;
193 if (host != NULL) host_len = strlen(host);
194 if (service != NULL) service_len = strlen(service);
195 if (application != NULL) application_len = strlen(application);
197 fd = fopen(file, "rb");
198 if (fd == NULL)
199 return gnutls_assert_val(GNUTLS_E_FILE_ERROR);
203 l2 = getline(&line, &line_size, fd);
204 if (l2 > 0)
206 ret = parse_line(line, application, application_len,
207 host, host_len, service, service_len, skey);
208 if (ret == 0) /* found */
210 goto cleanup;
212 else if (ret == GNUTLS_E_CERTIFICATE_KEY_MISMATCH)
213 mismatch = 1;
216 while(l2 >= 0);
218 if (mismatch)
219 ret = GNUTLS_E_CERTIFICATE_KEY_MISMATCH;
220 else
221 ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
223 cleanup:
224 free(line);
225 fclose(fd);
227 return ret;
230 static int raw_pubkey_to_base64(gnutls_datum_t* pubkey)
232 int ret;
233 char* out;
235 ret = base64_encode_alloc((void*)pubkey->data, pubkey->size, &out);
236 if (ret == 0)
237 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
239 gnutls_free(pubkey->data);
240 pubkey->data = (void*)out;
241 pubkey->size = ret;
243 return 0;
246 static int x509_crt_to_raw_pubkey(const gnutls_datum_t * cert, gnutls_datum_t *rpubkey)
248 gnutls_x509_crt_t crt = NULL;
249 gnutls_pubkey_t pubkey = NULL;
250 size_t size;
251 int ret;
253 ret = gnutls_x509_crt_init(&crt);
254 if (ret < 0)
255 return gnutls_assert_val(ret);
257 ret = gnutls_pubkey_init(&pubkey);
258 if (ret < 0)
260 gnutls_assert();
261 goto cleanup;
264 ret = gnutls_x509_crt_import(crt, cert, GNUTLS_X509_FMT_DER);
265 if (ret < 0)
267 gnutls_assert();
268 goto cleanup;
271 ret = gnutls_pubkey_import_x509 (pubkey, crt, 0);
272 if (ret < 0)
274 gnutls_assert();
275 goto cleanup;
278 size = 0;
279 ret = gnutls_pubkey_export(pubkey, GNUTLS_X509_FMT_DER, NULL, &size);
280 if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
282 gnutls_assert();
283 goto cleanup;
286 rpubkey->data = gnutls_malloc(size);
287 if (rpubkey->data == NULL)
288 if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
290 ret = GNUTLS_E_MEMORY_ERROR;
291 gnutls_assert();
292 goto cleanup;
295 ret = gnutls_pubkey_export(pubkey, GNUTLS_X509_FMT_DER, rpubkey->data, &size);
296 if (ret < 0)
298 gnutls_free(rpubkey->data);
299 gnutls_assert();
300 goto cleanup;
303 rpubkey->size = size;
304 ret = 0;
306 cleanup:
307 gnutls_x509_crt_deinit(crt);
308 gnutls_pubkey_deinit(pubkey);
310 return ret;
313 static int pgp_crt_to_raw_pubkey(const gnutls_datum_t * cert, gnutls_datum_t *rpubkey)
315 gnutls_openpgp_crt_t crt = NULL;
316 gnutls_pubkey_t pubkey = NULL;
317 size_t size;
318 int ret;
320 ret = gnutls_openpgp_crt_init(&crt);
321 if (ret < 0)
322 return gnutls_assert_val(ret);
324 ret = gnutls_pubkey_init(&pubkey);
325 if (ret < 0)
327 gnutls_assert();
328 goto cleanup;
331 ret = gnutls_openpgp_crt_import(crt, cert, GNUTLS_OPENPGP_FMT_RAW);
332 if (ret < 0)
334 gnutls_assert();
335 goto cleanup;
338 ret = gnutls_pubkey_import_openpgp (pubkey, crt, 0);
339 if (ret < 0)
341 gnutls_assert();
342 goto cleanup;
345 size = 0;
346 ret = gnutls_pubkey_export(pubkey, GNUTLS_X509_FMT_DER, NULL, &size);
347 if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
349 gnutls_assert();
350 goto cleanup;
353 rpubkey->data = gnutls_malloc(size);
354 if (rpubkey->data == NULL)
355 if (ret < 0 && ret != GNUTLS_E_SHORT_MEMORY_BUFFER)
357 ret = GNUTLS_E_MEMORY_ERROR;
358 gnutls_assert();
359 goto cleanup;
362 ret = gnutls_pubkey_export(pubkey, GNUTLS_X509_FMT_DER, rpubkey->data, &size);
363 if (ret < 0)
365 gnutls_free(rpubkey->data);
366 gnutls_assert();
367 goto cleanup;
370 rpubkey->size = size;
371 ret = 0;
373 cleanup:
374 gnutls_openpgp_crt_deinit(crt);
375 gnutls_pubkey_deinit(pubkey);
377 return ret;
381 * gnutls_store_pubkey:
382 * @file: A file specifying the stored keys (use NULL for the default)
383 * @application: non-NULL with an application name if this key is application-specific
384 * @host: The peer's name
385 * @service: non-NULL if this key is specific to a service (e.g. http)
386 * @cert_type: The type of the certificate
387 * @cert: The data of the certificate
388 * @flags: should be 0.
390 * This function will store to verify the provided certificate to
391 * the list of stored public keys.
393 * Note that this function is not thread safe.
395 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, otherwise a
396 * negative error value.
398 * Since: 3.0.0
401 gnutls_store_pubkey(const char* file,
402 const char* application,
403 const char* host,
404 const char* service,
405 gnutls_certificate_type_t cert_type,
406 const gnutls_datum_t * cert, unsigned int flags)
408 FILE* fd = NULL;
409 gnutls_datum_t pubkey = { NULL, 0 };
410 int ret;
411 char local_file[MAX_FILENAME];
413 if (cert_type != GNUTLS_CRT_X509 && cert_type != GNUTLS_CRT_OPENPGP)
414 return gnutls_assert_val(GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE);
416 if (file == NULL)
418 ret = _gnutls_find_config_path(local_file, sizeof(local_file));
419 if (ret < 0)
420 return gnutls_assert_val(ret);
422 _gnutls_debug_log("Configuration path: %s\n", local_file);
423 mkdir(local_file, 0700);
425 ret = find_config_file(local_file, sizeof(local_file));
426 if (ret < 0)
427 return gnutls_assert_val(ret);
428 file = local_file;
431 if (cert_type == GNUTLS_CRT_X509)
432 ret = x509_crt_to_raw_pubkey(cert, &pubkey);
433 else
434 ret = pgp_crt_to_raw_pubkey(cert, &pubkey);
435 if (ret < 0)
437 gnutls_assert();
438 goto cleanup;
441 ret = raw_pubkey_to_base64(&pubkey);
442 if (ret < 0)
444 gnutls_assert();
445 goto cleanup;
448 _gnutls_debug_log("Configuration file: %s\n", file);
450 fd = fopen(file, "ab+");
451 if (fd == NULL)
453 ret = gnutls_assert_val(GNUTLS_E_FILE_ERROR);
454 goto cleanup;
457 if (application == NULL) application = "*";
458 if (service == NULL) service = "*";
459 if (host == NULL) host = "*";
461 fprintf(fd, "|g0|%s|%s|%s|%.*s\n", application, host, service, pubkey.size, pubkey.data);
463 ret = 0;
465 cleanup:
466 gnutls_free(pubkey.data);
467 if (fd != NULL) fclose(fd);
469 return ret;
472 #define CONFIG_FILE "known_hosts"
474 static int find_config_file(char* file, size_t max_size)
476 char path[MAX_FILENAME];
477 int ret;
479 ret = _gnutls_find_config_path(path, sizeof(path));
480 if (ret < 0)
481 return gnutls_assert_val(ret);
483 if (path[0] == 0)
484 snprintf(file, max_size, "%s", CONFIG_FILE);
485 else
486 snprintf(file, max_size, "%s/%s", path, CONFIG_FILE);
488 return 0;