/* * Checks whether key is allowed in authorized_keys-format file, * returns 1 if the key is allowed or 0 otherwise. */ static int check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) { char line[SSH_MAX_PUBKEY_BYTES]; const char *reason; int found_key = 0; u_long linenum = 0; Key *found; char *fp; found_key = 0; found = NULL; while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { char *cp, *key_options = NULL; if (found != NULL) key_free(found); found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); auth_clear_options(); /* Skip leading whitespace, empty and comment lines. */ for (cp = line; *cp == ' ' || *cp == '\t'; cp++) ; if (!*cp || *cp == '\n' || *cp == '#') continue; if (key_read(found, &cp) != 1) { /* no key? check if there are options for this key */ int quoted = 0; debug2("user_key_allowed: check options: '%s'", cp); key_options = cp; for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { if (*cp == '\\' && cp[1] == '"') cp++; /* Skip both */ else if (*cp == '"') quoted = !quoted; } /* Skip remaining whitespace. */ for (; *cp == ' ' || *cp == '\t'; cp++) ; if (key_read(found, &cp) != 1) { debug2("user_key_allowed: advance: '%s'", cp); /* still no key? advance to next line*/ continue; } } if (key_is_cert(key)) { if (!key_equal(found, key->cert->signature_key)) continue; if (auth_parse_options(pw, key_options, file, linenum) != 1) continue; if (!key_is_cert_authority) continue; if ((fp = sshkey_fingerprint(found, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) continue; debug("matching CA found: file %s, line %lu, %s %s", file, linenum, key_type(found), fp); /* * If the user has specified a list of principals as * a key option, then prefer that list to matching * their username in the certificate principals list. */ if (authorized_principals != NULL && !match_principals_option(authorized_principals, key->cert)) { reason = "Certificate does not contain an " "authorized principal"; fail_reason: free(fp); error("%s", reason); auth_debug_add("%s", reason); continue; } if (key_cert_check_authority(key, 0, 0, authorized_principals == NULL ? pw->pw_name : NULL, &reason) != 0) goto fail_reason; if (auth_cert_options(key, pw) != 0) { free(fp); continue; } verbose("Accepted certificate ID \"%s\" " "signed by %s CA %s via %s", key->cert->key_id, key_type(found), fp, file); free(fp); found_key = 1; break; } else if (key_equal(found, key)) { if (auth_parse_options(pw, key_options, file, linenum) != 1) continue; if (key_is_cert_authority) continue; if ((fp = sshkey_fingerprint(found, options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) continue; debug("matching key found: file %s, line %lu %s %s", file, linenum, key_type(found), fp); free(fp); found_key = 1; break; } } if (found != NULL) key_free(found); if (!found_key) debug2("key not found"); return found_key; }
int mm_answer_keyallowed(int sock, Buffer *m) { Key *key; char *cuser, *chost; u_char *blob; u_int bloblen; enum mm_keytype type = 0; int allowed = 0; debug3("%s entering", __func__); type = buffer_get_int(m); cuser = buffer_get_string(m, NULL); chost = buffer_get_string(m, NULL); blob = buffer_get_string(m, &bloblen); key = key_from_blob(blob, bloblen); if ((compat20 && type == MM_RSAHOSTKEY) || (!compat20 && type != MM_RSAHOSTKEY)) fatal("%s: key type and protocol mismatch", __func__); debug3("%s: key_from_blob: %p", __func__, key); if (key != NULL && authctxt->valid) { switch (type) { case MM_USERKEY: allowed = options.pubkey_authentication && user_key_allowed(authctxt->pw, key); auth_method = "publickey"; break; case MM_HOSTKEY: allowed = options.hostbased_authentication && hostbased_key_allowed(authctxt->pw, cuser, chost, key); auth_method = "hostbased"; break; case MM_RSAHOSTKEY: key->type = KEY_RSA1; /* XXX */ allowed = options.rhosts_rsa_authentication && auth_rhosts_rsa_key_allowed(authctxt->pw, cuser, chost, key); auth_method = "rsa"; break; default: fatal("%s: unknown key type %d", __func__, type); break; } } if (key != NULL) key_free(key); /* clear temporarily storage (used by verify) */ monitor_reset_key_state(); if (allowed) { /* Save temporarily for comparison in verify */ key_blob = blob; key_bloblen = bloblen; key_blobtype = type; hostbased_cuser = cuser; hostbased_chost = chost; } else { /* Log failed attempt */ auth_log(authctxt, 0, auth_method, compat20 ? " ssh2" : ""); xfree(blob); xfree(cuser); xfree(chost); } debug3("%s: key %p is %s", __func__, key, allowed ? "allowed" : "disallowed"); buffer_clear(m); buffer_put_int(m, allowed); buffer_put_int(m, forced_command != NULL); mm_append_debug(m); mm_request_send(sock, MONITOR_ANS_KEYALLOWED, m); if (type == MM_RSAHOSTKEY) monitor_permit(mon_dispatch, MONITOR_REQ_RSACHALLENGE, allowed); return (0); }
/* * Checks if the user has an authentication agent, and if so, tries to * authenticate using the agent. */ static int try_agent_authentication(void) { int type; char *comment; AuthenticationConnection *auth; u_char response[16]; u_int i; Key *key; BIGNUM *challenge; /* Get connection to the agent. */ auth = ssh_get_authentication_connection(); if (!auth) return 0; if ((challenge = BN_new()) == NULL) fatal("try_agent_authentication: BN_new failed"); /* Loop through identities served by the agent. */ for (key = ssh_get_first_identity(auth, &comment, 1); key != NULL; key = ssh_get_next_identity(auth, &comment, 1)) { /* Try this identity. */ debug("Trying RSA authentication via agent with '%.100s'", comment); xfree(comment); /* Tell the server that we are willing to authenticate using this key. */ packet_start(SSH_CMSG_AUTH_RSA); packet_put_bignum(key->rsa->n); packet_send(); packet_write_wait(); /* Wait for server's response. */ type = packet_read(); /* The server sends failure if it doesn\'t like our key or does not support RSA authentication. */ if (type == SSH_SMSG_FAILURE) { debug("Server refused our key."); key_free(key); continue; } /* Otherwise it should have sent a challenge. */ if (type != SSH_SMSG_AUTH_RSA_CHALLENGE) packet_disconnect("Protocol error during RSA authentication: %d", type); packet_get_bignum(challenge); packet_check_eom(); debug("Received RSA challenge from server."); /* Ask the agent to decrypt the challenge. */ if (!ssh_decrypt_challenge(auth, key, challenge, session_id, 1, response)) { /* * The agent failed to authenticate this identifier * although it advertised it supports this. Just * return a wrong value. */ log("Authentication agent failed to decrypt challenge."); memset(response, 0, sizeof(response)); } key_free(key); debug("Sending response to RSA challenge."); /* Send the decrypted challenge back to the server. */ packet_start(SSH_CMSG_AUTH_RSA_RESPONSE); for (i = 0; i < 16; i++) packet_put_char(response[i]); packet_send(); packet_write_wait(); /* Wait for response from the server. */ type = packet_read(); /* The server returns success if it accepted the authentication. */ if (type == SSH_SMSG_SUCCESS) { ssh_close_authentication_connection(auth); BN_clear_free(challenge); debug("RSA authentication accepted by server."); return 1; } /* Otherwise it should return failure. */ if (type != SSH_SMSG_FAILURE) packet_disconnect("Protocol error waiting RSA auth response: %d", type); } ssh_close_authentication_connection(auth); BN_clear_free(challenge); debug("RSA authentication using agent refused."); return 0; }
static int valid_request(struct passwd *pw, char *host, Key **ret, u_char *data, u_int datalen) { Buffer b; Key *key = NULL; u_char *pkblob; u_int blen, len; char *pkalg, *p; int pktype, fail; fail = 0; buffer_init(&b); buffer_append(&b, data, datalen); /* session id, currently limited to SHA1 (20 bytes) */ p = buffer_get_string(&b, &len); if (len != 20) fail++; xfree(p); if (buffer_get_char(&b) != SSH2_MSG_USERAUTH_REQUEST) fail++; /* server user */ buffer_skip_string(&b); /* service */ p = buffer_get_string(&b, NULL); if (strcmp("ssh-connection", p) != 0) fail++; xfree(p); /* method */ p = buffer_get_string(&b, NULL); if (strcmp("hostbased", p) != 0) fail++; xfree(p); /* pubkey */ pkalg = buffer_get_string(&b, NULL); pkblob = buffer_get_string(&b, &blen); pktype = key_type_from_name(pkalg); if (pktype == KEY_UNSPEC) fail++; else if ((key = key_from_blob(pkblob, blen)) == NULL) fail++; else if (key->type != pktype) fail++; xfree(pkalg); xfree(pkblob); /* client host name, handle trailing dot */ p = buffer_get_string(&b, &len); debug2("valid_request: check expect chost %s got %s", host, p); if (strlen(host) != len - 1) fail++; else if (p[len - 1] != '.') fail++; else if (strncasecmp(host, p, len - 1) != 0) fail++; xfree(p); /* local user */ p = buffer_get_string(&b, NULL); if (strcmp(pw->pw_name, p) != 0) fail++; xfree(p); /* end of message */ if (buffer_len(&b) != 0) fail++; buffer_free(&b); debug3("valid_request: fail %d", fail); if (fail && key != NULL) key_free(key); else *ret = key; return (fail ? -1 : 0); }
static int userauth_hostbased(Authctxt *authctxt) { Buffer b; Key *key = NULL; char *pkalg, *cuser, *chost, *service; u_char *pkblob, *sig; u_int alen, blen, slen; int pktype; int authenticated = 0; if (!authctxt->valid) { debug2("userauth_hostbased: disabled because of invalid user"); return 0; } pkalg = packet_get_string(&alen); pkblob = packet_get_string(&blen); chost = packet_get_string(NULL); cuser = packet_get_string(NULL); sig = packet_get_string(&slen); debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d", cuser, chost, pkalg, slen); #ifdef DEBUG_PK debug("signature:"); buffer_init(&b); buffer_append(&b, sig, slen); buffer_dump(&b); buffer_free(&b); #endif pktype = key_type_from_name(pkalg); if (pktype == KEY_UNSPEC) { /* this is perfectly legal */ logit("userauth_hostbased: unsupported " "public key algorithm: %s", pkalg); goto done; } key = key_from_blob(pkblob, blen); if (key == NULL) { error("userauth_hostbased: cannot decode key: %s", pkalg); goto done; } if (key->type != pktype) { error("userauth_hostbased: type mismatch for decoded key " "(received %d, expected %d)", key->type, pktype); goto done; } service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" : authctxt->service; buffer_init(&b); 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, service); buffer_put_cstring(&b, "hostbased"); buffer_put_string(&b, pkalg, alen); buffer_put_string(&b, pkblob, blen); buffer_put_cstring(&b, chost); buffer_put_cstring(&b, cuser); #ifdef DEBUG_PK buffer_dump(&b); #endif pubkey_auth_info(authctxt, key, "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(key_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b))) == 1) authenticated = 1; buffer_free(&b); done: debug2("userauth_hostbased: authenticated %d", authenticated); if (key != NULL) key_free(key); free(pkalg); free(pkblob); free(cuser); free(chost); free(sig); return authenticated; }