2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 #include "agent_private_key.h"
22 #include <sys/types.h>
23 #include <sys/socket.h>
25 #include <arpa/inet.h>
31 #include <asn1/asn1.h>
35 #define UNIX_PATH_MAX 108
36 #endif /* UNIX_PATH_MAX */
38 typedef struct private_agent_private_key_t private_agent_private_key_t
;
39 typedef enum agent_msg_type_t agent_msg_type_t
;
42 * Private data of a agent_private_key_t object.
44 struct private_agent_private_key_t
{
46 * Public interface for this signer.
48 agent_private_key_t
public;
51 * ssh-agent unix socket connection
56 * key identity blob in ssh format
66 * Keyid formed as a SHA-1 hash of a publicKey object
68 identification_t
* keyid
;
71 * Keyid formed as a SHA-1 hash of a publicKeyInfo object
73 identification_t
* keyid_info
;
82 * Message types for ssh-agent protocol
84 enum agent_msg_type_t
{
85 SSH_AGENT_FAILURE
= 5,
86 SSH_AGENT_SUCCESS
= 6,
87 SSH_AGENT_ID_REQUEST
= 11,
88 SSH_AGENT_ID_RESPONSE
= 12,
89 SSH_AGENT_SIGN_REQUEST
= 13,
90 SSH_AGENT_SIGN_RESPONSE
= 14,
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 u_int32_t from a blob
112 static u_int32_t
read_uint32(chunk_t
*blob
)
116 if (blob
->len
< sizeof(u_int32_t
))
120 val
= ntohl(*(u_int32_t
*)blob
->ptr
);
121 *blob
= chunk_skip(*blob
, sizeof(u_int32_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("opening ssh-agent socket %s failed: %s:", path
, strerror(errno
));
158 addr
.sun_family
= AF_UNIX
;
159 addr
.sun_path
[UNIX_PATH_MAX
- 1] = '\0';
160 strncpy(addr
.sun_path
, path
, UNIX_PATH_MAX
- 1);
162 if (connect(s
, (struct sockaddr
*)&addr
, SUN_LEN(&addr
)) != 0)
164 DBG1("connecting to ssh-agent socket failed: %s", strerror(errno
));
172 * check if the ssh agent key blob matches to our public key
174 static bool matches_pubkey(chunk_t key
, public_key_t
*pubkey
)
176 chunk_t pubkeydata
, hash
, n
, e
;
178 identification_t
*id
;
186 e
= read_string(&key
);
187 n
= read_string(&key
);
188 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
193 pubkeydata
= asn1_wrap(ASN1_SEQUENCE
, "mm",
194 asn1_wrap(ASN1_INTEGER
, "c", n
),
195 asn1_wrap(ASN1_INTEGER
, "c", e
));
196 hasher
->allocate_hash(hasher
, pubkeydata
, &hash
);
197 free(pubkeydata
.ptr
);
198 id
= pubkey
->get_id(pubkey
, ID_PUBKEY_SHA1
);
203 match
= chunk_equals(id
->get_encoding(id
), hash
);
209 * Get the first usable key from the agent
211 static bool read_key(private_agent_private_key_t
*this, public_key_t
*pubkey
)
215 chunk_t blob
= chunk_from_buf(buf
), key
, type
, tmp
;
218 write(this->socket
, &len
, sizeof(len
));
219 buf
[0] = SSH_AGENT_ID_REQUEST
;
220 write(this->socket
, &buf
, 1);
222 blob
.len
= read(this->socket
, blob
.ptr
, blob
.len
);
224 if (blob
.len
< sizeof(u_int32_t
) + sizeof(u_char
) ||
225 read_uint32(&blob
) != blob
.len
||
226 read_byte(&blob
) != SSH_AGENT_ID_RESPONSE
)
228 DBG1("received invalid ssh-agent identity response");
231 count
= read_uint32(&blob
);
235 key
= read_string(&blob
);
239 type
= read_string(&tmp
);
241 tmp
= read_string(&tmp
);
242 if (type
.len
&& strneq("ssh-rsa", type
.ptr
, type
.len
) &&
243 tmp
.len
>= 512/8 && matches_pubkey(key
, pubkey
))
245 this->key
= chunk_clone(key
);
246 this->key_size
= tmp
.len
;
261 * Implementation of agent_private_key.destroy.
263 static bool sign(private_agent_private_key_t
*this, signature_scheme_t scheme
,
264 chunk_t data
, chunk_t
*signature
)
266 u_int32_t len
, flags
;
268 chunk_t blob
= chunk_from_buf(buf
);
270 if (scheme
!= SIGN_DEFAULT
&& scheme
!= SIGN_RSA_EMSA_PKCS1_SHA1
)
272 DBG1("signature scheme %N not supported by ssh-agent",
273 signature_scheme_names
, scheme
);
277 len
= htonl(1 + sizeof(u_int32_t
) * 3 + this->key
.len
+ data
.len
);
278 write(this->socket
, &len
, sizeof(len
));
279 buf
[0] = SSH_AGENT_SIGN_REQUEST
;
280 write(this->socket
, &buf
, 1);
282 len
= htonl(this->key
.len
);
283 write(this->socket
, &len
, sizeof(len
));
284 write(this->socket
, this->key
.ptr
, this->key
.len
);
286 len
= htonl(data
.len
);
287 write(this->socket
, &len
, sizeof(len
));
288 write(this->socket
, data
.ptr
, data
.len
);
291 write(this->socket
, &flags
, sizeof(flags
));
293 blob
.len
= read(this->socket
, blob
.ptr
, blob
.len
);
294 if (blob
.len
< sizeof(u_int32_t
) + sizeof(u_char
) ||
295 read_uint32(&blob
) != blob
.len
||
296 read_byte(&blob
) != SSH_AGENT_SIGN_RESPONSE
)
298 DBG1("received invalid ssh-agent signature response");
302 blob
= read_string(&blob
);
306 blob
= read_string(&blob
);
309 DBG1("received invalid ssh-agent signature response");
312 *signature
= chunk_clone(blob
);
317 * Implementation of agent_private_key.destroy.
319 static key_type_t
get_type(private_agent_private_key_t
*this)
325 * Implementation of agent_private_key.destroy.
327 static bool decrypt(private_agent_private_key_t
*this,
328 chunk_t crypto
, chunk_t
*plain
)
330 DBG1("private key decryption not supported by ssh-agent");
335 * Implementation of agent_private_key.destroy.
337 static size_t get_keysize(private_agent_private_key_t
*this)
339 return this->key_size
;
343 * Implementation of agent_private_key.destroy.
345 static identification_t
* get_id(private_agent_private_key_t
*this,
350 case ID_PUBKEY_INFO_SHA1
:
351 return this->keyid_info
;
360 * Implementation of agent_private_key.get_public_key.
362 static public_key_t
* get_public_key(private_agent_private_key_t
*this)
364 chunk_t key
, n
, e
, encoded
;
365 public_key_t
*public;
369 e
= read_string(&key
);
370 n
= read_string(&key
);
371 encoded
= asn1_wrap(ASN1_SEQUENCE
, "mm",
372 asn1_wrap(ASN1_INTEGER
, "c", n
),
373 asn1_wrap(ASN1_INTEGER
, "c", e
));
375 public = lib
->creds
->create(lib
->creds
, CRED_PUBLIC_KEY
, KEY_RSA
,
376 BUILD_BLOB_ASN1_DER
, encoded
, BUILD_END
);
382 * Implementation of agent_private_key.belongs_to.
384 static bool belongs_to(private_agent_private_key_t
*this, public_key_t
*public)
386 identification_t
*keyid
;
388 if (public->get_type(public) != KEY_RSA
)
392 keyid
= public->get_id(public, ID_PUBKEY_SHA1
);
393 if (keyid
&& keyid
->equals(keyid
, this->keyid
))
397 keyid
= public->get_id(public, ID_PUBKEY_INFO_SHA1
);
398 if (keyid
&& keyid
->equals(keyid
, this->keyid_info
))
406 * Build the RSA key identifier from n and e using SHA1 hashed publicKey(Info).
408 static bool build_ids(private_agent_private_key_t
*this)
410 chunk_t publicKeyInfo
, publicKey
, hash
, key
, n
, e
;
415 e
= read_string(&key
);
416 n
= read_string(&key
);
418 hasher
= lib
->crypto
->create_hasher(lib
->crypto
, HASH_SHA1
);
421 DBG1("SHA1 hash algorithm not supported, unable to use RSA");
424 publicKey
= asn1_wrap(ASN1_SEQUENCE
, "mm",
425 asn1_wrap(ASN1_INTEGER
, "c", n
),
426 asn1_wrap(ASN1_INTEGER
, "c", e
));
427 hasher
->allocate_hash(hasher
, publicKey
, &hash
);
428 this->keyid
= identification_create_from_encoding(ID_PUBKEY_SHA1
, hash
);
431 publicKeyInfo
= asn1_wrap(ASN1_SEQUENCE
, "cm",
432 asn1_algorithmIdentifier(OID_RSA_ENCRYPTION
),
433 asn1_bitstring("m", publicKey
));
434 hasher
->allocate_hash(hasher
, publicKeyInfo
, &hash
);
435 this->keyid_info
= identification_create_from_encoding(ID_PUBKEY_INFO_SHA1
, hash
);
438 hasher
->destroy(hasher
);
439 chunk_free(&publicKeyInfo
);
444 * Implementation of private_key_t.get_encoding.
446 static chunk_t
get_encoding(private_agent_private_key_t
*this)
452 * Implementation of agent_private_key.get_ref.
454 static private_agent_private_key_t
* get_ref(private_agent_private_key_t
*this)
461 * Implementation of agent_private_key.destroy.
463 static void destroy(private_agent_private_key_t
*this)
465 if (ref_put(&this->ref
))
468 DESTROY_IF(this->keyid
);
469 DESTROY_IF(this->keyid_info
);
476 * Internal constructor
478 static agent_private_key_t
*agent_private_key_create(char *path
,
479 public_key_t
*pubkey
)
481 private_agent_private_key_t
*this = malloc_thing(private_agent_private_key_t
);
483 this->public.interface
.get_type
= (key_type_t (*)(private_key_t
*this))get_type
;
484 this->public.interface
.sign
= (bool (*)(private_key_t
*this, signature_scheme_t scheme
, chunk_t data
, chunk_t
*signature
))sign
;
485 this->public.interface
.decrypt
= (bool (*)(private_key_t
*this, chunk_t crypto
, chunk_t
*plain
))decrypt
;
486 this->public.interface
.get_keysize
= (size_t (*) (private_key_t
*this))get_keysize
;
487 this->public.interface
.get_id
= (identification_t
* (*) (private_key_t
*this,id_type_t
))get_id
;
488 this->public.interface
.get_public_key
= (public_key_t
* (*)(private_key_t
*this))get_public_key
;
489 this->public.interface
.belongs_to
= (bool (*) (private_key_t
*this, public_key_t
*public))belongs_to
;
490 this->public.interface
.get_encoding
= (chunk_t(*)(private_key_t
*))get_encoding
;
491 this->public.interface
.get_ref
= (private_key_t
* (*)(private_key_t
*this))get_ref
;
492 this->public.interface
.destroy
= (void (*)(private_key_t
*this))destroy
;
494 this->socket
= open_connection(path
);
495 if (this->socket
< 0)
500 this->key
= chunk_empty
;
502 this->keyid_info
= NULL
;
504 if (!read_key(this, pubkey
) || !build_ids(this))
509 return &this->public;
512 typedef struct private_builder_t private_builder_t
;
514 * Builder implementation for key loading/generation
516 struct private_builder_t
{
517 /** implements the builder interface */
519 /** agent unix socket */
521 /** matching public key */
522 public_key_t
*pubkey
;
526 * Implementation of builder_t.build
528 static agent_private_key_t
*build(private_builder_t
*this)
530 agent_private_key_t
*key
= NULL
;
534 key
= agent_private_key_create(this->socket
, this->pubkey
);
541 * Implementation of builder_t.add
543 static void add(private_builder_t
*this, builder_part_t part
, ...)
549 case BUILD_AGENT_SOCKET
:
551 va_start(args
, part
);
552 this->socket
= va_arg(args
, char*);
556 case BUILD_PUBLIC_KEY
:
558 va_start(args
, part
);
559 this->pubkey
= va_arg(args
, public_key_t
*);
566 builder_cancel(&this->public);
570 * Builder construction function
572 builder_t
*agent_private_key_builder(key_type_t type
)
574 private_builder_t
*this;
581 this = malloc_thing(private_builder_t
);
585 this->public.add
= (void(*)(builder_t
*this, builder_part_t part
, ...))add
;
586 this->public.build
= (void*(*)(builder_t
*this))build
;
588 return &this->public;