1/*
2 * Copyright (c) 2012-2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25
26#include <stdbool.h>
27#include <pthread.h>
28#include <fcntl.h>
29#include <sys/mman.h>
30#include <unistd.h>
31
32#include <CoreFoundation/CoreFoundation.h>
33
34#include <AssertMacros.h>
35#include <Security/SecureTransportPriv.h> /* SSLSetOption */
36#include <Security/SecureTransport.h>
37#include <Security/SecPolicy.h>
38#include <Security/SecTrust.h>
39#include <Security/SecIdentity.h>
40#include <Security/SecIdentityPriv.h>
41#include <Security/SecCertificatePriv.h>
42#include <Security/SecKeyPriv.h>
43#include <Security/SecItem.h>
44#include <Security/SecRandom.h>
45
46#include <string.h>
47#include <sys/types.h>
48#include <sys/socket.h>
49#include <errno.h>
50#include <stdlib.h>
51#include <mach/mach_time.h>
52
53#if TARGET_OS_IPHONE
54#include <Security/SecRSAKey.h>
55#endif
56
57#include "ssl_regressions.h"
58#include "ssl-utils.h"
59
60
61typedef struct {
62    SSLContextRef st;
63    bool is_server;
64    int comm;
65    CFArrayRef certs;
66    int test;
67} ssl_test_handle;
68
69
70#pragma mark -
71#pragma mark SecureTransport support
72
73#if 0
74static void hexdump(const char *s, const uint8_t *bytes, size_t len) {
75	size_t ix;
76    printf("socket %s(%p, %lu)\n", s, bytes, len);
77	for (ix = 0; ix < len; ++ix) {
78        if (!(ix % 16))
79            printf("\n");
80		printf("%02X ", bytes[ix]);
81	}
82	printf("\n");
83}
84#else
85#define hexdump(string, bytes, len)
86#endif
87
88static OSStatus SocketWrite(SSLConnectionRef h, const void *data, size_t *length)
89{
90    int conn = ((const ssl_test_handle *)h)->comm;
91	size_t len = *length;
92	uint8_t *ptr = (uint8_t *)data;
93
94    do {
95        ssize_t ret;
96        do {
97            hexdump("write", ptr, len);
98            ret = write((int)conn, ptr, len);
99        } while ((ret < 0) && (errno == EAGAIN || errno == EINTR));
100        if (ret > 0) {
101            len -= ret;
102            ptr += ret;
103        }
104        else
105            return -36;
106    } while (len > 0);
107
108    *length = *length - len;
109    return errSecSuccess;
110}
111
112static int changepad=0;
113
114static OSStatus SocketRead(SSLConnectionRef h, void *data, size_t *length)
115{
116    const ssl_test_handle *handle=h;
117    int conn = handle->comm;
118	size_t len = *length;
119	uint8_t *ptr = (uint8_t *)data;
120
121
122    do {
123        ssize_t ret;
124        do {
125            ret = read((int)conn, ptr, len);
126        } while ((ret < 0) && (errno == EAGAIN || errno == EINTR));
127        if (ret > 0) {
128            len -= ret;
129            ptr += ret;
130        }
131        else
132            return -36;
133    } while (len > 0);
134
135    if(len!=0)
136        printf("Something went wrong here... len=%d\n", (int)len);
137
138    *length = *length - len;
139
140    ptr=data;
141
142    /* change pad in the data */
143    if(changepad==1) {
144        changepad=0;
145        ptr[31]=ptr[31]^0x08^0xff; // expected padding was 8, changing it to 0xff to trigger integer underflow.
146    }
147
148    /* We are reading a data application header */
149    if(*length==5 && ptr[0]==0x17) {
150        switch(handle->test) {
151            case 0:
152                ptr[4]=32; // reduce the size to 2 blocks and trigger integer underflow.
153                break;
154            case 1:
155                ptr[4]=48; // reduce the size to 3 blocks and triggering integer underflow in the padding.
156                break;
157            case 2:
158                changepad=1;
159                break;
160            default:
161                break;
162        }
163    }
164
165
166    return errSecSuccess;
167}
168
169
170
171static void *securetransport_ssl_thread(void *arg)
172{
173    OSStatus ortn;
174    ssl_test_handle * ssl = (ssl_test_handle *)arg;
175    SSLContextRef ctx = ssl->st;
176    bool got_server_auth = false;
177
178    //uint64_t start = mach_absolute_time();
179    do {
180        ortn = SSLHandshake(ctx);
181
182        if (ortn == errSSLServerAuthCompleted)
183        {
184            require_string(!got_server_auth, out, "second server auth");
185            got_server_auth = true;
186        }
187    } while (ortn == errSSLWouldBlock
188             || ortn == errSSLServerAuthCompleted);
189
190    require_noerr_action_quiet(ortn, out,
191                               fprintf(stderr, "Fell out of SSLHandshake with error: %d\n", (int)ortn));
192
193    unsigned char ibuf[8], obuf[8];
194    size_t len;
195    if (ssl->is_server) {
196        SecRandomCopyBytes(kSecRandomDefault, sizeof(obuf), obuf);
197        require_noerr_quiet(ortn = SSLWrite(ctx, obuf, sizeof(obuf), &len), out);
198        require_action_quiet(len == sizeof(obuf), out, ortn = -1);
199    } else {
200        require_noerr_quiet(ortn = SSLRead(ctx, ibuf, sizeof(ibuf), &len), out);
201        require_action_quiet(len == sizeof(ibuf), out, ortn = -1);
202    }
203
204out:
205    SSLClose(ctx);
206    CFRelease(ctx);
207    close(ssl->comm);
208    pthread_exit((void *)(intptr_t)ortn);
209    return NULL;
210}
211
212
213static ssl_test_handle *
214ssl_test_handle_create(bool server, int comm, CFArrayRef certs)
215{
216    ssl_test_handle *handle = calloc(1, sizeof(ssl_test_handle));
217    SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, server?kSSLServerSide:kSSLClientSide, kSSLStreamType);
218
219    require(handle, out);
220    require(ctx, out);
221
222    require_noerr(SSLSetIOFuncs(ctx,
223                                (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
224    require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)handle), out);
225
226    if (server)
227        require_noerr(SSLSetCertificate(ctx, certs), out);
228
229    require_noerr(SSLSetSessionOption(ctx,
230                                      kSSLSessionOptionBreakOnServerAuth, true), out);
231
232    /* Tell SecureTransport to not check certs itself: it will break out of the
233     handshake to let us take care of it instead. */
234    require_noerr(SSLSetEnableCertVerify(ctx, false), out);
235
236    handle->is_server = server;
237    handle->comm = comm;
238    handle->certs = certs;
239    handle->st = ctx;
240
241    return handle;
242
243out:
244    if (handle) free(handle);
245    if (ctx) CFRelease(ctx);
246    return NULL;
247}
248
249static void
250tests(void)
251{
252    pthread_t client_thread, server_thread;
253    CFArrayRef server_certs = server_chain();
254    ok(server_certs, "got server certs");
255
256    int i;
257
258    for(i=0; i<3; i++)
259    {
260        int sp[2];
261        if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) exit(errno);
262        fcntl(sp[0], F_SETNOSIGPIPE, 1);
263        fcntl(sp[1], F_SETNOSIGPIPE, 1);
264
265        ssl_test_handle *server, *client;
266
267        server = ssl_test_handle_create(true /*server*/, sp[0], server_certs);
268        client = ssl_test_handle_create(false/*client*/, sp[1], NULL);
269
270        server->test=i;
271        client->test=i;
272
273        require(client, out);
274        require(server, out);
275
276        SSLCipherSuite cipher = TLS_RSA_WITH_AES_128_CBC_SHA256;
277        require_noerr(SSLSetEnabledCiphers(client->st, &cipher, 1), out);
278
279        pthread_create(&client_thread, NULL, securetransport_ssl_thread, client);
280        pthread_create(&server_thread, NULL, securetransport_ssl_thread, server);
281
282        int server_err, client_err;
283        pthread_join(client_thread, (void*)&client_err);
284        pthread_join(server_thread, (void*)&server_err);
285
286
287        ok(!server_err, "Server error = %d", server_err);
288        /* tests 0/1 should cause errSSLClosedAbort, 2 should cause errSSLBadRecordMac */
289        ok(client_err==((i==2)?errSSLBadRecordMac:errSSLClosedAbort), "Client error = %d", client_err);
290
291out:
292        free(client);
293        free(server);
294
295    }
296    CFReleaseNull(server_certs);
297}
298
299int ssl_44_crashes(int argc, char *const *argv)
300{
301
302    plan_tests(3*2 + 1 /*cert*/);
303
304
305    tests();
306
307    return 0;
308}
309