File: | programs/pluto/ikev2_peer_id.c |
Warning: | line 308, column 25 The left operand of '!=' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* identify the PEER, for libreswan | |||
2 | * | |||
3 | * Copyright (C) 1997 Angelos D. Keromytis. | |||
4 | * Copyright (C) 1998-2010,2013-2017 D. Hugh Redelmeier <hugh@mimosa.com> | |||
5 | * Copyright (C) 2007-2008 Michael Richardson <mcr@xelerance.com> | |||
6 | * Copyright (C) 2009 David McCullough <david_mccullough@securecomputing.com> | |||
7 | * Copyright (C) 2008-2011 Paul Wouters <paul@xelerance.com> | |||
8 | * Copyright (C) 2010 Simon Deziel <simon@xelerance.com> | |||
9 | * Copyright (C) 2010 Tuomo Soini <tis@foobar.fi> | |||
10 | * Copyright (C) 2011-2012 Avesh Agarwal <avagarwa@redhat.com> | |||
11 | * Copyright (C) 2012 Paul Wouters <paul@libreswan.org> | |||
12 | * Copyright (C) 2012-2019 Paul Wouters <pwouters@redhat.com> | |||
13 | * Copyright (C) 2013 Matt Rogers <mrogers@redhat.com> | |||
14 | * Copyright (C) 2015-2019 Andrew Cagney | |||
15 | * Copyright (C) 2016-2018 Antony Antony <appu@phenome.org> | |||
16 | * Copyright (C) 2017 Sahana Prasad <sahana.prasad07@gmail.com> | |||
17 | * Copyright (C) 2020 Yulia Kuzovkova <ukuzovkova@gmail.com> | |||
18 | * | |||
19 | * This program is free software; you can redistribute it and/or modify it | |||
20 | * under the terms of the GNU General Public License as published by the | |||
21 | * Free Software Foundation; either version 2 of the License, or (at your | |||
22 | * option) any later version. See <https://www.gnu.org/licenses/gpl2.txt>. | |||
23 | * | |||
24 | * This program is distributed in the hope that it will be useful, but | |||
25 | * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY | |||
26 | * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
27 | * for more details. | |||
28 | * | |||
29 | */ | |||
30 | ||||
31 | #include "ikev2_peer_id.h" | |||
32 | ||||
33 | #include "defs.h" | |||
34 | #include "state.h" | |||
35 | #include "connections.h" | |||
36 | #include "log.h" | |||
37 | #include "demux.h" | |||
38 | #include "unpack.h" | |||
39 | #include "pluto_x509.h" | |||
40 | ||||
41 | static diag_t responder_match_initiator_id_counted(struct ike_sa *ike, | |||
42 | struct id peer_id, | |||
43 | struct id *tarzan_id, | |||
44 | struct msg_digest *md, int depth) | |||
45 | { | |||
46 | if (depth > 10) { | |||
47 | /* should not happen, but it would be nice to survive */ | |||
48 | return diag("decoding IKEv2 peer ID failed due to confusion"); | |||
49 | } | |||
50 | ||||
51 | bool_Bool must_switch = false0; | |||
52 | ||||
53 | /* start considering connection */ | |||
54 | ||||
55 | struct connection *c = ike->sa.st_connection; | |||
56 | ||||
57 | /* | |||
58 | * If there are certs, try re-running the id check. | |||
59 | */ | |||
60 | bool_Bool remote_cert_matches_id = false0; | |||
61 | if (ike->sa.st_remote_certs.verified != NULL((void*)0)) { | |||
62 | diag_t d = match_end_cert_id(ike->sa.st_remote_certs.verified, | |||
63 | &c->spd.that.id /*ID_FROMCERT => updated*/); | |||
64 | if (d == NULL((void*)0)) { | |||
65 | dbg("X509: CERT and ID matches current connection"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("X509: CERT and ID matches current connection" ); } }; | |||
66 | remote_cert_matches_id = true1; | |||
67 | } else { | |||
68 | llog_diag(RC_LOG_SERIOUS, ike->sa.st_logger, &d, "%s", ""); | |||
69 | if (!LIN(POLICY_ALLOW_NO_SAN, c->policy)(((((lset_t)1 << (POLICY_ALLOW_NO_SAN_IX))) & (c-> policy)) == (((lset_t)1 << (POLICY_ALLOW_NO_SAN_IX))))) { | |||
70 | diag_t d = diag("X509: connection failed due to unmatched IKE ID in certificate SAN"); | |||
71 | llog_diag(RC_LOG, ike->sa.st_logger, &d, "%s", ""); | |||
72 | must_switch = true1; | |||
73 | } else { | |||
74 | log_state(RC_LOG, &ike->sa, "X509: connection allows unmatched IKE ID and certificate SAN"); | |||
75 | } | |||
76 | } | |||
77 | } | |||
78 | ||||
79 | /* process any CERTREQ payloads */ | |||
80 | ikev2_decode_cr(md, ike->sa.st_logger); | |||
81 | ||||
82 | /* | |||
83 | * Figure out the authentication, use both what the initiator | |||
84 | * suggested and what the current connection contains. | |||
85 | */ | |||
86 | uint16_t auth = md->chain[ISAKMP_NEXT_v2AUTH]->payload.v2auth.isaa_auth_method; | |||
87 | enum keyword_authby authby = AUTHBY_NEVER; | |||
88 | ||||
89 | switch (auth) { | |||
90 | case IKEv2_AUTH_RSA: | |||
91 | authby = AUTHBY_RSASIG; | |||
92 | break; | |||
93 | case IKEv2_AUTH_PSK: | |||
94 | authby = AUTHBY_PSK; | |||
95 | break; | |||
96 | case IKEv2_AUTH_NULL: | |||
97 | authby = AUTHBY_NULL; | |||
98 | break; | |||
99 | case IKEv2_AUTH_DIGSIG: | |||
100 | if (c->policy & POLICY_RSASIG((lset_t)1 << (POLICY_RSASIG_IX))) { | |||
101 | authby = AUTHBY_RSASIG; | |||
102 | break; | |||
103 | } | |||
104 | if (c->policy & POLICY_ECDSA((lset_t)1 << (POLICY_ECDSA_IX))) { | |||
105 | authby = AUTHBY_ECDSA; | |||
106 | break; | |||
107 | } | |||
108 | /* FALL THROUGH */ | |||
109 | case IKEv2_AUTH_NONE: | |||
110 | default: | |||
111 | dbg("ikev2 skipping refine_host_connection due to unknown policy"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("ikev2 skipping refine_host_connection due to unknown policy" ); } }; | |||
112 | } | |||
113 | ||||
114 | /* | |||
115 | * Now that we've decoded the ID payload, let's see if we | |||
116 | * need to switch connections. | |||
117 | * We must not switch horses if we initiated: | |||
118 | * - if the initiation was explicit, we'd be ignoring user's intent | |||
119 | * - if opportunistic, we'll lose our HOLD info | |||
120 | */ | |||
121 | ||||
122 | if (authby != AUTHBY_NEVER) { | |||
123 | struct connection *r = NULL((void*)0); | |||
124 | id_buf peer_str; | |||
125 | bool_Bool fromcert = peer_id.kind == ID_DER_ASN1_DN; | |||
126 | ||||
127 | if (authby != AUTHBY_NULL) { | |||
128 | r = refine_host_connection_on_responder(&ike->sa, &peer_id, tarzan_id, | |||
129 | LEMPTY((lset_t)0) /* auth_policy */, | |||
130 | authby, &fromcert); | |||
131 | } | |||
132 | ||||
133 | if (r == NULL((void*)0)) { | |||
134 | /* no "improvement" on c found */ | |||
135 | if (DBGP(DBG_BASE)(cur_debugging & (((lset_t)1 << (DBG_BASE_IX))))) { | |||
136 | id_buf peer_str; | |||
137 | DBG_log("no suitable connection for peer '%s'", | |||
138 | str_id(&peer_id, &peer_str)str_id_bytes(&peer_id, jam_raw_bytes, &peer_str)); | |||
139 | } | |||
140 | /* can we continue with what we had? */ | |||
141 | if (must_switch) { | |||
142 | return diag("Peer ID '%s' is not specified on the certificate SubjectAltName (SAN) and no better connection found", | |||
143 | str_id(&peer_id, &peer_str)str_id_bytes(&peer_id, jam_raw_bytes, &peer_str)); | |||
144 | } | |||
145 | /* if X.509, we should have valid peer/san */ | |||
146 | if (ike->sa.st_remote_certs.verified != NULL((void*)0) && !remote_cert_matches_id) { | |||
147 | return diag("`Peer ID '%s' is not specified on the certificate SubjectAltName (SAN) and no better connection found", | |||
148 | str_id(&peer_id, &peer_str)str_id_bytes(&peer_id, jam_raw_bytes, &peer_str)); | |||
149 | } | |||
150 | if (!remote_cert_matches_id && | |||
151 | !same_id(&c->spd.that.id, &peer_id) && | |||
152 | c->spd.that.id.kind != ID_FROMCERT) { | |||
153 | if (LIN(POLICY_AUTH_NULL, c->policy)(((((lset_t)1 << (POLICY_AUTH_NULL_IX))) & (c->policy )) == (((lset_t)1 << (POLICY_AUTH_NULL_IX)))) && | |||
154 | tarzan_id != NULL((void*)0) && tarzan_id->kind == ID_NULL) { | |||
155 | log_state(RC_LOG, &ike->sa, | |||
156 | "Peer ID '%s' expects us to have ID_NULL and connection allows AUTH_NULL - allowing", | |||
157 | str_id(&peer_id, &peer_str)str_id_bytes(&peer_id, jam_raw_bytes, &peer_str)); | |||
158 | ike->sa.st_peer_wants_null = true1; | |||
159 | } else { | |||
160 | id_buf peer_str; | |||
161 | return diag("Peer ID '%s' mismatched on first found connection and no better connection found", | |||
162 | str_id(&peer_id, &peer_str)str_id_bytes(&peer_id, jam_raw_bytes, &peer_str)); | |||
163 | } | |||
164 | } else { | |||
165 | dbg("peer ID matches and no better connection found - continuing with existing connection"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("peer ID matches and no better connection found - continuing with existing connection" ); } }; | |||
166 | } | |||
167 | } else if (r != c) { | |||
168 | /* r is an improvement on c -- replace */ | |||
169 | connection_buf cb, rb; | |||
170 | log_state(RC_LOG, &ike->sa, | |||
171 | "switched from "PRI_CONNECTION"\"%s\"%s"" to "PRI_CONNECTION"\"%s\"%s", | |||
172 | pri_connection(c, &cb)(c)->name, str_connection_instance(c, &cb), | |||
173 | pri_connection(r, &rb)(r)->name, str_connection_instance(r, &rb)); | |||
174 | if (r->kind == CK_TEMPLATE || r->kind == CK_GROUP) { | |||
175 | /* instantiate it, filling in peer's ID */ | |||
176 | r = rw_instantiate(r, &c->spd.that.host_addr, | |||
177 | NULL((void*)0), &peer_id); | |||
178 | } | |||
179 | ||||
180 | update_state_connection(&ike->sa, r); | |||
181 | /* redo from scratch so we read and check CERT payload */ | |||
182 | dbg("retrying ikev2_decode_peer_id_and_certs() with new conn"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("retrying ikev2_decode_peer_id_and_certs() with new conn" ); } }; | |||
183 | return responder_match_initiator_id_counted(ike, peer_id, tarzan_id, md, depth + 1); | |||
184 | } else if (must_switch) { | |||
185 | id_buf peer_str; | |||
186 | return diag("Peer ID '%s' mismatched on first found connection and no better connection found", | |||
187 | str_id(&peer_id, &peer_str)str_id_bytes(&peer_id, jam_raw_bytes, &peer_str)); | |||
188 | } | |||
189 | ||||
190 | if (c->spd.that.has_id_wildcards) { | |||
191 | duplicate_id(&c->spd.that.id, &peer_id); | |||
192 | c->spd.that.has_id_wildcards = false0; | |||
193 | } else if (fromcert) { | |||
194 | dbg("copying ID for fromcert"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("copying ID for fromcert"); } }; | |||
195 | duplicate_id(&c->spd.that.id, &peer_id); | |||
196 | } | |||
197 | } | |||
198 | ||||
199 | dn_buf dnb; | |||
200 | dbg("offered CA: '%s'", str_dn_or_null(c->spd.this.ca, "%none", &dnb)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("offered CA: '%s'", str_dn_or_null(c->spd.this .ca, "%none", &dnb)); } }; | |||
201 | ||||
202 | return NULL((void*)0); | |||
203 | } | |||
204 | ||||
205 | static diag_t decode_v2_peer_id(const char *peer, struct payload_digest *const id_peer, struct id *peer_id) | |||
206 | { | |||
207 | if (id_peer == NULL((void*)0)) { | |||
208 | return diag("authentication failed: %s did not include ID payload", peer); | |||
209 | } | |||
210 | ||||
211 | diag_t d = unpack_peer_id(id_peer->payload.v2id.isai_type /* Peers Id Kind */, | |||
212 | peer_id, &id_peer->pbs); | |||
213 | if (d != NULL((void*)0)) { | |||
214 | return diag_diag(&d, "authentication failed: %s ID payload invalid: ", peer); | |||
215 | } | |||
216 | ||||
217 | id_buf idb; | |||
218 | esb_buf esb; | |||
219 | dbg("%s ID is %s: '%s'", peer,{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s ID is %s: '%s'", peer, enum_show(&ike_id_type_names , peer_id->kind, &esb), str_id_bytes(peer_id, jam_raw_bytes , &idb)); } } | |||
220 | enum_show(&ike_id_type_names, peer_id->kind, &esb),{ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s ID is %s: '%s'", peer, enum_show(&ike_id_type_names , peer_id->kind, &esb), str_id_bytes(peer_id, jam_raw_bytes , &idb)); } } | |||
221 | str_id(peer_id, &idb)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("%s ID is %s: '%s'", peer, enum_show(&ike_id_type_names , peer_id->kind, &esb), str_id_bytes(peer_id, jam_raw_bytes , &idb)); } }; | |||
222 | ||||
223 | return NULL((void*)0); | |||
224 | } | |||
225 | ||||
226 | diag_t ikev2_responder_decode_initiator_id(struct ike_sa *ike, struct msg_digest *md) | |||
227 | { | |||
228 | passert(ike->sa.st_sa_role == SA_RESPONDER)({ _Bool assertion__ = ike->sa.st_sa_role == SA_RESPONDER; if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2_peer_id.c" , .line = 228, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_passert(logger_, here, "%s", "ike->sa.st_sa_role == SA_RESPONDER" ); } (void) 1; }); | |||
229 | ||||
230 | struct id initiator_id; | |||
231 | diag_t d = decode_v2_peer_id("initiator", md->chain[ISAKMP_NEXT_v2IDi], &initiator_id); | |||
232 | if (d != NULL((void*)0)) { | |||
233 | return d; | |||
234 | } | |||
235 | ||||
236 | /* You Tarzan, me Jane? */ | |||
237 | struct id tarzan_id; /* may be unset */ | |||
238 | struct id *tip = NULL((void*)0); /* tarzan ID pointer (or NULL) */ | |||
239 | { | |||
240 | const struct payload_digest *const tarzan_pld = md->chain[ISAKMP_NEXT_v2IDr]; | |||
241 | ||||
242 | if (tarzan_pld != NULL((void*)0)) { | |||
243 | dbg("received IDr payload - extracting our alleged ID"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("received IDr payload - extracting our alleged ID" ); } }; | |||
244 | diag_t d = unpack_peer_id(tarzan_pld->payload.v2id.isai_type, | |||
245 | &tarzan_id, &tarzan_pld->pbs); | |||
246 | if (d != NULL((void*)0)) { | |||
247 | return diag_diag(&d, "IDr payload extraction failed: "); | |||
248 | } | |||
249 | tip = &tarzan_id; | |||
250 | } | |||
251 | } | |||
252 | ||||
253 | return responder_match_initiator_id_counted(ike, initiator_id, tip, md, 0); | |||
254 | } | |||
255 | ||||
256 | diag_t ikev2_initiator_decode_responder_id(struct ike_sa *ike, struct msg_digest *md) | |||
257 | { | |||
258 | passert(ike->sa.st_sa_role == SA_INITIATOR)({ _Bool assertion__ = ike->sa.st_sa_role == SA_INITIATOR; if (!assertion__) { where_t here = ({ static const struct where here = { .func = __func__, .file = "programs/pluto/ikev2_peer_id.c" , .line = 258, }; &here; }); const struct logger *logger_ = &failsafe_logger; llog_passert(logger_, here, "%s", "ike->sa.st_sa_role == SA_INITIATOR" ); } (void) 1; }); | |||
| ||||
259 | ||||
260 | struct id responder_id; | |||
261 | diag_t d = decode_v2_peer_id("responder", md->chain[ISAKMP_NEXT_v2IDr], &responder_id); | |||
262 | if (d != NULL((void*)0)) { | |||
263 | return d; | |||
264 | } | |||
265 | ||||
266 | /* start considering connection */ | |||
267 | ||||
268 | struct connection *c = ike->sa.st_connection; | |||
269 | ||||
270 | /* | |||
271 | * If there are certs, try running the id check. | |||
272 | */ | |||
273 | bool_Bool remote_cert_matches_id = false0; | |||
274 | if (ike->sa.st_remote_certs.verified != NULL((void*)0)) { | |||
275 | diag_t d = match_end_cert_id(ike->sa.st_remote_certs.verified, | |||
276 | &c->spd.that.id /*ID_FROMCERT => updated*/); | |||
277 | if (d == NULL((void*)0)) { | |||
278 | dbg("X509: CERT and ID matches current connection"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("X509: CERT and ID matches current connection" ); } }; | |||
279 | remote_cert_matches_id = true1; | |||
280 | } else if (!LIN(POLICY_ALLOW_NO_SAN, c->policy)(((((lset_t)1 << (POLICY_ALLOW_NO_SAN_IX))) & (c-> policy)) == (((lset_t)1 << (POLICY_ALLOW_NO_SAN_IX))))) { | |||
281 | return diag_diag(&d, "X509: authentication failed; "); | |||
282 | } else { | |||
283 | llog_diag(RC_LOG_SERIOUS, ike->sa.st_logger, &d, "%s", ""); | |||
284 | log_state(RC_LOG, &ike->sa, "X509: connection allows unmatched IKE ID and certificate SAN"); | |||
285 | } | |||
286 | } | |||
287 | ||||
288 | /* process any CERTREQ payloads */ | |||
289 | ikev2_decode_cr(md, ike->sa.st_logger); | |||
290 | ||||
291 | /* | |||
292 | * Now that we've decoded the ID payload, let's see if we | |||
293 | * need to switch connections. | |||
294 | * We must not switch horses if we initiated: | |||
295 | * - if the initiation was explicit, we'd be ignoring user's intent | |||
296 | * - if opportunistic, we'll lose our HOLD info | |||
297 | */ | |||
298 | if (!remote_cert_matches_id
| |||
299 | !same_id(&c->spd.that.id, &responder_id) && | |||
300 | c->spd.that.id.kind != ID_FROMCERT) { | |||
301 | id_buf expect, found; | |||
302 | return diag("we require IKEv2 peer to have ID '%s', but peer declares '%s'", | |||
303 | str_id(&c->spd.that.id, &expect)str_id_bytes(&c->spd.that.id, jam_raw_bytes, &expect ), | |||
304 | str_id(&responder_id, &found)str_id_bytes(&responder_id, jam_raw_bytes, &found)); | |||
305 | } | |||
306 | ||||
307 | if (c->spd.that.id.kind == ID_FROMCERT) { | |||
308 | if (responder_id.kind != ID_DER_ASN1_DN) { | |||
| ||||
309 | return diag("peer ID is not a certificate type"); | |||
310 | } | |||
311 | duplicate_id(&c->spd.that.id, &responder_id); | |||
312 | } | |||
313 | ||||
314 | dn_buf dnb; | |||
315 | dbg("offered CA: '%s'", str_dn_or_null(c->spd.this.ca, "%none", &dnb)){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX) )))) { DBG_log("offered CA: '%s'", str_dn_or_null(c->spd.this .ca, "%none", &dnb)); } }; | |||
316 | ||||
317 | return NULL((void*)0); | |||
318 | } |