agent: Use sshkey plugin to parse keys, adds support for ECDSA
authorTobias Brunner <tobias@strongswan.org>
Mon, 1 Apr 2013 17:47:23 +0000 (19:47 +0200)
committerTobias Brunner <tobias@strongswan.org>
Tue, 7 May 2013 15:08:31 +0000 (17:08 +0200)
configure.in
src/charon-cmd/cmd/cmd_creds.c
src/libstrongswan/plugins/agent/agent_plugin.c
src/libstrongswan/plugins/agent/agent_private_key.c

index 49a9164..dd16633 100644 (file)
@@ -968,7 +968,7 @@ ADD_PLUGIN([pkcs7],                [s scepclient pki])
 ADD_PLUGIN([pkcs8],                [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
 ADD_PLUGIN([pgp],                  [s charon])
 ADD_PLUGIN([dnskey],               [s charon])
-ADD_PLUGIN([sshkey],               [s charon])
+ADD_PLUGIN([sshkey],               [s charon nm cmd])
 ADD_PLUGIN([ipseckey],             [c charon])
 ADD_PLUGIN([pem],                  [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
 ADD_PLUGIN([padlock],              [s charon])
index 178b77d..31e5789 100644 (file)
@@ -148,7 +148,7 @@ static void load_agent(private_cmd_creds_t *this)
        }
 
        privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
-                                                                KEY_RSA, BUILD_AGENT_SOCKET, agent, BUILD_END);
+                                                                KEY_ANY, BUILD_AGENT_SOCKET, agent, BUILD_END);
        if (!privkey)
        {
                DBG1(DBG_CFG, "failed to load private key from ssh-agent");
@@ -200,6 +200,8 @@ METHOD(cmd_creds_t, handle, bool,
        if (this->agent && this->identity)
        {
                load_agent(this);
+               /* only do this once */
+               this->agent = FALSE;
        }
        return TRUE;
 }
index 980a140..322ded4 100644 (file)
@@ -42,7 +42,9 @@ METHOD(plugin_t, get_features, int,
 {
        static plugin_feature_t f[] = {
                PLUGIN_REGISTER(PRIVKEY, agent_private_key_open, FALSE),
+                       PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
                        PLUGIN_PROVIDE(PRIVKEY, KEY_RSA),
+                       PLUGIN_PROVIDE(PRIVKEY, KEY_ECDSA),
        };
        *features = f;
        return countof(f);
index 42c78c1..8a3fb15 100644 (file)
@@ -49,11 +49,16 @@ struct private_agent_private_key_t {
        int socket;
 
        /**
-        * key identity blob in ssh format
+        * public key encoded in SSH format
         */
        chunk_t key;
 
        /**
+        * public key
+        */
+       public_key_t *pubkey;
+
+       /**
         * keysize in bytes
         */
        size_t key_size;
@@ -163,7 +168,7 @@ static bool read_key(private_agent_private_key_t *this, public_key_t *pubkey)
 {
        int len;
        char buf[2048];
-       chunk_t blob, key, type, n;
+       chunk_t blob, key;
 
        len = htonl(1);
        buf[0] = SSH_AGENT_ID_REQUEST;
@@ -193,34 +198,40 @@ static bool read_key(private_agent_private_key_t *this, public_key_t *pubkey)
                {
                        break;
                }
-               this->key = key;
-               type = read_string(&key);
-               if (!type.len || !strneq("ssh-rsa", type.ptr, type.len))
-               {
-                       break;
-               }
-               read_string(&key);
-               n = read_string(&key);
-               if (n.len <= 512/8)
+               this->pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY,
+                                                                                 BUILD_BLOB_SSHKEY, key, BUILD_END);
+               if (!this->pubkey)
                {
-                       break;;
+                       continue;
                }
                if (pubkey && !private_key_belongs_to(&this->public.key, pubkey))
                {
+                       this->pubkey->destroy(this->pubkey);
+                       this->pubkey = NULL;
                        continue;
                }
-               this->key_size = n.len;
-               if (n.ptr[0] == 0)
-               {
-                       this->key_size--;
-               }
-               this->key = chunk_clone(this->key);
+               this->key = chunk_clone(key);
                return TRUE;
        }
-       this->key = chunk_empty;
        return FALSE;
 }
 
+static bool scheme_supported(private_agent_private_key_t *this,
+                                                       signature_scheme_t scheme)
+{
+       switch (this->pubkey->get_type(this->pubkey))
+       {
+               case KEY_RSA:
+                       return scheme == SIGN_RSA_EMSA_PKCS1_SHA1;
+               case KEY_ECDSA:
+                       return scheme == SIGN_ECDSA_256 ||
+                                  scheme == SIGN_ECDSA_384 ||
+                                  scheme == SIGN_ECDSA_521;
+               default:
+                       return FALSE;
+       }
+}
+
 METHOD(private_key_t, sign, bool,
        private_agent_private_key_t *this, signature_scheme_t scheme,
        chunk_t data, chunk_t *signature)
@@ -229,7 +240,7 @@ METHOD(private_key_t, sign, bool,
        char buf[2048];
        chunk_t blob;
 
-       if (scheme != SIGN_RSA_EMSA_PKCS1_SHA1)
+       if (!scheme_supported(this, scheme))
        {
                DBG1(DBG_LIB, "signature scheme %N not supported by ssh-agent",
                         signature_scheme_names, scheme);
@@ -279,23 +290,40 @@ METHOD(private_key_t, sign, bool,
        }
        /* parse length */
        blob = read_string(&blob);
-       /* skip sig type */
-       read_string(&blob);
-       /* parse length */
-       blob = read_string(&blob);
-       if (!blob.len)
-       {
-               DBG1(DBG_LIB, "received invalid ssh-agent signature response");
-               return FALSE;
+       /* check sig type */
+       if (chunk_equals(read_string(&blob), chunk_from_str("ssh-rsa")))
+       {       /* for RSA the signature has no special encoding */
+               blob = read_string(&blob);
+               if (blob.len)
+               {
+                       *signature = chunk_clone(blob);
+                       return TRUE;
+               }
+       }
+       else
+       {       /* anything else is treated as ECSDA for now */
+               blob = read_string(&blob);
+               if (blob.len)
+               {
+                       chunk_t r, s;
+
+                       r = read_string(&blob);
+                       s = read_string(&blob);
+                       if (r.len && s.len)
+                       {
+                               *signature = chunk_cat("cc", r, s);
+                               return TRUE;
+                       }
+               }
        }
-       *signature =  chunk_clone(blob);
-       return TRUE;
+       DBG1(DBG_LIB, "received invalid ssh-agent signature response");
+       return FALSE;
 }
 
 METHOD(private_key_t, get_type, key_type_t,
        private_agent_private_key_t *this)
 {
-       return KEY_RSA;
+       return this->pubkey->get_type(this->pubkey);
 }
 
 METHOD(private_key_t, decrypt, bool,
@@ -309,21 +337,13 @@ METHOD(private_key_t, decrypt, bool,
 METHOD(private_key_t, get_keysize, int,
        private_agent_private_key_t *this)
 {
-       return this->key_size * 8;
+       return this->pubkey->get_keysize(this->pubkey);
 }
 
 METHOD(private_key_t, get_public_key, public_key_t*,
        private_agent_private_key_t *this)
 {
-       chunk_t key, n, e;
-
-       key = this->key;
-       read_string(&key);
-       e = read_string(&key);
-       n = read_string(&key);
-
-       return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
-                                               BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END);
+       return this->pubkey->get_ref(this->pubkey);
 }
 
 METHOD(private_key_t, get_encoding, bool,
@@ -336,19 +356,7 @@ METHOD(private_key_t, get_encoding, bool,
 METHOD(private_key_t, get_fingerprint, bool,
        private_agent_private_key_t *this, cred_encoding_type_t type, chunk_t *fp)
 {
-       chunk_t n, e, key;
-
-       if (lib->encoding->get_cache(lib->encoding, type, this, fp))
-       {
-               return TRUE;
-       }
-       key = this->key;
-       read_string(&key);
-       e = read_string(&key);
-       n = read_string(&key);
-
-       return lib->encoding->encode(lib->encoding, type, this, fp,
-                       CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
+       return this->pubkey->get_fingerprint(this->pubkey, type, fp);
 }
 
 METHOD(private_key_t, get_ref, private_key_t*,
@@ -364,8 +372,8 @@ METHOD(private_key_t, destroy, void,
        if (ref_put(&this->ref))
        {
                close(this->socket);
-               free(this->key.ptr);
-               lib->encoding->clear_cache(lib->encoding, this);
+               chunk_free(&this->key);
+               DESTROY_IF(this->pubkey);
                free(this);
        }
 }