mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
1497 lines
40 KiB
C
1497 lines
40 KiB
C
/*
|
|
* Copyright (C) 2000, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation
|
|
*
|
|
* Author: Nikos Mavrogiannopoulos
|
|
*
|
|
* This file is part of GNUTLS.
|
|
*
|
|
* The GNUTLS library 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 library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
|
* USA
|
|
*
|
|
*/
|
|
|
|
#include "gnutls_int.h"
|
|
#include "gnutls_algorithms.h"
|
|
#include "gnutls_errors.h"
|
|
#include "gnutls_cert.h"
|
|
/* x509 */
|
|
#include "common.h"
|
|
|
|
/* Cred type mappings to KX algorithms
|
|
* FIXME: The mappings are not 1-1. Some KX such as SRP_RSA require
|
|
* more than one credentials type.
|
|
*/
|
|
typedef struct
|
|
{
|
|
enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm;
|
|
enum MHD_GNUTLS_CredentialsType client_type;
|
|
enum MHD_GNUTLS_CredentialsType server_type; /* The type of credentials a server
|
|
* needs to set */
|
|
} MHD_gnutls_cred_map;
|
|
|
|
static const MHD_gnutls_cred_map MHD_gtls_cred_mappings[] = {
|
|
{MHD_GNUTLS_KX_RSA,
|
|
MHD_GNUTLS_CRD_CERTIFICATE,
|
|
MHD_GNUTLS_CRD_CERTIFICATE},
|
|
{MHD_GNUTLS_KX_RSA_EXPORT,
|
|
MHD_GNUTLS_CRD_CERTIFICATE,
|
|
MHD_GNUTLS_CRD_CERTIFICATE},
|
|
{MHD_GNUTLS_KX_DHE_DSS,
|
|
MHD_GNUTLS_CRD_CERTIFICATE,
|
|
MHD_GNUTLS_CRD_CERTIFICATE},
|
|
{MHD_GNUTLS_KX_DHE_RSA,
|
|
MHD_GNUTLS_CRD_CERTIFICATE,
|
|
MHD_GNUTLS_CRD_CERTIFICATE},
|
|
{0,
|
|
0,
|
|
0}
|
|
};
|
|
|
|
#define GNUTLS_KX_MAP_LOOP(b) \
|
|
const MHD_gnutls_cred_map *p; \
|
|
for(p = MHD_gtls_cred_mappings; p->algorithm != 0; p++) { b ; }
|
|
|
|
#define GNUTLS_KX_MAP_ALG_LOOP_SERVER(a) \
|
|
GNUTLS_KX_MAP_LOOP( if(p->server_type == type) { a; break; })
|
|
|
|
#define GNUTLS_KX_MAP_ALG_LOOP_CLIENT(a) \
|
|
GNUTLS_KX_MAP_LOOP( if(p->client_type == type) { a; break; })
|
|
|
|
/* KX mappings to PK algorithms */
|
|
typedef struct
|
|
{
|
|
enum MHD_GNUTLS_KeyExchangeAlgorithm kx_algorithm;
|
|
enum MHD_GNUTLS_PublicKeyAlgorithm pk_algorithm;
|
|
enum encipher_type encipher_type; /* CIPHER_ENCRYPT if this algorithm is to be used
|
|
* for encryption, CIPHER_SIGN if signature only,
|
|
* CIPHER_IGN if this does not apply at all.
|
|
*
|
|
* This is useful to certificate cipher suites, which check
|
|
* against the certificate key usage bits.
|
|
*/
|
|
} MHD_gnutls_pk_map;
|
|
|
|
/* This table maps the Key exchange algorithms to
|
|
* the certificate algorithms. Eg. if we have
|
|
* RSA algorithm in the certificate then we can
|
|
* use GNUTLS_KX_RSA or GNUTLS_KX_DHE_RSA.
|
|
*/
|
|
static const MHD_gnutls_pk_map MHD_gtls_pk_mappings[] = {
|
|
{MHD_GNUTLS_KX_RSA,
|
|
MHD_GNUTLS_PK_RSA,
|
|
CIPHER_ENCRYPT},
|
|
{MHD_GNUTLS_KX_RSA_EXPORT,
|
|
MHD_GNUTLS_PK_RSA,
|
|
CIPHER_SIGN},
|
|
{MHD_GNUTLS_KX_DHE_RSA,
|
|
MHD_GNUTLS_PK_RSA,
|
|
CIPHER_SIGN},
|
|
{MHD_GNUTLS_KX_SRP_RSA,
|
|
MHD_GNUTLS_PK_RSA,
|
|
CIPHER_SIGN},
|
|
{0,
|
|
0,
|
|
0}
|
|
};
|
|
|
|
#define GNUTLS_PK_MAP_LOOP(b) \
|
|
const MHD_gnutls_pk_map *p; \
|
|
for(p = MHD_gtls_pk_mappings; p->kx_algorithm != 0; p++) { b }
|
|
|
|
#define GNUTLS_PK_MAP_ALG_LOOP(a) \
|
|
GNUTLS_PK_MAP_LOOP( if(p->kx_algorithm == kx_algorithm) { a; break; })
|
|
|
|
/* TLS Versions */
|
|
|
|
typedef struct
|
|
{
|
|
const char *name;
|
|
enum MHD_GNUTLS_Protocol id; /* gnutls internal version number */
|
|
int major; /* defined by the protocol */
|
|
int minor; /* defined by the protocol */
|
|
int supported; /* 0 not supported, > 0 is supported */
|
|
} MHD_gnutls_version_entry;
|
|
|
|
static const MHD_gnutls_version_entry MHD_gtls_sup_versions[] = {
|
|
{"SSL3.0",
|
|
MHD_GNUTLS_PROTOCOL_SSL3,
|
|
3,
|
|
0,
|
|
1},
|
|
{"TLS1.0",
|
|
MHD_GNUTLS_PROTOCOL_TLS1_0,
|
|
3,
|
|
1,
|
|
1},
|
|
{"TLS1.1",
|
|
MHD_GNUTLS_PROTOCOL_TLS1_1,
|
|
3,
|
|
2,
|
|
1},
|
|
{"TLS1.2",
|
|
MHD_GNUTLS_PROTOCOL_TLS1_2,
|
|
3,
|
|
3,
|
|
1},
|
|
{0,
|
|
0,
|
|
0,
|
|
0,
|
|
0}
|
|
};
|
|
|
|
/* Keep the contents of this struct the same as the previous one. */
|
|
static const enum MHD_GNUTLS_Protocol MHD_gtls_supported_protocols[] =
|
|
{ MHD_GNUTLS_PROTOCOL_SSL3,
|
|
MHD_GNUTLS_PROTOCOL_TLS1_0,
|
|
MHD_GNUTLS_PROTOCOL_TLS1_1,
|
|
MHD_GNUTLS_PROTOCOL_TLS1_2,
|
|
0
|
|
};
|
|
|
|
#define GNUTLS_VERSION_LOOP(b) \
|
|
const MHD_gnutls_version_entry *p; \
|
|
for(p = MHD_gtls_sup_versions; p->name != NULL; p++) { b ; }
|
|
|
|
#define GNUTLS_VERSION_ALG_LOOP(a) \
|
|
GNUTLS_VERSION_LOOP( if(p->id == version) { a; break; })
|
|
|
|
struct MHD_gnutls_cipher_entry
|
|
{
|
|
const char *name;
|
|
enum MHD_GNUTLS_CipherAlgorithm id;
|
|
uint16_t blocksize;
|
|
uint16_t keysize;
|
|
cipher_type_t block;
|
|
uint16_t iv;
|
|
int export_flag; /* 0 non export */
|
|
};
|
|
typedef struct MHD_gnutls_cipher_entry MHD_gnutls_cipher_entry;
|
|
|
|
/* Note that all algorithms are in CBC or STREAM modes.
|
|
* Do not add any algorithms in other modes (avoid modified algorithms).
|
|
* View first: "The order of encryption and authentication for
|
|
* protecting communications" by Hugo Krawczyk - CRYPTO 2001
|
|
*/
|
|
static const MHD_gnutls_cipher_entry MHD_gtls_algorithms[] = {
|
|
{"AES-256-CBC",
|
|
MHD_GNUTLS_CIPHER_AES_256_CBC,
|
|
16,
|
|
32,
|
|
CIPHER_BLOCK,
|
|
16,
|
|
0},
|
|
{"AES-128-CBC",
|
|
MHD_GNUTLS_CIPHER_AES_128_CBC,
|
|
16,
|
|
16,
|
|
CIPHER_BLOCK,
|
|
16,
|
|
0},
|
|
{"3DES-CBC",
|
|
MHD_GNUTLS_CIPHER_3DES_CBC,
|
|
8,
|
|
24,
|
|
CIPHER_BLOCK,
|
|
8,
|
|
0},
|
|
{"DES-CBC",
|
|
MHD_GNUTLS_CIPHER_DES_CBC,
|
|
8,
|
|
8,
|
|
CIPHER_BLOCK,
|
|
8,
|
|
0},
|
|
{"ARCFOUR-128",
|
|
MHD_GNUTLS_CIPHER_ARCFOUR_128,
|
|
1,
|
|
16,
|
|
CIPHER_STREAM,
|
|
0,
|
|
0},
|
|
{"ARCFOUR-40",
|
|
MHD_GNUTLS_CIPHER_ARCFOUR_40,
|
|
1,
|
|
5,
|
|
CIPHER_STREAM,
|
|
0,
|
|
1},
|
|
{"RC2-40",
|
|
MHD_GNUTLS_CIPHER_RC2_40_CBC,
|
|
8,
|
|
5,
|
|
CIPHER_BLOCK,
|
|
8,
|
|
1},
|
|
{"NULL",
|
|
MHD_GNUTLS_CIPHER_NULL,
|
|
1,
|
|
0,
|
|
CIPHER_STREAM,
|
|
0,
|
|
0},
|
|
{0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0}
|
|
};
|
|
|
|
/* Keep the contents of this struct the same as the previous one. */
|
|
static const enum MHD_GNUTLS_CipherAlgorithm MHD_gtls_supported_ciphers[] =
|
|
{ MHD_GNUTLS_CIPHER_AES_256_CBC,
|
|
MHD_GNUTLS_CIPHER_AES_128_CBC,
|
|
MHD_GNUTLS_CIPHER_3DES_CBC,
|
|
MHD_GNUTLS_CIPHER_DES_CBC,
|
|
MHD_GNUTLS_CIPHER_ARCFOUR_128,
|
|
MHD_GNUTLS_CIPHER_ARCFOUR_40,
|
|
MHD_GNUTLS_CIPHER_RC2_40_CBC,
|
|
MHD_GNUTLS_CIPHER_NULL,
|
|
0
|
|
};
|
|
|
|
#define GNUTLS_LOOP(b) \
|
|
const MHD_gnutls_cipher_entry *p; \
|
|
for(p = MHD_gtls_algorithms; p->name != NULL; p++) { b ; }
|
|
|
|
#define GNUTLS_ALG_LOOP(a) \
|
|
GNUTLS_LOOP( if(p->id == algorithm) { a; break; } )
|
|
|
|
struct MHD_gnutls_hash_entry
|
|
{
|
|
const char *name;
|
|
const char *oid;
|
|
enum MHD_GNUTLS_HashAlgorithm id;
|
|
size_t key_size; /* in case of mac */
|
|
};
|
|
typedef struct MHD_gnutls_hash_entry MHD_gnutls_hash_entry;
|
|
|
|
static const MHD_gnutls_hash_entry MHD_gtls_hash_algorithms[] = {
|
|
{"SHA1",
|
|
HASH_OID_SHA1,
|
|
MHD_GNUTLS_MAC_SHA1,
|
|
20},
|
|
{"MD5",
|
|
HASH_OID_MD5,
|
|
MHD_GNUTLS_MAC_MD5,
|
|
16},
|
|
{"SHA256",
|
|
HASH_OID_SHA256,
|
|
MHD_GNUTLS_MAC_SHA256,
|
|
32},
|
|
{"NULL",
|
|
NULL,
|
|
MHD_GNUTLS_MAC_NULL,
|
|
0},
|
|
{0,
|
|
0,
|
|
0,
|
|
0}
|
|
};
|
|
|
|
/* Keep the contents of this struct the same as the previous one. */
|
|
static const enum MHD_GNUTLS_HashAlgorithm MHD_gtls_supported_macs[] =
|
|
{ MHD_GNUTLS_MAC_SHA1,
|
|
MHD_GNUTLS_MAC_MD5,
|
|
MHD_GNUTLS_MAC_SHA256,
|
|
MHD_GNUTLS_MAC_NULL,
|
|
0
|
|
};
|
|
|
|
#define GNUTLS_HASH_LOOP(b) \
|
|
const MHD_gnutls_hash_entry *p; \
|
|
for(p = MHD_gtls_hash_algorithms; p->name != NULL; p++) { b ; }
|
|
|
|
#define GNUTLS_HASH_ALG_LOOP(a) \
|
|
GNUTLS_HASH_LOOP( if(p->id == algorithm) { a; break; } )
|
|
|
|
/* Compression Section */
|
|
#define GNUTLS_COMPRESSION_ENTRY(name, id, wb, ml, cl) \
|
|
{ #name, name, id, wb, ml, cl}
|
|
|
|
#define MAX_COMP_METHODS 5
|
|
const int MHD__gnutls_comp_algorithms_size = MAX_COMP_METHODS;
|
|
|
|
/* the compression entry is defined in MHD_gnutls_algorithms.h */
|
|
|
|
MHD_gnutls_compression_entry
|
|
MHD__gnutls_compression_algorithms[MAX_COMP_METHODS] =
|
|
{ GNUTLS_COMPRESSION_ENTRY (MHD_GNUTLS_COMP_NULL, 0x00, 0, 0, 0),
|
|
#ifdef HAVE_LIBZ
|
|
/* draft-ietf-tls-compression-02 */
|
|
GNUTLS_COMPRESSION_ENTRY (MHD_GNUTLS_COMP_DEFLATE, 0x01, 15, 8, 3),
|
|
#endif
|
|
{0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0}
|
|
};
|
|
|
|
static const enum MHD_GNUTLS_CompressionMethod
|
|
MHD_gtls_supported_compressions[] =
|
|
{
|
|
#ifdef HAVE_LIBZ
|
|
MHD_GNUTLS_COMP_DEFLATE,
|
|
#endif
|
|
MHD_GNUTLS_COMP_NULL,
|
|
0
|
|
};
|
|
|
|
#define GNUTLS_COMPRESSION_LOOP(b) \
|
|
const MHD_gnutls_compression_entry *p; \
|
|
for(p = MHD__gnutls_compression_algorithms; p->name != NULL; p++) { b ; }
|
|
#define GNUTLS_COMPRESSION_ALG_LOOP(a) \
|
|
GNUTLS_COMPRESSION_LOOP( if(p->id == algorithm) { a; break; } )
|
|
#define GNUTLS_COMPRESSION_ALG_LOOP_NUM(a) \
|
|
GNUTLS_COMPRESSION_LOOP( if(p->num == num) { a; break; } )
|
|
|
|
/* Key Exchange Section */
|
|
extern MHD_gtls_mod_auth_st MHD_gtls_rsa_auth_struct;
|
|
extern MHD_gtls_mod_auth_st MHD_rsa_export_auth_struct;
|
|
extern MHD_gtls_mod_auth_st MHD_gtls_dhe_rsa_auth_struct;
|
|
extern MHD_gtls_mod_auth_st MHD_gtls_dhe_dss_auth_struct;
|
|
extern MHD_gtls_mod_auth_st srp_auth_struct;
|
|
extern MHD_gtls_mod_auth_st psk_auth_struct;
|
|
extern MHD_gtls_mod_auth_st dhe_psk_auth_struct;
|
|
extern MHD_gtls_mod_auth_st srp_rsa_auth_struct;
|
|
extern MHD_gtls_mod_auth_st srp_dss_auth_struct;
|
|
|
|
typedef struct MHD_gtls_kx_algo_entry
|
|
{
|
|
const char *name;
|
|
enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm;
|
|
MHD_gtls_mod_auth_st *auth_struct;
|
|
int needs_dh_params;
|
|
int needs_rsa_params;
|
|
} MHD_gtls_kx_algo_entry_t;
|
|
|
|
static const MHD_gtls_kx_algo_entry_t MHD_gtls_kx_algorithms[] = {
|
|
{"RSA",
|
|
MHD_GNUTLS_KX_RSA,
|
|
&MHD_gtls_rsa_auth_struct,
|
|
0,
|
|
0},
|
|
{"RSA-EXPORT",
|
|
MHD_GNUTLS_KX_RSA_EXPORT,
|
|
&MHD_rsa_export_auth_struct,
|
|
0,
|
|
1 /* needs RSA params */ },
|
|
{"DHE-RSA",
|
|
MHD_GNUTLS_KX_DHE_RSA,
|
|
&MHD_gtls_dhe_rsa_auth_struct,
|
|
1,
|
|
0},
|
|
{"DHE-DSS",
|
|
MHD_GNUTLS_KX_DHE_DSS,
|
|
&MHD_gtls_dhe_dss_auth_struct,
|
|
1,
|
|
0},
|
|
{0,
|
|
0,
|
|
0,
|
|
0,
|
|
0}
|
|
};
|
|
|
|
/* Keep the contents of this struct the same as the previous one. */
|
|
static const enum MHD_GNUTLS_KeyExchangeAlgorithm MHD_gtls_supported_kxs[] =
|
|
{
|
|
MHD_GNUTLS_KX_RSA,
|
|
MHD_GNUTLS_KX_RSA_EXPORT,
|
|
MHD_GNUTLS_KX_DHE_RSA,
|
|
MHD_GNUTLS_KX_DHE_DSS,
|
|
0
|
|
};
|
|
|
|
#define GNUTLS_KX_LOOP(b) \
|
|
const MHD_gtls_kx_algo_entry_t *p; \
|
|
for(p = MHD_gtls_kx_algorithms; p->name != NULL; p++) { b ; }
|
|
|
|
#define GNUTLS_KX_ALG_LOOP(a) \
|
|
GNUTLS_KX_LOOP( if(p->algorithm == algorithm) { a; break; } )
|
|
|
|
/* Cipher SUITES */
|
|
#define GNUTLS_CIPHER_SUITE_ENTRY( name, block_algorithm, kx_algorithm, mac_algorithm, version ) \
|
|
{ #name, {name}, block_algorithm, kx_algorithm, mac_algorithm, version }
|
|
|
|
typedef struct
|
|
{
|
|
const char *name;
|
|
cipher_suite_st id;
|
|
enum MHD_GNUTLS_CipherAlgorithm block_algorithm;
|
|
enum MHD_GNUTLS_KeyExchangeAlgorithm kx_algorithm;
|
|
enum MHD_GNUTLS_HashAlgorithm mac_algorithm;
|
|
enum MHD_GNUTLS_Protocol version; /* this cipher suite is supported
|
|
* from 'version' and above;
|
|
*/
|
|
} MHD_gtls_cipher_suite_entry;
|
|
|
|
/* RSA with NULL cipher and MD5 MAC
|
|
* for test purposes.
|
|
*/
|
|
#define GNUTLS_RSA_NULL_MD5 { 0x00, 0x01 }
|
|
|
|
/* PSK (not in TLS 1.0)
|
|
* draft-ietf-tls-psk:
|
|
*/
|
|
#define GNUTLS_PSK_SHA_ARCFOUR_SHA1 { 0x00, 0x8A }
|
|
#define GNUTLS_PSK_SHA_3DES_EDE_CBC_SHA1 { 0x00, 0x8B }
|
|
#define GNUTLS_PSK_SHA_AES_128_CBC_SHA1 { 0x00, 0x8C }
|
|
#define GNUTLS_PSK_SHA_AES_256_CBC_SHA1 { 0x00, 0x8D }
|
|
|
|
#define GNUTLS_DHE_PSK_SHA_ARCFOUR_SHA1 { 0x00, 0x8E }
|
|
#define GNUTLS_DHE_PSK_SHA_3DES_EDE_CBC_SHA1 { 0x00, 0x8F }
|
|
#define GNUTLS_DHE_PSK_SHA_AES_128_CBC_SHA1 { 0x00, 0x90 }
|
|
#define GNUTLS_DHE_PSK_SHA_AES_256_CBC_SHA1 { 0x00, 0x91 }
|
|
|
|
/* 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_SHA1 { 0x00, 0x05 }
|
|
#define GNUTLS_RSA_ARCFOUR_MD5 { 0x00, 0x04 }
|
|
#define GNUTLS_RSA_3DES_EDE_CBC_SHA1 { 0x00, 0x0A }
|
|
|
|
#define GNUTLS_RSA_EXPORT_ARCFOUR_40_MD5 { 0x00, 0x03 }
|
|
|
|
/* 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 }
|
|
|
|
/* DHE DSS
|
|
*/
|
|
|
|
#define GNUTLS_DHE_DSS_3DES_EDE_CBC_SHA1 { 0x00, 0x13 }
|
|
|
|
/* draft-ietf-tls-56-bit-ciphersuites-01:
|
|
*/
|
|
#define GNUTLS_DHE_DSS_ARCFOUR_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 }
|
|
|
|
/* 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 CIPHER_SUITES_COUNT sizeof(MHD_gtls_cs_algorithms)/sizeof(MHD_gtls_cipher_suite_entry)-1
|
|
|
|
static const MHD_gtls_cipher_suite_entry MHD_gtls_cs_algorithms[] = {
|
|
/* SRP */
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_SRP_SHA_3DES_EDE_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_3DES_CBC, MHD_GNUTLS_KX_SRP,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_TLS1_0),
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_SRP_SHA_AES_128_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_AES_128_CBC, MHD_GNUTLS_KX_SRP,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_TLS1_0),
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_SRP_SHA_AES_256_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_AES_256_CBC, MHD_GNUTLS_KX_SRP,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_TLS1_0),
|
|
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_SRP_SHA_DSS_3DES_EDE_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_3DES_CBC,
|
|
MHD_GNUTLS_KX_SRP_DSS,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_TLS1_0),
|
|
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_SRP_SHA_RSA_3DES_EDE_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_3DES_CBC,
|
|
MHD_GNUTLS_KX_SRP_RSA,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_TLS1_0),
|
|
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_SRP_SHA_DSS_AES_128_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_AES_128_CBC,
|
|
MHD_GNUTLS_KX_SRP_DSS,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_TLS1_0),
|
|
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_SRP_SHA_RSA_AES_128_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_AES_128_CBC,
|
|
MHD_GNUTLS_KX_SRP_RSA,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_TLS1_0),
|
|
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_SRP_SHA_DSS_AES_256_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_AES_256_CBC,
|
|
MHD_GNUTLS_KX_SRP_DSS,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_TLS1_0),
|
|
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_SRP_SHA_RSA_AES_256_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_AES_256_CBC,
|
|
MHD_GNUTLS_KX_SRP_RSA,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_TLS1_0),
|
|
|
|
/* DHE_DSS */
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_DHE_DSS_ARCFOUR_SHA1,
|
|
MHD_GNUTLS_CIPHER_ARCFOUR_128,
|
|
MHD_GNUTLS_KX_DHE_DSS,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_TLS1_0),
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_DHE_DSS_3DES_EDE_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_3DES_CBC,
|
|
MHD_GNUTLS_KX_DHE_DSS,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_SSL3),
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_DHE_DSS_AES_128_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_AES_128_CBC,
|
|
MHD_GNUTLS_KX_DHE_DSS,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_SSL3),
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_DHE_DSS_AES_256_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_AES_256_CBC,
|
|
MHD_GNUTLS_KX_DHE_DSS,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_SSL3),
|
|
/* DHE_RSA */
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_DHE_RSA_3DES_EDE_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_3DES_CBC,
|
|
MHD_GNUTLS_KX_DHE_RSA,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_SSL3),
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_DHE_RSA_AES_128_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_AES_128_CBC,
|
|
MHD_GNUTLS_KX_DHE_RSA,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_SSL3),
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_DHE_RSA_AES_256_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_AES_256_CBC,
|
|
MHD_GNUTLS_KX_DHE_RSA,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_SSL3),
|
|
/* RSA */
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_NULL_MD5,
|
|
MHD_GNUTLS_CIPHER_NULL,
|
|
MHD_GNUTLS_KX_RSA, MHD_GNUTLS_MAC_MD5,
|
|
MHD_GNUTLS_PROTOCOL_SSL3),
|
|
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_EXPORT_ARCFOUR_40_MD5,
|
|
MHD_GNUTLS_CIPHER_ARCFOUR_40,
|
|
MHD_GNUTLS_KX_RSA_EXPORT, MHD_GNUTLS_MAC_MD5,
|
|
MHD_GNUTLS_PROTOCOL_SSL3),
|
|
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_ARCFOUR_SHA1,
|
|
MHD_GNUTLS_CIPHER_ARCFOUR_128,
|
|
MHD_GNUTLS_KX_RSA, MHD_GNUTLS_MAC_SHA1,
|
|
MHD_GNUTLS_PROTOCOL_SSL3),
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_ARCFOUR_MD5,
|
|
MHD_GNUTLS_CIPHER_ARCFOUR_128,
|
|
MHD_GNUTLS_KX_RSA, MHD_GNUTLS_MAC_MD5,
|
|
MHD_GNUTLS_PROTOCOL_SSL3),
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_3DES_EDE_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_3DES_CBC,
|
|
MHD_GNUTLS_KX_RSA, MHD_GNUTLS_MAC_SHA1,
|
|
MHD_GNUTLS_PROTOCOL_SSL3),
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_AES_128_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_AES_128_CBC, MHD_GNUTLS_KX_RSA,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_SSL3),
|
|
GNUTLS_CIPHER_SUITE_ENTRY (GNUTLS_RSA_AES_256_CBC_SHA1,
|
|
MHD_GNUTLS_CIPHER_AES_256_CBC, MHD_GNUTLS_KX_RSA,
|
|
MHD_GNUTLS_MAC_SHA1, MHD_GNUTLS_PROTOCOL_SSL3),
|
|
{0,
|
|
{
|
|
{0,
|
|
0}},
|
|
0,
|
|
0,
|
|
0,
|
|
0}
|
|
};
|
|
|
|
#define GNUTLS_CIPHER_SUITE_LOOP(b) \
|
|
const MHD_gtls_cipher_suite_entry *p; \
|
|
for(p = MHD_gtls_cs_algorithms; p->name != NULL; p++) { b ; }
|
|
|
|
#define GNUTLS_CIPHER_SUITE_ALG_LOOP(a) \
|
|
GNUTLS_CIPHER_SUITE_LOOP( if( (p->id.suite[0] == suite->suite[0]) && (p->id.suite[1] == suite->suite[1])) { a; break; } )
|
|
|
|
/* Generic Functions */
|
|
|
|
int
|
|
MHD_gtls_mac_priority (MHD_gtls_session_t session,
|
|
enum MHD_GNUTLS_HashAlgorithm algorithm)
|
|
{ /* actually returns the priority */
|
|
unsigned int i;
|
|
for (i = 0; i < session->internals.priorities.mac.num_algorithms; i++)
|
|
{
|
|
if (session->internals.priorities.mac.priority[i] == algorithm)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
int
|
|
MHD_gnutls_mac_is_ok (enum MHD_GNUTLS_HashAlgorithm algorithm)
|
|
{
|
|
ssize_t ret = -1;
|
|
GNUTLS_HASH_ALG_LOOP (ret = p->id);
|
|
if (ret >= 0)
|
|
ret = 0;
|
|
else
|
|
ret = 1;
|
|
return ret;
|
|
}
|
|
|
|
|
|
/**
|
|
* MHD__gnutls_compression_get_name - Returns a string with the name of the specified compression algorithm
|
|
* @algorithm: is a Compression algorithm
|
|
*
|
|
* Returns: a pointer to a string that contains the name of the
|
|
* specified compression algorithm, or %NULL.
|
|
**/
|
|
const char *
|
|
MHD_gtls_compression_get_name (enum MHD_GNUTLS_CompressionMethod algorithm)
|
|
{
|
|
const char *ret = NULL;
|
|
|
|
/* avoid prefix */
|
|
GNUTLS_COMPRESSION_ALG_LOOP (ret = p->name + sizeof ("GNUTLS_COMP_") - 1);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* MHD_gtls_compression_get_id - Returns the gnutls id of the specified in string algorithm
|
|
* @algorithm: is a compression method name
|
|
*
|
|
* The names are compared in a case insensitive way.
|
|
*
|
|
* Returns: an id of the specified in a string compression method, or
|
|
* %GNUTLS_COMP_UNKNOWN on error.
|
|
*
|
|
**/
|
|
enum MHD_GNUTLS_CompressionMethod
|
|
MHD_gtls_compression_get_id (const char *name)
|
|
{
|
|
enum MHD_GNUTLS_CompressionMethod ret = MHD_GNUTLS_COMP_UNKNOWN;
|
|
|
|
GNUTLS_COMPRESSION_LOOP (if
|
|
(strcasecmp
|
|
(p->name + sizeof ("GNUTLS_COMP_") - 1,
|
|
name) == 0) ret = p->id)
|
|
;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* return the tls number of the specified algorithm */
|
|
int
|
|
MHD_gtls_compression_get_num (enum MHD_GNUTLS_CompressionMethod algorithm)
|
|
{
|
|
int ret = -1;
|
|
|
|
/* avoid prefix */
|
|
GNUTLS_COMPRESSION_ALG_LOOP (ret = p->num);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
MHD_gtls_compression_get_wbits (enum MHD_GNUTLS_CompressionMethod algorithm)
|
|
{
|
|
int ret = -1;
|
|
/* avoid prefix */
|
|
GNUTLS_COMPRESSION_ALG_LOOP (ret = p->window_bits);
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
MHD_gtls_compression_get_mem_level (enum MHD_GNUTLS_CompressionMethod
|
|
algorithm)
|
|
{
|
|
int ret = -1;
|
|
/* avoid prefix */
|
|
GNUTLS_COMPRESSION_ALG_LOOP (ret = p->mem_level);
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
MHD_gtls_compression_get_comp_level (enum MHD_GNUTLS_CompressionMethod
|
|
algorithm)
|
|
{
|
|
int ret = -1;
|
|
/* avoid prefix */
|
|
GNUTLS_COMPRESSION_ALG_LOOP (ret = p->comp_level);
|
|
return ret;
|
|
}
|
|
|
|
/* returns the gnutls internal ID of the TLS compression
|
|
* method num
|
|
*/
|
|
enum MHD_GNUTLS_CompressionMethod
|
|
MHD_gtls_compression_get_id_from_int (int num)
|
|
{
|
|
enum MHD_GNUTLS_CompressionMethod ret = -1;
|
|
|
|
/* avoid prefix */
|
|
GNUTLS_COMPRESSION_ALG_LOOP_NUM (ret = p->id);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
MHD_gtls_compression_is_ok (enum MHD_GNUTLS_CompressionMethod algorithm)
|
|
{
|
|
ssize_t ret = -1;
|
|
GNUTLS_COMPRESSION_ALG_LOOP (ret = p->id);
|
|
if (ret >= 0)
|
|
ret = 0;
|
|
else
|
|
ret = 1;
|
|
return ret;
|
|
}
|
|
|
|
/* CIPHER functions */
|
|
int
|
|
MHD_gtls_cipher_get_block_size (enum MHD_GNUTLS_CipherAlgorithm algorithm)
|
|
{
|
|
size_t ret = 0;
|
|
GNUTLS_ALG_LOOP (ret = p->blocksize);
|
|
return ret;
|
|
|
|
}
|
|
|
|
/* returns the priority */
|
|
int
|
|
MHD_gtls_cipher_priority (MHD_gtls_session_t session,
|
|
enum MHD_GNUTLS_CipherAlgorithm algorithm)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < session->internals.priorities.cipher.num_algorithms; i++)
|
|
{
|
|
if (session->internals.priorities.cipher.priority[i] == algorithm)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int
|
|
MHD_gtls_cipher_is_block (enum MHD_GNUTLS_CipherAlgorithm algorithm)
|
|
{
|
|
size_t ret = 0;
|
|
|
|
GNUTLS_ALG_LOOP (ret = p->block);
|
|
return ret;
|
|
|
|
}
|
|
|
|
/**
|
|
* MHD__gnutls_cipher_get_key_size - Returns the length of the cipher's key size
|
|
* @algorithm: is an encryption algorithm
|
|
*
|
|
* Returns: length (in bytes) of the given cipher's key size, o 0 if
|
|
* the given cipher is invalid.
|
|
**/
|
|
size_t
|
|
MHD__gnutls_cipher_get_key_size (enum MHD_GNUTLS_CipherAlgorithm algorithm)
|
|
{ /* In bytes */
|
|
size_t ret = 0;
|
|
GNUTLS_ALG_LOOP (ret = p->keysize);
|
|
return ret;
|
|
|
|
}
|
|
|
|
int
|
|
MHD_gtls_cipher_get_iv_size (enum MHD_GNUTLS_CipherAlgorithm algorithm)
|
|
{ /* In bytes */
|
|
size_t ret = 0;
|
|
GNUTLS_ALG_LOOP (ret = p->iv);
|
|
return ret;
|
|
|
|
}
|
|
|
|
int
|
|
MHD_gtls_cipher_get_export_flag (enum MHD_GNUTLS_CipherAlgorithm algorithm)
|
|
{ /* In bytes */
|
|
size_t ret = 0;
|
|
GNUTLS_ALG_LOOP (ret = p->export_flag);
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
int
|
|
MHD_gtls_cipher_is_ok (enum MHD_GNUTLS_CipherAlgorithm algorithm)
|
|
{
|
|
ssize_t ret = -1;
|
|
GNUTLS_ALG_LOOP (ret = p->id);
|
|
if (ret >= 0)
|
|
ret = 0;
|
|
else
|
|
ret = 1;
|
|
return ret;
|
|
}
|
|
|
|
/* Key EXCHANGE functions */
|
|
MHD_gtls_mod_auth_st *
|
|
MHD_gtls_kx_auth_struct (enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm)
|
|
{
|
|
MHD_gtls_mod_auth_st *ret = NULL;
|
|
GNUTLS_KX_ALG_LOOP (ret = p->auth_struct);
|
|
return ret;
|
|
|
|
}
|
|
|
|
int
|
|
MHD_gtls_kx_priority (MHD_gtls_session_t session,
|
|
enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < session->internals.priorities.kx.num_algorithms; i++)
|
|
{
|
|
if (session->internals.priorities.kx.priority[i] == algorithm)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
int
|
|
MHD_gtls_kx_is_ok (enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm)
|
|
{
|
|
ssize_t ret = -1;
|
|
GNUTLS_KX_ALG_LOOP (ret = p->algorithm);
|
|
if (ret >= 0)
|
|
ret = 0;
|
|
else
|
|
ret = 1;
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
MHD_gtls_kx_needs_rsa_params (enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm)
|
|
{
|
|
ssize_t ret = 0;
|
|
GNUTLS_KX_ALG_LOOP (ret = p->needs_rsa_params);
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
MHD_gtls_kx_needs_dh_params (enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm)
|
|
{
|
|
ssize_t ret = 0;
|
|
GNUTLS_KX_ALG_LOOP (ret = p->needs_dh_params);
|
|
return ret;
|
|
}
|
|
|
|
/* Version */
|
|
int
|
|
MHD_gtls_version_priority (MHD_gtls_session_t session,
|
|
enum MHD_GNUTLS_Protocol version)
|
|
{ /* actually returns the priority */
|
|
unsigned int i;
|
|
|
|
if (session->internals.priorities.protocol.priority == NULL)
|
|
{
|
|
MHD_gnutls_assert ();
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < session->internals.priorities.protocol.num_algorithms; i++)
|
|
{
|
|
if (session->internals.priorities.protocol.priority[i] == version)
|
|
return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
enum MHD_GNUTLS_Protocol
|
|
MHD_gtls_version_max (MHD_gtls_session_t session)
|
|
{ /* returns the maximum version supported */
|
|
unsigned int i, max = 0x00;
|
|
|
|
if (session->internals.priorities.protocol.priority == NULL)
|
|
{
|
|
return MHD_GNUTLS_PROTOCOL_VERSION_UNKNOWN;
|
|
}
|
|
else
|
|
for (i = 0; i < session->internals.priorities.protocol.num_algorithms;
|
|
i++)
|
|
{
|
|
if (session->internals.priorities.protocol.priority[i] > max)
|
|
max = session->internals.priorities.protocol.priority[i];
|
|
}
|
|
|
|
if (max == 0x00)
|
|
return MHD_GNUTLS_PROTOCOL_VERSION_UNKNOWN; /* unknown version */
|
|
|
|
return max;
|
|
}
|
|
|
|
int
|
|
MHD_gtls_version_get_minor (enum MHD_GNUTLS_Protocol version)
|
|
{
|
|
int ret = -1;
|
|
|
|
GNUTLS_VERSION_ALG_LOOP (ret = p->minor);
|
|
return ret;
|
|
}
|
|
|
|
enum MHD_GNUTLS_Protocol
|
|
MHD_gtls_version_get (int major, int minor)
|
|
{
|
|
int ret = -1;
|
|
|
|
GNUTLS_VERSION_LOOP (if ((p->major == major) && (p->minor == minor))
|
|
ret = p->id)
|
|
;
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
MHD_gtls_version_get_major (enum MHD_GNUTLS_Protocol version)
|
|
{
|
|
int ret = -1;
|
|
|
|
GNUTLS_VERSION_ALG_LOOP (ret = p->major);
|
|
return ret;
|
|
}
|
|
|
|
/* Version Functions */
|
|
|
|
int
|
|
MHD_gtls_version_is_supported (MHD_gtls_session_t session,
|
|
const enum MHD_GNUTLS_Protocol version)
|
|
{
|
|
int ret = 0;
|
|
|
|
GNUTLS_VERSION_ALG_LOOP (ret = p->supported);
|
|
if (ret == 0)
|
|
return 0;
|
|
|
|
if (MHD_gtls_version_priority (session, version) < 0)
|
|
return 0; /* disabled by the user */
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
enum MHD_GNUTLS_CredentialsType
|
|
MHD_gtls_map_kx_get_cred (enum MHD_GNUTLS_KeyExchangeAlgorithm algorithm,
|
|
int server)
|
|
{
|
|
enum MHD_GNUTLS_CredentialsType ret = -1;
|
|
if (server)
|
|
{
|
|
GNUTLS_KX_MAP_LOOP (if (p->algorithm == algorithm) ret = p->server_type)
|
|
;
|
|
}
|
|
else
|
|
{
|
|
GNUTLS_KX_MAP_LOOP (if (p->algorithm == algorithm) ret = p->client_type)
|
|
;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* Cipher Suite's functions */
|
|
enum MHD_GNUTLS_CipherAlgorithm
|
|
MHD_gtls_cipher_suite_get_cipher_algo (const cipher_suite_st * suite)
|
|
{
|
|
int ret = 0;
|
|
GNUTLS_CIPHER_SUITE_ALG_LOOP (ret = p->block_algorithm);
|
|
return ret;
|
|
}
|
|
|
|
enum MHD_GNUTLS_Protocol
|
|
MHD_gtls_cipher_suite_get_version (const cipher_suite_st * suite)
|
|
{
|
|
int ret = 0;
|
|
GNUTLS_CIPHER_SUITE_ALG_LOOP (ret = p->version);
|
|
return ret;
|
|
}
|
|
|
|
enum MHD_GNUTLS_KeyExchangeAlgorithm
|
|
MHD_gtls_cipher_suite_get_kx_algo (const cipher_suite_st * suite)
|
|
{
|
|
int ret = 0;
|
|
|
|
GNUTLS_CIPHER_SUITE_ALG_LOOP (ret = p->kx_algorithm);
|
|
return ret;
|
|
|
|
}
|
|
|
|
enum MHD_GNUTLS_HashAlgorithm
|
|
MHD_gtls_cipher_suite_get_mac_algo (const cipher_suite_st * suite)
|
|
{ /* In bytes */
|
|
int ret = 0;
|
|
GNUTLS_CIPHER_SUITE_ALG_LOOP (ret = p->mac_algorithm);
|
|
return ret;
|
|
|
|
}
|
|
|
|
const char *
|
|
MHD_gtls_cipher_suite_get_name (cipher_suite_st * suite)
|
|
{
|
|
const char *ret = NULL;
|
|
|
|
/* avoid prefix */
|
|
GNUTLS_CIPHER_SUITE_ALG_LOOP (ret = p->name + sizeof ("GNUTLS_") - 1);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static inline int
|
|
MHD__gnutls_cipher_suite_is_ok (cipher_suite_st * suite)
|
|
{
|
|
size_t ret;
|
|
const char *name = NULL;
|
|
|
|
GNUTLS_CIPHER_SUITE_ALG_LOOP (name = p->name);
|
|
if (name != NULL)
|
|
ret = 0;
|
|
else
|
|
ret = 1;
|
|
return ret;
|
|
|
|
}
|
|
|
|
#define SWAP(x, y) memcpy(tmp,x,size); \
|
|
memcpy(x,y,size); \
|
|
memcpy(y,tmp,size);
|
|
|
|
#define MAX_ELEM_SIZE 4
|
|
static inline int
|
|
MHD__gnutls_partition (MHD_gtls_session_t session,
|
|
void *_base,
|
|
size_t nmemb,
|
|
size_t size,
|
|
int (*compar) (MHD_gtls_session_t,
|
|
const void *, const void *))
|
|
{
|
|
uint8_t *base = _base;
|
|
uint8_t tmp[MAX_ELEM_SIZE];
|
|
uint8_t ptmp[MAX_ELEM_SIZE];
|
|
unsigned int pivot;
|
|
unsigned int i, j;
|
|
unsigned int full;
|
|
|
|
i = pivot = 0;
|
|
j = full = (nmemb - 1) * size;
|
|
|
|
memcpy (ptmp, &base[0], size); /* set pivot item */
|
|
|
|
while (i < j)
|
|
{
|
|
while ((compar (session, &base[i], ptmp) <= 0) && (i < full))
|
|
{
|
|
i += size;
|
|
}
|
|
while ((compar (session, &base[j], ptmp) >= 0) && (j > 0))
|
|
j -= size;
|
|
|
|
if (i < j)
|
|
{
|
|
SWAP (&base[j], &base[i]);
|
|
}
|
|
}
|
|
|
|
if (j > pivot)
|
|
{
|
|
SWAP (&base[pivot], &base[j]);
|
|
pivot = j;
|
|
}
|
|
else if (i < pivot)
|
|
{
|
|
SWAP (&base[pivot], &base[i]);
|
|
pivot = i;
|
|
}
|
|
return pivot / size;
|
|
}
|
|
|
|
static void
|
|
MHD__gnutls_qsort (MHD_gtls_session_t session,
|
|
void *_base,
|
|
size_t nmemb,
|
|
size_t size,
|
|
int (*compar) (MHD_gtls_session_t, const void *,
|
|
const void *))
|
|
{
|
|
unsigned int pivot;
|
|
char *base = _base;
|
|
size_t snmemb = nmemb;
|
|
|
|
if (snmemb <= 1)
|
|
return;
|
|
pivot = MHD__gnutls_partition (session, _base, nmemb, size, compar);
|
|
|
|
MHD__gnutls_qsort (session, base, pivot < nmemb ? pivot + 1
|
|
: pivot, size, compar);
|
|
MHD__gnutls_qsort (session, &base[(pivot + 1) * size], nmemb - pivot - 1,
|
|
size, compar);
|
|
}
|
|
|
|
/* a compare function for KX algorithms (using priorities).
|
|
* For use with qsort
|
|
*/
|
|
static int
|
|
MHD__gnutls_compare_algo (MHD_gtls_session_t session,
|
|
const void *i_A1, const void *i_A2)
|
|
{
|
|
enum MHD_GNUTLS_KeyExchangeAlgorithm kA1 =
|
|
MHD_gtls_cipher_suite_get_kx_algo ((const cipher_suite_st *) i_A1);
|
|
enum MHD_GNUTLS_KeyExchangeAlgorithm kA2 =
|
|
MHD_gtls_cipher_suite_get_kx_algo ((const cipher_suite_st *) i_A2);
|
|
enum MHD_GNUTLS_CipherAlgorithm cA1 =
|
|
MHD_gtls_cipher_suite_get_cipher_algo ((const cipher_suite_st *) i_A1);
|
|
enum MHD_GNUTLS_CipherAlgorithm cA2 =
|
|
MHD_gtls_cipher_suite_get_cipher_algo ((const cipher_suite_st *) i_A2);
|
|
enum MHD_GNUTLS_HashAlgorithm mA1 =
|
|
MHD_gtls_cipher_suite_get_mac_algo ((const cipher_suite_st *) i_A1);
|
|
enum MHD_GNUTLS_HashAlgorithm mA2 =
|
|
MHD_gtls_cipher_suite_get_mac_algo ((const cipher_suite_st *) i_A2);
|
|
|
|
int p1 = (MHD_gtls_kx_priority (session, kA1) + 1) * 64;
|
|
int p2 = (MHD_gtls_kx_priority (session, kA2) + 1) * 64;
|
|
p1 += (MHD_gtls_cipher_priority (session, cA1) + 1) * 8;
|
|
p2 += (MHD_gtls_cipher_priority (session, cA2) + 1) * 8;
|
|
p1 += MHD_gtls_mac_priority (session, mA1);
|
|
p2 += MHD_gtls_mac_priority (session, mA2);
|
|
|
|
if (p1 > p2)
|
|
{
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
if (p1 == p2)
|
|
{
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
int
|
|
MHD_gtls_supported_ciphersuites_sorted (MHD_gtls_session_t session,
|
|
cipher_suite_st ** ciphers)
|
|
{
|
|
|
|
int count;
|
|
|
|
count = MHD_gtls_supported_ciphersuites (session, ciphers);
|
|
if (count <= 0)
|
|
{
|
|
MHD_gnutls_assert ();
|
|
return count;
|
|
}
|
|
MHD__gnutls_qsort (session, *ciphers, count, sizeof (cipher_suite_st),
|
|
MHD__gnutls_compare_algo);
|
|
|
|
return count;
|
|
}
|
|
|
|
int
|
|
MHD_gtls_supported_ciphersuites (MHD_gtls_session_t session,
|
|
cipher_suite_st ** _ciphers)
|
|
{
|
|
|
|
unsigned int i, ret_count, j;
|
|
unsigned int count = CIPHER_SUITES_COUNT;
|
|
cipher_suite_st *tmp_ciphers;
|
|
cipher_suite_st *ciphers;
|
|
enum MHD_GNUTLS_Protocol version;
|
|
|
|
if (count == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
tmp_ciphers = MHD_gnutls_alloca (count * sizeof (cipher_suite_st));
|
|
if (tmp_ciphers == NULL)
|
|
return GNUTLS_E_MEMORY_ERROR;
|
|
|
|
ciphers = MHD_gnutls_malloc (count * sizeof (cipher_suite_st));
|
|
if (ciphers == NULL)
|
|
{
|
|
MHD_gnutls_afree (tmp_ciphers);
|
|
return GNUTLS_E_MEMORY_ERROR;
|
|
}
|
|
|
|
version = MHD__gnutls_protocol_get_version (session);
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
memcpy (&tmp_ciphers[i], &MHD_gtls_cs_algorithms[i].id,
|
|
sizeof (cipher_suite_st));
|
|
}
|
|
|
|
for (i = j = 0; i < count; i++)
|
|
{
|
|
/* remove private cipher suites, if requested.
|
|
*/
|
|
if (tmp_ciphers[i].suite[0] == 0xFF && session->internals.enable_private
|
|
== 0)
|
|
continue;
|
|
|
|
/* remove cipher suites which do not support the
|
|
* protocol version used.
|
|
*/
|
|
if (MHD_gtls_cipher_suite_get_version (&tmp_ciphers[i]) > version)
|
|
continue;
|
|
|
|
if (MHD_gtls_kx_priority (session,
|
|
MHD_gtls_cipher_suite_get_kx_algo
|
|
(&tmp_ciphers[i])) < 0)
|
|
continue;
|
|
if (MHD_gtls_mac_priority (session,
|
|
MHD_gtls_cipher_suite_get_mac_algo
|
|
(&tmp_ciphers[i])) < 0)
|
|
continue;
|
|
if (MHD_gtls_cipher_priority (session,
|
|
MHD_gtls_cipher_suite_get_cipher_algo
|
|
(&tmp_ciphers[i])) < 0)
|
|
continue;
|
|
|
|
memcpy (&ciphers[j], &tmp_ciphers[i], sizeof (cipher_suite_st));
|
|
j++;
|
|
}
|
|
|
|
ret_count = j;
|
|
|
|
#if 0 /* expensive */
|
|
if (ret_count > 0 && ret_count != count)
|
|
{
|
|
ciphers =
|
|
MHD_gtls_realloc_fast (ciphers, ret_count * sizeof (cipher_suite_st));
|
|
}
|
|
else
|
|
{
|
|
if (ret_count != count)
|
|
{
|
|
MHD_gnutls_free (ciphers);
|
|
ciphers = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
MHD_gnutls_afree (tmp_ciphers);
|
|
|
|
/* This function can no longer return 0 cipher suites.
|
|
* It returns an error code instead.
|
|
*/
|
|
if (ret_count == 0)
|
|
{
|
|
MHD_gnutls_assert ();
|
|
MHD_gnutls_free (ciphers);
|
|
return GNUTLS_E_NO_CIPHER_SUITES;
|
|
}
|
|
*_ciphers = ciphers;
|
|
return ret_count;
|
|
}
|
|
|
|
/* For compression */
|
|
|
|
#define MIN_PRIVATE_COMP_ALGO 0xEF
|
|
|
|
/* returns the TLS numbers of the compression methods we support
|
|
*/
|
|
#define SUPPORTED_COMPRESSION_METHODS session->internals.priorities.compression.num_algorithms
|
|
int
|
|
MHD_gtls_supported_compression_methods (MHD_gtls_session_t session,
|
|
uint8_t ** comp)
|
|
{
|
|
unsigned int i, j;
|
|
|
|
*comp =
|
|
MHD_gnutls_malloc (sizeof (uint8_t) * SUPPORTED_COMPRESSION_METHODS);
|
|
if (*comp == NULL)
|
|
return GNUTLS_E_MEMORY_ERROR;
|
|
|
|
for (i = j = 0; i < SUPPORTED_COMPRESSION_METHODS; i++)
|
|
{
|
|
int tmp =
|
|
MHD_gtls_compression_get_num (session->internals.
|
|
priorities.compression.priority[i]);
|
|
|
|
/* remove private compression algorithms, if requested.
|
|
*/
|
|
if (tmp == -1 || (tmp >= MIN_PRIVATE_COMP_ALGO
|
|
&& session->internals.enable_private == 0))
|
|
{
|
|
MHD_gnutls_assert ();
|
|
continue;
|
|
}
|
|
|
|
(*comp)[j] = (uint8_t) tmp;
|
|
j++;
|
|
}
|
|
|
|
if (j == 0)
|
|
{
|
|
MHD_gnutls_assert ();
|
|
MHD_gnutls_free (*comp);
|
|
*comp = NULL;
|
|
return GNUTLS_E_NO_COMPRESSION_ALGORITHMS;
|
|
}
|
|
return j;
|
|
}
|
|
|
|
static const enum MHD_GNUTLS_CertificateType
|
|
MHD_gtls_supported_certificate_types[] =
|
|
{ MHD_GNUTLS_CRT_X509,
|
|
0
|
|
};
|
|
|
|
|
|
/* returns the enum MHD_GNUTLS_PublicKeyAlgorithm which is compatible with
|
|
* the given enum MHD_GNUTLS_KeyExchangeAlgorithm.
|
|
*/
|
|
enum MHD_GNUTLS_PublicKeyAlgorithm
|
|
MHD_gtls_map_pk_get_pk (enum MHD_GNUTLS_KeyExchangeAlgorithm kx_algorithm)
|
|
{
|
|
enum MHD_GNUTLS_PublicKeyAlgorithm ret = -1;
|
|
|
|
GNUTLS_PK_MAP_ALG_LOOP (ret = p->pk_algorithm) return ret;
|
|
}
|
|
|
|
/* Returns the encipher type for the given key exchange algorithm.
|
|
* That one of CIPHER_ENCRYPT, CIPHER_SIGN, CIPHER_IGN.
|
|
*
|
|
* ex. GNUTLS_KX_RSA requires a certificate able to encrypt... so returns CIPHER_ENCRYPT.
|
|
*/
|
|
enum encipher_type
|
|
MHD_gtls_kx_encipher_type (enum MHD_GNUTLS_KeyExchangeAlgorithm kx_algorithm)
|
|
{
|
|
int ret = CIPHER_IGN;
|
|
GNUTLS_PK_MAP_ALG_LOOP (ret = p->encipher_type) return ret;
|
|
|
|
}
|
|
|
|
/* signature algorithms;
|
|
*/
|
|
struct MHD_gnutls_sign_entry
|
|
{
|
|
const char *name;
|
|
const char *oid;
|
|
MHD_gnutls_sign_algorithm_t id;
|
|
enum MHD_GNUTLS_PublicKeyAlgorithm pk;
|
|
enum MHD_GNUTLS_HashAlgorithm mac;
|
|
};
|
|
typedef struct MHD_gnutls_sign_entry MHD_gnutls_sign_entry;
|
|
|
|
static const MHD_gnutls_sign_entry MHD_gtls_sign_algorithms[] = {
|
|
{"RSA-SHA",
|
|
SIG_RSA_SHA1_OID,
|
|
GNUTLS_SIGN_RSA_SHA1,
|
|
MHD_GNUTLS_PK_RSA,
|
|
MHD_GNUTLS_MAC_SHA1},
|
|
{"RSA-SHA256",
|
|
SIG_RSA_SHA256_OID,
|
|
GNUTLS_SIGN_RSA_SHA256,
|
|
MHD_GNUTLS_PK_RSA,
|
|
MHD_GNUTLS_MAC_SHA256},
|
|
{"RSA-MD5",
|
|
SIG_RSA_MD5_OID,
|
|
GNUTLS_SIGN_RSA_MD5,
|
|
MHD_GNUTLS_PK_RSA,
|
|
MHD_GNUTLS_MAC_MD5},
|
|
{"GOST R 34.10-2001",
|
|
SIG_GOST_R3410_2001_OID,
|
|
0,
|
|
0,
|
|
0},
|
|
{"GOST R 34.10-94",
|
|
SIG_GOST_R3410_94_OID,
|
|
0,
|
|
0,
|
|
0},
|
|
{0,
|
|
0,
|
|
0,
|
|
0,
|
|
0}
|
|
};
|
|
|
|
#define GNUTLS_SIGN_LOOP(b) \
|
|
do { \
|
|
const MHD_gnutls_sign_entry *p; \
|
|
for(p = MHD_gtls_sign_algorithms; p->name != NULL; p++) { b ; } \
|
|
} while (0)
|
|
|
|
#define GNUTLS_SIGN_ALG_LOOP(a) \
|
|
GNUTLS_SIGN_LOOP( if(p->id && p->id == sign) { a; break; } )
|
|
|
|
/* pk algorithms;
|
|
*/
|
|
struct MHD_gnutls_pk_entry
|
|
{
|
|
const char *name;
|
|
const char *oid;
|
|
enum MHD_GNUTLS_PublicKeyAlgorithm id;
|
|
};
|
|
typedef struct MHD_gnutls_pk_entry MHD_gnutls_pk_entry;
|
|
|
|
static const MHD_gnutls_pk_entry MHD_gtls_pk_algorithms[] = {
|
|
{"RSA",
|
|
PK_PKIX1_RSA_OID,
|
|
MHD_GNUTLS_PK_RSA},
|
|
{"GOST R 34.10-2001",
|
|
PK_GOST_R3410_2001_OID,
|
|
0},
|
|
{"GOST R 34.10-94",
|
|
PK_GOST_R3410_94_OID,
|
|
0},
|
|
{0,
|
|
0,
|
|
0}
|
|
};
|
|
|
|
enum MHD_GNUTLS_PublicKeyAlgorithm
|
|
MHD_gtls_x509_oid2pk_algorithm (const char *oid)
|
|
{
|
|
enum MHD_GNUTLS_PublicKeyAlgorithm ret = MHD_GNUTLS_PK_UNKNOWN;
|
|
const MHD_gnutls_pk_entry *p;
|
|
|
|
for (p = MHD_gtls_pk_algorithms; p->name != NULL; p++)
|
|
if (strcmp (p->oid, oid) == 0)
|
|
{
|
|
ret = p->id;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|