Exemple #1
0
static int wrap_nettle_cipher_exists(gnutls_cipher_algorithm_t algo)
{
	switch (algo) {
	case GNUTLS_CIPHER_AES_128_GCM:
	case GNUTLS_CIPHER_AES_256_GCM:
	case GNUTLS_CIPHER_AES_128_CBC:
	case GNUTLS_CIPHER_AES_192_CBC:
	case GNUTLS_CIPHER_AES_256_CBC:
	case GNUTLS_CIPHER_3DES_CBC:
		return 1;
	case GNUTLS_CIPHER_CAMELLIA_128_GCM:
	case GNUTLS_CIPHER_CAMELLIA_256_GCM:
	case GNUTLS_CIPHER_CAMELLIA_128_CBC:
	case GNUTLS_CIPHER_CAMELLIA_192_CBC:
	case GNUTLS_CIPHER_CAMELLIA_256_CBC:
	case GNUTLS_CIPHER_DES_CBC:
	case GNUTLS_CIPHER_ARCFOUR_128:
	case GNUTLS_CIPHER_SALSA20_256:
	case GNUTLS_CIPHER_ESTREAM_SALSA20_256:
	case GNUTLS_CIPHER_ARCFOUR_40:
	case GNUTLS_CIPHER_RC2_40_CBC:
		if (_gnutls_fips_mode_enabled() != 0)
			return 0;
		else
			return 1;
	default:
		return 0;
	}
}
Exemple #2
0
int _gnutls_rnd_preinit(void)
{
	int ret;

#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
# warning Insecure PRNG is enabled
	ret = gnutls_crypto_rnd_register(100, &_gnutls_fuzz_rnd_ops);
	if (ret < 0)
		return ret;

#elif defined(ENABLE_FIPS140)
	/* The FIPS140 random generator is only enabled when we are compiled
	 * with FIPS support, _and_ the system requires FIPS140.
	 */
	if (_gnutls_fips_mode_enabled() == 1) {
		ret = gnutls_crypto_rnd_register(100, &_gnutls_fips_rnd_ops);
		if (ret < 0)
			return ret;
	}
#endif

	ret = _rnd_system_entropy_init();
	if (ret < 0) {
		gnutls_assert();
		return GNUTLS_E_RANDOM_FAILED;
	}

	return 0;
}
Exemple #3
0
/**
 * gnutls_fips140_mode_enabled:
 *
 * Checks whether this library is in FIPS140 mode.
 *
 * Returns: return non-zero if true or zero if false.
 *
 * Since: 3.3.0
 **/
int gnutls_fips140_mode_enabled(void)
{
#ifdef ENABLE_FIPS140
int ret = _gnutls_fips_mode_enabled();

	if (ret == 1)
		return ret;
#endif
	return 0;
}
/* This generates p,q params using the B.3.2.2 algorithm in FIPS 186-4.
 * 
 * The hash function used is SHA384.
 * The exponent e used is the value in pub->e.
 */
int
rsa_generate_fips186_4_keypair(struct rsa_public_key *pub,
			       struct rsa_private_key *key,
			       void *random_ctx, nettle_random_func * random,
			       void *progress_ctx,
			       nettle_progress_func * progress,
			       unsigned *rseed_size,
			       void *rseed,
			       /* Desired size of modulo, in bits */
			       unsigned n_size)
{
	uint8_t seed[128];
	unsigned seed_length;
	int ret;

	if (_gnutls_fips_mode_enabled() != 0) {
		if (n_size != 2048 && n_size != 3072) {
			_gnutls_debug_log("The size of a prime can only be 2048 or 3072\n");
			return 0;
		}
	}

	seed_length = SEED_LENGTH(n_size);
	if (seed_length > sizeof(seed))
		return 0;

	random(random_ctx, seed_length, seed);

	if (rseed && rseed_size) {
		if (*rseed_size < seed_length) {
			return 0;
		}
		memcpy(rseed, seed, seed_length);
		*rseed_size = seed_length;
	}

	ret = _rsa_generate_fips186_4_keypair(pub, key, seed_length, seed,
					       progress_ctx, progress, n_size);
	gnutls_memset(seed, 0, seed_length);
	return ret;
}
Exemple #5
0
/* Returns true(non-zero) or false(0) if the 
 * provided cipher exists
 */
