summaryrefslogtreecommitdiff
path: root/src/libstrongswan/plugins/agent/agent_private_key.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/plugins/agent/agent_private_key.c')
-rw-r--r--src/libstrongswan/plugins/agent/agent_private_key.c133
1 files changed, 123 insertions, 10 deletions
diff --git a/src/libstrongswan/plugins/agent/agent_private_key.c b/src/libstrongswan/plugins/agent/agent_private_key.c
index 77c29916c..db87affc9 100644
--- a/src/libstrongswan/plugins/agent/agent_private_key.c
+++ b/src/libstrongswan/plugins/agent/agent_private_key.c
@@ -82,6 +82,14 @@ enum agent_msg_type_t {
};
/**
+ * Flags for signatures
+ */
+enum agent_signature_flags_t {
+ SSH_AGENT_FLAG_SHA2_256 = 2,
+ SSH_AGENT_FLAG_SHA2_512 = 4,
+};
+
+/**
* read a byte from a blob
*/
static u_char read_byte(chunk_t *blob)
@@ -217,12 +225,35 @@ static bool read_key(private_agent_private_key_t *this, public_key_t *pubkey)
}
static bool scheme_supported(private_agent_private_key_t *this,
- signature_scheme_t scheme)
+ signature_scheme_t scheme, uint32_t *flags,
+ char **prefix)
{
switch (this->pubkey->get_type(this->pubkey))
{
case KEY_RSA:
- return scheme == SIGN_RSA_EMSA_PKCS1_SHA1;
+ switch (scheme)
+ {
+ case SIGN_RSA_EMSA_PKCS1_SHA1:
+ *prefix = "ssh-rsa";
+ return TRUE;
+ case SIGN_RSA_EMSA_PKCS1_SHA2_256:
+ *flags |= SSH_AGENT_FLAG_SHA2_256;
+ *prefix = "rsa-sha2-256";
+ return TRUE;
+ case SIGN_RSA_EMSA_PKCS1_SHA2_512:
+ *flags |= SSH_AGENT_FLAG_SHA2_512;
+ *prefix = "rsa-sha2-512";
+ return TRUE;
+ default:
+ break;
+ }
+ return FALSE;
+ case KEY_ED25519:
+ *prefix = "ssh-ed25519";
+ return scheme == SIGN_ED25519;
+ case KEY_ED448:
+ *prefix = "ssh-ed448";
+ return scheme == SIGN_ED448;
case KEY_ECDSA:
return scheme == SIGN_ECDSA_256 ||
scheme == SIGN_ECDSA_384 ||
@@ -236,11 +267,12 @@ METHOD(private_key_t, sign, bool,
private_agent_private_key_t *this, signature_scheme_t scheme, void *params,
chunk_t data, chunk_t *signature)
{
- uint32_t len, flags;
- char buf[2048];
+ key_type_t type;
+ uint32_t len, flags = 0;
+ char buf[2048], *prefix = NULL;
chunk_t blob;
- if (!scheme_supported(this, scheme))
+ if (!scheme_supported(this, scheme, &flags, &prefix))
{
DBG1(DBG_LIB, "signature scheme %N not supported by ssh-agent",
signature_scheme_names, scheme);
@@ -272,7 +304,7 @@ METHOD(private_key_t, sign, bool,
return FALSE;
}
- flags = htonl(0);
+ flags = htonl(flags);
if (write(this->socket, &flags, sizeof(flags)) != sizeof(flags))
{
DBG1(DBG_LIB, "writing to ssh-agent failed");
@@ -290,9 +322,15 @@ METHOD(private_key_t, sign, bool,
}
/* parse length */
blob = read_string(&blob);
- /* check sig type */
- if (chunk_equals(read_string(&blob), chunk_from_str("ssh-rsa")))
- { /* for RSA the signature has no special encoding */
+ /* verify type */
+ if (prefix && !chunk_equals(read_string(&blob), chunk_from_str(prefix)))
+ {
+ DBG1(DBG_LIB, "ssh-agent didn't return requested %s signature", prefix);
+ return FALSE;
+ }
+ type = this->pubkey->get_type(this->pubkey);
+ if (type == KEY_RSA || type == KEY_ED25519 || type == KEY_ED448)
+ { /* for RSA/EdDSA, the signature has no special encoding */
blob = read_string(&blob);
if (blob.len)
{
@@ -301,7 +339,7 @@ METHOD(private_key_t, sign, bool,
}
}
else
- { /* anything else is treated as ECSDA for now */
+ { /* parse ECDSA signatures */
blob = read_string(&blob);
if (blob.len)
{
@@ -340,6 +378,80 @@ METHOD(private_key_t, get_keysize, int,
return this->pubkey->get_keysize(this->pubkey);
}
+/**
+ * Private data for RSA scheme enumerator
+ */
+typedef struct {
+ enumerator_t public;
+ int index;
+ bool reverse;
+} scheme_enumerator_t;
+
+static signature_params_t rsa_schemes[] = {
+ { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_256 },
+ { .scheme = SIGN_RSA_EMSA_PKCS1_SHA2_512 },
+};
+
+METHOD(enumerator_t, enumerate_rsa_scheme, bool,
+ scheme_enumerator_t *this, va_list args)
+{
+ signature_params_t **params;
+
+ VA_ARGS_VGET(args, params);
+
+ if ((this->reverse && --this->index >= 0) ||
+ (!this->reverse && ++this->index < countof(rsa_schemes)))
+ {
+ *params = &rsa_schemes[this->index];
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ * Create an enumerator for the supported RSA signature schemes
+ */
+static enumerator_t *create_rsa_enumerator(private_agent_private_key_t *this)
+{
+ scheme_enumerator_t *enumerator;
+
+ INIT(enumerator,
+ .public = {
+ .enumerate = enumerator_enumerate_default,
+ .venumerate = _enumerate_rsa_scheme,
+ .destroy = (void*)free,
+ },
+ .index = -1,
+ .reverse = FALSE,
+ );
+ /* propose SHA-512 first for larger keys */
+ if (get_keysize(this) > 3072)
+ {
+ enumerator->index = countof(rsa_schemes);
+ enumerator->reverse = TRUE;
+ }
+ return &enumerator->public;
+}
+
+METHOD(private_key_t, supported_signature_schemes, enumerator_t*,
+ private_agent_private_key_t *this)
+{
+ key_type_t type = get_type(this);
+
+ switch (type)
+ {
+ case KEY_RSA:
+ return create_rsa_enumerator(this);
+ case KEY_ED25519:
+ case KEY_ED448:
+ case KEY_ECDSA:
+ return signature_schemes_for_key(type, get_keysize(this));
+ default:
+ break;
+ }
+ return enumerator_create_empty();
+}
+
METHOD(private_key_t, get_public_key, public_key_t*,
private_agent_private_key_t *this)
{
@@ -413,6 +525,7 @@ agent_private_key_t *agent_private_key_open(key_type_t type, va_list args)
.public = {
.key = {
.get_type = _get_type,
+ .supported_signature_schemes = _supported_signature_schemes,
.sign = _sign,
.decrypt = _decrypt,
.get_keysize = _get_keysize,