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
@@ -96,6 +96,11 @@ struct private_ike_cfg_t {
|
|||||||
*/
|
*/
|
||||||
bool certreq;
|
bool certreq;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* should we send an OCSP status request?
|
||||||
|
*/
|
||||||
|
bool ocsp_certreq;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enforce UDP encapsulation
|
* enforce UDP encapsulation
|
||||||
*/
|
*/
|
||||||
@@ -134,6 +139,12 @@ METHOD(ike_cfg_t, send_certreq, bool,
|
|||||||
return this->certreq;
|
return this->certreq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(ike_cfg_t, send_ocsp_certreq, bool,
|
||||||
|
private_ike_cfg_t *this)
|
||||||
|
{
|
||||||
|
return this->ocsp_certreq;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(ike_cfg_t, force_encap_, bool,
|
METHOD(ike_cfg_t, force_encap_, bool,
|
||||||
private_ike_cfg_t *this)
|
private_ike_cfg_t *this)
|
||||||
{
|
{
|
||||||
@@ -388,6 +399,7 @@ METHOD(ike_cfg_t, equals, bool,
|
|||||||
return
|
return
|
||||||
this->version == other->version &&
|
this->version == other->version &&
|
||||||
this->certreq == other->certreq &&
|
this->certreq == other->certreq &&
|
||||||
|
this->ocsp_certreq == other->ocsp_certreq &&
|
||||||
this->force_encap == other->force_encap &&
|
this->force_encap == other->force_encap &&
|
||||||
this->fragmentation == other->fragmentation &&
|
this->fragmentation == other->fragmentation &&
|
||||||
this->childless == other->childless &&
|
this->childless == other->childless &&
|
||||||
@@ -587,6 +599,7 @@ ike_cfg_t *ike_cfg_create(ike_cfg_create_t *data)
|
|||||||
.public = {
|
.public = {
|
||||||
.get_version = _get_version,
|
.get_version = _get_version,
|
||||||
.send_certreq = _send_certreq,
|
.send_certreq = _send_certreq,
|
||||||
|
.send_ocsp_certreq = _send_ocsp_certreq,
|
||||||
.force_encap = _force_encap_,
|
.force_encap = _force_encap_,
|
||||||
.fragmentation = _fragmentation,
|
.fragmentation = _fragmentation,
|
||||||
.childless = _childless,
|
.childless = _childless,
|
||||||
@@ -611,6 +624,7 @@ ike_cfg_t *ike_cfg_create(ike_cfg_create_t *data)
|
|||||||
.refcount = 1,
|
.refcount = 1,
|
||||||
.version = data->version,
|
.version = data->version,
|
||||||
.certreq = !data->no_certreq,
|
.certreq = !data->no_certreq,
|
||||||
|
.ocsp_certreq = !data->no_ocsp_certreq,
|
||||||
.force_encap = data->force_encap,
|
.force_encap = data->force_encap,
|
||||||
.fragmentation = data->fragmentation,
|
.fragmentation = data->fragmentation,
|
||||||
.childless = data->childless,
|
.childless = data->childless,
|
||||||
|
|||||||
@@ -210,6 +210,13 @@ struct ike_cfg_t {
|
|||||||
*/
|
*/
|
||||||
bool (*send_certreq) (ike_cfg_t *this);
|
bool (*send_certreq) (ike_cfg_t *this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should we send an OCSP status request in IKE_SA_INIT?
|
||||||
|
*
|
||||||
|
* @return OCSP status request sending policy
|
||||||
|
*/
|
||||||
|
bool (*send_ocsp_certreq) (ike_cfg_t *this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enforce UDP encapsulation by faking NATD notifies?
|
* Enforce UDP encapsulation by faking NATD notifies?
|
||||||
*
|
*
|
||||||
@@ -288,6 +295,8 @@ struct ike_cfg_create_t {
|
|||||||
uint16_t remote_port;
|
uint16_t remote_port;
|
||||||
/** TRUE to not send any certificate requests */
|
/** TRUE to not send any certificate requests */
|
||||||
bool no_certreq;
|
bool no_certreq;
|
||||||
|
/** TRUE to not send OCSP status requests */
|
||||||
|
bool no_ocsp_certreq;
|
||||||
/** Enforce UDP encapsulation by faking NATD notify */
|
/** Enforce UDP encapsulation by faking NATD notify */
|
||||||
bool force_encap;
|
bool force_encap;
|
||||||
/** Use IKE fragmentation */
|
/** Use IKE fragmentation */
|
||||||
|
|||||||
@@ -32,6 +32,13 @@ ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND,
|
|||||||
"CERT_NEVER_SEND",
|
"CERT_NEVER_SEND",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ENUM(ocsp_policy_names, OCSP_SEND_BOTH, OCSP_SEND_NEVER,
|
||||||
|
"OCSP_SEND_BOTH",
|
||||||
|
"OCSP_SEND_REPLY",
|
||||||
|
"OCSP_SEND_REQUEST",
|
||||||
|
"OCSP_SEND_NEVER",
|
||||||
|
);
|
||||||
|
|
||||||
ENUM(unique_policy_names, UNIQUE_NEVER, UNIQUE_KEEP,
|
ENUM(unique_policy_names, UNIQUE_NEVER, UNIQUE_KEEP,
|
||||||
"UNIQUE_NEVER",
|
"UNIQUE_NEVER",
|
||||||
"UNIQUE_NO",
|
"UNIQUE_NO",
|
||||||
@@ -81,6 +88,11 @@ struct private_peer_cfg_t {
|
|||||||
*/
|
*/
|
||||||
cert_policy_t cert_policy;
|
cert_policy_t cert_policy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* should we send OCSP status request/response
|
||||||
|
*/
|
||||||
|
ocsp_policy_t ocsp_policy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* uniqueness of an IKE_SA
|
* uniqueness of an IKE_SA
|
||||||
*/
|
*/
|
||||||
@@ -495,6 +507,12 @@ METHOD(peer_cfg_t, get_cert_policy, cert_policy_t,
|
|||||||
return this->cert_policy;
|
return this->cert_policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(peer_cfg_t, get_ocsp_policy, ocsp_policy_t,
|
||||||
|
private_peer_cfg_t *this)
|
||||||
|
{
|
||||||
|
return this->ocsp_policy;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(peer_cfg_t, get_unique_policy, unique_policy_t,
|
METHOD(peer_cfg_t, get_unique_policy, unique_policy_t,
|
||||||
private_peer_cfg_t *this)
|
private_peer_cfg_t *this)
|
||||||
{
|
{
|
||||||
@@ -741,6 +759,7 @@ METHOD(peer_cfg_t, equals, bool,
|
|||||||
return (
|
return (
|
||||||
get_ike_version(this) == get_ike_version(other) &&
|
get_ike_version(this) == get_ike_version(other) &&
|
||||||
this->cert_policy == other->cert_policy &&
|
this->cert_policy == other->cert_policy &&
|
||||||
|
this->ocsp_policy == other->ocsp_policy &&
|
||||||
this->unique == other->unique &&
|
this->unique == other->unique &&
|
||||||
this->keyingtries == other->keyingtries &&
|
this->keyingtries == other->keyingtries &&
|
||||||
this->use_mobike == other->use_mobike &&
|
this->use_mobike == other->use_mobike &&
|
||||||
@@ -828,6 +847,7 @@ peer_cfg_t *peer_cfg_create(char *name, ike_cfg_t *ike_cfg,
|
|||||||
.create_child_cfg_enumerator = _create_child_cfg_enumerator,
|
.create_child_cfg_enumerator = _create_child_cfg_enumerator,
|
||||||
.select_child_cfg = _select_child_cfg,
|
.select_child_cfg = _select_child_cfg,
|
||||||
.get_cert_policy = _get_cert_policy,
|
.get_cert_policy = _get_cert_policy,
|
||||||
|
.get_ocsp_policy = _get_ocsp_policy,
|
||||||
.get_unique_policy = _get_unique_policy,
|
.get_unique_policy = _get_unique_policy,
|
||||||
.get_keyingtries = _get_keyingtries,
|
.get_keyingtries = _get_keyingtries,
|
||||||
.get_rekey_time = _get_rekey_time,
|
.get_rekey_time = _get_rekey_time,
|
||||||
@@ -861,6 +881,7 @@ peer_cfg_t *peer_cfg_create(char *name, ike_cfg_t *ike_cfg,
|
|||||||
.child_cfgs = linked_list_create(),
|
.child_cfgs = linked_list_create(),
|
||||||
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
|
.lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
|
||||||
.cert_policy = data->cert_policy,
|
.cert_policy = data->cert_policy,
|
||||||
|
.ocsp_policy = data->ocsp_policy,
|
||||||
.unique = data->unique,
|
.unique = data->unique,
|
||||||
.keyingtries = data->keyingtries,
|
.keyingtries = data->keyingtries,
|
||||||
.rekey_time = data->rekey_time,
|
.rekey_time = data->rekey_time,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#define PEER_CFG_H_
|
#define PEER_CFG_H_
|
||||||
|
|
||||||
typedef enum cert_policy_t cert_policy_t;
|
typedef enum cert_policy_t cert_policy_t;
|
||||||
|
typedef enum ocsp_policy_t ocsp_policy_t;
|
||||||
typedef enum unique_policy_t unique_policy_t;
|
typedef enum unique_policy_t unique_policy_t;
|
||||||
typedef struct peer_cfg_t peer_cfg_t;
|
typedef struct peer_cfg_t peer_cfg_t;
|
||||||
typedef struct peer_cfg_create_t peer_cfg_create_t;
|
typedef struct peer_cfg_create_t peer_cfg_create_t;
|
||||||
@@ -61,6 +62,25 @@ enum cert_policy_t {
|
|||||||
*/
|
*/
|
||||||
extern enum_name_t *cert_policy_names;
|
extern enum_name_t *cert_policy_names;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OCSP status request/response sending policy.
|
||||||
|
*/
|
||||||
|
enum ocsp_policy_t {
|
||||||
|
/** request OCSP status and reply to OCSP status requests */
|
||||||
|
OCSP_SEND_BOTH = 0,
|
||||||
|
/** send OCSP status upon OCSP status request */
|
||||||
|
OCSP_SEND_REPLY = 1,
|
||||||
|
/** send OCSP status request */
|
||||||
|
OCSP_SEND_REQUEST = 2,
|
||||||
|
/** never send OCSP status request or response */
|
||||||
|
OCSP_SEND_NEVER = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* enum strings for ocsp_policy_t
|
||||||
|
*/
|
||||||
|
extern enum_name_t *ocsp_policy_names;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uniqueness of an IKE_SA, used to drop multiple connections with one peer.
|
* Uniqueness of an IKE_SA, used to drop multiple connections with one peer.
|
||||||
*/
|
*/
|
||||||
@@ -213,6 +233,13 @@ struct peer_cfg_t {
|
|||||||
*/
|
*/
|
||||||
cert_policy_t (*get_cert_policy) (peer_cfg_t *this);
|
cert_policy_t (*get_cert_policy) (peer_cfg_t *this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should an OCSP status request/response be sent for this connection?
|
||||||
|
*
|
||||||
|
* @return OCSP sending policy
|
||||||
|
*/
|
||||||
|
ocsp_policy_t (*get_ocsp_policy) (peer_cfg_t *this);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How to handle uniqueness of IKE_SAs?
|
* How to handle uniqueness of IKE_SAs?
|
||||||
*
|
*
|
||||||
@@ -397,6 +424,8 @@ struct peer_cfg_t {
|
|||||||
struct peer_cfg_create_t {
|
struct peer_cfg_create_t {
|
||||||
/** Whether to send a certificate payload */
|
/** Whether to send a certificate payload */
|
||||||
cert_policy_t cert_policy;
|
cert_policy_t cert_policy;
|
||||||
|
/** Whether to send OCSP status request/response */
|
||||||
|
ocsp_policy_t ocsp_policy;
|
||||||
/** Uniqueness of an IKE_SA */
|
/** Uniqueness of an IKE_SA */
|
||||||
unique_policy_t unique;
|
unique_policy_t unique;
|
||||||
/** How many keying tries should be done before giving up */
|
/** How many keying tries should be done before giving up */
|
||||||
|
|||||||
@@ -230,6 +230,9 @@ METHOD(cert_payload_t, get_cert, certificate_t*,
|
|||||||
case ENC_CRL:
|
case ENC_CRL:
|
||||||
type = CERT_X509_CRL;
|
type = CERT_X509_CRL;
|
||||||
break;
|
break;
|
||||||
|
case ENC_OCSP_CONTENT:
|
||||||
|
type = CERT_X509_OCSP_RESPONSE;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -339,6 +342,9 @@ cert_payload_t *cert_payload_create_from_cert(payload_type_t type,
|
|||||||
case CERT_X509_AC:
|
case CERT_X509_AC:
|
||||||
this->encoding = ENC_X509_ATTRIBUTE;
|
this->encoding = ENC_X509_ATTRIBUTE;
|
||||||
break;
|
break;
|
||||||
|
case CERT_X509_OCSP_RESPONSE:
|
||||||
|
this->encoding = ENC_OCSP_CONTENT;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
DBG1(DBG_ENC, "embedding %N certificate in payload failed",
|
DBG1(DBG_ENC, "embedding %N certificate in payload failed",
|
||||||
certificate_type_names, cert->get_type(cert));
|
certificate_type_names, cert->get_type(cert));
|
||||||
|
|||||||
@@ -244,6 +244,8 @@ METHOD(certreq_payload_t, get_cert_type, certificate_type_t,
|
|||||||
{
|
{
|
||||||
case ENC_X509_SIGNATURE:
|
case ENC_X509_SIGNATURE:
|
||||||
return CERT_X509;
|
return CERT_X509;
|
||||||
|
case ENC_OCSP_CONTENT:
|
||||||
|
return CERT_X509_OCSP_REQUEST;
|
||||||
default:
|
default:
|
||||||
return CERT_ANY;
|
return CERT_ANY;
|
||||||
}
|
}
|
||||||
@@ -302,6 +304,9 @@ certreq_payload_t *certreq_payload_create_type(certificate_type_t type)
|
|||||||
case CERT_X509:
|
case CERT_X509:
|
||||||
this->encoding = ENC_X509_SIGNATURE;
|
this->encoding = ENC_X509_SIGNATURE;
|
||||||
break;
|
break;
|
||||||
|
case CERT_X509_OCSP_REQUEST:
|
||||||
|
this->encoding = ENC_OCSP_CONTENT;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
DBG1(DBG_ENC, "certificate type %N not supported in requests",
|
DBG1(DBG_ENC, "certificate type %N not supported in requests",
|
||||||
certificate_type_names, type);
|
certificate_type_names, type);
|
||||||
|
|||||||
@@ -314,6 +314,7 @@ typedef struct {
|
|||||||
identification_t *ppk_id;
|
identification_t *ppk_id;
|
||||||
bool ppk_required;
|
bool ppk_required;
|
||||||
cert_policy_t send_cert;
|
cert_policy_t send_cert;
|
||||||
|
ocsp_policy_t ocsp;
|
||||||
uint64_t dpd_delay;
|
uint64_t dpd_delay;
|
||||||
uint64_t dpd_timeout;
|
uint64_t dpd_timeout;
|
||||||
fragmentation_t fragmentation;
|
fragmentation_t fragmentation;
|
||||||
@@ -425,6 +426,7 @@ static void log_peer_data(peer_data_t *data)
|
|||||||
DBG2(DBG_CFG, " remote_port = %u", data->remote_port);
|
DBG2(DBG_CFG, " remote_port = %u", data->remote_port);
|
||||||
DBG2(DBG_CFG, " send_certreq = %u", data->send_certreq);
|
DBG2(DBG_CFG, " send_certreq = %u", data->send_certreq);
|
||||||
DBG2(DBG_CFG, " send_cert = %N", cert_policy_names, data->send_cert);
|
DBG2(DBG_CFG, " send_cert = %N", cert_policy_names, data->send_cert);
|
||||||
|
DBG2(DBG_CFG, " ocsp = %N", ocsp_policy_names, data->ocsp);
|
||||||
DBG2(DBG_CFG, " ppk_id = %Y", data->ppk_id);
|
DBG2(DBG_CFG, " ppk_id = %Y", data->ppk_id);
|
||||||
DBG2(DBG_CFG, " ppk_required = %u", data->ppk_required);
|
DBG2(DBG_CFG, " ppk_required = %u", data->ppk_required);
|
||||||
DBG2(DBG_CFG, " mobike = %u", data->mobike);
|
DBG2(DBG_CFG, " mobike = %u", data->mobike);
|
||||||
@@ -1678,6 +1680,28 @@ CALLBACK(parse_send_cert, bool,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse an ocsp_policy_t
|
||||||
|
*/
|
||||||
|
CALLBACK(parse_ocsp, bool,
|
||||||
|
ocsp_policy_t *out, chunk_t v)
|
||||||
|
{
|
||||||
|
enum_map_t map[] = {
|
||||||
|
{ "both", OCSP_SEND_BOTH },
|
||||||
|
{ "reply", OCSP_SEND_REPLY },
|
||||||
|
{ "request", OCSP_SEND_REQUEST },
|
||||||
|
{ "never", OCSP_SEND_NEVER },
|
||||||
|
};
|
||||||
|
int d;
|
||||||
|
|
||||||
|
if (parse_map(map, countof(map), &d, v))
|
||||||
|
{
|
||||||
|
*out = d;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a unique_policy_t
|
* Parse a unique_policy_t
|
||||||
*/
|
*/
|
||||||
@@ -1879,6 +1903,7 @@ CALLBACK(peer_kv, bool,
|
|||||||
{ "childless", parse_childless, &peer->childless },
|
{ "childless", parse_childless, &peer->childless },
|
||||||
{ "send_certreq", parse_bool, &peer->send_certreq },
|
{ "send_certreq", parse_bool, &peer->send_certreq },
|
||||||
{ "send_cert", parse_send_cert, &peer->send_cert },
|
{ "send_cert", parse_send_cert, &peer->send_cert },
|
||||||
|
{ "ocsp", parse_ocsp, &peer->ocsp },
|
||||||
{ "keyingtries", parse_uint32, &peer->keyingtries },
|
{ "keyingtries", parse_uint32, &peer->keyingtries },
|
||||||
{ "unique", parse_unique, &peer->unique },
|
{ "unique", parse_unique, &peer->unique },
|
||||||
{ "local_port", parse_uint32, &peer->local_port },
|
{ "local_port", parse_uint32, &peer->local_port },
|
||||||
@@ -2498,6 +2523,7 @@ CALLBACK(config_sn, bool,
|
|||||||
.send_certreq = TRUE,
|
.send_certreq = TRUE,
|
||||||
.pull = TRUE,
|
.pull = TRUE,
|
||||||
.send_cert = CERT_SEND_IF_ASKED,
|
.send_cert = CERT_SEND_IF_ASKED,
|
||||||
|
.ocsp = OCSP_SEND_REPLY,
|
||||||
.version = IKE_ANY,
|
.version = IKE_ANY,
|
||||||
.remote_port = IKEV2_UDP_PORT,
|
.remote_port = IKEV2_UDP_PORT,
|
||||||
.fragmentation = FRAGMENTATION_YES,
|
.fragmentation = FRAGMENTATION_YES,
|
||||||
@@ -2646,6 +2672,8 @@ CALLBACK(config_sn, bool,
|
|||||||
.remote = peer.remote_addrs,
|
.remote = peer.remote_addrs,
|
||||||
.remote_port = peer.remote_port,
|
.remote_port = peer.remote_port,
|
||||||
.no_certreq = !peer.send_certreq,
|
.no_certreq = !peer.send_certreq,
|
||||||
|
.no_ocsp_certreq = peer.ocsp != OCSP_SEND_BOTH &&
|
||||||
|
peer.ocsp != OCSP_SEND_REQUEST,
|
||||||
.force_encap = peer.encap,
|
.force_encap = peer.encap,
|
||||||
.fragmentation = peer.fragmentation,
|
.fragmentation = peer.fragmentation,
|
||||||
.childless = peer.childless,
|
.childless = peer.childless,
|
||||||
@@ -2655,6 +2683,7 @@ CALLBACK(config_sn, bool,
|
|||||||
|
|
||||||
cfg = (peer_cfg_create_t){
|
cfg = (peer_cfg_create_t){
|
||||||
.cert_policy = peer.send_cert,
|
.cert_policy = peer.send_cert,
|
||||||
|
.ocsp_policy = peer.ocsp,
|
||||||
.unique = peer.unique,
|
.unique = peer.unique,
|
||||||
.keyingtries = peer.keyingtries,
|
.keyingtries = peer.keyingtries,
|
||||||
.rekey_time = peer.rekey_time,
|
.rekey_time = peer.rekey_time,
|
||||||
|
|||||||
@@ -250,6 +250,11 @@ enum ike_condition_t {
|
|||||||
* All authentication rounds have been completed successfully
|
* All authentication rounds have been completed successfully
|
||||||
*/
|
*/
|
||||||
COND_AUTHENTICATED = (1<<14),
|
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
|
* add certificates to message
|
||||||
*/
|
*/
|
||||||
@@ -250,6 +310,23 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message)
|
|||||||
}
|
}
|
||||||
break;
|
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,
|
METHOD(task_t, build_i, status_t,
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
* for more details.
|
* for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "ike_cert_pre.h"
|
#include "ike_cert_pre.h"
|
||||||
|
|
||||||
#include <daemon.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)
|
certreq_payload_t *certreq, auth_cfg_t *auth)
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
u_int unknown = 0;
|
u_int unknown = 0, known = 0;
|
||||||
chunk_t keyid;
|
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);
|
this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE);
|
||||||
|
|
||||||
if (certreq->get_cert_type(certreq) != CERT_X509)
|
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
|
* 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:
|
case ENC_CRL:
|
||||||
process_crl(cert_payload, auth);
|
process_crl(cert_payload, auth);
|
||||||
break;
|
break;
|
||||||
|
case ENC_OCSP_CONTENT:
|
||||||
|
process_ocsp(cert_payload, auth,
|
||||||
|
this->ike_sa->get_ike_cfg(this->ike_sa));
|
||||||
|
break;
|
||||||
case ENC_X509_ATTRIBUTE:
|
case ENC_X509_ATTRIBUTE:
|
||||||
process_ac(cert_payload, auth);
|
process_ac(cert_payload, auth);
|
||||||
break;
|
break;
|
||||||
@@ -329,7 +401,6 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message)
|
|||||||
case ENC_SPKI:
|
case ENC_SPKI:
|
||||||
case ENC_RAW_RSA_KEY:
|
case ENC_RAW_RSA_KEY:
|
||||||
case ENC_X509_HASH_AND_URL_BUNDLE:
|
case ENC_X509_HASH_AND_URL_BUNDLE:
|
||||||
case ENC_OCSP_CONTENT:
|
|
||||||
default:
|
default:
|
||||||
DBG1(DBG_ENC, "certificate encoding %N not supported",
|
DBG1(DBG_ENC, "certificate encoding %N not supported",
|
||||||
cert_encoding_names, encoding);
|
cert_encoding_names, encoding);
|
||||||
@@ -403,6 +474,36 @@ static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth)
|
|||||||
enumerator->destroy(enumerator);
|
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
|
* 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;
|
certreq_payload_t *req = NULL;
|
||||||
|
|
||||||
ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa);
|
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)
|
||||||
/* 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))
|
|
||||||
{
|
{
|
||||||
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,
|
enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr,
|
||||||
CERT_ANY, KEY_ANY, NULL, TRUE);
|
CERT_ANY, KEY_ANY, NULL, TRUE);
|
||||||
while (enumerator->enumerate(enumerator, &cert))
|
while (enumerator->enumerate(enumerator, &cert))
|
||||||
{
|
{
|
||||||
add_certreq(&req, cert);
|
add_certreq_ocsp(req, cert);
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
}
|
|
||||||
|
|
||||||
if (req)
|
|
||||||
{
|
|
||||||
message->add_payload(message, (payload_t*)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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,6 +90,16 @@ struct cert_validator_t {
|
|||||||
bool (*validate_online)(cert_validator_t *this, certificate_t *subject,
|
bool (*validate_online)(cert_validator_t *this, certificate_t *subject,
|
||||||
certificate_t *issuer, u_int pathlen, bool anchor,
|
certificate_t *issuer, u_int pathlen, bool anchor,
|
||||||
auth_cfg_t *auth);
|
auth_cfg_t *auth);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do OCSP checking for the given certificate.
|
||||||
|
*
|
||||||
|
* @param subject subject certificate to check
|
||||||
|
* @param issuer issuer of subject
|
||||||
|
* @return a valid OCSP response, NULL otherwise
|
||||||
|
*/
|
||||||
|
certificate_t* (*ocsp)(cert_validator_t *this, certificate_t *subject,
|
||||||
|
certificate_t *issuer);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /** CERT_VALIDATOR_H_ @}*/
|
#endif /** CERT_VALIDATOR_H_ @}*/
|
||||||
|
|||||||
@@ -1352,6 +1352,33 @@ METHOD(credential_manager_t, get_private, private_key_t*,
|
|||||||
return private;
|
return private;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD(credential_manager_t, get_ocsp, certificate_t*,
|
||||||
|
private_credential_manager_t *this, certificate_t *subject,
|
||||||
|
certificate_t *issuer)
|
||||||
|
{
|
||||||
|
cert_validator_t *validator;
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
certificate_t *response = NULL;
|
||||||
|
|
||||||
|
this->lock->read_lock(this->lock);
|
||||||
|
enumerator = this->validators->create_enumerator(this->validators);
|
||||||
|
while (enumerator->enumerate(enumerator, &validator))
|
||||||
|
{
|
||||||
|
if (validator->ocsp)
|
||||||
|
{
|
||||||
|
response = validator->ocsp(validator, subject, issuer);
|
||||||
|
if (response)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
this->lock->unlock(this->lock);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(credential_manager_t, flush_cache, void,
|
METHOD(credential_manager_t, flush_cache, void,
|
||||||
private_credential_manager_t *this, certificate_type_t type)
|
private_credential_manager_t *this, certificate_type_t type)
|
||||||
{
|
{
|
||||||
@@ -1427,6 +1454,7 @@ credential_manager_t *credential_manager_create()
|
|||||||
.get_cert = _get_cert,
|
.get_cert = _get_cert,
|
||||||
.get_shared = _get_shared,
|
.get_shared = _get_shared,
|
||||||
.get_private = _get_private,
|
.get_private = _get_private,
|
||||||
|
.get_ocsp = _get_ocsp,
|
||||||
.create_trusted_enumerator = _create_trusted_enumerator,
|
.create_trusted_enumerator = _create_trusted_enumerator,
|
||||||
.create_public_enumerator = _create_public_enumerator,
|
.create_public_enumerator = _create_public_enumerator,
|
||||||
.flush_cache = _flush_cache,
|
.flush_cache = _flush_cache,
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ struct credential_manager_t {
|
|||||||
certificate_t *(*get_cert)(credential_manager_t *this,
|
certificate_t *(*get_cert)(credential_manager_t *this,
|
||||||
certificate_type_t cert, key_type_t key,
|
certificate_type_t cert, key_type_t key,
|
||||||
identification_t *id, bool trusted);
|
identification_t *id, bool trusted);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the best matching shared key for two IDs.
|
* Get the best matching shared key for two IDs.
|
||||||
*
|
*
|
||||||
@@ -176,6 +177,16 @@ struct credential_manager_t {
|
|||||||
private_key_t* (*get_private)(credential_manager_t *this, key_type_t type,
|
private_key_t* (*get_private)(credential_manager_t *this, key_type_t type,
|
||||||
identification_t *id, auth_cfg_t *auth);
|
identification_t *id, auth_cfg_t *auth);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an OCSP response for the given certificate.
|
||||||
|
*
|
||||||
|
* @param subject subject certificate to check
|
||||||
|
* @param issuer issuer of subject
|
||||||
|
* @return a valid OCSP response, NULL otherwise
|
||||||
|
*/
|
||||||
|
certificate_t* (*get_ocsp)(credential_manager_t *this, certificate_t *subject,
|
||||||
|
certificate_t *issuer);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an enumerator over trusted certificates.
|
* Create an enumerator over trusted certificates.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -141,6 +141,25 @@ static certificate_t *fetch_ocsp(char *url, certificate_t *subject,
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify OCSP response signature
|
||||||
|
*/
|
||||||
|
static bool verify_ocsp_sig(certificate_t *subject, certificate_t *issuer,
|
||||||
|
bool cached)
|
||||||
|
{
|
||||||
|
if (lib->credmgr->issued_by(lib->credmgr, subject, issuer, NULL))
|
||||||
|
{
|
||||||
|
if (!cached)
|
||||||
|
{
|
||||||
|
DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"",
|
||||||
|
issuer->get_subject(issuer));
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
DBG1(DBG_CFG, "OCSP response verification failed, invalid signature");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check the signature of an OCSP response
|
* check the signature of an OCSP response
|
||||||
*/
|
*/
|
||||||
@@ -182,18 +201,11 @@ static bool verify_ocsp(ocsp_response_t *response, certificate_t *ca,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
found = TRUE;
|
found = TRUE;
|
||||||
if (lib->credmgr->issued_by(lib->credmgr, subject, issuer, NULL))
|
verified = verify_ocsp_sig(subject, issuer, cached);
|
||||||
|
if (verified)
|
||||||
{
|
{
|
||||||
if (!cached)
|
|
||||||
{
|
|
||||||
DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"",
|
|
||||||
issuer->get_subject(issuer));
|
|
||||||
}
|
|
||||||
verified = TRUE;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
DBG1(DBG_CFG, "ocsp response verification failed, "
|
|
||||||
"invalid signature");
|
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
@@ -212,18 +224,11 @@ static bool verify_ocsp(ocsp_response_t *response, certificate_t *ca,
|
|||||||
issuer->get_validity(issuer, NULL, NULL, NULL))
|
issuer->get_validity(issuer, NULL, NULL, NULL))
|
||||||
{
|
{
|
||||||
found = TRUE;
|
found = TRUE;
|
||||||
if (lib->credmgr->issued_by(lib->credmgr, subject, issuer, NULL))
|
verified = verify_ocsp_sig(subject, issuer, cached);
|
||||||
|
if (verified)
|
||||||
{
|
{
|
||||||
if (!cached)
|
|
||||||
{
|
|
||||||
DBG1(DBG_CFG, " ocsp response correctly signed by \"%Y\"",
|
|
||||||
issuer->get_subject(issuer));
|
|
||||||
}
|
|
||||||
verified = TRUE;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
DBG1(DBG_CFG, "ocsp response verification failed, "
|
|
||||||
"invalid signature");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
enumerator->destroy(enumerator);
|
enumerator->destroy(enumerator);
|
||||||
@@ -323,7 +328,8 @@ static certificate_t *get_better_ocsp(certificate_t *cand, certificate_t *best,
|
|||||||
* validate a x509 certificate using OCSP
|
* validate a x509 certificate using OCSP
|
||||||
*/
|
*/
|
||||||
static cert_validation_t check_ocsp(x509_t *subject, x509_t *issuer,
|
static cert_validation_t check_ocsp(x509_t *subject, x509_t *issuer,
|
||||||
auth_cfg_t *auth, u_int timeout)
|
auth_cfg_t *auth, u_int timeout,
|
||||||
|
certificate_t **response)
|
||||||
{
|
{
|
||||||
enumerator_t *enumerator;
|
enumerator_t *enumerator;
|
||||||
cert_validation_t valid = VALIDATION_SKIPPED;
|
cert_validation_t valid = VALIDATION_SKIPPED;
|
||||||
@@ -409,7 +415,15 @@ static cert_validation_t check_ocsp(x509_t *subject, x509_t *issuer,
|
|||||||
{ /* successful OCSP check fulfills also CRL constraint */
|
{ /* successful OCSP check fulfills also CRL constraint */
|
||||||
auth->add(auth, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
|
auth->add(auth, AUTH_RULE_CRL_VALIDATION, VALIDATION_GOOD);
|
||||||
}
|
}
|
||||||
DESTROY_IF(best);
|
|
||||||
|
if (response)
|
||||||
|
{
|
||||||
|
*response = best;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DESTROY_IF(best);
|
||||||
|
}
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -866,7 +880,8 @@ METHOD(cert_validator_t, validate_online, bool,
|
|||||||
|
|
||||||
if (enable_ocsp)
|
if (enable_ocsp)
|
||||||
{
|
{
|
||||||
switch (check_ocsp((x509_t*)subject, (x509_t*)issuer, auth, timeout))
|
switch (check_ocsp((x509_t*)subject, (x509_t*)issuer, auth, timeout,
|
||||||
|
NULL))
|
||||||
{
|
{
|
||||||
case VALIDATION_GOOD:
|
case VALIDATION_GOOD:
|
||||||
DBG1(DBG_CFG, "certificate status is good");
|
DBG1(DBG_CFG, "certificate status is good");
|
||||||
@@ -927,6 +942,47 @@ METHOD(cert_validator_t, validate_online, bool,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
METHOD (cert_validator_t, ocsp, certificate_t *,
|
||||||
|
private_revocation_validator_t *this, certificate_t *subject,
|
||||||
|
certificate_t *issuer)
|
||||||
|
{
|
||||||
|
certificate_t *response = NULL;
|
||||||
|
auth_cfg_t *auth;
|
||||||
|
bool enable_ocsp;
|
||||||
|
u_int timeout;
|
||||||
|
|
||||||
|
this->lock->lock(this->lock);
|
||||||
|
enable_ocsp = this->enable_ocsp;
|
||||||
|
timeout = this->timeout;
|
||||||
|
this->lock->unlock(this->lock);
|
||||||
|
|
||||||
|
if (enable_ocsp &&
|
||||||
|
subject->get_type(subject) == CERT_X509 &&
|
||||||
|
issuer->get_type(issuer) == CERT_X509)
|
||||||
|
{
|
||||||
|
DBG1(DBG_CFG, "checking OCSP status of \"%Y\"",
|
||||||
|
subject->get_subject(subject));
|
||||||
|
|
||||||
|
auth = auth_cfg_create();
|
||||||
|
switch (check_ocsp((x509_t*)subject, (x509_t*)issuer, auth, timeout,
|
||||||
|
&response))
|
||||||
|
{
|
||||||
|
case VALIDATION_GOOD:
|
||||||
|
case VALIDATION_ON_HOLD:
|
||||||
|
case VALIDATION_REVOKED:
|
||||||
|
break;
|
||||||
|
case VALIDATION_STALE:
|
||||||
|
case VALIDATION_SKIPPED:
|
||||||
|
case VALIDATION_FAILED:
|
||||||
|
DESTROY_IF(response);
|
||||||
|
response = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auth->destroy(auth);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(revocation_validator_t, reload, void,
|
METHOD(revocation_validator_t, reload, void,
|
||||||
private_revocation_validator_t *this)
|
private_revocation_validator_t *this)
|
||||||
{
|
{
|
||||||
@@ -974,6 +1030,7 @@ revocation_validator_t *revocation_validator_create()
|
|||||||
INIT(this,
|
INIT(this,
|
||||||
.public = {
|
.public = {
|
||||||
.validator.validate_online = _validate_online,
|
.validator.validate_online = _validate_online,
|
||||||
|
.validator.ocsp = _ocsp,
|
||||||
.reload = _reload,
|
.reload = _reload,
|
||||||
.destroy = _destroy,
|
.destroy = _destroy,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -205,6 +205,19 @@ connections.<conn>.send_cert = ifasked
|
|||||||
certificate payloads altogether, _always_ causes certificate payloads to be
|
certificate payloads altogether, _always_ causes certificate payloads to be
|
||||||
sent unconditionally whenever certificate authentication is used.
|
sent unconditionally whenever certificate authentication is used.
|
||||||
|
|
||||||
|
connections.<conn>.ocsp = reply
|
||||||
|
Request and send OCSP status in certificate request or certificate payloads
|
||||||
|
(_never_, _reply, _request_ or _both_).
|
||||||
|
|
||||||
|
Send OCSP status requests in certificate request payloads and/or send OCSP
|
||||||
|
status response in certificate payloads when using certificate
|
||||||
|
authentication. With the default of _reply_ the daemon sends OCSP status
|
||||||
|
responses in certificate payloads if an OCSP status request has been
|
||||||
|
received in a certificate request, _never_ disables sending of OCSP status
|
||||||
|
requests and responses altogether, _request_ causes OCSP status requests in
|
||||||
|
certificate request payloads to be sent whenever certificate authentication
|
||||||
|
is used, _both_ combines _reply_ and _request_.
|
||||||
|
|
||||||
connections.<conn>.ppk_id =
|
connections.<conn>.ppk_id =
|
||||||
String identifying the Postquantum Preshared Key (PPK) to be used.
|
String identifying the Postquantum Preshared Key (PPK) to be used.
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user