int _gnutls_cipher_exists(gnutls_cipher_algorithm_t cipher)
{
	const gnutls_crypto_cipher_st *cc;
	int ret;

	/* All the other ciphers are disabled on the back-end library.
	 * The NULL needs to be detected here as it is not a cipher
	 * that is provided by the back-end.
	 */
	if (cipher == GNUTLS_CIPHER_NULL) {
		if (_gnutls_fips_mode_enabled() == 0)
			return 1;
		else
			return 0;
	}

	cc = _gnutls_get_crypto_cipher(cipher);
	if (cc != NULL)
		return 1;

	ret = _gnutls_cipher_ops.exists(cipher);
	return ret;
}
Exemple #6
0
/**
 * gnutls_session_ticket_key_generate:
 * @key: is a pointer to a #gnutls_datum_t which will contain a newly
 * created key.
 *
 * Generate a random key to encrypt security parameters within
 * SessionTicket.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, or an
 * error code.
 *
 * Since: 2.10.0
 **/
int gnutls_session_ticket_key_generate(gnutls_datum_t * key)
{
	if (_gnutls_fips_mode_enabled()) {
		int ret;
		/* in FIPS140-2 mode gnutls_key_generate imposes
		 * some limits on allowed key size, thus it is not
		 * used. These limits do not affect this function as
		 * it does not generate a "key" but rather key material
		 * that includes nonces and other stuff. */
		key->data = gnutls_malloc(TICKET_MASTER_KEY_SIZE);
		if (key->data == NULL)
			return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);

		key->size = TICKET_MASTER_KEY_SIZE;
		ret = gnutls_rnd(GNUTLS_RND_RANDOM, key->data, key->size);
		if (ret < 0) {
			gnutls_free(key->data);
			return ret;
		}
		return 0;
	} else {
		return gnutls_key_generate(key, TICKET_MASTER_KEY_SIZE);
	}
}
Exemple #7
0
static int _gnutls_global_init(unsigned constructor)
{
	int ret = 0, res;
	int level;
	const char* e;

	if (!constructor) {
		GNUTLS_STATIC_MUTEX_LOCK(global_init_mutex);
	}

	_gnutls_init++;
	if (_gnutls_init > 1) {
		if (_gnutls_init == 2 && _gnutls_init_ret == 0) {
			/* some applications may close the urandom fd 
			 * before calling gnutls_global_init(). in that
			 * case reopen it */
			ret = _gnutls_rnd_check();
			if (ret < 0) {
				gnutls_assert();
				goto out;
			}
		}
		ret = _gnutls_init_ret;
		goto out;
	}

	_gnutls_switch_lib_state(LIB_STATE_INIT);

	e = secure_getenv("GNUTLS_DEBUG_LEVEL");
	if (e != NULL) {
		level = atoi(e);
		gnutls_global_set_log_level(level);
		if (_gnutls_log_func == NULL)
			gnutls_global_set_log_function(default_log_func);
		_gnutls_debug_log("Enabled GnuTLS "VERSION" logging...\n");
	}

#ifdef HAVE_DCGETTEXT
	bindtextdomain(PACKAGE, LOCALEDIR);
#endif

	res = gnutls_crypto_init();
	if (res != 0) {
		gnutls_assert();
		ret = GNUTLS_E_CRYPTO_INIT_FAILED;
		goto out;
	}

	ret = _gnutls_system_key_init();
	if (ret != 0) {
		gnutls_assert();
	}

	/* initialize ASN.1 parser
	 */
	if (asn1_check_version(GNUTLS_MIN_LIBTASN1_VERSION) == NULL) {
		gnutls_assert();
		_gnutls_debug_log
		    ("Checking for libtasn1 failed: %s < %s\n",
		     asn1_check_version(NULL),
		     GNUTLS_MIN_LIBTASN1_VERSION);
		ret = GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY;
		goto out;
	}

	_gnutls_pkix1_asn = ASN1_TYPE_EMPTY;
	res = asn1_array2tree(pkix_asn1_tab, &_gnutls_pkix1_asn, NULL);
	if (res != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(res);
		goto out;
	}

	res = asn1_array2tree(gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL);
	if (res != ASN1_SUCCESS) {
		gnutls_assert();
		ret = _gnutls_asn2err(res);
		goto out;
	}

	/* Initialize the random generator */
	ret = _gnutls_rnd_preinit();
	if (ret < 0) {
		gnutls_assert();
		goto out;
	}

	/* Initialize the default TLS extensions */
	ret = _gnutls_ext_init();
	if (ret < 0) {
		gnutls_assert();
		goto out;
	}

	ret = gnutls_mutex_init(&_gnutls_file_mutex);
	if (ret < 0) {
		gnutls_assert();
		goto out;
	}

	ret = gnutls_mutex_init(&_gnutls_pkcs11_mutex);
	if (ret < 0) {
		gnutls_assert();
		goto out;
	}

	ret = gnutls_system_global_init();
	if (ret < 0) {
		gnutls_assert();
		goto out;
	}

#ifndef _WIN32
	ret = _gnutls_register_fork_handler();
	if (ret < 0) {
		gnutls_assert();
		goto out;
	}
#endif

#ifdef ENABLE_FIPS140
	res = _gnutls_fips_mode_enabled();
	/* res == 1 -> fips140-2 mode enabled
	 * res == 2 -> only self checks performed - but no failure
	 * res == not in fips140 mode
	 */
	if (res != 0) {
		_gnutls_debug_log("FIPS140-2 mode: %d\n", res);
		_gnutls_priority_update_fips();

		/* first round of self checks, these are done on the
		 * nettle algorithms which are used internally */
		ret = _gnutls_fips_perform_self_checks1();
		if (res != 2) {
			if (ret < 0) {
				gnutls_assert();
				goto out;
			}
		}
	}
#endif

	_gnutls_register_accel_crypto();
	_gnutls_cryptodev_init();
	_gnutls_load_system_priorities();

#ifdef ENABLE_FIPS140
	/* These self tests are performed on the overriden algorithms
	 * (e.g., AESNI overriden AES). They are after _gnutls_register_accel_crypto()
	 * intentionally */
	if (res != 0) {
		ret = _gnutls_fips_perform_self_checks2();
		if (res != 2) {
			if (ret < 0) {
				gnutls_assert();
				goto out;
			}
		}
		_gnutls_fips_mode_reset_zombie();
	}
#endif
	_gnutls_switch_lib_state(LIB_STATE_OPERATIONAL);
	ret = 0;

      out:
	_gnutls_init_ret = ret;
	if (!constructor) {
		GNUTLS_STATIC_MUTEX_UNLOCK(global_init_mutex);
	}
	return ret;
}
/* This generates p,q params using the B.3.2.2 algorithm in FIPS 186-4.
 * 
 * The hash function used is SHA384.
 * The exponent e used is the value in pub->e.
 */
