Skip to content

Commit 8d8e7a9

Browse files
committed
Merge branch 'ssh-eddsa'
This adds support for Ed25519/Ed448 SSH keys and their signatures via agent plugin.
2 parents 64adacc + 8f23e64 commit 8d8e7a9

File tree

7 files changed

+145
-47
lines changed

7 files changed

+145
-47
lines changed

src/charon-cmd/charon-cmd.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,9 +358,6 @@ int main(int argc, char *argv[])
358358
creds = cmd_creds_create();
359359
atexit(cleanup_creds);
360360

361-
/* handle all arguments */
362-
handle_arguments(argc, argv, FALSE);
363-
364361
if (uname(&utsname) != 0)
365362
{
366363
memset(&utsname, 0, sizeof(utsname));
@@ -369,6 +366,9 @@ int main(int argc, char *argv[])
369366
VERSION, utsname.sysname, utsname.release, utsname.machine);
370367
lib->plugins->status(lib->plugins, LEVEL_CTRL);
371368

369+
/* handle all arguments */
370+
handle_arguments(argc, argv, FALSE);
371+
372372
/* add handler for SEGV and ILL,
373373
* INT, TERM and HUP are handled by sigwaitinfo() in run() */
374374
action.sa_handler = segv_handler;

src/libstrongswan/credentials/builder.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ ENUM(builder_part_names, BUILD_FROM_FILE, BUILD_END,
7373
"BUILD_SAFE_PRIMES",
7474
"BUILD_SHARES",
7575
"BUILD_THRESHOLD",
76+
"BUILD_EDDSA_PUB",
7677
"BUILD_EDDSA_PRIV_ASN1_DER",
7778
"BUILD_END",
7879
);

