File: ikev2_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 (178 lines) | stat: -rw-r--r-- 5,460 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
/* Support for IKEv2 CERT payloads, 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-2022 Andrew Cagney
 * 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 "lswnss.h"

#include "defs.h"

#include "ikev2_cert.h"
#include "state.h"
#include "connections.h"
#include "nss_cert_verify.h"
#include "ikev2_message.h"
#include "log.h"
#include "pluto_x509.h"		/* for get_auth_chain() */

/*
 * Send v2 CERT and possible CERTREQ (which should be separated
 * eventually).
 */

stf_status emit_v2CERT(const struct connection *c, struct pbs_out *outpbs)
{
	const struct cert *mycert = c->local->host.config->cert.nss_cert != NULL ? &c->local->host.config->cert : NULL;
	bool send_authcerts = c->config->send_ca != CA_SEND_NONE;
	bool send_full_chain = send_authcerts && c->config->send_ca == CA_SEND_ALL;

	if (impair.send_pkcs7_thingie) {
		llog(RC_LOG, outpbs->logger, "IMPAIR: sending cert as PKCS7 blob");
		passert(mycert != NULL);
		SECItem *pkcs7 = nss_pkcs7_blob(mycert, send_full_chain);
		if (!pexpect(pkcs7 != NULL)) {
			return STF_INTERNAL_ERROR;
		}
		struct ikev2_cert pkcs7_hdr = {
			.isac_critical = build_ikev2_critical(false, outpbs->logger),
			.isac_enc = CERT_PKCS7_WRAPPED_X509,
		};
		struct pbs_out cert_pbs;
		if (!out_struct(&pkcs7_hdr, &ikev2_certificate_desc,
				outpbs, &cert_pbs) ||
		    !out_hunk(same_secitem_as_chunk(*pkcs7), &cert_pbs, "PKCS7")) {
			SECITEM_FreeItem(pkcs7, PR_TRUE);
			return STF_INTERNAL_ERROR;
		}
		close_output_pbs(&cert_pbs);
		SECITEM_FreeItem(pkcs7, PR_TRUE);
		return STF_OK;
	}

	/*****
	 * From here on, if send_authcerts, we are obligated to:
	 * free_auth_chain(auth_chain, chain_len);
	 *****/

	chunk_t auth_chain[MAX_CA_PATH_LEN] = { { NULL, 0 } };
	int chain_len = 0;

	if (send_authcerts) {
		chain_len = get_auth_chain(auth_chain, MAX_CA_PATH_LEN,
					   mycert,
					   send_full_chain ? true : false);
	}

	const struct ikev2_cert certhdr = {
		.isac_critical = build_ikev2_critical(false, outpbs->logger),
		.isac_enc = cert_ike_type(mycert),
	};

	/*   send own (Initiator CERT) */
	{
		struct pbs_out cert_pbs;

		dbg("sending [CERT] of certificate: %s", cert_nickname(mycert));

		if (!out_struct(&certhdr, &ikev2_certificate_desc,
				outpbs, &cert_pbs) ||
		    !out_hunk(cert_der(mycert), &cert_pbs, "CERT")) {
			free_auth_chain(auth_chain, chain_len);
			return STF_INTERNAL_ERROR;
		}

		close_output_pbs(&cert_pbs);
	}

	/* send optional chain CERTs */
	{
		for (int i = 0; i < chain_len ; i++) {
			struct pbs_out cert_pbs;

			dbg("sending an authcert");

			if (!out_struct(&certhdr, &ikev2_certificate_desc,
				outpbs, &cert_pbs) ||
			    !out_hunk(auth_chain[i], &cert_pbs, "CERT"))
			{
				free_auth_chain(auth_chain, chain_len);
				return STF_INTERNAL_ERROR;
			}
			close_output_pbs(&cert_pbs);
		}
	}
	free_auth_chain(auth_chain, chain_len);
	return STF_OK;
}

/*
 * For IKEv2, returns TRUE if we should be sending a cert.
 *
 * EAP-Only, for instance, never sends certs.
 */
bool ikev2_send_cert_decision(const struct ike_sa *ike)
{
	const struct connection *c = ike->sa.st_connection;

	if (ike->sa.st_peer_wants_null) {
		/* XXX: only ever true on responder */
		dbg("IKEv2 CERT: not sending cert: peer wants (we're using?) NULL")
		return false;
	}

	if (c->local->host.config->auth == AUTH_EAPONLY) {
		dbg("IKEv2 CERT: not sending cert: local %sauth==EAPONLY",
		    c->local->config->leftright)
		return false;
	}

	if (!authby_has_digsig(c->local->host.config->authby)) {
		authby_buf pb;
		dbg("IKEv2 CERT: not sending cert: local %sauthby=%s does not have RSA or ECDSA",
		    c->local->config->leftright,
		    str_authby(c->local->host.config->authby, &pb));
		return false;
	}

	if (c->local->host.config->cert.nss_cert == NULL) {
		dbg("IKEv2 CERT: not sending cert: there is no local certificate to send");
		return false;
	}

	if (c->local->host.config->sendcert == CERT_SENDIFASKED &&
	    ike->sa.st_v2_ike_seen_certreq) {
		dbg("IKEv2 CERT: OK to send certificate (send if asked)");
		return true;
	}

	if (c->local->host.config->sendcert == CERT_ALWAYSSEND) {
		dbg("IKEv2 CERT: OK to send a certificate (always)");
		return true;
	}

	return false;
}