/*
 * Copyright (C) 2011-2012 Free Software Foundation, Inc.
 *
 * Author: Nikos Mavrogiannopoulos
 *
 * This file is part of GnuTLS.
 *
 * The GnuTLS is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 *
 */

#include <gnutls_int.h>
#include <algorithms.h>
#include <gnutls_errors.h>
#include <gnutls_dh.h>
#include <gnutls_state.h>
#include <x509/common.h>
#include <auth/cert.h>
#include <auth/anon.h>
#include <auth/psk.h>

/* Cipher SUITES */
#define ENTRY( name, block_algorithm, kx_algorithm, mac_algorithm, min_version, dtls_version ) \
	{ #name, name, block_algorithm, kx_algorithm, mac_algorithm, min_version, dtls_version, GNUTLS_MAC_SHA256}
#define ENTRY_PRF( name, block_algorithm, kx_algorithm, mac_algorithm, min_version, dtls_version, prf ) \
	{ #name, name, block_algorithm, kx_algorithm, mac_algorithm, min_version, dtls_version, prf}

/* RSA with NULL cipher and MD5 MAC
 * for test purposes.
 */
#define GNUTLS_RSA_NULL_MD5 { 0x00, 0x01 }
#define GNUTLS_RSA_NULL_SHA1 { 0x00, 0x02 }
#define GNUTLS_RSA_NULL_SHA256 { 0x00, 0x3B }

/* ANONymous cipher suites.
 */

#define GNUTLS_DH_ANON_3DES_EDE_CBC_SHA1 { 0x00, 0x1B }
#define GNUTLS_DH_ANON_ARCFOUR_128_MD5 { 0x00, 0x18 }

 /* rfc3268: */
#define GNUTLS_DH_ANON_AES_128_CBC_SHA1 { 0x00, 0x34 }
#define GNUTLS_DH_ANON_AES_256_CBC_SHA1 { 0x00, 0x3A }

/* rfc4132 */
#define GNUTLS_DH_ANON_CAMELLIA_128_CBC_SHA1 { 0x00,0x46 }
#define GNUTLS_DH_ANON_CAMELLIA_256_CBC_SHA1 { 0x00,0x89 }

/* rfc5932 */
#define GNUTLS_RSA_CAMELLIA_128_CBC_SHA256     { 0x00,0xBA }
#define GNUTLS_DHE_DSS_CAMELLIA_128_CBC_SHA256 { 0x00,0xBD }
#define GNUTLS_DHE_RSA_CAMELLIA_128_CBC_SHA256 { 0x00,0xBE }
#define GNUTLS_DH_ANON_CAMELLIA_128_CBC_SHA256 { 0x00,0xBF }
#define GNUTLS_RSA_CAMELLIA_256_CBC_SHA256     { 0x00,0xC0 }
#define GNUTLS_DHE_DSS_CAMELLIA_256_CBC_SHA256 { 0x00,0xC3 }
#define GNUTLS_DHE_RSA_CAMELLIA_256_CBC_SHA256 { 0x00,0xC4 }
#define GNUTLS_DH_ANON_CAMELLIA_256_CBC_SHA256 { 0x00,0xC5 }

/* rfc6367 */
#define GNUTLS_ECDHE_ECDSA_CAMELLIA_128_CBC_SHA256 { 0xC0,0x72 }
#define GNUTLS_ECDHE_ECDSA_CAMELLIA_256_CBC_SHA384 { 0xC0,0x73 }
#define GNUTLS_ECDHE_RSA_CAMELLIA_128_CBC_SHA256   { 0xC0,0x76 }
#define GNUTLS_ECDHE_RSA_CAMELLIA_256_CBC_SHA384   { 0xC0,0x77 }
#define GNUTLS_PSK_CAMELLIA_128_CBC_SHA256     { 0xC0,0x94 }
#define GNUTLS_PSK_CAMELLIA_256_CBC_SHA384     { 0xC0,0x95 }
#define GNUTLS_DHE_PSK_CAMELLIA_128_CBC_SHA256 { 0xC0,0x96 }
#define GNUTLS_DHE_PSK_CAMELLIA_256_CBC_SHA384 { 0xC0,0x97 }
#define GNUTLS_RSA_PSK_CAMELLIA_128_CBC_SHA256 { 0xC0,0x98 }
#define GNUTLS_RSA_PSK_CAMELLIA_256_CBC_SHA384 { 0xC0,0x99 }
#define GNUTLS_ECDHE_PSK_CAMELLIA_128_CBC_SHA256 { 0xC0,0x9A }
#define GNUTLS_ECDHE_PSK_CAMELLIA_256_CBC_SHA384 { 0xC0,0x9B }

#define GNUTLS_RSA_CAMELLIA_128_GCM_SHA256          { 0xC0, 0x7A }
#define GNUTLS_RSA_CAMELLIA_256_GCM_SHA384          { 0xC0,0x7B }
#define GNUTLS_DHE_RSA_CAMELLIA_128_GCM_SHA256      { 0xC0,0x7C }
#define GNUTLS_DHE_RSA_CAMELLIA_256_GCM_SHA384      { 0xC0,0x7D }
#define GNUTLS_DHE_DSS_CAMELLIA_128_GCM_SHA256      { 0xC0,0x80 }
#define GNUTLS_DHE_DSS_CAMELLIA_256_GCM_SHA384      { 0xC0,0x81 }
#define GNUTLS_DH_ANON_CAMELLIA_128_GCM_SHA256      { 0xC0,0x84 }
#define GNUTLS_DH_ANON_CAMELLIA_256_GCM_SHA384      { 0xC0,0x85 }
#define GNUTLS_ECDHE_ECDSA_CAMELLIA_128_GCM_SHA256  { 0xC0,0x86 }
#define GNUTLS_ECDHE_ECDSA_CAMELLIA_256_GCM_SHA384  { 0xC0,0x87 }
#define GNUTLS_ECDHE_RSA_CAMELLIA_128_GCM_SHA256    { 0xC0,0x8A }
#define GNUTLS_ECDHE_RSA_CAMELLIA_256_GCM_SHA384    { 0xC0,0x8B }
#define GNUTLS_PSK_CAMELLIA_128_GCM_SHA256        { 0xC0,0x8E }
#define GNUTLS_PSK_CAMELLIA_256_GCM_SHA384        { 0xC0,0x8F }
#define GNUTLS_DHE_PSK_CAMELLIA_128_GCM_SHA256    { 0xC0,0x90 }
#define GNUTLS_DHE_PSK_CAMELLIA_256_GCM_SHA384    { 0xC0,0x91 }
#define GNUTLS_RSA_PSK_CAMELLIA_128_GCM_SHA256    { 0xC0,0x92 }
#define GNUTLS_RSA_PSK_CAMELLIA_256_GCM_SHA384    { 0xC0,0x93 }

#define GNUTLS_DH_ANON_AES_128_CBC_SHA256 { 0x00, 0x6C }
#define GNUTLS_DH_ANON_AES_256_CBC_SHA256 { 0x00, 0x6D }

/* draft-ietf-tls-chacha20-poly1305-02 */
#define GNUTLS_ECDHE_RSA_CHACHA20_POLY1305      { 0xCC, 0xA8 }
#define GNUTLS_ECDHE_ECDSA_CHACHA20_POLY1305	{ 0xCC, 0xA9 }
#define GNUTLS_DHE_RSA_CHACHA20_POLY1305	{ 0xCC, 0xAA }

#define GNUTLS_PSK_CHACHA20_POLY1305		{ 0xCC, 0xAB }
#define GNUTLS_ECDHE_PSK_CHACHA20_POLY1305	{ 0xCC, 0xAC }
#define GNUTLS_DHE_PSK_CHACHA20_POLY1305	{ 0xCC, 0xAD }
#define GNUTLS_RSA_PSK_CHACHA20_POLY1305	{ 0xCC, 0xAE }

/* PSK (not in TLS 1.0)
 * draft-ietf-tls-psk:
 */
#define GNUTLS_PSK_ARCFOUR_128_SHA1 { 0x00, 0x8A }
#define GNUTLS_PSK_3DES_EDE_CBC_SHA1 { 0x00, 0x8B }
#define GNUTLS_PSK_AES_128_CBC_SHA1 { 0x00, 0x8C }
#define GNUTLS_PSK_AES_256_CBC_SHA1 { 0x00, 0x8D }

#define GNUTLS_DHE_PSK_ARCFOUR_128_SHA1 { 0x00, 0x8E }
#define GNUTLS_DHE_PSK_3DES_EDE_CBC_SHA1 { 0x00, 0x8F }
#define GNUTLS_DHE_PSK_AES_128_CBC_SHA1 { 0x00, 0x90 }
#define GNUTLS_DHE_PSK_AES_256_CBC_SHA1 { 0x00, 0x91 }

#define GNUTLS_RSA_PSK_ARCFOUR_128_SHA1 { 0x00, 0x92 }
#define GNUTLS_RSA_PSK_3DES_EDE_CBC_SHA1 { 0x00, 0x93 }
#define GNUTLS_RSA_PSK_AES_128_CBC_SHA1 { 0x00, 0x94 }
#define GNUTLS_RSA_PSK_AES_256_CBC_SHA1 { 0x00, 0x95 }

/* SRP (rfc5054)
 */
#define GNUTLS_SRP_SHA_3DES_EDE_CBC_SHA1 { 0xC0, 0x1A }
#define GNUTLS_SRP_SHA_RSA_3DES_EDE_CBC_SHA1 { 0xC0, 0x1B }
#define GNUTLS_SRP_SHA_DSS_3DES_EDE_CBC_SHA1 { 0xC0, 0x1C }

#define GNUTLS_SRP_SHA_AES_128_CBC_SHA1 { 0xC0, 0x1D }
#define GNUTLS_SRP_SHA_RSA_AES_128_CBC_SHA1 { 0xC0, 0x1E }
#define GNUTLS_SRP_SHA_DSS_AES_128_CBC_SHA1 { 0xC0, 0x1F }

#define GNUTLS_SRP_SHA_AES_256_CBC_SHA1 { 0xC0, 0x20 }
#define GNUTLS_SRP_SHA_RSA_AES_256_CBC_SHA1 { 0xC0, 0x21 }
#define GNUTLS_SRP_SHA_DSS_AES_256_CBC_SHA1 { 0xC0, 0x22 }

/* RSA
 */
#define GNUTLS_RSA_ARCFOUR_128_SHA1 { 0x00, 0x05 }
#define GNUTLS_RSA_ARCFOUR_128_MD5 { 0x00, 0x04 }
#define GNUTLS_RSA_3DES_EDE_CBC_SHA1 { 0x00, 0x0A }

/* rfc3268:
 */
#define GNUTLS_RSA_AES_128_CBC_SHA1 { 0x00, 0x2F }
#define GNUTLS_RSA_AES_256_CBC_SHA1 { 0x00, 0x35 }

/* rfc4132 */
#define GNUTLS_RSA_CAMELLIA_128_CBC_SHA1 { 0x00,0x41 }
#define GNUTLS_RSA_CAMELLIA_256_CBC_SHA1 { 0x00,0x84 }

#define GNUTLS_RSA_AES_128_CBC_SHA256 { 0x00, 0x3C }
#define GNUTLS_RSA_AES_256_CBC_SHA256 { 0x00, 0x3D }

/* DHE DSS
 */
#define GNUTLS_DHE_DSS_3DES_EDE_CBC_SHA1 { 0x00, 0x13 }


/* draft-ietf-tls-56-bit-ciphersuites-01:
 */
#define GNUTLS_DHE_DSS_ARCFOUR_128_SHA1 { 0x00, 0x66 }


/* rfc3268:
 */
#define GNUTLS_DHE_DSS_AES_256_CBC_SHA1 { 0x00, 0x38 }
#define GNUTLS_DHE_DSS_AES_128_CBC_SHA1 { 0x00, 0x32 }

/* rfc4132 */
#define GNUTLS_DHE_DSS_CAMELLIA_128_CBC_SHA1 { 0x00,0x44 }
#define GNUTLS_DHE_DSS_CAMELLIA_256_CBC_SHA1 { 0x00,0x87 }

#define GNUTLS_DHE_DSS_AES_128_CBC_SHA256 { 0x00, 0x40 }
#define GNUTLS_DHE_DSS_AES_256_CBC_SHA256 { 0x00, 0x6A }

/* DHE RSA
 */
#define GNUTLS_DHE_RSA_3DES_EDE_CBC_SHA1 { 0x00, 0x16 }

/* rfc3268:
 */
#define GNUTLS_DHE_RSA_AES_128_CBC_SHA1 { 0x00, 0x33 }
#define GNUTLS_DHE_RSA_AES_256_CBC_SHA1 { 0x00, 0x39 }

/* rfc4132 */
#define GNUTLS_DHE_RSA_CAMELLIA_128_CBC_SHA1 { 0x00,0x45 }
#define GNUTLS_DHE_RSA_CAMELLIA_256_CBC_SHA1 { 0x00,0x88 }

#define GNUTLS_DHE_RSA_AES_128_CBC_SHA256 { 0x00, 0x67 }
#define GNUTLS_DHE_RSA_AES_256_CBC_SHA256 { 0x00, 0x6B }

/* GCM: RFC5288 */
#define GNUTLS_RSA_AES_128_GCM_SHA256 { 0x00, 0x9C }
#define GNUTLS_DHE_RSA_AES_128_GCM_SHA256 {0x00,0x9E}
#define GNUTLS_DHE_DSS_AES_128_GCM_SHA256 {0x00,0xA2}
#define GNUTLS_DH_ANON_AES_128_GCM_SHA256 {0x00,0xA6}
#define GNUTLS_RSA_AES_256_GCM_SHA384 { 0x00, 0x9D }
#define GNUTLS_DHE_RSA_AES_256_GCM_SHA384 {0x00,0x9F}
#define GNUTLS_DHE_DSS_AES_256_GCM_SHA384 {0x00,0xA3}
#define GNUTLS_DH_ANON_AES_256_GCM_SHA384 {0x00,0xA7}

/* CCM: RFC6655/7251 */
#define GNUTLS_RSA_AES_128_CCM { 0xC0, 0x9C }
#define GNUTLS_RSA_AES_256_CCM { 0xC0, 0x9D }
#define GNUTLS_DHE_RSA_AES_128_CCM {0xC0,0x9E}
#define GNUTLS_DHE_RSA_AES_256_CCM {0xC0,0x9F}

#define GNUTLS_ECDHE_ECDSA_AES_128_CCM {0xC0,0xAC}
#define GNUTLS_ECDHE_ECDSA_AES_256_CCM {0xC0,0xAD}

#define GNUTLS_PSK_AES_128_CCM { 0xC0, 0xA4 }
#define GNUTLS_PSK_AES_256_CCM { 0xC0, 0xA5 }
#define GNUTLS_DHE_PSK_AES_128_CCM {0xC0,0xA6}
#define GNUTLS_DHE_PSK_AES_256_CCM {0xC0,0xA7}

/* CCM-8: RFC6655/7251 */
#define GNUTLS_RSA_AES_128_CCM_8 { 0xC0, 0xA0 }
#define GNUTLS_RSA_AES_256_CCM_8 { 0xC0, 0xA1 }
#define GNUTLS_DHE_RSA_AES_128_CCM_8 {0xC0,0xA2}
#define GNUTLS_DHE_RSA_AES_256_CCM_8 {0xC0,0xA3}

#define GNUTLS_ECDHE_ECDSA_AES_128_CCM_8 {0xC0,0xAE}
#define GNUTLS_ECDHE_ECDSA_AES_256_CCM_8 {0xC0,0xAF}

#define GNUTLS_PSK_AES_128_CCM_8 { 0xC0, 0xA8 }
#define GNUTLS_PSK_AES_256_CCM_8 { 0xC0, 0xA9 }
#define GNUTLS_DHE_PSK_AES_128_CCM_8 {0xC0,0xAA}
#define GNUTLS_DHE_PSK_AES_256_CCM_8 {0xC0,0xAB}


/* RFC 5487 */
/* GCM-PSK */
#define GNUTLS_PSK_AES_128_GCM_SHA256 { 0x00, 0xA8 }
#define GNUTLS_DHE_PSK_AES_128_GCM_SHA256 { 0x00, 0xAA }
#define GNUTLS_PSK_AES_256_GCM_SHA384 { 0x00, 0xA9 }
#define GNUTLS_DHE_PSK_AES_256_GCM_SHA384 { 0x00, 0xAB }

#define GNUTLS_PSK_AES_256_CBC_SHA384     { 0x00,0xAF }
#define GNUTLS_PSK_NULL_SHA384            { 0x00,0xB1 }
#define GNUTLS_DHE_PSK_AES_256_CBC_SHA384 { 0x00,0xB3 }
#define GNUTLS_DHE_PSK_NULL_SHA384        { 0x00,0xB5 }

#define GNUTLS_PSK_NULL_SHA1              { 0x00,0x2C }
#define GNUTLS_DHE_PSK_NULL_SHA1          { 0x00,0x2D }
#define GNUTLS_RSA_PSK_NULL_SHA1          { 0x00,0x2E }
#define GNUTLS_ECDHE_PSK_NULL_SHA1        { 0xC0,0x39 }

#define GNUTLS_RSA_PSK_AES_128_GCM_SHA256 { 0x00,0xAC }
#define GNUTLS_RSA_PSK_AES_256_GCM_SHA384 { 0x00,0xAD }
#define GNUTLS_RSA_PSK_AES_128_CBC_SHA256 { 0x00,0xB6 }
#define GNUTLS_RSA_PSK_AES_256_CBC_SHA384 { 0x00,0xB7 }
#define GNUTLS_RSA_PSK_NULL_SHA256        { 0x00,0xB8 }
#define GNUTLS_RSA_PSK_NULL_SHA384        { 0x00,0xB9 }


/* PSK - SHA256 HMAC */
#define GNUTLS_PSK_AES_128_CBC_SHA256 { 0x00, 0xAE }
#define GNUTLS_DHE_PSK_AES_128_CBC_SHA256 { 0x00, 0xB2 }

#define GNUTLS_PSK_NULL_SHA256 { 0x00, 0xB0 }
#define GNUTLS_DHE_PSK_NULL_SHA256 { 0x00, 0xB4 }

/* ECC */
#define GNUTLS_ECDH_ANON_NULL_SHA1 { 0xC0, 0x15 }
#define GNUTLS_ECDH_ANON_3DES_EDE_CBC_SHA1 { 0xC0, 0x17 }
#define GNUTLS_ECDH_ANON_AES_128_CBC_SHA1 { 0xC0, 0x18 }
#define GNUTLS_ECDH_ANON_AES_256_CBC_SHA1 { 0xC0, 0x19 }
#define GNUTLS_ECDH_ANON_ARCFOUR_128_SHA1 { 0xC0, 0x16 }

/* ECC-RSA */
#define GNUTLS_ECDHE_RSA_NULL_SHA1 { 0xC0, 0x10 }
#define GNUTLS_ECDHE_RSA_3DES_EDE_CBC_SHA1 { 0xC0, 0x12 }
#define GNUTLS_ECDHE_RSA_AES_128_CBC_SHA1 { 0xC0, 0x13 }
#define GNUTLS_ECDHE_RSA_AES_256_CBC_SHA1 { 0xC0, 0x14 }
#define GNUTLS_ECDHE_RSA_ARCFOUR_128_SHA1 { 0xC0, 0x11 }

/* ECC-ECDSA */
#define GNUTLS_ECDHE_ECDSA_NULL_SHA1           { 0xC0, 0x06 }
#define GNUTLS_ECDHE_ECDSA_3DES_EDE_CBC_SHA1   { 0xC0, 0x08 }
#define GNUTLS_ECDHE_ECDSA_AES_128_CBC_SHA1    { 0xC0, 0x09 }
#define GNUTLS_ECDHE_ECDSA_AES_256_CBC_SHA1    { 0xC0, 0x0A }
#define GNUTLS_ECDHE_ECDSA_ARCFOUR_128_SHA1 { 0xC0, 0x07 }

/* RFC5289 */
/* ECC with SHA2 */
#define GNUTLS_ECDHE_ECDSA_AES_128_CBC_SHA256     {0xC0,0x23}
#define GNUTLS_ECDHE_RSA_AES_128_CBC_SHA256       {0xC0,0x27}
#define GNUTLS_ECDHE_RSA_AES_256_CBC_SHA384       { 0xC0,0x28 }

/* ECC with AES-GCM */
#define GNUTLS_ECDHE_ECDSA_AES_128_GCM_SHA256   {0xC0,0x2B}
#define GNUTLS_ECDHE_RSA_AES_128_GCM_SHA256     {0xC0,0x2F}
#define GNUTLS_ECDHE_RSA_AES_256_GCM_SHA384     {0xC0,0x30}

/* SuiteB */
#define GNUTLS_ECDHE_ECDSA_AES_256_GCM_SHA384   {0xC0,0x2C}
#define GNUTLS_ECDHE_ECDSA_AES_256_CBC_SHA384   {0xC0,0x24}


/* ECC with PSK */
#define GNUTLS_ECDHE_PSK_3DES_EDE_CBC_SHA1 { 0xC0, 0x34 }
#define GNUTLS_ECDHE_PSK_AES_128_CBC_SHA1 { 0xC0, 0x35 }
#define GNUTLS_ECDHE_PSK_AES_256_CBC_SHA1 { 0xC0, 0x36 }
#define GNUTLS_ECDHE_PSK_AES_128_CBC_SHA256 { 0xC0, 0x37 }
#define GNUTLS_ECDHE_PSK_AES_256_CBC_SHA384 { 0xC0, 0x38 }
#define GNUTLS_ECDHE_PSK_ARCFOUR_128_SHA1 { 0xC0, 0x33 }
#define GNUTLS_ECDHE_PSK_NULL_SHA256 { 0xC0, 0x3A }
#define GNUTLS_ECDHE_PSK_NULL_SHA384 { 0xC0, 0x3B }

#define CIPHER_SUITES_COUNT (sizeof(cs_algorithms)/sizeof(gnutls_cipher_suite_entry_st)-1)

/* The following is a potential list of ciphersuites. For the options to be
 * available, the ciphers and MACs must be available to gnutls as well.
 */
static const gnutls_cipher_suite_entry_st cs_algorithms[] = {
	/* RSA-NULL */
	ENTRY(GNUTLS_RSA_NULL_MD5,
	      GNUTLS_CIPHER_NULL,
	      GNUTLS_KX_RSA, GNUTLS_MAC_MD5, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_RSA_NULL_SHA1,
	      GNUTLS_CIPHER_NULL,
	      GNUTLS_KX_RSA, GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_RSA_NULL_SHA256,
	      GNUTLS_CIPHER_NULL,
	      GNUTLS_KX_RSA, GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),

	/* RSA */
	ENTRY(GNUTLS_RSA_ARCFOUR_128_SHA1,
	      GNUTLS_CIPHER_ARCFOUR_128,
	      GNUTLS_KX_RSA, GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_VERSION_UNKNOWN),
	ENTRY(GNUTLS_RSA_ARCFOUR_128_MD5,
	      GNUTLS_CIPHER_ARCFOUR_128,
	      GNUTLS_KX_RSA, GNUTLS_MAC_MD5, GNUTLS_SSL3,
	      GNUTLS_VERSION_UNKNOWN),
	ENTRY(GNUTLS_RSA_3DES_EDE_CBC_SHA1,
	      GNUTLS_CIPHER_3DES_CBC,
	      GNUTLS_KX_RSA, GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_RSA_AES_128_CBC_SHA1,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_RSA_AES_256_CBC_SHA1,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),

	ENTRY(GNUTLS_RSA_CAMELLIA_128_CBC_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_CBC, GNUTLS_KX_RSA,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_RSA_CAMELLIA_256_CBC_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_256_CBC, GNUTLS_KX_RSA,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_RSA_CAMELLIA_128_CBC_SHA1,
	      GNUTLS_CIPHER_CAMELLIA_128_CBC, GNUTLS_KX_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_RSA_CAMELLIA_256_CBC_SHA1,
	      GNUTLS_CIPHER_CAMELLIA_256_CBC, GNUTLS_KX_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_RSA_AES_128_CBC_SHA256,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_RSA,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_RSA_AES_256_CBC_SHA256,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_RSA,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
/* GCM */
	ENTRY(GNUTLS_RSA_AES_128_GCM_SHA256,
	      GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_RSA_AES_256_GCM_SHA384,
		  GNUTLS_CIPHER_AES_256_GCM, GNUTLS_KX_RSA,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY(GNUTLS_RSA_CAMELLIA_128_GCM_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_GCM, GNUTLS_KX_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_RSA_CAMELLIA_256_GCM_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_GCM, GNUTLS_KX_RSA,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),

/* CCM */
	ENTRY(GNUTLS_RSA_AES_128_CCM,
	      GNUTLS_CIPHER_AES_128_CCM, GNUTLS_KX_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_RSA_AES_256_CCM,
	      GNUTLS_CIPHER_AES_256_CCM, GNUTLS_KX_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),


/* CCM_8 */
	ENTRY(GNUTLS_RSA_AES_128_CCM_8,
	      GNUTLS_CIPHER_AES_128_CCM_8, GNUTLS_KX_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_RSA_AES_256_CCM_8,
	      GNUTLS_CIPHER_AES_256_CCM_8, GNUTLS_KX_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),


	/* DHE_DSS */
#ifdef ENABLE_DHE
	ENTRY(GNUTLS_DHE_DSS_ARCFOUR_128_SHA1,
	      GNUTLS_CIPHER_ARCFOUR_128, GNUTLS_KX_DHE_DSS,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_VERSION_UNKNOWN),
	ENTRY(GNUTLS_DHE_DSS_3DES_EDE_CBC_SHA1,
	      GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_DHE_DSS,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DHE_DSS_AES_128_CBC_SHA1,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_DHE_DSS,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DHE_DSS_AES_256_CBC_SHA1,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_DHE_DSS,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DHE_DSS_CAMELLIA_128_CBC_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_CBC,
	      GNUTLS_KX_DHE_DSS,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_DSS_CAMELLIA_256_CBC_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_256_CBC,
	      GNUTLS_KX_DHE_DSS,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),

	ENTRY(GNUTLS_DHE_DSS_CAMELLIA_128_CBC_SHA1,
	      GNUTLS_CIPHER_CAMELLIA_128_CBC,
	      GNUTLS_KX_DHE_DSS,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DHE_DSS_CAMELLIA_256_CBC_SHA1,
	      GNUTLS_CIPHER_CAMELLIA_256_CBC,
	      GNUTLS_KX_DHE_DSS,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DHE_DSS_AES_128_CBC_SHA256,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_DHE_DSS,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_DSS_AES_256_CBC_SHA256,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_DHE_DSS,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
/* GCM */
	ENTRY(GNUTLS_DHE_DSS_AES_128_GCM_SHA256,
	      GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_DHE_DSS,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_DHE_DSS_AES_256_GCM_SHA384,
		  GNUTLS_CIPHER_AES_256_GCM, GNUTLS_KX_DHE_DSS,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY(GNUTLS_DHE_DSS_CAMELLIA_128_GCM_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_GCM, GNUTLS_KX_DHE_DSS,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_DHE_DSS_CAMELLIA_256_GCM_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_GCM, GNUTLS_KX_DHE_DSS,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),

	/* DHE_RSA */
	ENTRY(GNUTLS_DHE_RSA_3DES_EDE_CBC_SHA1,
	      GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DHE_RSA_AES_128_CBC_SHA1,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DHE_RSA_AES_256_CBC_SHA1,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DHE_RSA_CAMELLIA_128_CBC_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_CBC,
	      GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_RSA_CAMELLIA_256_CBC_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_256_CBC,
	      GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_RSA_CAMELLIA_128_CBC_SHA1,
	      GNUTLS_CIPHER_CAMELLIA_128_CBC,
	      GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DHE_RSA_CAMELLIA_256_CBC_SHA1,
	      GNUTLS_CIPHER_CAMELLIA_256_CBC,
	      GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DHE_RSA_AES_128_CBC_SHA256,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_RSA_AES_256_CBC_SHA256,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
/* GCM */
	ENTRY(GNUTLS_DHE_RSA_AES_128_GCM_SHA256,
	      GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_DHE_RSA_AES_256_GCM_SHA384,
		  GNUTLS_CIPHER_AES_256_GCM, GNUTLS_KX_DHE_RSA,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY(GNUTLS_DHE_RSA_CAMELLIA_128_GCM_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_GCM, GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_DHE_RSA_CAMELLIA_256_GCM_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_GCM, GNUTLS_KX_DHE_RSA,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),

	ENTRY(GNUTLS_DHE_RSA_CHACHA20_POLY1305,
	      GNUTLS_CIPHER_CHACHA20_POLY1305, GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2, GNUTLS_DTLS1_2),

/* CCM */
	ENTRY(GNUTLS_DHE_RSA_AES_128_CCM,
	      GNUTLS_CIPHER_AES_128_CCM, GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_RSA_AES_256_CCM,
	      GNUTLS_CIPHER_AES_256_CCM, GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_RSA_AES_128_CCM_8,
	      GNUTLS_CIPHER_AES_128_CCM_8, GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_RSA_AES_256_CCM_8,
	      GNUTLS_CIPHER_AES_256_CCM_8, GNUTLS_KX_DHE_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),

#endif				/* DHE */
#ifdef ENABLE_ECDHE
/* ECC-RSA */
	ENTRY(GNUTLS_ECDHE_RSA_NULL_SHA1,
	      GNUTLS_CIPHER_NULL, GNUTLS_KX_ECDHE_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDHE_RSA_3DES_EDE_CBC_SHA1,
	      GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_ECDHE_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDHE_RSA_AES_128_CBC_SHA1,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_ECDHE_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDHE_RSA_AES_256_CBC_SHA1,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_ECDHE_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY_PRF(GNUTLS_ECDHE_RSA_AES_256_CBC_SHA384,
		  GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_ECDHE_RSA,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY(GNUTLS_ECDHE_RSA_ARCFOUR_128_SHA1,
	      GNUTLS_CIPHER_ARCFOUR, GNUTLS_KX_ECDHE_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_VERSION_UNKNOWN),
	ENTRY(GNUTLS_ECDHE_RSA_CAMELLIA_128_CBC_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_CBC, GNUTLS_KX_ECDHE_RSA,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_ECDHE_RSA_CAMELLIA_256_CBC_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_CBC, GNUTLS_KX_ECDHE_RSA,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),

	/* ECDHE-ECDSA */
	ENTRY(GNUTLS_ECDHE_ECDSA_NULL_SHA1,
	      GNUTLS_CIPHER_NULL, GNUTLS_KX_ECDHE_ECDSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDHE_ECDSA_3DES_EDE_CBC_SHA1,
	      GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_ECDHE_ECDSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDHE_ECDSA_AES_128_CBC_SHA1,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_ECDHE_ECDSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDHE_ECDSA_AES_256_CBC_SHA1,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_ECDHE_ECDSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDHE_ECDSA_ARCFOUR_128_SHA1,
	      GNUTLS_CIPHER_ARCFOUR, GNUTLS_KX_ECDHE_ECDSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_VERSION_UNKNOWN),
	ENTRY(GNUTLS_ECDHE_ECDSA_CAMELLIA_128_CBC_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_CBC, GNUTLS_KX_ECDHE_ECDSA,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_ECDHE_ECDSA_CAMELLIA_256_CBC_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_CBC, GNUTLS_KX_ECDHE_ECDSA,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),

	/* More ECC */

	ENTRY(GNUTLS_ECDHE_ECDSA_AES_128_CBC_SHA256,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_ECDHE_ECDSA,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_ECDHE_RSA_AES_128_CBC_SHA256,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_ECDHE_RSA,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_ECDHE_ECDSA_CAMELLIA_128_GCM_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_GCM, GNUTLS_KX_ECDHE_ECDSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_ECDHE_ECDSA_CAMELLIA_256_GCM_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_GCM, GNUTLS_KX_ECDHE_ECDSA,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY(GNUTLS_ECDHE_ECDSA_AES_128_GCM_SHA256,
	      GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_ECDHE_ECDSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_ECDHE_ECDSA_AES_256_GCM_SHA384,
		  GNUTLS_CIPHER_AES_256_GCM, GNUTLS_KX_ECDHE_ECDSA,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY(GNUTLS_ECDHE_RSA_AES_128_GCM_SHA256,
	      GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_ECDHE_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_ECDHE_RSA_AES_256_GCM_SHA384,
		  GNUTLS_CIPHER_AES_256_GCM, GNUTLS_KX_ECDHE_RSA,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY_PRF(GNUTLS_ECDHE_ECDSA_AES_256_CBC_SHA384,
		  GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_ECDHE_ECDSA,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),

	ENTRY(GNUTLS_ECDHE_RSA_CAMELLIA_128_GCM_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_GCM, GNUTLS_KX_ECDHE_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_ECDHE_RSA_CAMELLIA_256_GCM_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_GCM, GNUTLS_KX_ECDHE_RSA,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),

	ENTRY(GNUTLS_ECDHE_RSA_CHACHA20_POLY1305,
	      GNUTLS_CIPHER_CHACHA20_POLY1305, GNUTLS_KX_ECDHE_RSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),

	ENTRY(GNUTLS_ECDHE_ECDSA_CHACHA20_POLY1305,
	      GNUTLS_CIPHER_CHACHA20_POLY1305, GNUTLS_KX_ECDHE_ECDSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),

	ENTRY(GNUTLS_ECDHE_ECDSA_AES_128_CCM,
	      GNUTLS_CIPHER_AES_128_CCM, GNUTLS_KX_ECDHE_ECDSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_ECDHE_ECDSA_AES_256_CCM,
	      GNUTLS_CIPHER_AES_256_CCM, GNUTLS_KX_ECDHE_ECDSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_ECDHE_ECDSA_AES_128_CCM_8,
	      GNUTLS_CIPHER_AES_128_CCM_8, GNUTLS_KX_ECDHE_ECDSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_ECDHE_ECDSA_AES_256_CCM_8,
	      GNUTLS_CIPHER_AES_256_CCM_8, GNUTLS_KX_ECDHE_ECDSA,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
#endif
#ifdef ENABLE_PSK
	/* ECC - PSK */
	ENTRY(GNUTLS_ECDHE_PSK_3DES_EDE_CBC_SHA1,
	      GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_ECDHE_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDHE_PSK_AES_128_CBC_SHA1,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_ECDHE_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDHE_PSK_AES_256_CBC_SHA1,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_ECDHE_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDHE_PSK_AES_128_CBC_SHA256,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_ECDHE_PSK,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_ECDHE_PSK_AES_256_CBC_SHA384,
		  GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_ECDHE_PSK,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY(GNUTLS_ECDHE_PSK_ARCFOUR_128_SHA1,
	      GNUTLS_CIPHER_ARCFOUR, GNUTLS_KX_ECDHE_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_VERSION_UNKNOWN),
	ENTRY(GNUTLS_ECDHE_PSK_NULL_SHA1,
	      GNUTLS_CIPHER_NULL, GNUTLS_KX_ECDHE_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDHE_PSK_NULL_SHA256,
	      GNUTLS_CIPHER_NULL, GNUTLS_KX_ECDHE_PSK,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_ECDHE_PSK_NULL_SHA384,
		  GNUTLS_CIPHER_NULL, GNUTLS_KX_ECDHE_PSK,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY(GNUTLS_ECDHE_PSK_CAMELLIA_128_CBC_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_CBC, GNUTLS_KX_ECDHE_PSK,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_ECDHE_PSK_CAMELLIA_256_CBC_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_CBC, GNUTLS_KX_ECDHE_PSK,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),

	/* PSK */
	ENTRY(GNUTLS_PSK_ARCFOUR_128_SHA1,
	      GNUTLS_CIPHER_ARCFOUR, GNUTLS_KX_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_VERSION_UNKNOWN),
	ENTRY(GNUTLS_PSK_3DES_EDE_CBC_SHA1,
	      GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_PSK_AES_128_CBC_SHA1,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_PSK_AES_256_CBC_SHA1,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_PSK_AES_128_CBC_SHA256,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_PSK,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_PSK_AES_256_GCM_SHA384,
		  GNUTLS_CIPHER_AES_256_GCM, GNUTLS_KX_PSK,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY(GNUTLS_PSK_CAMELLIA_128_GCM_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_GCM, GNUTLS_KX_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_PSK_CAMELLIA_256_GCM_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_GCM, GNUTLS_KX_PSK,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),


	ENTRY(GNUTLS_PSK_AES_128_GCM_SHA256,
	      GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_PSK_NULL_SHA1,
	      GNUTLS_CIPHER_NULL, GNUTLS_KX_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_PSK_NULL_SHA256,
	      GNUTLS_CIPHER_NULL, GNUTLS_KX_PSK,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_PSK_CAMELLIA_128_CBC_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_CBC, GNUTLS_KX_PSK,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_PSK_CAMELLIA_256_CBC_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_CBC, GNUTLS_KX_PSK,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),

	ENTRY_PRF(GNUTLS_PSK_AES_256_CBC_SHA384,
		  GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_PSK,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY_PRF(GNUTLS_PSK_NULL_SHA384,
		  GNUTLS_CIPHER_NULL, GNUTLS_KX_PSK,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),

	/* RSA-PSK */
	ENTRY(GNUTLS_RSA_PSK_ARCFOUR_128_SHA1,
	      GNUTLS_CIPHER_ARCFOUR, GNUTLS_KX_RSA_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_TLS1,
	      GNUTLS_VERSION_UNKNOWN),
	ENTRY(GNUTLS_RSA_PSK_3DES_EDE_CBC_SHA1,
	      GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_RSA_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_TLS1,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_RSA_PSK_AES_128_CBC_SHA1,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_RSA_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_TLS1,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_RSA_PSK_AES_256_CBC_SHA1,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_RSA_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_TLS1,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_RSA_PSK_CAMELLIA_128_GCM_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_GCM, GNUTLS_KX_RSA_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_RSA_PSK_CAMELLIA_256_GCM_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_GCM, GNUTLS_KX_RSA_PSK,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),


	ENTRY(GNUTLS_RSA_PSK_AES_128_GCM_SHA256,
	      GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_RSA_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_RSA_PSK_AES_128_CBC_SHA256,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_RSA_PSK,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_RSA_PSK_NULL_SHA1,
	      GNUTLS_CIPHER_NULL, GNUTLS_KX_RSA_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_TLS1,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_RSA_PSK_NULL_SHA256,
	      GNUTLS_CIPHER_NULL, GNUTLS_KX_RSA_PSK,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_RSA_PSK_AES_256_GCM_SHA384,
		  GNUTLS_CIPHER_AES_256_GCM, GNUTLS_KX_RSA_PSK,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY_PRF(GNUTLS_RSA_PSK_AES_256_CBC_SHA384,
		  GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_RSA_PSK,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY_PRF(GNUTLS_RSA_PSK_NULL_SHA384,
		  GNUTLS_CIPHER_NULL, GNUTLS_KX_RSA_PSK,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY(GNUTLS_RSA_PSK_CAMELLIA_128_CBC_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_CBC, GNUTLS_KX_RSA_PSK,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_RSA_PSK_CAMELLIA_256_CBC_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_CBC, GNUTLS_KX_RSA_PSK,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),


	/* DHE-PSK */
	ENTRY(GNUTLS_DHE_PSK_ARCFOUR_128_SHA1,
	      GNUTLS_CIPHER_ARCFOUR, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_VERSION_UNKNOWN),
	ENTRY(GNUTLS_DHE_PSK_3DES_EDE_CBC_SHA1,
	      GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DHE_PSK_AES_128_CBC_SHA1,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DHE_PSK_AES_256_CBC_SHA1,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DHE_PSK_AES_128_CBC_SHA256,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_PSK_AES_128_GCM_SHA256,
	      GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_PSK_NULL_SHA1,
	      GNUTLS_CIPHER_NULL, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DHE_PSK_NULL_SHA256,
	      GNUTLS_CIPHER_NULL, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_DHE_PSK_NULL_SHA384,
		  GNUTLS_CIPHER_NULL, GNUTLS_KX_DHE_PSK,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY_PRF(GNUTLS_DHE_PSK_AES_256_CBC_SHA384,
		  GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_DHE_PSK,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY_PRF(GNUTLS_DHE_PSK_AES_256_GCM_SHA384,
		  GNUTLS_CIPHER_AES_256_GCM, GNUTLS_KX_DHE_PSK,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY(GNUTLS_DHE_PSK_CAMELLIA_128_CBC_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_CBC, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_DHE_PSK_CAMELLIA_256_CBC_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_CBC, GNUTLS_KX_DHE_PSK,
		  GNUTLS_MAC_SHA384, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY(GNUTLS_DHE_PSK_CAMELLIA_128_GCM_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_GCM, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_DHE_PSK_CAMELLIA_256_GCM_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_GCM, GNUTLS_KX_DHE_PSK,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),

	ENTRY(GNUTLS_PSK_AES_128_CCM,
	      GNUTLS_CIPHER_AES_128_CCM, GNUTLS_KX_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_PSK_AES_256_CCM,
	      GNUTLS_CIPHER_AES_256_CCM, GNUTLS_KX_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_PSK_AES_128_CCM,
	      GNUTLS_CIPHER_AES_128_CCM, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_PSK_AES_256_CCM,
	      GNUTLS_CIPHER_AES_256_CCM, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_PSK_AES_128_CCM_8,
	      GNUTLS_CIPHER_AES_128_CCM_8, GNUTLS_KX_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_PSK_AES_256_CCM_8,
	      GNUTLS_CIPHER_AES_256_CCM_8, GNUTLS_KX_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_PSK_AES_128_CCM_8,
	      GNUTLS_CIPHER_AES_128_CCM_8, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_PSK_AES_256_CCM_8,
	      GNUTLS_CIPHER_AES_256_CCM_8, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DHE_PSK_CHACHA20_POLY1305,
	      GNUTLS_CIPHER_CHACHA20_POLY1305, GNUTLS_KX_DHE_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2, GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_ECDHE_PSK_CHACHA20_POLY1305,
	      GNUTLS_CIPHER_CHACHA20_POLY1305, GNUTLS_KX_ECDHE_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2, GNUTLS_DTLS1_2),

	ENTRY(GNUTLS_RSA_PSK_CHACHA20_POLY1305,
	      GNUTLS_CIPHER_CHACHA20_POLY1305, GNUTLS_KX_RSA_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2, GNUTLS_DTLS1_2),

	ENTRY(GNUTLS_PSK_CHACHA20_POLY1305,
	      GNUTLS_CIPHER_CHACHA20_POLY1305, GNUTLS_KX_PSK,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2, GNUTLS_DTLS1_2),

#endif
#ifdef ENABLE_ANON
	/* DH_ANON */
	ENTRY(GNUTLS_DH_ANON_ARCFOUR_128_MD5,
	      GNUTLS_CIPHER_ARCFOUR_128,
	      GNUTLS_KX_ANON_DH, GNUTLS_MAC_MD5,
	      GNUTLS_SSL3, GNUTLS_VERSION_UNKNOWN),
	ENTRY(GNUTLS_DH_ANON_3DES_EDE_CBC_SHA1,
	      GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_ANON_DH,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DH_ANON_AES_128_CBC_SHA1,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_ANON_DH,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DH_ANON_AES_256_CBC_SHA1,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_ANON_DH,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DH_ANON_CAMELLIA_128_CBC_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_CBC,
	      GNUTLS_KX_ANON_DH,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DH_ANON_CAMELLIA_256_CBC_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_256_CBC,
	      GNUTLS_KX_ANON_DH,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DH_ANON_CAMELLIA_128_CBC_SHA1,
	      GNUTLS_CIPHER_CAMELLIA_128_CBC,
	      GNUTLS_KX_ANON_DH,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DH_ANON_CAMELLIA_256_CBC_SHA1,
	      GNUTLS_CIPHER_CAMELLIA_256_CBC,
	      GNUTLS_KX_ANON_DH,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_DH_ANON_AES_128_CBC_SHA256,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_ANON_DH,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DH_ANON_AES_256_CBC_SHA256,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_ANON_DH,
	      GNUTLS_MAC_SHA256, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY(GNUTLS_DH_ANON_AES_128_GCM_SHA256,
	      GNUTLS_CIPHER_AES_128_GCM, GNUTLS_KX_ANON_DH,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_DH_ANON_AES_256_GCM_SHA384,
		  GNUTLS_CIPHER_AES_256_GCM, GNUTLS_KX_ANON_DH,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),
	ENTRY(GNUTLS_DH_ANON_CAMELLIA_128_GCM_SHA256,
	      GNUTLS_CIPHER_CAMELLIA_128_GCM, GNUTLS_KX_ANON_DH,
	      GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
	      GNUTLS_DTLS1_2),
	ENTRY_PRF(GNUTLS_DH_ANON_CAMELLIA_256_GCM_SHA384,
		  GNUTLS_CIPHER_CAMELLIA_256_GCM, GNUTLS_KX_ANON_DH,
		  GNUTLS_MAC_AEAD, GNUTLS_TLS1_2,
		  GNUTLS_DTLS1_2, GNUTLS_MAC_SHA384),

/* ECC-ANON */
	ENTRY(GNUTLS_ECDH_ANON_NULL_SHA1,
	      GNUTLS_CIPHER_NULL, GNUTLS_KX_ANON_ECDH,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDH_ANON_3DES_EDE_CBC_SHA1,
	      GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_ANON_ECDH,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDH_ANON_AES_128_CBC_SHA1,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_ANON_ECDH,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDH_ANON_AES_256_CBC_SHA1,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_ANON_ECDH,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_ECDH_ANON_ARCFOUR_128_SHA1,
	      GNUTLS_CIPHER_ARCFOUR, GNUTLS_KX_ANON_ECDH,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_VERSION_UNKNOWN),
#endif
#ifdef ENABLE_SRP
	/* SRP */
	ENTRY(GNUTLS_SRP_SHA_3DES_EDE_CBC_SHA1,
	      GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_SRP,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_SRP_SHA_AES_128_CBC_SHA1,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_SRP,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
	ENTRY(GNUTLS_SRP_SHA_AES_256_CBC_SHA1,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_SRP,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),

	ENTRY(GNUTLS_SRP_SHA_DSS_3DES_EDE_CBC_SHA1,
	      GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_SRP_DSS,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),

	ENTRY(GNUTLS_SRP_SHA_RSA_3DES_EDE_CBC_SHA1,
	      GNUTLS_CIPHER_3DES_CBC, GNUTLS_KX_SRP_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),

	ENTRY(GNUTLS_SRP_SHA_DSS_AES_128_CBC_SHA1,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_SRP_DSS,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),

	ENTRY(GNUTLS_SRP_SHA_RSA_AES_128_CBC_SHA1,
	      GNUTLS_CIPHER_AES_128_CBC, GNUTLS_KX_SRP_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),

	ENTRY(GNUTLS_SRP_SHA_DSS_AES_256_CBC_SHA1,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_SRP_DSS,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),

	ENTRY(GNUTLS_SRP_SHA_RSA_AES_256_CBC_SHA1,
	      GNUTLS_CIPHER_AES_256_CBC, GNUTLS_KX_SRP_RSA,
	      GNUTLS_MAC_SHA1, GNUTLS_SSL3,
	      GNUTLS_DTLS_VERSION_MIN),
#endif


	{0, {0, 0}, 0, 0, 0, 0, 0, 0}
};

#define CIPHER_SUITE_LOOP(b) { \
        const gnutls_cipher_suite_entry_st *p; \
                for(p = cs_algorithms; p->name != NULL; p++) { b ; } }

#define CIPHER_SUITE_ALG_LOOP(a, suite) \
        CIPHER_SUITE_LOOP( if( (p->id[0] == suite[0]) && (p->id[1] == suite[1])) { a; break; } )


/* Cipher Suite's functions */
const gnutls_cipher_suite_entry_st *ciphersuite_to_entry(const uint8_t suite[2])
{
	CIPHER_SUITE_ALG_LOOP(return p, suite);
	return NULL;
}

const cipher_entry_st *_gnutls_cipher_suite_get_cipher_algo(const uint8_t
							    suite[2])
{
	int ret = 0;
	CIPHER_SUITE_ALG_LOOP(ret = p->block_algorithm, suite);
	return cipher_to_entry(ret);
}

gnutls_kx_algorithm_t
_gnutls_cipher_suite_get_kx_algo(const uint8_t suite[2])
{
	int ret = 0;

	CIPHER_SUITE_ALG_LOOP(ret = p->kx_algorithm, suite);
	return ret;

}

gnutls_mac_algorithm_t _gnutls_cipher_suite_get_prf(const uint8_t suite[2])
{
	int ret = 0;

	CIPHER_SUITE_ALG_LOOP(ret = p->prf, suite);
	return ret;

}

const mac_entry_st *_gnutls_cipher_suite_get_mac_algo(const uint8_t
						      suite[2])
{				/* In bytes */
	int ret = 0;
	CIPHER_SUITE_ALG_LOOP(ret = p->mac_algorithm, suite);
	return mac_to_entry(ret);

}

const char *_gnutls_cipher_suite_get_name(const uint8_t suite[2])
{
	const char *ret = NULL;

	/* avoid prefix */
	CIPHER_SUITE_ALG_LOOP(ret = p->name + sizeof("GNUTLS_") - 1, suite);

	return ret;
}


static const gnutls_cipher_suite_entry_st
    *cipher_suite_get(gnutls_kx_algorithm_t kx_algorithm,
		      gnutls_cipher_algorithm_t cipher_algorithm,
		      gnutls_mac_algorithm_t mac_algorithm)
{
	const gnutls_cipher_suite_entry_st *ret = NULL;

	CIPHER_SUITE_LOOP(
		if (kx_algorithm == p->kx_algorithm &&
			      cipher_algorithm == p->block_algorithm
			      && mac_algorithm == p->mac_algorithm) {
			ret = p; 
			break;
		}
	);

	return ret;
}

/* Returns 1 if the given KX has not the corresponding parameters
 * (DH or RSA) set up. Otherwise returns 0.
 */
inline static int
check_server_params(gnutls_session_t session,
		    gnutls_kx_algorithm_t kx,
		    gnutls_kx_algorithm_t * alg, int alg_size)
{
	int cred_type;
	gnutls_dh_params_t dh_params = NULL;
	int j;

	cred_type = _gnutls_map_kx_get_cred(kx, 1);

	/* Read the Diffie-Hellman parameters, if any.
	 */
	if (cred_type == GNUTLS_CRD_CERTIFICATE) {
		int delete;
		gnutls_certificate_credentials_t x509_cred =
		    (gnutls_certificate_credentials_t)
		    _gnutls_get_cred(session, cred_type);

		if (x509_cred != NULL) {
			dh_params =
			    _gnutls_get_dh_params(x509_cred->dh_params,
						  x509_cred->params_func,
						  session);
		}

		/* Check also if the certificate supports the
		 * KX method.
		 */
		delete = 1;
		for (j = 0; j < alg_size; j++) {
			if (alg[j] == kx) {
				delete = 0;
				break;
			}
		}

		if (delete == 1)
			return 1;

#ifdef ENABLE_ANON
	} else if (cred_type == GNUTLS_CRD_ANON) {
		gnutls_anon_server_credentials_t anon_cred =
		    (gnutls_anon_server_credentials_t)
		    _gnutls_get_cred(session, cred_type);

		if (anon_cred != NULL) {
			dh_params =
			    _gnutls_get_dh_params(anon_cred->dh_params,
						  anon_cred->params_func,
						  session);
		}
#endif
#ifdef ENABLE_PSK
	} else if (cred_type == GNUTLS_CRD_PSK) {
		gnutls_psk_server_credentials_t psk_cred =
		    (gnutls_psk_server_credentials_t)
		    _gnutls_get_cred(session, cred_type);

		if (psk_cred != NULL) {
			dh_params =
			    _gnutls_get_dh_params(psk_cred->dh_params,
						  psk_cred->params_func,
						  session);
		}
#endif
	} else
		return 0;	/* no need for params */

	/* If the key exchange method needs DH params,
	 * but they are not set then remove it.
	 */
	if (_gnutls_kx_needs_dh_params(kx) != 0) {
		/* needs DH params. */
		if (_gnutls_dh_params_to_mpi(dh_params) == NULL) {
			gnutls_assert();
			return 1;
		}
	}

	return 0;
}

/* This function will remove algorithms that are not supported by
 * the requested authentication method. We remove an algorithm if
 * we have a certificate with keyUsage bits set.
 *
 * This does a more elaborate check than gnutls_supported_ciphersuites(),
 * by checking certificates etc.
 */
int
_gnutls_remove_unwanted_ciphersuites(gnutls_session_t session,
			     uint8_t * cipher_suites,
			     int cipher_suites_size,
			     gnutls_pk_algorithm_t * pk_algos,
			     size_t pk_algos_size)
{

	int ret = 0;
	gnutls_certificate_credentials_t cert_cred;
	gnutls_kx_algorithm_t kx;
	int server =
	    session->security_parameters.entity == GNUTLS_SERVER ? 1 : 0;
	gnutls_kx_algorithm_t alg[MAX_ALGOS];
	int alg_size = MAX_ALGOS;
	uint8_t new_list[cipher_suites_size]; /* it's safe to use that size because it's provided by _gnutls_supported_ciphersuites() */
	int i, new_list_size = 0;
	const gnutls_cipher_suite_entry_st *entry;
	const uint8_t *cp;

	/* if we should use a specific certificate, 
	 * we should remove all algorithms that are not supported
	 * by that certificate and are on the same authentication
	 * method (CERTIFICATE).
	 */
	cert_cred =
	    (gnutls_certificate_credentials_t) _gnutls_get_cred(session,
								GNUTLS_CRD_CERTIFICATE);

	/* If there are certificate credentials, find an appropriate certificate
	 * or disable them;
	 */
	if (session->security_parameters.entity == GNUTLS_SERVER
	    && cert_cred != NULL && pk_algos_size > 0) {
		ret =
		    _gnutls_server_select_cert(session, pk_algos,
					       pk_algos_size);
		if (ret < 0) {
			gnutls_assert();
			_gnutls_debug_log
			    ("Could not find an appropriate certificate: %s\n",
			     gnutls_strerror(ret));
		}
	}

	/* get all the key exchange algorithms that are 
	 * supported by the X509 certificate parameters.
	 */
	if ((ret =
	     _gnutls_selected_cert_supported_kx(session, alg,
						&alg_size)) < 0) {
		gnutls_assert();
		return ret;
	}

	/* now remove ciphersuites based on the KX algorithm
	 */
	for (i = 0; i < cipher_suites_size; i += 2) {
		entry = NULL;
		cp = &cipher_suites[i];

		CIPHER_SUITE_ALG_LOOP(entry = p, cp);

		if (entry == NULL)
			continue;
		
		/* finds the key exchange algorithm in
		 * the ciphersuite
		 */
		kx = entry->kx_algorithm;

		/* if it is defined but had no credentials 
		 */
		if (!session->internals.premaster_set &&
		    _gnutls_get_kx_cred(session, kx) == NULL) {
			continue;
		} else {
			if (server && check_server_params(session, kx, alg,
							  alg_size) != 0)
				continue;
		}

		/* If we have not agreed to a common curve with the peer don't bother
		 * negotiating ECDH.
		 */
		if (server != 0 && _gnutls_kx_is_ecc(kx)) {
			if (_gnutls_session_ecc_curve_get(session) ==
			    GNUTLS_ECC_CURVE_INVALID) {
				continue;
			}
		}

		/* These two SRP kx's are marked to require a CRD_CERTIFICATE,
		   (see cred_mappings in gnutls_algorithms.c), but it also
		   requires a SRP credential.  Don't use SRP kx unless we have a
		   SRP credential too.  */
		if (kx == GNUTLS_KX_SRP_RSA || kx == GNUTLS_KX_SRP_DSS) {
			if (!_gnutls_get_cred
			    (session, GNUTLS_CRD_SRP)) {
				continue;
			}
		}

		_gnutls_handshake_log
			    ("HSK[%p]: Keeping ciphersuite: %s (%.2X.%.2X)\n",
			     session, entry->name,
			     cipher_suites[i], cipher_suites[i + 1]);

		memcpy(&new_list[new_list_size], &cipher_suites[i], 2);
		new_list_size += 2;
	}

	if (new_list_size == 0) {
		return gnutls_assert_val(GNUTLS_E_NO_CIPHER_SUITES);
	}

	memcpy(cipher_suites, new_list, new_list_size);

	return new_list_size;
}


/**
 * gnutls_cipher_suite_get_name:
 * @kx_algorithm: is a Key exchange algorithm
 * @cipher_algorithm: is a cipher algorithm
 * @mac_algorithm: is a MAC algorithm
 *
 * Note that the full cipher suite name must be prepended by TLS or
 * SSL depending of the protocol in use.
 *
 * Returns: a string that contains the name of a TLS cipher suite,
 * specified by the given algorithms, or %NULL.
 **/
const char *gnutls_cipher_suite_get_name(gnutls_kx_algorithm_t
					 kx_algorithm,
					 gnutls_cipher_algorithm_t
					 cipher_algorithm,
					 gnutls_mac_algorithm_t
					 mac_algorithm)
{
	const gnutls_cipher_suite_entry_st *ce;

	ce = cipher_suite_get(kx_algorithm, cipher_algorithm,
			      mac_algorithm);
	if (ce == NULL)
		return NULL;
	else
		return ce->name + sizeof("GNUTLS_") - 1;
}

/*-
 * _gnutls_cipher_suite_get_id:
 * @kx_algorithm: is a Key exchange algorithm
 * @cipher_algorithm: is a cipher algorithm
 * @mac_algorithm: is a MAC algorithm
 * @suite: The id to be returned
 *
 * It fills @suite with the ID of the ciphersuite of the provided parameters.
 *
 * Returns: 0 on success or a negative error code otherwise.
 -*/
int
_gnutls_cipher_suite_get_id(gnutls_kx_algorithm_t kx_algorithm,
			    gnutls_cipher_algorithm_t cipher_algorithm,
			    gnutls_mac_algorithm_t mac_algorithm,
			    uint8_t suite[2])
{
	const gnutls_cipher_suite_entry_st *ce;

	ce = cipher_suite_get(kx_algorithm, cipher_algorithm,
			      mac_algorithm);
	if (ce == NULL)
		return GNUTLS_E_INVALID_REQUEST;
	else {
		suite[0] = ce->id[0];
		suite[1] = ce->id[1];
	}
	return 0;
}

/**
 * gnutls_cipher_suite_info:
 * @idx: index of cipher suite to get information about, starts on 0.
 * @cs_id: output buffer with room for 2 bytes, indicating cipher suite value
 * @kx: output variable indicating key exchange algorithm, or %NULL.
 * @cipher: output variable indicating cipher, or %NULL.
 * @mac: output variable indicating MAC algorithm, or %NULL.
 * @min_version: output variable indicating TLS protocol version, or %NULL.
 *
 * Get information about supported cipher suites.  Use the function
 * iteratively to get information about all supported cipher suites.
 * Call with idx=0 to get information about first cipher suite, then
 * idx=1 and so on until the function returns NULL.
 *
 * Returns: the name of @idx cipher suite, and set the information
 * about the cipher suite in the output variables.  If @idx is out of
 * bounds, %NULL is returned.
 **/
const char *gnutls_cipher_suite_info(size_t idx,
				     unsigned char *cs_id,
				     gnutls_kx_algorithm_t * kx,
				     gnutls_cipher_algorithm_t * cipher,
				     gnutls_mac_algorithm_t * mac,
				     gnutls_protocol_t * min_version)
{
	if (idx >= CIPHER_SUITES_COUNT)
		return NULL;

	if (cs_id)
		memcpy(cs_id, cs_algorithms[idx].id, 2);
	if (kx)
		*kx = cs_algorithms[idx].kx_algorithm;
	if (cipher)
		*cipher = cs_algorithms[idx].block_algorithm;
	if (mac)
		*mac = cs_algorithms[idx].mac_algorithm;
	if (min_version)
		*min_version = cs_algorithms[idx].min_version;

	return cs_algorithms[idx].name + sizeof("GNU") - 1;
}


static inline int _gnutls_cipher_suite_is_ok(const uint8_t suite[2])
{
	size_t ret;
	const char *name = NULL;

	CIPHER_SUITE_ALG_LOOP(name = p->name, suite);
	if (name != NULL)
		ret = 0;
	else
		ret = 1;
	return ret;

}

/*-
 * _gnutls_supported_ciphersuites: 
 * @session: a TLS session
 * @cipher_suites: Where the ciphersuites will be stored (2bytes each)
 * @max_cipher_suite_size: the maximum size of the @cipher_suites buffer.
 *
 * Returns the supported ciphersuites by this session (based on priorities)
 * sorted by order of preference.
 *
 * Returns the size of the @cipher_suites buffer, or a negative value on error.
 *
 -*/
int
_gnutls_supported_ciphersuites(gnutls_session_t session,
			       uint8_t * cipher_suites,
			       unsigned int max_cipher_suite_size)
{

	unsigned int i, ret_count, j, z, k = 0;
	const gnutls_cipher_suite_entry_st *ce;
	const version_entry_st *version = get_version(session);
	unsigned int is_dtls = IS_DTLS(session);

	if (version == NULL)
		return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);

	for (i = 0; i < session->internals.priorities.kx.algorithms; i++)
		for (j = 0;
		     j < session->internals.priorities.cipher.algorithms;
		     j++)
			for (z = 0;
			     z <
			     session->internals.priorities.mac.algorithms;
			     z++) {
				ce = cipher_suite_get(session->internals.
						      priorities.kx.
						      priority[i],
						      session->internals.
						      priorities.cipher.
						      priority[j],
						      session->internals.
						      priorities.mac.
						      priority[z]);

				if (ce == NULL)
					continue;

				if (is_dtls) {
					if (version->id < ce->min_dtls_version)
						continue;
				} else {
					if (version->id < ce->min_version)
						continue;
				}

				if (k + 2 > max_cipher_suite_size)
					return
					    gnutls_assert_val
					    (GNUTLS_E_INTERNAL_ERROR);

				memcpy(&cipher_suites[k], ce->id, 2);
				k += 2;
			}

	ret_count = k;

	/* This function can no longer return 0 cipher suites.
	 * It returns an error code instead.
	 */
	if (ret_count == 0) {
		gnutls_assert();
		return GNUTLS_E_NO_CIPHER_SUITES;
	}
	return ret_count;
}

/**
 * gnutls_priority_get_cipher_suite:
 * @pcache: is a #gnutls_prioritity_t type.
 * @idx: is an index number.
 * @sidx: internal index of cipher suite to get information about.
 *
 * Provides the internal ciphersuite index to be used with
 * gnutls_cipher_suite_info(). The index @idx provided is an 
 * index kept at the priorities structure. It might be that a valid
 * priorities index does not correspond to a ciphersuite and in 
 * that case %GNUTLS_E_UNKNOWN_CIPHER_SUITE will be returned. 
 * Once the last available index is crossed then 
 * %GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE will be returned.
 *
 * Returns: On success it returns %GNUTLS_E_SUCCESS (0), or a negative error value otherwise.
 *
 * Since: 3.0.9
 **/
int
gnutls_priority_get_cipher_suite_index(gnutls_priority_t pcache,
				       unsigned int idx,
				       unsigned int *sidx)
{
	int mac_idx, cipher_idx, kx_idx;
	unsigned int i;
	unsigned int total =
	    pcache->mac.algorithms * pcache->cipher.algorithms *
	    pcache->kx.algorithms;

	if (idx >= total)
		return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;

	mac_idx = idx % pcache->mac.algorithms;

	idx /= pcache->mac.algorithms;
	cipher_idx = idx % pcache->cipher.algorithms;

	idx /= pcache->cipher.algorithms;
	kx_idx = idx % pcache->kx.algorithms;

	for (i = 0; i < CIPHER_SUITES_COUNT; i++) {
		if (cs_algorithms[i].kx_algorithm ==
		    pcache->kx.priority[kx_idx]
		    && cs_algorithms[i].block_algorithm ==
		    pcache->cipher.priority[cipher_idx]
		    && cs_algorithms[i].mac_algorithm ==
		    pcache->mac.priority[mac_idx]) {
			*sidx = i;
			return 0;
		}
	}
	return GNUTLS_E_UNKNOWN_CIPHER_SUITE;
}
