File: ikev1_cert.c

package info (click to toggle)
libreswan 5.2-2.3
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 81,644 kB
  • sloc: ansic: 129,988; sh: 32,018; xml: 20,646; python: 10,303; makefile: 3,022; javascript: 1,506; sed: 574; yacc: 511; perl: 264; awk: 52
file content (290 lines) | stat: -rw-r--r-- 9,049 bytes parent folder | download | duplicates (2)
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
/* Support of X.509 certificates and CRLs for libreswan
 *
 * Copyright (C) 2000 Andreas Hess, Patric Lichtsteiner, Roger Wegmann
 * Copyright (C) 2001 Marco Bertossa, Andreas Schleiss
 * Copyright (C) 2002 Mario Strasser
 * Copyright (C) 2000-2004 Andreas Steffen, Zuercher Hochschule Winterthur
 * Copyright (C) 2006-2010 Paul Wouters <paul@xelerance.com>
 * Copyright (C) 2008-2009 David McCullough <david_mccullough@securecomputing.com>
 * Copyright (C) 2009 Gilles Espinasse <g.esp@free.fr>
 * Copyright (C) 2012-2013 Paul Wouters <paul@libreswan.org>
 * Copyright (C) 2012 Wes Hardaker <opensource@hardakers.net>
 * Copyright (C) 2013 Matt Rogers <mrogers@redhat.com>
 * Copyright (C) 2013-2019 D. Hugh Redelmeier <hugh@mimosa.com>
 * Copyright (C) 2013 Kim B. Heino <b@bbbs.net>
 * Copyright (C) 2018-2019 Andrew Cagney <cagney@gnu.org>
 * Copyright (C) 2018 Sahana Prasad <sahana.prasad07@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or (at your
 * option) any later version.  See <https://www.gnu.org/licenses/gpl2.txt>.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 */

#include "defs.h"
#include "root_certs.h"

#include "ikev1_cert.h"
#include "log.h"
#include "demux.h"
#include "state.h"
#include "connections.h"
#include "secrets.h"
#include "nss_cert_verify.h"
#include "fetch.h"		/* for oscb_enable et.al. */
#include "pluto_x509.h"		/* for find_crl_fetch_dn() */
#include "crl_queue.h"		/* for submit_crl_fetch_request() */

/*
 * Decode the CERT payload of Phase 1.
 */
/* todo:
 * https://tools.ietf.org/html/rfc4945
 *  3.3.4. PKCS #7 Wrapped X.509 Certificate
 *
 *  This type defines a particular encoding, not a particular certificate
 *  type.  Implementations SHOULD NOT generate CERTs that contain this
 *  Certificate Type.  Implementations SHOULD accept CERTs that contain
 *  this Certificate Type because several implementations are known to
 *  generate them.  Note that those implementations sometimes include
 *  entire certificate hierarchies inside a single CERT PKCS #7 payload,
 *  which violates the requirement specified in ISAKMP that this payload
 *  contain a single certificate.
 */

/*
 * Decode the certs.  If something nasty happens, such as an expired
 * cert, return false.
 *
 * Only log failures, success is left to v2_verify_certs().
 */

bool v1_decode_certs(struct msg_digest *md)
{
	struct state *st = md->v1_st;
	passert(st->st_ike_version == IKEv1);

	/*
	 * At least one set of certs have been processed; and at least
	 * once.
	 *
	 * The way this code is called is broken (see functions
	 * ikev1_decode_peer_id*() and oakley_auth()):
	 *
	 * - it is repeatedly called to decode the same cert payload
	 * (causing a cert payload the be decoded multiple times)
	 *
	 * - it is called to decode cert payloads that aren't there
	 * (for instance the first aggressive request)
	 */
	st->st_remote_certs.processed = true;

	struct payload_digest *cert_payloads = md->chain[ISAKMP_NEXT_CERT];
	if (cert_payloads == NULL) {
		return true;
	}

	if (st->st_remote_certs.verified != NULL) {
		dbg("hacking around a redundant call to v1_process_certs() - releasing verified");
		release_certs(&st->st_remote_certs.verified);
	}
	if (st->st_remote_certs.pubkey_db != NULL) {
		dbg("hacking around a redundant call to v1_process_certs() - releasing pubkey_db");
		free_public_keys(&st->st_remote_certs.pubkey_db);
	}

	if (!pexpect(st->st_remote_certs.verified == NULL)) {
		/*
		 * Since the MITM has already failed their first
		 * attempt at proving their credentials, there's no
		 * point in giving them a second chance.
		 *
		 * Happens because code rejecting the first
		 * authentication attempt leaves the state as-is
		 * instead of zombifying (where the notification is
		 * recorded and then sent, and then the state
		 * transitions to zombie where it can linger while
		 * dealing with duplicate packets) or deleting it.
		 */
		return false;
	}

	statetime_t start = statetime_start(st);
	struct connection *c = st->st_connection;

	const struct rev_opts rev_opts = {
		.ocsp = ocsp_enable,
		.ocsp_strict = ocsp_strict,
		.ocsp_post = ocsp_post,
		.crl_strict = crl_strict,
	};

	struct root_certs *root_certs = root_certs_addref(&global_logger); /* must-release */
	struct verified_certs certs = find_and_verify_certs(st->logger, st->st_ike_version,
							    cert_payloads, &rev_opts,
							    root_certs, &c->remote->host.id);
	root_certs_delref(&root_certs, GLOBAL_LOGGER);

	/* either something went wrong, or there were no certs */
	if (certs.cert_chain == NULL) {
#if defined(LIBCURL) || defined(LIBLDAP)
		if (certs.crl_update_needed && deltasecs(crl_check_interval) > 0) {
			/*
			 * When a strict crl check fails, the certs
			 * are deleted and CRL_NEEDED is set.
			 *
			 * When a non-strict crl check fails, it is
			 * left to the crl fetch job to do a refresh.
			 *
			 * Trigger a refresh.
			 */
			chunk_t fdn = empty_chunk;
			if (find_crl_fetch_dn(&fdn, c)) {
				/* FDN contains issuer_dn */
				submit_crl_fetch_request(ASN1(fdn), st->logger);
			}
		}
#endif
		if (certs.harmless) {
			/* For instance, no CA, unknown certs, ... */
			return true;
		} else {
			log_state(RC_LOG, st,
				    "X509: certificate rejected for this connection");
			/* For instance, revoked */
			return false;
		}
	}

	pexpect(st->st_remote_certs.pubkey_db == NULL);
	st->st_remote_certs.pubkey_db = certs.pubkey_db;
	certs.pubkey_db = NULL;

	pexpect(st->st_remote_certs.verified == NULL);
	st->st_remote_certs.verified = certs.cert_chain;
	certs.cert_chain = NULL;

	statetime_stop(&start, "%s()", __func__);
	return true;
}

