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