Merge branch 'ssh-eddsa'

This adds support for Ed25519/Ed448 SSH keys and their signatures via
agent plugin.
This commit is contained in:
Tobias Brunner
2018-10-26 11:04:37 +02:00
7 changed files with 149 additions and 51 deletions
+3 -3
View File
@@ -358,9 +358,6 @@ int main(int argc, char *argv[])
creds = cmd_creds_create();
atexit(cleanup_creds);
/* handle all arguments */
handle_arguments(argc, argv, FALSE);
if (uname(&utsname) != 0)
{
memset(&utsname, 0, sizeof(utsname));
@@ -369,6 +366,9 @@ int main(int argc, char *argv[])
VERSION, utsname.sysname, utsname.release, utsname.machine);
lib->plugins->status(lib->plugins, LEVEL_CTRL);
/* handle all arguments */
handle_arguments(argc, argv, FALSE);
/* add handler for SEGV and ILL,
* INT, TERM and HUP are handled by sigwaitinfo() in run() */
action.sa_handler = segv_handler;
+1
View File
@@ -73,6 +73,7 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
"BUILD_SAFE_PRIMES",
"BUILD_SHARES",
"BUILD_THRESHOLD",
"BUILD_EDDSA_PUB",
"BUILD_EDDSA_PRIV_ASN1_DER",
"BUILD_END",
);
+2
View File
@@ -156,6 +156,8 @@ enum builder_part_t {
BUILD_SHARES,
/** minimum number of participating private key shares */
BUILD_THRESHOLD,
/** EdDSA public key blob */
BUILD_EDDSA_PUB,
/** DER encoded ASN.1 EdDSA private key */
BUILD_EDDSA_PRIV_ASN1_DER,
/** end of variable argument builder list */
@@ -248,6 +248,12 @@ static bool scheme_supported(private_agent_private_key_t *this,
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 ||
@@ -261,6 +267,7 @@ METHOD(private_key_t, sign, bool,
private_agent_private_key_t *this, signature_scheme_t scheme, void *params,
chunk_t data, chunk_t *signature)
{
key_type_t type;
uint32_t len, flags = 0;
char buf[2048], *prefix = NULL;
chunk_t blob;
@@ -321,9 +328,9 @@ METHOD(private_key_t, sign, bool,
DBG1(DBG_LIB, "ssh-agent didn't return requested %s signature", prefix);
return FALSE;
}
if (this->pubkey->get_type(this->pubkey) == KEY_RSA)
{ /* for RSA, the signature has no special encoding */
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)
{
@@ -429,12 +436,16 @@ static enumerator_t *create_rsa_enumerator(private_agent_private_key_t *this)
METHOD(private_key_t, supported_signature_schemes, enumerator_t*,
private_agent_private_key_t *this)
{
switch (get_type(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(KEY_ECDSA, get_keysize(this));
return signature_schemes_for_key(type, get_keysize(this));
default:
break;
}
@@ -1,4 +1,5 @@
/*
* Copyright (C) 2018 Tobias Brunner
* Copyright (C) 2016 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
@@ -200,50 +201,16 @@ static const asn1Object_t pubkeyObjects[] = {
#define ED25519_SUBJECT_PUBLIC_KEY 2
/**
* See header.
* Parse the ASN.1-encoded subjectPublicKeyInfo
*/
curve25519_public_key_t *curve25519_public_key_load(key_type_t type,
va_list args)
static bool parse_public_key_info(private_curve25519_public_key_t *this,
chunk_t blob)
{
private_curve25519_public_key_t *this;
chunk_t blob = chunk_empty, object;
asn1_parser_t *parser;
chunk_t object;
bool success = FALSE;
int objectID, oid;
while (TRUE)
{
switch (va_arg(args, builder_part_t))
{
case BUILD_BLOB_ASN1_DER:
blob = va_arg(args, chunk_t);
continue;
case BUILD_END:
break;
default:
return NULL;
}
break;
}
INIT(this,
.public = {
.key = {
.get_type = _get_type,
.verify = _verify,
.encrypt = _encrypt_,
.equals = public_key_equals,
.get_keysize = _get_keysize,
.get_fingerprint = _get_fingerprint,
.has_fingerprint = public_key_has_fingerprint,
.get_encoding = _get_encoding,
.get_ref = _get_ref,
.destroy = _destroy,
},
},
.ref = 1,
);
parser = asn1_parser_create(pubkeyObjects, blob);
while (parser->iterate(parser, &objectID, &object))
@@ -276,7 +243,59 @@ curve25519_public_key_t *curve25519_public_key_load(key_type_t type,
end:
parser->destroy(parser);
if (!success)
return success;
}
/**
* See header.
*/
curve25519_public_key_t *curve25519_public_key_load(key_type_t type,
va_list args)
{
private_curve25519_public_key_t *this;
chunk_t asn1 = chunk_empty, blob = chunk_empty;
while (TRUE)
{
switch (va_arg(args, builder_part_t))
{
case BUILD_BLOB_ASN1_DER:
asn1 = va_arg(args, chunk_t);
continue;
case BUILD_EDDSA_PUB:
blob = va_arg(args, chunk_t);
continue;
case BUILD_END:
break;
default:
return NULL;
}
break;
}
INIT(this,
.public = {
.key = {
.get_type = _get_type,
.verify = _verify,
.encrypt = _encrypt_,
.equals = public_key_equals,
.get_keysize = _get_keysize,
.get_fingerprint = _get_fingerprint,
.has_fingerprint = public_key_has_fingerprint,
.get_encoding = _get_encoding,
.get_ref = _get_ref,
.destroy = _destroy,
},
},
.ref = 1,
);
if (blob.len == ED25519_KEY_LEN)
{
this->pubkey = chunk_clone(blob);
}
else if (!asn1.len || !parse_public_key_info(this, asn1))
{
destroy(this);
return NULL;
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2014 Tobias Brunner
* Copyright (C) 2013-2018 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -89,6 +89,34 @@ static sshkey_public_key_t *parse_public_key(chunk_t blob)
return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END);
}
else if (chunk_equals(format, chunk_from_str("ssh-ed25519")))
{
chunk_t blob;
if (!reader->read_data32(reader, &blob))
{
DBG1(DBG_LIB, "invalid Ed25519 key in SSH key");
reader->destroy(reader);
return NULL;
}
reader->destroy(reader);
return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED25519,
BUILD_EDDSA_PUB, blob, BUILD_END);
}
else if (chunk_equals(format, chunk_from_str("ssh-ed448")))
{
chunk_t blob;
if (!reader->read_data32(reader, &blob))
{
DBG1(DBG_LIB, "invalid Ed448 key in SSH key");
reader->destroy(reader);
return NULL;
}
reader->destroy(reader);
return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448,
BUILD_EDDSA_PUB, blob, BUILD_END);
}
else if (format.len > strlen(ECDSA_PREFIX) &&
strpfx(format.ptr, ECDSA_PREFIX))
{
@@ -140,8 +168,9 @@ static sshkey_public_key_t *load_from_stream(FILE *file)
char line[1024], *token;
while (!public && fgets(line, sizeof(line), file))
{ /* the format is: ssh-rsa|ecdsa-... <key(base64)> <identifier> */
if (!strpfx(line, "ssh-rsa") && !strpfx(line, ECDSA_PREFIX))
{ /* the format is: ssh-<key-type> <key(base64)> <identifier> */
if (!strpfx(line, "ssh-rsa") && !strpfx(line, ECDSA_PREFIX) &&
!strpfx(line, "ssh-ed25519") && !strpfx(line, "ssh-ed448"))
{
continue;
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2013-2018 Tobias Brunner
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -72,6 +72,42 @@ static bool build_public_key(chunk_t *encoding, va_list args)
writer->destroy(writer);
return TRUE;
}
else if (cred_encoding_args(args, CRED_PART_EDDSA_PUB_ASN1_DER, &n,
CRED_PART_END))
{
chunk_t alg;
char *prefix;
int oid;
/* parse subjectPublicKeyInfo */
if (asn1_unwrap(&n, &n) != ASN1_SEQUENCE)
{
return FALSE;
}
oid = asn1_parse_algorithmIdentifier(n, 1, NULL);
switch (oid)
{
case OID_ED25519:
prefix = "ssh-ed25519";
break;
case OID_ED448:
prefix = "ssh-ed448";
break;
default:
return FALSE;
}
if (asn1_unwrap(&n, &alg) != ASN1_SEQUENCE ||
asn1_unwrap(&n, &n) != ASN1_BIT_STRING || !n.len)
{
return FALSE;
}
writer = bio_writer_create(0);
writer->write_data32(writer, chunk_from_str(prefix));
writer->write_data32(writer, chunk_skip(n, 1));
*encoding = chunk_to_base64(writer->get_buf(writer), NULL);
writer->destroy(writer);
return TRUE;
}
else if (cred_encoding_args(args, CRED_PART_ECDSA_PUB_ASN1_DER, &n,
CRED_PART_END))
{