SSH 公钥私钥匹配的问题

本人对SSH不是很了解,比如一般linux在设置ssh(rsa)登入的时候 会在 authorizedkeys文件中设置多个公钥。github也是如此,可以在用户设置下设置多个不同的公钥。当一个用户用ssh自己的私钥发起请求时,ssh服务器是如何确定哪一个公钥是与当前访问用户的私钥是匹配的(个人觉得不太可能是循环所有公钥去一个个验证)。

我不明白你的意思,不过我设置都是在kangle里面设置。

当然是循环一个个去匹配,这个验证就是这么处理的,这个只有最开始建立连接的时候处理一次。

说下我对ssh的理解。
每个用户有自己的ssh公钥和私钥(使用ssh-keygen创建),一般保存在用户home目录下的.ssh目录中。用户通过ssh客户端远程登录ssh服务器时,是向服务器发送他自己的公钥(私钥只有用户自己知道,是不公开的)。
authorized_keys中保存的是其他客户机的ssh公钥,从而这些公钥对应的客户机可以实现无密码登录ssh服务器。

openssh auth-rsa.c文件 不知道这个函数是否说明是循环处理比对的

 static int
rsa_key_allowed_in_file(struct passwd *pw, char *file,
    const BIGNUM *client_n, Key **rkey)
{
    char *fp, line[SSH_MAX_PUBKEY_BYTES];
    int allowed = 0, bits;
    FILE *f;
    u_long linenum = 0;
    Key *key;

    debug("trying public RSA key file %s", file);
    if ((f = auth_openkeyfile(file, pw, options.strict_modes)) == NULL)
        return 0;

    /*
     * Go though the accepted keys, looking for the current key.  If
     * found, perform a challenge-response dialog to verify that the
     * user really has the corresponding private key.
     */
    key = key_new(KEY_RSA1);
    while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) {
        char *cp;
        char *key_options;
        int keybits;

        /* Skip leading whitespace, empty and comment lines. */
        for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
            ;
        if (!*cp || *cp == '\n' || *cp == '#')
            continue;

        /*
         * Check if there are options for this key, and if so,
         * save their starting address and skip the option part
         * for now.  If there are no options, set the starting
         * address to NULL.
         */
        if (*cp < '0' || *cp > '9') {
            int quoted = 0;
            key_options = cp;
            for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
                if (*cp == '\\' && cp[1] == '"')
                    cp++;   /* Skip both */
                else if (*cp == '"')
                    quoted = !quoted;
            }
        } else
            key_options = NULL;

        /* Parse the key from the line. */
        if (hostfile_read_key(&cp, &bits, key) == 0) {
            debug("%.100s, line %lu: non ssh1 key syntax",
                file, linenum);
            continue;
        }
        /* cp now points to the comment part. */

        /*
         * Check if the we have found the desired key (identified
         * by its modulus).
         */
        if (BN_cmp(key->rsa->n, client_n) != 0)
            continue;

        /* check the real bits  */
        keybits = BN_num_bits(key->rsa->n);
        if (keybits < 0 || bits != keybits)
            logit("Warning: %s, line %lu: keysize mismatch: "
                "actual %d vs. announced %d.",
                file, linenum, BN_num_bits(key->rsa->n), bits);

        if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
            SSH_FP_DEFAULT)) == NULL)
            continue;
        debug("matching key found: file %s, line %lu %s %s",
            file, linenum, key_type(key), fp);
        free(fp);

        /* Never accept a revoked key */
        if (auth_key_is_revoked(key))
            break;

        /* We have found the desired key. */
        /*
         * If our options do not allow this key to be used,
         * do not send challenge.
         */
        if (!auth_parse_options(pw, key_options, file, linenum))
            continue;
        if (key_is_cert_authority)
            continue;
        /* break out, this key is allowed */
        allowed = 1;
        break;
    }

    /* Close the file. */
    fclose(f);

    /* return key if allowed */
    if (allowed && rkey != NULL)
        *rkey = key;
    else
        key_free(key);

    return allowed;
}