X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/b1ab9ed8d0e0f1c3b66d7daa8fd5564444c56195..e3d3b979fd185d8303f28a937baa53a187fb8c7d:/libsecurity_ssl/lib/ssl3Callouts.c?ds=inline diff --git a/libsecurity_ssl/lib/ssl3Callouts.c b/libsecurity_ssl/lib/ssl3Callouts.c index 3b9f18f1..dc32edfb 100644 --- a/libsecurity_ssl/lib/ssl3Callouts.c +++ b/libsecurity_ssl/lib/ssl3Callouts.c @@ -36,349 +36,6 @@ #include #include -/* - * ssl3WriteRecord does not send alerts on failure, out of the assumption/fear - * that this might result in a loop (since sending an alert causes ssl3WriteRecord - * to be called). - * - * As far as I can tell, we can use this same routine for SSLv3 and TLSv1, as long - * as we're not trying to use the "variable length padding" feature of TLSv1. - * OpenSSL doesn't use that feature; for now, neither will we. Thus this routine - * is used for the SslTlsCallouts.writeRecord function for both protocols. - */ -OSStatus ssl3WriteRecord( - SSLRecord rec, - SSLContext *ctx) -{ - OSStatus err; - int padding = 0, i; - WaitingRecord *out = NULL, *queue; - SSLBuffer payload, mac; - UInt8 *charPtr; - UInt16 payloadSize,blockSize; - int head = 5; - - switch(rec.protocolVersion) { - case DTLS_Version_1_0: - head += 8; - case SSL_Version_3_0: - case TLS_Version_1_0: - case TLS_Version_1_1: - case TLS_Version_1_2: - break; - default: - assert(0); - return errSSLInternal; - } - assert(rec.contents.length <= 16384); - - sslLogRecordIo("type = %02x, ver = %04x, len = %ld, seq = %08x_%08x", - rec.contentType, rec.protocolVersion, rec.contents.length, - ctx->writeCipher.sequenceNum.high, ctx->writeCipher.sequenceNum.low); - - /* Allocate enough room for the transmitted record, which will be: - * 5 bytes of header (13 for DTLS) + - * IV [block cipher and TLS1.1 or DTLS 1.0 only] - * encrypted contents + - * macLength + - * padding [block ciphers only] + - * padding length field (1 byte) [block ciphers only] - */ - payloadSize = (UInt16) (rec.contents.length + ctx->writeCipher.macRef->hash->digestSize); - blockSize = ctx->writeCipher.symCipher->blockSize; - if (blockSize > 0) - { - padding = blockSize - (payloadSize % blockSize) - 1; - payloadSize += padding + 1; - /* TLS 1.1 and DTLS 1.0 have an extra block for IV */ - if(ctx->negProtocolVersion >= TLS_Version_1_1) { - payloadSize += blockSize; - } - } - - out = (WaitingRecord *)sslMalloc(offsetof(WaitingRecord, data) + - head + payloadSize); - out->next = NULL; - out->sent = 0; - out->length = head + payloadSize; - - charPtr = out->data; - *(charPtr++) = rec.contentType; - charPtr = SSLEncodeInt(charPtr, rec.protocolVersion, 2); - - /* DTLS sequence number */ - if(rec.protocolVersion == DTLS_Version_1_0) - charPtr = SSLEncodeUInt64(charPtr,ctx->writeCipher.sequenceNum); - - charPtr = SSLEncodeInt(charPtr, payloadSize, 2); - - /* Also for DTLS */ - if((ctx->negProtocolVersion >= TLS_Version_1_1) && (blockSize>0)) - { - SSLBuffer randomIV; - randomIV.data = charPtr; - randomIV.length = blockSize; - if((err = sslRand(ctx, &randomIV)) != 0) - return err; - charPtr += blockSize; - } - - /* Copy the contents into the output buffer */ - memcpy(charPtr, rec.contents.data, rec.contents.length); - payload.data = charPtr; - payload.length = rec.contents.length; - - charPtr += rec.contents.length; - /* MAC immediately follows data */ - mac.data = charPtr; - mac.length = ctx->writeCipher.macRef->hash->digestSize; - charPtr += mac.length; - - /* MAC the data */ - if (mac.length > 0) /* Optimize away null case */ - { - assert(ctx->sslTslCalls != NULL); - if ((err = ctx->sslTslCalls->computeMac(rec.contentType, - payload, - mac, - &ctx->writeCipher, - ctx->writeCipher.sequenceNum, - ctx)) != 0) - goto fail; - } - - /* For TLS 1.1 and DTLS, we would need to specify the IV, but instead - we are clever like this: since the IV is just one block in front, - we encrypt it with the rest of the data. The actual transmitted IV - is the result of the encryption, with whatever internal IV is used. - This method is explained in the TLS 1.1 RFC */ - if(ctx->negProtocolVersion >= TLS_Version_1_1) - { - if(blockSize > 0) - payload.data -= blockSize; - } - - /* Update payload to reflect encrypted data: IV, contents, mac & padding */ - payload.length = payloadSize; - - /* Fill in the padding bytes & padding length field with the padding value; the - * protocol only requires the last byte, - * but filling them all in avoids leaking data - */ - if (ctx->writeCipher.symCipher->blockSize > 0) - for (i = 1; i <= padding + 1; ++i) - payload.data[payload.length - i] = padding; - - /* Encrypt the data */ - if ((err = ctx->writeCipher.symCipher->encrypt(payload.data, - payload.data, payload.length, - &ctx->writeCipher, - ctx)) != 0) - goto fail; - - /* Enqueue the record to be written from the idle loop */ - if (ctx->recordWriteQueue == 0) - ctx->recordWriteQueue = out; - else - { queue = ctx->recordWriteQueue; - while (queue->next != 0) - queue = queue->next; - queue->next = out; - } - - /* Increment the sequence number */ - IncrementUInt64(&ctx->writeCipher.sequenceNum); - - return noErr; - -fail: - /* - * Only for if we fail between when the WaitingRecord is allocated and when - * it is queued - */ - sslFree(out); - return err; -} - -static OSStatus ssl3DecryptRecord( - UInt8 type, - SSLBuffer *payload, - SSLContext *ctx) -{ - OSStatus err; - SSLBuffer content; - - if ((ctx->readCipher.symCipher->blockSize > 0) && - ((payload->length % ctx->readCipher.symCipher->blockSize) != 0)) - { SSLFatalSessionAlert(SSL_AlertUnexpectedMsg, ctx); - return errSSLProtocol; - } - - /* Decrypt in place */ - if ((err = ctx->readCipher.symCipher->decrypt(payload->data, - payload->data, payload->length, - &ctx->readCipher, - ctx)) != 0) - { - /* Complies with TLS 1.1 - But we do it for every protocol version */ - SSLFatalSessionAlert(SSL_AlertBadRecordMac, ctx); - return err; - } - - /* Locate content within decrypted payload */ - content.data = payload->data; - content.length = payload->length - ctx->readCipher.macRef->hash->digestSize; - if (ctx->readCipher.symCipher->blockSize > 0) - { /* padding can't be equal to or more than a block */ - if (payload->data[payload->length - 1] >= ctx->readCipher.symCipher->blockSize) - { - /* Complies with TLS 1.1 - But we do it for every protocol version */ - SSLFatalSessionAlert(SSL_AlertBadRecordMac, ctx); - sslErrorLog("DecryptSSLRecord: bad padding length (%d)\n", - (unsigned)payload->data[payload->length - 1]); - return errSSLDecryptionFail; - } - content.length -= 1 + payload->data[payload->length - 1]; - /* Remove block size padding */ - } - - /* Verify MAC on payload */ - if (ctx->readCipher.macRef->hash->digestSize > 0) - /* Optimize away MAC for null case */ - if ((err = SSLVerifyMac(type, &content, - payload->data + content.length, ctx)) != 0) - { SSLFatalSessionAlert(SSL_AlertBadRecordMac, ctx); - return errSSLBadRecordMac; - } - - *payload = content; /* Modify payload buffer to indicate content length */ - - return noErr; -} - -/* initialize a per-CipherContext HashHmacContext for use in MACing each record */ -static OSStatus ssl3InitMac ( - CipherContext *cipherCtx, // macRef, macSecret valid on entry - // macCtx valid on return - SSLContext *ctx) -{ - const HashReference *hash; - SSLBuffer *hashCtx; - OSStatus serr; - - assert(cipherCtx->macRef != NULL); - hash = cipherCtx->macRef->hash; - assert(hash != NULL); - - hashCtx = &cipherCtx->macCtx.hashCtx; - if(hashCtx->data != NULL) { - SSLFreeBuffer(hashCtx, ctx); - } - serr = SSLAllocBuffer(hashCtx, hash->contextSize, ctx); - if(serr) { - return serr; - } - return noErr; -} - -static OSStatus ssl3FreeMac ( - CipherContext *cipherCtx) -{ - SSLBuffer *hashCtx; - - assert(cipherCtx != NULL); - /* this can be called on a completely zeroed out CipherContext... */ - if(cipherCtx->macRef == NULL) { - return noErr; - } - hashCtx = &cipherCtx->macCtx.hashCtx; - if(hashCtx->data != NULL) { - sslFree(hashCtx->data); - hashCtx->data = NULL; - } - hashCtx->length = 0; - return noErr; -} - -static OSStatus ssl3ComputeMac ( - UInt8 type, - SSLBuffer data, - SSLBuffer mac, // caller mallocs data - CipherContext *cipherCtx, // assumes macCtx, macRef - sslUint64 seqNo, - SSLContext *ctx) -{ - OSStatus err; - UInt8 innerDigestData[SSL_MAX_DIGEST_LEN]; - UInt8 scratchData[11], *charPtr; - SSLBuffer digest, digestCtx, scratch; - SSLBuffer secret; - - const HashReference *hash; - - assert(cipherCtx != NULL); - assert(cipherCtx->macRef != NULL); - hash = cipherCtx->macRef->hash; - assert(hash != NULL); - assert(hash->macPadSize <= MAX_MAC_PADDING); - assert(hash->digestSize <= SSL_MAX_DIGEST_LEN); - digestCtx = cipherCtx->macCtx.hashCtx; // may be NULL, for null cipher - secret.data = cipherCtx->macSecret; - secret.length = hash->digestSize; - - /* init'd early in SSLNewContext() */ - assert(SSLMACPad1[0] == 0x36 && SSLMACPad2[0] == 0x5C); - - /* - * MAC = hash( MAC_write_secret + pad_2 + - * hash( MAC_write_secret + pad_1 + seq_num + type + - * length + content ) - * ) - */ - if ((err = hash->init(&digestCtx, ctx)) != 0) - goto exit; - if ((err = hash->update(&digestCtx, &secret)) != 0) /* MAC secret */ - goto exit; - scratch.data = (UInt8 *)SSLMACPad1; - scratch.length = hash->macPadSize; - if ((err = hash->update(&digestCtx, &scratch)) != 0) /* pad1 */ - goto exit; - charPtr = scratchData; - charPtr = SSLEncodeUInt64(charPtr, seqNo); - *charPtr++ = type; - charPtr = SSLEncodeSize(charPtr, data.length, 2); - scratch.data = scratchData; - scratch.length = 11; - assert(charPtr = scratchData+11); - if ((err = hash->update(&digestCtx, &scratch)) != 0) - /* sequenceNo, type & length */ - goto exit; - if ((err = hash->update(&digestCtx, &data)) != 0) /* content */ - goto exit; - digest.data = innerDigestData; - digest.length = hash->digestSize; - if ((err = hash->final(&digestCtx, &digest)) != 0) /* figure inner digest */ - goto exit; - - if ((err = hash->init(&digestCtx, ctx)) != 0) - goto exit; - if ((err = hash->update(&digestCtx, &secret)) != 0) /* MAC secret */ - goto exit; - scratch.data = (UInt8 *)SSLMACPad2; - scratch.length = hash->macPadSize; - if ((err = hash->update(&digestCtx, &scratch)) != 0) /* pad2 */ - goto exit; - if ((err = hash->update(&digestCtx, &digest)) != 0) /* inner digest */ - goto exit; - if ((err = hash->final(&digestCtx, &mac)) != 0) /* figure the mac */ - goto exit; - - err = noErr; /* redundant, I know */ - -exit: - return err; -} - #define LOG_GEN_KEY 0 /* @@ -436,11 +93,11 @@ static OSStatus ssl3GenerateKeyMaterial ( md5Context.data = 0; shaContext.data = 0; - if ((err = ReadyHash(&SSLHashMD5, &md5Context, ctx)) != 0) - goto fail; - if ((err = ReadyHash(&SSLHashSHA1, &shaContext, ctx)) != 0) + if ((err = ReadyHash(&SSLHashMD5, &md5Context)) != 0) goto fail; - + if ((err = ReadyHash(&SSLHashSHA1, &shaContext)) != 0) + goto fail; + keyProgress = key.data; remaining = key.length; @@ -475,103 +132,25 @@ static OSStatus ssl3GenerateKeyMaterial ( if(remaining > 0) { /* at top of loop, this was done in ReadyHash() */ - if ((err = SSLHashMD5.init(&md5Context, ctx)) != 0) + if ((err = SSLHashMD5.init(&md5Context)) != 0) goto fail; - if ((err = SSLHashSHA1.init(&shaContext, ctx)) != 0) + if ((err = SSLHashSHA1.init(&shaContext)) != 0) goto fail; } } assert(remaining == 0 && keyProgress == (key.data + key.length)); - err = noErr; + err = errSecSuccess; fail: - SSLFreeBuffer(&md5Context, ctx); - SSLFreeBuffer(&shaContext, ctx); - + SSLFreeBuffer(&md5Context); + SSLFreeBuffer(&shaContext); + #if LOG_GEN_KEY printf("GenerateKey: DONE\n"); #endif return err; } -static OSStatus ssl3GenerateExportKeyAndIv ( - SSLContext *ctx, // clientRandom, serverRandom valid - const SSLBuffer clientWriteKey, - const SSLBuffer serverWriteKey, - SSLBuffer finalClientWriteKey, // RETURNED, mallocd by caller - SSLBuffer finalServerWriteKey, // RETURNED, mallocd by caller - SSLBuffer finalClientIV, // RETURNED, mallocd by caller - SSLBuffer finalServerIV) // RETURNED, mallocd by caller -{ - OSStatus err; - SSLBuffer hashCtx, serverRandom, clientRandom; - - /* random blobs are 32 bytes */ - serverRandom.data = ctx->serverRandom; - serverRandom.length = SSL_CLIENT_SRVR_RAND_SIZE; - clientRandom.data = ctx->clientRandom; - clientRandom.length = SSL_CLIENT_SRVR_RAND_SIZE; - - if ((err = SSLAllocBuffer(&hashCtx, SSLHashMD5.contextSize, ctx)) != 0) - return err; - /* client write key */ - if ((err = SSLHashMD5.init(&hashCtx, ctx)) != 0) - goto fail; - if ((err = SSLHashMD5.update(&hashCtx, &clientWriteKey)) != 0) - goto fail; - if ((err = SSLHashMD5.update(&hashCtx, &clientRandom)) != 0) - goto fail; - if ((err = SSLHashMD5.update(&hashCtx, &serverRandom)) != 0) - goto fail; - finalClientWriteKey.length = 16; - if ((err = SSLHashMD5.final(&hashCtx, &finalClientWriteKey)) != 0) - goto fail; - - /* optional client IV */ - if (ctx->selectedCipherSpec.cipher->ivSize > 0) - { if ((err = SSLHashMD5.init(&hashCtx, ctx)) != 0) - goto fail; - if ((err = SSLHashMD5.update(&hashCtx, &clientRandom)) != 0) - goto fail; - if ((err = SSLHashMD5.update(&hashCtx, &serverRandom)) != 0) - goto fail; - finalClientIV.length = 16; - if ((err = SSLHashMD5.final(&hashCtx, &finalClientIV)) != 0) - goto fail; - } - - /* server write key */ - if ((err = SSLHashMD5.init(&hashCtx, ctx)) != 0) - goto fail; - if ((err = SSLHashMD5.update(&hashCtx, &serverWriteKey)) != 0) - goto fail; - if ((err = SSLHashMD5.update(&hashCtx, &serverRandom)) != 0) - goto fail; - if ((err = SSLHashMD5.update(&hashCtx, &clientRandom)) != 0) - goto fail; - finalServerWriteKey.length = 16; - if ((err = SSLHashMD5.final(&hashCtx, &finalServerWriteKey)) != 0) - goto fail; - - /* optional server IV */ - if (ctx->selectedCipherSpec.cipher->ivSize > 0) - { if ((err = SSLHashMD5.init(&hashCtx, ctx)) != 0) - goto fail; - if ((err = SSLHashMD5.update(&hashCtx, &serverRandom)) != 0) - goto fail; - if ((err = SSLHashMD5.update(&hashCtx, &clientRandom)) != 0) - goto fail; - finalServerIV.length = 16; - if ((err = SSLHashMD5.final(&hashCtx, &finalServerIV)) != 0) - goto fail; - } - - err = noErr; -fail: - SSLFreeBuffer(&hashCtx, ctx); - return err; -} - /* * On entry: clientRandom, serverRandom, preMasterSecret valid * On return: masterSecret valid @@ -586,9 +165,9 @@ static OSStatus ssl3GenerateMasterSecret ( int i; md5State.data = shaState.data = 0; - if ((err = SSLAllocBuffer(&md5State, SSLHashMD5.contextSize, ctx)) != 0) + if ((err = SSLAllocBuffer(&md5State, SSLHashMD5.contextSize))) goto fail; - if ((err = SSLAllocBuffer(&shaState, SSLHashSHA1.contextSize, ctx)) != 0) + if ((err = SSLAllocBuffer(&shaState, SSLHashSHA1.contextSize))) goto fail; clientRandom.data = ctx->clientRandom; @@ -601,9 +180,9 @@ static OSStatus ssl3GenerateMasterSecret ( masterProgress = ctx->masterSecret; for (i = 1; i <= 3; i++) - { if ((err = SSLHashMD5.init(&md5State, ctx)) != 0) + { if ((err = SSLHashMD5.init(&md5State)) != 0) goto fail; - if ((err = SSLHashSHA1.init(&shaState, ctx)) != 0) + if ((err = SSLHashSHA1.init(&shaState)) != 0) goto fail; leaderData[0] = leaderData[1] = leaderData[2] = 0x40 + i; /* 'A', 'B', etc. */ @@ -631,10 +210,10 @@ static OSStatus ssl3GenerateMasterSecret ( masterProgress += 16; } - err = noErr; + err = errSecSuccess; fail: - SSLFreeBuffer(&shaState, ctx); - SSLFreeBuffer(&md5State, ctx); + SSLFreeBuffer(&shaState); + SSLFreeBuffer(&md5State); return err; } @@ -683,9 +262,9 @@ ssl3CalculateFinishedMessage( hash.length = 20; if ((err = SSLHashSHA1.final(&shaMsgState, &hash)) != 0) goto fail; - if ((err = SSLHashMD5.init(&md5MsgState, ctx)) != 0) + if ((err = SSLHashMD5.init(&md5MsgState)) != 0) goto fail; - if ((err = SSLHashSHA1.init(&shaMsgState, ctx)) != 0) + if ((err = SSLHashSHA1.init(&shaMsgState)) != 0) goto fail; input.data = ctx->masterSecret; input.length = SSL_MASTER_SECRET_SIZE; @@ -732,17 +311,17 @@ static OSStatus ssl3ComputeFinishedMac ( shaMsgState.data = 0; md5MsgState.data = 0; - if ((serr = CloneHashState(&SSLHashSHA1, &ctx->shaState, &shaMsgState, ctx)) != 0) + if ((serr = CloneHashState(&SSLHashSHA1, &ctx->shaState, &shaMsgState)) != 0) goto fail; - if ((serr = CloneHashState(&SSLHashMD5, &ctx->md5State, &md5MsgState, ctx)) != 0) + if ((serr = CloneHashState(&SSLHashMD5, &ctx->md5State, &md5MsgState)) != 0) goto fail; serr = ssl3CalculateFinishedMessage(ctx, finished, shaMsgState, md5MsgState, isServer ? SSL_Finished_Sender_Server : SSL_Finished_Sender_Client); fail: - SSLFreeBuffer(&shaMsgState, ctx); - SSLFreeBuffer(&md5MsgState, ctx); + SSLFreeBuffer(&shaMsgState); + SSLFreeBuffer(&md5MsgState); return serr; } @@ -758,9 +337,9 @@ static OSStatus ssl3ComputeCertVfyMac ( shaMsgState.data = 0; md5MsgState.data = 0; - if ((serr = CloneHashState(&SSLHashSHA1, &ctx->shaState, &shaMsgState, ctx)) != 0) + if ((serr = CloneHashState(&SSLHashSHA1, &ctx->shaState, &shaMsgState)) != 0) goto fail; - if ((serr = CloneHashState(&SSLHashMD5, &ctx->md5State, &md5MsgState, ctx)) != 0) + if ((serr = CloneHashState(&SSLHashMD5, &ctx->md5State, &md5MsgState)) != 0) goto fail; assert(finished->length >= SSL_MD5_DIGEST_LEN + SSL_SHA1_DIGEST_LEN); @@ -769,20 +348,14 @@ static OSStatus ssl3ComputeCertVfyMac ( serr = ssl3CalculateFinishedMessage(ctx, *finished, shaMsgState, md5MsgState, 0); fail: - SSLFreeBuffer(&shaMsgState, ctx); - SSLFreeBuffer(&md5MsgState, ctx); + SSLFreeBuffer(&shaMsgState); + SSLFreeBuffer(&md5MsgState); return serr; } const SslTlsCallouts Ssl3Callouts = { - ssl3DecryptRecord, - ssl3WriteRecord, - ssl3InitMac, - ssl3FreeMac, - ssl3ComputeMac, ssl3GenerateKeyMaterial, - ssl3GenerateExportKeyAndIv, ssl3GenerateMasterSecret, ssl3ComputeFinishedMac, ssl3ComputeCertVfyMac