Commit message: bn/asm/x86_64-mont5.pl: fix carry propagating bug (CVE-2015-3193).

Reviewed-by: Richard Levitte <levitte@openssl.org>
(cherry picked from commit e7c078db57908cbf16074c68034977565ffaf107)
CVE: CVE-2015-3193
CWE: CWE-200
Vulnerability description: The Montgomery squaring implementation in crypto/bn/asm/x86_64-mont5.pl in OpenSSL 1.0.2 before 1.0.2e on the x86_64 platform, as used by the BN_mod_exp function, mishandles carry propagation and produces incorrect output, which makes it easier for remote attackers to obtain sensitive private-key information via an attack against use of a (1) Diffie-Hellman (DH) or (2) Diffie-Hellman Ephemeral (DHE) ciphersuite.

Project: openssl

int test_add(BIO *bp)
{
    BIGNUM a, b, c;
    int i;

    BN_init(&a);
    BN_init(&b);
    BN_init(&c);

    BN_bntest_rand(&a, 512, 0, 0);
    for (i = 0; i < num0; i++) {
        BN_bntest_rand(&b, 450 + i, 0, 0);
        a.neg = rand_neg();
        b.neg = rand_neg();
        BN_add(&c, &a, &b);
        if (bp != NULL) {
            if (!results) {
                BN_print(bp, &a);
                BIO_puts(bp, " + ");
                BN_print(bp, &b);
                BIO_puts(bp, " - ");
            }
            BN_print(bp, &c);
            BIO_puts(bp, "\n");
        }
        a.neg = !a.neg;
        b.neg = !b.neg;
        BN_add(&c, &c, &b);
        BN_add(&c, &c, &a);
        if (!BN_is_zero(&c)) {
            fprintf(stderr, "Add test failed!\n");
            return 0;
        }
    }
    BN_free(&a);
    BN_free(&b);
    BN_free(&c);
    return (1);
}

Project: openssl

int test_div(BIO *bp, BN_CTX *ctx)
{
    BIGNUM a, b, c, d, e;
    int i;

    BN_init(&a);
    BN_init(&b);
    BN_init(&c);
    BN_init(&d);
    BN_init(&e);

    BN_one(&a);
    BN_zero(&b);

    if (BN_div(&d, &c, &a, &b, ctx)) {
        fprintf(stderr, "Division by zero succeeded!\n");
        return 0;
    }

    for (i = 0; i < num0 + num1; i++) {
        if (i < num1) {
            BN_bntest_rand(&a, 400, 0, 0);
            BN_copy(&b, &a);
            BN_lshift(&a, &a, i);
            BN_add_word(&a, i);
        } else
            BN_bntest_rand(&b, 50 + 3 * (i - num1), 0, 0);
        a.neg = rand_neg();
        b.neg = rand_neg();
        BN_div(&d, &c, &a, &b, ctx);
        if (bp != NULL) {
            if (!results) {
                BN_print(bp, &a);
                BIO_puts(bp, " / ");
                BN_print(bp, &b);
                BIO_puts(bp, " - ");
            }
            BN_print(bp, &d);
            BIO_puts(bp, "\n");

            if (!results) {
                BN_print(bp, &a);
                BIO_puts(bp, " % ");
                BN_print(bp, &b);
                BIO_puts(bp, " - ");
            }
            BN_print(bp, &c);
            BIO_puts(bp, "\n");
        }
        BN_mul(&e, &d, &b, ctx);
        BN_add(&d, &e, &c);
        BN_sub(&d, &d, &a);
        if (!BN_is_zero(&d)) {
            fprintf(stderr, "Division test failed!\n");
            return 0;
        }
    }
    BN_free(&a);
    BN_free(&b);
    BN_free(&c);
    BN_free(&d);
    BN_free(&e);
    return (1);
}

Project: openssl

int test_gf2m_mod_div(BIO *bp, BN_CTX *ctx)
{
    BIGNUM *a, *b[2], *c, *d, *e, *f;
    int i, j, ret = 0;
    int p0[] = { 163, 7, 6, 3, 0, -1 };
    int p1[] = { 193, 15, 0, -1 };

    a = BN_new();
    b[0] = BN_new();
    b[1] = BN_new();
    c = BN_new();
    d = BN_new();
    e = BN_new();
    f = BN_new();

    BN_GF2m_arr2poly(p0, b[0]);
    BN_GF2m_arr2poly(p1, b[1]);

    for (i = 0; i < num0; i++) {
        BN_bntest_rand(a, 512, 0, 0);
        BN_bntest_rand(c, 512, 0, 0);
        for (j = 0; j < 2; j++) {
            BN_GF2m_mod_div(d, a, c, b[j], ctx);
            BN_GF2m_mod_mul(e, d, c, b[j], ctx);
            BN_GF2m_mod_div(f, a, e, b[j], ctx);
# if 0                          /* make test uses ouput in bc but bc can't
                                 * handle GF(2^m) arithmetic */
            if (bp != NULL) {
                if (!results) {
                    BN_print(bp, a);
                    BIO_puts(bp, " = ");
                    BN_print(bp, c);
                    BIO_puts(bp, " * ");
                    BN_print(bp, d);
                    BIO_puts(bp, " % ");
                    BN_print(bp, b[j]);
                    BIO_puts(bp, "\n");
                }
            }
# endif
            /* Test that ((a/c)*c)/a = 1. */
            if (!BN_is_one(f)) {
                fprintf(stderr, "GF(2^m) modular division test failed!\n");
                goto err;
            }
        }
    }
    ret = 1;
 err:
    BN_free(a);
    BN_free(b[0]);
    BN_free(b[1]);
    BN_free(c);
    BN_free(d);
    BN_free(e);
    BN_free(f);
    return ret;
}

