sslCipherSpecs.c   [plain text]


/*
 * Copyright (c) 1999-2001,2005-2014 Apple Inc. All Rights Reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this
 * file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

/*
 * cipherSpecs.c - SSLCipherSpec declarations
 */

#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>


/* SecureTransport needs it's own copy of KnownCipherSuites for now, there is a copy in coreTLS,
   that is exported, but it actually should only included the "default" not the supported */

#define ENABLE_ECDH      		1
#define ENABLE_AES_GCM          0
#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


    /* Unsafe ciphersuites */

#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]);


/*
 * Build ctx->validCipherSpecs as a copy of KnownCipherSpecs, assuming that
 * validCipherSpecs is currently not valid (i.e., SSLSetEnabledCiphers() has
 * not been called).
 */
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;
	}

	/*
	 * Trim out inappropriate ciphers:
	 *  -- trim anonymous ciphers if !ctx->anonCipherEnable
	 *  -- trim ECDSA ciphers for server side if appropriate
	 *  -- trim ECDSA ciphers if TLSv1 disable or SSLv2 enabled (since
	 *     we MUST do the Client Hello extensions to make these ciphers
	 *     work reliably)
     *  -- trim Stream ciphers if DTLSv1 enable
     *  -- trim CBC ciphers when doing SSLv3 fallback
	 */
	uint16_t *dst = ctx->validCipherSuites;
	const uint16_t *src = STKnownCipherSuites;

	bool trimECDSA = false;
	if((ctx->protocolSide==kSSLServerSide) && !SSL_ECDSA_SERVER) {
		trimECDSA = true;
	}
	if(ctx->minProtocolVersion == SSL_Version_2_0
       || ctx->maxProtocolVersion == SSL_Version_3_0) {
        /* We trim ECDSA cipher suites if SSL2 is enabled or
         The maximum allowed protocol is SSL3.  Note that this
         won't trim ECDSA cipherspecs for DTLS which should be
         the right thing to do here. */
		trimECDSA = true;
	}

    /* trim Stream Ciphers for DTLS */
    bool trimRC4 = ctx->isDTLS;

    /* trim CBC cipher when doing SSLv3 only fallback */
    bool trimCBC = (ctx->protocolSide==kSSLClientSide)
                    && (ctx->maxProtocolVersion == SSL_Version_3_0)
                    && ctx->fallbackEnabled;

    bool trimDHE = (ctx->protocolSide==kSSLServerSide) &&
                    !ctx->dhParamsEncoded.length;

	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);
		/* First skip ECDSA ciphers as appropriate */
		switch(kem) {
			case SSL_ECDH_ECDSA:
			case SSL_ECDHE_ECDSA:
			case SSL_ECDH_RSA:
			case SSL_ECDHE_RSA:
			case SSL_ECDH_anon:
				if(trimECDSA) {
					/* Skip this one */
					ctx->numValidCipherSuites--;
					src++;
					continue;
				}
				else {
					break;
				}
			default:
				break;
		}
		if(!ctx->anonCipherEnable) {
			/* trim out the anonymous (and null-auth-cipher) ciphers */
			if(mac == HA_Null) {
                /* skip this one */
				ctx->numValidCipherSuites--;
				src++;
				continue;
			}
			switch(kem) {
				case SSL_DH_anon:
				case SSL_DH_anon_EXPORT:
				case SSL_ECDH_anon:
					/* skip this one */
					ctx->numValidCipherSuites--;
					src++;
					continue;
				default:
					break;
			}
		}
        if(ctx->falseStartEnabled) {
            switch(kem){
                case SSL_ECDHE_ECDSA:
                case SSL_ECDHE_RSA:
                case SSL_DHE_RSA:
                case SSL_DHE_DSS:
                    /* Ok for false start */
                    break;
                default:
					/* Not ok, skip */
					ctx->numValidCipherSuites--;
					src++;
					continue;
            }
            switch(cipher) {
                case SSL_CipherAlgorithmAES_128_CBC:
                case SSL_CipherAlgorithmAES_128_GCM:
                case SSL_CipherAlgorithmAES_256_CBC:
                case SSL_CipherAlgorithmAES_256_GCM:
                case SSL_CipherAlgorithmRC4_128:
                    /* Ok for false start */
                    break;
                default:
					/* Not ok, skip*/
					ctx->numValidCipherSuites--;
					src++;
					continue;
            }
        }

        /* This will skip the simple DES cipher suites, but not the NULL cipher ones */
        if (keySize == 8)
        {
            /* skip this one */
            ctx->numValidCipherSuites--;
            src++;
            continue;
        }

        /* Trim PSK ciphersuites, they need to be enabled explicitely */
        if (kem==TLS_PSK) {
            ctx->numValidCipherSuites--;
            src++;
            continue;
        }

        if (trimDHE) {
			switch(kem) {
				case SSL_DHE_DSS:
				case SSL_DHE_DSS_EXPORT:
				case SSL_DHE_RSA:
				case SSL_DHE_RSA_EXPORT:
					/* skip this one */
					ctx->numValidCipherSuites--;
					src++;
					continue;
				default:
					break;
			}
		}

        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;
        }

        /* This one is good to go */
        *dst++ = *src++;
	}

	// sslAnalyzeCipherSpecs(ctx);

    tls_handshake_set_ciphersuites(ctx->hdsk, ctx->validCipherSuites, ctx->numValidCipherSuites);

	return errSecSuccess;
}


