/* ARGSUSED */ int kex_input_kexinit(int type, u_int32_t seq, void *ctxt) { struct ssh *ssh = ctxt; struct kex *kex = ssh->kex; const u_char *ptr; u_int i; size_t dlen; int r; debug("SSH2_MSG_KEXINIT received"); if (kex == NULL) return SSH_ERR_INVALID_ARGUMENT; ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, NULL); ptr = sshpkt_ptr(ssh, &dlen); if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) return r; /* discard packet */ for (i = 0; i < KEX_COOKIE_LEN; i++) if ((r = sshpkt_get_u8(ssh, NULL)) != 0) return r; for (i = 0; i < PROPOSAL_MAX; i++) if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) return r; /* * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported * KEX method has the server move first, but a server might be using * a custom method or one that we otherwise don't support. We should * be prepared to remember first_kex_follows here so we can eat a * packet later. * XXX2 - RFC4253 is kind of ambiguous on what first_kex_follows means * for cases where the server *doesn't* go first. I guess we should * ignore it when it is set for these cases, which is what we do now. */ if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */ (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */ (r = sshpkt_get_end(ssh)) != 0) return r; if (!(kex->flags & KEX_INIT_SENT)) if ((r = kex_send_kexinit(ssh)) != 0) return r; if ((r = kex_choose_conf(ssh)) != 0) return r; if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) return (kex->kex[kex->kex_type])(ssh); return SSH_ERR_INTERNAL_ERROR; }
void * ssh_packet_get_string(struct ssh *ssh, u_int *length_ptr) { int r; size_t len; u_char *val; if ((r = sshpkt_get_string(ssh, &val, &len)) != 0) fatal("%s: %s", __func__, ssh_err(r)); if (length_ptr != NULL) *length_ptr = (u_int)len; return val; }
static int input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) { Authctxt *authctxt = ssh->authctxt; Gssctxt *gssctxt; int r, authenticated = 0; struct sshbuf *b; gss_buffer_desc mic, gssbuf; const char *displayname; u_char *p; size_t len; if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) fatal("No authentication or GSSAPI context"); gssctxt = authctxt->methoddata; if ((r = sshpkt_get_string(ssh, &p, &len)) != 0) fatal("%s: %s", __func__, ssh_err(r)); if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); mic.value = p; mic.length = len; ssh_gssapi_buildmic(b, authctxt->user, authctxt->service, "gssapi-with-mic"); if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL) fatal("%s: sshbuf_mutable_ptr failed", __func__); gssbuf.length = sshbuf_len(b); if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); else logit("GSSAPI MIC check failed"); sshbuf_free(b); free(mic.value); if ((!use_privsep || mm_is_monitor()) && (displayname = ssh_gssapi_displayname()) != NULL) auth2_record_info(authctxt, "%s", displayname); authctxt->postponed = 0; ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); userauth_finish(ssh, authenticated, "gssapi-with-mic", NULL); return 0; }
/* ARGSUSED */ int kex_input_kexinit(int type, u_int32_t seq, struct ssh *ssh) { Kex *kex = ssh->kex; u_char *ptr; u_int i; size_t dlen; int r; debug("SSH2_MSG_KEXINIT received"); if (kex == NULL) return SSH_ERR_INVALID_ARGUMENT; ptr = sshpkt_ptr(ssh, &dlen); if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) return r; /* discard packet */ for (i = 0; i < KEX_COOKIE_LEN; i++) if ((r = sshpkt_get_u8(ssh, NULL)) != 0) return r; for (i = 0; i < PROPOSAL_MAX; i++) if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) return r; if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || (r = sshpkt_get_u32(ssh, NULL)) != 0 || (r = sshpkt_get_end(ssh)) != 0) return r; if (!(kex->flags & KEX_INIT_SENT)) if ((r = kex_send_kexinit(ssh)) != 0) return r; if ((r = kex_choose_conf(ssh)) != 0) return r; if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) return (kex->kex[kex->kex_type])(ssh); return SSH_ERR_INTERNAL_ERROR; }
static int server_input_stdin_data(int type, u_int32_t seq, struct ssh *ssh) { u_char *data = NULL; size_t data_len; int r; /* Stdin data from the client. Append it to the buffer. */ /* Ignore any data if the client has closed stdin. */ if (fdin == -1) return 0; if ((r = sshpkt_get_string(ssh, &data, &data_len)) != 0 || (r = sshpkt_get_end(ssh)) != 0 || (r = sshbuf_put(stdin_buffer, data, data_len)) != 0) goto out; r = 0; out: if (data) { explicit_bzero(data, data_len); free(data); } return r; }
static int input_gssapi_errtok(int type, u_int32_t plen, struct ssh *ssh) { Authctxt *authctxt = ssh->authctxt; Gssctxt *gssctxt; gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; gss_buffer_desc recv_tok; OM_uint32 maj_status; int r; u_char *p; size_t len; if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) fatal("No authentication or GSSAPI context"); gssctxt = authctxt->methoddata; if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 || (r = sshpkt_get_end(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); recv_tok.value = p; recv_tok.length = len; /* Push the error token into GSSAPI to see what it says */ maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok, NULL)); free(recv_tok.value); /* We can't return anything to the client, even if we wanted to */ ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); /* The client will have already moved on to the next auth */ gss_release_buffer(&maj_status, &send_tok); return 0; }
static int input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh) { Kex *kex = ssh->kex; BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; struct sshkey *server_host_key; u_char *kbuf = NULL, *hash, *signature = NULL, *server_host_key_blob = NULL; size_t klen = 0, slen, sbloblen, hashlen; int kout, r; debug("got SSH2_MSG_KEX_DH_GEX_REPLY"); if (kex->verify_host_key == NULL) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } /* key, cert */ if ((r = sshpkt_get_string(ssh, &server_host_key_blob, &sbloblen)) != 0 || (r = sshkey_from_blob(server_host_key_blob, sbloblen, &server_host_key)) != 0) goto out; if (server_host_key->type != kex->hostkey_type) { r = SSH_ERR_KEY_TYPE_MISMATCH; goto out; } if (kex->verify_host_key(server_host_key, ssh) == -1) { r = SSH_ERR_SIGNATURE_INVALID; goto out; } /* DH parameter f, server public DH key */ if ((dh_server_pub = BN_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } /* signed H */ if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 || (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || (r = sshpkt_get_end(ssh)) != 0) goto out; #ifdef DEBUG_KEXDH fprintf(stderr, "dh_server_pub= "); BN_print_fp(stderr, dh_server_pub); fprintf(stderr, "\n"); debug("bits %d", BN_num_bits(dh_server_pub)); #endif if (!dh_pub_is_valid(kex->dh, dh_server_pub)) { sshpkt_disconnect(ssh, "bad server public DH value"); r = SSH_ERR_MESSAGE_INCOMPLETE; goto out; } klen = DH_size(kex->dh); if ((kbuf = malloc(klen)) == NULL || (shared_secret = BN_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 || BN_bin2bn(kbuf, kout, shared_secret) == NULL) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } #ifdef DEBUG_KEXDH dump_digest("shared secret", kbuf, kout); #endif if (ssh->compat & SSH_OLD_DHGEX) kex->min = kex->max = -1; /* calc and verify H */ if ((r = kexgex_hash( kex->evp_md, kex->client_version_string, kex->server_version_string, sshbuf_ptr(kex->my), sshbuf_len(kex->my), sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), server_host_key_blob, sbloblen, kex->min, kex->nbits, kex->max, kex->dh->p, kex->dh->g, kex->dh->pub_key, dh_server_pub, shared_secret, &hash, &hashlen)) != 0) goto out; if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen, ssh->compat)) != 0) goto out; /* save session id */ if (kex->session_id == NULL) { kex->session_id_len = hashlen; kex->session_id = malloc(kex->session_id_len); if (kex->session_id == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(kex->session_id, hash, kex->session_id_len); } if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) r = kex_send_newkeys(ssh); out: DH_free(kex->dh); kex->dh = NULL; if (server_host_key_blob) free(server_host_key_blob); if (server_host_key) sshkey_free(server_host_key); if (dh_server_pub) BN_clear_free(dh_server_pub); if (kbuf) { bzero(kbuf, klen); free(kbuf); } if (shared_secret) BN_clear_free(shared_secret); if (signature) free(signature); return r; }
static int input_kex_c25519_init(int type, u_int32_t seq, struct ssh *ssh) { struct kex *kex = ssh->kex; struct sshkey *server_host_private, *server_host_public; struct sshbuf *shared_secret = NULL; u_char *server_host_key_blob = NULL, *signature = NULL; u_char server_key[CURVE25519_SIZE]; u_char *client_pubkey = NULL; u_char server_pubkey[CURVE25519_SIZE]; u_char hash[SSH_DIGEST_MAX_LENGTH]; size_t slen, pklen, sbloblen, hashlen; int r; /* generate private key */ kexc25519_keygen(server_key, server_pubkey); #ifdef DEBUG_KEXECDH dump_digest("server private key:", server_key, sizeof(server_key)); #endif if (kex->load_host_public_key == NULL || kex->load_host_private_key == NULL) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } server_host_public = kex->load_host_public_key(kex->hostkey_type, kex->hostkey_nid, ssh); server_host_private = kex->load_host_private_key(kex->hostkey_type, kex->hostkey_nid, ssh); if (server_host_public == NULL) { r = SSH_ERR_NO_HOSTKEY_LOADED; goto out; } if ((r = sshpkt_get_string(ssh, &client_pubkey, &pklen)) != 0 || (r = sshpkt_get_end(ssh)) != 0) goto out; if (pklen != CURVE25519_SIZE) { r = SSH_ERR_SIGNATURE_INVALID; goto out; } #ifdef DEBUG_KEXECDH dump_digest("client public key:", client_pubkey, CURVE25519_SIZE); #endif if ((shared_secret = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = kexc25519_shared_key(server_key, client_pubkey, shared_secret)) < 0) goto out; /* calc H */ if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob, &sbloblen)) != 0) goto out; hashlen = sizeof(hash); if ((r = kex_c25519_hash( kex->hash_alg, kex->client_version_string, kex->server_version_string, sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), sshbuf_ptr(kex->my), sshbuf_len(kex->my), server_host_key_blob, sbloblen, client_pubkey, server_pubkey, sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), hash, &hashlen)) < 0) goto out; /* save session id := H */ if (kex->session_id == NULL) { kex->session_id_len = hashlen; kex->session_id = malloc(kex->session_id_len); if (kex->session_id == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(kex->session_id, hash, kex->session_id_len); } /* sign H */ if ((r = kex->sign(server_host_private, server_host_public, &signature, &slen, hash, hashlen, kex->hostkey_alg, ssh->compat)) < 0) goto out; /* send server hostkey, ECDH pubkey 'Q_S' and signed H */ if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 || (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || (r = sshpkt_put_string(ssh, server_pubkey, sizeof(server_pubkey))) != 0 || (r = sshpkt_put_string(ssh, signature, slen)) != 0 || (r = sshpkt_send(ssh)) != 0) goto out; if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) r = kex_send_newkeys(ssh); out: explicit_bzero(hash, sizeof(hash)); explicit_bzero(server_key, sizeof(server_key)); free(server_host_key_blob); free(signature); free(client_pubkey); sshbuf_free(shared_secret); return r; }
static int input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt) { struct ssh *ssh = ctxt; struct kex *kex = ssh->kex; const EC_GROUP *group; EC_POINT *server_public = NULL; EC_KEY *client_key; BIGNUM *shared_secret = NULL; struct sshkey *server_host_key = NULL; u_char *server_host_key_blob = NULL, *signature = NULL; u_char *kbuf = NULL; u_char hash[SSH_DIGEST_MAX_LENGTH]; size_t slen, sbloblen; size_t klen = 0, hashlen; int r; if (kex->verify_host_key == NULL) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } group = kex->ec_group; client_key = kex->ec_client_key; /* hostkey */ if ((r = sshpkt_get_string(ssh, &server_host_key_blob, &sbloblen)) != 0 || (r = sshkey_from_blob(server_host_key_blob, sbloblen, &server_host_key)) != 0) goto out; if (server_host_key->type != kex->hostkey_type || (kex->hostkey_type == KEY_ECDSA && server_host_key->ecdsa_nid != kex->hostkey_nid)) { r = SSH_ERR_KEY_TYPE_MISMATCH; goto out; } if (kex->verify_host_key(server_host_key, ssh) == -1) { r = SSH_ERR_SIGNATURE_INVALID; goto out; } /* Q_S, server public key */ /* signed H */ if ((server_public = EC_POINT_new(group)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = sshpkt_get_ec(ssh, server_public, group)) != 0 || (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || (r = sshpkt_get_end(ssh)) != 0) goto out; #ifdef DEBUG_KEXECDH fputs("server public key:\n", stderr); sshkey_dump_ec_point(group, server_public); #endif if (sshkey_ec_validate_public(group, server_public) != 0) { sshpkt_disconnect(ssh, "invalid server public key"); r = SSH_ERR_MESSAGE_INCOMPLETE; goto out; } klen = (EC_GROUP_get_degree(group) + 7) / 8; if ((kbuf = malloc(klen)) == NULL || (shared_secret = BN_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if (ECDH_compute_key(kbuf, klen, server_public, client_key, NULL) != (int)klen || BN_bin2bn(kbuf, klen, shared_secret) == NULL) { r = SSH_ERR_LIBCRYPTO_ERROR; goto out; } #ifdef DEBUG_KEXECDH dump_digest("shared secret", kbuf, klen); #endif /* calc and verify H */ hashlen = sizeof(hash); if ((r = kex_ecdh_hash( kex->hash_alg, group, kex->client_version_string, kex->server_version_string, sshbuf_ptr(kex->my), sshbuf_len(kex->my), sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), server_host_key_blob, sbloblen, EC_KEY_get0_public_key(client_key), server_public, shared_secret, hash, &hashlen)) != 0) goto out; if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen, ssh->compat)) != 0) goto out; /* save session id */ if (kex->session_id == NULL) { kex->session_id_len = hashlen; kex->session_id = malloc(kex->session_id_len); if (kex->session_id == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(kex->session_id, hash, kex->session_id_len); } if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) r = kex_send_newkeys(ssh); out: explicit_bzero(hash, sizeof(hash)); if (kex->ec_client_key) { EC_KEY_free(kex->ec_client_key); kex->ec_client_key = NULL; } if (server_public) EC_POINT_clear_free(server_public); if (kbuf) { explicit_bzero(kbuf, klen); free(kbuf); } if (shared_secret) BN_clear_free(shared_secret); sshkey_free(server_host_key); free(server_host_key_blob); free(signature); return r; }
static int input_kex_c25519_reply(int type, u_int32_t seq, struct ssh *ssh) { struct kex *kex = ssh->kex; struct sshkey *server_host_key = NULL; struct sshbuf *shared_secret = NULL; u_char *server_pubkey = NULL; u_char *server_host_key_blob = NULL, *signature = NULL; u_char *hash; size_t slen, pklen, sbloblen, hashlen; int r; if (kex->verify_host_key == NULL) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } /* hostkey */ if ((r = sshpkt_get_string(ssh, &server_host_key_blob, &sbloblen)) != 0 || (r = sshkey_from_blob(server_host_key_blob, sbloblen, &server_host_key)) != 0) goto out; if (server_host_key->type != kex->hostkey_type) { r = SSH_ERR_KEY_TYPE_MISMATCH; goto out; } if (kex->verify_host_key(server_host_key, ssh) == -1) { r = SSH_ERR_SIGNATURE_INVALID; goto out; } /* Q_S, server public key */ /* signed H */ if ((r = sshpkt_get_string(ssh, &server_pubkey, &pklen)) != 0 || (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || (r = sshpkt_get_end(ssh)) != 0) goto out; if (pklen != CURVE25519_SIZE) { r = SSH_ERR_SIGNATURE_INVALID; goto out; } #ifdef DEBUG_KEXECDH dump_digest("server public key:", server_pubkey, CURVE25519_SIZE); #endif if ((shared_secret = sshbuf_new()) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } if ((r = kexc25519_shared_key(kex->c25519_client_key, server_pubkey, shared_secret)) < 0) goto out; /* calc and verify H */ if ((r = kex_c25519_hash( kex->hash_alg, kex->client_version_string, kex->server_version_string, sshbuf_ptr(kex->my), sshbuf_len(kex->my), sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), server_host_key_blob, sbloblen, kex->c25519_client_pubkey, server_pubkey, sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), &hash, &hashlen)) < 0) goto out; if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen, ssh->compat)) != 0) goto out; /* save session id */ if (kex->session_id == NULL) { kex->session_id_len = hashlen; kex->session_id = malloc(kex->session_id_len); if (kex->session_id == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(kex->session_id, hash, kex->session_id_len); } if ((r = kex_derive_keys(ssh, hash, hashlen, sshbuf_ptr(shared_secret), sshbuf_len(shared_secret))) == 0) r = kex_send_newkeys(ssh); r = 0; out: explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key)); free(server_host_key_blob); free(server_pubkey); free(signature); sshkey_free(server_host_key); sshbuf_free(shared_secret); return r; }
static int userauth_hostbased(struct ssh *ssh) { Authctxt *authctxt = ssh->authctxt; struct sshbuf *b; struct sshkey *key = NULL; char *pkalg, *cuser, *chost; u_char *pkblob, *sig; size_t alen, blen, slen; int r, pktype, authenticated = 0; if (!authctxt->valid) { debug2("%s: disabled because of invalid user", __func__); return 0; } /* XXX use sshkey_froms() */ if ((r = sshpkt_get_cstring(ssh, &pkalg, &alen)) != 0 || (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 || (r = sshpkt_get_cstring(ssh, &chost, NULL)) != 0 || (r = sshpkt_get_cstring(ssh, &cuser, NULL)) != 0 || (r = sshpkt_get_string(ssh, &sig, &slen)) != 0) fatal("%s: packet parsing: %s", __func__, ssh_err(r)); debug("%s: cuser %s chost %s pkalg %s slen %zu", __func__, cuser, chost, pkalg, slen); #ifdef DEBUG_PK debug("signature:"); sshbuf_dump_data(sig, siglen, stderr); #endif pktype = sshkey_type_from_name(pkalg); if (pktype == KEY_UNSPEC) { /* this is perfectly legal */ logit("%s: unsupported public key algorithm: %s", __func__, pkalg); goto done; } if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) { error("%s: key_from_blob: %s", __func__, ssh_err(r)); goto done; } if (key == NULL) { error("%s: cannot decode key: %s", __func__, pkalg); goto done; } if (key->type != pktype) { error("%s: type mismatch for decoded key " "(received %d, expected %d)", __func__, key->type, pktype); goto done; } if (sshkey_type_plain(key->type) == KEY_RSA && (ssh->compat & SSH_BUG_RSASIGMD5) != 0) { error("Refusing RSA key because peer uses unsafe " "signature format"); goto done; } if (match_pattern_list(sshkey_ssh_name(key), options.hostbased_key_types, 0) != 1) { logit("%s: key type %s not in HostbasedAcceptedKeyTypes", __func__, sshkey_type(key)); goto done; } if ((b = sshbuf_new()) == NULL) fatal("%s: sshbuf_new failed", __func__); /* reconstruct packet */ if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 || (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || (r = sshbuf_put_cstring(b, authctxt->user)) != 0 || (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || (r = sshbuf_put_cstring(b, "hostbased")) != 0 || (r = sshbuf_put_string(b, pkalg, alen)) != 0 || (r = sshbuf_put_string(b, pkblob, blen)) != 0 || (r = sshbuf_put_cstring(b, chost)) != 0 || (r = sshbuf_put_cstring(b, cuser)) != 0) fatal("%s: buffer error: %s", __func__, ssh_err(r)); #ifdef DEBUG_PK sshbuf_dump(b, stderr); #endif auth2_record_info(authctxt, "client user \"%.100s\", client host \"%.100s\"", cuser, chost); /* test for allowed key and correct signature */ authenticated = 0; if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) && PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), sshbuf_len(b), pkalg, ssh->compat)) == 0) authenticated = 1; auth2_record_key(authctxt, authenticated, key); sshbuf_free(b); done: debug2("%s: authenticated %d", __func__, authenticated); sshkey_free(key); free(pkalg); free(pkblob); free(cuser); free(chost); free(sig); return authenticated; }
/* * We only support those mechanisms that we know about (ie ones that we know * how to check local user kuserok and the like) */ static int userauth_gssapi(struct ssh *ssh) { Authctxt *authctxt = ssh->authctxt; gss_OID_desc goid = {0, NULL}; Gssctxt *ctxt = NULL; int r, present; u_int mechs; OM_uint32 ms; size_t len; u_char *doid = NULL; if ((r = sshpkt_get_u32(ssh, &mechs)) != 0) fatal("%s: %s", __func__, ssh_err(r)); if (mechs == 0) { debug("Mechanism negotiation is not supported"); return (0); } do { mechs--; free(doid); present = 0; if ((r = sshpkt_get_string(ssh, &doid, &len)) != 0) fatal("%s: %s", __func__, ssh_err(r)); if (len > 2 && doid[0] == SSH_GSS_OIDTYPE && doid[1] == len - 2) { goid.elements = doid + 2; goid.length = len - 2; ssh_gssapi_test_oid_supported(&ms, &goid, &present); } else { logit("Badly formed OID received"); } } while (mechs > 0 && !present); if (!present) { free(doid); authctxt->server_caused_failure = 1; return (0); } if (!authctxt->valid || authctxt->user == NULL) { debug2("%s: disabled because of invalid user", __func__); free(doid); return (0); } if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) { if (ctxt != NULL) ssh_gssapi_delete_ctx(&ctxt); free(doid); authctxt->server_caused_failure = 1; return (0); } authctxt->methoddata = (void *)ctxt; /* Return the OID that we received */ if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_GSSAPI_RESPONSE)) != 0 || (r = sshpkt_put_string(ssh, doid, len)) != 0 || (r = sshpkt_send(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); free(doid); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); authctxt->postponed = 1; return (0); }
static int input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh) { Authctxt *authctxt = ssh->authctxt; Gssctxt *gssctxt; gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; gss_buffer_desc recv_tok; OM_uint32 maj_status, min_status, flags; u_char *p; size_t len; int r; if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) fatal("No authentication or GSSAPI context"); gssctxt = authctxt->methoddata; if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 || (r = sshpkt_get_end(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); recv_tok.value = p; recv_tok.length = len; maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok, &flags)); free(p); if (GSS_ERROR(maj_status)) { if (send_tok.length != 0) { if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK)) != 0 || (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || (r = sshpkt_send(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); } authctxt->postponed = 0; ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); userauth_finish(ssh, 0, "gssapi-with-mic", NULL); } else { if (send_tok.length != 0) { if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN)) != 0 || (r = sshpkt_put_string(ssh, send_tok.value, send_tok.length)) != 0 || (r = sshpkt_send(ssh)) != 0) fatal("%s: %s", __func__, ssh_err(r)); } if (maj_status == GSS_S_COMPLETE) { ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); if (flags & GSS_C_INTEG_FLAG) ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC, &input_gssapi_mic); else ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, &input_gssapi_exchange_complete); } } gss_release_buffer(&min_status, &send_tok); return 0; }