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
|
/* Process the IKEv2 CERT payload (offline), 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 "demux.h"
#include "state.h"
#include "pluto_x509.h"
#include "server_pool.h"
#include "cert_decode_helper.h"
#include "pluto_stats.h"
#include "id.h"
#include "nss_cert_verify.h"
#include "connections.h"
#include "fetch.h"
#include "root_certs.h"
#include "x509.h"
#include "crl_queue.h"
#include "log.h"
/*
* Just decode a cert payload.
*/
struct task {
/* input */
struct msg_digest *md; /* counted reference */
struct payload_digest *cert_payloads; /* ref into md */
cert_decode_cb *cb;
struct id id;
struct rev_opts rev_opts;
enum ike_version ike_version;
struct root_certs *root_certs; /* counted reference */
/* output */
struct verified_certs verified;
};
static task_computer_fn cert_decode_computer; /* type check */
static task_completed_cb cert_decode_completed; /* type check */
static task_cleanup_cb cert_decode_cleanup; /* type check */
struct task_handler cert_decode_handler = {
.name = "decode certificate payload",
.computer_fn = cert_decode_computer,
.completed_cb = cert_decode_completed,
.cleanup_cb = cert_decode_cleanup,
};
void submit_v2_cert_decode(struct ike_sa *ike,
struct msg_digest *md, struct payload_digest *cert_payloads,
cert_decode_cb *cb, where_t where)
{
struct task task = {
.root_certs = root_certs_addref(&global_logger),
.md = md_addref(md),
.cert_payloads = cert_payloads,
.cb = cb,
.ike_version = ike->sa.st_ike_version,
.id = ike->sa.st_connection->remote->host.id, /* XXX: safe? */
.rev_opts = {
.ocsp = ocsp_enable,
.ocsp_strict = ocsp_strict,
.ocsp_post = ocsp_post,
.crl_strict = crl_strict,
},
};
submit_task(/*callback*/&ike->sa, /*task*/&ike->sa, md,
/*detach_whack*/false,
clone_thing(task, "decode certificate payload task"),
&cert_decode_handler, where);
}
static void cert_decode_computer(struct logger *logger,
struct task *task,
int my_thread UNUSED)
{
task->verified = find_and_verify_certs(logger, task->ike_version,
task->cert_payloads, &task->rev_opts,
task->root_certs, &task->id);
}
static stf_status cert_decode_completed(struct state *st,
struct msg_digest *md,
struct task *task)
{
struct ike_sa *ike = ike_sa(st, HERE);
pexpect(!ike->sa.st_remote_certs.processed);
ike->sa.st_remote_certs.processed = true;
ike->sa.st_remote_certs.harmless = task->verified.harmless;
/* if there's an error, log it */
#if defined(LIBCURL) || defined(LIBLDAP)
if (task->verified.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 (and
* crl_update_needed is left unset).
*
* Trigger a refresh.
*/
chunk_t fdn = empty_chunk;
if (find_crl_fetch_dn(&fdn, ike->sa.st_connection)) {
submit_crl_fetch_request(ASN1(fdn), ike->sa.logger);
}
pexpect(task->verified.cert_chain == NULL);
pexpect(task->verified.pubkey_db == NULL);
}
#endif
/*
* transfer certs and db to state (might be NULL).
*/
pexpect(st->st_remote_certs.verified == NULL);
ike->sa.st_remote_certs.verified = task->verified.cert_chain;
ike->sa.st_remote_certs.groundhog = task->verified.groundhog;
task->verified.cert_chain = NULL;
pexpect(ike->sa.st_remote_certs.pubkey_db == NULL);
ike->sa.st_remote_certs.pubkey_db = task->verified.pubkey_db;
task->verified.pubkey_db = NULL;
/*
* Log failure, and for the initiator possibly fail.
*
* The strange logging order is largely to keep expected test
* output happy. See decode_certs().
*/
if (task->verified.harmless) {
if (ike->sa.st_remote_certs.verified != NULL) {
CERTCertificate *end_cert = ike->sa.st_remote_certs.verified->cert;
passert(end_cert != NULL);
dbg("certificate verified OK: %s", end_cert->subjectName);
}
} else {
pexpect(ike->sa.st_remote_certs.verified == NULL);
pexpect(ike->sa.st_remote_certs.pubkey_db == NULL);
/* NSS: already logged details */
llog_sa(RC_LOG, ike, "X509: certificate payload rejected for this connection");
if (ike->sa.st_sa_role == SA_INITIATOR) {
/*
* One of the certs was bad; no point switching
* initiator.
*/
pstat_sa_failed(&ike->sa, REASON_AUTH_FAILED);
return STF_FATAL;
}
/*
* The 'end-cert' was bad so all the certs have been
* tossed. However, since this is the responder
* stumble on. There might be a connection that still
* authenticates (after a switch?).
*/
}
return task->cb(st, md);
}
static void cert_decode_cleanup(struct task **task)
{
release_certs(&(*task)->verified.cert_chain); /* may be NULL */
free_public_keys(&(*task)->verified.pubkey_db); /* may be NULL */
md_delref(&(*task)->md);
root_certs_delref(&(*task)->root_certs, GLOBAL_LOGGER);
pfreeany((*task));
}
|