agent: Use sshkey plugin to parse keys, adds support for ECDSA
This commit is contained in:
+1
-1
@@ -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([pkcs8], [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
|
||||||
ADD_PLUGIN([pgp], [s charon])
|
ADD_PLUGIN([pgp], [s charon])
|
||||||
ADD_PLUGIN([dnskey], [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([ipseckey], [c charon])
|
||||||
ADD_PLUGIN([pem], [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
|
ADD_PLUGIN([pem], [s charon openac scepclient pki scripts manager medsrv attest nm cmd])
|
||||||
ADD_PLUGIN([padlock], [s charon])
|
ADD_PLUGIN([padlock], [s charon])
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ static void load_agent(private_cmd_creds_t *this)
|
|||||||
}
|
}
|
||||||
|
|
||||||
privkey = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
|
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)
|
if (!privkey)
|
||||||
{
|
{
|
||||||
DBG1(DBG_CFG, "failed to load private key from ssh-agent");
|
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)
|
if (this->agent && this->identity)
|
||||||
{
|
{
|
||||||
load_agent(this);
|
load_agent(this);
|
||||||
|
/* only do this once */
|
||||||
|
this->agent = FALSE;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,9 @@ METHOD(plugin_t, get_features, int,
|
|||||||
{
|
{
|
||||||
static plugin_feature_t f[] = {
|
static plugin_feature_t f[] = {
|
||||||
PLUGIN_REGISTER(PRIVKEY, agent_private_key_open, FALSE),
|
PLUGIN_REGISTER(PRIVKEY, agent_private_key_open, FALSE),
|
||||||
|
PLUGIN_PROVIDE(PRIVKEY, KEY_ANY),
|
||||||
PLUGIN_PROVIDE(PRIVKEY, KEY_RSA),
|
PLUGIN_PROVIDE(PRIVKEY, KEY_RSA),
|
||||||
|
PLUGIN_PROVIDE(PRIVKEY, KEY_ECDSA),
|
||||||
};
|
};
|
||||||
*features = f;
|
*features = f;
|
||||||
return countof(f);
|
return countof(f);
|
||||||
|
|||||||
@@ -49,10 +49,15 @@ struct private_agent_private_key_t {
|
|||||||
int socket;
|
int socket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* key identity blob in ssh format
|
* public key encoded in SSH format
|
||||||
*/
|
*/
|
||||||
chunk_t key;
|
chunk_t key;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* public key
|
||||||
|
*/
|
||||||
|
public_key_t *pubkey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* keysize in bytes
|
* keysize in bytes
|
||||||
*/
|
*/
|
||||||
@@ -163,7 +168,7 @@ static bool read_key(private_agent_private_key_t *this, public_key_t *pubkey)
|
|||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
char buf[2048];
|
char buf[2048];
|
||||||
chunk_t blob, key, type, n;
|
chunk_t blob, key;
|
||||||
|
|
||||||
len = htonl(1);
|
len = htonl(1);
|
||||||
buf[0] = SSH_AGENT_ID_REQUEST;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
this->key = key;
|
this->pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ANY,
|
||||||
type = read_string(&key);
|
BUILD_BLOB_SSHKEY, key, BUILD_END);
|
||||||
if (!type.len || !strneq("ssh-rsa", type.ptr, type.len))
|
if (!this->pubkey)
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
read_string(&key);
|
|
||||||
n = read_string(&key);
|
|
||||||
if (n.len <= 512/8)
|
|
||||||
{
|
|
||||||
break;;
|
|
||||||
}
|
|
||||||
if (pubkey && !private_key_belongs_to(&this->public.key, pubkey))
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
this->key_size = n.len;
|
if (pubkey && !private_key_belongs_to(&this->public.key, pubkey))
|
||||||
if (n.ptr[0] == 0)
|
|
||||||
{
|
{
|
||||||
this->key_size--;
|
this->pubkey->destroy(this->pubkey);
|
||||||
|
this->pubkey = NULL;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
this->key = chunk_clone(this->key);
|
this->key = chunk_clone(key);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
this->key = chunk_empty;
|
|
||||||
return FALSE;
|
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,
|
METHOD(private_key_t, sign, bool,
|
||||||
private_agent_private_key_t *this, signature_scheme_t scheme,
|
private_agent_private_key_t *this, signature_scheme_t scheme,
|
||||||
chunk_t data, chunk_t *signature)
|
chunk_t data, chunk_t *signature)
|
||||||
@@ -229,7 +240,7 @@ METHOD(private_key_t, sign, bool,
|
|||||||
char buf[2048];
|
char buf[2048];
|
||||||
chunk_t blob;
|
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",
|
DBG1(DBG_LIB, "signature scheme %N not supported by ssh-agent",
|
||||||
signature_scheme_names, scheme);
|
signature_scheme_names, scheme);
|
||||||
@@ -279,23 +290,40 @@ METHOD(private_key_t, sign, bool,
|
|||||||
}
|
}
|
||||||
/* parse length */
|
/* parse length */
|
||||||
blob = read_string(&blob);
|
blob = read_string(&blob);
|
||||||
/* skip sig type */
|
/* check sig type */
|
||||||
read_string(&blob);
|
if (chunk_equals(read_string(&blob), chunk_from_str("ssh-rsa")))
|
||||||
/* parse length */
|
{ /* for RSA the signature has no special encoding */
|
||||||
blob = read_string(&blob);
|
blob = read_string(&blob);
|
||||||
if (!blob.len)
|
if (blob.len)
|
||||||
{
|
{
|
||||||
DBG1(DBG_LIB, "received invalid ssh-agent signature response");
|
*signature = chunk_clone(blob);
|
||||||
return FALSE;
|
return TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*signature = chunk_clone(blob);
|
else
|
||||||
return TRUE;
|
{ /* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DBG1(DBG_LIB, "received invalid ssh-agent signature response");
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(private_key_t, get_type, key_type_t,
|
METHOD(private_key_t, get_type, key_type_t,
|
||||||
private_agent_private_key_t *this)
|
private_agent_private_key_t *this)
|
||||||
{
|
{
|
||||||
return KEY_RSA;
|
return this->pubkey->get_type(this->pubkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(private_key_t, decrypt, bool,
|
METHOD(private_key_t, decrypt, bool,
|
||||||
@@ -309,21 +337,13 @@ METHOD(private_key_t, decrypt, bool,
|
|||||||
METHOD(private_key_t, get_keysize, int,
|
METHOD(private_key_t, get_keysize, int,
|
||||||
private_agent_private_key_t *this)
|
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*,
|
METHOD(private_key_t, get_public_key, public_key_t*,
|
||||||
private_agent_private_key_t *this)
|
private_agent_private_key_t *this)
|
||||||
{
|
{
|
||||||
chunk_t key, n, e;
|
return this->pubkey->get_ref(this->pubkey);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(private_key_t, get_encoding, bool,
|
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,
|
METHOD(private_key_t, get_fingerprint, bool,
|
||||||
private_agent_private_key_t *this, cred_encoding_type_t type, chunk_t *fp)
|
private_agent_private_key_t *this, cred_encoding_type_t type, chunk_t *fp)
|
||||||
{
|
{
|
||||||
chunk_t n, e, key;
|
return this->pubkey->get_fingerprint(this->pubkey, type, fp);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
METHOD(private_key_t, get_ref, private_key_t*,
|
METHOD(private_key_t, get_ref, private_key_t*,
|
||||||
@@ -364,8 +372,8 @@ METHOD(private_key_t, destroy, void,
|
|||||||
if (ref_put(&this->ref))
|
if (ref_put(&this->ref))
|
||||||
{
|
{
|
||||||
close(this->socket);
|
close(this->socket);
|
||||||
free(this->key.ptr);
|
chunk_free(&this->key);
|
||||||
lib->encoding->clear_cache(lib->encoding, this);
|
DESTROY_IF(this->pubkey);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user