Project: openssl

int test_lshift(BIO *bp, BN_CTX *ctx, BIGNUM *a_)
{
    BIGNUM *a, *b, *c, *d;
    int i;

    b = BN_new();
    c = BN_new();
    d = BN_new();
    BN_one(c);

    if (a_)
        a = a_;
    else {
        a = BN_new();
        BN_bntest_rand(a, 200, 0, 0);
        a->neg = rand_neg();
    }
    for (i = 0; i < num0; i++) {
        BN_lshift(b, a, i + 1);
        BN_add(c, c, c);
        if (bp != NULL) {
            if (!results) {
                BN_print(bp, a);
                BIO_puts(bp, " * ");
                BN_print(bp, c);
                BIO_puts(bp, " - ");
            }
            BN_print(bp, b);
            BIO_puts(bp, "\n");
        }
        BN_mul(d, a, c, ctx);
        BN_sub(d, d, b);
        if (!BN_is_zero(d)) {
            fprintf(stderr, "Left shift test failed!\n");
            fprintf(stderr, "a=");
            BN_print_fp(stderr, a);
            fprintf(stderr, "\nb=");
            BN_print_fp(stderr, b);
            fprintf(stderr, "\nc=");
            BN_print_fp(stderr, c);
            fprintf(stderr, "\nd=");
            BN_print_fp(stderr, d);
            fprintf(stderr, "\n");
            return 0;
        }
    }
    BN_free(a);
    BN_free(b);
    BN_free(c);
    BN_free(d);
    return (1);
}

Project: openssl

int test_sqrt(BIO *bp, BN_CTX *ctx)
{
    BN_GENCB cb;
    BIGNUM *a, *p, *r;
    int i, j;
    int ret = 0;

    a = BN_new();
    p = BN_new();
    r = BN_new();
    if (a == NULL || p == NULL || r == NULL)
        goto err;

    BN_GENCB_set(&cb, genprime_cb, NULL);

    for (i = 0; i < 16; i++) {
        if (i < 8) {
            unsigned primes[8] = { 2, 3, 5, 7, 11, 13, 17, 19 };

            if (!BN_set_word(p, primes[i]))
                goto err;
        } else {
            if (!BN_set_word(a, 32))
                goto err;
            if (!BN_set_word(r, 2 * i + 1))
                goto err;

            if (!BN_generate_prime_ex(p, 256, 0, a, r, &cb))
                goto err;
            putc('\n', stderr);
        }
        p->neg = rand_neg();

        for (j = 0; j < num2; j++) {
            /*
             * construct 'a' such that it is a square modulo p, but in
             * general not a proper square and not reduced modulo p
             */
            if (!BN_bntest_rand(r, 256, 0, 3))
                goto err;
            if (!BN_nnmod(r, r, p, ctx))
                goto err;
            if (!BN_mod_sqr(r, r, p, ctx))
                goto err;
            if (!BN_bntest_rand(a, 256, 0, 3))
                goto err;
            if (!BN_nnmod(a, a, p, ctx))
                goto err;
            if (!BN_mod_sqr(a, a, p, ctx))
                goto err;
            if (!BN_mul(a, a, r, ctx))
                goto err;
            if (rand_neg())
                if (!BN_sub(a, a, p))
                    goto err;

            if (!BN_mod_sqrt(r, a, p, ctx))
                goto err;
            if (!BN_mod_sqr(r, r, p, ctx))
                goto err;

            if (!BN_nnmod(a, a, p, ctx))
                goto err;

            if (BN_cmp(a, r) != 0) {
                fprintf(stderr, "BN_mod_sqrt failed: a = ");
                BN_print_fp(stderr, a);
                fprintf(stderr, ", r = ");
                BN_print_fp(stderr, r);
                fprintf(stderr, ", p = ");
                BN_print_fp(stderr, p);
                fprintf(stderr, "\n");
                goto err;
            }

            putc('.', stderr);
            fflush(stderr);
        }

        putc('\n', stderr);
        fflush(stderr);
    }
    ret = 1;
 err:
    if (a != NULL)
        BN_free(a);
    if (p != NULL)
        BN_free(p);
    if (r != NULL)
        BN_free(r);
    return ret;
}