Skip to content

Instantly share code, notes, and snippets.

@csm
Last active November 26, 2022 20:46
Show Gist options
  • Save csm/9285494 to your computer and use it in GitHub Desktop.
Save csm/9285494 to your computer and use it in GitHub Desktop.
Apple's SSL bug; diff between last known-good (OS X 10.8.5) and known-bad (OS X 10.9)
@@ -596,8 +597,8 @@
dataToSignLen = SSL_SHA1_DIGEST_LEN + SSL_MD5_DIGEST_LEN;
hashOut.data = hashes;
hashOut.length = SSL_MD5_DIGEST_LEN;
-
- if ((err = ReadyHash(&SSLHashMD5, &hashCtx, ctx)) != 0)
+
+ if ((err = ReadyHash(&SSLHashMD5, &hashCtx)) != 0)
goto fail;
if ((err = SSLHashMD5.update(&hashCtx, &clientRandom)) != 0)
goto fail;
@@ -616,10 +617,10 @@
hashOut.data = hashes + SSL_MD5_DIGEST_LEN;
hashOut.length = SSL_SHA1_DIGEST_LEN;
- if ((err = SSLFreeBuffer(&hashCtx, ctx)) != 0)
+ if ((err = SSLFreeBuffer(&hashCtx)) != 0)
goto fail;
- if ((err = ReadyHash(&SSLHashSHA1, &hashCtx, ctx)) != 0)
+ if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0)
goto fail;
@@ -627,6 +628,7 @@
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
+ goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
@@ -643,8 +645,8 @@
}
fail:
- SSLFreeBuffer(&signedHashes, ctx);
- SSLFreeBuffer(&hashCtx, ctx);
+ SSLFreeBuffer(&signedHashes);
+ SSLFreeBuffer(&hashCtx);
return err;
}
@@ -694,7 +696,7 @@
hashOut.data = hashes;
hashOut.length = hashRef->digestSize;
- if ((err = ReadyHash(hashRef, &hashCtx, ctx)) != 0)
+ if ((err = ReadyHash(hashRef, &hashCtx)) != 0)
goto fail;
if ((err = hashRef->update(&hashCtx, &clientRandom)) != 0)
goto fail;
@@ -729,8 +731,8 @@
}
fail:
- SSLFreeBuffer(&signedHashes, ctx);
- SSLFreeBuffer(&hashCtx, ctx);
+ SSLFreeBuffer(&signedHashes);
+ SSLFreeBuffer(&hashCtx);
return err;
}
@@ -757,7 +759,7 @@
--- sslKeyExchange-55179.13.c 2014-02-28 20:57:37.000000000 -0800
+++ sslKeyExchange-55471.c 2014-02-28 20:57:54.000000000 -0800
@@ -32,28 +32,30 @@
#include "sslDebug.h"
#include "sslUtils.h"
#include "sslCrypto.h"
-
+#include "sslRand.h"
#include "sslDigests.h"
#include <assert.h>
#include <string.h>
#include <stdio.h>
-
+#include <utilities/SecCFRelease.h>
#include <corecrypto/ccdh_gp.h>
#ifdef USE_CDSA_CRYPTO
-//#include <security_utilities/globalizer.h>
-//#include <security_utilities/threading.h>
+//#include <utilities/globalizer.h>
+//#include <utilities/threading.h>
#include <Security/cssmapi.h>
#include <Security/SecKeyPriv.h>
#include "ModuleAttacher.h"
#else
-#include <Security/SecRSAKey.h>
#include <AssertMacros.h>
#include <Security/oidsalg.h>
#if APPLE_DH
+#if TARGET_OS_IPHONE
+#include <Security/SecRSAKey.h>
+#endif
static OSStatus SSLGenServerDHParamsAndKey(SSLContext *ctx);
static size_t SSLEncodedDHKeyParamsLen(SSLContext *ctx);
@@ -62,10 +64,8 @@
#endif /* APPLE_DH */
#endif /* USE_CDSA_CRYPTO */
-#include <pthread.h>
-
-#pragma mark -
-#pragma mark Forward Static Declarations
+// MARK: -
+// MARK: Forward Static Declarations
#if APPLE_DH
#if USE_CDSA_CRYPTO
@@ -108,8 +108,8 @@
#if APPLE_DH
-#pragma mark -
-#pragma mark Local Diffie-Hellman Parameter Generator
+// MARK: -
+// MARK: Local Diffie-Hellman Parameter Generator
/*
* Process-wide server-supplied Diffie-Hellman parameters.
@@ -128,8 +128,8 @@
#endif /* APPLE_DH */
-#pragma mark -
-#pragma mark RSA Key Exchange
+// MARK: -
+// MARK: RSA Key Exchange
/*
* Client RSA Key Exchange msgs actually start with a two-byte
@@ -160,8 +160,8 @@
&modulus,
&exponent);
if(err) {
- SSLFreeBuffer(&modulus, ctx);
- SSLFreeBuffer(&exponent, ctx);
+ SSLFreeBuffer(&modulus);
+ SSLFreeBuffer(&exponent);
return err;
}
@@ -177,9 +177,9 @@
memcpy(charPtr, exponent.data, exponent.length);
/* these were mallocd by sslGetPubKeyBits() */
- SSLFreeBuffer(&modulus, ctx);
- SSLFreeBuffer(&exponent, ctx);
- return noErr;
+ SSLFreeBuffer(&modulus);
+ SSLFreeBuffer(&exponent);
+ return errSecSuccess;
#else
CFDataRef modulus = SecKeyCopyModulus(SECKEYREF(key));
if (!modulus) {
@@ -198,8 +198,10 @@
sslDebugLog("SSLEncodeRSAKeyParams: modulus len=%ld, exponent len=%ld\n",
modulusLength, exponentLength);
OSStatus err;
- if ((err = SSLAllocBuffer(keyParams,
- modulusLength + exponentLength + 4, ctx)) != 0) {
+ if ((err = SSLAllocBuffer(keyParams,
+ modulusLength + exponentLength + 4)) != 0) {
+ CFReleaseSafe(exponent);
+ CFReleaseSafe(modulus);
return err;
}
uint8_t *charPtr = keyParams->data;
@@ -210,7 +212,7 @@
memcpy(charPtr, CFDataGetBytePtr(exponent), exponentLength);
CFRelease(modulus);
CFRelease(exponent);
- return noErr;
+ return errSecSuccess;
#endif
}
@@ -218,20 +220,19 @@
SSLEncodeRSAPremasterSecret(SSLContext *ctx)
{ SSLBuffer randData;
OSStatus err;
- SSLProtocolVersion maxVersion;
- if ((err = SSLAllocBuffer(&ctx->preMasterSecret,
- SSL_RSA_PREMASTER_SECRET_SIZE, ctx)) != 0)
+ if ((err = SSLAllocBuffer(&ctx->preMasterSecret,
+ SSL_RSA_PREMASTER_SECRET_SIZE)) != 0)
return err;
assert(ctx->negProtocolVersion >= SSL_Version_3_0);
- sslGetMaxProtVersion(ctx, &maxVersion);
- SSLEncodeInt(ctx->preMasterSecret.data, maxVersion, 2);
+
+ SSLEncodeInt(ctx->preMasterSecret.data, ctx->clientReqProtocol, 2);
randData.data = ctx->preMasterSecret.data+2;
randData.length = SSL_RSA_PREMASTER_SECRET_SIZE - 2;
- if ((err = sslRand(ctx, &randData)) != 0)
+ if ((err = sslRand(&randData)) != 0)
return err;
- return noErr;
+ return errSecSuccess;
}
/*
@@ -282,7 +283,7 @@
hashOut.data = hashes;
hashOut.length = hashRef->digestSize;
- if ((err = ReadyHash(hashRef, &hashCtx, ctx)) != 0)
+ if ((err = ReadyHash(hashRef, &hashCtx)) != 0)
goto fail;
if ((err = hashRef->update(&hashCtx, &clientRandom)) != 0)
goto fail;
@@ -319,8 +320,8 @@
}
fail:
- SSLFreeBuffer(&signedHashes, ctx);
- SSLFreeBuffer(&hashCtx, ctx);
+ SSLFreeBuffer(&signedHashes);
+ SSLFreeBuffer(&hashCtx);
return err;
}
@@ -348,7 +349,7 @@
hash.data = &hashes[0];
hash.length = SSL_MD5_DIGEST_LEN;
- if ((err = ReadyHash(&SSLHashMD5, &hashCtx, ctx)) != 0)
+ if ((err = ReadyHash(&SSLHashMD5, &hashCtx)) != 0)
goto fail;
if ((err = SSLHashMD5.update(&hashCtx, &clientRandom)) != 0)
goto fail;
@@ -358,7 +359,7 @@
goto fail;
if ((err = SSLHashMD5.final(&hashCtx, &hash)) != 0)
goto fail;
- if ((err = SSLFreeBuffer(&hashCtx, ctx)) != 0)
+ if ((err = SSLFreeBuffer(&hashCtx)) != 0)
goto fail;
}
else {
@@ -368,7 +369,7 @@
}
hash.data = &hashes[SSL_MD5_DIGEST_LEN];
hash.length = SSL_SHA1_DIGEST_LEN;
- if ((err = ReadyHash(&SSLHashSHA1, &hashCtx, ctx)) != 0)
+ if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0)
goto fail;
@@ -378,7 +379,7 @@
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hash)) != 0)
goto fail;
- if ((err = SSLFreeBuffer(&hashCtx, ctx)) != 0)
+ if ((err = SSLFreeBuffer(&hashCtx)) != 0)
goto fail;
@@ -394,7 +395,7 @@
}
fail:
- SSLFreeBuffer(&hashCtx, ctx);
+ SSLFreeBuffer(&hashCtx);
return err;
}
@@ -422,7 +423,7 @@
//Let's only support SHA1 and SHA256. SHA384 does not work with 512 bits keys.
// We should actually test against what the cert can do.
if((alg->hash==SSL_HashAlgorithmSHA1) || (alg->hash==SSL_HashAlgorithmSHA256)) {
- return noErr;
+ return errSecSuccess;
}
}
// We could not find a supported signature and hash algorithm
@@ -455,7 +456,7 @@
/* Set up parameter block to hash ==> exchangeParams */
- switch(ctx->selectedCipherSpec.keyExchangeMethod) {
+ switch(ctx->selectedCipherSpecParams.keyExchangeMethod) {
case SSL_RSA:
case SSL_RSA_EXPORT:
/*
@@ -488,7 +489,7 @@
return err;
}
size_t len = SSLEncodedDHKeyParamsLen(ctx);
- err = SSLAllocBuffer(&exchangeParams, len, ctx);
+ err = SSLAllocBuffer(&exchangeParams, len);
if(err) {
goto fail;
}
@@ -512,7 +513,7 @@
if(err) {
goto fail;
}
- err = SSLAllocBuffer(&signature, maxSigLen, ctx);
+ err = SSLAllocBuffer(&signature, maxSigLen);
if(err) {
goto fail;
}
@@ -543,7 +544,7 @@
/* package it all up */
keyExch->protocolVersion = ctx->negProtocolVersion;
keyExch->contentType = SSL_RecordTypeHandshake;
- if ((err = SSLAllocBuffer(&keyExch->contents, outputLen+head, ctx)) != 0)
+ if ((err = SSLAllocBuffer(&keyExch->contents, outputLen+head)) != 0)
goto fail;
charPtr = SSLEncodeHandshakeHeader(ctx, keyExch, SSL_HdskServerKeyExchange, outputLen);
@@ -562,11 +563,11 @@
assert((charPtr + actSigLen) ==
(keyExch->contents.data + keyExch->contents.length));
- err = noErr;
+ err = errSecSuccess;
fail:
- SSLFreeBuffer(&exchangeParams, ctx);
- SSLFreeBuffer(&signature, ctx);
+ SSLFreeBuffer(&exchangeParams);
+ SSLFreeBuffer(&signature);
return err;
}
@@ -596,8 +597,8 @@
dataToSignLen = SSL_SHA1_DIGEST_LEN + SSL_MD5_DIGEST_LEN;
hashOut.data = hashes;
hashOut.length = SSL_MD5_DIGEST_LEN;
-
- if ((err = ReadyHash(&SSLHashMD5, &hashCtx, ctx)) != 0)
+
+ if ((err = ReadyHash(&SSLHashMD5, &hashCtx)) != 0)
goto fail;
if ((err = SSLHashMD5.update(&hashCtx, &clientRandom)) != 0)
goto fail;
@@ -616,10 +617,10 @@
hashOut.data = hashes + SSL_MD5_DIGEST_LEN;
hashOut.length = SSL_SHA1_DIGEST_LEN;
- if ((err = SSLFreeBuffer(&hashCtx, ctx)) != 0)
+ if ((err = SSLFreeBuffer(&hashCtx)) != 0)
goto fail;
- if ((err = ReadyHash(&SSLHashSHA1, &hashCtx, ctx)) != 0)
+ if ((err = ReadyHash(&SSLHashSHA1, &hashCtx)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &clientRandom)) != 0)
goto fail;
@@ -627,6 +628,7 @@
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
+ goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
@@ -643,8 +645,8 @@
}
fail:
- SSLFreeBuffer(&signedHashes, ctx);
- SSLFreeBuffer(&hashCtx, ctx);
+ SSLFreeBuffer(&signedHashes);
+ SSLFreeBuffer(&hashCtx);
return err;
}
@@ -694,7 +696,7 @@
hashOut.data = hashes;
hashOut.length = hashRef->digestSize;
- if ((err = ReadyHash(hashRef, &hashCtx, ctx)) != 0)
+ if ((err = ReadyHash(hashRef, &hashCtx)) != 0)
goto fail;
if ((err = hashRef->update(&hashCtx, &clientRandom)) != 0)
goto fail;
@@ -729,8 +731,8 @@
}
fail:
- SSLFreeBuffer(&signedHashes, ctx);
- SSLFreeBuffer(&hashCtx, ctx);
+ SSLFreeBuffer(&signedHashes);
+ SSLFreeBuffer(&hashCtx);
return err;
}
@@ -757,7 +759,7 @@
/* first extract the key-exchange-method-specific parameters */
uint8_t *charPtr = message.data;
uint8_t *endCp = charPtr + message.length;
- switch(ctx->selectedCipherSpec.keyExchangeMethod) {
+ switch(ctx->selectedCipherSpecParams.keyExchangeMethod) {
case SSL_RSA:
case SSL_RSA_EXPORT:
modulusLen = SSLDecodeInt(charPtr, 2);
@@ -844,7 +846,7 @@
goto fail;
/* Signature matches; now replace server key with new key (RSA only) */
- switch(ctx->selectedCipherSpec.keyExchangeMethod) {
+ switch(ctx->selectedCipherSpecParams.keyExchangeMethod) {
case SSL_RSA:
case SSL_RSA_EXPORT:
{
@@ -889,24 +891,9 @@
SSLPrivKey *keyRef = NULL;
assert(ctx->protocolSide == kSSLServerSide);
-
- #if SSL_SERVER_KEYEXCH_HACK
- /*
- * the way we work with Netscape.
- * FIXME - maybe we should *require* an encryptPrivKey in this
- * situation?
- */
- if((ctx->selectedCipherSpec.keyExchangeMethod == SSL_RSA_EXPORT) &&
- (ctx->encryptPrivKey != NULL)) {
- useEncryptKey = true;
- }
-
- #else /* !SSL_SERVER_KEYEXCH_HACK */
- /* The "correct" way, I think, which doesn't work with Netscape */
- if (ctx->encryptPrivKeyRef) {
- useEncryptKey = true;
- }
- #endif /* SSL_SERVER_KEYEXCH_HACK */
+ if (ctx->encryptPrivKeyRef) {
+ useEncryptKey = true;
+ }
if (useEncryptKey) {
keyRef = ctx->encryptPrivKeyRef;
/* FIXME: when 3420180 is implemented, pick appropriate creds here */
@@ -940,7 +927,7 @@
(unsigned)localKeyModulusLen, (unsigned)keyExchange.length);
return errSSLProtocol;
}
- err = SSLAllocBuffer(&ctx->preMasterSecret, SSL_RSA_PREMASTER_SECRET_SIZE, ctx);
+ err = SSLAllocBuffer(&ctx->preMasterSecret, SSL_RSA_PREMASTER_SECRET_SIZE);
if(err != 0) {
return err;
}
@@ -973,7 +960,7 @@
SSL_RSA_PREMASTER_SECRET_SIZE, // plaintext buf available
&outputLen);
- if(err != noErr) {
+ if(err != errSecSuccess) {
/* possible Bleichenbacher attack */
sslLogNegotiateDebug("SSLDecodeRSAKeyExchange: RSA decrypt fail");
}
@@ -982,7 +969,7 @@
err = errSSLProtocol; // not passed back to caller
}
- if(err == noErr) {
+ if(err == errSecSuccess) {
/*
* Two legal values here - the one we actually negotiated (which is
* technically incorrect but not uncommon), and the one the client
@@ -996,7 +983,7 @@
err = errSSLProtocol;
}
}
- if(err != noErr) {
+ if(err != errSecSuccess) {
/*
* Obfuscate failures for defense against Bleichenbacher and
* Klima-Pokorny-Rosa attacks.
@@ -1006,11 +993,11 @@
tmpBuf.data = ctx->preMasterSecret.data + 2;
tmpBuf.length = SSL_RSA_PREMASTER_SECRET_SIZE - 2;
/* must ignore failures here */
- sslRand(ctx, &tmpBuf);
+ sslRand(&tmpBuf);
}
/* in any case, save premaster secret (good or bogus) and proceed */
- return noErr;
+ return errSecSuccess;
}
static OSStatus
@@ -1049,9 +1036,9 @@
#endif
head = SSLHandshakeHeaderSize(keyExchange);
bufLen = msglen + head;
- if ((err = SSLAllocBuffer(&keyExchange->contents,
- bufLen,ctx)) != 0)
- {
+ if ((err = SSLAllocBuffer(&keyExchange->contents,
+ bufLen)) != 0)
+ {
return err;
}
dst = keyExchange->contents.data + head;
@@ -1082,20 +1069,20 @@
peerKeyModulusLen,
&outputLen);
if(err) {
- sslErrorLog("SSLEncodeRSAKeyExchange: error %d\n", err);
+ sslErrorLog("SSLEncodeRSAKeyExchange: error %d\n", (int)err);
return err;
}
assert(outputLen == (encodeLen ? msglen - 2 : msglen));
- return noErr;
+ return errSecSuccess;
}
#if APPLE_DH
-#pragma mark -
-#pragma mark Diffie-Hellman Key Exchange
+// MARK: -
+// MARK: Diffie-Hellman Key Exchange
/*
* Diffie-Hellman setup, server side. On successful return, the
@@ -1148,7 +1135,7 @@
#if USE_CDSA_CRYPTO
/* generate per-session D-H key pair */
sslFreeKey(ctx->cspHand, &ctx->dhPrivate, NULL);
- SSLFreeBuffer(&ctx->dhExchangePublic, ctx);
+ SSLFreeBuffer(&ctx->dhExchangePublic);
ctx->dhPrivate = (CSSM_KEY *)sslMalloc(sizeof(CSSM_KEY));
CSSM_KEY pubKey;
ortn = sslDhGenerateKeyPair(ctx,
@@ -1167,7 +1154,7 @@
}
return sslDhGenerateKeyPair(ctx);
#endif
- return noErr;
+ return errSecSuccess;
}
/*
@@ -1219,7 +1206,7 @@
dumpBuf("server generator", &generator);
dumpBuf("server pub key", &ctx->dhExchangePublic);
- return noErr;
+ return errSecSuccess;
}
/*
@@ -1231,7 +1218,7 @@
uint8_t **charPtr, // IN/OUT
size_t length)
{
- OSStatus err = noErr;
+ OSStatus err = errSecSuccess;
SSLBuffer prime;
SSLBuffer generator;
@@ -1239,8 +1226,8 @@
uint8_t *endCp = *charPtr + length;
/* Allow reuse via renegotiation */
- SSLFreeBuffer(&ctx->dhPeerPublic, ctx);
-
+ SSLFreeBuffer(&ctx->dhPeerPublic);
+
/* Prime, with a two-byte length */
UInt32 len = SSLDecodeInt(*charPtr, 2);
(*charPtr) += 2;
@@ -1270,7 +1257,7 @@
/* peer public key, with a two-byte length */
len = SSLDecodeInt(*charPtr, 2);
(*charPtr) += 2;
- err = SSLAllocBuffer(&ctx->dhPeerPublic, len, ctx);
+ err = SSLAllocBuffer(&ctx->dhPeerPublic, len);
if(err) {
return err;
}
@@ -1278,8 +1265,8 @@
(*charPtr) += len;
dumpBuf("client peer pub", &ctx->dhPeerPublic);
- dumpBuf("client prime", &ctx->dhParamsPrime);
- dumpBuf("client generator", &ctx->dhParamsGenerator);
+ // dumpBuf("client prime", &ctx->dhParamsPrime);
+ // dumpBuf("client generator", &ctx->dhParamsGenerator);
return err;
}
@@ -1349,7 +1336,7 @@
static OSStatus
SSLEncodeDHanonServerKeyExchange(SSLRecord *keyExch, SSLContext *ctx)
{
- OSStatus ortn = noErr;
+ OSStatus ortn = errSecSuccess;
int head;
assert(ctx->negProtocolVersion >= SSL_Version_3_0);
@@ -1368,7 +1355,7 @@
keyExch->protocolVersion = ctx->negProtocolVersion;
keyExch->contentType = SSL_RecordTypeHandshake;
head = SSLHandshakeHeaderSize(keyExch);
- if ((ortn = SSLAllocBuffer(&keyExch->contents, length+head, ctx)) != 0)
+ if ((ortn = SSLAllocBuffer(&keyExch->contents, length+head)))
return ortn;
uint8_t *charPtr = SSLEncodeHandshakeHeader(ctx, keyExch, SSL_HdskServerKeyExchange, length);
@@ -1380,7 +1367,7 @@
static OSStatus
SSLDecodeDHanonServerKeyExchange(SSLBuffer message, SSLContext *ctx)
{
- OSStatus err = noErr;
+ OSStatus err = errSecSuccess;
assert(ctx->protocolSide == kSSLClientSide);
if (message.length < 6) {
@@ -1390,7 +1377,7 @@
}
uint8_t *charPtr = message.data;
err = SSLDecodeDHKeyParams(ctx, &charPtr, message.length);
- if(err == noErr) {
+ if(err == errSecSuccess) {
if((message.data + message.length) != charPtr) {
err = errSSLProtocol;
}
@@ -1401,7 +1388,7 @@
static OSStatus
SSLDecodeDHClientKeyExchange(SSLBuffer keyExchange, SSLContext *ctx)
{
- OSStatus ortn = noErr;
+ OSStatus ortn = errSecSuccess;
unsigned int publicLen;
assert(ctx->protocolSide == kSSLServerSide);
@@ -1422,15 +1409,15 @@
return errSSLProtocol;
}
*/
- SSLFreeBuffer(&ctx->dhPeerPublic, ctx); // allow reuse via renegotiation
- ortn = SSLAllocBuffer(&ctx->dhPeerPublic, publicLen, ctx);
+ SSLFreeBuffer(&ctx->dhPeerPublic); // allow reuse via renegotiation
+ ortn = SSLAllocBuffer(&ctx->dhPeerPublic, publicLen);
if(ortn) {
return ortn;
}
memmove(ctx->dhPeerPublic.data, charPtr, publicLen);
/* DH Key exchange, result --> premaster secret */
- SSLFreeBuffer(&ctx->preMasterSecret, ctx);
+ SSLFreeBuffer(&ctx->preMasterSecret);
#if USE_CDSA_CRYPTO
ortn = sslDhKeyExchange(ctx, ctx->dhParamsPrime.length * 8,
&ctx->preMasterSecret);
@@ -1459,7 +1446,7 @@
outputLen = ctx->dhExchangePublic.length + 2;
head = SSLHandshakeHeaderSize(keyExchange);
- if ((err = SSLAllocBuffer(&keyExchange->contents,outputLen + head,ctx)) != 0)
+ if ((err = SSLAllocBuffer(&keyExchange->contents,outputLen + head)))
return err;
uint8_t *charPtr = SSLEncodeHandshakeHeader(ctx, keyExchange, SSL_HdskClientKeyExchange, outputLen);
@@ -1470,13 +1457,13 @@
dumpBuf("client pub key", &ctx->dhExchangePublic);
dumpBuf("client premaster", &ctx->preMasterSecret);
- return noErr;
+ return errSecSuccess;
}
#endif /* APPLE_DH */
-#pragma mark -
-#pragma mark ECDSA Key Exchange
+// MARK: -
+// MARK: ECDSA Key Exchange
/*
* Given the server's ECDH curve params and public key, generate our
@@ -1503,7 +1490,7 @@
assert(ctx->protocolSide == kSSLClientSide);
- switch(ctx->selectedCipherSpec.keyExchangeMethod) {
+ switch(ctx->selectedCipherSpecParams.keyExchangeMethod) {
case SSL_ECDHE_ECDSA:
case SSL_ECDHE_RSA:
/* Server sent us an ephemeral key with peer curve specified */
@@ -1548,7 +1535,7 @@
#if USE_CDSA_CRYPTO
//assert(ctx->cspHand != 0);
sslFreeKey(ctx->cspHand, &ctx->ecdhPrivate, NULL);
- SSLFreeBuffer(&ctx->ecdhExchangePublic, ctx);
+ SSLFreeBuffer(&ctx->ecdhExchangePublic);
ortn = SecKeyGetCSSMKey(ctx->signingPrivKeyRef, (const CSSM_KEY **)&ctx->ecdhPrivate);
if(ortn) {
return ortn;
@@ -1580,7 +1567,7 @@
if(ortn) {
return ortn;
}
- return noErr;
+ return errSecSuccess;
}
@@ -1593,7 +1580,7 @@
uint8_t **charPtr, // IN/OUT
size_t length)
{
- OSStatus err = noErr;
+ OSStatus err = errSecSuccess;
sslEcdsaDebug("+++ Decoding ECDH Server Key Exchange");
@@ -1601,7 +1588,7 @@
uint8_t *endCp = *charPtr + length;
/* Allow reuse via renegotiation */
- SSLFreeBuffer(&ctx->ecdhPeerPublic, ctx);
+ SSLFreeBuffer(&ctx->ecdhPeerPublic);
/*** ECParameters - just a curveType and a named curve ***/
@@ -1648,7 +1635,7 @@
if((*charPtr + len) > endCp) {
return errSSLProtocol;
}
- err = SSLAllocBuffer(&ctx->ecdhPeerPublic, len, ctx);
+ err = SSLAllocBuffer(&ctx->ecdhPeerPublic, len);
if(err) {
return err;
}
@@ -1696,7 +1683,7 @@
assert(ctx->negProtocolVersion >= SSL_Version_3_0);
keyExchange->protocolVersion = ctx->negProtocolVersion;
head = SSLHandshakeHeaderSize(keyExchange);
- if ((err = SSLAllocBuffer(&keyExchange->contents,outputLen + head,ctx)) != 0)
+ if ((err = SSLAllocBuffer(&keyExchange->contents,outputLen + head)))
return err;
uint8_t *charPtr = SSLEncodeHandshakeHeader(ctx, keyExchange, SSL_HdskClientKeyExchange, outputLen);
@@ -1712,16 +1699,108 @@
dumpBuf("client pub key", &ctx->ecdhExchangePublic);
dumpBuf("client premaster", &ctx->preMasterSecret);
- return noErr;
+ return errSecSuccess;
}
-#pragma mark -
-#pragma mark Public Functions
+
+
+static OSStatus
+SSLDecodePSKClientKeyExchange(SSLBuffer keyExchange, SSLContext *ctx)
+{
+ OSStatus ortn = errSecSuccess;
+ unsigned int identityLen;
+
+ assert(ctx->protocolSide == kSSLServerSide);
+
+ /* this message simply contains the client's PSK identity */
+ uint8_t *charPtr = keyExchange.data;
+ identityLen = SSLDecodeInt(charPtr, 2);
+ charPtr += 2;
+
+ SSLFreeBuffer(&ctx->pskIdentity); // allow reuse via renegotiation
+ ortn = SSLAllocBuffer(&ctx->pskIdentity, identityLen);
+ if(ortn) {
+ return ortn;
+ }
+ memmove(ctx->pskIdentity.data, charPtr, identityLen);
+
+ /* TODO: At this point we know the identity of the PSK client,
+ we should break out of the handshake, so we can select the appropriate
+ PreShared secret. As this stands, the preshared secret needs to be known
+ before the handshake starts. */
+
+ size_t n=ctx->pskSharedSecret.length;
+
+ if(n==0) return errSSLBadConfiguration;
+
+ if ((ortn = SSLAllocBuffer(&ctx->preMasterSecret, 2*(n+2))) != 0)
+ return ortn;
+
+ uint8_t *p=ctx->preMasterSecret.data;
+
+ p = SSLEncodeInt(p, n, 2);
+ memset(p, 0, n); p+=n;
+ p = SSLEncodeInt(p, n, 2);
+ memcpy(p, ctx->pskSharedSecret.data, n);
+
+ dumpBuf("server premaster (PSK)", &ctx->preMasterSecret);
+
+ return ortn;
+}
+
+
+static OSStatus
+SSLEncodePSKClientKeyExchange(SSLRecord *keyExchange, SSLContext *ctx)
+{
+ OSStatus err;
+ size_t outputLen;
+ int head;
+
+ assert(ctx->protocolSide == kSSLClientSide);
+
+ outputLen = ctx->pskIdentity.length+2;
+
+ keyExchange->contentType = SSL_RecordTypeHandshake;
+ assert(ctx->negProtocolVersion >= SSL_Version_3_0);
+ keyExchange->protocolVersion = ctx->negProtocolVersion;
+ head = SSLHandshakeHeaderSize(keyExchange);
+ if ((err = SSLAllocBuffer(&keyExchange->contents,outputLen + head)))
+ return err;
+
+ uint8_t *charPtr = SSLEncodeHandshakeHeader(ctx, keyExchange, SSL_HdskClientKeyExchange, outputLen);
+
+ charPtr = SSLEncodeSize(charPtr, ctx->pskIdentity.length, 2);
+ memcpy(charPtr, ctx->pskIdentity.data, ctx->pskIdentity.length);
+
+
+ /* We better have a pskSharedSecret already */
+ size_t n=ctx->pskSharedSecret.length;
+
+ if(n==0) return errSSLBadConfiguration;
+
+ if ((err = SSLAllocBuffer(&ctx->preMasterSecret, 2*(n+2))) != 0)
+ return err;
+
+ uint8_t *p=ctx->preMasterSecret.data;
+
+ p = SSLEncodeInt(p, n, 2);
+ memset(p, 0, n); p+=n;
+ p = SSLEncodeInt(p, n, 2);
+ memcpy(p, ctx->pskSharedSecret.data, n);
+
+ dumpBuf("client premaster (PSK)", &ctx->preMasterSecret);
+
+ return errSecSuccess;
+}
+
+
+// MARK: -
+// MARK: Public Functions
OSStatus
SSLEncodeServerKeyExchange(SSLRecord *keyExch, SSLContext *ctx)
{ OSStatus err;
-
- switch (ctx->selectedCipherSpec.keyExchangeMethod)
+
+ switch (ctx->selectedCipherSpecParams.keyExchangeMethod)
{ case SSL_RSA:
case SSL_RSA_EXPORT:
#if APPLE_DH
@@ -1741,18 +1820,18 @@
break;
#endif
default:
- return unimpErr;
+ return errSecUnimplemented;
}
- return noErr;
+ return errSecSuccess;
}
OSStatus
SSLProcessServerKeyExchange(SSLBuffer message, SSLContext *ctx)
{
OSStatus err;
-
- switch (ctx->selectedCipherSpec.keyExchangeMethod) {
+
+ switch (ctx->selectedCipherSpecParams.keyExchangeMethod) {
case SSL_RSA:
case SSL_RSA_EXPORT:
#if APPLE_DH
@@ -1772,7 +1851,7 @@
break;
#endif
default:
- err = unimpErr;
+ err = errSecUnimplemented;
break;
}
@@ -1782,10 +1861,10 @@
OSStatus
SSLEncodeKeyExchange(SSLRecord *keyExchange, SSLContext *ctx)
{ OSStatus err;
-
- assert(ctx->protocolSide == kSSLClientSide);
-
- switch (ctx->selectedCipherSpec.keyExchangeMethod) {
+
+ assert(ctx->protocolSide == kSSLClientSide);
+
+ switch (ctx->selectedCipherSpecParams.keyExchangeMethod) {
case SSL_RSA:
case SSL_RSA_EXPORT:
sslDebugLog("SSLEncodeKeyExchange: RSA method\n");
@@ -1810,10 +1889,13 @@
sslDebugLog("SSLEncodeKeyExchange: ECDH method\n");
err = SSLEncodeECDHClientKeyExchange(keyExchange, ctx);
break;
+ case TLS_PSK:
+ err = SSLEncodePSKClientKeyExchange(keyExchange, ctx);
+ break;
default:
- sslDebugLog("SSLEncodeKeyExchange: unknown method (%d)\n",
- ctx->selectedCipherSpec.keyExchangeMethod);
- err = unimpErr;
+ sslErrorLog("SSLEncodeKeyExchange: unknown method (%d)\n",
+ ctx->selectedCipherSpecParams.keyExchangeMethod);
+ err = errSecUnimplemented;
}
return err;
@@ -1822,187 +1904,66 @@
OSStatus
SSLProcessKeyExchange(SSLBuffer keyExchange, SSLContext *ctx)
{ OSStatus err;
-
- switch (ctx->selectedCipherSpec.keyExchangeMethod)
- { case SSL_RSA:
- case SSL_RSA_EXPORT:
- sslDebugLog("SSLProcessKeyExchange: processing RSA key exchange (%d)\n",
- ctx->selectedCipherSpec.keyExchangeMethod);
- if ((err = SSLDecodeRSAKeyExchange(keyExchange, ctx)) != 0)
- return err;
- break;
-#if APPLE_DH
- case SSL_DH_anon:
+
+ switch (ctx->selectedCipherSpecParams.keyExchangeMethod)
+ { case SSL_RSA:
+ case SSL_RSA_EXPORT:
+ if ((err = SSLDecodeRSAKeyExchange(keyExchange, ctx)) != 0)
+ return err;
+ break;
+ #if APPLE_DH
+ case SSL_DH_anon:
case SSL_DHE_DSS:
case SSL_DHE_DSS_EXPORT:
case SSL_DHE_RSA:
case SSL_DHE_RSA_EXPORT:
case SSL_DH_anon_EXPORT:
sslDebugLog("SSLProcessKeyExchange: processing DH key exchange (%d)\n",
- ctx->selectedCipherSpec.keyExchangeMethod);
+ ctx->selectedCipherSpecParams.keyExchangeMethod);
if ((err = SSLDecodeDHClientKeyExchange(keyExchange, ctx)) != 0)
return err;
break;
#endif
+ case TLS_PSK:
+ if ((err = SSLDecodePSKClientKeyExchange(keyExchange, ctx)) != 0)
+ return err;
+ break;
default:
sslErrorLog("SSLProcessKeyExchange: unknown keyExchangeMethod (%d)\n",
- ctx->selectedCipherSpec.keyExchangeMethod);
- return unimpErr;
+ ctx->selectedCipherSpecParams.keyExchangeMethod);
+ return errSecUnimplemented;
}
- return noErr;
+ return errSecSuccess;
}
OSStatus
SSLInitPendingCiphers(SSLContext *ctx)
{ OSStatus err;
SSLBuffer key;
- uint8_t *keyDataProgress, *keyPtr, *ivPtr;
int keyDataLen;
- CipherContext *serverPending, *clientPending;
-
+
+ err = errSecSuccess;
key.data = 0;
- ctx->readPending.macRef = ctx->selectedCipherSpec.macAlgorithm;
- ctx->writePending.macRef = ctx->selectedCipherSpec.macAlgorithm;
- ctx->readPending.symCipher = ctx->selectedCipherSpec.cipher;
- ctx->writePending.symCipher = ctx->selectedCipherSpec.cipher;
-
- if(ctx->negProtocolVersion == DTLS_Version_1_0)
- {
- ctx->readPending.sequenceNum.high = (ctx->readPending.sequenceNum.high & (0xffff<<16)) + (1<<16);
- ctx->writePending.sequenceNum.high = (ctx->writePending.sequenceNum.high & (0xffff<<16)) + (1<<16);
- } else {
- ctx->writePending.sequenceNum.high=0;
- ctx->readPending.sequenceNum.high=0;
- }
- ctx->readPending.sequenceNum.low = 0;
- ctx->writePending.sequenceNum.low = 0;
-
- keyDataLen = ctx->selectedCipherSpec.macAlgorithm->hash->digestSize +
- ctx->selectedCipherSpec.cipher->secretKeySize;
- if (ctx->selectedCipherSpec.isExportable == NotExportable)
- keyDataLen += ctx->selectedCipherSpec.cipher->ivSize;
+ keyDataLen = ctx->selectedCipherSpecParams.macSize +
+ ctx->selectedCipherSpecParams.keySize +
+ ctx->selectedCipherSpecParams.ivSize;
keyDataLen *= 2; /* two of everything */
- if ((err = SSLAllocBuffer(&key, keyDataLen, ctx)) != 0)
+ if ((err = SSLAllocBuffer(&key, keyDataLen)))
return err;
assert(ctx->sslTslCalls != NULL);
if ((err = ctx->sslTslCalls->generateKeyMaterial(key, ctx)) != 0)
goto fail;
-
- if (ctx->protocolSide == kSSLServerSide)
- { serverPending = &ctx->writePending;
- clientPending = &ctx->readPending;
- }
- else
- { serverPending = &ctx->readPending;
- clientPending = &ctx->writePending;
- }
-
- keyDataProgress = key.data;
- memcpy(clientPending->macSecret, keyDataProgress,
- ctx->selectedCipherSpec.macAlgorithm->hash->digestSize);
- keyDataProgress += ctx->selectedCipherSpec.macAlgorithm->hash->digestSize;
- memcpy(serverPending->macSecret, keyDataProgress,
- ctx->selectedCipherSpec.macAlgorithm->hash->digestSize);
- keyDataProgress += ctx->selectedCipherSpec.macAlgorithm->hash->digestSize;
-
- /* init the reusable-per-record MAC contexts */
- err = ctx->sslTslCalls->initMac(clientPending, ctx);
- if(err) {
- goto fail;
- }
- err = ctx->sslTslCalls->initMac(serverPending, ctx);
- if(err) {
- goto fail;
- }
-
- if (ctx->selectedCipherSpec.isExportable == NotExportable)
- { keyPtr = keyDataProgress;
- keyDataProgress += ctx->selectedCipherSpec.cipher->secretKeySize;
- /* Skip server write key to get to IV */
- UInt8 ivSize = ctx->selectedCipherSpec.cipher->ivSize;
-
- if (ivSize == 0)
- {
- ivPtr = NULL;
- }
- else
- {
- ivPtr = keyDataProgress + ctx->selectedCipherSpec.cipher->secretKeySize;
- }
-
- if ((err = ctx->selectedCipherSpec.cipher->initialize(keyPtr, ivPtr,
- clientPending, ctx)) != 0)
- goto fail;
- keyPtr = keyDataProgress;
- keyDataProgress += ctx->selectedCipherSpec.cipher->secretKeySize;
- /* Skip client write IV to get to server write IV */
- if (ivSize == 0)
- {
- ivPtr = NULL;
- }
- else
- {
- ivPtr = keyDataProgress + ctx->selectedCipherSpec.cipher->ivSize;
- }
-
- if ((err = ctx->selectedCipherSpec.cipher->initialize(keyPtr, ivPtr,
- serverPending, ctx)) != 0)
- goto fail;
- }
- else {
- uint8_t clientExportKey[16], serverExportKey[16],
- clientExportIV[16], serverExportIV[16];
- SSLBuffer clientWrite, serverWrite;
- SSLBuffer finalClientWrite, finalServerWrite;
- SSLBuffer finalClientIV, finalServerIV;
-
- assert(ctx->selectedCipherSpec.cipher->keySize <= 16);
- assert(ctx->selectedCipherSpec.cipher->ivSize <= 16);
-
- /* Inputs to generateExportKeyAndIv are clientRandom, serverRandom,
- * clientWriteKey, serverWriteKey. The first two are already present
- * in ctx.
- * Outputs are a key and IV for each of {server, client}.
- */
- clientWrite.data = keyDataProgress;
- clientWrite.length = ctx->selectedCipherSpec.cipher->secretKeySize;
- serverWrite.data = keyDataProgress + clientWrite.length;
- serverWrite.length = ctx->selectedCipherSpec.cipher->secretKeySize;
- finalClientWrite.data = clientExportKey;
- finalServerWrite.data = serverExportKey;
- finalClientIV.data = clientExportIV;
- finalServerIV.data = serverExportIV;
- finalClientWrite.length = 16;
- finalServerWrite.length = 16;
- /* these can be zero */
- finalClientIV.length = ctx->selectedCipherSpec.cipher->ivSize;
- finalServerIV.length = ctx->selectedCipherSpec.cipher->ivSize;
-
- assert(ctx->sslTslCalls != NULL);
- err = ctx->sslTslCalls->generateExportKeyAndIv(ctx, clientWrite, serverWrite,
- finalClientWrite, finalServerWrite, finalClientIV, finalServerIV);
- if(err) {
- goto fail;
- }
- if ((err = ctx->selectedCipherSpec.cipher->initialize(clientExportKey,
- clientExportIV, clientPending, ctx)) != 0)
- goto fail;
- if ((err = ctx->selectedCipherSpec.cipher->initialize(serverExportKey,
- serverExportIV, serverPending, ctx)) != 0)
- goto fail;
- }
-
- /* Ciphers are ready for use */
- ctx->writePending.ready = 1;
- ctx->readPending.ready = 1;
-
- /* Ciphers get swapped by sending or receiving a change cipher spec message */
-
- err = noErr;
+
+ if((err = ctx->recFuncs->initPendingCiphers(ctx->recCtx, ctx->selectedCipher, (ctx->protocolSide==kSSLServerSide), key)) != 0)
+ goto fail;
+
+ ctx->writePending_ready = 1;
+ ctx->readPending_ready = 1;
+
fail:
- SSLFreeBuffer(&key, ctx);
+ SSLFreeBuffer(&key);
return err;
}
@csm
Copy link
Author

csm commented Mar 1, 2014

This is a diff for the file libsecurity_ssl/lib/sslKeyExchange.c between revisions 55179.13 (shipped with Mac OS X 10.8.5) and 55471 (shipped with Mac OS X until 10.9.2 and iOS until 6.1.6 and 7.0.6).

The abbreviated diff above is a snippet of the full diff, confined to changes to the SSLVerifySignedServerKeyExchange function. You can see, the changes to this function are very minor; eight function calls are changed to omit the ctx argument, presumably from changes to how various functions are called. That's a minor refactoring task, pretty simple, and software engineers do it all the time. The only other change is an add of the extra goto fail statement, which caused the vulnerability.

This kind of thing could still be tracked down to a mistake, like a botched merge; from a glance, many engineers would probably not even see the bug, especially given that a lot of the changes here is from simple, boring refactoring work. However, given the light amount of changes to that function, and considering the fact that none of the trivial changes in that function are near the line where the bug was introduced, I have a hard time believing that this bug was entirely a mistake.

Disclaimer: of course, only a thorough review of the sequence of changes committed to these files could really shed light on whether it was a mistake or not. The diff above only compares two released versions of this source code, and can't tell the full story. It is, nevertheless, suspicious.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment