/* S = (A * v^u) ^ b % N * this is our shared key (server premaster secret) */ mpi_t _gnutls_calc_srp_S1 (mpi_t A, mpi_t b, mpi_t u, mpi_t v, mpi_t n) { mpi_t tmp1 = NULL, tmp2 = NULL; mpi_t S = NULL; S = _gnutls_mpi_alloc_like (n); if (S == NULL) return NULL; tmp1 = _gnutls_mpi_alloc_like (n); tmp2 = _gnutls_mpi_alloc_like (n); if (tmp1 == NULL || tmp2 == NULL) goto freeall; _gnutls_mpi_powm (tmp1, v, u, n); _gnutls_mpi_mulm (tmp2, A, tmp1, n); _gnutls_mpi_powm (S, tmp2, b, n); _gnutls_mpi_release (&tmp1); _gnutls_mpi_release (&tmp2); return S; freeall: _gnutls_mpi_release (&tmp1); _gnutls_mpi_release (&tmp2); return NULL; }
/* S = (B - k*g^x) ^ (a + u * x) % N * this is our shared key (client premaster secret) */ bigint_t _gnutls_calc_srp_S2 (bigint_t B, bigint_t g, bigint_t x, bigint_t a, bigint_t u, bigint_t n) { bigint_t S = NULL, tmp1 = NULL, tmp2 = NULL; bigint_t tmp4 = NULL, tmp3 = NULL, k = NULL; S = _gnutls_mpi_alloc_like (n); if (S == NULL) return NULL; tmp1 = _gnutls_mpi_alloc_like (n); tmp2 = _gnutls_mpi_alloc_like (n); tmp3 = _gnutls_mpi_alloc_like (n); if (tmp1 == NULL || tmp2 == NULL || tmp3 == NULL) { goto freeall; } k = _gnutls_calc_srp_u (n, g, n); if (k == NULL) { gnutls_assert (); goto freeall; } _gnutls_mpi_powm (tmp1, g, x, n); /* g^x */ _gnutls_mpi_mulm (tmp3, tmp1, k, n); /* k*g^x mod n */ _gnutls_mpi_subm (tmp2, B, tmp3, n); tmp4 = _gnutls_mpi_alloc_like (n); if (tmp4 == NULL) goto freeall; _gnutls_mpi_mul (tmp1, u, x); _gnutls_mpi_add (tmp4, a, tmp1); _gnutls_mpi_powm (S, tmp2, tmp4, n); _gnutls_mpi_release (&tmp1); _gnutls_mpi_release (&tmp2); _gnutls_mpi_release (&tmp3); _gnutls_mpi_release (&tmp4); _gnutls_mpi_release (&k); return S; freeall: _gnutls_mpi_release (&k); _gnutls_mpi_release (&tmp1); _gnutls_mpi_release (&tmp2); _gnutls_mpi_release (&tmp3); _gnutls_mpi_release (&tmp4); _gnutls_mpi_release (&S); return NULL; }
/* A = g^a % N * returns A and a (which is random) */ bigint_t _gnutls_calc_srp_A (bigint_t * a, bigint_t g, bigint_t n) { bigint_t tmpa; bigint_t A; int bits; bits = _gnutls_mpi_get_nbits (n); tmpa = _gnutls_mpi_randomize (NULL, bits, GNUTLS_RND_RANDOM); A = _gnutls_mpi_new (bits); if (A == NULL) { gnutls_assert (); _gnutls_mpi_release (&tmpa); return NULL; } _gnutls_mpi_powm (A, g, tmpa, n); if (a != NULL) *a = tmpa; else _gnutls_mpi_release (&tmpa); return A; }
/* A = g^a % N * returns A and a (which is random) */ mpi_t _gnutls_calc_srp_A (mpi_t * a, mpi_t g, mpi_t n) { mpi_t tmpa; mpi_t A; int bits; bits = _gnutls_mpi_get_nbits (n); tmpa = _gnutls_mpi_snew (bits); if (tmpa == NULL) { gnutls_assert (); return NULL; } _gnutls_mpi_randomize (tmpa, bits, GCRY_STRONG_RANDOM); A = _gnutls_mpi_snew (bits); if (A == NULL) { gnutls_assert (); _gnutls_mpi_release (&tmpa); return NULL; } _gnutls_mpi_powm (A, g, tmpa, n); if (a != NULL) *a = tmpa; else _gnutls_mpi_release (&tmpa); return A; }
/* A = g^a % N * returns A and a (which is random) */ bigint_t _gnutls_calc_srp_A(bigint_t * a, bigint_t g, bigint_t n) { bigint_t tmpa; bigint_t A; int ret; ret = _gnutls_mpi_init_multi(&A, &tmpa, NULL); if (ret < 0) { gnutls_assert(); return NULL; } _gnutls_mpi_random_modp(tmpa, n, GNUTLS_RND_RANDOM); ret = _gnutls_mpi_powm(A, g, tmpa, n); if (ret < 0) goto error; if (a != NULL) *a = tmpa; else _gnutls_mpi_release(&tmpa); return A; error: _gnutls_mpi_release(&tmpa); _gnutls_mpi_release(&A); return NULL; }
/**************** * Choose a random value b and calculate B = (k* v + g^b) % N. * where k == SHA1(N|g) * Return: B and if ret_b is not NULL b. */ bigint_t _gnutls_calc_srp_B(bigint_t * ret_b, bigint_t g, bigint_t n, bigint_t v) { bigint_t tmpB = NULL, tmpV = NULL; bigint_t b = NULL, B = NULL, k = NULL; int ret; /* calculate: B = (k*v + g^b) % N */ ret = _gnutls_mpi_init_multi(&tmpV, &tmpB, &B, &b, NULL); if (ret < 0) return NULL; _gnutls_mpi_random_modp(b, n, GNUTLS_RND_RANDOM); k = _gnutls_calc_srp_u(n, g, n); if (k == NULL) { gnutls_assert(); goto error; } ret = _gnutls_mpi_mulm(tmpV, k, v, n); if (ret < 0) { gnutls_assert(); goto error; } ret = _gnutls_mpi_powm(tmpB, g, b, n); if (ret < 0) { gnutls_assert(); goto error; } ret = _gnutls_mpi_addm(B, tmpV, tmpB, n); if (ret < 0) { gnutls_assert(); goto error; } _gnutls_mpi_release(&k); _gnutls_mpi_release(&tmpB); _gnutls_mpi_release(&tmpV); if (ret_b) *ret_b = b; else _gnutls_mpi_release(&b); return B; error: _gnutls_mpi_release(&b); _gnutls_mpi_release(&B); _gnutls_mpi_release(&k); _gnutls_mpi_release(&tmpB); _gnutls_mpi_release(&tmpV); return NULL; }
/* returns the public value (X), and the secret (ret_x). */ mpi_t gnutls_calc_dh_secret (mpi_t * ret_x, mpi_t g, mpi_t prime) { mpi_t e, x; int x_size = _gnutls_mpi_get_nbits (prime) - 1; /* The size of the secret key is less than * prime/2 */ if (x_size > MAX_BITS || x_size <= 0) { gnutls_assert (); return NULL; } x = _gnutls_mpi_new (x_size); if (x == NULL) { gnutls_assert (); if (ret_x) *ret_x = NULL; return NULL; } /* FIXME: (x_size/8)*8 is there to overcome a bug in libgcrypt * which does not really check the bits given but the bytes. */ do { _gnutls_mpi_randomize (x, (x_size / 8) * 8, GCRY_STRONG_RANDOM); /* Check whether x is zero. */ } while (_gnutls_mpi_cmp_ui (x, 0) == 0); e = _gnutls_mpi_alloc_like (prime); if (e == NULL) { gnutls_assert (); if (ret_x) *ret_x = NULL; _gnutls_mpi_release (&x); return NULL; } _gnutls_mpi_powm (e, g, x, prime); if (ret_x) *ret_x = x; else _gnutls_mpi_release (&x); return e; }
/* returns the blinded c and the inverse of a random * number r; */ static bigint_t rsa_blind (bigint_t c, bigint_t e, bigint_t n, bigint_t * _ri) { bigint_t nc = NULL, r = NULL, ri = NULL; /* nc = c*(r^e) * ri = r^(-1) */ nc = _gnutls_mpi_alloc_like (n); if (nc == NULL) { gnutls_assert (); return NULL; } ri = _gnutls_mpi_alloc_like (n); if (nc == NULL) { gnutls_assert (); goto fail; } r = _gnutls_mpi_randomize (NULL, _gnutls_mpi_get_nbits (n), GNUTLS_RND_NONCE); if (r == NULL) { gnutls_assert (); goto fail; } /* invert r */ if (mpz_invert (ri, r, n) == 0) { gnutls_assert (); goto fail; } /* r = r^e */ _gnutls_mpi_powm (r, r, e, n); _gnutls_mpi_mulm (nc, c, r, n); *_ri = ri; _gnutls_mpi_release (&r); return nc; fail: _gnutls_mpi_release (&nc); _gnutls_mpi_release (&r); return NULL; }
/* S = (A * v^u) ^ b % N * this is our shared key (server premaster secret) */ bigint_t _gnutls_calc_srp_S1(bigint_t A, bigint_t b, bigint_t u, bigint_t v, bigint_t n) { bigint_t tmp1 = NULL, tmp2 = NULL; bigint_t S = NULL; int ret; ret = _gnutls_mpi_init_multi(&S, &tmp1, &tmp2, NULL); if (ret < 0) return NULL; ret = _gnutls_mpi_powm(tmp1, v, u, n); if (ret < 0) { gnutls_assert(); goto error; } ret = _gnutls_mpi_mulm(tmp2, A, tmp1, n); if (ret < 0) { gnutls_assert(); goto error; } _gnutls_mpi_powm(S, tmp2, b, n); _gnutls_mpi_release(&tmp1); _gnutls_mpi_release(&tmp2); return S; error: _gnutls_mpi_release(&S); _gnutls_mpi_release(&tmp1); _gnutls_mpi_release(&tmp2); return NULL; }
int _gnutls_srp_gx (opaque * text, size_t textsize, opaque ** result, bigint_t g, bigint_t prime, gnutls_alloc_function galloc_func) { bigint_t x, e; size_t result_size; int ret; if (_gnutls_mpi_scan_nz (&x, text, textsize)) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } e = _gnutls_mpi_alloc_like (prime); if (e == NULL) { gnutls_assert (); _gnutls_mpi_release (&x); return GNUTLS_E_MEMORY_ERROR; } /* e = g^x mod prime (n) */ _gnutls_mpi_powm (e, g, x, prime); _gnutls_mpi_release (&x); ret = _gnutls_mpi_print (e, NULL, &result_size); if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { *result = galloc_func (result_size); if ((*result) == NULL) return GNUTLS_E_MEMORY_ERROR; _gnutls_mpi_print (e, *result, &result_size); ret = result_size; } else { gnutls_assert (); ret = GNUTLS_E_MPI_PRINT_FAILED; } _gnutls_mpi_release (&e); return ret; }
static int _gnutls_srp_gx(uint8_t * text, size_t textsize, uint8_t ** result, bigint_t g, bigint_t prime) { bigint_t x, e = NULL; size_t result_size; int ret; if (_gnutls_mpi_init_scan_nz(&x, text, textsize)) { gnutls_assert(); return GNUTLS_E_MPI_SCAN_FAILED; } ret = _gnutls_mpi_init(&e); if (ret < 0) goto cleanup; /* e = g^x mod prime (n) */ ret = _gnutls_mpi_powm(e, g, x, prime); if (ret < 0) goto cleanup; ret = _gnutls_mpi_print(e, NULL, &result_size); if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) { *result = gnutls_malloc(result_size); if ((*result) == NULL) { ret = GNUTLS_E_MEMORY_ERROR; goto cleanup; } ret = _gnutls_mpi_print(e, *result, &result_size); if (ret < 0) goto cleanup; ret = result_size; } else { gnutls_assert(); ret = GNUTLS_E_MPI_PRINT_FAILED; } cleanup: _gnutls_mpi_release(&e); _gnutls_mpi_release(&x); return ret; }
mpi_t gnutls_calc_dh_key (mpi_t f, mpi_t x, mpi_t prime) { mpi_t k; int bits; bits = _gnutls_mpi_get_nbits (prime); if (bits <= 0 || bits > MAX_BITS) { gnutls_assert (); return NULL; } k = _gnutls_mpi_alloc_like (prime); if (k == NULL) return NULL; _gnutls_mpi_powm (k, f, x, prime); return k; }
int _gnutls_srp_gx (opaque * text, size_t textsize, opaque ** result, mpi_t g, mpi_t prime, gnutls_alloc_function galloc_func) { mpi_t x, e; size_t result_size; if (_gnutls_mpi_scan_nz (&x, text, &textsize)) { gnutls_assert (); return GNUTLS_E_MPI_SCAN_FAILED; } e = _gnutls_mpi_alloc_like (prime); if (e == NULL) { gnutls_assert (); _gnutls_mpi_release (&x); return GNUTLS_E_MEMORY_ERROR; } /* e = g^x mod prime (n) */ _gnutls_mpi_powm (e, g, x, prime); _gnutls_mpi_release (&x); _gnutls_mpi_print (NULL, &result_size, e); if (result != NULL) { *result = galloc_func (result_size); if ((*result) == NULL) return GNUTLS_E_MEMORY_ERROR; _gnutls_mpi_print (*result, &result_size, e); } _gnutls_mpi_release (&e); return result_size; }
/**************** * Choose a random value b and calculate B = (k* v + g^b) % N. * where k == SHA1(N|g) * Return: B and if ret_b is not NULL b. */ mpi_t _gnutls_calc_srp_B (mpi_t * ret_b, mpi_t g, mpi_t n, mpi_t v) { mpi_t tmpB = NULL, tmpV = NULL; mpi_t b = NULL, B = NULL, k = NULL; int bits; /* calculate: B = (k*v + g^b) % N */ bits = _gnutls_mpi_get_nbits (n); b = _gnutls_mpi_snew (bits); if (b == NULL) { gnutls_assert (); return NULL; } tmpV = _gnutls_mpi_alloc_like (n); if (tmpV == NULL) { gnutls_assert (); goto error; } _gnutls_mpi_randomize (b, bits, GCRY_STRONG_RANDOM); tmpB = _gnutls_mpi_snew (bits); if (tmpB == NULL) { gnutls_assert (); goto error; } B = _gnutls_mpi_snew (bits); if (B == NULL) { gnutls_assert (); goto error; } k = _gnutls_calc_srp_u (n, g, n); if (k == NULL) { gnutls_assert (); goto error; } _gnutls_mpi_mulm (tmpV, k, v, n); _gnutls_mpi_powm (tmpB, g, b, n); _gnutls_mpi_addm (B, tmpV, tmpB, n); _gnutls_mpi_release (&k); _gnutls_mpi_release (&tmpB); _gnutls_mpi_release (&tmpV); if (ret_b) *ret_b = b; else _gnutls_mpi_release (&b); return B; error: _gnutls_mpi_release (&b); _gnutls_mpi_release (&B); _gnutls_mpi_release (&k); _gnutls_mpi_release (&tmpB); _gnutls_mpi_release (&tmpV); return NULL; }
static int wrap_nettle_pk_verify_params(gnutls_pk_algorithm_t algo, const gnutls_pk_params_st * params) { int ret; switch (algo) { case GNUTLS_PK_RSA: { bigint_t t1 = NULL, t2 = NULL; if (params->params_nr != RSA_PRIVATE_PARAMS) return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST); t1 = _gnutls_mpi_new(256); if (t1 == NULL) return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); _gnutls_mpi_mulm(t1, params->params[RSA_PRIME1], params->params[RSA_PRIME2], params->params[RSA_MODULUS]); if (_gnutls_mpi_cmp_ui(t1, 0) != 0) { ret = gnutls_assert_val (GNUTLS_E_ILLEGAL_PARAMETER); goto rsa_cleanup; } mpz_invert(TOMPZ(t1), TOMPZ(params->params[RSA_PRIME2]), TOMPZ(params->params[RSA_PRIME1])); if (_gnutls_mpi_cmp(t1, params->params[RSA_COEF]) != 0) { ret = gnutls_assert_val (GNUTLS_E_ILLEGAL_PARAMETER); goto rsa_cleanup; } /* [RSA_PRIME1] = d % p-1, [RSA_PRIME2] = d % q-1 */ _gnutls_mpi_sub_ui(t1, params->params[RSA_PRIME1], 1); t2 = _gnutls_mpi_mod(params->params[RSA_PRIV], t1); if (t2 == NULL) { ret = gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); goto rsa_cleanup; } if (_gnutls_mpi_cmp(params->params[RSA_E1], t2) != 0) { ret = gnutls_assert_val (GNUTLS_E_ILLEGAL_PARAMETER); goto rsa_cleanup; } _gnutls_mpi_sub_ui(t1, params->params[RSA_PRIME2], 1); _gnutls_mpi_release(&t2); t2 = _gnutls_mpi_mod(params->params[RSA_PRIV], t1); if (t2 == NULL) { ret = gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); goto rsa_cleanup; } if (_gnutls_mpi_cmp(params->params[RSA_E2], t2) != 0) { ret = gnutls_assert_val (GNUTLS_E_ILLEGAL_PARAMETER); goto rsa_cleanup; } ret = 0; rsa_cleanup: _gnutls_mpi_release(&t1); _gnutls_mpi_release(&t2); } break; case GNUTLS_PK_DSA: { bigint_t t1 = NULL; if (params->params_nr != DSA_PRIVATE_PARAMS) return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST); t1 = _gnutls_mpi_new(256); if (t1 == NULL) return gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); _gnutls_mpi_powm(t1, params->params[DSA_G], params->params[DSA_X], params->params[DSA_P]); if (_gnutls_mpi_cmp(t1, params->params[DSA_Y]) != 0) { ret = gnutls_assert_val (GNUTLS_E_ILLEGAL_PARAMETER); goto dsa_cleanup; } ret = 0; dsa_cleanup: _gnutls_mpi_release(&t1); } break; case GNUTLS_PK_EC: { struct ecc_point r, pub; struct ecc_scalar priv; mpz_t x1, y1, x2, y2; const struct ecc_curve *curve; if (params->params_nr != ECC_PRIVATE_PARAMS) return gnutls_assert_val (GNUTLS_E_INVALID_REQUEST); curve = get_supported_curve(params->flags); if (curve == NULL) return gnutls_assert_val (GNUTLS_E_ECC_UNSUPPORTED_CURVE); ret = _ecc_params_to_pubkey(params, &pub, curve); if (ret < 0) return gnutls_assert_val(ret); ret = _ecc_params_to_privkey(params, &priv, curve); if (ret < 0) { ecc_point_clear(&pub); return gnutls_assert_val(ret); } ecc_point_init(&r, curve); /* verify that x,y lie on the curve */ ret = ecc_point_set(&r, TOMPZ(params->params[ECC_X]), TOMPZ(params->params[ECC_Y])); if (ret == 0) { ret = gnutls_assert_val (GNUTLS_E_ILLEGAL_PARAMETER); goto ecc_cleanup; } ecc_point_clear(&r); ecc_point_init(&r, curve); ecc_point_mul_g(&r, &priv); mpz_init(x1); mpz_init(y1); ecc_point_get(&r, x1, y1); ecc_point_clear(&r); mpz_init(x2); mpz_init(y2); ecc_point_get(&pub, x2, y2); /* verify that k*(Gx,Gy)=(x,y) */ if (mpz_cmp(x1, x2) != 0 || mpz_cmp(y1, y2) != 0) { ret = gnutls_assert_val (GNUTLS_E_ILLEGAL_PARAMETER); goto ecc_cleanup; } ret = 0; ecc_cleanup: ecc_scalar_clear(&priv); ecc_point_clear(&pub); } break; default: ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); } return ret; }
/* This is used for DH or ECDH key derivation. In DH for example * it is given the peers Y and our x, and calculates Y^x */ static int _wrap_nettle_pk_derive(gnutls_pk_algorithm_t algo, gnutls_datum_t * out, const gnutls_pk_params_st * priv, const gnutls_pk_params_st * pub) { int ret; switch (algo) { case GNUTLS_PK_DH: { bigint_t f, x, prime; bigint_t k = NULL, ff = NULL; unsigned int bits; f = pub->params[DH_Y]; x = priv->params[DH_X]; prime = priv->params[DH_P]; ret = _gnutls_mpi_init_multi(&k, &ff, NULL); if (ret < 0) return gnutls_assert_val(ret); ret = _gnutls_mpi_modm(ff, f, prime); if (ret < 0) { gnutls_assert(); goto dh_cleanup; } ret = _gnutls_mpi_add_ui(ff, ff, 1); if (ret < 0) { gnutls_assert(); goto dh_cleanup; } /* check if f==0,1,p-1. * or (ff=f+1) equivalently ff==1,2,p */ if ((_gnutls_mpi_cmp_ui(ff, 2) == 0) || (_gnutls_mpi_cmp_ui(ff, 1) == 0) || (_gnutls_mpi_cmp(ff, prime) == 0)) { gnutls_assert(); ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; goto dh_cleanup; } /* prevent denial of service */ bits = _gnutls_mpi_get_nbits(prime); if (bits == 0 || bits > MAX_DH_BITS) { gnutls_assert(); ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; goto dh_cleanup; } ret = _gnutls_mpi_powm(k, f, x, prime); if (ret < 0) { gnutls_assert(); goto dh_cleanup; } ret = _gnutls_mpi_dprint(k, out); if (ret < 0) { gnutls_assert(); goto dh_cleanup; } ret = 0; dh_cleanup: _gnutls_mpi_release(&ff); zrelease_temp_mpi_key(&k); if (ret < 0) goto cleanup; break; } case GNUTLS_PK_EC: { struct ecc_scalar ecc_priv; struct ecc_point ecc_pub; const struct ecc_curve *curve; out->data = NULL; curve = get_supported_curve(priv->flags); if (curve == NULL) return gnutls_assert_val (GNUTLS_E_ECC_UNSUPPORTED_CURVE); ret = _ecc_params_to_pubkey(pub, &ecc_pub, curve); if (ret < 0) return gnutls_assert_val(ret); ret = _ecc_params_to_privkey(priv, &ecc_priv, curve); if (ret < 0) { ecc_point_clear(&ecc_pub); return gnutls_assert_val(ret); } out->size = gnutls_ecc_curve_get_size(priv->flags); /*ecc_size(curve)*sizeof(mp_limb_t); */ out->data = gnutls_malloc(out->size); if (out->data == NULL) { ret = gnutls_assert_val (GNUTLS_E_MEMORY_ERROR); goto ecc_cleanup; } ecc_shared_secret(&ecc_priv, &ecc_pub, out->data, out->size); ecc_cleanup: ecc_point_clear(&ecc_pub); ecc_scalar_zclear(&ecc_priv); if (ret < 0) goto cleanup; break; } default: gnutls_assert(); ret = GNUTLS_E_INTERNAL_ERROR; goto cleanup; } ret = 0; cleanup: return ret; }
/* Check if N is a prime and G a generator of the * group. This is check only done if N is big enough. * Otherwise only the included parameters must be used. */ static int group_check_g_n (mpi_t g, mpi_t n) { mpi_t q = NULL, two = NULL, w = NULL; int ret; if (_gnutls_mpi_get_nbits (n) < 2048) { gnutls_assert (); return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; } /* N must be of the form N=2q+1 * where q is also a prime. */ if (_gnutls_prime_check (n, 0) != 0) { _gnutls_dump_mpi ("no prime N: ", n); gnutls_assert (); return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; } two = _gnutls_mpi_new (4); if (two == NULL) { gnutls_assert (); return GNUTLS_E_MEMORY_ERROR; } q = _gnutls_mpi_alloc_like (n); if (q == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto error; } /* q = n-1 */ _gnutls_mpi_sub_ui (q, n, 1); /* q = q/2, remember that q is divisible by 2 (prime - 1) */ _gnutls_mpi_set_ui (two, 2); _gnutls_mpi_div (q, NULL, q, two, 0); if (_gnutls_prime_check (q, 0) != 0) { /* N was not on the form N=2q+1, where q = prime */ _gnutls_dump_mpi ("no prime Q: ", q); gnutls_assert (); return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; } /* We also check whether g is a generator, */ /* check if g < q < N */ if (_gnutls_mpi_cmp (g, q) >= 0) { gnutls_assert (); ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; goto error; } w = _gnutls_mpi_alloc_like (q); if (w == NULL) { gnutls_assert (); ret = GNUTLS_E_MEMORY_ERROR; goto error; } /* check if g^q mod N == N-1 * w = g^q mod N */ _gnutls_mpi_powm (w, g, q, n); /* w++ */ _gnutls_mpi_add_ui (w, w, 1); if (_gnutls_mpi_cmp (w, n) != 0) { gnutls_assert (); ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; goto error; } ret = 0; error: _gnutls_mpi_release (&q); _gnutls_mpi_release (&two); _gnutls_mpi_release (&w); return ret; }
/* Check if N is a prime and G a generator of the * group. This check is only done if N is big enough. * Otherwise only the included parameters must be used. */ static int group_check_g_n(gnutls_session_t session, bigint_t g, bigint_t n) { bigint_t q = NULL, two = NULL, w = NULL; int ret; if (_gnutls_mpi_get_nbits(n) < (session->internals.srp_prime_bits ? session->internals.srp_prime_bits : 2048)) { gnutls_assert(); return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; } /* N must be of the form N=2q+1 * where q is also a prime. */ if (_gnutls_prime_check(n) != 0) { _gnutls_mpi_log("no prime N: ", n); gnutls_assert(); return GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; } ret = _gnutls_mpi_init_multi(&two, &q, &w, NULL); if (ret < 0) { gnutls_assert(); return ret; } /* q = n-1 */ ret = _gnutls_mpi_sub_ui(q, n, 1); if (ret < 0) { gnutls_assert(); goto error; } /* q = q/2, remember that q is divisible by 2 (prime - 1) */ ret = _gnutls_mpi_set_ui(two, 2); if (ret < 0) { gnutls_assert(); goto error; } ret = _gnutls_mpi_div(q, q, two); if (ret < 0) { gnutls_assert(); goto error; } if (_gnutls_prime_check(q) != 0) { /* N was not on the form N=2q+1, where q = prime */ _gnutls_mpi_log("no prime Q: ", q); gnutls_assert(); ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; goto error; } /* We also check whether g is a generator, */ /* check if g < q < N */ if (_gnutls_mpi_cmp(g, q) >= 0) { gnutls_assert(); ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; goto error; } /* check if g^q mod N == N-1 * w = g^q mod N */ ret = _gnutls_mpi_powm(w, g, q, n); if (ret < 0) { gnutls_assert(); goto error; } /* w++ */ ret = _gnutls_mpi_add_ui(w, w, 1); if (ret < 0) { gnutls_assert(); goto error; } if (_gnutls_mpi_cmp(w, n) != 0) { gnutls_assert(); ret = GNUTLS_E_RECEIVED_ILLEGAL_PARAMETER; goto error; } ret = 0; error: _gnutls_mpi_release(&q); _gnutls_mpi_release(&two); _gnutls_mpi_release(&w); return ret; }
static int wrap_nettle_pk_verify_params (gnutls_pk_algorithm_t algo, const gnutls_pk_params_st * params) { int ret; switch (algo) { case GNUTLS_PK_RSA: { bigint_t t1 = NULL, t2 = NULL; if (params->params_nr != RSA_PRIVATE_PARAMS) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); t1 = _gnutls_mpi_new (256); if (t1 == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); _gnutls_mpi_mulm (t1, params->params[RSA_PRIME1], params->params[RSA_PRIME2], params->params[RSA_MODULUS]); if (_gnutls_mpi_cmp_ui(t1, 0) != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto rsa_cleanup; } mpz_invert (TOMPZ(t1), TOMPZ (params->params[RSA_PRIME2]), TOMPZ (params->params[RSA_PRIME1])); if (_gnutls_mpi_cmp(t1, params->params[RSA_COEF]) != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto rsa_cleanup; } /* [RSA_PRIME1] = d % p-1, [RSA_PRIME2] = d % q-1 */ _gnutls_mpi_sub_ui (t1, params->params[RSA_PRIME1], 1); t2 = _gnutls_mpi_mod (params->params[RSA_PRIV], t1); if (t2 == NULL) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto rsa_cleanup; } if (_gnutls_mpi_cmp(params->params[RSA_E1], t2) != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto rsa_cleanup; } _gnutls_mpi_sub_ui (t1, params->params[RSA_PRIME2], 1); _gnutls_mpi_release(&t2); t2 = _gnutls_mpi_mod (params->params[RSA_PRIV], t1); if (t2 == NULL) { ret = gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); goto rsa_cleanup; } if (_gnutls_mpi_cmp(params->params[RSA_E2], t2) != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto rsa_cleanup; } ret = 0; rsa_cleanup: _gnutls_mpi_release(&t1); _gnutls_mpi_release(&t2); } break; case GNUTLS_PK_DSA: { bigint_t t1 = NULL; if (params->params_nr != DSA_PRIVATE_PARAMS) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); t1 = _gnutls_mpi_new (256); if (t1 == NULL) return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR); _gnutls_mpi_powm (t1, params->params[DSA_G], params->params[DSA_X], params->params[DSA_P]); if (_gnutls_mpi_cmp(t1, params->params[DSA_Y]) != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto dsa_cleanup; } ret = 0; dsa_cleanup: _gnutls_mpi_release(&t1); } break; case GNUTLS_PK_EC: { int curve = params->flags; ecc_key ecc_priv; ecc_point *R; ecc_point zero; if (params->params_nr != ECC_PRIVATE_PARAMS) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); if (is_supported_curve(curve) == 0) return gnutls_assert_val(GNUTLS_E_ECC_UNSUPPORTED_CURVE); _ecc_params_to_privkey(params, &ecc_priv); R = ecc_new_point(); /* verify that x,y lie on the curve */ ret = ecc_projective_check_point(&ecc_priv.pubkey, TOMPZ(params->params[ECC_B]), params->params[ECC_PRIME]); if (ret != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto ecc_cleanup; } memcpy(&zero.x, ecc_priv.Gx, sizeof(mpz_t)); memcpy(&zero.y, ecc_priv.Gy, sizeof(mpz_t)); memcpy(&zero.z, ecc_priv.pubkey.z, sizeof(mpz_t)); /* z = 1 */ /* verify that k*(Gx,Gy)=(x,y) */ ret = ecc_mulmod_cached(ecc_priv.k, curve, R, TOMPZ(params->params[ECC_A]), TOMPZ(params->params[ECC_PRIME]), 1); if (ret != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto ecc_cleanup; } if (mpz_cmp(ecc_priv.pubkey.x, R->x) != 0 || mpz_cmp(ecc_priv.pubkey.y, R->y) != 0) { ret = gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER); goto ecc_cleanup; } ret = 0; ecc_cleanup: _ecc_params_clear(&ecc_priv); ecc_del_point(R); } break; default: ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); } return ret; }
/* Decodes an DSA privateKey and params from a PKCS8 structure. */ static int _decode_pkcs8_dsa_key(ASN1_TYPE pkcs8_asn, gnutls_x509_privkey_t pkey) { int ret; gnutls_datum_t tmp = {NULL, 0}; gnutls_pk_params_init(&pkey->params); ret = _gnutls_x509_read_value(pkcs8_asn, "privateKey", &tmp); if (ret < 0) { gnutls_assert(); goto error; } ret = _gnutls_x509_read_der_int(tmp.data, tmp.size, &pkey->params.params[4]); _gnutls_free_key_datum(&tmp); if (ret < 0) { gnutls_assert(); goto error; } ret = _gnutls_x509_read_value(pkcs8_asn, "privateKeyAlgorithm.parameters", &tmp); if (ret < 0) { gnutls_assert(); goto error; } ret = _gnutls_x509_read_pubkey_params(GNUTLS_PK_DSA, tmp.data, tmp.size, &pkey->params); _gnutls_free_datum(&tmp); if (ret < 0) { gnutls_assert(); goto error; } if (_gnutls_mpi_cmp_ui(pkey->params.params[0], 0) == 0) { gnutls_assert(); ret = GNUTLS_E_ILLEGAL_PARAMETER; goto error; } /* the public key can be generated as g^x mod p */ ret = _gnutls_mpi_init(&pkey->params.params[3]); if (ret < 0) { gnutls_assert(); goto error; } ret = _gnutls_mpi_powm(pkey->params.params[3], pkey->params.params[2], pkey->params.params[4], pkey->params.params[0]); if (ret < 0) { gnutls_assert(); goto error; } pkey->params.algo = GNUTLS_PK_DSA; pkey->params.params_nr = DSA_PRIVATE_PARAMS; ret = _gnutls_asn1_encode_privkey(&pkey->key, &pkey->params); if (ret < 0) { gnutls_assert(); goto error; } return 0; error: if (pkey->params.params_nr != DSA_PRIVATE_PARAMS) _gnutls_mpi_release(&pkey->params.params[4]); return ret; }
/* S = (B - k*g^x) ^ (a + u * x) % N * this is our shared key (client premaster secret) */ bigint_t _gnutls_calc_srp_S2(bigint_t B, bigint_t g, bigint_t x, bigint_t a, bigint_t u, bigint_t n) { bigint_t S = NULL, tmp1 = NULL, tmp2 = NULL; bigint_t tmp4 = NULL, tmp3 = NULL, k = NULL; int ret; ret = _gnutls_mpi_init_multi(&S, &tmp1, &tmp2, &tmp3, &tmp4, NULL); if (ret < 0) return NULL; k = _gnutls_calc_srp_u(n, g, n); if (k == NULL) { gnutls_assert(); goto freeall; } ret = _gnutls_mpi_powm(tmp1, g, x, n); /* g^x */ if (ret < 0) { gnutls_assert(); goto freeall; } ret = _gnutls_mpi_mulm(tmp3, tmp1, k, n); /* k*g^x mod n */ if (ret < 0) { gnutls_assert(); goto freeall; } ret = _gnutls_mpi_subm(tmp2, B, tmp3, n); if (ret < 0) { gnutls_assert(); goto freeall; } ret = _gnutls_mpi_mul(tmp1, u, x); if (ret < 0) { gnutls_assert(); goto freeall; } ret = _gnutls_mpi_add(tmp4, a, tmp1); if (ret < 0) { gnutls_assert(); goto freeall; } ret = _gnutls_mpi_powm(S, tmp2, tmp4, n); if (ret < 0) { gnutls_assert(); goto freeall; } _gnutls_mpi_release(&tmp1); _gnutls_mpi_release(&tmp2); _gnutls_mpi_release(&tmp3); _gnutls_mpi_release(&tmp4); _gnutls_mpi_release(&k); return S; freeall: _gnutls_mpi_release(&k); _gnutls_mpi_release(&tmp1); _gnutls_mpi_release(&tmp2); _gnutls_mpi_release(&tmp3); _gnutls_mpi_release(&tmp4); _gnutls_mpi_release(&S); return NULL; }