x509_t* (*get_ca_certificate) (credential_store_t *this, identification_t *id);
/**
+ * @brief Returns the ca certificate of a specific keyID.
+ *
+ * @param this calling object
+ * @param keyid identification_t object identifiying the cacert.
+ * @return certificate, or NULL if not found
+ */
+ x509_t* (*get_ca_certificate_by_keyid) (credential_store_t *this, chunk_t keyid);
+
+ /**
* @brief Returns the ca certificate of a specific subject distinguished name.
*
* @param this calling object
x509_t *current_cert;
iterator_t *iterator = this->ca_certs->create_iterator(this->ca_certs, TRUE);
+
while (iterator->iterate(iterator, (void**)¤t_cert))
{
if (id->equals(id, current_cert->get_subject(current_cert)))
return found;
}
+
+/**
+ * Implementation of credential_store_t.get_ca_certificate_by_keyid.
+ */
+static x509_t* get_ca_certificate_by_keyid(private_local_credential_store_t *this,
+ chunk_t keyid)
+{
+ x509_t *found = NULL;
+ x509_t *current_cert;
+
+ iterator_t *iterator = this->ca_certs->create_iterator(this->ca_certs, TRUE);
+
+ while (iterator->iterate(iterator, (void**)¤t_cert))
+ {
+ rsa_public_key_t *pubkey = current_cert->get_public_key(current_cert);
+
+ if (chunk_equals(keyid, pubkey->get_keyid(pubkey)))
+ {
+ found = current_cert;
+ break;
+ }
+ }
+ iterator->destroy(iterator);
+
+ return found;
+}
+
/**
* Implementation of credential_store_t.get_issuer_certificate.
*/
x509_t *current_cert;
iterator_t *iterator = this->ca_certs->create_iterator(this->ca_certs, TRUE);
+
while (iterator->iterate(iterator, (void**)¤t_cert))
{
if (cert->is_issuer(cert, current_cert))
this->public.credential_store.get_trusted_public_key = (rsa_public_key_t*(*)(credential_store_t*,identification_t*))get_trusted_public_key;
this->public.credential_store.get_certificate = (x509_t* (*) (credential_store_t*,identification_t*))get_certificate;
this->public.credential_store.get_ca_certificate = (x509_t* (*) (credential_store_t*,identification_t*))get_ca_certificate;
+ this->public.credential_store.get_ca_certificate_by_keyid = (x509_t* (*) (credential_store_t*,identification_t*))get_ca_certificate_by_keyid;
this->public.credential_store.get_issuer_certificate = (x509_t* (*) (credential_store_t*,const x509_t*))get_issuer_certificate;
this->public.credential_store.verify = (bool (*) (credential_store_t*,x509_t*,bool*))verify;
this->public.credential_store.add_end_certificate = (x509_t* (*) (credential_store_t*,x509_t*))add_end_certificate;
*/
#include <stddef.h>
+#include <string.h>
+
+#include <daemon.h>
+#include <crypto/hashers/hasher.h>
#include "certreq_payload.h"
/*
* Described in header
*/
-certreq_payload_t *certreq_payload_create_from_x509(x509_t *cert)
+certreq_payload_t *certreq_payload_create_from_cacert(identification_t *id)
{
+ x509_t *cacert = charon->credentials->get_ca_certificate(charon->credentials, id);
+ rsa_public_key_t *pubkey = cacert->get_public_key(cacert);
+ chunk_t keyid = pubkey->get_keyid(pubkey);
+
certreq_payload_t *this = certreq_payload_create();
- rsa_public_key_t *pubkey = cert->get_public_key(cert);
+
+ DBG1(DBG_IKE, "request certificate issued by '%D'", id);
+ DBG2(DBG_IKE, " with keyid %#B", &keyid);
+
+ this->set_cert_encoding(this, CERT_X509_SIGNATURE);
+ this->set_data(this, keyid);
+ return this;
+}
+
+/*
+ * Described in header
+ */
+certreq_payload_t *certreq_payload_create_from_cacerts(void)
+{
+ certreq_payload_t *this;
+ chunk_t keyids;
+ u_char *pos;
+ x509_t *cacert;
+
+ iterator_t *iterator = charon->credentials->create_cacert_iterator(charon->credentials);
+ int count = iterator->get_count(iterator);
+
+ if (count == 0)
+ return NULL;
+
+ this = certreq_payload_create();
+ keyids = chunk_alloc(count * HASH_SIZE_SHA1);
+ pos = keyids.ptr;
+
+ while (iterator->iterate(iterator, (void**)&cacert))
+ {
+ rsa_public_key_t *pubkey = cacert->get_public_key(cacert);
+ chunk_t keyid = pubkey->get_keyid(pubkey);
+
+ DBG1(DBG_IKE, "request certificate issued by '%D'", cacert->get_subject(cacert));
+ DBG2(DBG_IKE, " with keyid %#B", &keyid);
+ memcpy(pos, keyid.ptr, keyid.len);
+ pos += HASH_SIZE_SHA1;
+ }
+ iterator->destroy(iterator);
this->set_cert_encoding(this, CERT_X509_SIGNATURE);
- this->set_data(this, pubkey->get_keyid(pubkey));
+ this->set_data(this, keyids);
+ free(keyids.ptr);
return this;
}
certreq_payload_t *certreq_payload_create(void);
/**
- * @brief Creates a certreq_payload_t object from a X.509 CA certificate.
+ * @brief Creates a certreq_payload_t object from a ca certificate
*
- * @param cert X.509 CA certificate
+ * @param id subject distinguished name of CA certificate
* @return certreq_payload_t object
*
* @ingroup payloads
*/
-certreq_payload_t *certreq_payload_create_from_x509(x509_t *cert);
+certreq_payload_t *certreq_payload_create_from_cacert(identification_t *id);
+
+/**
+ * @brief Creates a certreq_payload_t object from all ca certificates
+ *
+ * @return certreq_payload_t object
+ *
+ * @ingroup payloads
+ */
+certreq_payload_t *certreq_payload_create_from_cacerts(void);
#endif /* CERTREQ_PAYLOAD_H_ */
if (this->connection->get_certreq_policy(this->connection) != CERT_NEVER_SEND)
{
certreq_payload_t *certreq_payload;
-
identification_t *other_ca = this->policy->get_other_ca(this->policy);
- if (other_ca->get_type(other_ca) == ID_ANY)
- {
+ certreq_payload = (other_ca->get_type(other_ca) == ID_ANY)
+ ? certreq_payload_create_from_cacerts()
+ : certreq_payload_create_from_cacert(other_ca);
- }
- else
+ if (certreq_payload != NULL)
{
- x509_t *cacert = charon->credentials->get_ca_certificate(charon->credentials, other_ca);
-
- DBG2(DBG_IKE, "certreq with ca: '%D'", other_ca);
- certreq_payload = certreq_payload_create_from_x509(cacert);
request->add_payload(request, (payload_t*)certreq_payload);
}
}
}
/**
+ * Import certificate requests from a certreq payload
+ */
+static void import_certificate_request(certreq_payload_t *certreq_payload)
+{
+ chunk_t keyids;
+ cert_encoding_t encoding = certreq_payload->get_cert_encoding(certreq_payload);
+
+ if (encoding != CERT_X509_SIGNATURE)
+ {
+ DBG1(DBG_IKE, "certreq payload %N not supported, ignored",
+ cert_encoding_names, encoding);
+ return;
+ }
+
+ keyids = certreq_payload->get_data(certreq_payload);
+
+ while (keyids.len >= HASH_SIZE_SHA1)
+ {
+ chunk_t keyid = { keyids.ptr, HASH_SIZE_SHA1};
+ x509_t *cacert = charon->credentials->get_ca_certificate_by_keyid(charon->credentials, keyid);
+
+ if (cacert)
+ {
+ DBG1(DBG_IKE, "request for certificate issued by ca '%D'", cacert->get_subject(cacert));
+ DBG2(DBG_IKE, " with keyid %#B", &keyid);
+ }
+ else
+ {
+ DBG1(DBG_IKE, "request for certificate issued by unknown ca");
+ DBG1(DBG_IKE, " with keyid %#B", &keyid);
+ }
+ keyids.ptr += HASH_SIZE_SHA1;
+ keyids.len -= HASH_SIZE_SHA1;
+ }
+}
+
+/**
* Import a certificate from a cert payload
*/
-static void import_certificate(private_ike_auth_t *this, cert_payload_t *cert_payload)
+static void import_certificate(cert_payload_t *cert_payload)
{
bool found;
x509_t *cert;
id_payload_t *idi_request = NULL;
id_payload_t *idr_request = NULL;
auth_payload_t *auth_request = NULL;
+ certreq_payload_t *certreq_request = NULL;
cert_payload_t *cert_request = NULL;
sa_payload_t *sa_request = NULL;
ts_payload_t *tsi_request = NULL;
case AUTHENTICATION:
auth_request = (auth_payload_t*)payload;
break;
+ case CERTIFICATE_REQUEST:
+ certreq_request = (certreq_payload_t*)payload;
+ break;
case CERTIFICATE:
cert_request = (cert_payload_t*)payload;
break;
}
}
+ if (certreq_request)
+ { /* process certificate request payload */
+ import_certificate_request(certreq_request);
+ }
+
if (cert_request)
{ /* process certificate payload */
- import_certificate(this, cert_request);
+ import_certificate(cert_request);
}
{ /* process auth payload */
if (cert_payload)
{ /* process cert payload */
- import_certificate(this, cert_payload);
+ import_certificate(cert_payload);
}
{ /* authenticate peer */