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 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
|
/* Support of X.509 certificates and CRLs 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,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 "asn1.h"
#include "crypt_hash.h"
#include "ike_alg_hash.h"
#include "defs.h"
#include "ikev2_certreq.h"
#include "demux.h"
#include "state.h"
#include "connections.h"
#include "log.h"
#include "iface.h"
#include "pluto_x509.h"
/*
* https://www.rfc-editor.org/rfc/rfc4945#section-3.2.6
*
* When in-band exchange of certificate keying materials is desired,
* implementations MUST inform the peer of this by sending at least one
* CERTREQ. In other words, an implementation that does not send any
* CERTREQs during an exchange SHOULD NOT expect to receive any CERT
* payloads.
*
* i.e., the absence of CERTREQ is a hint to not send certs
*
* https://datatracker.ietf.org/doc/html/rfc7296#section-3.7
* 3.7. Certificate Request Payload
*
* The Certificate Encoding field has the same values as those
* defined in Section 3.6. The Certification Authority field
* contains an indicator of trusted authorities for this certificate
* type. The Certification Authority value is a concatenated list
* of SHA-1 hashes of the public keys of trusted Certification
* Authorities (CAs). Each is encoded as the SHA-1 hash of the
* Subject Public Key Info element (see Section 4.1.2.7 of [PKIX])
* from each Trust Anchor certificate. The 20-octet hashes are
* concatenated and included with no other formatting.
*
* The code below hashes the .derPublicKey field; correct?
*/
void process_v2CERTREQ_payload(struct ike_sa *ike, struct msg_digest *md)
{
/* XXX: there should only be one! */
struct payload_digest *p = md->chain[ISAKMP_NEXT_v2CERTREQ];
if (p == NULL) {
ldbg_sa(ike, "no CERTREQ");
return;
}
if (p->next != NULL) {
ldbg_sa(ike, "ignoring duplicate CERTREQ");
/* stumble on */
}
const struct ikev2_certreq *const cr = &p->payload.v2certreq;
switch (cr->isacertreq_enc) {
case CERT_X509_SIGNATURE:
{
struct pbs_in pbs = p->pbs;
unsigned count = 0;
/*
* https://www.rfc-editor.org/rfc/rfc4945#section-3.2.7.2
* 3.2.7.2. Empty Certification Authority Field
*
* i.e., during IKE_SA_INIT, the responder has no clue
* as to the initiator's true identity and hence no
* clue as to which cert chain to ask for. As a
* work-around allow empty CERTREQ payloads.
*/
while (pbs_in_left(&pbs).len > 0) {
ckaid_t hash = { .len = SHA1_DIGEST_SIZE, /*see RFC*/};
diag_t d = pbs_in_bytes(&pbs, hash.ptr, hash.len,
"Certification Authority hash");
if (d != NULL) {
llog(RC_LOG, ike->sa.logger, "ignoring CERTREQ payload: %s", str_diag(d));
pfree_diag(&d);
return;
}
count++;
}
ldbg_sa(ike, "found %d CERTREQ Certification Authority hashes", count);
/* both are non-zero */
ike->sa.st_v2_ike_seen_certreq = (count == 0 ? SEEN_EMPTY_v2CERTREQ : SEEN_FULL_v2CERTREQ);
break;
}
default:
{
enum_buf b;
llog_sa(RC_LOG, ike,
"ignoring CERTREQ payload of unsupported type %s",
str_enum(&ikev2_cert_type_names, cr->isacertreq_enc, &b));
}
}
}
/*
* Compute and emit the hash for the given CA
*/
static bool emit_v2CERTREQ_ca_hash(struct pbs_out *cr_pbs,
CERTCertificate *cert)
{
unsigned char sighash[SHA1_DIGEST_SIZE];
zero(&sighash);
/*
* XXX: RFC requires that SHA-1 is used, regardless of the
* system's crypto policy. Since crypt_hash*() uses the
* low-leve PK11*() interface it should be ok.
*/
struct crypt_hash *ctx = crypt_hash_init("SHA-1 of Certificate Public Key",
&ike_alg_hash_sha1,
cr_pbs->logger);
crypt_hash_digest_bytes(ctx, "pubkey",
cert->derPublicKey.data,
cert->derPublicKey.len);
crypt_hash_final_bytes(&ctx, sighash, sizeof(sighash));
pexpect(ctx == NULL);
if (!pbs_out_thing(cr_pbs, sighash, "Certification Authority hash")) {
return false;
}
return true;
}
static bool emit_v2CERTREQ_header(struct pbs_out *outs, enum ike_cert_type type,
struct pbs_out *cr_pbs)
{
struct ikev2_certreq cr_hd = {
.isacertreq_critical = ISAKMP_PAYLOAD_NONCRITICAL,
.isacertreq_enc = type,
};
/* build CR header */
if (!out_struct(&cr_hd, &ikev2_certificate_req_desc, outs, cr_pbs)) {
return false;
}
return true;
}
static bool emit_v2CERTREQ_ca(struct pbs_out *cr_pbs, chunk_t ca)
{
/*
* This call is fast and cheap.
*
* CERT_GetDefaultCertDB() just returns the contents of a
* static variable set by NSS_Initialize(). It doesn't check
* the value and doesn't set PR error. Short of calling
* CERT_SetDefaultCertDB(NULL), the value can never be NULL.
*/
CERTCertDBHandle *handle = CERT_GetDefaultCertDB();
passert(handle != NULL);
/*
* The Certificate Encoding field has the same values as those
* defined in Section 3.6. The Certification Authority field
* contains an indicator of trusted authorities for this
* certificate type. The Certification Authority value is a
* concatenated list of SHA-1 hashes of the public keys of
* trusted Certification Authorities (CAs). Each is encoded
* as the SHA-1 hash of the Subject Public Key Info element
* (see section 4.1.2.7 of [PKIX]) from each Trust Anchor
* certificate. The 20-octet hashes are concatenated and
* included with no other formatting.
*/
SECItem caname = same_shunk_as_dercert_secitem(ASN1(ca));
CERTCertificate *cacert = CERT_FindCertByName(handle, &caname); /* must unref */
if (cacert == NULL) {
LDBGP_JAMBUF(DBG_BASE, cr_pbs->logger, buf) {
jam(buf, "NSS: locating CA cert \'");
jam_dn(buf, ASN1(ca), jam_sanitized_bytes);
jam(buf, "\' for CERTREQ using CERT_FindCertByName() failed: ");
jam_nss_error_code(buf, PR_GetError());
}
return true;
}
if (!CERT_IsCACert(cacert, NULL)) {
dbg("located CA cert %s for CERTREQ is not a CA", cacert->subjectName);
CERT_DestroyCertificate(cacert);
return true;
}
if (!emit_v2CERTREQ_ca_hash(cr_pbs, cacert)) {
CERT_DestroyCertificate(cacert);
return false;
}
return true;
}
stf_status emit_v2CERTREQ(const struct ike_sa *ike,
struct pbs_out *outpbs)
{
struct pbs_out cr_pbs;
if (!emit_v2CERTREQ_header(outpbs, CERT_X509_SIGNATURE, &cr_pbs)) {
/* already logged */
return STF_INTERNAL_ERROR; /*fatal*/
}
if (is_permanent(ike->sa.st_connection)) {
dbg("connection->kind is CK_PERMANENT so send (possibly empty) CERTREQ");
chunk_t ca = ike->sa.st_connection->remote->host.config->ca;
if (ca.len > 0) {
if (!emit_v2CERTREQ_ca(&cr_pbs, ca)) {
/* already logged */
return STF_INTERNAL_ERROR; /*fatal*/
}
}
} else {
dbg("connection->kind is not CK_PERMANENT (instance), so collect CAs");
ip_address local_address = ike->sa.st_iface_endpoint->ip_dev->local_address;
generalName_t *gn = collect_rw_ca_candidates(local_address, IKEv2);
if (gn != NULL) {
dbg("connection is RW, lookup CA candidates");
for (generalName_t *ca = gn; ca != NULL; ca = ca->next) {
if (!emit_v2CERTREQ_ca(&cr_pbs, ca->name)) {
free_generalNames(gn, false);
return STF_INTERNAL_ERROR; /*fatal*/
}
}
free_generalNames(gn, false);
} else {
dbg("not a roadwarrior instance, sending empty CA in CERTREQ");
}
}
close_output_pbs(&cr_pbs);
return STF_OK;
}
bool need_v2CERTREQ_in_IKE_SA_INIT_response(const struct ike_sa *ike)
{
struct authby authby = ike->sa.st_connection->remote->host.config->authby;
return (authby_has_digsig(authby) && !remote_has_preloaded_pubkey(ike));
}
bool need_v2CERTREQ_in_IKE_AUTH_request(const struct ike_sa *ike)
{
dbg("IKEv2 CERTREQ: send a cert request?");
const struct connection *c = ike->sa.st_connection;
if (!authby_has_digsig(c->remote->host.config->authby)) {
dbg("IKEv2 CERTREQ: responder has no auth method requiring them to send back their cert");
return false;
}
if (remote_has_preloaded_pubkey(ike)) {
dbg("IKEv2 CERTREQ: public key already known");
return false;
}
if (c->remote->host.config->ca.ptr == NULL ||
c->remote->host.config->ca.len < 1) {
dbg("IKEv2 CERTREQ: no CA DN known to send");
return false;
}
dbg("IKEv2 CERTREQ: OK to send a certificate request");
return true;
}
|