int mm_key_verify(Key *key, u_char *sig, u_int siglen, u_char *data, u_int datalen) { Buffer m; u_char *blob; u_int len; int verified = 0; debug3("%s entering", __func__); /* Convert the key to a blob and the pass it over */ if (!key_to_blob(key, &blob, &len)) return (0); buffer_init(&m); buffer_put_string(&m, blob, len); buffer_put_string(&m, sig, siglen); buffer_put_string(&m, data, datalen); xfree(blob); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYVERIFY, &m); debug3("%s: waiting for MONITOR_ANS_KEYVERIFY", __func__); mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KEYVERIFY, &m); verified = buffer_get_int(&m); buffer_free(&m); return (verified); }
BIGNUM * mm_auth_rsa_generate_challenge(Key *key) { Buffer m; BIGNUM *challenge; u_char *blob; u_int blen; debug3("%s entering", __func__); if ((challenge = BN_new()) == NULL) fatal("%s: BN_new failed", __func__); key->type = KEY_RSA; /* XXX cheat for key_to_blob */ if (key_to_blob(key, &blob, &blen) == 0) fatal("%s: key_to_blob failed", __func__); key->type = KEY_RSA1; buffer_init(&m); buffer_put_string(&m, blob, blen); xfree(blob); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_RSACHALLENGE, &m); mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_RSACHALLENGE, &m); buffer_get_bignum2(&m, challenge); buffer_free(&m); return (challenge); }
int mm_auth_rsa_verify_response(Key *key, BIGNUM *p, u_char response[16]) { Buffer m; u_char *blob; u_int blen; int success = 0; debug3("%s entering", __func__); key->type = KEY_RSA; /* XXX cheat for key_to_blob */ if (key_to_blob(key, &blob, &blen) == 0) fatal("%s: key_to_blob failed", __func__); key->type = KEY_RSA1; buffer_init(&m); buffer_put_string(&m, blob, blen); buffer_put_string(&m, response, 16); xfree(blob); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_RSARESPONSE, &m); mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_RSARESPONSE, &m); success = buffer_get_int(&m); buffer_free(&m); return (success); }
static int send_pubkey_test(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback, int hint) { u_char *blob; u_int bloblen, have_sig = 0; debug3("send_pubkey_test"); if (key_to_blob(k, &blob, &bloblen) == 0) { /* we cannot handle this key */ debug3("send_pubkey_test: cannot handle key"); return 0; } /* register callback for USERAUTH_PK_OK message */ authctxt->last_key_sign = sign_callback; authctxt->last_key_hint = hint; authctxt->last_key = k; dispatch_set(SSH2_MSG_USERAUTH_PK_OK, &input_userauth_pk_ok); packet_start(SSH2_MSG_USERAUTH_REQUEST); packet_put_cstring(authctxt->server_user); packet_put_cstring(authctxt->service); packet_put_cstring(authctxt->method->name); packet_put_char(have_sig); if (!(datafellows & SSH_BUG_PKAUTH)) packet_put_cstring(key_ssh_name(k)); packet_put_string(blob, bloblen); xfree(blob); packet_send(); return 1; }
int mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen, const u_char *data, size_t datalen, u_int compat) { Buffer m; u_char *blob; u_int len; u_int encoded_ret = 0; debug3("%s entering", __func__); /* Convert the key to a blob and the pass it over */ if (!key_to_blob(key, &blob, &len)) return (0); buffer_init(&m); buffer_put_string(&m, blob, len); buffer_put_string(&m, sig, siglen); buffer_put_string(&m, data, datalen); free(blob); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYVERIFY, &m); debug3("%s: waiting for MONITOR_ANS_KEYVERIFY", __func__); mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KEYVERIFY, &m); encoded_ret = buffer_get_int(&m); buffer_free(&m); if (encoded_ret != 0) return SSH_ERR_SIGNATURE_INVALID; return 0; }
int ssh_remove_identity(AuthenticationConnection *auth, Key *key) { Buffer msg; int type; u_char *blob; u_int blen; buffer_init(&msg); if (key->type == KEY_RSA1) { buffer_put_char(&msg, SSH_AGENTC_REMOVE_RSA_IDENTITY); buffer_put_int(&msg, BN_num_bits(key->rsa->n)); buffer_put_bignum(&msg, key->rsa->e); buffer_put_bignum(&msg, key->rsa->n); } else if (key->type == KEY_DSA || key->type == KEY_RSA) { key_to_blob(key, &blob, &blen); buffer_put_char(&msg, SSH2_AGENTC_REMOVE_IDENTITY); buffer_put_string(&msg, blob, blen); xfree(blob); } else { buffer_free(&msg); return 0; } if (ssh_request_reply(auth, &msg, &msg) == 0) { buffer_free(&msg); return 0; } type = buffer_get_char(&msg); buffer_free(&msg); return decode_reply(type); }
int mm_answer_rsa_keyallowed(int sock, Buffer *m) { BIGNUM *client_n; Key *key = NULL; u_char *blob = NULL; u_int blen = 0; int allowed = 0; debug3("%s entering", __func__); auth_method = "rsa"; if (options.rsa_authentication && authctxt->valid) { if ((client_n = BN_new()) == NULL) fatal("%s: BN_new", __func__); buffer_get_bignum2(m, client_n); allowed = auth_rsa_key_allowed(authctxt->pw, client_n, &key); BN_clear_free(client_n); } buffer_clear(m); buffer_put_int(m, allowed); buffer_put_int(m, forced_command != NULL); /* clear temporarily storage (used by generate challenge) */ monitor_reset_key_state(); if (allowed && key != NULL) { key->type = KEY_RSA; /* cheat for key_to_blob */ if (key_to_blob(key, &blob, &blen) == 0) fatal("%s: key_to_blob failed", __func__); buffer_put_string(m, blob, blen); /* Save temporarily for comparison in verify */ key_blob = blob; key_bloblen = blen; key_blobtype = MM_RSAUSERKEY; } if (key != NULL) key_free(key); mm_append_debug(m); mm_request_send(sock, MONITOR_ANS_RSAKEYALLOWED, m); monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed); monitor_permit(mon_dispatch, MONITOR_REQ_RSARESPONSE, 0); return (0); }
/* 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 (key_to_blob(key, &blob, &blen) == 0) return -1; if (datafellows & SSH_BUG_SIGBLOB) flags = SSH_AGENT_OLD_SIGNATURE; buffer_init(&msg); buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); buffer_put_string(&msg, blob, blen); buffer_put_string(&msg, data, datalen); buffer_put_int(&msg, flags); xfree(blob); if (ssh_request_reply(auth, &msg, &msg) == 0) { buffer_free(&msg); return -1; } type = buffer_get_char(&msg); if (agent_failed(type)) { log("Agent admitted failure to sign using the key."); } else if (type != SSH2_AGENT_SIGN_RESPONSE) { fatal("Bad authentication response: %d", type); } else { ret = 0; *sigp = buffer_get_string(&msg, lenp); } buffer_free(&msg); return ret; }
int mm_key_allowed(enum mm_keytype type, char *user, char *host, Key *key) { Buffer m; u_char *blob; u_int len; int allowed = 0, have_forced = 0; debug3("%s entering", __func__); /* Convert the key to a blob and the pass it over */ if (!key_to_blob(key, &blob, &len)) return (0); buffer_init(&m); buffer_put_int(&m, type); buffer_put_cstring(&m, user ? user : ""); buffer_put_cstring(&m, host ? host : ""); buffer_put_string(&m, blob, len); xfree(blob); mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_KEYALLOWED, &m); debug3("%s: waiting for MONITOR_ANS_KEYALLOWED", __func__); mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_KEYALLOWED, &m); allowed = buffer_get_int(&m); /* fake forced command */ auth_clear_options(); have_forced = buffer_get_int(&m); forced_command = have_forced ? xstrdup("true") : NULL; /* Send potential debug messages */ mm_send_debug(&m); buffer_free(&m); return (allowed); }
static int pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa, int padding) { Key key; u_char *blob, *signature = NULL; u_int blen, slen = 0; int ret = -1; Buffer msg; if (padding != RSA_PKCS1_PADDING) return (-1); key.type = KEY_RSA; key.rsa = rsa; if (key_to_blob(&key, &blob, &blen) == 0) return -1; buffer_init(&msg); buffer_put_char(&msg, SSH2_AGENTC_SIGN_REQUEST); buffer_put_string(&msg, blob, blen); buffer_put_string(&msg, from, flen); buffer_put_int(&msg, 0); free(blob); send_msg(&msg); buffer_clear(&msg); if (recv_msg(&msg) == SSH2_AGENT_SIGN_RESPONSE) { signature = buffer_get_string(&msg, &slen); if (slen <= (u_int)RSA_size(rsa)) { memcpy(to, signature, slen); ret = slen; } free(signature); } buffer_free(&msg); return (ret); }
char* key_fingerprint_raw(Key *k, enum fp_type dgst_type, int *dgst_raw_length) { const EVP_MD *md = NULL; EVP_MD_CTX ctx; char *blob = NULL; char *retval = NULL; int len = 0; int nlen, elen; RSA *rsa; *dgst_raw_length = 0; switch (dgst_type) { case SSH_FP_MD5: md = EVP_md5(); break; case SSH_FP_SHA1: md = EVP_sha1(); break; case SSH_FP_SHA256: md = EVP_sha256(); break; default: md = EVP_md5(); } switch (k->type) { case KEY_RSA1: rsa = make_key(NULL, k->bits, k->exp, k->mod); nlen = BN_num_bytes(rsa->n); elen = BN_num_bytes(rsa->e); len = nlen + elen; blob = malloc(len); if (blob == NULL) { // TODO: } BN_bn2bin(rsa->n, blob); BN_bn2bin(rsa->e, blob + nlen); RSA_free(rsa); break; case KEY_DSA: case KEY_RSA: case KEY_ECDSA256: case KEY_ECDSA384: case KEY_ECDSA521: case KEY_ED25519: key_to_blob(k, &blob, &len); break; case KEY_UNSPEC: return retval; break; default: //fatal("key_fingerprint_raw: bad key type %d", k->type); break; } if (blob != NULL) { retval = malloc(EVP_MAX_MD_SIZE); if (retval == NULL) { // TODO: } EVP_DigestInit(&ctx, md); EVP_DigestUpdate(&ctx, blob, len); EVP_DigestFinal(&ctx, retval, dgst_raw_length); memset(blob, 0, len); free(blob); } else { //fatal("key_fingerprint_raw: blob is null"); } return retval; }
void kexgex_server(Kex *kex) { BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; Key *server_host_public, *server_host_private; DH *dh; u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; u_int sbloblen, klen, slen, hashlen; int omin = -1, min = -1, omax = -1, max = -1, onbits = -1, nbits = -1; int type, kout; if (kex->load_host_public_key == NULL || kex->load_host_private_key == NULL) fatal("Cannot load hostkey"); server_host_public = kex->load_host_public_key(kex->hostkey_type); if (server_host_public == NULL) fatal("Unsupported hostkey type %d", kex->hostkey_type); server_host_private = kex->load_host_private_key(kex->hostkey_type); type = packet_read(); switch (type) { case SSH2_MSG_KEX_DH_GEX_REQUEST: debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); omin = min = packet_get_int(); onbits = nbits = packet_get_int(); omax = max = packet_get_int(); min = MAX(DH_GRP_MIN, min); max = MIN(DH_GRP_MAX, max); nbits = MAX(DH_GRP_MIN, nbits); nbits = MIN(DH_GRP_MAX, nbits); break; case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); onbits = nbits = packet_get_int(); /* unused for old GEX */ omin = min = DH_GRP_MIN; omax = max = DH_GRP_MAX; break; default: fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type); } packet_check_eom(); if (omax < omin || onbits < omin || omax < onbits) fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", omin, onbits, omax); /* Contact privileged parent */ dh = PRIVSEP(choose_dh(min, nbits, max)); if (dh == NULL) packet_disconnect("Protocol error: no matching DH grp found"); debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); packet_put_bignum2(dh->p); packet_put_bignum2(dh->g); packet_send(); /* flush */ packet_write_wait(); /* Compute our exchange value in parallel with the client */ dh_gen_key(dh, kex->we_need * 8); debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT); /* key, cert */ if ((dh_client_pub = BN_new()) == NULL) fatal("dh_client_pub == NULL"); packet_get_bignum2(dh_client_pub); packet_check_eom(); #ifdef DEBUG_KEXDH fprintf(stderr, "dh_client_pub= "); BN_print_fp(stderr, dh_client_pub); fprintf(stderr, "\n"); debug("bits %d", BN_num_bits(dh_client_pub)); #endif #ifdef DEBUG_KEXDH DHparams_print_fp(stderr, dh); fprintf(stderr, "pub= "); BN_print_fp(stderr, dh->pub_key); fprintf(stderr, "\n"); #endif if (!dh_pub_is_valid(dh, dh_client_pub)) packet_disconnect("bad client public DH value"); klen = DH_size(dh); kbuf = xmalloc(klen); if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0) fatal("DH_compute_key: failed"); #ifdef DEBUG_KEXDH dump_digest("shared secret", kbuf, kout); #endif if ((shared_secret = BN_new()) == NULL) fatal("kexgex_server: BN_new failed"); if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) fatal("kexgex_server: BN_bin2bn failed"); memset(kbuf, 0, klen); free(kbuf); key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) omin = min = omax = max = -1; /* calc H */ kexgex_hash( kex->evp_md, kex->client_version_string, kex->server_version_string, buffer_ptr(&kex->peer), buffer_len(&kex->peer), buffer_ptr(&kex->my), buffer_len(&kex->my), server_host_key_blob, sbloblen, omin, onbits, omax, dh->p, dh->g, dh_client_pub, dh->pub_key, shared_secret, &hash, &hashlen ); BN_clear_free(dh_client_pub); /* save session id := H */ if (kex->session_id == NULL) { kex->session_id_len = hashlen; kex->session_id = xmalloc(kex->session_id_len); memcpy(kex->session_id, hash, kex->session_id_len); } /* sign H */ kex->sign(server_host_private, server_host_public, &signature, &slen, hash, hashlen); /* destroy_sensitive_data(); */ /* send server hostkey, DH pubkey 'f' and singed H */ debug("SSH2_MSG_KEX_DH_GEX_REPLY sent"); packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); packet_put_string(server_host_key_blob, sbloblen); packet_put_bignum2(dh->pub_key); /* f */ packet_put_string(signature, slen); packet_send(); free(signature); free(server_host_key_blob); /* have keys, free DH */ DH_free(dh); kex_derive_keys(kex, hash, hashlen, shared_secret); BN_clear_free(shared_secret); kex_finish(kex); }
void kexdh_server(Kex *kex) { BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; DH *dh; Key *server_host_key; u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; u_int sbloblen, klen, kout, hashlen; u_int slen; /* generate server DH public key */ switch (kex->kex_type) { case KEX_DH_GRP1_SHA1: dh = dh_new_group1(); break; case KEX_DH_GRP14_SHA1: dh = dh_new_group14(); break; default: fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); } dh_gen_key(dh, kex->we_need * 8); debug("expecting SSH2_MSG_KEXDH_INIT"); packet_read_expect(SSH2_MSG_KEXDH_INIT); if (kex->load_host_key == NULL) fatal("Cannot load hostkey"); server_host_key = kex->load_host_key(kex->hostkey_type); if (server_host_key == NULL) fatal("Unsupported hostkey type %d", kex->hostkey_type); /* key, cert */ if ((dh_client_pub = BN_new()) == NULL) fatal("dh_client_pub == NULL"); packet_get_bignum2(dh_client_pub); packet_check_eom(); #ifdef DEBUG_KEXDH fprintf(stderr, "dh_client_pub= "); BN_print_fp(stderr, dh_client_pub); fprintf(stderr, "\n"); debug("bits %d", BN_num_bits(dh_client_pub)); #endif #ifdef DEBUG_KEXDH DHparams_print_fp(stderr, dh); fprintf(stderr, "pub= "); BN_print_fp(stderr, dh->pub_key); fprintf(stderr, "\n"); #endif if (!dh_pub_is_valid(dh, dh_client_pub)) packet_disconnect("bad client public DH value"); klen = DH_size(dh); kbuf = xmalloc(klen); kout = DH_compute_key(kbuf, dh_client_pub, dh); #ifdef DEBUG_KEXDH dump_digest("shared secret", kbuf, kout); #endif if ((shared_secret = BN_new()) == NULL) fatal("kexdh_server: BN_new failed"); BN_bin2bn(kbuf, kout, shared_secret); memset(kbuf, 0, klen); xfree(kbuf); key_to_blob(server_host_key, &server_host_key_blob, &sbloblen); /* calc H */ kex_dh_hash( kex->client_version_string, kex->server_version_string, buffer_ptr(&kex->peer), buffer_len(&kex->peer), buffer_ptr(&kex->my), buffer_len(&kex->my), server_host_key_blob, sbloblen, dh_client_pub, dh->pub_key, shared_secret, &hash, &hashlen ); BN_clear_free(dh_client_pub); /* save session id := H */ if (kex->session_id == NULL) { kex->session_id_len = hashlen; kex->session_id = xmalloc(kex->session_id_len); memcpy(kex->session_id, hash, kex->session_id_len); } /* sign H */ PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, hashlen)); /* destroy_sensitive_data(); */ /* send server hostkey, DH pubkey 'f' and singed H */ packet_start(SSH2_MSG_KEXDH_REPLY); packet_put_string(server_host_key_blob, sbloblen); packet_put_bignum2(dh->pub_key); /* f */ packet_put_string(signature, slen); packet_send(); xfree(signature); xfree(server_host_key_blob); /* have keys, free DH */ DH_free(dh); kex_derive_keys(kex, hash, hashlen, shared_secret); BN_clear_free(shared_secret); kex_finish(kex); }
static int sign_and_send_pubkey(Authctxt *authctxt, Key *k, sign_cb_fn *sign_callback) { Buffer b; u_char *blob, *signature; u_int bloblen, slen; int skip = 0; int ret = -1; int have_sig = 1; debug3("sign_and_send_pubkey"); if (key_to_blob(k, &blob, &bloblen) == 0) { /* we cannot handle this key */ debug3("sign_and_send_pubkey: cannot handle key"); return 0; } /* data to be signed */ buffer_init(&b); if (datafellows & SSH_OLD_SESSIONID) { buffer_append(&b, session_id2, session_id2_len); skip = session_id2_len; } else { buffer_put_string(&b, session_id2, session_id2_len); skip = buffer_len(&b); } buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); buffer_put_cstring(&b, authctxt->server_user); buffer_put_cstring(&b, datafellows & SSH_BUG_PKSERVICE ? "ssh-userauth" : authctxt->service); if (datafellows & SSH_BUG_PKAUTH) { buffer_put_char(&b, have_sig); } else { buffer_put_cstring(&b, authctxt->method->name); buffer_put_char(&b, have_sig); buffer_put_cstring(&b, key_ssh_name(k)); } buffer_put_string(&b, blob, bloblen); /* generate signature */ ret = (*sign_callback)(authctxt, k, &signature, &slen, buffer_ptr(&b), buffer_len(&b)); if (ret == -1) { xfree(blob); buffer_free(&b); return 0; } #ifdef DEBUG_PK buffer_dump(&b); #endif if (datafellows & SSH_BUG_PKSERVICE) { buffer_clear(&b); buffer_append(&b, session_id2, session_id2_len); skip = session_id2_len; buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); buffer_put_cstring(&b, authctxt->server_user); buffer_put_cstring(&b, authctxt->service); buffer_put_cstring(&b, authctxt->method->name); buffer_put_char(&b, have_sig); if (!(datafellows & SSH_BUG_PKAUTH)) buffer_put_cstring(&b, key_ssh_name(k)); buffer_put_string(&b, blob, bloblen); } xfree(blob); /* append signature */ buffer_put_string(&b, signature, slen); xfree(signature); /* skip session id and packet type */ if (buffer_len(&b) < skip + 1) fatal("userauth_pubkey: internal error"); buffer_consume(&b, skip + 1); /* put remaining data from buffer into packet */ packet_start(SSH2_MSG_USERAUTH_REQUEST); packet_put_raw(buffer_ptr(&b), buffer_len(&b)); buffer_free(&b); packet_send(); return 1; }
void kexecdh_server(Kex *kex) { EC_POINT *client_public; EC_KEY *server_key; const EC_GROUP *group; BIGNUM *shared_secret; Key *server_host_private, *server_host_public; u_char *server_host_key_blob = NULL, *signature = NULL; u_char *kbuf, *hash; u_int klen, slen, sbloblen, hashlen; int curve_nid; if ((curve_nid = kex_ecdh_name_to_nid(kex->name)) == -1) fatal("%s: unsupported ECDH curve \"%s\"", __func__, kex->name); if ((server_key = EC_KEY_new_by_curve_name(curve_nid)) == NULL) fatal("%s: EC_KEY_new_by_curve_name failed", __func__); if (EC_KEY_generate_key(server_key) != 1) fatal("%s: EC_KEY_generate_key failed", __func__); group = EC_KEY_get0_group(server_key); #ifdef DEBUG_KEXECDH fputs("server private key:\n", stderr); key_dump_ec_key(server_key); #endif if (kex->load_host_public_key == NULL || kex->load_host_private_key == NULL) fatal("Cannot load hostkey"); server_host_public = kex->load_host_public_key(kex->hostkey_type); if (server_host_public == NULL) fatal("Unsupported hostkey type %d", kex->hostkey_type); server_host_private = kex->load_host_private_key(kex->hostkey_type); if (server_host_private == NULL) fatal("Missing private key for hostkey type %d", kex->hostkey_type); debug("expecting SSH2_MSG_KEX_ECDH_INIT"); packet_read_expect(SSH2_MSG_KEX_ECDH_INIT); if ((client_public = EC_POINT_new(group)) == NULL) fatal("%s: EC_POINT_new failed", __func__); packet_get_ecpoint(group, client_public); packet_check_eom(); if (key_ec_validate_public(group, client_public) != 0) fatal("%s: invalid client public key", __func__); #ifdef DEBUG_KEXECDH fputs("client public key:\n", stderr); key_dump_ec_point(group, client_public); #endif /* Calculate shared_secret */ klen = (EC_GROUP_get_degree(group) + 7) / 8; kbuf = xmalloc(klen); if (ECDH_compute_key(kbuf, klen, client_public, server_key, NULL) != (int)klen) fatal("%s: ECDH_compute_key failed", __func__); #ifdef DEBUG_KEXDH dump_digest("shared secret", kbuf, klen); #endif if ((shared_secret = BN_new()) == NULL) fatal("%s: BN_new failed", __func__); if (BN_bin2bn(kbuf, klen, shared_secret) == NULL) fatal("%s: BN_bin2bn failed", __func__); memset(kbuf, 0, klen); xfree(kbuf); /* calc H */ key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); kex_ecdh_hash( kex->evp_md, group, kex->client_version_string, kex->server_version_string, buffer_ptr(&kex->peer), buffer_len(&kex->peer), buffer_ptr(&kex->my), buffer_len(&kex->my), server_host_key_blob, sbloblen, client_public, EC_KEY_get0_public_key(server_key), shared_secret, &hash, &hashlen ); EC_POINT_clear_free(client_public); /* save session id := H */ if (kex->session_id == NULL) { kex->session_id_len = hashlen; kex->session_id = xmalloc(kex->session_id_len); memcpy(kex->session_id, hash, kex->session_id_len); } /* sign H */ if (PRIVSEP(key_sign(server_host_private, &signature, &slen, hash, hashlen)) < 0) fatal("kexdh_server: key_sign failed"); /* destroy_sensitive_data(); */ /* send server hostkey, ECDH pubkey 'Q_S' and signed H */ packet_start(SSH2_MSG_KEX_ECDH_REPLY); packet_put_string(server_host_key_blob, sbloblen); packet_put_ecpoint(group, EC_KEY_get0_public_key(server_key)); packet_put_string(signature, slen); packet_send(); xfree(signature); xfree(server_host_key_blob); /* have keys, free server key */ EC_KEY_free(server_key); kex_derive_keys(kex, hash, hashlen, shared_secret); BN_clear_free(shared_secret); kex_finish(kex); }
static void userauth_pubkey(Authctxt *authctxt) { Buffer b; Key *key = NULL; char *pkalg; u_char *pkblob, *sig; u_int alen, blen, slen; int have_sig, pktype; int authenticated = 0; if (!authctxt || !authctxt->method) fatal("%s: missing context", __func__); have_sig = packet_get_char(); if (datafellows & SSH_BUG_PKAUTH) { debug2("userauth_pubkey: SSH_BUG_PKAUTH"); /* no explicit pkalg given */ pkblob = packet_get_string(&blen); buffer_init(&b); buffer_append(&b, pkblob, blen); /* so we have to extract the pkalg from the pkblob */ pkalg = buffer_get_string(&b, &alen); buffer_free(&b); } else { pkalg = packet_get_string(&alen); pkblob = packet_get_string(&blen); } pktype = key_type_from_name(pkalg); if (pktype == KEY_UNSPEC) { /* this is perfectly legal */ log("userauth_pubkey: unsupported public key algorithm: %s", pkalg); goto done; } key = key_from_blob(pkblob, blen); if (key == NULL) { error("userauth_pubkey: cannot decode key: %s", pkalg); goto done; } if (key->type != pktype) { error("userauth_pubkey: type mismatch for decoded key " "(received %d, expected %d)", key->type, pktype); goto done; } /* Detect and count abandonment */ if (authctxt->method->method_data) { Key *prev_key; unsigned char *prev_pkblob; int prev_blen; /* * Check for earlier test of a key that was allowed but * not followed up with a pubkey req for the same pubkey * and with a signature. */ prev_key = authctxt->method->method_data; if ((prev_blen = key_to_blob(prev_key, &prev_pkblob, NULL))) { if (prev_blen != blen || memcmp(prev_pkblob, pkblob, blen) != 0) { authctxt->method->abandons++; authctxt->method->attempts++; } } key_free(prev_key); authctxt->method->method_data = NULL; } if (have_sig) { sig = packet_get_string(&slen); packet_check_eom(); buffer_init(&b); if (datafellows & SSH_OLD_SESSIONID) { buffer_append(&b, session_id2, session_id2_len); } else { buffer_put_string(&b, session_id2, session_id2_len); } /* reconstruct packet */ buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); buffer_put_cstring(&b, authctxt->user); buffer_put_cstring(&b, datafellows & SSH_BUG_PKSERVICE ? "ssh-userauth" : authctxt->service); if (datafellows & SSH_BUG_PKAUTH) { buffer_put_char(&b, have_sig); } else { buffer_put_cstring(&b, "publickey"); buffer_put_char(&b, have_sig); buffer_put_cstring(&b, pkalg); } buffer_put_string(&b, pkblob, blen); #ifdef DEBUG_PK buffer_dump(&b); #endif /* test for correct signature */ if (user_key_allowed(authctxt->pw, key) && key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1) { authenticated = 1; } authctxt->method->postponed = 0; buffer_free(&b); xfree(sig); } else { debug("test whether pkalg/pkblob are acceptable"); packet_check_eom(); /* XXX fake reply and always send PK_OK ? */ /* * XXX this allows testing whether a user is allowed * to login: if you happen to have a valid pubkey this * message is sent. the message is NEVER sent at all * if a user is not allowed to login. is this an * issue? -markus */ if (user_key_allowed(authctxt->pw, key)) { packet_start(SSH2_MSG_USERAUTH_PK_OK); packet_put_string(pkalg, alen); packet_put_string(pkblob, blen); packet_send(); packet_write_wait(); authctxt->method->postponed = 1; /* * Remember key that was tried so we can * correctly detect abandonment. See above. */ authctxt->method->method_data = (void *) key; key = NULL; } } if (authenticated != 1) auth_clear_options(); done: /* * XXX TODO: add config options for specifying users for whom * this userauth is insufficient and what userauths may * continue. */ #ifdef USE_PAM if (authenticated) { if (!do_pam_non_initial_userauth(authctxt)) authenticated = 0; } #endif /* USE_PAM */ debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); if (key != NULL) key_free(key); xfree(pkalg); xfree(pkblob); #ifdef HAVE_CYGWIN if (check_nt_auth(0, authctxt->pw) == 0) return; #endif if (authenticated) authctxt->method->authenticated = 1; }