示例#1
0
文件: srp.c 项目: attilamolnar/gnutls
/* 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;
}
示例#2
0
文件: srp.c 项目: attilamolnar/gnutls
/****************
 * 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;

}
示例#3
0
static int calc_rsa_exp(gnutls_pk_params_st * params)
{
	bigint_t tmp;
	int ret;

	if (params->params_nr < RSA_PRIVATE_PARAMS - 2) {
		gnutls_assert();
		return GNUTLS_E_INTERNAL_ERROR;
	}

	params->params[6] = params->params[7] = NULL;

	ret = _gnutls_mpi_init_multi(&tmp, &params->params[6], &params->params[7], NULL);
	if (ret < 0)
		return gnutls_assert_val(ret);

	/* [6] = d % p-1, [7] = d % q-1 */
	_gnutls_mpi_sub_ui(tmp, params->params[3], 1);
	ret =
	    _gnutls_mpi_modm(params->params[6], params->params[2] /*d */ , tmp);
	if (ret < 0)
		goto fail;

	_gnutls_mpi_sub_ui(tmp, params->params[4], 1);
	ret =
	    _gnutls_mpi_modm(params->params[7], params->params[2] /*d */ , tmp);
	if (ret < 0)
		goto fail;

	zrelease_mpi_key(&tmp);

	return 0;

fail:
	zrelease_mpi_key(&tmp);
	zrelease_mpi_key(&params->params[6]);
	zrelease_mpi_key(&params->params[7]);

	return ret;
}
示例#4
0
文件: srp.c 项目: attilamolnar/gnutls
/* 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;
}
示例#5
0
/* 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;

}
示例#6
0
文件: srp.c 项目: attilamolnar/gnutls
/* 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;
}
示例#7
0
/* Generates algorithm's parameters. That is:
 *  For DSA: p, q, and g are generated.
 *  For RSA: nothing
 *  For ECDSA: just checks the curve is ok
 */