int
_rsa_generate_fips186_4_keypair(struct rsa_public_key *pub,
				struct rsa_private_key *key,
				unsigned seed_length, uint8_t * seed,
				void *progress_ctx,
				nettle_progress_func * progress,
				/* Desired size of modulo, in bits */
				unsigned n_size)
{
	mpz_t t, r, p1, q1, lcm;
	int ret;
	struct dss_params_validation_seeds cert;
	unsigned l = n_size / 2;

	if (_gnutls_fips_mode_enabled() != 0) {
		if (n_size == 2048) {
			if (seed_length != 14 * 2) {
				_gnutls_debug_log("Seed length must be 28 bytes (it is %d)\n", seed_length);
				return 0;
			}
		} else if (n_size == 3072) {
			if (seed_length != 16 * 2) {
				_gnutls_debug_log("Seed length must be 32 bytes (it is %d)\n", seed_length);
				return 0;
			}
		} else {
			_gnutls_debug_log("Unsupported size for modulus\n");
			return 0;
		}
	}

	if (!mpz_tstbit(pub->e, 0)) {
		_gnutls_debug_log("Unacceptable e (it is even)\n");
		return 0;
	}

	if (mpz_cmp_ui(pub->e, 65536) <= 0) {
		_gnutls_debug_log("Unacceptable e\n");
		return 0;
	}

	mpz_init(p1);
	mpz_init(q1);
	mpz_init(lcm);
	mpz_init(t);
	mpz_init(r);

	mpz_set_ui(t, 1);
	mpz_mul_2exp(t, t, 256);

	if (mpz_cmp(pub->e, t) >= 0) {
		ret = 0;
		goto cleanup;
	}

	cert.pseed_length = sizeof(cert.pseed);
	ret = rsa_provable_prime(key->p, &cert.pseed_length, cert.pseed,
				l, seed_length,
				seed, pub->e, progress_ctx, progress);
	if (ret == 0) {
		goto cleanup;
	}

	mpz_set_ui(r, 1);
	mpz_mul_2exp(r, r, (l) - 100);

	do {
		cert.qseed_length = sizeof(cert.qseed);
		ret = rsa_provable_prime(key->q, &cert.qseed_length, cert.qseed,
					l, cert.pseed_length, cert.pseed,
					pub->e,
					progress_ctx, progress);
		if (ret == 0) {
			goto cleanup;
		}


		cert.pseed_length = cert.qseed_length;
		memcpy(cert.pseed, cert.qseed, cert.qseed_length);


		if (mpz_cmp(key->p, key->q) > 0)
			mpz_sub(t, key->p, key->q);
		else
			mpz_sub(t, key->q, key->p);
	} while (mpz_cmp(t, r) <= 0);

	memset(&cert, 0, sizeof(cert));

	mpz_mul(pub->n, key->p, key->q);

	assert(mpz_sizeinbase(pub->n, 2) == n_size);

	/* c = q^{-1} (mod p) */
	assert(mpz_invert(key->c, key->q, key->p) != 0);

	mpz_sub_ui(p1, key->p, 1);
	mpz_sub_ui(q1, key->q, 1);

	mpz_lcm(lcm, p1, q1);

	if (mpz_invert(key->d, pub->e, lcm) == 0) {
		ret = 0;
		goto cleanup;
	}

	/* Done! Almost, we must compute the auxillary private values. */
	/* a = d % (p-1) */
	mpz_fdiv_r(key->a, key->d, p1);

	/* b = d % (q-1) */
	mpz_fdiv_r(key->b, key->d, q1);

	/* c was computed earlier */

	pub->size = key->size = (n_size + 7) / 8;
	assert(pub->size >= RSA_MINIMUM_N_OCTETS);

	ret = 1;
 cleanup:
	mpz_clear(p1);
	mpz_clear(q1);
	mpz_clear(lcm);
	mpz_clear(t);
	mpz_clear(r);
	return ret;
}
Exemple #9
0
/**
 * gnutls_global_init:
 *
 * This function performs any required precalculations, detects
 * the supported CPU capabilities and initializes the underlying
 * cryptographic backend. In order to free any resources 
 * taken by this call you should gnutls_global_deinit() 
 * when gnutls usage is no longer needed.
 *
 * This function increments a global counter, so that
 * gnutls_global_deinit() only releases resources when it has been
 * called as many times as gnutls_global_init().  This is useful when
 * GnuTLS is used by more than one library in an application.  This
 * function can be called many times, but will only do something the
 * first time.
 *
 * Since GnuTLS 3.3.0 this function is only required in systems that
 * do not support library constructors and static linking. This
 * function also became thread safe.
 *
 * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned,
 *   otherwise a negative error code is returned.
 **/
