1
2#include <stdbool.h>
3#include <pthread.h>
4#include <fcntl.h>
5#include <sys/mman.h>
6#include <unistd.h>
7
8#include <CoreFoundation/CoreFoundation.h>
9
10#include <AssertMacros.h>
11#include <Security/SecureTransportPriv.h> /* SSLSetOption */
12#include <Security/SecureTransport.h>
13#include <Security/SecPolicy.h>
14#include <Security/SecTrust.h>
15#include <Security/SecIdentity.h>
16#include <Security/SecIdentityPriv.h>
17#include <Security/SecCertificatePriv.h>
18#include <Security/SecKeyPriv.h>
19#include <Security/SecItem.h>
20#include <Security/SecRandom.h>
21
22#include <utilities/array_size.h>
23#include <string.h>
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <errno.h>
27#include <stdlib.h>
28#include <mach/mach_time.h>
29
30#include <stdio.h>
31#include <unistd.h>
32#include <strings.h>
33#include <sys/types.h>
34#include <sys/socket.h>
35#include <netinet/in.h>
36#include <arpa/inet.h>
37#include <netdb.h>
38#include <errno.h>
39
40
41#if TARGET_OS_IPHONE
42#include <Security/SecRSAKey.h>
43#endif
44
45#include "ssl_regressions.h"
46#include "ssl-utils.h"
47
48typedef struct {
49    SSLContextRef st;
50    int comm;
51    CFArrayRef certs;
52} ssl_test_handle;
53
54
55// MARK: -
56// MARK: SecureTransport support
57
58#if 0
59static void hexdump(const uint8_t *bytes, size_t len) {
60	size_t ix;
61    printf("socket write(%p, %lu)\n", bytes, len);
62	for (ix = 0; ix < len; ++ix) {
63        if (!(ix % 16))
64            printf("\n");
65		printf("%02X ", bytes[ix]);
66	}
67	printf("\n");
68}
69#else
70#define hexdump(bytes, len)
71#endif
72
73
74/* Listen to on port */
75static int SocketListen(int port)
76{
77    struct sockaddr_in  sa;
78    int					sock;
79    int                 val  = 1;
80
81    if ((sock=socket(AF_INET, SOCK_STREAM, 0))==-1) {
82        perror("socket");
83        return -errno;
84    }
85
86    setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&val, sizeof(val));
87
88    memset((char *) &sa, 0, sizeof(sa));
89    sa.sin_family = AF_INET;
90    sa.sin_port = htons(port);
91    sa.sin_addr.s_addr = htonl(INADDR_ANY);
92
93    if(bind (sock, (struct sockaddr *)&sa, sizeof(sa))==-1)
94    {
95        perror("bind");
96        return -errno;
97    }
98
99    if(listen(sock, 5)==-1)
100    {
101        perror("listen");
102        return -errno;
103    }
104
105    return sock;
106}
107
108
109static OSStatus SocketWrite(SSLConnectionRef conn, const void *data, size_t *length)
110{
111	size_t len = *length;
112	uint8_t *ptr = (uint8_t *)data;
113
114    do {
115        ssize_t ret;
116        do {
117            hexdump(ptr, len);
118            ret = write((int)conn, ptr, len);
119        } while ((ret < 0) && (errno == EAGAIN || errno == EINTR));
120        if (ret > 0) {
121            len -= ret;
122            ptr += ret;
123        }
124        else
125            return -36;
126    } while (len > 0);
127
128    *length = *length - len;
129    return errSecSuccess;
130}
131
132static OSStatus SocketRead(SSLConnectionRef conn, void *data, size_t *length)
133{
134	size_t len = *length;
135	uint8_t *ptr = (uint8_t *)data;
136
137    do {
138        ssize_t ret;
139        do {
140            ret = read((int)conn, ptr, len);
141        } while ((ret < 0) && (errno == EINPROGRESS || errno == EAGAIN || errno == EINTR));
142        if (ret > 0) {
143            len -= ret;
144            ptr += ret;
145        } else {
146            printf("read error(%d): ret=%zd, errno=%d\n", (int)conn, ret, errno);
147            return -errno;
148        }
149    } while (len > 0);
150
151    *length = *length - len;
152    return errSecSuccess;
153}
154
155
156static SSLContextRef make_ssl_ref(bool server, int sock, CFArrayRef certs)
157{
158    SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, server?kSSLServerSide:kSSLClientSide, kSSLStreamType);
159    require(ctx, out);
160
161    require_noerr(SSLSetIOFuncs(ctx, (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
162    require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)sock), out);
163    require_noerr(SSLSetCertificate(ctx, certs), out);
164
165    return ctx;
166out:
167    if (ctx)
168        CFRelease(ctx);
169    return NULL;
170}
171
172
173static ssl_test_handle *
174ssl_test_handle_create(int comm, CFArrayRef certs)
175{
176    ssl_test_handle *handle = calloc(1, sizeof(ssl_test_handle));
177    if (handle) {
178        handle->comm = comm;
179        handle->certs = certs;
180        handle->st = make_ssl_ref(true, comm, certs);
181    }
182    return handle;
183}
184
185static void *securetransport_ssl_thread(void *arg)
186{
187    OSStatus ortn;
188    int sock = (int)arg;
189
190    int socket = accept(sock, NULL, NULL);
191
192    CFArrayRef server_certs = server_chain();
193    ssl_test_handle * ssl = ssl_test_handle_create(socket, server_certs);
194    SSLContextRef ctx = ssl->st;
195
196    pthread_setname_np("server thread");
197
198    //uint64_t start = mach_absolute_time();
199    do {
200        ortn = SSLHandshake(ctx);
201    } while (ortn == errSSLWouldBlock);
202
203    require_noerr_action_quiet(ortn, out,
204                               fprintf(stderr, "Fell out of SSLHandshake with error: %d\n", (int)ortn));
205
206    //uint64_t elapsed = mach_absolute_time() - start;
207    //fprintf(stderr, "setr elapsed: %lld\n", elapsed);
208
209    /*
210    SSLProtocol proto = kSSLProtocolUnknown;
211    require_noerr_quiet(SSLGetNegotiatedProtocolVersion(ctx, &proto), out); */
212
213    SSLCipherSuite cipherSuite;
214    require_noerr_quiet(ortn = SSLGetNegotiatedCipher(ctx, &cipherSuite), out);
215    //fprintf(stderr, "st negotiated %s\n", sslcipher_itoa(cipherSuite));
216
217
218out:
219    CFRelease(server_certs);
220
221    SSLClose(ctx);
222    CFRelease(ctx);
223    if(ssl) {
224        close(ssl->comm);
225        free(ssl);
226    }
227    pthread_exit((void *)(intptr_t)ortn);
228    return NULL;
229}
230
231
232
233static void
234tests(void)
235{
236    pthread_t server_thread;
237    int socket;
238
239    socket = SocketListen(4443);
240
241    ok(socket>=0, "SocketListen failed");
242    if(socket<0) {
243        return;
244    }
245    //fprintf(stderr, "session_id: %d\n", session_id);
246
247    pthread_create(&server_thread, NULL, securetransport_ssl_thread, socket);
248
249    system("/usr/bin/openssl s_client -msg -debug -connect localhost:4443");
250
251    int server_err;
252    pthread_join(server_thread, (void*)&server_err);
253
254    ok(!server_err, "Server thread failed err=%d", server_err);
255}
256
257int ssl_50_server(int argc, char *const *argv)
258{
259
260    plan_tests(1 + 1 /*cert*/);
261
262
263    tests();
264
265    return 0;
266}
267