Add support for IKEv2 OCSP extensions (RFC 4806)
Closes strongswan/strongswan#2016 Co-authored-by: Tobias Brunner <[email protected]>
This commit is contained in:
committed by
Tobias Brunner
co-authored by
Tobias Brunner
parent
ddd926b698
commit
15612b3a42
@@ -250,6 +250,11 @@ enum ike_condition_t {
|
||||
* All authentication rounds have been completed successfully
|
||||
*/
|
||||
COND_AUTHENTICATED = (1<<14),
|
||||
|
||||
/**
|
||||
* An OCSP status request was received
|
||||
*/
|
||||
COND_OCSP_REQUEST = (1<<15),
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -215,6 +215,66 @@ static void add_attribute_certs(private_ike_cert_post_t *this,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build CERT payload with OCSP status for the given cert
|
||||
*/
|
||||
static cert_payload_t *build_cert_ocsp_payload(certificate_t *cert,
|
||||
certificate_t *issuer)
|
||||
{
|
||||
certificate_t *response;
|
||||
cert_payload_t *payload;
|
||||
|
||||
response = lib->credmgr->get_ocsp(lib->credmgr, cert, issuer);
|
||||
if (!response)
|
||||
{
|
||||
DBG2(DBG_IKE, "no OCSP status for certificate \"%Y\"",
|
||||
cert->get_subject(cert));
|
||||
return NULL;
|
||||
}
|
||||
payload = cert_payload_create_from_cert(PLV2_CERTIFICATE, response);
|
||||
response->destroy(response);
|
||||
return payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add subject certificate and intermediate CA certificates OCSP status to message
|
||||
*/
|
||||
static void add_cert_ocsp(private_ike_cert_post_t *this, auth_cfg_t *auth,
|
||||
message_t *message)
|
||||
{
|
||||
auth_rule_t type;
|
||||
cert_payload_t *payload;
|
||||
certificate_t *cert, *issuer;
|
||||
enumerator_t *enumerator;
|
||||
|
||||
cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
|
||||
if (!cert)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
enumerator = auth->create_enumerator(auth);
|
||||
while (enumerator->enumerate(enumerator, &type, &issuer))
|
||||
{
|
||||
if (type == AUTH_RULE_CA_CERT || type == AUTH_RULE_IM_CERT)
|
||||
{
|
||||
payload = build_cert_ocsp_payload(cert, issuer);
|
||||
if (payload)
|
||||
{
|
||||
DBG1(DBG_IKE, "sending OCSP status for certificate \"%Y\"",
|
||||
cert->get_subject(cert));
|
||||
message->add_payload(message, (payload_t*)payload);
|
||||
}
|
||||
if (type == AUTH_RULE_CA_CERT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
cert = issuer;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* add certificates to message
|
||||
*/
|
||||
@@ -250,6 +310,23 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message)
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (peer_cfg->get_ocsp_policy(peer_cfg))
|
||||
{
|
||||
case OCSP_SEND_NEVER:
|
||||
case OCSP_SEND_REQUEST:
|
||||
break;
|
||||
case OCSP_SEND_REPLY:
|
||||
case OCSP_SEND_BOTH:
|
||||
if (this->ike_sa->has_condition(this->ike_sa, COND_OCSP_REQUEST) &&
|
||||
!this->ike_sa->has_condition(this->ike_sa,
|
||||
COND_ONLINE_VALIDATION_SUSPENDED))
|
||||
{
|
||||
auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE);
|
||||
add_cert_ocsp(this, auth, message);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(task_t, build_i, status_t,
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "ike_cert_pre.h"
|
||||
|
||||
#include <daemon.h>
|
||||
@@ -59,9 +61,51 @@ static void process_certreq(private_ike_cert_pre_t *this,
|
||||
certreq_payload_t *certreq, auth_cfg_t *auth)
|
||||
{
|
||||
enumerator_t *enumerator;
|
||||
u_int unknown = 0;
|
||||
u_int unknown = 0, known = 0;
|
||||
chunk_t keyid;
|
||||
|
||||
if (certreq->get_cert_type(certreq) == CERT_X509_OCSP_REQUEST)
|
||||
{
|
||||
this->ike_sa->set_condition(this->ike_sa, COND_OCSP_REQUEST, TRUE);
|
||||
|
||||
enumerator = certreq->create_keyid_enumerator(certreq);
|
||||
while (enumerator->enumerate(enumerator, &keyid))
|
||||
{
|
||||
identification_t *id;
|
||||
certificate_t *cert;
|
||||
|
||||
id = identification_create_from_encoding(ID_KEY_ID, keyid);
|
||||
cert = lib->credmgr->get_cert(lib->credmgr,
|
||||
CERT_X509, KEY_ANY, id, TRUE);
|
||||
if (cert)
|
||||
{
|
||||
DBG1(DBG_IKE, "received OCSP cert request claiming trust "
|
||||
"for \"%Y\"", cert->get_subject(cert));
|
||||
cert->destroy(cert);
|
||||
known++;
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG2(DBG_IKE, "received OCSP cert request claiming trust for "
|
||||
"unknown certificate with keyid %Y", id);
|
||||
unknown++;
|
||||
}
|
||||
id->destroy(id);
|
||||
|
||||
}
|
||||
if (unknown)
|
||||
{
|
||||
DBG1(DBG_IKE, "received OCSP cert request with %u unknown trusted "
|
||||
"certificates", unknown);
|
||||
}
|
||||
else if (!known)
|
||||
{
|
||||
DBG1(DBG_IKE, "received empty OCSP cert request");
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
return;
|
||||
}
|
||||
|
||||
this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE);
|
||||
|
||||
if (certreq->get_cert_type(certreq) != CERT_X509)
|
||||
@@ -255,6 +299,30 @@ static void process_crl(cert_payload_t *payload, auth_cfg_t *auth)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an OCSP certificate payload
|
||||
*/
|
||||
static void process_ocsp(cert_payload_t *payload, auth_cfg_t *auth,
|
||||
ike_cfg_t *ike_cfg)
|
||||
{
|
||||
certificate_t *cert;
|
||||
|
||||
if (!ike_cfg->send_ocsp_certreq(ike_cfg))
|
||||
{
|
||||
DBG1(DBG_IKE, "received OCSP response, but we didn't request any, "
|
||||
"ignore");
|
||||
return;
|
||||
}
|
||||
|
||||
cert = payload->get_cert(payload);
|
||||
if (cert)
|
||||
{
|
||||
DBG1(DBG_IKE, "received OCSP response issued by \"%Y\"",
|
||||
cert->get_issuer(cert));
|
||||
auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an attribute certificate payload
|
||||
*/
|
||||
@@ -318,6 +386,10 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message)
|
||||
case ENC_CRL:
|
||||
process_crl(cert_payload, auth);
|
||||
break;
|
||||
case ENC_OCSP_CONTENT:
|
||||
process_ocsp(cert_payload, auth,
|
||||
this->ike_sa->get_ike_cfg(this->ike_sa));
|
||||
break;
|
||||
case ENC_X509_ATTRIBUTE:
|
||||
process_ac(cert_payload, auth);
|
||||
break;
|
||||
@@ -329,7 +401,6 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message)
|
||||
case ENC_SPKI:
|
||||
case ENC_RAW_RSA_KEY:
|
||||
case ENC_X509_HASH_AND_URL_BUNDLE:
|
||||
case ENC_OCSP_CONTENT:
|
||||
default:
|
||||
DBG1(DBG_ENC, "certificate encoding %N not supported",
|
||||
cert_encoding_names, encoding);
|
||||
@@ -403,6 +474,36 @@ static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth)
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
/**
|
||||
* add the keyid of a self-signed OCSP signer to the certificate request payload
|
||||
*/
|
||||
static void add_certreq_ocsp(certreq_payload_t *req, certificate_t *cert)
|
||||
{
|
||||
public_key_t *public;
|
||||
chunk_t keyid;
|
||||
x509_t *x509 = (x509_t*)cert;
|
||||
|
||||
if (cert->get_type(cert) != CERT_X509 ||
|
||||
!(x509->get_flags(x509) & X509_OCSP_SIGNER &&
|
||||
x509->get_flags(x509) & X509_SELF_SIGNED))
|
||||
{
|
||||
/* no self-signed OCSP-signer cert, skip */
|
||||
return;
|
||||
}
|
||||
public = cert->get_public_key(cert);
|
||||
if (!public)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid))
|
||||
{
|
||||
req->add_keyid(req, keyid);
|
||||
DBG1(DBG_IKE, "sending OCSP cert request with self-signed "
|
||||
"OCSP-signer \"%Y\"", cert->get_subject(cert));
|
||||
}
|
||||
public->destroy(public);
|
||||
}
|
||||
|
||||
/**
|
||||
* build certificate requests
|
||||
*/
|
||||
@@ -416,46 +517,59 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message)
|
||||
certreq_payload_t *req = NULL;
|
||||
|
||||
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
||||
if (!ike_cfg->send_certreq(ike_cfg))
|
||||
if (ike_cfg->send_certreq(ike_cfg))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* check if we require a specific CA for that peer */
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
if (peer_cfg)
|
||||
{
|
||||
enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
|
||||
while (enumerator->enumerate(enumerator, &auth))
|
||||
/* check if we require a specific CA for that peer */
|
||||
peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa);
|
||||
if (peer_cfg)
|
||||
{
|
||||
add_certreqs(&req, auth);
|
||||
enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE);
|
||||
while (enumerator->enumerate(enumerator, &auth))
|
||||
{
|
||||
add_certreqs(&req, auth);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
if (!req)
|
||||
{
|
||||
/* otherwise add all trusted CA certificates */
|
||||
enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
|
||||
CERT_ANY, KEY_ANY, NULL, TRUE);
|
||||
while (enumerator->enumerate(enumerator, &cert))
|
||||
{
|
||||
add_certreq(&req, cert);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
if (req)
|
||||
{
|
||||
message->add_payload(message, (payload_t*)req);
|
||||
|
||||
if (lib->settings->get_bool(lib->settings,
|
||||
"%s.hash_and_url", FALSE, lib->ns))
|
||||
{
|
||||
message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED,
|
||||
chunk_empty);
|
||||
this->do_http_lookup = TRUE;
|
||||
}
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
if (!req)
|
||||
if (ike_cfg->send_ocsp_certreq(ike_cfg))
|
||||
{
|
||||
/* otherwise add all trusted CA certificates */
|
||||
req = certreq_payload_create_type(CERT_X509_OCSP_REQUEST);
|
||||
|
||||
enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
|
||||
CERT_ANY, KEY_ANY, NULL, TRUE);
|
||||
while (enumerator->enumerate(enumerator, &cert))
|
||||
{
|
||||
add_certreq(&req, cert);
|
||||
add_certreq_ocsp(req, cert);
|
||||
}
|
||||
enumerator->destroy(enumerator);
|
||||
}
|
||||
|
||||
if (req)
|
||||
{
|
||||
message->add_payload(message, (payload_t*)req);
|
||||
|
||||
if (lib->settings->get_bool(lib->settings,
|
||||
"%s.hash_and_url", FALSE, lib->ns))
|
||||
{
|
||||
message->add_notify(message, FALSE, HTTP_CERT_LOOKUP_SUPPORTED,
|
||||
chunk_empty);
|
||||
this->do_http_lookup = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user