/*
 * Decode the CR payload of Phase 1.
 *
 *  https://tools.ietf.org/html/rfc4945
 *  3.2.4. PKCS #7 wrapped X.509 certificate
 *
 *  This ID type defines a particular encoding (not a particular
 *  certificate type); some current implementations may ignore CERTREQs
 *  they receive that contain this ID type, and the editors are unaware
 *  of any implementations that generate such CERTREQ messages.
 *  Therefore, the use of this type is deprecated.  Implementations
 *  SHOULD NOT require CERTREQs that contain this Certificate Type.
 *  Implementations that receive CERTREQs that contain this ID type MAY
 *  treat such payloads as synonymous with "X.509 Certificate -
 *  Signature".
 */

static void decode_v1_certificate_request(struct ike_sa *ike,
					  enum ike_cert_type cert_type,
					  const struct pbs_in *pbs)
{
	switch (cert_type) {
	case CERT_X509_SIGNATURE:
	{
		asn1_t ca_name = pbs_in_left(pbs);

		if (DBGP(DBG_BASE)) {
			DBG_dump_hunk("CR", ca_name);
		}

		if (ca_name.len > 0) {
			err_t e = asn1_ok(ca_name);
			if (e != NULL) {
				llog(RC_LOG, ike->sa.logger,
				     "ignoring CERTREQ payload that is not ASN1: %s", e);
				return;
			}

			generalName_t *gn = alloc_thing(generalName_t, "generalName");
			gn->name = clone_hunk(ca_name, "ca name");
			gn->kind = GN_DIRECTORY_NAME;
			gn->next = ike->sa.st_v1_requested_ca;
			ike->sa.st_v1_requested_ca = gn;
		}

		if (LDBGP(DBG_BASE, ike->sa.logger)) {
			dn_buf buf;
			LDBG_log(ike->sa.logger, "requested CA: '%s'",
				 str_dn_or_null(ca_name, "%any", &buf));
		}
		break;
	}
	default:
	{
		enum_buf b;
		llog(RC_LOG, ike->sa.logger,
		     "ignoring CERTREQ payload of unsupported type %s",
		     str_enum(&ikev2_cert_type_names, cert_type, &b));
	}
	}
}

void decode_v1_certificate_requests(struct ike_sa *ike, struct msg_digest *md)
{
	for (struct payload_digest *p = md->chain[ISAKMP_NEXT_CR]; p != NULL; p = p->next) {
		const struct isakmp_cr *const cr = &p->payload.cr;
		decode_v1_certificate_request(ike, cr->isacr_type, &p->pbs);
	}
}

bool ikev1_ship_CERT(enum ike_cert_type type, shunk_t cert, struct pbs_out *outs)
{
	struct pbs_out cert_pbs;
	struct isakmp_cert cert_hd = {
		.isacert_type = type,
		.isacert_reserved = 0,
		.isacert_length = 0, /* XXX unused on sending ? */
	};

	if (!out_struct(&cert_hd, &isakmp_ipsec_certificate_desc, outs,
				&cert_pbs) ||
	    !out_hunk(cert, &cert_pbs, "CERT"))
		return false;

	close_output_pbs(&cert_pbs);
	return true;
}

bool ikev1_build_and_ship_CR(enum ike_cert_type type,
			     chunk_t ca, struct pbs_out *outs)
{
	struct pbs_out cr_pbs;
	struct isakmp_cr cr_hd = {
		.isacr_type = type,
	};

	if (!out_struct(&cr_hd, &isakmp_ipsec_cert_req_desc, outs, &cr_pbs) ||
	    (ca.ptr != NULL && !out_hunk(ca, &cr_pbs, "CA")))
		return false;

	close_output_pbs(&cr_pbs);
	return true;
}

bool ikev1_ship_chain(chunk_t *chain, int n, struct pbs_out *outs,
		      uint8_t type)
{
	for (int i = 0; i < n; i++) {
		if (!ikev1_ship_CERT(type, HUNK_AS_SHUNK(chain[i]), outs))
			return false;
	}

	return true;
}