2 * Copyright (C) 2013-2019 Tobias Brunner
3 * Copyright (C) 2008-2009 Martin Willi
4 * HSR Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 #include "agent_private_key.h"
21 #include <sys/types.h>
22 #include <sys/socket.h>
24 #include <arpa/inet.h>
28 #include <utils/chunk.h>
29 #include <utils/debug.h>
32 #define UNIX_PATH_MAX 108
33 #endif /* UNIX_PATH_MAX */
35 typedef struct private_agent_private_key_t private_agent_private_key_t
;
36 typedef enum agent_msg_type_t agent_msg_type_t
;
39 * Private data of a agent_private_key_t object.
41 struct private_agent_private_key_t
{
43 * Public interface for this signer.
45 agent_private_key_t
public;
48 * Path to the UNIX socket
53 * public key encoded in SSH format
74 * Message types for ssh-agent protocol
76 enum agent_msg_type_t
{
77 SSH_AGENT_FAILURE
= 5,
78 SSH_AGENT_SUCCESS
= 6,
79 SSH_AGENT_ID_REQUEST
= 11,
80 SSH_AGENT_ID_RESPONSE
= 12,
81 SSH_AGENT_SIGN_REQUEST
= 13,
82 SSH_AGENT_SIGN_RESPONSE
= 14,
86 * Flags for signatures
88 enum agent_signature_flags_t
{
89 SSH_AGENT_FLAG_SHA2_256
= 2,
90 SSH_AGENT_FLAG_SHA2_512
= 4,
94 * read a byte from a blob
96 static u_char
read_byte(chunk_t
*blob
)
100 if (blob
->len
< sizeof(u_char
))
105 *blob
= chunk_skip(*blob
, sizeof(u_char
));
110 * read a uint32_t from a blob
112 static uint32_t read_uint32(chunk_t
*blob
)
116 if (blob
->len
< sizeof(uint32_t))
120 val
= ntohl(*(uint32_t*)blob
->ptr
);
121 *blob
= chunk_skip(*blob
, sizeof(uint32_t));
126 * read a ssh-agent "string" length/value from a blob
128 static chunk_t
read_string(chunk_t
*blob
)
133 len
= read_uint32(blob
);
138 str
= chunk_create(blob
->ptr
, len
);
139 *blob
= chunk_skip(*blob
, + len
);
144 * open socket connection to the ssh-agent
146 static int open_connection(char *path
)
148 struct sockaddr_un addr
;
151 s
= socket(AF_UNIX
, SOCK_STREAM
, 0);
154 DBG1(DBG_LIB
, "opening ssh-agent socket %s failed: %s:", path
,
159 addr
.sun_family
= AF_UNIX
;
160 addr
.sun_path
[UNIX_PATH_MAX
- 1] = '\0';
161 strncpy(addr
.sun_path
, path
, UNIX_PATH_MAX
- 1);
163 if (connect(s
, (struct sockaddr
*)&addr
, SUN_LEN(&addr
)) != 0)
165 DBG1(DBG_LIB
, "connecting to ssh-agent socket failed: %s",
174 * Get the first usable key from the agent
176 static bool read_key(private_agent_private_key_t
*this, public_key_t
*pubkey
)
181 bool success
= FALSE
;
183 socket
= open_connection(this->path
);
190 buf
[0] = SSH_AGENT_ID_REQUEST
;
191 if (write(socket
, &len
, sizeof(len
)) != sizeof(len
) ||
192 write(socket
, &buf
, 1) != 1)
194 DBG1(DBG_LIB
, "writing to ssh-agent failed");
198 blob
= chunk_create(buf
, sizeof(buf
));
199 blob
.len
= read(socket
, blob
.ptr
, blob
.len
);
201 if (blob
.len
< sizeof(uint32_t) + sizeof(u_char
) ||
202 read_uint32(&blob
) != blob
.len
||
203 read_byte(&blob
) != SSH_AGENT_ID_RESPONSE
)
205 DBG1(DBG_LIB
, "received invalid ssh-agent identity response");
212 key
= read_string(&blob
);
217 this->pubkey
= lib
->creds
->create(lib
->creds
, CRED_PUBLIC_KEY
, KEY_ANY
,
218 BUILD_BLOB_SSHKEY
, key
, BUILD_END
);
223 if (pubkey
&& !private_key_belongs_to(&this->public.key
, pubkey
))
225 this->pubkey
->destroy(this->pubkey
);
229 this->key
= chunk_clone(key
);
238 static bool scheme_supported(private_agent_private_key_t
*this,
239 signature_scheme_t scheme
, uint32_t *flags
,
242 switch (this->pubkey
->get_type(this->pubkey
))
247 case SIGN_RSA_EMSA_PKCS1_SHA1
:
250 case SIGN_RSA_EMSA_PKCS1_SHA2_256
:
251 *flags
|= SSH_AGENT_FLAG_SHA2_256
;
252 *prefix
= "rsa-sha2-256";
254 case SIGN_RSA_EMSA_PKCS1_SHA2_512
:
255 *flags
|= SSH_AGENT_FLAG_SHA2_512
;
256 *prefix
= "rsa-sha2-512";
263 *prefix
= "ssh-ed25519";
264 return scheme
== SIGN_ED25519
;
266 *prefix
= "ssh-ed448";
267 return scheme
== SIGN_ED448
;
269 return scheme
== SIGN_ECDSA_256
||
270 scheme
== SIGN_ECDSA_384
||
271 scheme
== SIGN_ECDSA_521
;
277 METHOD(private_key_t
, sign
, bool,
278 private_agent_private_key_t
*this, signature_scheme_t scheme
, void *params
,
279 chunk_t data
, chunk_t
*signature
)
282 uint32_t len
, flags
= 0;
283 char buf
[2048], *prefix
= NULL
;
286 bool success
= FALSE
;
288 if (!scheme_supported(this, scheme
, &flags
, &prefix
))
290 DBG1(DBG_LIB
, "signature scheme %N not supported by ssh-agent",
291 signature_scheme_names
, scheme
);
295 socket
= open_connection(this->path
);
301 len
= htonl(1 + sizeof(uint32_t) * 3 + this->key
.len
+ data
.len
);
302 buf
[0] = SSH_AGENT_SIGN_REQUEST
;
303 if (write(socket
, &len
, sizeof(len
)) != sizeof(len
) ||
304 write(socket
, &buf
, 1) != 1)
306 DBG1(DBG_LIB
, "writing to ssh-agent failed");
310 len
= htonl(this->key
.len
);
311 if (write(socket
, &len
, sizeof(len
)) != sizeof(len
) ||
312 write(socket
, this->key
.ptr
, this->key
.len
) != this->key
.len
)
314 DBG1(DBG_LIB
, "writing to ssh-agent failed");
318 len
= htonl(data
.len
);
319 if (write(socket
, &len
, sizeof(len
)) != sizeof(len
) ||
320 write(socket
, data
.ptr
, data
.len
) != data
.len
)
322 DBG1(DBG_LIB
, "writing to ssh-agent failed");
326 flags
= htonl(flags
);
327 if (write(socket
, &flags
, sizeof(flags
)) != sizeof(flags
))
329 DBG1(DBG_LIB
, "writing to ssh-agent failed");
333 blob
= chunk_create(buf
, sizeof(buf
));
334 blob
.len
= read(socket
, blob
.ptr
, blob
.len
);
335 if (blob
.len
< sizeof(uint32_t) + sizeof(u_char
) ||
336 read_uint32(&blob
) != blob
.len
||
337 read_byte(&blob
) != SSH_AGENT_SIGN_RESPONSE
)
339 DBG1(DBG_LIB
, "received invalid ssh-agent signature response");
343 blob
= read_string(&blob
);
345 if (prefix
&& !chunk_equals(read_string(&blob
), chunk_from_str(prefix
)))
347 DBG1(DBG_LIB
, "ssh-agent didn't return requested %s signature", prefix
);
350 type
= this->pubkey
->get_type(this->pubkey
);
351 if (type
== KEY_RSA
|| type
== KEY_ED25519
|| type
== KEY_ED448
)
352 { /* for RSA/EdDSA, the signature has no special encoding */
353 blob
= read_string(&blob
);
356 *signature
= chunk_clone(blob
);
361 { /* parse ECDSA signatures */
362 blob
= read_string(&blob
);
367 r
= read_string(&blob
);
368 s
= read_string(&blob
);
371 *signature
= chunk_cat("cc", r
, s
);
378 DBG1(DBG_LIB
, "received invalid ssh-agent signature response");
386 METHOD(private_key_t
, get_type
, key_type_t
,
387 private_agent_private_key_t
*this)
389 return this->pubkey
->get_type(this->pubkey
);
392 METHOD(private_key_t
, decrypt
, bool,
393 private_agent_private_key_t
*this, encryption_scheme_t scheme
,
394 void *params
, chunk_t crypto
, chunk_t
*plain
)
396 DBG1(DBG_LIB
, "private key decryption not supported by ssh-agent");
400 METHOD(private_key_t
, get_keysize
, int,
401 private_agent_private_key_t
*this)
403 return this->pubkey
->get_keysize(this->pubkey
);
407 * Private data for RSA scheme enumerator
413 } scheme_enumerator_t
;
415 static signature_params_t rsa_schemes
[] = {
416 { .scheme
= SIGN_RSA_EMSA_PKCS1_SHA2_256
},
417 { .scheme
= SIGN_RSA_EMSA_PKCS1_SHA2_512
},
420 METHOD(enumerator_t
, enumerate_rsa_scheme
, bool,
421 scheme_enumerator_t
*this, va_list args
)
423 signature_params_t
**params
;
425 VA_ARGS_VGET(args
, params
);
427 if ((this->reverse
&& --this->index
>= 0) ||
428 (!this->reverse
&& ++this->index
< countof(rsa_schemes
)))
430 *params
= &rsa_schemes
[this->index
];
437 * Create an enumerator for the supported RSA signature schemes
439 static enumerator_t
*create_rsa_enumerator(private_agent_private_key_t
*this)
441 scheme_enumerator_t
*enumerator
;
445 .enumerate
= enumerator_enumerate_default
,
446 .venumerate
= _enumerate_rsa_scheme
,
447 .destroy
= (void*)free
,
452 /* propose SHA-512 first for larger keys */
453 if (get_keysize(this) > 3072)
455 enumerator
->index
= countof(rsa_schemes
);
456 enumerator
->reverse
= TRUE
;
458 return &enumerator
->public;
461 METHOD(private_key_t
, supported_signature_schemes
, enumerator_t
*,
462 private_agent_private_key_t
*this)
464 key_type_t type
= get_type(this);
469 return create_rsa_enumerator(this);
473 return signature_schemes_for_key(type
, get_keysize(this));
477 return enumerator_create_empty();
480 METHOD(private_key_t
, get_public_key
, public_key_t
*,
481 private_agent_private_key_t
*this)
483 return this->pubkey
->get_ref(this->pubkey
);
486 METHOD(private_key_t
, get_encoding
, bool,
487 private_agent_private_key_t
*this, cred_encoding_type_t type
,
493 METHOD(private_key_t
, get_fingerprint
, bool,
494 private_agent_private_key_t
*this, cred_encoding_type_t type
, chunk_t
*fp
)
496 return this->pubkey
->get_fingerprint(this->pubkey
, type
, fp
);
499 METHOD(private_key_t
, get_ref
, private_key_t
*,
500 private_agent_private_key_t
*this)
503 return &this->public.key
;
506 METHOD(private_key_t
, destroy
, void,
507 private_agent_private_key_t
*this)
509 if (ref_put(&this->ref
))
511 chunk_free(&this->key
);
512 DESTROY_IF(this->pubkey
);
521 agent_private_key_t
*agent_private_key_open(key_type_t type
, va_list args
)
523 private_agent_private_key_t
*this;
524 public_key_t
*pubkey
= NULL
;
529 switch (va_arg(args
, builder_part_t
))
531 case BUILD_AGENT_SOCKET
:
532 path
= va_arg(args
, char*);
534 case BUILD_PUBLIC_KEY
:
535 pubkey
= va_arg(args
, public_key_t
*);
552 .get_type
= _get_type
,
553 .supported_signature_schemes
= _supported_signature_schemes
,
556 .get_keysize
= _get_keysize
,
557 .get_public_key
= _get_public_key
,
558 .belongs_to
= private_key_belongs_to
,
559 .equals
= private_key_equals
,
560 .get_fingerprint
= _get_fingerprint
,
561 .has_fingerprint
= private_key_has_fingerprint
,
562 .get_encoding
= _get_encoding
,
567 .path
= strdup(path
),
571 if (!read_key(this, pubkey
))
576 return &this->public;