Merge branch 'ssh-eddsa'
This adds support for Ed25519/Ed448 SSH keys and their signatures via agent plugin.
This commit is contained in:
@@ -358,9 +358,6 @@ int main(int argc, char *argv[])
|
|||||||
creds = cmd_creds_create();
|
creds = cmd_creds_create();
|
||||||
atexit(cleanup_creds);
|
atexit(cleanup_creds);
|
||||||
|
|
||||||
/* handle all arguments */
|
|
||||||
handle_arguments(argc, argv, FALSE);
|
|
||||||
|
|
||||||
if (uname(&utsname) != 0)
|
if (uname(&utsname) != 0)
|
||||||
{
|
{
|
||||||
memset(&utsname, 0, sizeof(utsname));
|
memset(&utsname, 0, sizeof(utsname));
|
||||||
@@ -369,6 +366,9 @@ int main(int argc, char *argv[])
|
|||||||
VERSION, utsname.sysname, utsname.release, utsname.machine);
|
VERSION, utsname.sysname, utsname.release, utsname.machine);
|
||||||
lib->plugins->status(lib->plugins, LEVEL_CTRL);
|
lib->plugins->status(lib->plugins, LEVEL_CTRL);
|
||||||
|
|
||||||
|
/* handle all arguments */
|
||||||
|
handle_arguments(argc, argv, FALSE);
|
||||||
|
|
||||||
/* add handler for SEGV and ILL,
|
/* add handler for SEGV and ILL,
|
||||||
* INT, TERM and HUP are handled by sigwaitinfo() in run() */
|
* INT, TERM and HUP are handled by sigwaitinfo() in run() */
|
||||||
action.sa_handler = segv_handler;
|
action.sa_handler = segv_handler;
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
|
|||||||
"BUILD_SAFE_PRIMES",
|
"BUILD_SAFE_PRIMES",
|
||||||
"BUILD_SHARES",
|
"BUILD_SHARES",
|
||||||
"BUILD_THRESHOLD",
|
"BUILD_THRESHOLD",
|
||||||
|
"BUILD_EDDSA_PUB",
|
||||||
"BUILD_EDDSA_PRIV_ASN1_DER",
|
"BUILD_EDDSA_PRIV_ASN1_DER",
|
||||||
"BUILD_END",
|
"BUILD_END",
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -156,6 +156,8 @@ enum builder_part_t {
|
|||||||
BUILD_SHARES,
|
BUILD_SHARES,
|
||||||
/** minimum number of participating private key shares */
|
/** minimum number of participating private key shares */
|
||||||
BUILD_THRESHOLD,
|
BUILD_THRESHOLD,
|
||||||
|
/** EdDSA public key blob */
|
||||||
|
BUILD_EDDSA_PUB,
|
||||||
/** DER encoded ASN.1 EdDSA private key */
|
/** DER encoded ASN.1 EdDSA private key */
|
||||||
BUILD_EDDSA_PRIV_ASN1_DER,
|
BUILD_EDDSA_PRIV_ASN1_DER,
|
||||||
/** end of variable argument builder list */
|
/** end of variable argument builder list */
|
||||||
|
|||||||
@@ -248,6 +248,12 @@ static bool scheme_supported(private_agent_private_key_t *this,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return FALSE;
|
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:
|
case KEY_ECDSA:
|
||||||
return scheme == SIGN_ECDSA_256 ||
|
return scheme == SIGN_ECDSA_256 ||
|
||||||
scheme == SIGN_ECDSA_384 ||
|
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,
|
private_agent_private_key_t *this, signature_scheme_t scheme, void *params,
|
||||||
chunk_t data, chunk_t *signature)
|
chunk_t data, chunk_t *signature)
|
||||||
{
|
{
|
||||||
|
key_type_t type;
|
||||||
uint32_t len, flags = 0;
|
uint32_t len, flags = 0;
|
||||||
char buf[2048], *prefix = NULL;
|
char buf[2048], *prefix = NULL;
|
||||||
chunk_t blob;
|
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);
|
DBG1(DBG_LIB, "ssh-agent didn't return requested %s signature", prefix);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
type = this->pubkey->get_type(this->pubkey);
|
||||||
if (this->pubkey->get_type(this->pubkey) == KEY_RSA)
|
if (type == KEY_RSA || type == KEY_ED25519 || type == KEY_ED448)
|
||||||
{ /* for RSA, the signature has no special encoding */
|
{ /* for RSA/EdDSA, the signature has no special encoding */
|
||||||
blob = read_string(&blob);
|
blob = read_string(&blob);
|
||||||
if (blob.len)
|
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*,
|
METHOD(private_key_t, supported_signature_schemes, enumerator_t*,
|
||||||
private_agent_private_key_t *this)
|
private_agent_private_key_t *this)
|
||||||
{
|
{
|
||||||
switch (get_type(this))
|
key_type_t type = get_type(this);
|
||||||
|
|
||||||
|
switch (type)
|
||||||
{
|
{
|
||||||
case KEY_RSA:
|
case KEY_RSA:
|
||||||
return create_rsa_enumerator(this);
|
return create_rsa_enumerator(this);
|
||||||
|
case KEY_ED25519:
|
||||||
|
case KEY_ED448:
|
||||||
case KEY_ECDSA:
|
case KEY_ECDSA:
|
||||||
return signature_schemes_for_key(KEY_ECDSA, get_keysize(this));
|
return signature_schemes_for_key(type, get_keysize(this));
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright (C) 2018 Tobias Brunner
|
||||||
* Copyright (C) 2016 Andreas Steffen
|
* Copyright (C) 2016 Andreas Steffen
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
@@ -200,50 +201,16 @@ static const asn1Object_t pubkeyObjects[] = {
|
|||||||
#define ED25519_SUBJECT_PUBLIC_KEY 2
|
#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,
|
static bool parse_public_key_info(private_curve25519_public_key_t *this,
|
||||||
va_list args)
|
chunk_t blob)
|
||||||
{
|
{
|
||||||
private_curve25519_public_key_t *this;
|
|
||||||
chunk_t blob = chunk_empty, object;
|
|
||||||
asn1_parser_t *parser;
|
asn1_parser_t *parser;
|
||||||
|
chunk_t object;
|
||||||
bool success = FALSE;
|
bool success = FALSE;
|
||||||
int objectID, oid;
|
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);
|
parser = asn1_parser_create(pubkeyObjects, blob);
|
||||||
|
|
||||||
while (parser->iterate(parser, &objectID, &object))
|
while (parser->iterate(parser, &objectID, &object))
|
||||||
@@ -276,7 +243,59 @@ curve25519_public_key_t *curve25519_public_key_load(key_type_t type,
|
|||||||
|
|
||||||
end:
|
end:
|
||||||
parser->destroy(parser);
|
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);
|
destroy(this);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013-2014 Tobias Brunner
|
* Copyright (C) 2013-2018 Tobias Brunner
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* 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,
|
return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
|
||||||
BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END);
|
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) &&
|
else if (format.len > strlen(ECDSA_PREFIX) &&
|
||||||
strpfx(format.ptr, 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;
|
char line[1024], *token;
|
||||||
|
|
||||||
while (!public && fgets(line, sizeof(line), file))
|
while (!public && fgets(line, sizeof(line), file))
|
||||||
{ /* the format is: ssh-rsa|ecdsa-... <key(base64)> <identifier> */
|
{ /* the format is: ssh-<key-type> <key(base64)> <identifier> */
|
||||||
if (!strpfx(line, "ssh-rsa") && !strpfx(line, ECDSA_PREFIX))
|
if (!strpfx(line, "ssh-rsa") && !strpfx(line, ECDSA_PREFIX) &&
|
||||||
|
!strpfx(line, "ssh-ed25519") && !strpfx(line, "ssh-ed448"))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2013 Tobias Brunner
|
* Copyright (C) 2013-2018 Tobias Brunner
|
||||||
* HSR Hochschule fuer Technik Rapperswil
|
* HSR Hochschule fuer Technik Rapperswil
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* 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);
|
writer->destroy(writer);
|
||||||
return TRUE;
|
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,
|
else if (cred_encoding_args(args, CRED_PART_ECDSA_PUB_ASN1_DER, &n,
|
||||||
CRED_PART_END))
|
CRED_PART_END))
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user