src/libstrongswan/credentials/builder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ enum builder_part_t {
156156
BUILD_SHARES,
157157
/** minimum number of participating private key shares */
158158
BUILD_THRESHOLD,
159+
/** EdDSA public key blob */
160+
BUILD_EDDSA_PUB,
159161
/** DER encoded ASN.1 EdDSA private key */
160162
BUILD_EDDSA_PRIV_ASN1_DER,
161163
/** end of variable argument builder list */

src/libstrongswan/plugins/agent/agent_private_key.c

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,12 @@ static bool scheme_supported(private_agent_private_key_t *this,
248248
break;
249249
}
250250
return FALSE;
251+
case KEY_ED25519:
252+
*prefix = "ssh-ed25519";
253+
return scheme == SIGN_ED25519;
254+
case KEY_ED448:
255+
*prefix = "ssh-ed448";
256+
return scheme == SIGN_ED448;
251257
case KEY_ECDSA:
252258
return scheme == SIGN_ECDSA_256 ||
253259
scheme == SIGN_ECDSA_384 ||
@@ -261,6 +267,7 @@ METHOD(private_key_t, sign, bool,
261267
private_agent_private_key_t *this, signature_scheme_t scheme, void *params,
262268
chunk_t data, chunk_t *signature)
263269
{
270+
key_type_t type;
264271
uint32_t len, flags = 0;
265272
char buf[2048], *prefix = NULL;
266273
chunk_t blob;
@@ -321,9 +328,9 @@ METHOD(private_key_t, sign, bool,
321328
DBG1(DBG_LIB, "ssh-agent didn't return requested %s signature", prefix);
322329
return FALSE;
323330
}
324-
325-
if (this->pubkey->get_type(this->pubkey) == KEY_RSA)
326-
{ /* for RSA, the signature has no special encoding */
331+
type = this->pubkey->get_type(this->pubkey);
332+
if (type == KEY_RSA || type == KEY_ED25519 || type == KEY_ED448)
333+
{ /* for RSA/EdDSA, the signature has no special encoding */
327334
blob = read_string(&blob);
328335
if (blob.len)
329336
{
@@ -429,12 +436,16 @@ static enumerator_t *create_rsa_enumerator(private_agent_private_key_t *this)
429436
METHOD(private_key_t, supported_signature_schemes, enumerator_t*,
430437
private_agent_private_key_t *this)
431438
{
432-
switch (get_type(this))
439+
key_type_t type = get_type(this);
440+
441+
switch (type)
433442
{
434443
case KEY_RSA:
435444
return create_rsa_enumerator(this);
445+
case KEY_ED25519:
446+
case KEY_ED448:
436447
case KEY_ECDSA:
437-
return signature_schemes_for_key(KEY_ECDSA, get_keysize(this));
448+
return signature_schemes_for_key(type, get_keysize(this));
438449
default:
439450
break;
440451
}

src/libstrongswan/plugins/curve25519/curve25519_public_key.c

Lines changed: 54 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/*
2+
* Copyright (C) 2018 Tobias Brunner
23
* Copyright (C) 2016 Andreas Steffen
34
* HSR Hochschule fuer Technik Rapperswil
45
*
@@ -199,23 +200,69 @@ static const asn1Object_t pubkeyObjects[] = {
199200
#define ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM 1
200201
#define ED25519_SUBJECT_PUBLIC_KEY 2
201202

203+
/**
204+
* Parse the ASN.1-encoded subjectPublicKeyInfo
205+
*/
206+
static bool parse_public_key_info(private_curve25519_public_key_t *this,
207+
chunk_t blob)
208+
{
209+
asn1_parser_t *parser;
210+
chunk_t object;
211+
bool success = FALSE;
212+
int objectID, oid;
213+
214+
parser = asn1_parser_create(pubkeyObjects, blob);
215+
216+
while (parser->iterate(parser, &objectID, &object))
217+
{
218+
switch (objectID)
219+
{
220+
case ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM:
221+
{
222+
oid = asn1_parse_algorithmIdentifier(object,
223+
parser->get_level(parser) + 1, NULL);
224+
if (oid != OID_ED25519)
225+
{
226+
goto end;
227+
}
228+
break;
229+
}
230+
case ED25519_SUBJECT_PUBLIC_KEY:
231+
{
232+
/* encoded as an ASN1 BIT STRING */
233+
if (object.len != 1 + ED25519_KEY_LEN)
234+
{
235+
goto end;
236+
}
237+
this->pubkey = chunk_clone(chunk_skip(object, 1));
238+
break;
239+
}
240+
}
241+
}
242+
success = parser->success(parser);
243+
244+
end:
245+
parser->destroy(parser);
246+
return success;
247+
}
248+
202249
/**
203250
* See header.
204251
*/
205252
curve25519_public_key_t *curve25519_public_key_load(key_type_t type,
206253
va_list args)
207254
{
208255
private_curve25519_public_key_t *this;
209-
chunk_t blob = chunk_empty, object;
210-
asn1_parser_t *parser;
211-
bool success = FALSE;
212-
int objectID, oid;
256+
chunk_t asn1 = chunk_empty, blob = chunk_empty;
213257

214258
while (TRUE)
215259
{
216260
switch (va_arg(args, builder_part_t))
217261
{
218262
case BUILD_BLOB_ASN1_DER:
263+
asn1 = va_arg(args, chunk_t);
264+
continue;
265+
case BUILD_EDDSA_PUB:
219266
blob = va_arg(args, chunk_t);
220267
continue;
221268
case BUILD_END:
@@ -244,39 +291,11 @@ curve25519_public_key_t *curve25519_public_key_load(key_type_t type,
244291
.ref = 1,
245292
);
246293

247-
parser = asn1_parser_create(pubkeyObjects, blob);
248-
249-
while (parser->iterate(parser, &objectID, &object))
294+
if (blob.len == ED25519_KEY_LEN)
250295
{
251-
switch (objectID)
252-
{
253-
case ED25519_SUBJECT_PUBLIC_KEY_ALGORITHM:
254-
{
255-
oid = asn1_parse_algorithmIdentifier(object,
256-
parser->get_level(parser) + 1, NULL);
257-
if (oid != OID_ED25519)
258-
{
259-
goto end;
260-
}
261-
break;
262-
}
263-
case ED25519_SUBJECT_PUBLIC_KEY:
264-
{
265-
/* encoded as an ASN1 BIT STRING */
266-
if (object.len != 1 + ED25519_KEY_LEN)
267-
{
268-
goto end;
269-
}
270-
this->pubkey = chunk_clone(chunk_skip(object, 1));
271-
break;
272-
}
273-
}
296+
this->pubkey = chunk_clone(blob);
274297
}
275-
success = parser->success(parser);
276-
277-
end:
278-
parser->destroy(parser);
279-
if (!success)
298+
else if (!asn1.len || !parse_public_key_info(this, asn1))
280299
{
281300
destroy(this);
282301
return NULL;

src/libstrongswan/plugins/sshkey/sshkey_builder.c

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2013-2014 Tobias Brunner
2+
* Copyright (C) 2013-2018 Tobias Brunner
33
* HSR Hochschule fuer Technik Rapperswil
44
*
55
* 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)
8989
return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_RSA,
9090
BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END);
9191
}
92+
else if (chunk_equals(format, chunk_from_str("ssh-ed25519")))
93+
{
94+
chunk_t blob;
95+
96+
if (!reader->read_data32(reader, &blob))
97+
{
98+
DBG1(DBG_LIB, "invalid Ed25519 key in SSH key");
99+
reader->destroy(reader);
100+
return NULL;
101+
}
102+
reader->destroy(reader);
103+
return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED25519,
104+
BUILD_EDDSA_PUB, blob, BUILD_END);
105+
}
106+
else if (chunk_equals(format, chunk_from_str("ssh-ed448")))
107+
{
108+
chunk_t blob;
109+
110+
if (!reader->read_data32(reader, &blob))
111+
{
112+
DBG1(DBG_LIB, "invalid Ed448 key in SSH key");
113+
reader->destroy(reader);
114+
return NULL;
115+
}
116+
reader->destroy(reader);
117+
return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, KEY_ED448,
118+
BUILD_EDDSA_PUB, blob, BUILD_END);
119+
}
92120
else if (format.len > strlen(ECDSA_PREFIX) &&
93121
strpfx(format.ptr, ECDSA_PREFIX))
94122
{
@@ -140,8 +168,9 @@ static sshkey_public_key_t *load_from_stream(FILE *file)
140168
char line[1024], *token;
141169

142170
while (!public && fgets(line, sizeof(line), file))
143-
{ /* the format is: ssh-rsa|ecdsa-... <key(base64)> <identifier> */
144-
if (!strpfx(line, "ssh-rsa") && !strpfx(line, ECDSA_PREFIX))
171+
{ /* the format is: ssh-<key-type> <key(base64)> <identifier> */
172+
if (!strpfx(line, "ssh-rsa") && !strpfx(line, ECDSA_PREFIX) &&
173+
!strpfx(line, "ssh-ed25519") && !strpfx(line, "ssh-ed448"))
145174
{
146175
continue;
147176
}

src/libstrongswan/plugins/sshkey/sshkey_encoder.c

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2013 Tobias Brunner
2+
* Copyright (C) 2013-2018 Tobias Brunner
33
* HSR Hochschule fuer Technik Rapperswil
44
*
55
* 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)
7272
writer->destroy(writer);
7373
return TRUE;
7474
}
75+
else if (cred_encoding_args(args, CRED_PART_EDDSA_PUB_ASN1_DER, &n,
76+
CRED_PART_END))
77+
{
78+
chunk_t alg;
79+
char *prefix;
80+
int oid;
81+
82+
/* parse subjectPublicKeyInfo */
83+
if (asn1_unwrap(&n, &n) != ASN1_SEQUENCE)
84+
{
85+
return FALSE;
86+
}
87+
oid = asn1_parse_algorithmIdentifier(n, 1, NULL);
88+
switch (oid)
89+
{
90+
case OID_ED25519:
91+
prefix = "ssh-ed25519";
92+
break;
93+
case OID_ED448:
94+
prefix = "ssh-ed448";
95+
break;
96+
default:
97+
return FALSE;
98+
}
99+
if (asn1_unwrap(&n, &alg) != ASN1_SEQUENCE ||
100+
asn1_unwrap(&n, &n) != ASN1_BIT_STRING || !n.len)
101+
{
102+
return FALSE;
103+
}
104+
writer = bio_writer_create(0);
105+
writer->write_data32(writer, chunk_from_str(prefix));
106+
writer->write_data32(writer, chunk_skip(n, 1));
107+
*encoding = chunk_to_base64(writer->get_buf(writer), NULL);
108+
writer->destroy(writer);
109+
return TRUE;
110+
}
75111
else if (cred_encoding_args(args, CRED_PART_ECDSA_PUB_ASN1_DER, &n,
76112
CRED_PART_END))
77113
{

0 commit comments

Comments
 (0)