/*
 * Convert an array of SSLCipherSuites (which is always KnownCipherSpecs)
 * to an array of SSLCipherSuites.
 */
static OSStatus
cipherSuitesToCipherSuites(
                          size_t				numCipherSuites,
                          const uint16_t        *cipherSuites,
                          SSLCipherSuite		*ciphers,		/* RETURNED */
                          size_t				*numCiphers)	/* IN/OUT */
{
    size_t i;
	if(*numCiphers < numCipherSuites) {
		return errSSLBufferOverflow;
	}

    /* NOTE: this is required to go from uint16_t to SSLCipherSuite 
       which is either 32 or 16 bits, depending on the platform */
    for(i=0;i<numCipherSuites; i++) {
        ciphers[i]=cipherSuites[i];
    }
	*numCiphers = numCipherSuites;
	return errSecSuccess;
}

/***
 *** Publically exported functions declared in SecureTransport.h
 ***/

/*
 * Determine number and values of all of the SSLCipherSuites we support.
 * Caller allocates output buffer for SSLGetSupportedCiphers() and passes in
 * its size in *numCiphers. If supplied buffer is too small, errSSLBufferOverflow
 * will be returned.
 */
OSStatus
SSLGetNumberSupportedCiphers (SSLContextRef	ctx,
							  size_t		*numCiphers)
{
	if((ctx == NULL) || (numCiphers == NULL)) {
		return errSecParam;
	}
	*numCiphers = STCipherSuiteCount;
	return errSecSuccess;
}

OSStatus
SSLGetSupportedCiphers		 (SSLContextRef		ctx,
							  SSLCipherSuite	*ciphers,		/* RETURNED */
							  size_t			*numCiphers)	/* IN/OUT */
{
	if((ctx == NULL) || (ciphers == NULL) || (numCiphers == NULL)) {
		return errSecParam;
	}
	return cipherSuitesToCipherSuites(STCipherSuiteCount,
		STKnownCipherSuites,
		ciphers,
		numCiphers);
}

/*
 * Specify a (typically) restricted set of SSLCipherSuites to be enabled by
 * the current SSLContext. Can only be called when no session is active. Default
 * set of enabled SSLCipherSuites is NOT the same as the complete set of supported
 * SSLCipherSuites as obtained by SSLGetSupportedCiphers().
 */
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)) {
		/* can't do this with an active session */
		return errSecBadReq;
	}
	size = numCiphers * sizeof(uint16_t);
	ctx->validCipherSuites = (uint16_t *)sslMalloc(size);
	if(ctx->validCipherSuites == NULL) {
		ctx->numValidCipherSuites = 0;
		return errSecAllocate;
	}

	/*
	 * Run thru caller's specs, keep only the supported ones.
	 */
    for(callerDex=0; callerDex<numCiphers; callerDex++) {
        /* find matching CipherSpec in our known table */
        for(tableDex=0; tableDex<STCipherSuiteCount; tableDex++) {
            if(ciphers[callerDex] == STKnownCipherSuites[tableDex]) {
                ctx->validCipherSuites[foundCiphers] = STKnownCipherSuites[tableDex];
                foundCiphers++;
                break;
            }
        }
	}

    if(foundCiphers==0) {
        /* caller specified only unsupported ciphersuites */
        sslFree(ctx->validCipherSuites);
        ctx->validCipherSuites = NULL;
        return errSSLBadCipherSuite;
    }
    
	/* success */
	ctx->numValidCipherSuites = foundCiphers;

    tls_handshake_set_ciphersuites(ctx->hdsk, ctx->validCipherSuites, ctx->numValidCipherSuites);

    return errSecSuccess;
}

/*
 * Determine number and values of all of the SSLCipherSuites currently enabled.
 * Caller allocates output buffer for SSLGetEnabledCiphers() and passes in
 * its size in *numCiphers. If supplied buffer is too small, errSSLBufferOverflow
 * will be returned.
 */
OSStatus
SSLGetNumberEnabledCiphers 	(SSLContextRef			ctx,
							 size_t					*numCiphers)
{
	if((ctx == NULL) || (numCiphers == NULL)) {
		return errSecParam;
	}
	if(ctx->validCipherSuites == NULL) {
		/* hasn't been set; use default */
		*numCiphers = STCipherSuiteCount;
	}
	else {
		/* caller set via SSLSetEnabledCiphers */
		*numCiphers = ctx->numValidCipherSuites;
	}
	return errSecSuccess;
}

OSStatus
SSLGetEnabledCiphers		(SSLContextRef			ctx,
							 SSLCipherSuite			*ciphers,		/* RETURNED */
							 size_t					*numCiphers)	/* IN/OUT */
{
	if((ctx == NULL) || (ciphers == NULL) || (numCiphers == NULL)) {
		return errSecParam;
	}
	if(ctx->validCipherSuites == NULL) {
		/* hasn't been set; use default */
		return cipherSuitesToCipherSuites(STCipherSuiteCount,
			STKnownCipherSuites,
			ciphers,
			numCiphers);
	}
	else {
		/* use the ones specified in SSLSetEnabledCiphers() */
		return cipherSuitesToCipherSuites(ctx->numValidCipherSuites,
			ctx->validCipherSuites,
			ciphers,
			numCiphers);
	}
}