42
#include "libssh2_priv.h"
56
#if defined(_WIN32) && !defined(LIBSSH2_WINDOWS_UWP)
57
#define HAVE_WIN32_AGENTS
65
#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
66
#define SSH_AGENTC_RSA_CHALLENGE 3
67
#define SSH_AGENTC_ADD_RSA_IDENTITY 7
68
#define SSH_AGENTC_REMOVE_RSA_IDENTITY 8
69
#define SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES 9
70
#define SSH_AGENTC_ADD_RSA_ID_CONSTRAINED 24
74
#define SSH2_AGENTC_REQUEST_IDENTITIES 11
75
#define SSH2_AGENTC_SIGN_REQUEST 13
77
#define SSH2_AGENTC_ADD_IDENTITY 17
78
#define SSH2_AGENTC_REMOVE_IDENTITY 18
79
#define SSH2_AGENTC_REMOVE_ALL_IDENTITIES 19
80
#define SSH2_AGENTC_ADD_ID_CONSTRAINED 25
83
#define SSH_AGENTC_ADD_SMARTCARD_KEY 20
84
#define SSH_AGENTC_REMOVE_SMARTCARD_KEY 21
85
#define SSH_AGENTC_LOCK 22
86
#define SSH_AGENTC_UNLOCK 23
87
#define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26
90
#define SSH_AGENT_FAILURE 5
91
#define SSH_AGENT_SUCCESS 6
94
#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2
95
#define SSH_AGENT_RSA_RESPONSE 4
98
#define SSH_AGENT_CONSTRAIN_LIFETIME 1
99
#define SSH_AGENT_CONSTRAIN_CONFIRM 2
103
#define SSH2_AGENT_IDENTITIES_ANSWER 12
104
#define SSH2_AGENT_SIGN_RESPONSE 14
107
#define SSH_AGENT_RSA_SHA2_256 2
108
#define SSH_AGENT_RSA_SHA2_512 4
113
agent_NB_state_init = 0,
114
agent_NB_state_request_created,
115
agent_NB_state_request_length_sent,
116
agent_NB_state_request_sent,
117
agent_NB_state_response_length_received,
118
agent_NB_state_response_received
119
} agent_nonblocking_states;
121
typedef struct agent_transaction_ctx {
122
unsigned char *request;
124
unsigned char *response;
126
agent_nonblocking_states state;
127
size_t send_recv_total;
128
} *agent_transaction_ctx_t;
130
typedef int (*agent_connect_func)(LIBSSH2_AGENT *agent);
131
typedef int (*agent_transact_func)(LIBSSH2_AGENT *agent,
132
agent_transaction_ctx_t transctx);
133
typedef int (*agent_disconnect_func)(LIBSSH2_AGENT *agent);
135
struct agent_publickey {
136
struct list_node node;
139
struct libssh2_agent_publickey external;
143
const agent_connect_func connect;
144
const agent_transact_func transact;
145
const agent_disconnect_func disconnect;
150
LIBSSH2_SESSION *session;
154
struct agent_ops *ops;
156
struct agent_transaction_ctx transctx;
157
struct agent_publickey *identity;
158
struct list_head head;
160
char *identity_agent_path;
162
#ifdef HAVE_WIN32_AGENTS
163
OVERLAPPED overlapped;
169
#include "agent_win.c"
173
agent_connect_unix(LIBSSH2_AGENT *agent)
176
struct sockaddr_un s_un;
178
path = agent->identity_agent_path;
180
path = getenv("SSH_AUTH_SOCK");
182
return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE,
183
"no auth sock variable");
186
agent->fd = socket(PF_UNIX, SOCK_STREAM, 0);
188
return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_SOCKET,
189
"failed creating socket");
191
s_un.sun_family = AF_UNIX;
192
strncpy(s_un.sun_path, path, sizeof(s_un.sun_path));
193
s_un.sun_path[sizeof(s_un.sun_path)-1] = 0;
195
if(connect(agent->fd, (struct sockaddr*)(&s_un), sizeof(s_un)) != 0) {
197
return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
198
"failed connecting with agent");
201
return LIBSSH2_ERROR_NONE;
204
#define RECV_SEND_ALL(func, socket, buffer, length, flags, abstract) \
206
size_t finished = 0; \
208
while(finished < length) { \
211
(char *)buffer + finished, length - finished, \
222
static ssize_t _send_all(LIBSSH2_SEND_FUNC(func), libssh2_socket_t socket,
223
const void *buffer, size_t length,
224
int flags, void **abstract)
226
RECV_SEND_ALL(func, socket, buffer, length, flags, abstract);
229
static ssize_t _recv_all(LIBSSH2_RECV_FUNC(func), libssh2_socket_t socket,
230
void *buffer, size_t length,
231
int flags, void **abstract)
233
RECV_SEND_ALL(func, socket, buffer, length, flags, abstract);
239
agent_transact_unix(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
241
unsigned char buf[4];
245
if(transctx->state == agent_NB_state_request_created) {
246
_libssh2_htonu32(buf, (uint32_t)transctx->request_len);
247
rc = (int)_send_all(agent->session->send, agent->fd,
249
&agent->session->abstract);
251
return LIBSSH2_ERROR_EAGAIN;
253
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
254
"agent send failed");
255
transctx->state = agent_NB_state_request_length_sent;
259
if(transctx->state == agent_NB_state_request_length_sent) {
260
rc = (int)_send_all(agent->session->send, agent->fd,
261
transctx->request, transctx->request_len, 0,
262
&agent->session->abstract);
264
return LIBSSH2_ERROR_EAGAIN;
266
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
267
"agent send failed");
268
transctx->state = agent_NB_state_request_sent;
272
if(transctx->state == agent_NB_state_request_sent) {
273
rc = (int)_recv_all(agent->session->recv, agent->fd,
275
&agent->session->abstract);
278
return LIBSSH2_ERROR_EAGAIN;
279
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_RECV,
280
"agent recv failed");
282
transctx->response_len = _libssh2_ntohu32(buf);
283
transctx->response = LIBSSH2_ALLOC(agent->session,
284
transctx->response_len);
285
if(!transctx->response)
286
return LIBSSH2_ERROR_ALLOC;
288
transctx->state = agent_NB_state_response_length_received;
292
if(transctx->state == agent_NB_state_response_length_received) {
293
rc = (int)_recv_all(agent->session->recv, agent->fd,
294
transctx->response, transctx->response_len, 0,
295
&agent->session->abstract);
298
return LIBSSH2_ERROR_EAGAIN;
299
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_SEND,
300
"agent recv failed");
302
transctx->state = agent_NB_state_response_received;
309
agent_disconnect_unix(LIBSSH2_AGENT *agent)
312
ret = close(agent->fd);
314
agent->fd = LIBSSH2_INVALID_SOCKET;
316
return _libssh2_error(agent->session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
317
"failed closing the agent socket");
318
return LIBSSH2_ERROR_NONE;
321
static struct agent_ops agent_ops_unix = {
324
agent_disconnect_unix
328
#ifdef HAVE_WIN32_AGENTS
336
#define PAGEANT_COPYDATA_ID 0x804e50ba
337
#define PAGEANT_MAX_MSGLEN 8192
340
agent_connect_pageant(LIBSSH2_AGENT *agent)
343
hwnd = FindWindowA("Pageant", "Pageant");
345
return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
346
"failed connecting agent");
348
return LIBSSH2_ERROR_NONE;
352
agent_transact_pageant(LIBSSH2_AGENT *agent, agent_transaction_ctx_t transctx)
362
if(!transctx || 4 + transctx->request_len > PAGEANT_MAX_MSGLEN)
363
return _libssh2_error(agent->session, LIBSSH2_ERROR_INVAL,
366
hwnd = FindWindowA("Pageant", "Pageant");
368
return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
371
snprintf(mapname, sizeof(mapname),
372
"PageantRequest%08x", (unsigned)GetCurrentThreadId());
373
filemap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
374
0, PAGEANT_MAX_MSGLEN, mapname);
376
if(!filemap || filemap == INVALID_HANDLE_VALUE)
377
return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
378
"failed setting up pageant filemap");
380
p2 = p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, 0);
382
CloseHandle(filemap);
383
return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
384
"failed to open pageant filemap for writing");
387
_libssh2_store_str(&p2, (const char *)transctx->request,
388
transctx->request_len);
390
cds.dwData = PAGEANT_COPYDATA_ID;
391
cds.cbData = (DWORD)(1 + strlen(mapname));
392
cds.lpData = mapname;
394
id = SendMessage(hwnd, WM_COPYDATA, (WPARAM) NULL, (LPARAM) &cds);
396
transctx->response_len = _libssh2_ntohu32(p);
397
if(transctx->response_len > PAGEANT_MAX_MSGLEN) {
399
CloseHandle(filemap);
400
return _libssh2_error(agent->session, LIBSSH2_ERROR_AGENT_PROTOCOL,
403
transctx->response = LIBSSH2_ALLOC(agent->session,
404
transctx->response_len);
405
if(!transctx->response) {
407
CloseHandle(filemap);
408
return _libssh2_error(agent->session, LIBSSH2_ERROR_ALLOC,
411
memcpy(transctx->response, p + 4, transctx->response_len);
415
CloseHandle(filemap);
420
agent_disconnect_pageant(LIBSSH2_AGENT *agent)
422
agent->fd = LIBSSH2_INVALID_SOCKET;
426
static struct agent_ops agent_ops_pageant = {
427
agent_connect_pageant,
428
agent_transact_pageant,
429
agent_disconnect_pageant
435
struct agent_ops *ops;
436
} supported_backends[] = {
437
#ifdef HAVE_WIN32_AGENTS
438
{"Pageant", &agent_ops_pageant},
439
{"OpenSSH", &agent_ops_openssh},
442
{"Unix", &agent_ops_unix},
448
agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len,
449
const unsigned char *data, size_t data_len, void **abstract)
451
LIBSSH2_AGENT *agent = (LIBSSH2_AGENT *) (*abstract);
452
agent_transaction_ctx_t transctx = &agent->transctx;
453
struct agent_publickey *identity = agent->identity;
454
ssize_t len = 1 + 4 + identity->external.blob_len + 4 + data_len + 4;
458
unsigned char *method_name = NULL;
459
uint32_t sign_flags = 0;
463
if(transctx->state == agent_NB_state_init) {
464
s = transctx->request = LIBSSH2_ALLOC(session, len);
465
if(!transctx->request)
466
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
469
*s++ = SSH2_AGENTC_SIGN_REQUEST;
471
_libssh2_store_str(&s, (const char *)identity->external.blob,
472
identity->external.blob_len);
474
_libssh2_store_str(&s, (const char *)data, data_len);
477
if(session->userauth_pblc_method_len > 0 &&
478
session->userauth_pblc_method) {
479
if(session->userauth_pblc_method_len == 12 &&
480
!memcmp(session->userauth_pblc_method, "rsa-sha2-512", 12)) {
481
sign_flags = SSH_AGENT_RSA_SHA2_512;
483
else if(session->userauth_pblc_method_len == 12 &&
484
!memcmp(session->userauth_pblc_method, "rsa-sha2-256", 12)) {
485
sign_flags = SSH_AGENT_RSA_SHA2_256;
488
_libssh2_store_u32(&s, sign_flags);
490
transctx->request_len = s - transctx->request;
491
transctx->send_recv_total = 0;
492
transctx->state = agent_NB_state_request_created;
496
if(*transctx->request != SSH2_AGENTC_SIGN_REQUEST)
497
return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE,
502
return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE,
503
"agent not connected");
505
rc = agent->ops->transact(agent, transctx);
509
LIBSSH2_FREE(session, transctx->request);
510
transctx->request = NULL;
512
len = transctx->response_len;
513
s = transctx->response;
516
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
519
if(*s != SSH2_AGENT_SIGN_RESPONSE) {
520
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
528
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
536
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
539
method_len = _libssh2_ntohu32(s);
543
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
548
method_name = LIBSSH2_ALLOC(session, method_len);
550
rc = LIBSSH2_ERROR_ALLOC;
553
memcpy(method_name, s, method_len);
556
plain_len = plain_method((char *)session->userauth_pblc_method,
557
session->userauth_pblc_method_len);
560
if(((size_t)method_len != session->userauth_pblc_method_len &&
561
method_len != plain_len) ||
562
memcmp(method_name, session->userauth_pblc_method, method_len)) {
563
_libssh2_debug((session,
565
"Agent sign method %.*s",
566
(int)method_len, method_name));
568
rc = LIBSSH2_ERROR_ALGO_UNSUPPORTED;
575
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
578
*sig_len = _libssh2_ntohu32(s);
582
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
586
*sig = LIBSSH2_ALLOC(session, *sig_len);
588
rc = LIBSSH2_ERROR_ALLOC;
591
memcpy(*sig, s, *sig_len);
596
LIBSSH2_FREE(session, method_name);
598
LIBSSH2_FREE(session, transctx->request);
599
transctx->request = NULL;
601
LIBSSH2_FREE(session, transctx->response);
602
transctx->response = NULL;
604
transctx->state = agent_NB_state_init;
606
return _libssh2_error(session, rc, "agent sign failure");
610
agent_list_identities(LIBSSH2_AGENT *agent)
612
agent_transaction_ctx_t transctx = &agent->transctx;
613
ssize_t len, num_identities;
616
unsigned char c = SSH2_AGENTC_REQUEST_IDENTITIES;
619
if(transctx->state == agent_NB_state_init) {
620
transctx->request = &c;
621
transctx->request_len = 1;
622
transctx->send_recv_total = 0;
623
transctx->state = agent_NB_state_request_created;
627
if(*transctx->request != SSH2_AGENTC_REQUEST_IDENTITIES)
628
return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE,
629
"illegal agent request");
633
return _libssh2_error(agent->session, LIBSSH2_ERROR_BAD_USE,
634
"agent not connected");
636
rc = agent->ops->transact(agent, transctx);
638
LIBSSH2_FREE(agent->session, transctx->response);
639
transctx->response = NULL;
642
transctx->request = NULL;
644
len = transctx->response_len;
645
s = transctx->response;
648
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
651
if(*s != SSH2_AGENT_IDENTITIES_ANSWER) {
652
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
660
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
663
num_identities = _libssh2_ntohu32(s);
666
while(num_identities--) {
667
struct agent_publickey *identity;
673
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
676
identity = LIBSSH2_ALLOC(agent->session, sizeof(*identity));
678
rc = LIBSSH2_ERROR_ALLOC;
681
identity->external.blob_len = _libssh2_ntohu32(s);
685
len -= identity->external.blob_len;
687
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
688
LIBSSH2_FREE(agent->session, identity);
692
identity->external.blob = LIBSSH2_ALLOC(agent->session,
693
identity->external.blob_len);
694
if(!identity->external.blob) {
695
rc = LIBSSH2_ERROR_ALLOC;
696
LIBSSH2_FREE(agent->session, identity);
699
memcpy(identity->external.blob, s, identity->external.blob_len);
700
s += identity->external.blob_len;
705
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
706
LIBSSH2_FREE(agent->session, identity->external.blob);
707
LIBSSH2_FREE(agent->session, identity);
710
comment_len = _libssh2_ntohu32(s);
713
if(comment_len > (size_t)len) {
714
rc = LIBSSH2_ERROR_AGENT_PROTOCOL;
715
LIBSSH2_FREE(agent->session, identity->external.blob);
716
LIBSSH2_FREE(agent->session, identity);
722
identity->external.comment = LIBSSH2_ALLOC(agent->session,
724
if(!identity->external.comment) {
725
rc = LIBSSH2_ERROR_ALLOC;
726
LIBSSH2_FREE(agent->session, identity->external.blob);
727
LIBSSH2_FREE(agent->session, identity);
730
identity->external.comment[comment_len] = '\0';
731
memcpy(identity->external.comment, s, comment_len);
734
_libssh2_list_add(&agent->head, &identity->node);
737
LIBSSH2_FREE(agent->session, transctx->response);
738
transctx->response = NULL;
740
return _libssh2_error(agent->session, rc,
741
"agent list id failed");
745
agent_free_identities(LIBSSH2_AGENT *agent)
747
struct agent_publickey *node;
748
struct agent_publickey *next;
750
for(node = _libssh2_list_first(&agent->head); node; node = next) {
751
next = _libssh2_list_next(&node->node);
752
LIBSSH2_FREE(agent->session, node->external.blob);
753
LIBSSH2_FREE(agent->session, node->external.comment);
754
LIBSSH2_FREE(agent->session, node);
756
_libssh2_list_init(&agent->head);
759
#define AGENT_PUBLICKEY_MAGIC 0x3bdefed2
766
static struct libssh2_agent_publickey *
767
agent_publickey_to_external(struct agent_publickey *node)
769
struct libssh2_agent_publickey *ext = &node->external;
771
ext->magic = AGENT_PUBLICKEY_MAGIC;
783
LIBSSH2_API LIBSSH2_AGENT *
784
libssh2_agent_init(LIBSSH2_SESSION *session)
786
LIBSSH2_AGENT *agent;
788
agent = LIBSSH2_CALLOC(session, sizeof(*agent));
790
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
791
"Unable to allocate space for agent connection");
794
agent->fd = LIBSSH2_INVALID_SOCKET;
795
agent->session = session;
796
agent->identity_agent_path = NULL;
797
_libssh2_list_init(&agent->head);
799
#ifdef HAVE_WIN32_AGENTS
800
agent->pipe = INVALID_HANDLE_VALUE;
801
memset(&agent->overlapped, 0, sizeof(OVERLAPPED));
802
agent->pending_io = FALSE;
816
libssh2_agent_connect(LIBSSH2_AGENT *agent)
819
for(i = 0; supported_backends[i].name; i++) {
820
agent->ops = supported_backends[i].ops;
821
rc = (agent->ops->connect)(agent);
836
libssh2_agent_list_identities(LIBSSH2_AGENT *agent)
838
memset(&agent->transctx, 0, sizeof(agent->transctx));
840
agent_free_identities(agent);
841
return agent_list_identities(agent);
857
libssh2_agent_get_identity(LIBSSH2_AGENT *agent,
858
struct libssh2_agent_publickey **ext,
859
struct libssh2_agent_publickey *oprev)
861
struct agent_publickey *node;
862
if(oprev && oprev->node) {
864
struct agent_publickey *prev = oprev->node;
867
node = _libssh2_list_next(&prev->node);
870
node = _libssh2_list_first(&agent->head);
876
*ext = agent_publickey_to_external(node);
889
libssh2_agent_userauth(LIBSSH2_AGENT *agent,
890
const char *username,
891
struct libssh2_agent_publickey *identity)
893
void *abstract = agent;
896
if(agent->session->userauth_pblc_state == libssh2_NB_state_idle) {
897
memset(&agent->transctx, 0, sizeof(agent->transctx));
898
agent->identity = identity->node;
901
BLOCK_ADJUST(rc, agent->session,
902
_libssh2_userauth_publickey(agent->session, username,
919
libssh2_agent_sign(LIBSSH2_AGENT *agent,
920
struct libssh2_agent_publickey *identity,
923
const unsigned char *data,
926
unsigned int method_len)
928
void *abstract = agent;
932
if(agent->session->userauth_pblc_state == libssh2_NB_state_idle) {
933
memset(&agent->transctx, 0, sizeof(agent->transctx));
934
agent->identity = identity->node;
937
if(identity->blob_len < sizeof(uint32_t)) {
938
return LIBSSH2_ERROR_BUFFER_TOO_SMALL;
941
methodLen = _libssh2_ntohu32(identity->blob);
943
if(identity->blob_len < sizeof(uint32_t) + methodLen) {
944
return LIBSSH2_ERROR_BUFFER_TOO_SMALL;
947
agent->session->userauth_pblc_method_len = method_len;
948
agent->session->userauth_pblc_method = LIBSSH2_ALLOC(agent->session,
951
memcpy(agent->session->userauth_pblc_method, method, methodLen);
953
rc = agent_sign(agent->session, sig, s_len, data, d_len, &abstract);
955
LIBSSH2_FREE(agent->session, agent->session->userauth_pblc_method);
956
agent->session->userauth_pblc_method = NULL;
957
agent->session->userauth_pblc_method_len = 0;
970
libssh2_agent_disconnect(LIBSSH2_AGENT *agent)
972
if(agent->ops && agent->fd != LIBSSH2_INVALID_SOCKET)
973
return agent->ops->disconnect(agent);
984
libssh2_agent_free(LIBSSH2_AGENT *agent)
987
if(agent->fd != LIBSSH2_INVALID_SOCKET) {
988
libssh2_agent_disconnect(agent);
991
if(agent->identity_agent_path)
992
LIBSSH2_FREE(agent->session, agent->identity_agent_path);
994
agent_free_identities(agent);
995
LIBSSH2_FREE(agent->session, agent);
1005
libssh2_agent_set_identity_path(LIBSSH2_AGENT *agent, const char *path)
1007
if(agent->identity_agent_path) {
1008
LIBSSH2_FREE(agent->session, agent->identity_agent_path);
1009
agent->identity_agent_path = NULL;
1013
size_t path_len = strlen(path);
1014
if(path_len < SIZE_MAX - 1) {
1015
char *path_buf = LIBSSH2_ALLOC(agent->session, path_len + 1);
1016
memcpy(path_buf, path, path_len);
1017
path_buf[path_len] = '\0';
1018
agent->identity_agent_path = path_buf;
1029
LIBSSH2_API const char *libssh2_agent_get_identity_path(LIBSSH2_AGENT *agent)
1031
return agent->identity_agent_path;