mirror of
https://github.com/strongswan/strongswan.git
synced 2025-10-05 00:00:45 -04:00
Merge branch 'multi-cert'
Allows the configuration of multiple certificates in leftcert, and select the correct certificate to use based on the received certificate requests.
This commit is contained in:
commit
e82deaf6ce
@ -618,6 +618,10 @@ connection. See ipsec.secrets(5) for details about smartcard definitions.
|
|||||||
is required only if selecting the certificate with
|
is required only if selecting the certificate with
|
||||||
.B leftid
|
.B leftid
|
||||||
is not sufficient, for example if multiple certificates use the same subject.
|
is not sufficient, for example if multiple certificates use the same subject.
|
||||||
|
.br
|
||||||
|
Multiple certificate paths or PKCS#11 backends can be specified in a comma
|
||||||
|
separated list. The daemon chooses the certificate based on the received
|
||||||
|
certificate requests if possible before enforcing the first.
|
||||||
.TP
|
.TP
|
||||||
.BR leftcert2 " = <path>"
|
.BR leftcert2 " = <path>"
|
||||||
Same as
|
Same as
|
||||||
|
@ -447,6 +447,13 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
|
|||||||
/* add identity and peer certificate */
|
/* add identity and peer certificate */
|
||||||
identity = identification_create_from_string(id);
|
identity = identification_create_from_string(id);
|
||||||
if (cert)
|
if (cert)
|
||||||
|
{
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
bool has_subject = FALSE;
|
||||||
|
certificate_t *first = NULL;
|
||||||
|
|
||||||
|
enumerator = enumerator_create_token(cert, ",", " ");
|
||||||
|
while (enumerator->enumerate(enumerator, &cert))
|
||||||
{
|
{
|
||||||
certificate = this->cred->load_peer(this->cred, cert);
|
certificate = this->cred->load_peer(this->cred, cert);
|
||||||
if (certificate)
|
if (certificate)
|
||||||
@ -456,18 +463,28 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
|
|||||||
this->ca->check_for_hash_and_url(this->ca, certificate);
|
this->ca->check_for_hash_and_url(this->ca, certificate);
|
||||||
}
|
}
|
||||||
cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
|
cfg->add(cfg, AUTH_RULE_SUBJECT_CERT, certificate);
|
||||||
if (identity->get_type(identity) == ID_ANY ||
|
if (!first)
|
||||||
!certificate->has_subject(certificate, identity))
|
{
|
||||||
|
first = certificate;
|
||||||
|
}
|
||||||
|
if (identity->get_type(identity) != ID_ANY &&
|
||||||
|
certificate->has_subject(certificate, identity))
|
||||||
|
{
|
||||||
|
has_subject = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
|
||||||
|
if (first && !has_subject)
|
||||||
{
|
{
|
||||||
DBG1(DBG_CFG, " id '%Y' not confirmed by certificate, "
|
DBG1(DBG_CFG, " id '%Y' not confirmed by certificate, "
|
||||||
"defaulting to '%Y'", identity,
|
"defaulting to '%Y'", identity, first->get_subject(first));
|
||||||
certificate->get_subject(certificate));
|
|
||||||
identity->destroy(identity);
|
identity->destroy(identity);
|
||||||
identity = certificate->get_subject(certificate);
|
identity = first->get_subject(first);
|
||||||
identity = identity->clone(identity);
|
identity = identity->clone(identity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (identity->get_type(identity) != ID_ANY)
|
if (identity->get_type(identity) != ID_ANY)
|
||||||
{
|
{
|
||||||
cfg->add(cfg, AUTH_RULE_IDENTITY, identity);
|
cfg->add(cfg, AUTH_RULE_IDENTITY, identity);
|
||||||
|
@ -76,7 +76,6 @@ static inline bool is_multi_value_rule(auth_rule_t type)
|
|||||||
case AUTH_RULE_AAA_IDENTITY:
|
case AUTH_RULE_AAA_IDENTITY:
|
||||||
case AUTH_RULE_XAUTH_IDENTITY:
|
case AUTH_RULE_XAUTH_IDENTITY:
|
||||||
case AUTH_RULE_XAUTH_BACKEND:
|
case AUTH_RULE_XAUTH_BACKEND:
|
||||||
case AUTH_RULE_SUBJECT_CERT:
|
|
||||||
case AUTH_HELPER_SUBJECT_CERT:
|
case AUTH_HELPER_SUBJECT_CERT:
|
||||||
case AUTH_HELPER_SUBJECT_HASH_URL:
|
case AUTH_HELPER_SUBJECT_HASH_URL:
|
||||||
case AUTH_RULE_MAX:
|
case AUTH_RULE_MAX:
|
||||||
@ -84,6 +83,7 @@ static inline bool is_multi_value_rule(auth_rule_t type)
|
|||||||
case AUTH_RULE_OCSP_VALIDATION:
|
case AUTH_RULE_OCSP_VALIDATION:
|
||||||
case AUTH_RULE_CRL_VALIDATION:
|
case AUTH_RULE_CRL_VALIDATION:
|
||||||
case AUTH_RULE_GROUP:
|
case AUTH_RULE_GROUP:
|
||||||
|
case AUTH_RULE_SUBJECT_CERT:
|
||||||
case AUTH_RULE_CA_CERT:
|
case AUTH_RULE_CA_CERT:
|
||||||
case AUTH_RULE_IM_CERT:
|
case AUTH_RULE_IM_CERT:
|
||||||
case AUTH_RULE_CERT_POLICY:
|
case AUTH_RULE_CERT_POLICY:
|
||||||
@ -503,8 +503,9 @@ METHOD(auth_cfg_t, complies, bool,
|
|||||||
private_auth_cfg_t *this, auth_cfg_t *constraints, bool log_error)
|
private_auth_cfg_t *this, auth_cfg_t *constraints, bool log_error)
|
||||||
{
|
{
|
||||||
enumerator_t *e1, *e2;
|
enumerator_t *e1, *e2;
|
||||||
bool success = TRUE, group_match = FALSE;
|
bool success = TRUE, group_match = FALSE, cert_match = FALSE;
|
||||||
identification_t *require_group = NULL;
|
identification_t *require_group = NULL;
|
||||||
|
certificate_t *require_cert = NULL;
|
||||||
signature_scheme_t scheme = SIGN_UNKNOWN;
|
signature_scheme_t scheme = SIGN_UNKNOWN;
|
||||||
u_int strength = 0;
|
u_int strength = 0;
|
||||||
auth_rule_t t1, t2;
|
auth_rule_t t1, t2;
|
||||||
@ -542,20 +543,21 @@ METHOD(auth_cfg_t, complies, bool,
|
|||||||
}
|
}
|
||||||
case AUTH_RULE_SUBJECT_CERT:
|
case AUTH_RULE_SUBJECT_CERT:
|
||||||
{
|
{
|
||||||
certificate_t *c1, *c2;
|
certificate_t *cert;
|
||||||
|
|
||||||
c1 = (certificate_t*)value;
|
/* for certs, a match of a single cert is sufficient */
|
||||||
c2 = get(this, AUTH_RULE_SUBJECT_CERT);
|
require_cert = (certificate_t*)value;
|
||||||
if (!c2 || !c1->equals(c1, c2))
|
|
||||||
|
e2 = create_enumerator(this);
|
||||||
|
while (e2->enumerate(e2, &t2, &cert))
|
||||||
{
|
{
|
||||||
success = FALSE;
|
if (t2 == AUTH_RULE_SUBJECT_CERT &&
|
||||||
if (log_error)
|
cert->equals(cert, require_cert))
|
||||||
{
|
{
|
||||||
DBG1(DBG_CFG, "constraint check failed: peer not "
|
cert_match = TRUE;
|
||||||
"authenticated with peer cert '%Y'.",
|
|
||||||
c1->get_subject(c1));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
e2->destroy(e2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AUTH_RULE_CRL_VALIDATION:
|
case AUTH_RULE_CRL_VALIDATION:
|
||||||
@ -828,6 +830,17 @@ METHOD(auth_cfg_t, complies, bool,
|
|||||||
}
|
}
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (require_cert && !cert_match)
|
||||||
|
{
|
||||||
|
if (log_error)
|
||||||
|
{
|
||||||
|
DBG1(DBG_CFG, "constraint check failed: peer not "
|
||||||
|
"authenticated with peer cert '%Y'.",
|
||||||
|
require_cert->get_subject(require_cert));
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1083,6 +1083,29 @@ static private_key_t *get_private_by_cert(private_credential_manager_t *this,
|
|||||||
return private;
|
return private;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move the actually used certificate to front, so it gets returned with get()
|
||||||
|
*/
|
||||||
|
static void prefer_cert(auth_cfg_t *auth, certificate_t *cert)
|
||||||
|
{
|
||||||
|
enumerator_t *enumerator;
|
||||||
|
auth_rule_t rule;
|
||||||
|
certificate_t *current;
|
||||||
|
|
||||||
|
enumerator = auth->create_enumerator(auth);
|
||||||
|
while (enumerator->enumerate(enumerator, &rule, ¤t))
|
||||||
|
{
|
||||||
|
if (rule == AUTH_RULE_SUBJECT_CERT)
|
||||||
|
{
|
||||||
|
current->get_ref(current);
|
||||||
|
auth->replace(auth, enumerator, AUTH_RULE_SUBJECT_CERT, cert);
|
||||||
|
cert = current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert);
|
||||||
|
}
|
||||||
|
|
||||||
METHOD(credential_manager_t, get_private, private_key_t*,
|
METHOD(credential_manager_t, get_private, private_key_t*,
|
||||||
private_credential_manager_t *this, key_type_t type, identification_t *id,
|
private_credential_manager_t *this, key_type_t type, identification_t *id,
|
||||||
auth_cfg_t *auth)
|
auth_cfg_t *auth)
|
||||||
@ -1091,6 +1114,7 @@ METHOD(credential_manager_t, get_private, private_key_t*,
|
|||||||
certificate_t *cert;
|
certificate_t *cert;
|
||||||
private_key_t *private = NULL;
|
private_key_t *private = NULL;
|
||||||
auth_cfg_t *trustchain;
|
auth_cfg_t *trustchain;
|
||||||
|
auth_rule_t rule;
|
||||||
|
|
||||||
/* check if this is a lookup by key ID, and do it if so */
|
/* check if this is a lookup by key ID, and do it if so */
|
||||||
if (id && id->get_type(id) == ID_KEY_ID)
|
if (id && id->get_type(id) == ID_KEY_ID)
|
||||||
@ -1104,7 +1128,35 @@ METHOD(credential_manager_t, get_private, private_key_t*,
|
|||||||
|
|
||||||
if (auth)
|
if (auth)
|
||||||
{
|
{
|
||||||
/* if a specific certificate is preferred, check for a matching key */
|
/* try to find a trustchain with one of the configured subject certs */
|
||||||
|
enumerator = auth->create_enumerator(auth);
|
||||||
|
while (enumerator->enumerate(enumerator, &rule, &cert))
|
||||||
|
{
|
||||||
|
if (rule == AUTH_RULE_SUBJECT_CERT)
|
||||||
|
{
|
||||||
|
private = get_private_by_cert(this, cert, type);
|
||||||
|
if (private)
|
||||||
|
{
|
||||||
|
trustchain = build_trustchain(this, cert, auth);
|
||||||
|
if (trustchain)
|
||||||
|
{
|
||||||
|
auth->merge(auth, trustchain, FALSE);
|
||||||
|
prefer_cert(auth, cert->get_ref(cert));
|
||||||
|
trustchain->destroy(trustchain);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
private->destroy(private);
|
||||||
|
private = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enumerator->destroy(enumerator);
|
||||||
|
if (private)
|
||||||
|
{
|
||||||
|
return private;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if none yielded a trustchain, enforce the first configured cert */
|
||||||
cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
|
cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT);
|
||||||
if (cert)
|
if (cert)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user