1/* 2 * sslEAP - test EAP-FAST style PAC-based session resumption. 3 * 4 * This only works with a debug Security.framework since server side 5 * PAC support is not present in deployment builds. 6 * 7 * Written by Doug Mitchell. 8 */ 9#include <Security/SecureTransport.h> 10#include <Security/SecureTransportPriv.h> 11#include <clAppUtils/sslAppUtils.h> 12#include <security_cdsa_utils/cuFileIo.h> 13#include <utilLib/common.h> 14#include <clAppUtils/ringBufferIo.h> 15#include "ringBufferThreads.h" /* like the ones in clAppUtils, tailored for EAP/PAC */ 16 17#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h> 18#include <stdio.h> 19#include <stdlib.h> 20#include <string.h> 21#include <time.h> 22#include <ctype.h> 23#include <sys/param.h> 24#include <CoreFoundation/CoreFoundation.h> 25#include <security_utilities/devrandom.h> 26 27#define DEFAULT_XFER 1024 /* total xfer size in bytes */ 28 29/* we might make these user-tweakable */ 30#define DEFAULT_NUM_BUFS 16 31#define DEFAULT_BUF_SIZE 2048 /* in the ring buffers */ 32#define DEFAULT_CHUNK 1024 /* bytes to write per SSLWrite() */ 33#define SESSION_TICKET_SIZE 512 34 35static void usage(char **argv) 36{ 37 printf("Usage: %s [option ...]\n", argv[0]); 38 printf("Options:\n"); 39 printf(" -x transferSize -- default=%d; 0=forever\n", DEFAULT_XFER); 40 printf(" -k keychainName -- not needed if PAC will be done\n"); 41 printf(" -n -- *NO* PAC\n"); 42 printf(" -h hostName -- force a SSLSetPeerDomainName on client side\n"); 43 printf(" -p (pause on error)\n"); 44 exit(1); 45} 46 47int main(int argc, char **argv) 48{ 49 RingBuffer serverToClientRing; 50 RingBuffer clientToServerRing; 51 unsigned numBufs = DEFAULT_NUM_BUFS; 52 unsigned bufSize = DEFAULT_BUF_SIZE; 53 unsigned chunkSize = DEFAULT_CHUNK; 54 unsigned char clientBuf[DEFAULT_CHUNK]; 55 unsigned char serverBuf[DEFAULT_CHUNK]; 56 RingBufferArgs clientArgs; 57 RingBufferArgs serverArgs; 58 bool abortFlag = false; 59 pthread_t client_thread = NULL; 60 int result; 61 OSStatus ortn; 62 unsigned char sessionTicket[SESSION_TICKET_SIZE]; 63 int ourRtn = 0; 64 CFArrayRef idArray = NULL; /* for SSLSetCertificate */ 65 CFArrayRef anchorArray = NULL; /* trusted roots */ 66 char *hostName = NULL; 67 68 /* user-spec'd variables */ 69 char *kcName = NULL; 70 unsigned xferSize = DEFAULT_XFER; 71 bool pauseOnError = false; 72 bool runForever = false; 73 bool skipPAC = false; 74 75 extern int optind; 76 extern char *optarg; 77 int arg; 78 optind = 1; 79 while ((arg = getopt(argc, argv, "x:c:k:h:np")) != -1) { 80 switch (arg) { 81 case 'x': 82 { 83 unsigned xsize = atoi(optarg); 84 if(xsize == 0) { 85 runForever = true; 86 /* and leave xferSize alone */ 87 } 88 else { 89 xferSize = xsize; 90 } 91 break; 92 } 93 case 'k': 94 kcName = optarg; 95 break; 96 case 'n': 97 skipPAC = true; 98 break; 99 case 'h': 100 /* mainly to test EAP session ticket and ServerName simultaneously */ 101 hostName = optarg; 102 break; 103 case 'p': 104 pauseOnError = true; 105 break; 106 default: 107 usage(argv); 108 } 109 } 110 if(optind != argc) { 111 usage(argv); 112 } 113 114 /* set up ring buffers */ 115 ringBufSetup(&serverToClientRing, "serveToClient", numBufs, bufSize); 116 ringBufSetup(&clientToServerRing, "clientToServe", numBufs, bufSize); 117 118 /* get optional server SecIdentity */ 119 if(kcName) { 120 SecKeychainRef kcRef = NULL; 121 SecCertificateRef anchorCert = NULL; 122 SecIdentityRef idRef = NULL; 123 idArray = getSslCerts(kcName, 124 CSSM_FALSE, /* encryptOnly */ 125 CSSM_FALSE, /* completeCertChain */ 126 NULL, /* anchorFile */ 127 &kcRef); 128 if(idArray == NULL) { 129 printf("***Can't get signing cert from %s\n", kcName); 130 exit(1); 131 } 132 idRef = (SecIdentityRef)CFArrayGetValueAtIndex(idArray, 0); 133 ortn = SecIdentityCopyCertificate(idRef, &anchorCert); 134 if(ortn) { 135 cssmPerror("SecIdentityCopyCertificate", ortn); 136 exit(1); 137 } 138 anchorArray = CFArrayCreate(NULL, (const void **)&anchorCert, 139 1, &kCFTypeArrayCallBacks); 140 CFRelease(kcRef); 141 CFRelease(anchorCert); 142 } 143 144 /* set up server side */ 145 memset(&serverArgs, 0, sizeof(serverArgs)); 146 serverArgs.xferSize = xferSize; 147 serverArgs.xferBuf = serverBuf; 148 serverArgs.chunkSize = chunkSize; 149 serverArgs.ringWrite = &serverToClientRing; 150 serverArgs.ringRead = &clientToServerRing; 151 serverArgs.goFlag = &clientArgs.iAmReady; 152 serverArgs.abortFlag = &abortFlag; 153 serverArgs.pauseOnError = pauseOnError; 154 appGetRandomBytes(serverArgs.sharedSecret, SHARED_SECRET_SIZE); 155 if(!skipPAC) { 156 serverArgs.setMasterSecret = true; 157 } 158 serverArgs.idArray = idArray; 159 serverArgs.trustedRoots = anchorArray; 160 161 /* set up client side */ 162 memset(&clientArgs, 0, sizeof(clientArgs)); 163 clientArgs.xferSize = xferSize; 164 clientArgs.xferBuf = clientBuf; 165 clientArgs.chunkSize = chunkSize; 166 clientArgs.ringWrite = &clientToServerRing; 167 clientArgs.ringRead = &serverToClientRing; 168 clientArgs.goFlag = &serverArgs.iAmReady; 169 clientArgs.abortFlag = &abortFlag; 170 clientArgs.pauseOnError = pauseOnError; 171 memmove(clientArgs.sharedSecret, serverArgs.sharedSecret, SHARED_SECRET_SIZE); 172 clientArgs.hostName = hostName; 173 174 /* for now set up an easily recognizable ticket */ 175 for(unsigned dex=0; dex<SESSION_TICKET_SIZE; dex++) { 176 sessionTicket[dex] = dex; 177 } 178 clientArgs.sessionTicket = sessionTicket; 179 clientArgs.sessionTicketLen = SESSION_TICKET_SIZE; 180 /* client always tries setting the master secret in this test */ 181 clientArgs.setMasterSecret = true; 182 clientArgs.trustedRoots = anchorArray; 183 184 /* fire up client thread */ 185 result = pthread_create(&client_thread, NULL, 186 rbClientThread, &clientArgs); 187 if(result) { 188 printf("***pthread_create returned %d, aborting\n", result); 189 exit(1); 190 } 191 192 /* 193 * And the server pseudo thread. This returns when all data has been transferred. 194 */ 195 ortn = rbServerThread(&serverArgs); 196 197 if(abortFlag) { 198 printf("***Test aborted.\n"); 199 exit(1); 200 } 201 202 printf("\n"); 203 204 printf("SSL Protocol Version : %s\n", 205 sslGetProtocolVersionString(serverArgs.negotiatedProt)); 206 printf("SSL Cipher : %s\n", 207 sslGetCipherSuiteString(serverArgs.negotiatedCipher)); 208 209 if(skipPAC) { 210 if(clientArgs.sessionWasResumed) { 211 printf("***skipPAC true, but client reported sessionWasResumed\n"); 212 ourRtn = -1; 213 } 214 if(serverArgs.sessionWasResumed) { 215 printf("***skipPAC true, but server reported sessionWasResumed\n"); 216 ourRtn = -1; 217 } 218 if(ourRtn == 0) { 219 printf("...PAC session attempted by client; refused by server;\n"); 220 printf(" Normal session proceeded correctly.\n"); 221 } 222 } 223 else { 224 if(!clientArgs.sessionWasResumed) { 225 printf("***client reported !sessionWasResumed\n"); 226 ourRtn = -1; 227 } 228 if(!serverArgs.sessionWasResumed) { 229 printf("***server reported !sessionWasResumed\n"); 230 ourRtn = -1; 231 } 232 if(memcmp(clientBuf, serverBuf, DEFAULT_CHUNK)) { 233 printf("***Data miscompare***\n"); 234 ourRtn = -1; 235 } 236 if(ourRtn == 0) { 237 printf("...PAC session resumed correctly.\n"); 238 } 239 } 240 /* FIXME other stuff? */ 241 242 return ourRtn; 243} 244 245 246 247