I understand that OpenSSH server looks in /etc/ssh/moduli and picks a modulus at random for each Diffie-Hellman group exchange. What I am wondering is whether there is a practical limit on how many modulus lines can be in that file.

Would an absurdly large number, such as 50,000 lines, pose a problem or create some weird behavior?

Most likely 4294967295.

In the source file dh.c, the moduli file is opened with fopen, and a fgets loop is used to extract each line. The current line being processed is recorded in a variable declared as int linenum. This means it is a 32 bit signed integer, capable of representing 232 possible values. Since it is signed, this equates to -2147483648 to 2147483647 (one less because 0 is still a number and is considered positive). Since it starts at 0 and increments, the maximum value is thus 232 / 2 - 1. It will become negative if it exceeds this bound and wraps around.

There is some conversion between signed and unsigned in the source code. The int linenum holds the number of lines, while int bestcount has the number of suitable lines and is passed to arc4random_uniform, which outputs a random value between 0 and bestcount. The value it accepts and the value it returns is unsigned, but it is stored in another signed integer, which. That integer is used to specify which random line is to be used. If the number of lines exceeds what an 32 bit integer can hold, the random choice of line's upper bound will be smaller, perhaps much smaller, than the actual number of lines.

This limitation is not an issue in practice. The maximum length of a line is 4096 bytes, and 232 lines (not - 1 because the first line starts at 0) of 4096 bytes each gives a maximum file size of 16 terabytes! Good luck waiting for openssl dhparam to generate terabytes of moduli.

The whole function in the source code, as of OpenSSH 7.5p1:

DH *
choose_dh(int min, int wantbits, int max)
{
    FILE *f;
    char line[4096];
    int best, bestcount, which;
    int linenum;
    struct dhgroup dhg;

    if ((f = fopen(_PATH_DH_MODULI, "r")) == NULL) {
        logit("WARNING: could not open %s (%s), using fixed modulus",
            _PATH_DH_MODULI, strerror(errno));
        return (dh_new_group_fallback(max));
    }

    linenum = 0;
    best = bestcount = 0;
    while (fgets(line, sizeof(line), f)) {
        linenum++;
        if (!parse_prime(linenum, line, &dhg))
            continue;
        BN_clear_free(dhg.g);
        BN_clear_free(dhg.p);

        if (dhg.size > max || dhg.size < min)
            continue;

        if ((dhg.size > wantbits && dhg.size < best) ||
            (dhg.size > best && best < wantbits)) {
            best = dhg.size;
            bestcount = 0;
        }
        if (dhg.size == best)
            bestcount++;
    }
    rewind(f);

    if (bestcount == 0) {
        fclose(f);
        logit("WARNING: no suitable primes in %s", _PATH_DH_MODULI);
        return (dh_new_group_fallback(max));
    }

    linenum = 0;
    which = arc4random_uniform(bestcount);
    while (fgets(line, sizeof(line), f)) {
        if (!parse_prime(linenum, line, &dhg))
            continue;
        if ((dhg.size > max || dhg.size < min) ||
            dhg.size != best ||
            linenum++ != which) {
            BN_clear_free(dhg.g);
            BN_clear_free(dhg.p);
            continue;
        }
        break;
    }
    fclose(f);
    if (linenum != which+1) {
        logit("WARNING: line %d disappeared in %s, giving up",
            which, _PATH_DH_MODULI);
        return (dh_new_group_fallback(max));
    }

    return (dh_new_group(dhg.g, dhg.p));
}

Note that this is all from a cursory glance at the source code. If there are other issues that may occur down the line for reasons I can't predict caused by a large file, the upper limit may be smaller. I don't see any reason to think it would be, though.

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.