Bug Summary

File:programs/pluto/ikev2_peer_id.c
Warning:line 308, column 25
The left operand of '!=' is a garbage value

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ikev2_peer_id.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/build/quick-libreswan-2/programs/pluto -resource-dir /usr/lib64/clang/13.0.0 -D TimeZoneOffset=timezone -D PIE -D NSS_IPSEC_PROFILE -D XFRM_LIFETIME_DEFAULT=30 -D USE_IKEv1 -D XFRM_SUPPORT -D USE_XFRM_INTERFACE -D USE_DNSSEC -D DEFAULT_DNSSEC_ROOTKEY_FILE="/var/lib/unbound/root.key" -D HAVE_LABELED_IPSEC -D HAVE_SECCOMP -D LIBCURL -D USE_LINUX_AUDIT -D HAVE_NM -D USE_PAM_AUTH -D USE_3DES -D USE_AES -D USE_CAMELLIA -D USE_CHACHA -D USE_DH31 -D USE_MD5 -D USE_SHA1 -D USE_SHA2 -D USE_PRF_AES_XCBC -D USE_NSS_KDF -D DEFAULT_RUNDIR="/run/pluto" -D IPSEC_CONF="/etc/ipsec.conf" -D IPSEC_CONFDDIR="/etc/ipsec.d" -D IPSEC_NSSDIR="/var/lib/ipsec/nss" -D IPSEC_CONFDIR="/etc" -D IPSEC_EXECDIR="/usr/local/libexec/ipsec" -D IPSEC_SBINDIR="/usr/local/sbin" -D IPSEC_VARDIR="/var" -D POLICYGROUPSDIR="/etc/ipsec.d/policies" -D IPSEC_SECRETS_FILE="/etc/ipsec.secrets" -D FORCE_PR_ASSERT -D USE_FORK=1 -D USE_VFORK=0 -D USE_DAEMON=0 -D USE_PTHREAD_SETSCHEDPRIO=1 -D GCC_LINT -D HAVE_LIBCAP_NG -I . -I ../../OBJ.linux.x86_64/programs/pluto -I ../../include -I /usr/include/nss3 -I /usr/include/nspr4 -I /home/build/quick-libreswan-2/programs/pluto/linux-copy -D HERE_FILENAME="programs/pluto/ikev2_peer_id.c" -internal-isystem /usr/lib64/clang/13.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/11/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -std=gnu99 -fdebug-compilation-dir=/home/build/quick-libreswan-2/programs/pluto -ferror-limit 19 -stack-protector 3 -fgnuc-version=4.2.1 -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-01-01-205714-1273399-1 -x c /home/build/quick-libreswan-2/programs/pluto/ikev2_peer_id.c
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
41static 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
205static 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)) {
4
Assuming 'id_peer' is equal to NULL
5
Taking true branch
208 return diag("authentication failed: %s did not include ID payload", peer);
6
Returning without writing to 'peer_id->kind'
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
226diag_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
256diag_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; })
;
1
Assuming field 'st_sa_role' is equal to SA_INITIATOR
2
Taking false branch
259
260 struct id responder_id;
261 diag_t d = decode_v2_peer_id("responder", md->chain[ISAKMP_NEXT_v2IDr], &responder_id);
3
Calling 'decode_v2_peer_id'
7
Returning from 'decode_v2_peer_id'
262 if (d != NULL((void*)0)) {
8
Assuming 'd' is equal to NULL
9
Taking false branch
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)) {
10
Assuming field 'verified' is equal to NULL
11
Taking false branch
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
11.1
'remote_cert_matches_id' is false
&&
299 !same_id(&c->spd.that.id, &responder_id) &&
12
Assuming the condition is false
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) {
13
Assuming field 'kind' is equal to ID_FROMCERT
14
Taking true branch
308 if (responder_id.kind != ID_DER_ASN1_DN) {
15
The left operand of '!=' is a garbage value
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}