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