#include "sslBuildFlags.h"
#include "sslContext.h"
#include "sslCipherSpecs.h"
#include "sslDebug.h"
#include "sslMemory.h"
#include "sslDebug.h"
#include "sslUtils.h"
#include "sslPriv.h"
#include <tls_handshake.h>
#include <string.h>
#include <assert.h>
#include <Security/SecBase.h>
#include <TargetConditionals.h>
#define ENABLE_ECDH 1
#define ENABLE_AES_GCM 1
#define ENABLE_PSK 1
static const uint16_t STKnownCipherSuites[] = {
#if ENABLE_AES_GCM
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
#endif
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
#if ENABLE_AES_GCM
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
#endif
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
#if ENABLE_ECDH
#if ENABLE_AES_GCM
TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
#endif
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
#if ENABLE_AES_GCM
TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
#endif
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
#endif
#if ENABLE_AES_GCM
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
#endif // ENABLE_AES_GCM
TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,
TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,
TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA,
#if ENABLE_AES_GCM
TLS_RSA_WITH_AES_256_GCM_SHA384,
TLS_RSA_WITH_AES_128_GCM_SHA256,
#endif
TLS_RSA_WITH_AES_256_CBC_SHA256,
TLS_RSA_WITH_AES_128_CBC_SHA256,
TLS_RSA_WITH_AES_256_CBC_SHA,
TLS_RSA_WITH_AES_128_CBC_SHA,
SSL_RSA_WITH_3DES_EDE_CBC_SHA,
#if ENABLE_RC4
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
TLS_ECDHE_RSA_WITH_RC4_128_SHA,
TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
TLS_ECDH_RSA_WITH_RC4_128_SHA,
SSL_RSA_WITH_RC4_128_SHA,
SSL_RSA_WITH_RC4_128_MD5,
#endif
#if ENABLE_AES_GCM
TLS_DH_anon_WITH_AES_256_GCM_SHA384,
TLS_DH_anon_WITH_AES_128_GCM_SHA256,
#endif
TLS_DH_anon_WITH_AES_128_CBC_SHA256,
TLS_DH_anon_WITH_AES_256_CBC_SHA256,
TLS_DH_anon_WITH_AES_128_CBC_SHA,
TLS_DH_anon_WITH_AES_256_CBC_SHA,
SSL_DH_anon_WITH_RC4_128_MD5,
SSL_DH_anon_WITH_3DES_EDE_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_NULL_SHA,
TLS_ECDHE_RSA_WITH_NULL_SHA,
#if ENABLE_ECDH
TLS_ECDH_ECDSA_WITH_NULL_SHA,
TLS_ECDH_RSA_WITH_NULL_SHA,
#endif
#if ENABLE_PSK
TLS_PSK_WITH_AES_256_CBC_SHA384,
TLS_PSK_WITH_AES_128_CBC_SHA256,
TLS_PSK_WITH_AES_256_CBC_SHA,
TLS_PSK_WITH_AES_128_CBC_SHA,
TLS_PSK_WITH_RC4_128_SHA,
TLS_PSK_WITH_3DES_EDE_CBC_SHA,
TLS_PSK_WITH_NULL_SHA384,
TLS_PSK_WITH_NULL_SHA256,
TLS_PSK_WITH_NULL_SHA,
#endif
TLS_RSA_WITH_NULL_SHA256,
SSL_RSA_WITH_NULL_SHA,
SSL_RSA_WITH_NULL_MD5
};
static const unsigned STCipherSuiteCount = sizeof(STKnownCipherSuites)/sizeof(STKnownCipherSuites[0]);
OSStatus sslBuildCipherSuiteArray(SSLContext *ctx)
{
size_t size;
unsigned dex;
assert(ctx != NULL);
assert(ctx->validCipherSuites == NULL);
ctx->numValidCipherSuites = STCipherSuiteCount;
size = STCipherSuiteCount * sizeof(uint16_t);
ctx->validCipherSuites = (uint16_t *)sslMalloc(size);
if(ctx->validCipherSuites == NULL) {
ctx->numValidCipherSuites = 0;
return errSecAllocate;
}
uint16_t *dst = ctx->validCipherSuites;
const uint16_t *src = STKnownCipherSuites;
bool trimDHE = !ctx->dheEnabled;
bool trimECDHE = false;
const bool trimECDH = true;
if(ctx->maxProtocolVersion == SSL_Version_3_0) {
trimECDHE = true;
}
bool trimRC4 = ctx->isDTLS;
bool trimCBC = (ctx->protocolSide==kSSLClientSide)
&& (ctx->maxProtocolVersion == SSL_Version_3_0)
&& ctx->fallbackEnabled;
for(dex=0; dex<STCipherSuiteCount; dex++) {
KeyExchangeMethod kem = sslCipherSuiteGetKeyExchangeMethod(*src);
uint8_t keySize = sslCipherSuiteGetSymmetricCipherKeySize(*src);
HMAC_Algs mac = sslCipherSuiteGetMacAlgorithm(*src);
SSL_CipherAlgorithm cipher = sslCipherSuiteGetSymmetricCipherAlgorithm(*src);
switch(kem) {
case SSL_ECDHE_ECDSA:
case SSL_ECDHE_RSA:
if(trimECDHE) {
ctx->numValidCipherSuites--;
src++;
continue;
}
else {
break;
}
case SSL_ECDH_ECDSA:
case SSL_ECDH_RSA:
case SSL_ECDH_anon:
if(trimECDH) {
ctx->numValidCipherSuites--;
src++;
continue;
}
else {
break;
}
case SSL_DHE_RSA:
if(trimDHE) {
ctx->numValidCipherSuites--;
src++;
continue;
}
default:
break;
}
if(!ctx->anonCipherEnable) {
if(mac == HA_Null) {
ctx->numValidCipherSuites--;
src++;
continue;
}
switch(kem) {
case SSL_DH_anon:
case SSL_DH_anon_EXPORT:
case SSL_ECDH_anon:
ctx->numValidCipherSuites--;
src++;
continue;
default:
break;
}
}
if (keySize == 8)
{
ctx->numValidCipherSuites--;
src++;
continue;
}
if (kem==TLS_PSK) {
ctx->numValidCipherSuites--;
src++;
continue;
}
if (trimRC4 && (cipher==SSL_CipherAlgorithmRC4_128)) {
ctx->numValidCipherSuites--;
src++;
continue;
}
if(trimCBC) {
switch (cipher) {
case SSL_CipherAlgorithmAES_128_CBC:
case SSL_CipherAlgorithmAES_256_CBC:
case SSL_CipherAlgorithm3DES_CBC:
ctx->numValidCipherSuites--;
src++;
continue;
default:
break;
}
}
if(cipher==SSL_CipherAlgorithmNull) {
ctx->numValidCipherSuites--;
src++;
continue;
}
*dst++ = *src++;
}
tls_handshake_set_ciphersuites(ctx->hdsk, ctx->validCipherSuites, ctx->numValidCipherSuites);
return errSecSuccess;
}
static OSStatus
cipherSuitesToCipherSuites(
size_t numCipherSuites,
const uint16_t *cipherSuites,
SSLCipherSuite *ciphers,
size_t *numCiphers)
{
size_t i;
if(*numCiphers < numCipherSuites) {
return errSSLBufferOverflow;
}
for(i=0;i<numCipherSuites; i++) {
ciphers[i]=cipherSuites[i];
}
*numCiphers = numCipherSuites;
return errSecSuccess;
}
OSStatus
SSLGetNumberSupportedCiphers (SSLContextRef ctx,
size_t *numCiphers)
{
if((ctx == NULL) || (numCiphers == NULL)) {
return errSecParam;
}
*numCiphers = STCipherSuiteCount;
return errSecSuccess;
}
OSStatus
SSLGetSupportedCiphers (SSLContextRef ctx,
SSLCipherSuite *ciphers,
size_t *numCiphers)
{
if((ctx == NULL) || (ciphers == NULL) || (numCiphers == NULL)) {
return errSecParam;
}
return cipherSuitesToCipherSuites(STCipherSuiteCount,
STKnownCipherSuites,
ciphers,
numCiphers);
}
OSStatus
SSLSetEnabledCiphers (SSLContextRef ctx,
const SSLCipherSuite *ciphers,
size_t numCiphers)
{
size_t size;
unsigned foundCiphers=0;
unsigned callerDex;
unsigned tableDex;
if((ctx == NULL) || (ciphers == NULL) || (numCiphers == 0)) {
return errSecParam;
}
if(sslIsSessionActive(ctx)) {
return errSecBadReq;
}
size = numCiphers * sizeof(uint16_t);
ctx->validCipherSuites = (uint16_t *)sslMalloc(size);
if(ctx->validCipherSuites == NULL) {
ctx->numValidCipherSuites = 0;
return errSecAllocate;
}
for(callerDex=0; callerDex<numCiphers; callerDex++) {
for(tableDex=0; tableDex<STCipherSuiteCount; tableDex++) {
if(ciphers[callerDex] == STKnownCipherSuites[tableDex]) {
ctx->validCipherSuites[foundCiphers] = STKnownCipherSuites[tableDex];
foundCiphers++;
break;
}
}
}
if(foundCiphers==0) {
sslFree(ctx->validCipherSuites);
ctx->validCipherSuites = NULL;
return errSSLBadCipherSuite;
}
ctx->numValidCipherSuites = foundCiphers;
tls_handshake_set_ciphersuites(ctx->hdsk, ctx->validCipherSuites, ctx->numValidCipherSuites);
return errSecSuccess;
}
OSStatus
SSLGetNumberEnabledCiphers (SSLContextRef ctx,
size_t *numCiphers)
{
if((ctx == NULL) || (numCiphers == NULL)) {
return errSecParam;
}
unsigned n;
const uint16_t *ciphersuites;
int err;
err = tls_handshake_get_ciphersuites(ctx->hdsk, &ciphersuites, &n);
if(err) {
return err;
} else {
*numCiphers = n;
return errSecSuccess;
}
}
OSStatus
SSLGetEnabledCiphers (SSLContextRef ctx,
SSLCipherSuite *ciphers,
size_t *numCiphers)
{
if((ctx == NULL) || (ciphers == NULL) || (numCiphers == NULL)) {
return errSecParam;
}
unsigned n;
const uint16_t *ciphersuites;
int err;
err = tls_handshake_get_ciphersuites(ctx->hdsk, &ciphersuites, &n);
return cipherSuitesToCipherSuites(n,
ciphersuites,
ciphers,
numCiphers);
}