Bug Summary

File:lib/libswan/proposals.c
Warning:line 427, column 24
Value stored to 'ps' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name proposals.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 -mrelocation-model pic -pic-level 2 -pic-is-pie -mthread-model posix -mdisable-fp-elim -relaxed-aliasing -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib64/clang/8.0.0 -D TimeZoneOffset=timezone -D linux -D PIE -D NSS_IPSEC_PROFILE -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 USE_SYSTEMD_WATCHDOG -D HAVE_NM -D XAUTH_HAVE_PAM -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 DEFAULT_RUNDIR="/run/pluto" -D IPSEC_CONF="/etc/ipsec.conf" -D IPSEC_CONFDDIR="/etc/ipsec.d" -D IPSEC_NSSDIR="/etc/ipsec.d" -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/lib/libswan -I ../../include -I /usr/include/nss3 -I /usr/include/nspr4 -D HERE_BASENAME="proposals.c" -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/8.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-missing-field-initializers -std=gnu99 -fdebug-compilation-dir /home/build/libreswan/lib/libswan -ferror-limit 19 -fmessage-length 0 -stack-protector 3 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -o /tmp/scan-build-2020-09-09-193337-25440-1 -x c /home/build/libreswan/lib/libswan/proposals.c -faddrsig
1/*
2 * Algorithm info parsing and creation functions
3 * Author: JuanJo Ciarlante <jjo-ipsec@mendoza.gov.ar>
4 *
5 * Copyright (C) 2012 Paul Wouters <paul@libreswan.org>
6 * Copyright (C) 2015-2020 Andrew Cagney <cagney@gnu.org>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <https://www.gnu.org/licenses/gpl2.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19#include <stdio.h>
20#include <string.h>
21#include <limits.h>
22
23#include "lswlog.h"
24#include "lswalloc.h"
25#include "constants.h"
26#include "proposals.h"
27#include "ike_alg.h"
28#include "ike_alg_integ.h"
29#include "ike_alg_dh.h"
30#include "alg_byname.h"
31
32struct proposal {
33 /*
34 * The algorithm entries.
35 */
36 struct algorithm *algorithms[PROPOSAL_ALGORITHM_ROOF];
37 /*
38 * Which protocol is this proposal intended for?
39 */
40 const struct proposal_protocol *protocol;
41 struct proposal *next;
42};
43
44struct proposals {
45 bool_Bool defaulted;
46 int ref_cnt;
47 struct proposal *proposals;
48};
49
50struct proposal_parser *alloc_proposal_parser(const struct proposal_policy *policy,
51 const struct proposal_protocol *protocol)
52{
53 struct proposal_parser *parser = alloc_thing(struct proposal_parser, "parser")((struct proposal_parser*) alloc_bytes(sizeof(struct proposal_parser
), ("parser")))
;
54 parser->policy = policy;
55 parser->protocol = protocol;
56 parser->error[0] = '\0';
57 return parser;
58}
59
60void free_proposal_parser(struct proposal_parser **parser)
61{
62 pfree(*parser);
63 *parser = NULL((void*)0);
64}
65
66bool_Bool proposal_encrypt_aead(const struct proposal *proposal)
67{
68 if (proposal->algorithms[PROPOSAL_encrypt] == NULL((void*)0)) {
69 return false0;
70 }
71 FOR_EACH_ALGORITHM(proposal, encrypt, alg)for (struct algorithm *alg = next_algorithm(proposal, PROPOSAL_encrypt
, ((void*)0)); alg != ((void*)0); alg = next_algorithm(proposal
, PROPOSAL_encrypt, alg))
{
72 const struct encrypt_desc *encrypt = encrypt_desc(alg->desc);
73 if (!encrypt_desc_is_aead(encrypt)) {
74 return false0;
75 }
76 }
77 return true1;
78}
79
80bool_Bool proposal_encrypt_norm(const struct proposal *proposal)
81{
82 if (proposal->algorithms[PROPOSAL_encrypt] == NULL((void*)0)) {
83 return false0;
84 }
85 FOR_EACH_ALGORITHM(proposal, encrypt, alg)for (struct algorithm *alg = next_algorithm(proposal, PROPOSAL_encrypt
, ((void*)0)); alg != ((void*)0); alg = next_algorithm(proposal
, PROPOSAL_encrypt, alg))
{
86 const struct encrypt_desc *encrypt = encrypt_desc(alg->desc);
87 if (encrypt_desc_is_aead(encrypt)) {
88 return false0;
89 }
90 }
91 return true1;
92}
93
94bool_Bool proposal_integ_none(const struct proposal *proposal)
95{
96 /* interpret NULL as NONE */
97 FOR_EACH_ALGORITHM(proposal, integ, alg)for (struct algorithm *alg = next_algorithm(proposal, PROPOSAL_integ
, ((void*)0)); alg != ((void*)0); alg = next_algorithm(proposal
, PROPOSAL_integ, alg))
{
98 const struct integ_desc *integ = integ_desc(alg->desc);
99 if (integ != &ike_alg_integ_none) {
100 return false0;
101 }
102 }
103 return true1;
104}
105
106bool_Bool proposal_aead_none_ok(struct proposal_parser *parser,
107 const struct proposal *proposal)
108{
109 if (impair.allow_null_none) {
110 return true1;
111 }
112
113 if (proposal->algorithms[PROPOSAL_encrypt] == NULL((void*)0)) {
114 return true1;
115 }
116
117 /* are any and all encrypt algorithms AEAD? */
118 bool_Bool aead = proposal_encrypt_aead(proposal);
119 bool_Bool norm = proposal_encrypt_norm(proposal);
120
121 if (!aead && !norm) {
122 proposal_error(parser, "AEAD and non-AEAD %s encryption algorithm cannot be combined",
123 proposal->protocol->name);
124 return false0;
125 }
126
127 /* are any and all integ algorithms NONE? */
128 bool_Bool none = proposal_integ_none(proposal);
129
130 if (aead && !none) {
131 const struct ike_alg *encrypt = proposal->algorithms[PROPOSAL_encrypt]->desc;
132 /*
133 * At least one of the integrity algorithms wasn't
134 * NONE. For instance, esp=aes_gcm-sha1" is invalid.
135 */
136 proposal_error(parser, "AEAD %s encryption algorithm %s must have 'NONE' as the integrity algorithm",
137 proposal->protocol->name,
138 encrypt->fqn);
139 return false0;
140 }
141
142 if (norm && none) {
143 const struct ike_alg *encrypt = proposal->algorithms[PROPOSAL_encrypt]->desc;
144 /*
145 * Not AEAD and either there was no integrity
146 * algorithm (implying NONE) or at least one integrity
147 * algorithm was NONE. For instance,
148 * esp=aes_cbc-none" is invalid.
149 */
150 proposal_error(parser, "non-AEAD %s encryption algorithm %s cannot have 'NONE' as the integrity algorithm",
151 proposal->protocol->name,
152 encrypt->fqn);
153 return false0;
154 }
155
156 return true1;
157}
158
159
160/*
161 * proposals struct can be shared by several connections instances,
162 * handle free() with ref_cnts.
163 */
164
165void proposals_addref(struct proposals **proposals)
166{
167 if ((*proposals) != NULL((void*)0)) {
168 (*proposals)->ref_cnt++;
169 }
170}
171
172void proposals_delref(struct proposals **proposals)
173{
174 if ((*proposals) != NULL((void*)0)) {
175 if ((*proposals)->ref_cnt == 0) {
176 free_proposal(&(*proposals)->proposals);
177 pfree((*proposals));
178 } else {
179 (*proposals)->ref_cnt--;
180 }
181 *proposals = NULL((void*)0);
182 }
183}
184struct proposal *next_proposal(const struct proposals *proposals,
185 struct proposal *last)
186{
187 if (last == NULL((void*)0)) {
188 return proposals->proposals;
189 } else {
190 return last->next;
191 }
192}
193
194unsigned nr_proposals(struct proposals *proposals)
195{
196 unsigned nr = 0;
197 FOR_EACH_PROPOSAL(proposals, proposal)for (struct proposal *proposal = next_proposal(proposals, ((void
*)0)); proposal != ((void*)0); proposal = next_proposal(proposals
, proposal))
{
198 nr++;
199 }
200 return nr;
201}
202
203void append_proposal(struct proposals *proposals, struct proposal **proposal)
204{
205 struct proposal **end = &proposals->proposals;
206 /* check for duplicates */
207 while ((*end) != NULL((void*)0)) {
208 bool_Bool same = true1;
209 for (enum proposal_algorithm pa = 0;
210 same && pa < PROPOSAL_ALGORITHM_ROOF; pa++) {
211 struct algorithm *old = (*end)->algorithms[pa];
212 struct algorithm *new = (*proposal)->algorithms[pa];
213 while (same) {
214 if (new == NULL((void*)0) && old == NULL((void*)0)) {
215 break;
216 }
217 if (new == NULL((void*)0) || old == NULL((void*)0)) {
218 same = false0;
219 break;
220 }
221 if (new->desc != old->desc) {
222 same = false0;
223 break;
224 }
225 /*
226 * If list already contains encryption
227 * with ENCKEYLEN=0 then new is a
228 * duplicate as 0 generates all keys.
229 * Ignore reverse vis aes128,aes.
230 */
231 if (old->desc->algo_type == IKE_ALG_ENCRYPT&ike_alg_encrypt &&
232 (old->enckeylen != 0 &&
233 new->enckeylen != old->enckeylen)) {
234 same = false0;
235 break;
236 }
237 new = new->next;
238 old = old->next;
239 }
240 }
241 if (same) {
242 dbg("discarding duplicate proposal"){ if ((cur_debugging & (((lset_t)1 << (DBG_BASE_IX)
)))) { DBG_log("discarding duplicate proposal"); } }
;
243 free_proposal(proposal);
244 return;
245 }
246 end = &(*end)->next;
247 }
248 *end = *proposal;
249 *proposal = NULL((void*)0);
250}
251
252struct v1_proposal v1_proposal(const struct proposal *proposal)
253{
254 struct v1_proposal v1 = {
255 .protocol = proposal->protocol,
256#define D(ALG) .ALG = proposal->algorithms[PROPOSAL_##ALG] != NULL((void*)0) ? ALG##_desc(proposal->algorithms[PROPOSAL_##ALG]->desc) : NULL((void*)0)
257 D(encrypt),
258 D(prf),
259 D(integ),
260 D(dh),
261#undef D
262 };
263 v1.enckeylen = proposal->algorithms[PROPOSAL_encrypt] != NULL((void*)0) ? proposal->algorithms[PROPOSAL_encrypt]->enckeylen : 0;
264
265 return v1;
266}
267
268struct algorithm *next_algorithm(const struct proposal *proposal,
269 enum proposal_algorithm algorithm,
270 struct algorithm *last)
271{
272 if (last == NULL((void*)0)) {
273 /*
274 * Hack, there should there a way to index algorithm
275 * types; however the old enum proved very dangerous.
276 */
277 passert(algorithm < elemsof(proposal->algorithms)){ _Bool assertion__ = algorithm < (sizeof(proposal->algorithms
) / sizeof(*(proposal->algorithms))); if (!assertion__) { lsw_passert_fail
((where_t) { .func = __func__, .basename = "proposals.c" , .line
= 277}, "%s", "algorithm < elemsof(proposal->algorithms)"
); } }
;
278 return proposal->algorithms[algorithm];
279 } else {
280 return last->next;
281 }
282}
283
284void free_algorithms(struct proposal *proposal,
285 enum proposal_algorithm algorithm)
286{
287 passert(algorithm < elemsof(proposal->algorithms)){ _Bool assertion__ = algorithm < (sizeof(proposal->algorithms
) / sizeof(*(proposal->algorithms))); if (!assertion__) { lsw_passert_fail
((where_t) { .func = __func__, .basename = "proposals.c" , .line
= 287}, "%s", "algorithm < elemsof(proposal->algorithms)"
); } }
;
288 struct algorithm *alg = proposal->algorithms[algorithm];
289 while (alg != NULL((void*)0)) {
290 struct algorithm *del = alg;
291 alg = alg->next;
292 pfree(del);
293 }
294 proposal->algorithms[algorithm] = NULL((void*)0);
295}
296
297struct proposal *alloc_proposal(struct proposal_parser *parser)
298{
299 struct proposal *proposal = alloc_thing(struct proposal, "proposal")((struct proposal*) alloc_bytes(sizeof(struct proposal), ("proposal"
)))
;
300 proposal->protocol = parser->protocol;
301 return proposal;
302}
303
304void free_proposal(struct proposal **proposals)
305{
306 struct proposal *proposal = *proposals;
307 while (proposal != NULL((void*)0)) {
308 struct proposal *del = proposal;
309 proposal = proposal->next;
310 for (enum proposal_algorithm algorithm = 0;
311 algorithm < PROPOSAL_ALGORITHM_ROOF;
312 algorithm++) {
313 free_algorithms(del, algorithm);
314 }
315 pfree(del);
316 }
317 *proposals = NULL((void*)0);
318}
319
320
321/*
322 * XXX: hack, need to come up with a type safe way of mapping an
323 * ike_alg onto an index.
324 */
325static enum proposal_algorithm ike_to_proposal_algorithm(const struct ike_alg *alg)
326{
327 if (alg->algo_type == IKE_ALG_ENCRYPT&ike_alg_encrypt) {
328 return PROPOSAL_encrypt;
329 } else if (alg->algo_type == IKE_ALG_PRF&ike_alg_prf) {
330 return PROPOSAL_prf;
331 } else if (alg->algo_type == IKE_ALG_INTEG&ike_alg_integ) {
332 return PROPOSAL_integ;
333 } else if (alg->algo_type == IKE_ALG_DH&ike_alg_dh) {
334 return PROPOSAL_dh;
335 } else {
336 PASSERT_FAIL("unexpected algorithm type %s",lsw_passert_fail((where_t) { .func = __func__, .basename = "proposals.c"
, .line = 337}, "unexpected algorithm type %s", ike_alg_type_name
(alg->algo_type))
337 ike_alg_type_name(alg->algo_type))lsw_passert_fail((where_t) { .func = __func__, .basename = "proposals.c"
, .line = 337}, "unexpected algorithm type %s", ike_alg_type_name
(alg->algo_type))
;
338 }
339}
340
341void append_algorithm(struct proposal_parser *parser,
342 struct proposal *proposal,
343 const struct ike_alg *alg,
344 int enckeylen)
345{
346 enum proposal_algorithm algorithm = ike_to_proposal_algorithm(alg);
347 passert(algorithm < elemsof(proposal->algorithms)){ _Bool assertion__ = algorithm < (sizeof(proposal->algorithms
) / sizeof(*(proposal->algorithms))); if (!assertion__) { lsw_passert_fail
((where_t) { .func = __func__, .basename = "proposals.c" , .line
= 347}, "%s", "algorithm < elemsof(proposal->algorithms)"
); } }
;
348 struct algorithm **end = &proposal->algorithms[algorithm];
349 /* find end, and check for duplicates */
350 while ((*end) != NULL((void*)0)) {
351 /*
352 * enckeylen=0 acts as a wildcard
353 */
354 if (alg == (*end)->desc &&
355 (alg->algo_type != IKE_ALG_ENCRYPT&ike_alg_encrypt ||
356 ((*end)->enckeylen == 0 ||
357 enckeylen == (*end)->enckeylen))) {
358 log_message(parser->policy->logger_rc_flags, parser->policy->logger,
359 "discarding duplicate %s %s algorithm %s",
360 parser->protocol->name, ike_alg_type_name(alg->algo_type), alg->fqn);
361 return;
362 }
363 end = &(*end)->next;
364 }
365 struct algorithm new_algorithm = {
366 .desc = alg,
367 .enckeylen = enckeylen,
368 };
369 DBGF(DBG_PROPOSAL_PARSER, "appending %s %s algorithm %s[_%d]",{ if ((cur_debugging & (((lset_t)1 << (DBG_TMI_IX))
))) { DBG_log("appending %s %s algorithm %s[_%d]", parser->
protocol->name, ike_alg_type_name(alg->algo_type), alg->
fqn, enckeylen); } }
370 parser->protocol->name, ike_alg_type_name(alg->algo_type), alg->fqn,{ if ((cur_debugging & (((lset_t)1 << (DBG_TMI_IX))
))) { DBG_log("appending %s %s algorithm %s[_%d]", parser->
protocol->name, ike_alg_type_name(alg->algo_type), alg->
fqn, enckeylen); } }
371 enckeylen){ if ((cur_debugging & (((lset_t)1 << (DBG_TMI_IX))
))) { DBG_log("appending %s %s algorithm %s[_%d]", parser->
protocol->name, ike_alg_type_name(alg->algo_type), alg->
fqn, enckeylen); } }
;
372 *end = clone_thing(new_algorithm, "alg")((__typeof__(&(new_algorithm))) clone_bytes((const void *
)&(new_algorithm), sizeof(new_algorithm), ("alg")))
;
373}
374
375void jam_proposal(struct jambuf *log,
376 const struct proposal *proposal)
377{
378 const char *ps = "";
379
380 const char *as = "";
381
382 as = ps;
383 FOR_EACH_ALGORITHM(proposal, encrypt, alg)for (struct algorithm *alg = next_algorithm(proposal, PROPOSAL_encrypt
, ((void*)0)); alg != ((void*)0); alg = next_algorithm(proposal
, PROPOSAL_encrypt, alg))
{
384 const struct encrypt_desc *encrypt = encrypt_desc(alg->desc);
385 jam_string(log, as); ps = "-"; as = "+";
386 jam_string(log, encrypt->common.fqn);
387 if (alg->enckeylen != 0) {
388 jam(log, "_%d", alg->enckeylen);
389 }
390 }
391
392 as = ps;
393 FOR_EACH_ALGORITHM(proposal, prf, alg)for (struct algorithm *alg = next_algorithm(proposal, PROPOSAL_prf
, ((void*)0)); alg != ((void*)0); alg = next_algorithm(proposal
, PROPOSAL_prf, alg))
{
394 const struct prf_desc *prf = prf_desc(alg->desc);
395 jam_string(log, as); ps = "-"; as = "+";
396 jam_string(log, prf->common.fqn);
397 }
398
399 bool_Bool print_integ = (impair.proposal_parser ||
400 /* no PRF */
401 next_algorithm(proposal, PROPOSAL_prf, NULL((void*)0)) == NULL((void*)0) ||
402 /* AEAD should have NONE */
403 (proposal_encrypt_aead(proposal) && !proposal_integ_none(proposal)));
404 if (!print_integ && proposal_encrypt_norm(proposal)) {
405 /* non-AEAD should have matching PRF and INTEG */
406 for (struct algorithm *integ = next_algorithm(proposal, PROPOSAL_integ, NULL((void*)0)),
407 *prf = next_algorithm(proposal, PROPOSAL_prf, NULL((void*)0));
408 !print_integ && (integ != NULL((void*)0) || prf != NULL((void*)0));
409 integ = next_algorithm(proposal, PROPOSAL_integ, integ),
410 prf = next_algorithm(proposal, PROPOSAL_prf, prf)) {
411 print_integ = (integ == NULL((void*)0) || prf == NULL((void*)0) ||
412 &integ_desc(integ->desc)->prf->common != prf->desc);
413 }
414 }
415 as = ps;
416 if (print_integ) {
417 FOR_EACH_ALGORITHM(proposal, integ, alg)for (struct algorithm *alg = next_algorithm(proposal, PROPOSAL_integ
, ((void*)0)); alg != ((void*)0); alg = next_algorithm(proposal
, PROPOSAL_integ, alg))
{
418 const struct integ_desc *integ = integ_desc(alg->desc);
419 jam_string(log, as); ps = "-"; as = "+";
420 jam_string(log, integ->common.fqn);
421 }
422 }
423
424 as = ps;
425 FOR_EACH_ALGORITHM(proposal, dh, alg)for (struct algorithm *alg = next_algorithm(proposal, PROPOSAL_dh
, ((void*)0)); alg != ((void*)0); alg = next_algorithm(proposal
, PROPOSAL_dh, alg))
{
426 const struct dh_desc *dh = dh_desc(alg->desc);
427 jam_string(log, as); ps = "-"; as = "+";
Value stored to 'ps' is never read
428 jam_string(log, dh->common.fqn);
429 }
430}
431
432void jam_proposals(struct jambuf *log, const struct proposals *proposals)
433{
434 const char *sep = "";
435 FOR_EACH_PROPOSAL(proposals, proposal)for (struct proposal *proposal = next_proposal(proposals, ((void
*)0)); proposal != ((void*)0); proposal = next_proposal(proposals
, proposal))
{
436 jam_string(log, sep);
437 jam_proposal(log, proposal);
438 sep = ", ";
439 }
440}
441
442/*
443 * When PFS=no ignore any DH algorithms, and when PFS=yes reject
444 * mixing implicit and explicit DH.
445 */
446static bool_Bool proposals_pfs_vs_dh_check(struct proposal_parser *parser,
447 struct proposals *proposals)
448{
449 /* scrape the proposals for dh algorithms */
450 const struct proposal *first_null = NULL((void*)0);
451 const struct proposal *first_none = NULL((void*)0);
452 const struct ike_alg *first_dh = NULL((void*)0);
453 const struct ike_alg *second_dh = NULL((void*)0);
454 FOR_EACH_PROPOSAL(proposals, proposal)for (struct proposal *proposal = next_proposal(proposals, ((void
*)0)); proposal != ((void*)0); proposal = next_proposal(proposals
, proposal))
{
455 if (proposal->algorithms[PROPOSAL_dh] == NULL((void*)0)) {
456 if (first_null == NULL((void*)0)) {
457 first_null = proposal;
458 }
459 } else if (proposal->algorithms[PROPOSAL_dh]->desc == &ike_alg_dh_none.common) {
460 if (first_none == NULL((void*)0)) {
461 first_none = proposal;
462 }
463 } else if (first_dh == NULL((void*)0)) {
464 first_dh = proposal->algorithms[PROPOSAL_dh]->desc;
465 } else if (second_dh == NULL((void*)0) &&
466 first_dh != proposal->algorithms[PROPOSAL_dh]->desc) {
467 second_dh = proposal->algorithms[PROPOSAL_dh]->desc;
468 }
469 }
470
471 if (first_dh == NULL((void*)0) && first_none == NULL((void*)0)) {
472 /* no DH is always ok */
473 return true1;
474 }
475
476 /*
477 * Try to generate very specific errors first. For instance,
478 * given PFS=no esp=aes,aes;dh21, an error stating that dh21
479 * is not valid because of PFS is more helpful than an error
480 * saying that all or no proposals need PFS.
481 */
482
483 /*
484 * Since PFS=NO overrides any DH, don't silently ignore it.
485 * Check this early so that a conflict with PFS=no code gets
486 * reported before anything else.
487 */
488 if (!parser->policy->pfs && (first_dh != NULL((void*)0) || first_none != NULL((void*)0))) {
489 FOR_EACH_PROPOSAL(proposals, proposal)for (struct proposal *proposal = next_proposal(proposals, ((void
*)0)); proposal != ((void*)0); proposal = next_proposal(proposals
, proposal))
{
490 const struct ike_alg *dh = NULL((void*)0);
491 if (proposal->algorithms[PROPOSAL_dh] != NULL((void*)0)) {
492 dh = proposal->algorithms[PROPOSAL_dh]->desc;
493 }
494 if (dh == &ike_alg_dh_none.common) {
495 log_message(parser->policy->logger_rc_flags, parser->policy->logger,
496 "ignoring redundant %s DH algorithm NONE as PFS policy is disabled",
497 parser->protocol->name);
498 } else if (dh != NULL((void*)0)) {
499 log_message(parser->policy->logger_rc_flags, parser->policy->logger,
500 "ignoring %s DH algorithm %s as PFS policy is disabled",
501 parser->protocol->name, dh->fqn);
502 }
503 free_algorithms(proposal, PROPOSAL_dh);
504 }
505 return true1;
506 }
507
508 /*
509 * Since at least one proposal included DH, all proposals
510 * should. A proposal without DH is an error.
511 *
512 * (The converse, no proposals including DH was handled right
513 * at the start).
514 */
515 if (first_null != NULL((void*)0)) {
516 /* DH was specified */
517 proposal_error(parser, "either all or no %s proposals should specify DH",
518 parser->protocol->name);
519 if (!impair_proposal_errors(parser)) {
520 return false0;
521 }
522 }
523
524 switch (parser->policy->version) {
525
526 case IKEv1:
527 /*
528 * IKEv1 only allows one DH algorithm.
529 */
530 if (first_dh != NULL((void*)0) && second_dh != NULL((void*)0)) {
531 proposal_error(parser, "more than one IKEv1 %s DH algorithm (%s, %s) is not allowed in quick mode",
532 parser->protocol->name,
533 first_dh->fqn,
534 second_dh->fqn);
535 if (!impair_proposal_errors(parser)) {
536 return false0;
537 }
538 }
539 break;
540
541 case IKEv2:
542 /*
543 * IKEv2, only implements one DH algorithm.
544 */
545 if (first_dh != NULL((void*)0) && second_dh != NULL((void*)0)) {
546 proposal_error(parser, "more than one IKEv2 %s DH algorithm (%s, %s) requires unimplemented CHILD_SA INVALID_KE",
547 parser->protocol->name,
548 first_dh->fqn,
549 second_dh->fqn);
550 if (!impair_proposal_errors(parser)) {
551 return false0;
552 }
553 }
554 break;
555
556 default:
557 /* ignore */
558 break;
559 }
560
561 return true1;
562}
563
564void proposal_error(struct proposal_parser *parser, const char *fmt, ...)
565{
566 va_list ap;
567 va_start(ap, fmt)__builtin_va_start(ap, fmt);
568 vsnprintf(parser->error, sizeof(parser->error), fmt, ap);
569 va_end(ap)__builtin_va_end(ap);
570}
571
572bool_Bool impair_proposal_errors(struct proposal_parser *parser)
573{
574 pexpect(parser->error[0] != '\0')({ _Bool assertion__ = parser->error[0] != '\0'; if (!assertion__
) { log_pexpect((where_t) { .func = __func__, .basename = "proposals.c"
, .line = 574}, "%s", "parser->error[0] != '\\0'"); } assertion__
; })
;
575 if (impair.proposal_parser) {
576 log_message(parser->policy->logger_rc_flags,
577 parser->policy->logger,
578 "IMPAIR: ignoring proposal error: %s",
579 parser->error);
580 parser->error[0] = '\0';
581 return true1;
582 } else {
583 return false0;
584 }
585}
586
587struct proposals *proposals_from_str(struct proposal_parser *parser,
588 const char *str)
589{
590 struct proposals *proposals = alloc_thing(struct proposals, "proposals")((struct proposals*) alloc_bytes(sizeof(struct proposals), ("proposals"
)))
;
591 unsigned parser_version = parser->policy->parser_version;
592 if (parser_version == 0) {
593 parser_version = parser->policy->version;
594 }
595 if (str == NULL((void*)0)) {
596 proposals->defaulted = true1;
597 /* may still be null */
598 str = parser->protocol->defaults[parser->policy->version]->proposals;
599 }
600 bool_Bool ok;
601 switch (parser_version) {
602 case 2: ok = v2_proposals_parse_str(parser, proposals, shunk1(str)); break;
603 default: ok = v1_proposals_parse_str(parser, proposals, shunk1(str)); break;
604 }
605 if (!ok) {
606 proposals_delref(&proposals);
607 return NULL((void*)0);
608 }
609 if (proposals->proposals == NULL((void*)0)) {
610 proposals_delref(&proposals);
611 return NULL((void*)0);
612 }
613 if (parser->policy->check_pfs_vs_dh &&
614 !proposals_pfs_vs_dh_check(parser, proposals)) {
615 pexpect(parser->error[0] != '\0')({ _Bool assertion__ = parser->error[0] != '\0'; if (!assertion__
) { log_pexpect((where_t) { .func = __func__, .basename = "proposals.c"
, .line = 615}, "%s", "parser->error[0] != '\\0'"); } assertion__
; })
;
616 proposals_delref(&proposals);
617 return NULL((void*)0);
618 }
619 return proposals;
620}
621
622bool_Bool default_proposals(struct proposals *proposals)
623{
624 return proposals == NULL((void*)0) || proposals->defaulted;
625}
626
627/*
628 * Try to parse any of <ealg>-<ekeylen>, <ealg>_<ekeylen>,
629 * <ealg><ekeylen>, or <ealg> using some look-ahead.
630 */
631
632static int parse_proposal_eklen(struct proposal_parser *parser, shunk_t print, shunk_t buf)
633{
634 /* convert -<eklen> if present */
635 char *end = NULL((void*)0);
636 long eklen = strtol(buf.ptr, &end, 10);
637 if (buf.ptr + buf.len != end) {
638 proposal_error(parser, "%s encryption algorithm '"PRI_SHUNK"%.*s""' key length contains a non-numeric character",
639 parser->protocol->name,
640 pri_shunk(print)((int) (print).len), (const char *) ((print).ptr));
641 return 0;
642 }
643 if (eklen >= INT_MAX2147483647) {
644 proposal_error(parser, "%s encryption algorithm '"PRI_SHUNK"%.*s""' key length WAY too big",
645 parser->protocol->name,
646 pri_shunk(print)((int) (print).len), (const char *) ((print).ptr));
647 return 0;
648 }
649 if (eklen == 0) {
650 proposal_error(parser, "%s encryption key length is zero",
651 parser->protocol->name);
652 return 0;
653 }
654 return eklen;
655}
656
657bool_Bool proposal_parse_encrypt(struct proposal_parser *parser,
658 struct proposal_tokenizer *tokens,
659 const struct ike_alg **encrypt,
660 int *encrypt_keylen)
661{
662 if (tokens->this.len == 0) {
663 return false0;
664 }
665
666 /*
667 * Does it match <ealg>-<eklen>?
668 *
669 * Use the tokens NEXT lookahead to check <eklen> first. If
670 * it starts with a digit then just assume <ealg>-<ealg> and
671 * error out if it is not so.
672 */
673 if (tokens->this_term == '-' &&
674 tokens->next.len > 0 &&
675 hunk_char_isdigit(tokens->next, 0)({ unsigned char c_ = ({ const typeof(tokens->next) hunk_ =
tokens->next; size_t index_ = 0; const char *string_ = hunk_
.ptr; index_ < hunk_.len ? string_[0] : '\0'; }); ((*__ctype_b_loc
())[(int) ((c_))] & (unsigned short int) _ISdigit); })
) {
676 /* assume <ealg>-<eklen> */
677 shunk_t ealg = tokens->this;
678 shunk_t eklen = tokens->next;
679 /* print "<ealg>-<eklen>" in errors */
680 shunk_t print = shunk2(ealg.ptr, eklen.ptr + eklen.len - ealg.ptr);
681 int enckeylen = parse_proposal_eklen(parser, print, eklen);
682 if (enckeylen <= 0) {
683 pexpect(parser->error[0] != '\0')({ _Bool assertion__ = parser->error[0] != '\0'; if (!assertion__
) { log_pexpect((where_t) { .func = __func__, .basename = "proposals.c"
, .line = 683}, "%s", "parser->error[0] != '\\0'"); } assertion__
; })
;
684 return false0;
685 }
686 const struct ike_alg *alg = encrypt_alg_byname(parser, ealg,
687 enckeylen, print);
688 if (alg == NULL((void*)0)) {
689 DBGF(DBG_PROPOSAL_PARSER, "<ealg>byname('"PRI_SHUNK"') with <eklen>='"PRI_SHUNK"' failed: %s",{ if ((cur_debugging & (((lset_t)1 << (DBG_TMI_IX))
))) { DBG_log("<ealg>byname('""%.*s""') with <eklen>='"
"%.*s""' failed: %s", ((int) (ealg).len), (const char *) ((ealg
).ptr), ((int) (eklen).len), (const char *) ((eklen).ptr), parser
->error); } }
690 pri_shunk(ealg), pri_shunk(eklen), parser->error){ if ((cur_debugging & (((lset_t)1 << (DBG_TMI_IX))
))) { DBG_log("<ealg>byname('""%.*s""') with <eklen>='"
"%.*s""' failed: %s", ((int) (ealg).len), (const char *) ((ealg
).ptr), ((int) (eklen).len), (const char *) ((eklen).ptr), parser
->error); } }
;
691 return false0;
692 }
693 /* consume <ealg>-<eklen> */
694 proposal_next_token(tokens);
695 proposal_next_token(tokens);
696 // append_algorithm(parser, proposal, alg, enckeylen);
697 *encrypt = alg; *encrypt_keylen = enckeylen;
698 return true1;
699 }
700
701 /*
702 * Does it match <ealg> (without any _<eklen> suffix?)
703 */
704 const shunk_t print = tokens->this;
705 shunk_t ealg = tokens->this;
706 const struct ike_alg *alg = encrypt_alg_byname(parser, ealg,
707 0/*enckeylen*/, print);
708 if (alg != NULL((void*)0)) {
709 /* consume <ealg> */
710 proposal_next_token(tokens);
711 // append_algorithm(parser, proposal, alg, 0/*enckeylen*/);
712 *encrypt = alg; *encrypt_keylen = 0;
713 return true1;
714 }
715 /* buffer still contains error from <ealg> lookup */
716 pexpect(parser->error[0] != '\0')({ _Bool assertion__ = parser->error[0] != '\0'; if (!assertion__
) { log_pexpect((where_t) { .func = __func__, .basename = "proposals.c"
, .line = 716}, "%s", "parser->error[0] != '\\0'"); } assertion__
; })
;
717
718
719 /*
720 * See if there's a trailing <eklen> in <ealg>. If there
721 * isn't then the lookup error above can be returned.
722 */
723 size_t end = ealg.len;
724 while (end > 0 && hunk_char_isdigit(ealg, end-1)({ unsigned char c_ = ({ const typeof(ealg) hunk_ = ealg; size_t
index_ = end-1; const char *string_ = hunk_.ptr; index_ <
hunk_.len ? string_[end-1] : '\0'; }); ((*__ctype_b_loc ())[
(int) ((c_))] & (unsigned short int) _ISdigit); })
) {
725 end--;
726 }
727 if (end == ealg.len) {
728 /*
729 * no trailing <eklen> digits and <ealg> was rejected
730 * by above); error still contains message from not
731 * finding just <ealg>.
732 */
733 passert(parser->error[0] != '\0'){ _Bool assertion__ = parser->error[0] != '\0'; if (!assertion__
) { lsw_passert_fail((where_t) { .func = __func__, .basename =
"proposals.c" , .line = 733}, "%s", "parser->error[0] != '\\0'"
); } }
;
734 return false0; // warning_or_false(parser, "encryption", print);
735 }
736
737 /*
738 * Try parsing the <eklen> found in <ealg>. For something
739 * like aes_gcm_16, above lookup should have found the
740 * algorithm so isn't a problem here.
741 */
742 shunk_t eklen = shunk_slice(ealg, end, ealg.len);
743 int enckeylen = parse_proposal_eklen(parser, print, eklen);
744 if (enckeylen <= 0) {
745 pexpect(parser->error[0] != '\0')({ _Bool assertion__ = parser->error[0] != '\0'; if (!assertion__
) { log_pexpect((where_t) { .func = __func__, .basename = "proposals.c"
, .line = 745}, "%s", "parser->error[0] != '\\0'"); } assertion__
; })
;
746 return false0;
747 }
748
749 /*
750 * The <eklen> in <ealg><eklen> or <ealg>_<eklen> parsed; trim
751 * <eklen> from <ealg> and then try the lookup.
752 */
753 ealg = shunk_slice(ealg, 0, end);
754 if (hunk_char_ischar(ealg, ealg.len-1, "_")({ unsigned char c_ = ({ const typeof(ealg) hunk_ = ealg; size_t
index_ = ealg.len-1; const char *string_ = hunk_.ptr; index_
< hunk_.len ? string_[ealg.len-1] : '\0'; }); strchr("_",
c_); })
) {
755 ealg = shunk_slice(ealg, 0, end-1);
756 }
757 parser->error[0] = '\0'; /* zap old error */
758 alg = encrypt_alg_byname(parser, ealg, enckeylen, print);
759 if (alg == NULL((void*)0)) {
760 pexpect(parser->error[0] != '\0')({ _Bool assertion__ = parser->error[0] != '\0'; if (!assertion__
) { log_pexpect((where_t) { .func = __func__, .basename = "proposals.c"
, .line = 760}, "%s", "parser->error[0] != '\\0'"); } assertion__
; })
;
761 return false0; // warning_or_false(parser, "encryption", print);
762 }
763
764 /* consume <ealg> */
765 proposal_next_token(tokens);
766 // append_algorithm(parser, proposal, alg, enckeylen);
767 *encrypt = alg; *encrypt_keylen = enckeylen;
768 return true1;
769}
770
771struct proposal_tokenizer proposal_first_token(shunk_t input, const char *delims)
772{
773 struct proposal_tokenizer token = {
774 .input = input,
775 .delims = delims,
776 };
777 /* parse next */
778 proposal_next_token(&token);
779 /* next<-this; parse next */
780 proposal_next_token(&token);
781 return token;
782}
783
784void proposal_next_token(struct proposal_tokenizer *tokens)
785{
786 /* shuffle terminators */
787 tokens->prev_term = tokens->this_term;
788 tokens->this_term = tokens->next_term;
789 /* shuffle tokens */
790 tokens->this = tokens->next;
791 tokens->next = shunk_token(&tokens->input, &tokens->next_term, tokens->delims);
792 if (DBGP(DBG_PROPOSAL_PARSER)(cur_debugging & (((lset_t)1 << (DBG_TMI_IX))))) {
793 JAMBUF(buf)for (char lswbuf[((size_t)1024)], *lswbuf_ = lswbuf; lswbuf_ !=
((void*)0); lswbuf_ = ((void*)0)) for (struct jambuf jambuf =
array_as_jambuf((lswbuf), sizeof(lswbuf)), *buf = &jambuf
; buf != ((void*)0); buf = ((void*)0))
{
794 jam(buf, "token: ");
795 if (tokens->prev_term != '\0') {
796 jam(buf, "'%c'", tokens->prev_term);
797 } else {
798 jam(buf, "''");
799 }
800 jam(buf, " ");
801 if (tokens->this.ptr == NULL((void*)0)) {
802 jam(buf, "<null>");
803 } else {
804 jam(buf, "\""PRI_SHUNK"%.*s""\"", pri_shunk(tokens->this)((int) (tokens->this).len), (const char *) ((tokens->this
).ptr)
);
805 }
806 jam(buf, " ");
807 if (tokens->this_term != '\0') {
808 jam(buf, "'%c'", tokens->this_term);
809 } else {
810 jam(buf, "''");
811 }
812 jam(buf, " ");
813 if (tokens->this.ptr == NULL((void*)0)) {
814 jam(buf, "<null>");
815 } else {
816 jam(buf, "\""PRI_SHUNK"%.*s""\"", pri_shunk(tokens->this)((int) (tokens->this).len), (const char *) ((tokens->this
).ptr)
);
817 }
818 jam(buf, " ");
819 if (tokens->next_term != '\0') {
820 jam(buf, "'%c'", tokens->next_term);
821 } else {
822 jam(buf, "''");
823 }
824 jambuf_to_debug_stream(buf); /* XXX: grrr */
825 }
826 }
827}