/* * 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 #include #include #include #include /* 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; dexnumValidCipherSuites--; 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;ivalidCipherSuites = (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; callerDexvalidCipherSuites[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); } }