diff options
Diffstat (limited to 'src/libstrongswan/plugins/agent/agent_private_key.c')
-rw-r--r-- | src/libstrongswan/plugins/agent/agent_private_key.c | 133 |
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, |