File: ex-verify-ssh.c

package info (click to toggle)
gnutls28 3.8.12-3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 82,380 kB
  • sloc: ansic: 392,233; asm: 117,804; sh: 18,758; makefile: 6,804; yacc: 1,858; python: 1,399; cpp: 1,243; perl: 995; sed: 39
file content (96 lines) | stat: -rw-r--r-- 2,862 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
/* This example code is placed in the public domain. */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
#include <assert.h>
#include "examples.h"

#define CHECK(x) assert((x) >= 0)

/* This function will verify the peer's certificate, check
 * if the hostname matches. In addition it will perform an
 * SSH-style authentication, where ultimately trusted keys
 * are only the keys that have been seen before.
 */
int _ssh_verify_certificate_callback(gnutls_session_t session)
{
	unsigned int status;
	const gnutls_datum_t *cert_list;
	unsigned int cert_list_size;
	int ret, type;
	gnutls_datum_t out;
	const char *hostname;

	/* read hostname */
	hostname = gnutls_session_get_ptr(session);

	/* This verification function uses the trusted CAs in the credentials
	 * structure. So you must have installed one or more CA certificates.
	 */
	CHECK(gnutls_certificate_verify_peers3(session, hostname, &status));

	type = gnutls_certificate_type_get(session);

	CHECK(gnutls_certificate_verification_status_print(status, type, &out,
							   0));
	printf("%s", out.data);

	gnutls_free(out.data);

	if (status != 0) /* Certificate is not trusted */
		return GNUTLS_E_CERTIFICATE_ERROR;

	/* Do SSH verification */
	cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
	if (cert_list == NULL) {
		printf("No certificate was found!\n");
		return GNUTLS_E_CERTIFICATE_ERROR;
	}

	/* service may be obtained alternatively using getservbyport() */
	ret = gnutls_verify_stored_pubkey(NULL, NULL, hostname, "https", type,
					  &cert_list[0], 0);
	if (ret == GNUTLS_E_NO_CERTIFICATE_FOUND) {
		printf("Host %s is not known.", hostname);
		if (status == 0)
			printf("Its certificate is valid for %s.\n", hostname);

		/* the certificate must be printed and user must be asked on
		 * whether it is trustworthy. --see gnutls_x509_crt_print() */

		/* if not trusted */
		return GNUTLS_E_CERTIFICATE_ERROR;
	} else if (ret == GNUTLS_E_CERTIFICATE_KEY_MISMATCH) {
		printf("Warning: host %s is known but has another key associated.",
		       hostname);
		printf("It might be that the server has multiple keys, or you are under attack\n");
		if (status == 0)
			printf("Its certificate is valid for %s.\n", hostname);

		/* the certificate must be printed and user must be asked on
		 * whether it is trustworthy. --see gnutls_x509_crt_print() */

		/* if not trusted */
		return GNUTLS_E_CERTIFICATE_ERROR;
	} else if (ret < 0) {
		printf("gnutls_verify_stored_pubkey: %s\n",
		       gnutls_strerror(ret));
		return ret;
	}

	/* user trusts the key -> store it */
	if (ret != 0) {
		CHECK(gnutls_store_pubkey(NULL, NULL, hostname, "https", type,
					  &cert_list[0], 0, 0));
	}

	/* notify gnutls to continue handshake normally */
	return 0;
}