]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* |
2 | * Copyright (c) 2011,2013-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 | ||
427c49bc A |
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 | ||
41 | #include <string.h> | |
42 | #include <sys/types.h> | |
43 | #include <sys/socket.h> | |
44 | #include <errno.h> | |
45 | #include <stdlib.h> | |
46 | #include <mach/mach_time.h> | |
47 | ||
48 | ||
49 | #include "ssl_regressions.h" | |
50 | ||
51 | ||
52 | typedef struct { | |
53 | uint32_t session_id; | |
54 | bool is_session_resume; | |
55 | SSLContextRef st; | |
56 | bool is_server; | |
57 | bool client_side_auth; | |
58 | bool dh_anonymous; | |
59 | int comm; | |
60 | CFArrayRef certs; | |
61 | } ssl_test_handle; | |
62 | ||
63 | ||
64 | ||
65 | #if 0 | |
66 | static void hexdump(const uint8_t *bytes, size_t len) { | |
67 | size_t ix; | |
68 | printf("socket write(%p, %lu)\n", bytes, len); | |
69 | for (ix = 0; ix < len; ++ix) { | |
70 | if (!(ix % 16)) | |
71 | printf("\n"); | |
72 | printf("%02X ", bytes[ix]); | |
73 | } | |
74 | printf("\n"); | |
75 | } | |
76 | #else | |
77 | #define hexdump(bytes, len) | |
78 | #endif | |
79 | ||
80 | static int SocketConnect(const char *hostName, int port) | |
81 | { | |
82 | struct sockaddr_in addr; | |
83 | struct in_addr host; | |
fa7225c8 | 84 | int sock; |
427c49bc A |
85 | int err; |
86 | struct hostent *ent; | |
87 | ||
fa7225c8 | 88 | if (hostName[0] >= '0' && hostName[0] <= '9') { |
427c49bc | 89 | host.s_addr = inet_addr(hostName); |
fa7225c8 A |
90 | } else { |
91 | ent = gethostbyname(hostName); | |
427c49bc | 92 | if(ent == NULL) { |
fa7225c8 A |
93 | printf("\n***gethostbyname(%s) returned: %s\n", hostName, hstrerror(h_errno)); |
94 | return -2; | |
427c49bc A |
95 | } |
96 | memcpy(&host, ent->h_addr, sizeof(struct in_addr)); | |
97 | } | |
98 | ||
427c49bc A |
99 | sock = socket(AF_INET, SOCK_STREAM, 0); |
100 | addr.sin_addr = host; | |
101 | addr.sin_port = htons((u_short)port); | |
102 | ||
103 | addr.sin_family = AF_INET; | |
104 | err = connect(sock, (struct sockaddr *) &addr, sizeof(struct sockaddr_in)); | |
105 | ||
106 | if(err!=0) | |
107 | { | |
108 | perror("connect failed"); | |
fa7225c8 | 109 | return -1; |
427c49bc A |
110 | } |
111 | ||
112 | /* make non blocking */ | |
113 | fcntl(sock, F_SETFL, O_NONBLOCK); | |
114 | ||
427c49bc A |
115 | return sock; |
116 | } | |
117 | ||
427c49bc A |
118 | static OSStatus SocketWrite(SSLConnectionRef conn, const void *data, size_t *length) |
119 | { | |
120 | size_t len = *length; | |
121 | uint8_t *ptr = (uint8_t *)data; | |
122 | ||
123 | do { | |
124 | ssize_t ret; | |
125 | do { | |
126 | hexdump(ptr, len); | |
127 | ret = write((int)conn, ptr, len); | |
128 | if (ret < 0) | |
129 | perror("send"); | |
130 | } while ((ret < 0) && (errno == EAGAIN || errno == EINTR)); | |
131 | if (ret > 0) { | |
132 | len -= ret; | |
133 | ptr += ret; | |
134 | } | |
135 | else | |
136 | return -36; | |
137 | } while (len > 0); | |
138 | ||
139 | *length = *length - len; | |
140 | return errSecSuccess; | |
141 | } | |
142 | ||
143 | static | |
144 | OSStatus SocketRead( | |
145 | SSLConnectionRef connection, | |
146 | void *data, | |
147 | size_t *dataLength) | |
148 | { | |
149 | int fd = (int)connection; | |
150 | ssize_t len; | |
151 | ||
152 | len = read(fd, data, *dataLength); | |
153 | ||
154 | if(len<0) { | |
155 | int theErr = errno; | |
156 | switch(theErr) { | |
157 | case EAGAIN: | |
158 | //printf("SocketRead: EAGAIN\n"); | |
159 | *dataLength=0; | |
160 | /* nonblocking, no data */ | |
161 | return errSSLWouldBlock; | |
162 | default: | |
163 | perror("SocketRead"); | |
164 | return -36; | |
165 | } | |
166 | } | |
167 | ||
168 | if(len<(ssize_t)*dataLength) { | |
169 | *dataLength=len; | |
170 | return errSSLWouldBlock; | |
171 | } | |
172 | ||
173 | return errSecSuccess; | |
174 | } | |
175 | ||
176 | static SSLContextRef make_ssl_ref(int sock, SSLProtocol maxprot, Boolean false_start) | |
177 | { | |
178 | SSLContextRef ctx = NULL; | |
179 | ||
180 | require_noerr(SSLNewContext(false, &ctx), out); | |
181 | require_noerr(SSLSetIOFuncs(ctx, | |
182 | (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out); | |
183 | require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)sock), out); | |
184 | ||
185 | require_noerr(SSLSetSessionOption(ctx, | |
186 | kSSLSessionOptionBreakOnServerAuth, true), out); | |
187 | ||
188 | require_noerr(SSLSetSessionOption(ctx, | |
189 | kSSLSessionOptionFalseStart, false_start), out); | |
190 | ||
191 | require_noerr(SSLSetProtocolVersionMax(ctx, maxprot), out); | |
192 | ||
193 | return ctx; | |
194 | out: | |
195 | if (ctx) | |
196 | SSLDisposeContext(ctx); | |
197 | return NULL; | |
198 | } | |
199 | ||
200 | const char request[]="GET / HTTP/1.1\n\n"; | |
201 | char reply[2048]; | |
202 | ||
203 | static OSStatus securetransport(ssl_test_handle * ssl) | |
204 | { | |
205 | OSStatus ortn; | |
206 | SSLContextRef ctx = ssl->st; | |
207 | SecTrustRef trust = NULL; | |
208 | bool got_server_auth = false, got_client_cert_req = false; | |
209 | ||
210 | ortn = SSLHandshake(ctx); | |
fa7225c8 A |
211 | |
212 | require_action_quiet(ortn==errSSLWouldBlock, out, printf("SSLHandshake failed with err %ld\n", (long)ortn)); | |
213 | ||
427c49bc A |
214 | size_t sent, received; |
215 | const char *r=request; | |
216 | size_t l=sizeof(request); | |
217 | ||
218 | do { | |
219 | ||
220 | ortn = SSLWrite(ctx, r, l, &sent); | |
221 | ||
222 | if(ortn == errSSLWouldBlock) { | |
223 | r+=sent; | |
224 | l-=sent; | |
225 | } | |
226 | ||
227 | if (ortn == errSSLServerAuthCompleted) | |
228 | { | |
229 | require_string(!got_server_auth, out, "second server auth"); | |
230 | require_string(!got_client_cert_req, out, "got client cert req before server auth"); | |
231 | got_server_auth = true; | |
232 | require_string(!trust, out, "Got errSSLServerAuthCompleted twice?"); | |
233 | /* verify peer cert chain */ | |
234 | require_noerr(SSLCopyPeerTrust(ctx, &trust), out); | |
235 | SecTrustResultType trust_result = 0; | |
236 | /* this won't verify without setting up a trusted anchor */ | |
237 | require_noerr(SecTrustEvaluate(trust, &trust_result), out); | |
238 | } | |
427c49bc A |
239 | } while(ortn == errSSLWouldBlock || ortn == errSSLServerAuthCompleted); |
240 | ||
241 | //fprintf(stderr, "\nHTTP Request Sent\n"); | |
242 | ||
243 | require_noerr_action_quiet(ortn, out, printf("SSLWrite failed with err %ld\n", (long)ortn)); | |
244 | ||
245 | require_string(got_server_auth, out, "never got server auth"); | |
246 | ||
247 | do { | |
248 | ortn = SSLRead(ctx, reply, sizeof(reply)-1, &received); | |
249 | //fprintf(stderr, "r"); usleep(1000); | |
250 | } while(ortn == errSSLWouldBlock); | |
251 | ||
252 | //fprintf(stderr, "\n"); | |
253 | ||
254 | require_noerr_action_quiet(ortn, out, printf("SSLRead failed with err %ld\n", (long)ortn)); | |
255 | ||
256 | reply[received]=0; | |
257 | ||
258 | //fprintf(stderr, "HTTP reply:\n"); | |
259 | //fprintf(stderr, "%s\n",reply); | |
260 | ||
261 | out: | |
262 | SSLClose(ctx); | |
263 | SSLDisposeContext(ctx); | |
264 | if (trust) CFRelease(trust); | |
265 | ||
266 | return ortn; | |
267 | } | |
268 | ||
427c49bc A |
269 | static ssl_test_handle * |
270 | ssl_test_handle_create(int comm, SSLProtocol maxprot, Boolean false_start) | |
271 | { | |
272 | ssl_test_handle *handle = calloc(1, sizeof(ssl_test_handle)); | |
273 | if (handle) { | |
274 | handle->comm = comm; | |
275 | handle->st = make_ssl_ref(comm, maxprot, false_start); | |
276 | } | |
277 | return handle; | |
278 | } | |
279 | ||
280 | static | |
281 | struct s_server { | |
282 | char *host; | |
283 | int port; | |
284 | SSLProtocol maxprot; | |
285 | } servers[] = { | |
286 | /* Good tls 1.2 servers */ | |
287 | {"encrypted.google.com", 443, kTLSProtocol12 }, | |
288 | {"www.amazon.com",443, kTLSProtocol12 }, | |
d8f41ccd | 289 | //{"www.mikestoolbox.org",443, kTLSProtocol12 }, |
427c49bc A |
290 | }; |
291 | ||
292 | #define NSERVERS (int)(sizeof(servers)/sizeof(servers[0])) | |
293 | #define NLOOPS 1 | |
fa7225c8 | 294 | #define CONNECT_TRIES 3 |
427c49bc A |
295 | |
296 | static void | |
297 | tests(void) | |
298 | { | |
299 | int p; | |
300 | int fs; | |
301 | ||
302 | for(p=0; p<NSERVERS;p++) { | |
303 | for(int loops=0; loops<NLOOPS; loops++) { | |
304 | for(fs=0;fs<2; fs++) { | |
305 | ||
306 | ssl_test_handle *client; | |
427c49bc | 307 | OSStatus r; |
fa7225c8 A |
308 | int s = -1; |
309 | ||
310 | for(int try = 0; s<0 && try<CONNECT_TRIES; try++) { | |
311 | s=SocketConnect(servers[p].host, servers[p].port); | |
312 | } | |
427c49bc | 313 | |
427c49bc A |
314 | if(s<0) { |
315 | fail("connect failed with err=%d - %s:%d (try %d)", s, servers[p].host, servers[p].port, loops); | |
316 | break; | |
317 | } | |
318 | ||
319 | client = ssl_test_handle_create(s, servers[p].maxprot, fs); | |
320 | ||
321 | r=securetransport(client); | |
322 | ok(!r, "handshake failed with err=%ld - %s:%d (try %d), false start=%d", (long)r, servers[p].host, servers[p].port, loops, fs); | |
323 | ||
324 | close(s); | |
d8f41ccd | 325 | free(client); |
427c49bc A |
326 | } } } |
327 | } | |
328 | ||
329 | int ssl_47_falsestart(int argc, char *const *argv) | |
330 | { | |
331 | plan_tests(NSERVERS*NLOOPS*2); | |
332 | ||
333 | tests(); | |
334 | ||
335 | return 0; | |
336 | } |