int gnutls_global_init(void)
{
	int ret = 0, res;
	int level;
	const char* e;
	
	GNUTLS_STATIC_MUTEX_LOCK(global_init_mutex);

	_gnutls_init++;
	if (_gnutls_init > 1) {
		ret = 0;
		goto out;
	}

	_gnutls_switch_lib_state(LIB_STATE_INIT);

	e = getenv("GNUTLS_DEBUG_LEVEL");
	if (e != NULL) {
		level = atoi(e);
		gnutls_global_set_log_level(level);
		if (_gnutls_log_func == NULL)
			gnutls_global_set_log_function(default_log_func);
		_gnutls_debug_log("Enabled GnuTLS logging...\n");
	}

	bindtextdomain(PACKAGE, LOCALEDIR);

	res = gnutls_crypto_init();
	if (res != 0) {
		gnutls_assert();
		ret = GNUTLS_E_CRYPTO_INIT_FAILED;
		goto out;
	}

	/* initialize ASN.1 parser
	 */
	if (asn1_check_version(GNUTLS_MIN_LIBTASN1_VERSION) == NULL) {
		gnutls_assert();
		_gnutls_debug_log
		    ("Checking for libtasn1 failed: %s < %s\n",
		     asn1_check_version(NULL),
		     GNUTLS_MIN_LIBTASN1_VERSION);
		ret = GNUTLS_E_INCOMPATIBLE_LIBTASN1_LIBRARY;
		goto out;
	}

	res = asn1_array2tree(pkix_asn1_tab, &_gnutls_pkix1_asn, NULL);
	if (res != ASN1_SUCCESS) {
		ret = _gnutls_asn2err(res);
		goto out;
	}

	res = asn1_array2tree(gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL);
	if (res != ASN1_SUCCESS) {
		ret = _gnutls_asn2err(res);
		goto out;
	}

	/* Initialize the random generator */
	ret = _gnutls_rnd_init();
	if (ret < 0) {
		gnutls_assert();
		goto out;
	}

	/* Initialize the default TLS extensions */
	ret = _gnutls_ext_init();
	if (ret < 0) {
		gnutls_assert();
		goto out;
	}

	ret = gnutls_mutex_init(&_gnutls_file_mutex);
	if (ret < 0) {
		gnutls_assert();
		goto out;
	}

	ret = gnutls_mutex_init(&_gnutls_pkcs11_mutex);
	if (ret < 0) {
		gnutls_assert();
		goto out;
	}

	ret = gnutls_system_global_init();
	if (ret < 0) {
		gnutls_assert();
		goto out;
	}

	_gnutls_register_accel_crypto();
	_gnutls_cryptodev_init();

#ifdef ENABLE_FIPS140
	/* Perform FIPS140 checks last, so that all modules
	 * have been loaded */
	res = _gnutls_fips_mode_enabled();
	/* res == 1 -> fips140-2 mode enabled
	 * res == 2 -> only self checks performed - but no failure
	 * res == not in fips140 mode
	 */
	if (res != 0) {
		_gnutls_priority_update_fips();

		ret = _gnutls_fips_perform_self_checks();
		if (res != 2) {
			if (ret < 0) {
				gnutls_assert();
				goto out;
			}
		}
	}
#endif
	_gnutls_switch_lib_state(LIB_STATE_OPERATIONAL);
	ret = 0;

      out:
	GNUTLS_STATIC_MUTEX_UNLOCK(global_init_mutex);
	return ret;
}
Exemple #10
0
static int
wrap_nettle_cipher_setkey(void *_ctx, const void *key, size_t keysize)
{
	struct nettle_cipher_ctx *ctx = _ctx;
	uint8_t des_key[DES3_KEY_SIZE];

	switch (ctx->algo) {
	case GNUTLS_CIPHER_AES_128_GCM:
	case GNUTLS_CIPHER_AES_256_GCM:
		gcm_aes_set_key(&ctx->ctx.aes_gcm, keysize, key);
		break;
	case GNUTLS_CIPHER_AES_128_CBC:
	case GNUTLS_CIPHER_AES_192_CBC:
	case GNUTLS_CIPHER_AES_256_CBC:
		if (ctx->enc)
			aes_set_encrypt_key(ctx->ctx_ptr, keysize, key);
		else
			aes_set_decrypt_key(ctx->ctx_ptr, keysize, key);
		break;
	case GNUTLS_CIPHER_CAMELLIA_128_CBC:
	case GNUTLS_CIPHER_CAMELLIA_192_CBC:
	case GNUTLS_CIPHER_CAMELLIA_256_CBC:
		if (ctx->enc)
			camellia_set_encrypt_key(ctx->ctx_ptr, keysize,
						 key);
		else
			camellia_set_decrypt_key(ctx->ctx_ptr, keysize,
						 key);
		break;
	case GNUTLS_CIPHER_3DES_CBC:
		if (keysize != DES3_KEY_SIZE) {
			gnutls_assert();
			return GNUTLS_E_INTERNAL_ERROR;
		}

		des_fix_parity(keysize, des_key, key);

		if (des3_set_key(ctx->ctx_ptr, des_key) != 1) {
			gnutls_assert();
		}
		zeroize_temp_key(des_key, sizeof(des_key));

		break;
	case GNUTLS_CIPHER_CAMELLIA_128_GCM:
	case GNUTLS_CIPHER_CAMELLIA_256_GCM:
		if (_gnutls_fips_mode_enabled() != 0)
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

		_gcm_camellia_set_key(&ctx->ctx.camellia_gcm, keysize,
				      key);
		break;
	case GNUTLS_CIPHER_DES_CBC:
		if (_gnutls_fips_mode_enabled() != 0)
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

		if (keysize != DES_KEY_SIZE) {
			gnutls_assert();
			return GNUTLS_E_INTERNAL_ERROR;
		}

		des_fix_parity(keysize, des_key, key);

		if (des_set_key(ctx->ctx_ptr, des_key) != 1) {
			gnutls_assert();
			return GNUTLS_E_INTERNAL_ERROR;
		}
		zeroize_temp_key(des_key, sizeof(des_key));
		break;
	case GNUTLS_CIPHER_ARCFOUR_128:
	case GNUTLS_CIPHER_ARCFOUR_40:
		if (_gnutls_fips_mode_enabled() != 0)
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

		arcfour_set_key(ctx->ctx_ptr, keysize, key);
		break;
	case GNUTLS_CIPHER_SALSA20_256:
	case GNUTLS_CIPHER_ESTREAM_SALSA20_256:
		if (_gnutls_fips_mode_enabled() != 0)
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

		salsa20_set_key(ctx->ctx_ptr, keysize, key);
		break;
	case GNUTLS_CIPHER_RC2_40_CBC:
		if (_gnutls_fips_mode_enabled() != 0)
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

		arctwo_set_key(ctx->ctx_ptr, keysize, key);
		break;
	default:
		gnutls_assert();
		return GNUTLS_E_INVALID_REQUEST;
	}

	return 0;
}
Exemple #11
0
static int
wrap_nettle_cipher_init(gnutls_cipher_algorithm_t algo, void **_ctx,
			int enc)
{
	struct nettle_cipher_ctx *ctx;

	ctx = gnutls_calloc(1, sizeof(*ctx));
	if (ctx == NULL) {
		gnutls_assert();
		return GNUTLS_E_MEMORY_ERROR;
	}

	ctx->algo = algo;
	ctx->enc = enc;

	switch (algo) {
	case GNUTLS_CIPHER_AES_128_GCM:
	case GNUTLS_CIPHER_AES_256_GCM:
		ctx->encrypt = _aes_gcm_encrypt;
		ctx->decrypt = _aes_gcm_decrypt;
		ctx->i_encrypt = (nettle_crypt_func *) aes_encrypt;
		ctx->auth = (auth_func) gcm_aes_update;
		ctx->tag = (tag_func) gcm_aes_digest;
		ctx->ctx_ptr = &ctx->ctx.aes_gcm;
		ctx->block_size = AES_BLOCK_SIZE;
		break;
	case GNUTLS_CIPHER_AES_128_CBC:
	case GNUTLS_CIPHER_AES_192_CBC:
	case GNUTLS_CIPHER_AES_256_CBC:
		ctx->encrypt = cbc_encrypt;
		ctx->decrypt = cbc_decrypt;
		ctx->i_encrypt = (nettle_crypt_func *) aes_encrypt;
		ctx->i_decrypt = (nettle_crypt_func *) aes_decrypt;
		ctx->ctx_ptr = &ctx->ctx.aes;
		ctx->block_size = AES_BLOCK_SIZE;
		break;
	case GNUTLS_CIPHER_3DES_CBC:
		ctx->encrypt = cbc_encrypt;
		ctx->decrypt = cbc_decrypt;
		ctx->i_encrypt = (nettle_crypt_func *) des3_encrypt;
		ctx->i_decrypt = (nettle_crypt_func *) des3_decrypt;
		ctx->ctx_ptr = &ctx->ctx.des3;
		ctx->block_size = DES3_BLOCK_SIZE;
		break;
	case GNUTLS_CIPHER_CAMELLIA_128_GCM:
	case GNUTLS_CIPHER_CAMELLIA_256_GCM:
		if (_gnutls_fips_mode_enabled() != 0)
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

		ctx->encrypt = _camellia_gcm_encrypt;
		ctx->decrypt = _camellia_gcm_decrypt;
		ctx->i_encrypt = (nettle_crypt_func *) camellia_crypt;
		ctx->auth = (auth_func) _gcm_camellia_update;
		ctx->tag = (tag_func) _gcm_camellia_digest;
		ctx->ctx_ptr = &ctx->ctx.camellia_gcm;
		ctx->block_size = CAMELLIA_BLOCK_SIZE;
		break;
	case GNUTLS_CIPHER_CAMELLIA_128_CBC:
	case GNUTLS_CIPHER_CAMELLIA_192_CBC:
	case GNUTLS_CIPHER_CAMELLIA_256_CBC:
		if (_gnutls_fips_mode_enabled() != 0)
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

		ctx->encrypt = cbc_encrypt;
		ctx->decrypt = cbc_decrypt;
		ctx->i_encrypt = (nettle_crypt_func *) camellia_crypt;
		ctx->i_decrypt = (nettle_crypt_func *) camellia_crypt;
		ctx->ctx_ptr = &ctx->ctx.camellia;
		ctx->block_size = CAMELLIA_BLOCK_SIZE;
		break;
	case GNUTLS_CIPHER_DES_CBC:
		if (_gnutls_fips_mode_enabled() != 0)
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

		ctx->encrypt = cbc_encrypt;
		ctx->decrypt = cbc_decrypt;
		ctx->i_encrypt = (nettle_crypt_func *) des_encrypt;
		ctx->i_decrypt = (nettle_crypt_func *) des_decrypt;
		ctx->ctx_ptr = &ctx->ctx.des;
		ctx->block_size = DES_BLOCK_SIZE;
		break;
	case GNUTLS_CIPHER_ARCFOUR_128:
	case GNUTLS_CIPHER_ARCFOUR_40:
		if (_gnutls_fips_mode_enabled() != 0)
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

		ctx->encrypt = stream_encrypt;
		ctx->decrypt = stream_encrypt;
		ctx->i_encrypt = (nettle_crypt_func *) arcfour_crypt;
		ctx->i_decrypt = (nettle_crypt_func *) arcfour_crypt;
		ctx->ctx_ptr = &ctx->ctx.arcfour;
		ctx->block_size = 1;
		break;
	case GNUTLS_CIPHER_SALSA20_256:
		if (_gnutls_fips_mode_enabled() != 0)
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

		ctx->encrypt = stream_encrypt;
		ctx->decrypt = stream_encrypt;
		ctx->i_encrypt = (nettle_crypt_func *) salsa20_crypt;
		ctx->i_decrypt = (nettle_crypt_func *) salsa20_crypt;
		ctx->ctx_ptr = &ctx->ctx.salsa20;
		ctx->block_size = 1;
		break;
	case GNUTLS_CIPHER_ESTREAM_SALSA20_256:
		if (_gnutls_fips_mode_enabled() != 0)
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

		ctx->encrypt = stream_encrypt;
		ctx->decrypt = stream_encrypt;
		ctx->i_encrypt = (nettle_crypt_func *) salsa20r12_crypt;
		ctx->i_decrypt = (nettle_crypt_func *) salsa20r12_crypt;
		ctx->ctx_ptr = &ctx->ctx.salsa20;
		ctx->block_size = 1;
		break;
	case GNUTLS_CIPHER_RC2_40_CBC:
		if (_gnutls_fips_mode_enabled() != 0)
			return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);

		ctx->encrypt = cbc_encrypt;
		ctx->decrypt = cbc_decrypt;
		ctx->i_encrypt = (nettle_crypt_func *) arctwo_encrypt;
		ctx->i_decrypt = (nettle_crypt_func *) arctwo_decrypt;
		ctx->ctx_ptr = &ctx->ctx.arctwo;
		ctx->block_size = ARCTWO_BLOCK_SIZE;
		break;
	default:
		gnutls_assert();
		gnutls_free(ctx);
		return GNUTLS_E_INVALID_REQUEST;
	}

	*_ctx = ctx;

	return 0;
}