2 * Copyright (c) 2011,2013-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
30 #include <sys/types.h>
31 #include <netinet/in.h>
32 #include <sys/socket.h>
34 #include <arpa/inet.h>
35 #include <CoreFoundation/CoreFoundation.h>
37 #include <AssertMacros.h>
38 #include <Security/SecureTransportPriv.h> /* SSLSetOption */
39 #include <Security/SecureTransport.h>
42 #include <sys/types.h>
43 #include <sys/socket.h>
46 #include <mach/mach_time.h>
48 #import "STLegacyTests.h"
50 #pragma clang diagnostic push
51 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
53 @implementation STLegacyTests (falsestart)
57 bool is_session_resume;
60 bool client_side_auth;
67 #if SECTRANS_VERBOSE_DEBUG
68 static void hexdump(const uint8_t *bytes, size_t len) {
70 printf("socket write(%p, %lu)\n", bytes, len);
71 for (ix = 0; ix < len; ++ix) {
74 printf("%02X ", bytes[ix]);
79 #define hexdump(bytes, len)
82 static int SocketConnect(const char *hostName, int port)
84 struct sockaddr_in addr;
90 if (hostName[0] >= '0' && hostName[0] <= '9') {
91 host.s_addr = inet_addr(hostName);
93 ent = gethostbyname(hostName);
95 printf("\n***gethostbyname(%s) returned: %s\n", hostName, hstrerror(h_errno));
98 memcpy(&host, ent->h_addr, sizeof(struct in_addr));
101 sock = socket(AF_INET, SOCK_STREAM, 0);
102 addr.sin_addr = host;
103 addr.sin_port = htons((u_short)port);
105 addr.sin_family = AF_INET;
106 err = connect(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in));
110 perror("connect failed");
114 /* make non blocking */
115 fcntl(sock, F_SETFL, O_NONBLOCK);
120 static OSStatus SocketWrite(SSLConnectionRef conn, const void *data, size_t *length)
122 size_t len = *length;
123 uint8_t *ptr = (uint8_t *)data;
129 ret = write((int)conn, ptr, len);
132 } while ((ret < 0) && (errno == EAGAIN || errno == EINTR));
141 *length = *length - len;
142 return errSecSuccess;
147 SSLConnectionRef connection,
151 int fd = (int)connection;
154 len = read(fd, data, *dataLength);
161 /* nonblocking, no data */
162 return errSSLWouldBlock;
164 perror("SocketRead");
169 if (len < (ssize_t)*dataLength) {
171 return errSSLWouldBlock;
174 return errSecSuccess;
177 static SSLContextRef make_ssl_ref(int sock, SSLProtocol maxprot, Boolean false_start)
179 SSLContextRef ctx = NULL;
181 require_noerr(SSLNewContext(false, &ctx), out);
182 require_noerr(SSLSetIOFuncs(ctx,
183 (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
184 require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)sock), out);
186 require_noerr(SSLSetSessionOption(ctx,
187 kSSLSessionOptionBreakOnServerAuth, true), out);
189 require_noerr(SSLSetSessionOption(ctx,
190 kSSLSessionOptionFalseStart, false_start), out);
192 require_noerr(SSLSetProtocolVersionMax(ctx, maxprot), out);
197 SSLDisposeContext(ctx);
202 const char request[]="GET / HTTP/1.1\n\n";
205 static OSStatus securetransport(ssl_test_handle * ssl)
208 SSLContextRef ctx = ssl->st;
209 SecTrustRef trust = NULL;
210 bool got_server_auth = false, got_client_cert_req = false;
212 ortn = SSLHandshake(ctx);
214 require_action_quiet(ortn == errSSLWouldBlock, out, printf("SSLHandshake failed with err %ld\n", (long)ortn));
216 size_t sent, received;
217 const char *r = request;
218 size_t l = sizeof(request);
222 ortn = SSLWrite(ctx, r, l, &sent);
224 if (ortn == errSSLWouldBlock) {
229 if (ortn == errSSLServerAuthCompleted) {
230 require_string(!got_server_auth, out, "second server auth");
231 require_string(!got_client_cert_req, out, "got client cert req before server auth");
232 got_server_auth = true;
233 require_string(!trust, out, "Got errSSLServerAuthCompleted twice?");
234 /* verify peer cert chain */
235 require_noerr(SSLCopyPeerTrust(ctx, &trust), out);
236 SecTrustResultType trust_result = 0;
237 /* this won't verify without setting up a trusted anchor */
238 require_noerr(SecTrustEvaluate(trust, &trust_result), out);
240 } while (ortn == errSSLWouldBlock || ortn == errSSLServerAuthCompleted);
242 require_noerr_action_quiet(ortn, out, printf("SSLWrite failed with err %ld\n", (long)ortn));
244 require_string(got_server_auth, out, "never got server auth");
247 ortn = SSLRead(ctx, reply, sizeof(reply)-1, &received);
248 } while (ortn == errSSLWouldBlock);
250 require_noerr_action_quiet(ortn, out, printf("SSLRead failed with err %ld\n", (long)ortn));
256 SSLDisposeContext(ctx);
257 if (trust) CFRelease(trust);
262 static ssl_test_handle *
263 ssl_test_handle_create(int comm, SSLProtocol maxprot, Boolean false_start)
265 ssl_test_handle *handle = calloc(1, sizeof(ssl_test_handle));
268 handle->st = make_ssl_ref(comm, maxprot, false_start);
279 /* Good tls 1.2 servers */
280 {"encrypted.google.com", 443, kTLSProtocol12 },
281 {"www.amazon.com",443, kTLSProtocol12 },
284 #define NSERVERS (int)(sizeof(servers)/sizeof(servers[0]))
286 #define CONNECT_TRIES 3
288 -(void)testFalseStart
293 for (p = 0; p < NSERVERS; p++) {
294 for (int loops = 0; loops < NLOOPS; loops++) {
295 for (fs = 0;fs < 2; fs++) {
297 ssl_test_handle *client;
301 for (int try = 0; s < 0 && try < CONNECT_TRIES; try++) {
302 s = SocketConnect(servers[p].host, servers[p].port);
307 client = ssl_test_handle_create(s, servers[p].maxprot, fs);
309 r = securetransport(client);
310 XCTAssert(!r, "handshake failed with err=%ld - %s:%d (try %d), false start=%d", (long)r, servers[p].host, servers[p].port, loops, fs);
321 #pragma clang diagnostic pop