agent plugin optionally accepts a BUILD_PUBLIC_KEY to select a specific private key from the agent
This commit is contained in:
@@ -168,10 +168,47 @@ static int open_connection(char *path)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* check if the ssh agent key blob matches to our public key
|
||||||
|
*/
|
||||||
|
static bool matches_pubkey(chunk_t key, public_key_t *pubkey)
|
||||||
|
{
|
||||||
|
chunk_t pubkeydata, hash, n, e;
|
||||||
|
hasher_t *hasher;
|
||||||
|
identification_t *id;
|
||||||
|
bool match;
|
||||||
|
|
||||||
|
if (!pubkey)
|
||||||
|
{
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
read_string(&key);
|
||||||
|
e = read_string(&key);
|
||||||
|
n = read_string(&key);
|
||||||
|
hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
|
||||||
|
if (hasher == NULL)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
pubkeydata = asn1_wrap(ASN1_SEQUENCE, "mm",
|
||||||
|
asn1_wrap(ASN1_INTEGER, "c", n),
|
||||||
|
asn1_wrap(ASN1_INTEGER, "c", e));
|
||||||
|
hasher->allocate_hash(hasher, pubkeydata, &hash);
|
||||||
|
free(pubkeydata.ptr);
|
||||||
|
id = pubkey->get_id(pubkey, ID_PUBKEY_SHA1);
|
||||||
|
if (!id)
|
||||||
|
{
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
match = chunk_equals(id->get_encoding(id), hash);
|
||||||
|
free(hash.ptr);
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the first usable key from the agent
|
* Get the first usable key from the agent
|
||||||
*/
|
*/
|
||||||
static bool read_key(private_agent_private_key_t *this)
|
static bool read_key(private_agent_private_key_t *this, public_key_t *pubkey)
|
||||||
{
|
{
|
||||||
int len, count;
|
int len, count;
|
||||||
char buf[2048];
|
char buf[2048];
|
||||||
@@ -203,7 +240,7 @@ static bool read_key(private_agent_private_key_t *this)
|
|||||||
read_string(&tmp);
|
read_string(&tmp);
|
||||||
tmp = read_string(&tmp);
|
tmp = read_string(&tmp);
|
||||||
if (type.len && strneq("ssh-rsa", type.ptr, type.len) &&
|
if (type.len && strneq("ssh-rsa", type.ptr, type.len) &&
|
||||||
tmp.len >= 512/8)
|
tmp.len >= 512/8 && matches_pubkey(key, pubkey))
|
||||||
{
|
{
|
||||||
this->key = chunk_clone(key);
|
this->key = chunk_clone(key);
|
||||||
this->key_size = tmp.len;
|
this->key_size = tmp.len;
|
||||||
@@ -374,6 +411,7 @@ static bool build_ids(private_agent_private_key_t *this)
|
|||||||
hasher_t *hasher;
|
hasher_t *hasher;
|
||||||
|
|
||||||
key = this->key;
|
key = this->key;
|
||||||
|
read_string(&key);
|
||||||
e = read_string(&key);
|
e = read_string(&key);
|
||||||
n = read_string(&key);
|
n = read_string(&key);
|
||||||
|
|
||||||
@@ -383,7 +421,9 @@ static bool build_ids(private_agent_private_key_t *this)
|
|||||||
DBG1("SHA1 hash algorithm not supported, unable to use RSA");
|
DBG1("SHA1 hash algorithm not supported, unable to use RSA");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
publicKey = asn1_wrap(ASN1_SEQUENCE, "cc", n, e);
|
publicKey = asn1_wrap(ASN1_SEQUENCE, "mm",
|
||||||
|
asn1_wrap(ASN1_INTEGER, "c", n),
|
||||||
|
asn1_wrap(ASN1_INTEGER, "c", e));
|
||||||
hasher->allocate_hash(hasher, publicKey, &hash);
|
hasher->allocate_hash(hasher, publicKey, &hash);
|
||||||
this->keyid = identification_create_from_encoding(ID_PUBKEY_SHA1, hash);
|
this->keyid = identification_create_from_encoding(ID_PUBKEY_SHA1, hash);
|
||||||
chunk_free(&hash);
|
chunk_free(&hash);
|
||||||
@@ -435,7 +475,8 @@ static void destroy(private_agent_private_key_t *this)
|
|||||||
/**
|
/**
|
||||||
* Internal constructor
|
* Internal constructor
|
||||||
*/
|
*/
|
||||||
static agent_private_key_t *agent_private_key_create(char *path)
|
static agent_private_key_t *agent_private_key_create(char *path,
|
||||||
|
public_key_t *pubkey)
|
||||||
{
|
{
|
||||||
private_agent_private_key_t *this = malloc_thing(private_agent_private_key_t);
|
private_agent_private_key_t *this = malloc_thing(private_agent_private_key_t);
|
||||||
|
|
||||||
@@ -456,10 +497,11 @@ static agent_private_key_t *agent_private_key_create(char *path)
|
|||||||
free(this);
|
free(this);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
this->key = chunk_empty;
|
||||||
this->keyid = NULL;
|
this->keyid = NULL;
|
||||||
this->keyid_info = NULL;
|
this->keyid_info = NULL;
|
||||||
this->ref = 1;
|
this->ref = 1;
|
||||||
if (!read_key(this) || !build_ids(this))
|
if (!read_key(this, pubkey) || !build_ids(this))
|
||||||
{
|
{
|
||||||
destroy(this);
|
destroy(this);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -474,8 +516,10 @@ typedef struct private_builder_t private_builder_t;
|
|||||||
struct private_builder_t {
|
struct private_builder_t {
|
||||||
/** implements the builder interface */
|
/** implements the builder interface */
|
||||||
builder_t public;
|
builder_t public;
|
||||||
/** loaded/generated private key */
|
/** agent unix socket */
|
||||||
agent_private_key_t *key;
|
char *socket;
|
||||||
|
/** matching public key */
|
||||||
|
public_key_t *pubkey;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -483,8 +527,12 @@ struct private_builder_t {
|
|||||||
*/
|
*/
|
||||||
static agent_private_key_t *build(private_builder_t *this)
|
static agent_private_key_t *build(private_builder_t *this)
|
||||||
{
|
{
|
||||||
agent_private_key_t *key = this->key;
|
agent_private_key_t *key = NULL;
|
||||||
|
|
||||||
|
if (this->socket)
|
||||||
|
{
|
||||||
|
key = agent_private_key_create(this->socket, this->pubkey);
|
||||||
|
}
|
||||||
free(this);
|
free(this);
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
@@ -496,25 +544,26 @@ static void add(private_builder_t *this, builder_part_t part, ...)
|
|||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
if (this->key)
|
|
||||||
{
|
|
||||||
DBG1("ignoring surplus build part %N", builder_part_names, part);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (part)
|
switch (part)
|
||||||
{
|
{
|
||||||
case BUILD_AGENT_SOCKET:
|
case BUILD_AGENT_SOCKET:
|
||||||
{
|
{
|
||||||
va_start(args, part);
|
va_start(args, part);
|
||||||
this->key = agent_private_key_create(va_arg(args, char*));
|
this->socket = va_arg(args, char*);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
break;
|
return;
|
||||||
|
}
|
||||||
|
case BUILD_PUBLIC_KEY:
|
||||||
|
{
|
||||||
|
va_start(args, part);
|
||||||
|
this->pubkey = va_arg(args, public_key_t*);
|
||||||
|
va_end(args);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
DBG1("ignoring unsupported build part %N", builder_part_names, part);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
builder_cancel(&this->public);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -531,7 +580,8 @@ builder_t *agent_private_key_builder(key_type_t type)
|
|||||||
|
|
||||||
this = malloc_thing(private_builder_t);
|
this = malloc_thing(private_builder_t);
|
||||||
|
|
||||||
this->key = NULL;
|
this->pubkey = NULL;
|
||||||
|
this->socket = NULL;
|
||||||
this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
|
this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
|
||||||
this->public.build = (void*(*)(builder_t *this))build;
|
this->public.build = (void*(*)(builder_t *this))build;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user