]>
Commit | Line | Data |
---|---|---|
5c19dc3a A |
1 | // |
2 | // ssl-49-sni.c | |
3 | // libsecurity_ssl | |
4 | // | |
5 | // | |
6 | ||
7 | ||
8 | #include <stdbool.h> | |
9 | #include <pthread.h> | |
10 | #include <fcntl.h> | |
11 | #include <sys/mman.h> | |
12 | #include <unistd.h> | |
13 | ||
14 | #include <CoreFoundation/CoreFoundation.h> | |
15 | ||
16 | #include <AssertMacros.h> | |
17 | #include <Security/SecureTransportPriv.h> /* SSLSetOption */ | |
18 | #include <Security/SecureTransport.h> | |
19 | #include <Security/SecPolicy.h> | |
20 | #include <Security/SecTrust.h> | |
21 | #include <Security/SecIdentity.h> | |
22 | #include <Security/SecIdentityPriv.h> | |
23 | #include <Security/SecCertificatePriv.h> | |
24 | #include <Security/SecKeyPriv.h> | |
25 | #include <Security/SecItem.h> | |
26 | #include <Security/SecRandom.h> | |
27 | ||
28 | #include <string.h> | |
29 | #include <sys/types.h> | |
30 | #include <sys/socket.h> | |
31 | #include <errno.h> | |
32 | #include <stdlib.h> | |
33 | #include <mach/mach_time.h> | |
34 | ||
35 | #if TARGET_OS_IPHONE | |
36 | #include <Security/SecRSAKey.h> | |
37 | #endif | |
38 | ||
39 | #include "ssl_regressions.h" | |
40 | #include "ssl-utils.h" | |
41 | ||
42 | typedef struct { | |
43 | SSLContextRef handle; | |
44 | uint32_t session_id; | |
45 | bool is_server; | |
46 | int comm; | |
47 | } ssl_test_handle; | |
48 | ||
49 | ||
50 | #pragma mark - | |
51 | #pragma mark SecureTransport support | |
52 | ||
53 | #if 0 | |
54 | static void hexdump(const uint8_t *bytes, size_t len) { | |
55 | size_t ix; | |
56 | printf("socket write(%p, %lu)\n", bytes, len); | |
57 | for (ix = 0; ix < len; ++ix) { | |
58 | if (!(ix % 16)) | |
59 | printf("\n"); | |
60 | printf("%02X ", bytes[ix]); | |
61 | } | |
62 | printf("\n"); | |
63 | } | |
64 | #else | |
65 | #define hexdump(bytes, len) | |
66 | #endif | |
67 | ||
68 | ||
69 | static OSStatus SocketWrite(SSLConnectionRef h, const void *data, size_t *length) | |
70 | { | |
71 | size_t len = *length; | |
72 | uint8_t *ptr = (uint8_t *)data; | |
73 | ||
74 | do { | |
75 | ssize_t ret; | |
76 | do { | |
77 | hexdump(ptr, len); | |
78 | ret = write((int)h, ptr, len); | |
79 | } while ((ret < 0) && (errno == EAGAIN || errno == EINTR)); | |
80 | if (ret > 0) { | |
81 | len -= ret; | |
82 | ptr += ret; | |
83 | } | |
84 | else | |
85 | return -36; | |
86 | } while (len > 0); | |
87 | ||
88 | *length = *length - len; | |
89 | return errSecSuccess; | |
90 | } | |
91 | ||
92 | static OSStatus SocketRead(SSLConnectionRef h, void *data, size_t *length) | |
93 | { | |
94 | size_t len = *length; | |
95 | uint8_t *ptr = (uint8_t *)data; | |
96 | ||
97 | do { | |
98 | ssize_t ret; | |
99 | do { | |
100 | ret = read((int)h, ptr, len); | |
101 | } while ((ret < 0) && (errno == EAGAIN || errno == EINTR)); | |
102 | if (ret > 0) { | |
103 | len -= ret; | |
104 | ptr += ret; | |
105 | } else { | |
106 | printf("read error(%d): ret=%zd, errno=%d\n", (int)h, ret, errno); | |
107 | return -errno; | |
108 | } | |
109 | } while (len > 0); | |
110 | ||
111 | *length = *length - len; | |
112 | return errSecSuccess; | |
113 | } | |
114 | ||
115 | static char peername[] = "localhost"; | |
116 | ||
117 | static void *securetransport_server_thread(void *arg) | |
118 | { | |
119 | OSStatus ortn; | |
120 | ssl_test_handle * ssl = (ssl_test_handle *)arg; | |
121 | SSLContextRef ctx = ssl->handle; | |
122 | CFArrayRef server_certs = server_chain(); | |
123 | ||
124 | do { | |
125 | ortn = SSLHandshake(ctx); | |
126 | } while (ortn == errSSLWouldBlock); | |
127 | ||
128 | ok(ortn==errSSLClientHelloReceived, "Unexpected Handshake exit code"); | |
129 | ||
130 | if (ortn == errSSLClientHelloReceived) { | |
131 | char *sni = NULL; | |
132 | size_t length = 0; | |
133 | SSLCopyRequestedPeerNameLength(ctx, &length); | |
134 | if (length > 0) { | |
135 | sni = malloc(length); | |
136 | SSLCopyRequestedPeerName(ctx, sni, &length); | |
137 | } | |
138 | ||
139 | SSLProtocol version = 0; | |
140 | require_noerr(SSLGetProtocolVersionMax(ctx, &version), out); | |
141 | if (version == kSSLProtocol3) { | |
142 | ok(sni==NULL, "Unexpected SNI"); | |
143 | } else { | |
144 | ok(sni!=NULL && | |
145 | length == sizeof(peername) && | |
146 | (memcmp(sni, peername, sizeof(peername))==0), | |
147 | "SNI does not match"); | |
148 | } | |
149 | require_noerr(SSLSetCertificate(ctx, server_certs), out); | |
150 | } | |
151 | ||
152 | out: | |
153 | SSLClose(ctx); | |
154 | SSLDisposeContext(ctx); | |
155 | close(ssl->comm); | |
156 | ||
157 | pthread_exit((void *)(intptr_t)ortn); | |
158 | return NULL; | |
159 | } | |
160 | ||
161 | static void *securetransport_client_thread(void *arg) | |
162 | { | |
163 | OSStatus ortn; | |
164 | ssl_test_handle * ssl = (ssl_test_handle *)arg; | |
165 | SSLContextRef ctx = ssl->handle; | |
166 | ||
167 | do { | |
168 | ortn = SSLHandshake(ctx); | |
169 | } while (ortn == errSSLWouldBlock || ortn != errSSLClosedGraceful); | |
170 | ||
171 | SSLClose(ctx); | |
172 | SSLDisposeContext(ctx); | |
173 | close(ssl->comm); | |
174 | ||
175 | pthread_exit((void *)(intptr_t)ortn); | |
176 | return NULL; | |
177 | } | |
178 | ||
179 | static SSLCipherSuite ciphers[] = { | |
180 | TLS_RSA_WITH_AES_128_CBC_SHA, | |
181 | //FIXME: re-enable this test when its fixed. | |
182 | //TLS_RSA_WITH_RC4_128_SHA, | |
183 | }; | |
184 | ||
185 | static ssl_test_handle * | |
186 | ssl_test_handle_create(uint32_t session_id, bool server, int comm) | |
187 | { | |
188 | ssl_test_handle *handle = calloc(1, sizeof(ssl_test_handle)); | |
189 | SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, server?kSSLServerSide:kSSLClientSide, kSSLStreamType); | |
190 | ||
191 | require(handle, out); | |
192 | require(ctx, out); | |
193 | ||
194 | require_noerr(SSLSetIOFuncs(ctx, | |
195 | (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out); | |
196 | require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out); | |
197 | ||
198 | if (server) | |
199 | require_noerr(SSLSetSessionOption(ctx, | |
200 | kSSLSessionOptionBreakOnClientHello, true), out); | |
201 | else | |
202 | require_noerr(SSLSetSessionOption(ctx, | |
203 | kSSLSessionOptionBreakOnServerAuth, true), out); | |
204 | ||
205 | /* Tell SecureTransport to not check certs itself: it will break out of the | |
206 | handshake to let us take care of it instead. */ | |
207 | require_noerr(SSLSetEnableCertVerify(ctx, false), out); | |
208 | ||
209 | handle->handle = ctx; | |
210 | handle->is_server = server; | |
211 | handle->session_id = session_id; | |
212 | handle->comm = comm; | |
213 | ||
214 | return handle; | |
215 | ||
216 | out: | |
217 | if (ctx) CFRelease(ctx); | |
218 | return NULL; | |
219 | } | |
220 | ||
221 | static SSLProtocol versions[] = { | |
222 | kSSLProtocol3, | |
223 | kTLSProtocol1, | |
224 | kTLSProtocol11, | |
225 | kTLSProtocol12, | |
226 | }; | |
227 | static int nversions = sizeof(versions)/sizeof(versions[0]); | |
228 | ||
229 | static void | |
230 | tests(void) | |
231 | { | |
232 | int j; | |
233 | pthread_t client_thread, server_thread; | |
234 | ||
235 | for(j=0; j<nversions; j++) | |
236 | { | |
237 | int sp[2]; | |
238 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) exit(errno); | |
239 | ||
240 | ssl_test_handle *server, *client; | |
241 | ||
242 | uint32_t session_id = (j+1) << 16 | 1 << 8; | |
243 | server = ssl_test_handle_create(session_id, true /*server*/, sp[0]); | |
244 | client = ssl_test_handle_create(session_id, false/*client*/, sp[1]); | |
245 | ||
246 | require_noerr(SSLSetPeerID(server->handle, &session_id, sizeof(session_id)), out); | |
247 | require_noerr(SSLSetPeerID(client->handle, &session_id, sizeof(session_id)), out); | |
248 | ||
249 | /* set fixed cipher on client and server */ | |
250 | require_noerr(SSLSetEnabledCiphers(client->handle, &ciphers[0], 1), out); | |
251 | require_noerr(SSLSetEnabledCiphers(server->handle, &ciphers[0], 1), out); | |
252 | ||
253 | require_noerr(SSLSetProtocolVersionMax(client->handle, versions[j]), out); | |
254 | require_noerr(SSLSetPeerDomainName(client->handle, peername, sizeof(peername)), out); | |
255 | ||
256 | require_noerr(SSLSetProtocolVersionMax(server->handle, versions[j]), out); | |
257 | ||
258 | pthread_create(&client_thread, NULL, securetransport_client_thread, client); | |
259 | pthread_create(&server_thread, NULL, securetransport_server_thread, server); | |
260 | ||
261 | int server_err, client_err; | |
262 | pthread_join(client_thread, (void*)&client_err); | |
263 | pthread_join(server_thread, (void*)&server_err); | |
264 | ||
265 | out: | |
266 | free(client); | |
267 | free(server); | |
268 | ||
269 | } | |
270 | } | |
271 | ||
272 | int ssl_49_sni(int argc, char *const *argv) | |
273 | { | |
274 | ||
275 | plan_tests(8); | |
276 | ||
277 | ||
278 | tests(); | |
279 | ||
280 | return 0; | |
281 | } |