X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/822b670c6f91d089ccb51b77e24b6ac80406b337..dd5fb164cf5b32c462296bc65e289e100f74b59a:/OSX/libsecurity_ssl/lib/sslTransport.c?ds=sidebyside diff --git a/OSX/libsecurity_ssl/lib/sslTransport.c b/OSX/libsecurity_ssl/lib/sslTransport.c index 8bd50bca..616b9d49 100644 --- a/OSX/libsecurity_ssl/lib/sslTransport.c +++ b/OSX/libsecurity_ssl/lib/sslTransport.c @@ -31,12 +31,15 @@ #include "sslRecord.h" #include "sslDebug.h" #include "sslCipherSpecs.h" -#include "sslUtils.h" #include #include #include +#include + +#include +#include #ifndef NDEBUG static inline void sslIoTrace( @@ -57,7 +60,7 @@ extern int kSplitDefaultValue; static OSStatus SSLProcessProtocolMessage(SSLRecord *rec, SSLContext *ctx); static OSStatus SSLHandshakeProceed(SSLContext *ctx); -//static OSStatus SSLInitConnection(SSLContext *ctx); +static OSStatus SSLSendAlert(SSLContext *ctx, tls_alert_level_t level, tls_alert_t description); OSStatus SSLWrite( @@ -75,7 +78,6 @@ SSLWrite( return errSecParam; } dataLen = dataLength; - processed = 0; /* Initialize in case we return with errSSLWouldBlock */ *bytesWritten = 0; switch(ctx->state) { @@ -83,6 +85,7 @@ SSLWrite( err = errSSLClosedGraceful; goto abort; case SSL_HdskStateErrorClose: + case SSL_HdskStateOutOfBandError: err = errSSLClosedAbort; goto abort; case SSL_HdskStateReady: @@ -98,7 +101,6 @@ SSLWrite( /* First, we have to wait until the session is ready to send data, so the encryption keys and such have been established. */ - err = errSecSuccess; while (!(ctx->writeCipher_ready)) { if ((err = SSLHandshakeProceed(ctx)) != 0) goto exit; @@ -113,7 +115,6 @@ SSLWrite( /* Skip empty writes, fragmentation is done at the coreTLS layer */ if(dataLen) { rec.contentType = SSL_RecordTypeAppData; - rec.protocolVersion = ctx->negProtocolVersion; rec.contents.data = ((uint8_t *)data) + processed; rec.contents.length = dataLen; if ((err = SSLWriteRecord(rec, ctx)) != 0) @@ -133,13 +134,14 @@ exit: case errSSLUnexpectedRecord: case errSSLServerAuthCompleted: /* == errSSLClientAuthCompleted */ case errSSLClientCertRequested: - case errSSLClosedGraceful: - break; - default: - sslErrorLog("SSLWrite: going to state errorClose due to err %d\n", - (int)err); - SSLChangeHdskState(ctx, SSL_HdskStateErrorClose); - break; + case errSSLClientHelloReceived: + case errSSLClosedGraceful: + break; + default: + sslErrorLog("SSLWrite: going to state errorClose due to err %d\n", + (int)err); + SSLChangeHdskState(ctx, SSL_HdskStateErrorClose); + break; } abort: sslIoTrace(ctx, "SSLWrite(2)", dataLength, *bytesWritten, err); @@ -172,6 +174,7 @@ readRetry: err = errSSLClosedGraceful; goto abort; case SSL_HdskStateErrorClose: + case SSL_HdskStateOutOfBandError: err = errSSLClosedAbort; goto abort; case SSL_HdskStateNoNotifyClose: @@ -183,25 +186,31 @@ readRetry: /* First, we have to wait until the session is ready to receive data, so the encryption keys and such have been established. */ - err = errSecSuccess; while (ctx->readCipher_ready == 0) { if ((err = SSLHandshakeProceed(ctx)) != 0) { goto exit; } } + /* Need this to handle the case were SSLRead returned + errSSLClientHelloReceived as readCipher_ready is not set yet in that case */ + if ((err = tls_handshake_continue(ctx->hdsk)) != 0) + return err; + /* Attempt to service the write queue */ if ((err = SSLServiceWriteQueue(ctx)) != 0) { if (err != errSSLWouldBlock) { goto exit; } - err = errSecSuccess; /* Write blocking shouldn't stop attempts to read */ } remaining = bufSize; charPtr = (uint8_t *)data; + + /* If we have data in the buffer, use that first */ if (ctx->receivedDataBuffer.data) - { count = ctx->receivedDataBuffer.length - ctx->receivedDataPos; + { + count = ctx->receivedDataBuffer.length - ctx->receivedDataPos; if (count > bufSize) count = bufSize; memcpy(data, ctx->receivedDataBuffer.data + ctx->receivedDataPos, count); @@ -217,29 +226,27 @@ readRetry: if (ctx->receivedDataBuffer.data != 0 && ctx->receivedDataPos >= ctx->receivedDataBuffer.length) - { SSLFreeBuffer(&ctx->receivedDataBuffer); + { + SSLFreeBuffer(&ctx->receivedDataBuffer); ctx->receivedDataBuffer.data = 0; ctx->receivedDataPos = 0; } /* - * This while statement causes a hang when using nonblocking low-level I/O! - while (remaining > 0 && ctx->state != SSL_HdskStateGracefulClose) - ..what we really have to do is just return as soon as we read one - record. A performance hit in the nonblocking case, but that is - the only way this code can work in both modes... + * If we didnt fill up the users buffer, get some more data */ if (remaining > 0 && ctx->state != SSL_HdskStateGracefulClose) - { assert(ctx->receivedDataBuffer.data == 0); + { + assert(ctx->receivedDataBuffer.data == 0); if ((err = SSLReadRecord(&rec, ctx)) != 0) { goto exit; } if (rec.contentType == SSL_RecordTypeAppData || rec.contentType == SSL_RecordTypeV2_0) - { if (rec.contents.length <= remaining) - { memcpy(charPtr, rec.contents.data, rec.contents.length); - remaining -= rec.contents.length; - charPtr += rec.contents.length; + { + if (rec.contents.length <= remaining) + { /* Copy all we got in the user's buffer */ + memcpy(charPtr, rec.contents.data, rec.contents.length); *processed += rec.contents.length; { if ((err = SSLFreeRecord(rec, ctx))) { @@ -248,12 +255,11 @@ readRetry: } } else - { memcpy(charPtr, rec.contents.data, remaining); - charPtr += remaining; + { /* Copy what we can in the user's buffer, keep the rest for next SSLRead. */ + memcpy(charPtr, rec.contents.data, remaining); *processed += remaining; ctx->receivedDataBuffer = rec.contents; ctx->receivedDataPos = remaining; - remaining = 0; } } else { @@ -262,7 +268,7 @@ readRetry: process the write queue. This replicate exactly the behavior before the coreTLS adoption */ if(err == errSSLClosedGraceful) { - err = SSLClose(ctx); + SSLClose(ctx); } else { goto exit; } @@ -282,20 +288,21 @@ exit: goto readRetry; } /* shut down on serious errors */ - switch(err) { - case errSecSuccess: - case errSSLWouldBlock: + switch(err) { + case errSecSuccess: + case errSSLWouldBlock: case errSSLUnexpectedRecord: - case errSSLServerAuthCompleted: /* == errSSLClientAuthCompleted */ - case errSSLClientCertRequested: - case errSSLClosedGraceful: - case errSSLClosedNoNotify: - break; - default: - sslErrorLog("SSLRead: going to state errorClose due to err %d\n", - (int)err); - SSLChangeHdskState(ctx, SSL_HdskStateErrorClose); - break; + case errSSLServerAuthCompleted: /* == errSSLClientAuthCompleted */ + case errSSLClientCertRequested: + case errSSLClientHelloReceived: + case errSSLClosedGraceful: + case errSSLClosedNoNotify: + break; + default: + sslErrorLog("SSLRead: going to state errorClose due to err %d\n", + (int)err); + SSLChangeHdskState(ctx, SSL_HdskStateErrorClose); + break; } abort: sslIoTrace(ctx, "SSLRead returns", dataLength, *processed, err); @@ -306,6 +313,90 @@ abort: #include "sslCrypto.h" #endif + + +static void get_extended_peer_id(SSLContext *ctx, tls_buffer *extended_peer_id) +{ + uint8_t md[CC_SHA256_DIGEST_LENGTH]; + __block CC_SHA256_CTX hash_ctx; + + CC_SHA256_Init(&hash_ctx); + + CC_SHA256_Update(&hash_ctx, &ctx->allowAnyRoot, sizeof(ctx->allowAnyRoot)); + +#if !TARGET_OS_IPHONE + if(ctx->trustedLeafCerts) { + CFArrayForEach(ctx->trustedLeafCerts, ^(const void *value) { + SecCertificateRef cert = (SecCertificateRef) value; + CC_SHA256_Update(&hash_ctx, SecCertificateGetBytePtr(cert), (CC_LONG)SecCertificateGetLength(cert)); + }); + } +#endif + + CC_SHA256_Update(&hash_ctx, &ctx->trustedCertsOnly, sizeof(ctx->trustedCertsOnly)); + + + if(ctx->trustedCerts) { + CFArrayForEach(ctx->trustedCerts, ^(const void *value) { + SecCertificateRef cert = (SecCertificateRef) value; + CC_SHA256_Update(&hash_ctx, SecCertificateGetBytePtr(cert), (CC_LONG)SecCertificateGetLength(cert)); + }); + } + + CC_SHA256_Final(md, &hash_ctx); + + extended_peer_id->length = ctx->peerID.length + sizeof(md); + extended_peer_id->data = sslMalloc(extended_peer_id->length); + memcpy(extended_peer_id->data, ctx->peerID.data, ctx->peerID.length); + memcpy(extended_peer_id->data+ctx->peerID.length, md, sizeof(md)); +} + +/* Send the initial client hello */ +static OSStatus +SSLHandshakeStart(SSLContext *ctx) +{ + int err; + tls_buffer extended_peer_id; + get_extended_peer_id(ctx, &extended_peer_id); + err = tls_handshake_negotiate(ctx->hdsk, &extended_peer_id); + free(extended_peer_id.data); + if(err) + return err; + + ctx->readCipher_ready = 0; + ctx->writeCipher_ready = 0; + SSLChangeHdskState(ctx, SSL_HdskStatePending); + + return noErr; +} + +OSStatus +SSLReHandshake(SSLContext *ctx) +{ + if(ctx == NULL) { + return errSecParam; + } + + switch (ctx->state) { + case SSL_HdskStateGracefulClose: + return errSSLClosedGraceful; + case SSL_HdskStateErrorClose: + case SSL_HdskStateOutOfBandError: + return errSSLClosedAbort; + case SSL_HdskStatePending: + return errSecBadReq; + default: + break; + } + + /* If we are the client, we start the negotiation */ + if(ctx->protocolSide == kSSLClientSide) { + return SSLHandshakeStart(ctx); + } else { + return tls_handshake_request_renegotiation(ctx->hdsk); + } +} + OSStatus SSLHandshake(SSLContext *ctx) { @@ -314,12 +405,15 @@ SSLHandshake(SSLContext *ctx) if(ctx == NULL) { return errSecParam; } - if (ctx->state == SSL_HdskStateGracefulClose) - return errSSLClosedGraceful; - if (ctx->state == SSL_HdskStateErrorClose) - return errSSLClosedAbort; - err = errSecSuccess; + switch (ctx->state) { + case SSL_HdskStateGracefulClose: + return errSSLClosedGraceful; + case SSL_HdskStateErrorClose: + return errSSLClosedAbort; + default: + break; + } if(ctx->isDTLS && ctx->timeout_deadline) { CFAbsoluteTime current = CFAbsoluteTimeGetCurrent(); @@ -333,12 +427,44 @@ SSLHandshake(SSLContext *ctx) } } - while (ctx->readCipher_ready == 0 || ctx->writeCipher_ready == 0) - { + /* Initial Client Hello */ + if(ctx->state==SSL_HdskStateUninit) { + /* If we are the client, we start the negotiation */ + if(ctx->protocolSide == kSSLClientSide) { + err = SSLHandshakeStart(ctx); + if(err) { + return err; + } + } + SSLChangeHdskState(ctx, SSL_HdskStatePending); + } + + /* If an out-of-band error occurred, handle it here and then terminate + the connection as needed. */ + if (ctx->state == SSL_HdskStateOutOfBandError) { + bool shouldClose = true; + switch (ctx->outOfBandError) { + case errSecCertificateExpired: + SSLSendAlert(ctx, tls_handshake_alert_level_fatal, tls_handshake_alert_CertExpired); + break; + case errSecCertificateRevoked: + SSLSendAlert(ctx, tls_handshake_alert_level_fatal, tls_handshake_alert_CertRevoked); + break; + default: + shouldClose = false; + break; + } + + if (shouldClose) { + return SSLClose(ctx); + } + } + + do { err = SSLHandshakeProceed(ctx); if((err != 0) && (err != errSSLUnexpectedRecord)) return err; - } + } while (ctx->readCipher_ready == 0 || ctx->writeCipher_ready == 0); /* one more flush at completion of successful handshake */ if ((err = SSLServiceWriteQueue(ctx)) != 0) { @@ -350,50 +476,14 @@ SSLHandshake(SSLContext *ctx) #if (TARGET_OS_IPHONE && !TARGET_IPHONE_SIMULATOR) -#include - -typedef void (*type_ADClientAddValueForScalarKey)(CFStringRef key, int64_t value); -static type_ADClientAddValueForScalarKey gADClientAddValueForScalarKey = NULL; -static dispatch_once_t gADFunctionPointersSet = 0; -static CFBundleRef gAggdBundleRef = NULL; - -static bool InitializeADFunctionPointers() -{ - if (gADClientAddValueForScalarKey) - { - return true; - } - - dispatch_once(&gADFunctionPointersSet, - ^{ - CFStringRef path_to_aggd_framework = CFSTR("/System/Library/PrivateFrameworks/AggregateDictionary.framework"); - - CFURLRef aggd_url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path_to_aggd_framework, kCFURLPOSIXPathStyle, true); - - if (NULL != aggd_url) - { - gAggdBundleRef = CFBundleCreate(kCFAllocatorDefault, aggd_url); - if (NULL != gAggdBundleRef) - { - gADClientAddValueForScalarKey = (type_ADClientAddValueForScalarKey) - CFBundleGetFunctionPointerForName(gAggdBundleRef, CFSTR("ADClientAddValueForScalarKey")); - } - CFRelease(aggd_url); - } - }); - - return (gADClientAddValueForScalarKey!=NULL); -} +#include "SecADWrapper.h" static void ad_log_SecureTransport_early_fail(long signature) { - if (InitializeADFunctionPointers()) { - - CFStringRef key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("com.apple.SecureTransport.early_fail.%ld"), signature); - - if(key) - gADClientAddValueForScalarKey(key, 1); + CFStringRef key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("com.apple.SecureTransport.early_fail.%ld"), signature); + if (key) { + SecADAddValueForScalarKey(key, 1); CFRelease(key); } } @@ -431,22 +521,12 @@ static void log_SecureTransport_early_fail(long signature) #endif } + static OSStatus SSLHandshakeProceed(SSLContext *ctx) { OSStatus err; - - if(ctx->state==SSL_HdskStateUninit) { - /* If we are the client, we start the negotiation */ - if(ctx->protocolSide == kSSLClientSide) { - err = tls_handshake_negotiate(ctx->hdsk, &ctx->peerID); - if(err) - return err; - } - SSLChangeHdskState(ctx, SSL_HdskStatePending); - } - if ((err = tls_handshake_continue(ctx->hdsk)) != 0) return err; @@ -499,11 +579,30 @@ SSLClose(SSLContext *ctx) err = SSLServiceWriteQueue(ctx); SSLChangeHdskState(ctx, SSL_HdskStateGracefulClose); - if (err == errSecIO) + if (err == errSecIO) err = errSecSuccess; /* Ignore errors related to closed streams */ return err; } +static OSStatus +SSLSendAlert(SSLContext *ctx, tls_alert_level_t alertLevel, tls_alert_t alert) +{ + sslHdskStateDebug("SSLSendAlert"); + if (ctx == NULL) { + return errSecParam; + } + + return tls_handshake_send_alert(ctx->hdsk, alertLevel, alert); +} + +OSStatus +SSLSetError(SSLContext *ctx, OSStatus error) +{ + ctx->state = SSL_HdskStateOutOfBandError; + ctx->outOfBandError = error; + return errSecSuccess; +} + /* * Determine how much data the client can be guaranteed to * obtain via SSLRead() without blocking or causing any low-level