1/* 2 * Copyright (c) 2006-2008,2010-2011,2013 Apple Inc. All Rights Reserved. 3 * 4 * sslClient.cpp : perform one SSL client side sesssion 5 */ 6 7#include <Security/SecureTransport.h> 8#include <Security/Security.h> 9#include <clAppUtils/sslAppUtils.h> 10#include <clAppUtils/ioSock.h> 11#include <clAppUtils/sslThreading.h> 12#include <utilLib/fileIo.h> 13#include <utilLib/common.h> 14#include <security_cdsa_utils/cuPrintCert.h> 15 16#include <Security/SecBase.h> 17 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 25/* when true, keep listening until server disconnects */ 26#define KEEP_CONNECTED 1 27 28#define CLIENT_GETMSG "GET / HTTP/1.0\r\n\r\n" 29 30#define READBUF_LEN 256 31 32/* relies on SSLSetProtocolVersionEnabled */ 33OSStatus sslAppClient( 34 SslAppTestParams *params) 35{ 36 PeerSpec peerId; 37 otSocket sock = 0; 38 OSStatus ortn; 39 SSLContextRef ctx = NULL; 40 SecKeychainRef clientKc = nil; 41 CFArrayRef clientCerts = nil; 42 43 sslThrDebug("Client", "starting"); 44 params->negVersion = kSSLProtocolUnknown; 45 params->negCipher = SSL_NULL_WITH_NULL_NULL; 46 params->ortn = noHardwareErr; 47 48 /* first make sure requested server is there */ 49 ortn = MakeServerConnection(params->hostName, params->port, 50 params->nonBlocking, &sock, &peerId); 51 if(ortn) { 52 printf("MakeServerConnection returned %d; aborting\n", (int)ortn); 53 return ortn; 54 } 55 56 /* 57 * Set up a SecureTransport session. 58 */ 59 ortn = SSLNewContext(false, &ctx); 60 if(ortn) { 61 printSslErrStr("SSLNewContext", ortn); 62 goto cleanup; 63 } 64 ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite); 65 if(ortn) { 66 printSslErrStr("SSLSetIOFuncs", ortn); 67 goto cleanup; 68 } 69 ortn = SSLSetConnection(ctx, (SSLConnectionRef)sock); 70 if(ortn) { 71 printSslErrStr("SSLSetConnection", ortn); 72 goto cleanup; 73 } 74 if(!params->skipHostNameCheck) { 75 ortn = SSLSetPeerDomainName(ctx, params->hostName, 76 strlen(params->hostName)); 77 if(ortn) { 78 printSslErrStr("SSLSetPeerDomainName", ortn); 79 goto cleanup; 80 } 81 } 82 83 /* remainder of setup is optional */ 84 if(params->anchorFile) { 85 ortn = sslAddTrustedRoot(ctx, params->anchorFile, params->replaceAnchors); 86 if(ortn) { 87 goto cleanup; 88 } 89 } 90 ortn = sslSetProtocols(ctx, params->acceptedProts, params->tryVersion); 91 if(ortn) { 92 goto cleanup; 93 } 94 if(params->resumeEnable) { 95 ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec)); 96 if(ortn) { 97 printSslErrStr("SSLSetPeerID", ortn); 98 goto cleanup; 99 } 100 } 101 if(params->disableCertVerify) { 102 ortn = SSLSetEnableCertVerify(ctx, false); 103 if(ortn) { 104 printSslErrStr("SSLSetEnableCertVerify", ortn); 105 goto cleanup; 106 } 107 } 108 if(params->ciphers != NULL) { 109 ortn = sslSetEnabledCiphers(ctx, params->ciphers); 110 if(ortn) { 111 goto cleanup; 112 } 113 } 114 if(params->myCertKcName) { 115 clientCerts = getSslCerts(params->myCertKcName, false, false, NULL, &clientKc); 116 if(clientCerts == nil) { 117 exit(1); 118 } 119 if(params->password) { 120 ortn = SecKeychainUnlock(clientKc, strlen(params->password), 121 (void *)params->password, true); 122 if(ortn) { 123 printf("SecKeychainUnlock returned %d\n", (int)ortn); 124 /* oh well */ 125 } 126 } 127 if(params->idIsTrustedRoot) { 128 /* assume this is a root we want to implicitly trust */ 129 ortn = addIdentityAsTrustedRoot(ctx, clientCerts); 130 if(ortn) { 131 goto cleanup; 132 } 133 } 134 ortn = SSLSetCertificate(ctx, clientCerts); 135 if(ortn) { 136 printSslErrStr("SSLSetCertificate", ortn); 137 goto cleanup; 138 } 139 } 140 do { 141 ortn = SSLHandshake(ctx); 142 if((ortn == errSSLWouldBlock) && !params->silent) { 143 /* keep UI responsive */ 144 sslOutputDot(); 145 } 146 } while (ortn == errSSLWouldBlock); 147 148 SSLGetClientCertificateState(ctx, ¶ms->certState); 149 SSLGetNegotiatedCipher(ctx, ¶ms->negCipher); 150 SSLGetNegotiatedProtocolVersion(ctx, ¶ms->negVersion); 151 152 if(ortn != errSecSuccess) { 153 goto cleanup; 154 } 155 156 /* send a GET msg */ 157 size_t actLen; 158 ortn = SSLWrite(ctx, CLIENT_GETMSG, strlen(CLIENT_GETMSG), &actLen); 159 if(ortn) { 160 printSslErrStr("SSLWrite", ortn); 161 goto cleanup; 162 } 163 164 #if KEEP_CONNECTED 165 166 /* 167 * Consume any server data and wait for server to disconnect 168 */ 169 char readBuf[READBUF_LEN]; 170 do { 171 ortn = SSLRead(ctx, readBuf, READBUF_LEN, &actLen); 172 } while (ortn == errSSLWouldBlock); 173 174 /* convert normal "shutdown" into zero err rtn */ 175 if(ortn == errSSLClosedGraceful) { 176 ortn = errSecSuccess; 177 } 178 #endif /* KEEP_CONNECTED */ 179 180cleanup: 181 if(ctx) { 182 OSStatus cerr = SSLClose(ctx); 183 if(ortn == errSecSuccess) { 184 ortn = cerr; 185 } 186 } 187 if(sock) { 188 endpointShutdown(sock); 189 } 190 if(ctx) { 191 SSLDisposeContext(ctx); 192 } 193 params->ortn = ortn; 194 sslThrDebug("Client", "done"); 195 return ortn; 196} 197