static int
wrap_nettle_pk_generate_params(gnutls_pk_algorithm_t algo,
			       unsigned int level /*bits or curve*/ ,
			       gnutls_pk_params_st * params)
{
	int ret;
	unsigned int i, q_bits;

	params->algo = algo;

	switch (algo) {
	case GNUTLS_PK_DSA:
	case GNUTLS_PK_DH:
		{
			struct dsa_public_key pub;
			struct dsa_private_key priv;
#ifdef ENABLE_FIPS140
			struct dss_params_validation_seeds cert;
			unsigned index;
#endif

			dsa_public_key_init(&pub);
			dsa_private_key_init(&priv);

			if (GNUTLS_BITS_HAVE_SUBGROUP(level)) {
				q_bits = GNUTLS_BITS_TO_SUBGROUP(level);
				level = GNUTLS_BITS_TO_GROUP(level);
			} else {
				q_bits = _gnutls_pk_bits_to_subgroup_bits(level);
			}

			if (q_bits == 0)
				return gnutls_assert_val(GNUTLS_E_ILLEGAL_PARAMETER);

#ifdef ENABLE_FIPS140
			if (algo==GNUTLS_PK_DSA)
				index = 1;
			else
				index = 2;

			ret =
			    dsa_generate_dss_pqg(&pub, &cert,
			    			 index,
						 NULL, rnd_func, 
						 NULL, NULL,
						 level, q_bits);
			if (ret != 1) {
				gnutls_assert();
				ret = GNUTLS_E_PK_GENERATION_ERROR;
				goto dsa_fail;
			}

			/* verify the generated parameters */
			ret = dsa_validate_dss_pqg(&pub, &cert, index);
			if (ret != 1) {
				gnutls_assert();
				ret = GNUTLS_E_PK_GENERATION_ERROR;
				goto dsa_fail;
			}
#else
			/* unfortunately nettle only accepts 160 or 256
			 * q_bits size. The check below makes sure we handle
			 * cases in between by rounding up, but fail when
			 * larger numbers are requested. */
			if (q_bits < 160)
				q_bits = 160;
			else if (q_bits > 160 && q_bits <= 256)
				q_bits = 256;
			ret =
			    dsa_generate_keypair(&pub, &priv,
						 NULL, rnd_func, 
						 NULL, NULL,
						 level, q_bits);
			if (ret != 1) {
				gnutls_assert();
				ret = GNUTLS_E_PK_GENERATION_ERROR;
				goto dsa_fail;
			}
#endif

			params->params_nr = 0;

			ret = _gnutls_mpi_init_multi(&params->params[DSA_P], &params->params[DSA_Q],
					&params->params[DSA_G], NULL);
			if (ret < 0) {
				gnutls_assert();
				goto dsa_fail;
			}
			params->params_nr = 3;

			mpz_set(TOMPZ(params->params[DSA_P]), pub.p);
			mpz_set(TOMPZ(params->params[DSA_Q]), pub.q);
			mpz_set(TOMPZ(params->params[DSA_G]), pub.g);

			ret = 0;

		      dsa_fail:
			dsa_private_key_clear(&priv);
			dsa_public_key_clear(&pub);

			if (ret < 0)
				goto fail;

			break;
		}
	case GNUTLS_PK_RSA:
	case GNUTLS_PK_EC:
		ret = 0;
		break;
	default:
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	FAIL_IF_LIB_ERROR;
	return 0;

      fail:

	for (i = 0; i < params->params_nr; i++) {
		_gnutls_mpi_release(&params->params[i]);
	}
	params->params_nr = 0;

	FAIL_IF_LIB_ERROR;
	return ret;
}
示例#8
0
/* 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;
}
示例#9
0
static int
wrap_nettle_pk_verify_priv_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);

			ret = _gnutls_mpi_init_multi(&t1, &t2, NULL);
			if (ret < 0)
				return
				    gnutls_assert_val(ret);

			_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);
			ret = _gnutls_mpi_modm(t2, params->params[RSA_PRIV], t1);
			if (ret < 0) {
				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);

			ret = _gnutls_mpi_modm(t2, params->params[RSA_PRIV], t1);
			if (ret < 0) {
				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:
			zrelease_mpi_key(&t1);
			zrelease_mpi_key(&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);

			ret = _gnutls_mpi_init(&t1);
			if (ret < 0)
				return
				    gnutls_assert_val(ret);

			ret = _gnutls_mpi_powm(t1, params->params[DSA_G],
					 params->params[DSA_X],
					 params->params[DSA_P]);
			if (ret < 0) {
				gnutls_assert();
				goto dsa_cleanup;
			}

			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:
			zrelease_mpi_key(&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_zclear(&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_zclear(&priv);
			ecc_point_clear(&pub);
		}
		break;
	default:
		ret = gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
	}

	return ret;
}
示例#10
0
/* To generate a DH key either q must be set in the params or
 * level should be set to the number of required bits.
 */
static int
wrap_nettle_pk_generate_keys(gnutls_pk_algorithm_t algo,
			       unsigned int level /*bits */ ,
			       gnutls_pk_params_st * params)
{
	int ret;
	unsigned int i;

	switch (algo) {
	case GNUTLS_PK_DSA:
#ifdef ENABLE_FIPS140
		{
			struct dsa_public_key pub;
			struct dsa_private_key priv;

			if (params->params[DSA_Q] == NULL)
				return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

			_dsa_params_to_pubkey(params, &pub);

			dsa_private_key_init(&priv);
			mpz_init(pub.y);

			ret =
			    dsa_generate_dss_keypair(&pub, &priv, 
						 NULL, rnd_func, 
						 NULL, NULL);
			if (ret != 1) {
				gnutls_assert();
				ret = GNUTLS_E_PK_GENERATION_ERROR;
				goto dsa_fail;
			}

			ret = _gnutls_mpi_init_multi(&params->params[DSA_Y], &params->params[DSA_X], NULL);
			if (ret < 0) {
				gnutls_assert();
				goto dsa_fail;
			}

			mpz_set(TOMPZ(params->params[DSA_Y]), pub.y);
			mpz_set(TOMPZ(params->params[DSA_X]), priv.x);
			params->params_nr += 2;

		      dsa_fail:
			dsa_private_key_clear(&priv);
			mpz_clear(pub.y);

			if (ret < 0)
				goto fail;

			break;
		}
#endif
	case GNUTLS_PK_DH:
		{
			struct dsa_public_key pub;
			mpz_t r;
			mpz_t x, y;
			int max_tries;
			unsigned have_q = 0;

			if (algo != params->algo)
				return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

			_dsa_params_to_pubkey(params, &pub);

			if (params->params[DSA_Q] != NULL)
				have_q = 1;

			/* This check is for the case !ENABLE_FIPS140 */
			if (algo == GNUTLS_PK_DSA && have_q == 0)
				return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

			mpz_init(r);
			mpz_init(x);
			mpz_init(y);

			max_tries = 3;
			do {
				if (have_q) {
					mpz_set(r, pub.q);
					mpz_sub_ui(r, r, 2);
					nettle_mpz_random(x, NULL, rnd_func, r);
					mpz_add_ui(x, x, 1);
				} else {
					unsigned size = mpz_sizeinbase(pub.p, 2);
					if (level == 0)
						level = MIN(size, DH_EXPONENT_SIZE(size));
					nettle_mpz_random_size(x, NULL, rnd_func, level);

					if (level >= size)
						mpz_mod(x, x, pub.p);
				}

				mpz_powm(y, pub.g, x, pub.p);

				max_tries--;
				if (max_tries <= 0) {
					gnutls_assert();
					ret = GNUTLS_E_RANDOM_FAILED;
					goto dh_fail;
				}
			} while(mpz_cmp_ui(y, 1) == 0);

			ret = _gnutls_mpi_init_multi(&params->params[DSA_Y], &params->params[DSA_X], NULL);
			if (ret < 0) {
				gnutls_assert();
				goto dh_fail;
			}

			mpz_set(TOMPZ(params->params[DSA_Y]), y);
			mpz_set(TOMPZ(params->params[DSA_X]), x);
			params->params_nr += 2;

			ret = 0;

		      dh_fail:
			mpz_clear(r);
			mpz_clear(x);
			mpz_clear(y);

			if (ret < 0)
				goto fail;

			break;
		}
	case GNUTLS_PK_RSA:
		{
			struct rsa_public_key pub;
			struct rsa_private_key priv;

			rsa_public_key_init(&pub);
			rsa_private_key_init(&priv);

			mpz_set_ui(pub.e, 65537);
#ifdef ENABLE_FIPS140
			ret =
			    rsa_generate_fips186_4_keypair(&pub, &priv, NULL,
						 rnd_func, NULL, NULL,
						 level);
#else
			ret =
			    rsa_generate_keypair(&pub, &priv, NULL,
						 rnd_func, NULL, NULL,
						 level, 0);
#endif
			if (ret != 1) {
				gnutls_assert();
				ret = GNUTLS_E_PK_GENERATION_ERROR;
				goto rsa_fail;
			}

			params->params_nr = 0;
			for (i = 0; i < RSA_PRIVATE_PARAMS; i++) {
				ret = _gnutls_mpi_init(&params->params[i]);
				if (ret < 0) {
					gnutls_assert();
					goto rsa_fail;
				}
				params->params_nr++;
			}

			mpz_set(TOMPZ(params->params[0]), pub.n);
			mpz_set(TOMPZ(params->params[1]), pub.e);
			mpz_set(TOMPZ(params->params[2]), priv.d);
			mpz_set(TOMPZ(params->params[3]), priv.p);
			mpz_set(TOMPZ(params->params[4]), priv.q);
			mpz_set(TOMPZ(params->params[5]), priv.c);
			mpz_set(TOMPZ(params->params[6]), priv.a);
			mpz_set(TOMPZ(params->params[7]), priv.b);

			ret = 0;

		      rsa_fail:
			rsa_private_key_clear(&priv);
			rsa_public_key_clear(&pub);

			if (ret < 0)
				goto fail;

			break;
		}
	case GNUTLS_PK_EC:
		{
			struct ecc_scalar key;
			struct ecc_point pub;
			const struct ecc_curve *curve;

			curve = get_supported_curve(level);
			if (curve == NULL)
				return
				    gnutls_assert_val
				    (GNUTLS_E_ECC_UNSUPPORTED_CURVE);

			ecc_scalar_init(&key, curve);
			ecc_point_init(&pub, curve);

			ecdsa_generate_keypair(&pub, &key, NULL, rnd_func);

			ret = _gnutls_mpi_init_multi(&params->params[ECC_X], &params->params[ECC_Y], 
					&params->params[ECC_K], NULL);
			if (ret < 0) {
				gnutls_assert();
				goto ecc_fail;
			}

			params->flags = level;
			params->params_nr = ECC_PRIVATE_PARAMS;

			ecc_point_get(&pub, TOMPZ(params->params[ECC_X]),
				      TOMPZ(params->params[ECC_Y]));
			ecc_scalar_get(&key, TOMPZ(params->params[ECC_K]));

			ret = 0;

		      ecc_fail:
			ecc_point_clear(&pub);
			ecc_scalar_clear(&key);

			if (ret < 0)
				goto fail;

			break;
		}
	default:
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	FAIL_IF_LIB_ERROR;
	return 0;

      fail:

	for (i = 0; i < params->params_nr; i++) {
		_gnutls_mpi_release(&params->params[i]);
	}
	params->params_nr = 0;

	FAIL_IF_LIB_ERROR;
	return ret;
}