1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 09:27:59 +00:00

Pageant: move signing requests out into a coroutine.

The previous commit introduced the PageantAsyncOp trait, with only one
trivial implementation. This one introduces a second implementation
used for SSH2_AGENTC_SIGN_REQUEST only, which waits to actually
construct the signature until after a callback has happened. This will
allow the signing process to be suspended in order to request a dialog
box and wait for a user response to decide _how_ to reply.

Suspended signing operations relating to a particular key are held in
a linked list dangling from the corresponding PageantKey structure.
This will allow them all to be found easily if that key should be
deleted from the agent: in that situation pending signatures from the
key will all return SSH_AGENT_FAILURE.

Still no functional change, however: the new coroutine doesn't
actually wait for anything, it just contains a comment noting that it
could if it wanted to.
This commit is contained in:
Simon Tatham 2020-01-25 17:25:28 +00:00
parent de38a4d826
commit 7bcbc79818

View File

@ -99,6 +99,18 @@ struct PageantKey {
RSAKey *rkey; /* if ssh_version == 1 */
ssh2_userkey *skey; /* if ssh_version == 2 */
};
PageantKeyRequestNode blocked_requests;
};
typedef struct PageantSignOp PageantSignOp;
struct PageantSignOp {
PageantKey *pk;
strbuf *data_to_sign;
unsigned flags;
int crLine;
PageantKeyRequestNode pkr;
PageantAsyncOp pao;
};
static void failure(PageantClient *pc, PageantClientRequestId *reqid,
@ -117,6 +129,19 @@ static void pk_free(PageantKey *pk)
ssh_key_free(pk->skey->key);
sfree(pk->skey);
}
while (pk->blocked_requests.next != &pk->blocked_requests) {
PageantSignOp *so = container_of(pk->blocked_requests.next,
PageantSignOp, pkr);
so->pkr.next->prev = so->pkr.prev;
so->pkr.prev->next = so->pkr.next;
strbuf *sb = strbuf_new();
failure(so->pao.info->pc, so->pao.reqid, sb,
"key deleted from Pageant while signing request was pending");
pageant_client_got_response(so->pao.info->pc, so->pao.reqid,
ptrlen_from_strbuf(sb));
strbuf_free(sb);
pageant_async_op_unlink_and_free(&so->pao);
}
sfree(pk);
}
@ -192,6 +217,8 @@ bool pageant_add_ssh1_key(RSAKey *rkey)
pk->sort.ssh_version = 1;
pk->public_blob = makeblob1(rkey);
pk->sort.public_blob = ptrlen_from_strbuf(pk->public_blob);
pk->blocked_requests.next = pk->blocked_requests.prev =
&pk->blocked_requests;
if (add234(keytree, pk) == pk) {
pk->rkey = rkey;
@ -211,6 +238,8 @@ bool pageant_add_ssh2_key(ssh2_userkey *skey)
pk->sort.ssh_version = 2;
pk->public_blob = makeblob2(skey);
pk->sort.public_blob = ptrlen_from_strbuf(pk->public_blob);
pk->blocked_requests.next = pk->blocked_requests.prev =
&pk->blocked_requests;
if (add234(keytree, pk) == pk) {
pk->skey = skey;
@ -294,6 +323,47 @@ static void failure(PageantClient *pc, PageantClientRequestId *reqid,
}
}
static void signop_free(PageantAsyncOp *pao)
{
PageantSignOp *so = container_of(pao, PageantSignOp, pao);
strbuf_free(so->data_to_sign);
sfree(so);
}
static void signop_coroutine(PageantAsyncOp *pao)
{
PageantSignOp *so = container_of(pao, PageantSignOp, pao);
crBegin(so->crLine);
/*
* If we want to request a user interaction, we should set it up;
* arrange that when it finishes, it re-queues
* pageant_async_op_callback; and then crReturnV so that we resume
* from after that.
*/
if (0) crReturnV;
strbuf *signature = strbuf_new();
ssh_key_sign(so->pk->skey->key, ptrlen_from_strbuf(so->data_to_sign),
so->flags, BinarySink_UPCAST(signature));
strbuf *response = strbuf_new();
put_byte(response, SSH2_AGENT_SIGN_RESPONSE);
put_stringsb(response, signature);
pageant_client_got_response(so->pao.info->pc, so->pao.reqid,
ptrlen_from_strbuf(response));
strbuf_free(response);
pageant_async_op_unlink_and_free(&so->pao);
crFinishFreedV;
}
static struct PageantAsyncOpVtable signop_vtable = {
signop_coroutine,
signop_free,
};
typedef struct PageantImmOp PageantImmOp;
struct PageantImmOp {
int crLine;
@ -474,7 +544,6 @@ void pageant_handle_msg(PageantClient *pc, PageantClientRequestId *reqid,
{
PageantKey *pk;
ptrlen keyblob, sigdata;
strbuf *signature;
uint32_t flags, supported_flags;
pageant_client_log(pc, reqid, "request: SSH2_AGENTC_SIGN_REQUEST");
@ -535,14 +604,25 @@ void pageant_handle_msg(PageantClient *pc, PageantClientRequestId *reqid,
goto responded;
}
signature = strbuf_new();
ssh_key_sign(pk->skey->key, sigdata, flags,
BinarySink_UPCAST(signature));
strbuf_free(sb); /* no immediate response */
put_byte(sb, SSH2_AGENT_SIGN_RESPONSE);
put_stringsb(sb, signature);
pageant_client_log(pc, reqid, "reply: SSH2_AGENT_SIGN_RESPONSE");
PageantSignOp *so = snew(PageantSignOp);
so->pao.vt = &signop_vtable;
so->pao.info = pc->info;
so->pao.cr.prev = pc->info->head.prev;
so->pao.cr.next = &pc->info->head;
so->pao.reqid = reqid;
so->pk = pk;
so->pkr.prev = pk->blocked_requests.prev;
so->pkr.next = &pk->blocked_requests;
so->pkr.prev->next = so->pkr.next;
so->pkr.next->prev = so->pkr.prev;
so->data_to_sign = strbuf_new();
put_datapl(so->data_to_sign, sigdata);
so->flags = flags;
so->crLine = 0;
queue_toplevel_callback(pageant_async_op_callback, &so->pao);
return;
}
break;
case SSH1_AGENTC_ADD_RSA_IDENTITY: