X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/Security/libsecurity_ssl/regressions/ssl-48-split.c diff --git a/Security/libsecurity_ssl/regressions/ssl-48-split.c b/Security/libsecurity_ssl/regressions/ssl-48-split.c new file mode 100644 index 00000000..940628d3 --- /dev/null +++ b/Security/libsecurity_ssl/regressions/ssl-48-split.c @@ -0,0 +1,357 @@ +// +// ssl-48-crashes.c +// libsecurity_ssl +// +// + + +#include +#include +#include +#include +#include + +#include + +#include +#include /* SSLSetOption */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#if TARGET_OS_IPHONE +#include +#endif + +#include "ssl_regressions.h" +#include "ssl-utils.h" + +#include + + +typedef struct { + SSLContextRef st; + bool is_server; + int comm; + CFArrayRef certs; + int write_counter; + tls_stream_parser_t parser; + size_t write_size; +} ssl_test_handle; + + +#pragma mark - +#pragma mark SecureTransport support + +#if 0 +static void hexdump(const char *s, const uint8_t *bytes, size_t len) { + size_t ix; + printf("socket %s(%p, %lu)\n", s, bytes, len); + for (ix = 0; ix < len; ++ix) { + if (!(ix % 16)) + printf("\n"); + printf("%02X ", bytes[ix]); + } + printf("\n"); +} +#else +#define hexdump(string, bytes, len) +#endif + +static OSStatus SocketWrite(SSLConnectionRef h, const void *data, size_t *length) +{ + ssl_test_handle *handle =(ssl_test_handle *)h; + int conn = handle->comm; + size_t len = *length; + uint8_t *ptr = (uint8_t *)data; + + if(handle->is_server) { + //printf("SocketWrite: server write len=%zd\n", len); + + tls_buffer buffer; + buffer.data = ptr; + buffer.length = len; + tls_stream_parser_parse(handle->parser, buffer); + } + + do { + ssize_t ret; + do { + hexdump("write", ptr, len); + ret = write((int)conn, ptr, len); + } while ((ret < 0) && (errno == EAGAIN || errno == EINTR)); + if (ret > 0) { + len -= ret; + ptr += ret; + } + else + return -36; + } while (len > 0); + + *length = *length - len; + return errSecSuccess; +} + +static OSStatus SocketRead(SSLConnectionRef h, void *data, size_t *length) +{ + const ssl_test_handle *handle=h; + int conn = handle->comm; + size_t len = *length; + uint8_t *ptr = (uint8_t *)data; + + + do { + ssize_t ret; + do { + ret = read((int)conn, ptr, len); + } while ((ret < 0) && (errno == EAGAIN || errno == EINTR)); + if (ret > 0) { + len -= ret; + ptr += ret; + } + else + return -36; + } while (len > 0); + + if(len!=0) + printf("Something went wrong here... len=%d\n", (int)len); + + *length = *length - len; + return errSecSuccess; +} + +static int process(tls_stream_parser_ctx_t ctx, tls_buffer record) +{ + ssl_test_handle *handle = (ssl_test_handle *)ctx; + + // printf("processing record len=%zd, type=%d\n", record.length, record.data[0]); + if(record.data[0]==tls_record_type_AppData) { + handle->write_counter++; + // printf("record count = %d\n", handle->write_counter); + } + + return 0; +} + + +static void *securetransport_ssl_thread(void *arg) +{ + OSStatus ortn; + ssl_test_handle * ssl = (ssl_test_handle *)arg; + SSLContextRef ctx = ssl->st; + bool got_server_auth = false; + + //uint64_t start = mach_absolute_time(); + do { + ortn = SSLHandshake(ctx); + + if (ortn == errSSLServerAuthCompleted) + { + require_string(!got_server_auth, out, "second server auth"); + got_server_auth = true; + } + } while (ortn == errSSLWouldBlock + || ortn == errSSLServerAuthCompleted); + + require_noerr_action_quiet(ortn, out, + fprintf(stderr, "Fell out of SSLHandshake with error: %d\n", (int)ortn)); + + unsigned char ibuf[90000], obuf[45000]; + + if (ssl->is_server) { + size_t len; + SecRandomCopyBytes(kSecRandomDefault, ssl->write_size, obuf); + require_noerr(ortn = SSLWrite(ctx, obuf, ssl->write_size, &len), out); + require_action(len == ssl->write_size, out, ortn = -1); + require_noerr(ortn = SSLWrite(ctx, obuf, ssl->write_size, &len), out); + require_action(len == ssl->write_size, out, ortn = -1); + } else { + size_t len = ssl->write_size*2; + size_t olen; + unsigned char *p = ibuf; + while (len) { + require_noerr(ortn = SSLRead(ctx, p, len, &olen), out); + len -= olen; + p += olen; + } + } + +out: + SSLClose(ctx); + CFRelease(ctx); + close(ssl->comm); + pthread_exit((void *)(intptr_t)ortn); + return NULL; +} + +static void +ssl_test_handle_destroy(ssl_test_handle *handle) +{ + if(handle) { + if(handle->parser) tls_stream_parser_destroy(handle->parser); + free(handle); + } +} + +static ssl_test_handle * +ssl_test_handle_create(bool server, int comm, CFArrayRef certs) +{ + ssl_test_handle *handle = calloc(1, sizeof(ssl_test_handle)); + SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, server?kSSLServerSide:kSSLClientSide, kSSLStreamType); + + require(handle, out); + require(ctx, out); + + require_noerr(SSLSetIOFuncs(ctx, + (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out); + require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)handle), out); + + if (server) + require_noerr(SSLSetCertificate(ctx, certs), out); + + require_noerr(SSLSetSessionOption(ctx, + kSSLSessionOptionBreakOnServerAuth, true), out); + + /* Tell SecureTransport to not check certs itself: it will break out of the + handshake to let us take care of it instead. */ + require_noerr(SSLSetEnableCertVerify(ctx, false), out); + + handle->is_server = server; + handle->comm = comm; + handle->certs = certs; + handle->st = ctx; + handle->write_counter = 0; + handle->parser = tls_stream_parser_create(handle, process); + + return handle; + +out: + if (handle) free(handle); + if (ctx) CFRelease(ctx); + return NULL; +} + +static SSLCipherSuite ciphers[] = { + TLS_RSA_WITH_AES_128_CBC_SHA, + //FIXME: re-enable this test when its fixed. + //TLS_RSA_WITH_RC4_128_SHA, +}; +static int nciphers = sizeof(ciphers)/sizeof(ciphers[0]); + +static SSLProtocolVersion versions[] = { + kSSLProtocol3, + kTLSProtocol1, + kTLSProtocol11, + kTLSProtocol12, +}; +static int nversions = sizeof(versions)/sizeof(versions[0]); + +// { write size, expected count when nosplit, expected count when split } +static size_t wsizes[][3] = { + { 1, 2, 2 }, + { 2, 2, 3 }, + { 3, 2, 3 }, + { 4, 2, 3 }, + { 16384, 2, 3 }, + { 16385, 4, 4 }, + { 16386, 4, 6 }, + { 16387, 4, 7 }, + { 16388, 4, 7 }, + { 32768, 4, 7 }, + { 32769, 6, 7 }, + { 32770, 6, 8 }, + { 32771, 6, 10 }, + { 32772, 6, 11 }, + { 32773, 6, 11 }, +}; +static int nwsizes = sizeof(wsizes)/sizeof(wsizes[0]); + +static void +tests(void) +{ + pthread_t client_thread, server_thread; + CFArrayRef server_certs = server_chain(); + ok(server_certs, "got server certs"); + + int i,j,k,s; + + for(i=0; iwrite_size = wsizes[k][0]; + client->write_size = wsizes[k][0]; + + require(client, out); + require(server, out); + + require_noerr(SSLSetProtocolVersionMax(client->st, versions[j]), out); + require_noerr(SSLSetEnabledCiphers(client->st, &ciphers[i], 1), out); + if(s) { + // s=0: default (should be enabled) + // s=1: explicit enable + // s=2: expliciti disable + require_noerr(SSLSetSessionOption(server->st, kSSLSessionOptionSendOneByteRecord, (s==1)?true:false), out); + } + // printf("**** Test Case: i=%d, j=%d, k=%d (%zd), s=%d ****\n", i, j, k, wsizes[k][0], s); + + pthread_create(&client_thread, NULL, securetransport_ssl_thread, client); + pthread_create(&server_thread, NULL, securetransport_ssl_thread, server); + + int server_err, client_err; + pthread_join(client_thread, (void*)&client_err); + pthread_join(server_thread, (void*)&server_err); + + ok(!server_err, "Server error = %d", server_err); + ok(!client_err, "Client error = %d", client_err); + + /* one byte split is expected only for AES when using TLS 1.0 or lower, and when not disabled */ + bool expected_split = (i==0) && (s!=2) && (versions[j]<=kTLSProtocol1); + int expected_count = (int)(expected_split ? wsizes[k][2]: wsizes[k][1]); + + is(server->write_counter, expected_count, "wrong number of data records"); + + // fprintf(stderr, "Server write counter = %d, expected %d\n", server->write_counter, expected_count); + +out: + ssl_test_handle_destroy(client); + ssl_test_handle_destroy(server); + + } + CFReleaseNull(server_certs); +} + +int ssl_48_split(int argc, char *const *argv) +{ + + plan_tests(1 + nciphers*nversions*nwsizes*3 * 3); + + + tests(); + + return 0; +}