/* Convert success/failure response from agent to a err.h status */ static int decode_reply(u_char type) { if (agent_failed(type)) return SSH_ERR_AGENT_FAILURE; else if (type == SSH_AGENT_SUCCESS) return 0; else return SSH_ERR_INVALID_FORMAT; }
/* ask agent to sign data, returns err.h code on error, 0 on success */ int ssh_agent_sign(int sock, struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat) { struct sshbuf *msg; u_char *blob = NULL, type; size_t blen = 0, len = 0; u_int flags = 0; int r = SSH_ERR_INTERNAL_ERROR; if (sigp != NULL) *sigp = NULL; if (lenp != NULL) *lenp = 0; if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) return SSH_ERR_INVALID_ARGUMENT; if (compat & SSH_BUG_SIGBLOB) flags |= SSH_AGENT_OLD_SIGNATURE; if ((msg = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshkey_to_blob(key, &blob, &blen)) != 0) goto out; if ((r = sshbuf_put_u8(msg, SSH2_AGENTC_SIGN_REQUEST)) != 0 || (r = sshbuf_put_string(msg, blob, blen)) != 0 || (r = sshbuf_put_string(msg, data, datalen)) != 0 || (r = sshbuf_put_u32(msg, flags)) != 0) goto out; if ((r = ssh_request_reply(sock, msg, msg) != 0)) goto out; if ((r = sshbuf_get_u8(msg, &type)) != 0) goto out; if (agent_failed(type)) { r = SSH_ERR_AGENT_FAILURE; goto out; } else if (type != SSH2_AGENT_SIGN_RESPONSE) { r = SSH_ERR_INVALID_FORMAT; goto out; } if ((r = sshbuf_get_string(msg, sigp, &len)) != 0) goto out; *lenp = len; r = 0; out: if (blob != NULL) { explicit_bzero(blob, blen); free(blob); } sshbuf_free(msg); return r; }
int ssh_decrypt_challenge(AuthenticationConnection *auth, Key* key, BIGNUM *challenge, u_char session_id[16], u_int response_type, u_char response[16]) { Buffer buffer; int success = 0; int i; int type; if (key->type != KEY_RSA1) return 0; if (response_type == 0) { pamsshagentauth_logit("Compatibility with ssh protocol version 1.0 no longer supported."); return 0; } pamsshagentauth_buffer_init(&buffer); pamsshagentauth_buffer_put_char(&buffer, SSH_AGENTC_RSA_CHALLENGE); pamsshagentauth_buffer_put_int(&buffer, BN_num_bits(key->rsa->n)); pamsshagentauth_buffer_put_bignum(&buffer, key->rsa->e); pamsshagentauth_buffer_put_bignum(&buffer, key->rsa->n); pamsshagentauth_buffer_put_bignum(&buffer, challenge); pamsshagentauth_buffer_append(&buffer, session_id, 16); pamsshagentauth_buffer_put_int(&buffer, response_type); if (ssh_request_reply(auth, &buffer, &buffer) == 0) { pamsshagentauth_buffer_free(&buffer); return 0; } type = pamsshagentauth_buffer_get_char(&buffer); if (agent_failed(type)) { pamsshagentauth_logit("Agent admitted failure to authenticate using the key."); } else if (type != SSH_AGENT_RSA_RESPONSE) { pamsshagentauth_fatal("Bad authentication response: %d", type); } else { success = 1; /* * Get the response from the packet. This will abort with a * fatal error if the packet is corrupt. */ for (i = 0; i < 16; i++) response[i] = (u_char)pamsshagentauth_buffer_get_char(&buffer); } pamsshagentauth_buffer_free(&buffer); return success; }
int ssh_get_num_identities(AuthenticationConnection *auth, int version) { int type, code1 = 0, code2 = 0; Buffer request; switch (version) { case 1: code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES; code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER; break; case 2: code1 = SSH2_AGENTC_REQUEST_IDENTITIES; code2 = SSH2_AGENT_IDENTITIES_ANSWER; break; default: return 0; } /* * Send a message to the agent requesting for a list of the * identities it can represent. */ pamsshagentauth_buffer_init(&request); pamsshagentauth_buffer_put_char(&request, code1); pamsshagentauth_buffer_clear(&auth->identities); if (ssh_request_reply(auth, &request, &auth->identities) == 0) { pamsshagentauth_buffer_free(&request); return 0; } pamsshagentauth_buffer_free(&request); /* Get message type, and verify that we got a proper answer. */ type = pamsshagentauth_buffer_get_char(&auth->identities); if (agent_failed(type)) { return 0; } else if (type != code2) { pamsshagentauth_fatal("Bad authentication reply message type: %d", type); } /* Get the number of entries in the response and check it for sanity. */ auth->howmany = pamsshagentauth_buffer_get_int(&auth->identities); if ((u_int)auth->howmany > 1024) pamsshagentauth_fatal("Too many identities in authentication reply: %d", auth->howmany); return auth->howmany; }
/* ask agent to sign data, returns -1 on error, 0 on success */ int ssh_agent_sign(AuthenticationConnection *auth, Key *key, u_char **sigp, u_int *lenp, u_char *data, u_int datalen) { extern int datafellows; Buffer msg; u_char *blob; u_int blen; int type, flags = 0; int ret = -1; if (pamsshagentauth_key_to_blob(key, &blob, &blen) == 0) return -1; if (datafellows & SSH_BUG_SIGBLOB) flags = SSH_AGENT_OLD_SIGNATURE; pamsshagentauth_buffer_init(&msg); pamsshagentauth_buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); pamsshagentauth_buffer_put_string(&msg, blob, blen); pamsshagentauth_buffer_put_string(&msg, data, datalen); pamsshagentauth_buffer_put_int(&msg, flags); pamsshagentauth_xfree(blob); if (ssh_request_reply(auth, &msg, &msg) == 0) { pamsshagentauth_buffer_free(&msg); return -1; } type = pamsshagentauth_buffer_get_char(&msg); if (agent_failed(type)) { pamsshagentauth_logit("Agent admitted failure to sign using the key."); } else if (type != SSH2_AGENT_SIGN_RESPONSE) { pamsshagentauth_fatal("Bad authentication response: %d", type); } else { ret = 0; *sigp = pamsshagentauth_buffer_get_string(&msg, lenp); } pamsshagentauth_buffer_free(&msg); return ret; }
int ssh_decrypt_challenge(int sock, struct sshkey* key, BIGNUM *challenge, u_char session_id[16], u_char response[16]) { struct sshbuf *msg; int r; u_char type; if (key->type != KEY_RSA1) return SSH_ERR_INVALID_ARGUMENT; if ((msg = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_put_u8(msg, SSH_AGENTC_RSA_CHALLENGE)) != 0 || (r = sshbuf_put_u32(msg, BN_num_bits(key->rsa->n))) != 0 || (r = sshbuf_put_bignum1(msg, key->rsa->e)) != 0 || (r = sshbuf_put_bignum1(msg, key->rsa->n)) != 0 || (r = sshbuf_put_bignum1(msg, challenge)) != 0 || (r = sshbuf_put(msg, session_id, 16)) != 0 || (r = sshbuf_put_u32(msg, 1)) != 0) /* Response type for proto 1.1 */ goto out; if ((r = ssh_request_reply(sock, msg, msg)) != 0) goto out; if ((r = sshbuf_get_u8(msg, &type)) != 0) goto out; if (agent_failed(type)) { r = SSH_ERR_AGENT_FAILURE; goto out; } else if (type != SSH_AGENT_RSA_RESPONSE) { r = SSH_ERR_INVALID_FORMAT; goto out; } if ((r = sshbuf_get(msg, response, 16)) != 0) goto out; r = 0; out: sshbuf_free(msg); return r; }
/* * Fetch list of identities held by the agent. */ int ssh_fetch_identitylist(int sock, int version, struct ssh_identitylist **idlp) { u_char type, code1 = 0, code2 = 0; u_int32_t num, i; struct sshbuf *msg; struct ssh_identitylist *idl = NULL; int r; /* Determine request and expected response types */ switch (version) { case 1: code1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES; code2 = SSH_AGENT_RSA_IDENTITIES_ANSWER; break; case 2: code1 = SSH2_AGENTC_REQUEST_IDENTITIES; code2 = SSH2_AGENT_IDENTITIES_ANSWER; break; default: return SSH_ERR_INVALID_ARGUMENT; } /* * Send a message to the agent requesting for a list of the * identities it can represent. */ if ((msg = sshbuf_new()) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_put_u8(msg, code1)) != 0) goto out; if ((r = ssh_request_reply(sock, msg, msg)) != 0) goto out; /* Get message type, and verify that we got a proper answer. */ if ((r = sshbuf_get_u8(msg, &type)) != 0) goto out; if (agent_failed(type)) { r = SSH_ERR_AGENT_FAILURE; goto out; } else if (type != code2) { r = SSH_ERR_INVALID_FORMAT; goto out; } /* Get the number of entries in the response and check it for sanity. */ if ((r = sshbuf_get_u32(msg, &num)) != 0) goto out; if (num > MAX_AGENT_IDENTITIES) { r = SSH_ERR_INVALID_FORMAT; goto out; } if (num == 0) { r = SSH_ERR_AGENT_NO_IDENTITIES; goto out; } /* Deserialise the response into a list of keys/comments */ if ((idl = calloc(1, sizeof(*idl))) == NULL || (idl->keys = calloc(num, sizeof(*idl->keys))) == NULL || (idl->comments = calloc(num, sizeof(*idl->comments))) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } for (i = 0; i < num;) { switch (version) { case 1: #ifdef WITH_SSH1 if ((r = deserialise_identity1(msg, &(idl->keys[i]), &(idl->comments[i]))) != 0) goto out; #endif break; case 2: if ((r = deserialise_identity2(msg, &(idl->keys[i]), &(idl->comments[i]))) != 0) { if (r == SSH_ERR_KEY_TYPE_UNKNOWN) { /* Gracefully skip unknown key types */ num--; continue; } else goto out; } break; } i++; } idl->nkeys = num; *idlp = idl; idl = NULL; r = 0; out: sshbuf_free(msg); if (idl != NULL) ssh_free_identitylist(idl); return r; }
ssh_string ssh_agent_sign_data(ssh_session session, const ssh_key pubkey, struct ssh_buffer_struct *data) { ssh_buffer request; ssh_buffer reply; ssh_string key_blob; ssh_string sig_blob; int type = SSH2_AGENT_FAILURE; int flags = 0; uint32_t dlen; int rc; request = ssh_buffer_new(); if (request == NULL) { return NULL; } /* create request */ if (buffer_add_u8(request, SSH2_AGENTC_SIGN_REQUEST) < 0) { return NULL; } rc = ssh_pki_export_pubkey_blob(pubkey, &key_blob); if (rc < 0) { ssh_buffer_free(request); return NULL; } /* adds len + blob */ rc = buffer_add_ssh_string(request, key_blob); ssh_string_free(key_blob); if (rc < 0) { ssh_buffer_free(request); return NULL; } /* Add data */ dlen = buffer_get_rest_len(data); if (buffer_add_u32(request, htonl(dlen)) < 0) { ssh_buffer_free(request); return NULL; } if (buffer_add_data(request, buffer_get_rest(data), dlen) < 0) { ssh_buffer_free(request); return NULL; } if (buffer_add_u32(request, htonl(flags)) < 0) { ssh_buffer_free(request); return NULL; } reply = ssh_buffer_new(); if (reply == NULL) { ssh_buffer_free(request); return NULL; } /* send the request */ if (agent_talk(session, request, reply) < 0) { ssh_buffer_free(request); return NULL; } ssh_buffer_free(request); /* check if reply is valid */ if (buffer_get_u8(reply, (uint8_t *) &type) != sizeof(uint8_t)) { ssh_buffer_free(reply); return NULL; } if (agent_failed(type)) { SSH_LOG(session, SSH_LOG_WARN, "Agent reports failure in signing the key"); ssh_buffer_free(reply); return NULL; } else if (type != SSH2_AGENT_SIGN_RESPONSE) { ssh_set_error(session, SSH_FATAL, "Bad authentication response: %d", type); ssh_buffer_free(reply); return NULL; } sig_blob = buffer_get_ssh_string(reply); ssh_buffer_free(reply); return sig_blob; }
int ssh_agent_get_ident_count(struct ssh_session_struct *session) { ssh_buffer request = NULL; ssh_buffer reply = NULL; unsigned int type = 0; unsigned int c1 = 0, c2 = 0; uint32_t buf = 0; switch (session->version) { case 1: c1 = SSH_AGENTC_REQUEST_RSA_IDENTITIES; c2 = SSH_AGENT_RSA_IDENTITIES_ANSWER; break; case 2: c1 = SSH2_AGENTC_REQUEST_IDENTITIES; c2 = SSH2_AGENT_IDENTITIES_ANSWER; break; default: return 0; } /* send message to the agent requesting the list of identities */ request = ssh_buffer_new(); if (buffer_add_u8(request, c1) < 0) { ssh_set_error(session, SSH_FATAL, "Not enough space"); return -1; } reply = ssh_buffer_new(); if (reply == NULL) { ssh_set_error(session, SSH_FATAL, "Not enough space"); return -1; } if (agent_talk(session, request, reply) < 0) { ssh_buffer_free(request); return 0; } ssh_buffer_free(request); /* get message type and verify the answer */ buffer_get_u8(reply, (uint8_t *) &type); SSH_LOG(session, SSH_LOG_WARN, "Answer type: %d, expected answer: %d", type, c2); if (agent_failed(type)) { return 0; } else if (type != c2) { ssh_set_error(session, SSH_FATAL, "Bad authentication reply message type: %d", type); return -1; } buffer_get_u32(reply, &buf); session->agent->count = agent_get_u32((uint8_t*)&buf); SSH_LOG(session, SSH_LOG_DEBUG, "Agent count: %d", session->agent->count); if (session->agent->count > 1024) { ssh_set_error(session, SSH_FATAL, "Too many identities in authentication reply: %d", session->agent->count); ssh_buffer_free(reply); return -1; } if (session->agent->ident) { buffer_reinit(session->agent->ident); } session->agent->ident = reply; return session->agent->count; }
ssh_string agent_sign_data(struct ssh_session_struct *session, struct ssh_buffer_struct *data, struct ssh_public_key_struct *pubkey) { struct ssh_string_struct *blob = NULL; struct ssh_string_struct *sig = NULL; struct ssh_buffer_struct *request = NULL; struct ssh_buffer_struct *reply = NULL; int type = SSH2_AGENT_FAILURE; int flags = 0; uint32_t dlen = 0; /* create blob from the pubkey */ blob = publickey_to_string(pubkey); request = buffer_new(); if (request == NULL) { goto error; } /* create request */ if (buffer_add_u8(request, SSH2_AGENTC_SIGN_REQUEST) < 0) { goto error; } /* adds len + blob */ if (buffer_add_ssh_string(request, blob) < 0) { goto error; } /* Add data */ dlen = buffer_get_len(data); if (buffer_add_u32(request, htonl(dlen)) < 0) { goto error; } if (buffer_add_data(request, buffer_get(data), dlen) < 0) { goto error; } if (buffer_add_u32(request, htonl(flags)) < 0) { goto error; } string_free(blob); reply = buffer_new(); if (reply == NULL) { goto error; } /* send the request */ if (agent_talk(session, request, reply) < 0) { buffer_free(request); return NULL; } buffer_free(request); /* check if reply is valid */ if (buffer_get_u8(reply, (uint8_t *) &type) != sizeof(uint8_t)) { goto error; } if (agent_failed(type)) { ssh_log(session, SSH_LOG_RARE, "Agent reports failure in signing the key"); buffer_free(reply); return NULL; } else if (type != SSH2_AGENT_SIGN_RESPONSE) { ssh_set_error(session, SSH_FATAL, "Bad authentication response: %d", type); buffer_free(reply); return NULL; } sig = buffer_get_ssh_string(reply); buffer_free(reply); return sig; error: ssh_set_error(session, SSH_FATAL, "Not enough memory"); string_free(blob); buffer_free(request); buffer_free(reply); return NULL; }