1/*
2 * Copyright (c) 2011-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#include <stdbool.h>
26#include <pthread.h>
27#include <fcntl.h>
28#include <sys/mman.h>
29#include <unistd.h>
30#include <sys/types.h>
31#include <netinet/in.h>
32#include <sys/socket.h>
33#include <netdb.h>
34#include <arpa/inet.h>
35#include <CoreFoundation/CoreFoundation.h>
36
37#include <AssertMacros.h>
38#include <Security/SecureTransportPriv.h> /* SSLSetOption */
39#include <Security/SecureTransport.h>
40#include <Security/SecPolicy.h>
41#include <Security/SecTrust.h>
42#include <Security/SecIdentity.h>
43#include <Security/SecIdentityPriv.h>
44#include <Security/SecCertificatePriv.h>
45#include <Security/SecKeyPriv.h>
46#include <Security/SecItem.h>
47#include <Security/SecRandom.h>
48
49#include <string.h>
50#include <sys/types.h>
51#include <sys/socket.h>
52#include <errno.h>
53#include <stdlib.h>
54#include <mach/mach_time.h>
55
56#include "ssl_regressions.h"
57
58typedef struct {
59    uint32_t session_id;
60    bool is_session_resume;
61    SSLContextRef st;
62    bool is_server;
63    bool client_side_auth;
64    bool dh_anonymous;
65    int comm;
66    CFArrayRef certs;
67} ssl_test_handle;
68
69
70
71#if 0
72static void hexdump(const uint8_t *bytes, size_t len) {
73	size_t ix;
74    printf("socket write(%p, %lu)\n", bytes, len);
75	for (ix = 0; ix < len; ++ix) {
76        if (!(ix % 16))
77            printf("\n");
78		printf("%02X ", bytes[ix]);
79	}
80	printf("\n");
81}
82#else
83#define hexdump(bytes, len)
84#endif
85
86static int SocketConnect(const char *hostName, int port)
87{
88    struct sockaddr_in  addr;
89    struct in_addr      host;
90	int					sock;
91    int                 err;
92    struct hostent      *ent;
93
94    if (hostName[0] >= '0' && hostName[0] <= '9')
95    {
96        host.s_addr = inet_addr(hostName);
97    }
98    else {
99		unsigned dex;
100#define GETHOST_RETRIES 5
101		/* seeing a lot of soft failures here that I really don't want to track down */
102		for(dex=0; dex<GETHOST_RETRIES; dex++) {
103			if(dex != 0) {
104				printf("\n...retrying gethostbyname(%s)", hostName);
105			}
106			ent = gethostbyname(hostName);
107			if(ent != NULL) {
108				break;
109			}
110		}
111        if(ent == NULL) {
112			printf("\n***gethostbyname(%s) returned: %s\n", hostName, hstrerror(h_errno));
113            return -1;
114        }
115        memcpy(&host, ent->h_addr, sizeof(struct in_addr));
116    }
117
118
119    sock = socket(AF_INET, SOCK_STREAM, 0);
120    addr.sin_addr = host;
121    addr.sin_port = htons((u_short)port);
122
123    addr.sin_family = AF_INET;
124    err = connect(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in));
125
126    if(err!=0)
127    {
128        perror("connect failed");
129        return err;
130    }
131
132    return sock;
133}
134
135
136static OSStatus SocketWrite(SSLConnectionRef conn, const void *data, size_t *length)
137{
138	size_t len = *length;
139	uint8_t *ptr = (uint8_t *)data;
140
141    do {
142        ssize_t ret;
143        do {
144            hexdump(ptr, len);
145            ret = write((int)conn, ptr, len);
146            if (ret < 0)
147                perror("send");
148        } while ((ret < 0) && (errno == EAGAIN || errno == EINTR));
149        if (ret > 0) {
150            len -= ret;
151            ptr += ret;
152        }
153        else
154            return -36;
155    } while (len > 0);
156
157    *length = *length - len;
158    return errSecSuccess;
159}
160
161static OSStatus SocketRead(SSLConnectionRef conn, void *data, size_t *length)
162{
163	size_t len = *length;
164	uint8_t *ptr = (uint8_t *)data;
165
166    do {
167        ssize_t ret;
168        do {
169            ret = read((int)conn, ptr, len);
170            if (ret < 0)
171                perror("send");
172        } while ((ret < 0) && (errno == EAGAIN || errno == EINTR));
173        if (ret > 0) {
174            len -= ret;
175            ptr += ret;
176        }
177        else
178            return -36;
179    } while (len > 0);
180
181    *length = *length - len;
182    return errSecSuccess;
183}
184
185static SSLContextRef make_ssl_ref(int sock, SSLProtocol maxprot)
186{
187    SSLContextRef ctx = NULL;
188
189    require_noerr(SSLNewContext(false, &ctx), out);
190    require_noerr(SSLSetIOFuncs(ctx,
191                                (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
192    require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)sock), out);
193
194    require_noerr(SSLSetSessionOption(ctx,
195                                      kSSLSessionOptionBreakOnServerAuth, true), out);
196
197    require_noerr(SSLSetProtocolVersionMax(ctx, maxprot), out);
198    /* Tell SecureTransport to not check certs itself: it will break out of the
199     handshake to let us take care of it instead. */
200    require_noerr(SSLSetEnableCertVerify(ctx, false), out);
201
202    return ctx;
203out:
204    if (ctx)
205        SSLDisposeContext(ctx);
206    return NULL;
207}
208
209static OSStatus securetransport(ssl_test_handle * ssl)
210{
211    OSStatus ortn;
212    SSLContextRef ctx = ssl->st;
213    SecTrustRef trust = NULL;
214    bool got_server_auth = false, got_client_cert_req = false;
215
216    //uint64_t start = mach_absolute_time();
217    do {
218        ortn = SSLHandshake(ctx);
219
220        if (ortn == errSSLServerAuthCompleted)
221        {
222            require_string(!got_server_auth, out, "second server auth");
223            require_string(!got_client_cert_req, out, "got client cert req before server auth");
224            got_server_auth = true;
225            require_string(!trust, out, "Got errSSLServerAuthCompleted twice?");
226            /* verify peer cert chain */
227            require_noerr(SSLCopyPeerTrust(ctx, &trust), out);
228            SecTrustResultType trust_result = 0;
229            /* this won't verify without setting up a trusted anchor */
230            require_noerr(SecTrustEvaluate(trust, &trust_result), out);
231
232        }    } while (ortn == errSSLWouldBlock
233             || ortn == errSSLServerAuthCompleted);
234    require_noerr_action_quiet(ortn, out,
235                               fprintf(stderr, "Fell out of SSLHandshake with error: %d\n", (int)ortn));
236
237    require_string(got_server_auth, out, "never got server auth");
238
239    //uint64_t elapsed = mach_absolute_time() - start;
240    //fprintf(stderr, "setr elapsed: %lld\n", elapsed);
241
242    /*
243     SSLProtocol proto = kSSLProtocolUnknown;
244     require_noerr_quiet(SSLGetNegotiatedProtocolVersion(ctx, &proto), out); */
245
246    SSLCipherSuite cipherSuite;
247    require_noerr_quiet(ortn = SSLGetNegotiatedCipher(ctx, &cipherSuite), out);
248    //fprintf(stderr, "st negotiated %02x\n", cipherSuite);
249
250
251out:
252    SSLClose(ctx);
253    SSLDisposeContext(ctx);
254    if (trust) CFRelease(trust);
255
256    return ortn;
257}
258
259
260
261static ssl_test_handle *
262ssl_test_handle_create(int comm, SSLProtocol maxprot)
263{
264    ssl_test_handle *handle = calloc(1, sizeof(ssl_test_handle));
265    if (handle) {
266        handle->comm = comm;
267        handle->st = make_ssl_ref(comm, maxprot);
268    }
269    return handle;
270}
271
272struct s_server {
273    char *host;
274    int port;
275    SSLProtocol maxprot;
276} servers[] = {
277    /* Good tls 1.2 servers */
278    {"encrypted.google.com", 443, kTLSProtocol12 },
279    {"www.amazon.com",443, kTLSProtocol12 },
280    //{"www.mikestoolbox.org",443, kTLSProtocol12 },
281    /* servers with issues */
282    {"vpp.visa.co.uk", 443, kTLSProtocol12 }, // Doesnt like SSL 3.0 in initial record layer version
283    {"imap.softbank.jp",993, kTLSProtocol1 },   // softbank imap server, there are multiple servers behind this, one of them is not able to handle downgrading to TLS 1.2 properly (126.240.66.17).
284    {"mobile.charter.net",993, kTLSProtocol1 }, // Support 1.2 but fail to negotiate properly
285    {"mybill.vodafone.com.au", 443, kTLSProtocol1 }, /* 2056 bit server key */
286};
287
288#define NSERVERS (int)(sizeof(servers)/sizeof(servers[0]))
289#define NLOOPS 1
290
291static void
292tests(void)
293{
294    int p;
295
296    for(p=0; p<NSERVERS;p++) {
297    for(int loops=0; loops<NLOOPS; loops++) {
298
299        ssl_test_handle *client;
300
301        int s;
302        OSStatus r;
303
304        s=SocketConnect(servers[p].host, servers[p].port);
305        if(s<0) {
306            fail("connect failed with err=%d - %s:%d (try %d)", s, servers[p].host, servers[p].port, loops);
307            break;
308        }
309
310        client = ssl_test_handle_create(s, servers[p].maxprot);
311
312        r=securetransport(client);
313        ok(!r, "handshake failed with err=%ld - %s:%d (try %d)", (long)r, servers[p].host, servers[p].port, loops);
314
315        free(client);
316        close(s);
317    } }
318}
319
320int ssl_45_tls12(int argc, char *const *argv)
321{
322        plan_tests(NSERVERS*NLOOPS);
323
324        tests();
325
326        return 0;
327}
328