Key strength checking stores all key sizes in auth_cfg, verifies all in complies()
[strongswan.git] / src / libstrongswan / credentials / credential_manager.c
index 3b671c7..f437bbf 100644 (file)
@@ -157,8 +157,10 @@ static enumerator_t *create_sets_enumerator(private_credential_manager_t *this)
        linked_list_t *local;
 
        INIT(enumerator,
-               .public.enumerate = (void*)_sets_enumerate,
-               .public.destroy = _sets_destroy,
+               .public = {
+                       .enumerate = (void*)_sets_enumerate,
+                       .destroy = _sets_destroy,
+               },
                .global = this->sets->create_enumerator(this->sets),
        );
        local = this->local_sets->get(this->local_sets);
@@ -549,6 +551,37 @@ static certificate_t *get_issuer_cert(private_credential_manager_t *this,
 }
 
 /**
+ * Get the strength of certificate, add it to auth
+ */
+static void get_key_strength(certificate_t *cert, auth_cfg_t *auth)
+{
+       uintptr_t strength;
+       public_key_t *key;
+       key_type_t type;
+
+       key = cert->get_public_key(cert);
+       if (key)
+       {
+               type = key->get_type(key);
+               strength = key->get_keysize(key);
+               DBG2(DBG_CFG, "  certificate \"%Y\" key: %d bit %N",
+                        cert->get_subject(cert), strength, key_type_names, type);
+               switch (type)
+               {
+                       case KEY_RSA:
+                               auth->add(auth, AUTH_RULE_RSA_STRENGTH, strength);
+                               break;
+                       case KEY_ECDSA:
+                               auth->add(auth, AUTH_RULE_ECDSA_STRENGTH, strength);
+                               break;
+                       default:
+                               break;
+               }
+               key->destroy(key);
+       }
+}
+
+/**
  * try to verify the trust chain of subject, return TRUE if trusted
  */
 static bool verify_trust_chain(private_credential_manager_t *this,
@@ -560,6 +593,7 @@ static bool verify_trust_chain(private_credential_manager_t *this,
        int pathlen;
 
        auth = auth_cfg_create();
+       get_key_strength(subject, auth);
        current = subject->get_ref(subject);
 
        for (pathlen = 0; pathlen <= MAX_TRUST_PATH_LEN; pathlen++)
@@ -612,6 +646,10 @@ static bool verify_trust_chain(private_credential_manager_t *this,
                        issuer->destroy(issuer);
                        break;
                }
+               if (issuer)
+               {
+                       get_key_strength(issuer, auth);
+               }
                current->destroy(current);
                current = issuer;
                if (trusted)
@@ -708,6 +746,8 @@ METHOD(enumerator_t, trusted_enumerate, bool,
                if (verify_trust_chain(this->this, current, this->auth, FALSE,
                                                           this->online))
                {
+                       this->auth->add(this->auth, AUTH_RULE_SUBJECT_CERT,
+                                                       current->get_ref(current));
                        *cert = current;
                        if (auth)
                        {
@@ -822,7 +862,7 @@ METHOD(credential_manager_t, create_public_enumerator, enumerator_t*,
 }
 
 /**
- * Check if a certificate's keyid is contained in the auth helper
+ * Check if an helper contains a certificate as trust anchor
  */
 static bool auth_contains_cacert(auth_cfg_t *auth, certificate_t *cert)
 {
@@ -854,17 +894,10 @@ static auth_cfg_t *build_trustchain(private_credential_manager_t *this,
        certificate_t *issuer, *current;
        auth_cfg_t *trustchain;
        int pathlen = 0;
+       bool has_anchor;
 
        trustchain = auth_cfg_create();
-
-       current = auth->get(auth, AUTH_RULE_CA_CERT);
-       if (!current)
-       {
-               /* no trust anchor specified, return this cert only */
-               trustchain->add(trustchain, AUTH_RULE_SUBJECT_CERT,
-                                               subject->get_ref(subject));
-               return trustchain;
-       }
+       has_anchor = auth->get(auth, AUTH_RULE_CA_CERT) != NULL;
        current = subject->get_ref(subject);
        while (TRUE)
        {
@@ -879,17 +912,33 @@ static auth_cfg_t *build_trustchain(private_credential_manager_t *this,
                }
                else
                {
+                       if (!has_anchor &&
+                               this->cache->issued_by(this->cache, current, current))
+                       {       /* If no trust anchor specified, accept any CA */
+                               trustchain->add(trustchain, AUTH_RULE_CA_CERT, current);
+                               return trustchain;
+                       }
                        trustchain->add(trustchain, AUTH_RULE_IM_CERT, current);
                }
+               if (pathlen++ > MAX_TRUST_PATH_LEN)
+               {
+                       break;
+               }
                issuer = get_issuer_cert(this, current, FALSE);
-               if (!issuer || issuer->equals(issuer, current) ||
-                       pathlen > MAX_TRUST_PATH_LEN)
+               if (!issuer)
                {
-                       DESTROY_IF(issuer);
+                       if (!has_anchor)
+                       {       /* If no trust anchor specified, accept incomplete chains */
+                               return trustchain;
+                       }
+                       break;
+               }
+               if (has_anchor && issuer->equals(issuer, current))
+               {
+                       issuer->destroy(issuer);
                        break;
                }
                current = issuer;
-               pathlen++;
        }
        trustchain->destroy(trustchain);
        return NULL;
@@ -909,7 +958,7 @@ static private_key_t *get_private_by_cert(private_credential_manager_t *this,
        public = cert->get_public_key(cert);
        if (public)
        {
-               if (public->get_fingerprint(public, KEY_ID_PUBKEY_SHA1, &chunk))
+               if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &chunk))
                {
                        keyid = identification_create_from_encoding(ID_KEY_ID, chunk);
                        private = get_private_by_keyid(this, type, keyid);