1/* 2 * Copyright (c) 2000-2001,2005-2007,2010-2013 Apple Inc. All Rights Reserved. 3 * 4 * The contents of this file constitute Original Code as defined in and are 5 * subject to the Apple Public Source License Version 1.2 (the 'License'). 6 * You may not use this file except in compliance with the License. Please obtain 7 * a copy of the License at http://www.apple.com/publicsource and read it before 8 * using this file. 9 * 10 * This Original Code and all software distributed under the License are 11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS 12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT 13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the 15 * specific language governing rights and limitations under the License. 16 */ 17 18 19// 20// securetransport++ - C++ interface to Apple's Secure Transport layer 21// 22#include "securetransport++.h" 23#include <security_utilities/debugging.h> 24 25 26namespace Security { 27namespace IPPlusPlus { 28 29 30// 31// Construct a core object. 32// This creates the Context object and sets the I/O functions. 33// 34SecureTransportCore::SecureTransportCore() : mAtEnd(false) 35{ 36 MacOSError::check(SSLNewContext(false, &mContext)); 37 try { 38 MacOSError::check(SSLSetIOFuncs(mContext, sslReadFunc, sslWriteFunc)); 39 MacOSError::check(SSLSetConnection(mContext, this)); 40 secdebug("ssl", "%p constructed", this); 41 } catch (...) { 42 SSLDisposeContext(mContext); 43 throw; 44 } 45} 46 47 48// 49// On destruction, we force a close and destroy the Context. 50// 51SecureTransportCore::~SecureTransportCore() 52{ 53 SSLDisposeContext(mContext); // ignore error (can't do anything if error) 54 secdebug("ssl", "%p destroyed", this); 55} 56 57 58// 59// Open initiates or continues the SSL handshake. 60// In nonblocking mode, open may return while handshake is still in 61// Progress. Keep calling open until state() != errSSLWouldBlock, or 62// go directly to I/O. 63// 64void SecureTransportCore::open() 65{ 66 switch (OSStatus err = SSLHandshake(mContext)) { 67 case errSecSuccess: 68 case errSSLWouldBlock: 69 secdebug("ssl", "%p open, state=%d", this, state()); 70 return; 71 default: 72 MacOSError::throwMe(err); 73 } 74} 75 76 77// 78// Close the SSL layer if needed. 79// Note that this does nothing to the underlying I/O layer. 80// 81void SecureTransportCore::close() 82{ 83 switch (state()) { 84 case kSSLHandshake: 85 case kSSLConnected: 86 secdebug("ssl", "%p closed", this); 87 SSLClose(mContext); 88 break; 89 default: 90 break; 91 } 92} 93 94 95// 96// Read bytes from the SSL layer. This is the standard FileDescoid 97// read function. 98// Note that if the connection is still handshaking, handshake will proceed 99// and no bytes will be read (yet). 100// 101size_t SecureTransportCore::read(void *data, size_t length) 102{ 103 if (continueHandshake()) 104 return 0; 105 size_t bytesRead; 106 switch (OSStatus err = SSLRead(mContext, data, length, &bytesRead)) { 107 case errSecSuccess: // full read 108 case errSSLWouldBlock: // partial read 109 return bytesRead; // (may be zero in non-blocking scenarios) 110 case errSSLClosedGraceful: // means end-of-data, but we may still return some 111 case errSSLClosedNoNotify: // peer closed abruptly (not sending SSL layer shutdown) 112 if (bytesRead == 0) 113 mAtEnd = true; // no more data - set final end-of-data flag 114 return bytesRead; 115 default: 116 MacOSError::throwMe(err); 117 } 118} 119 120 121// 122// Write bytes to the SSL layer. This is the standard FileDescoid write function. 123// Note that if the connection is still handshaking, handshake will proceed 124// and no bytes will be written (yet). 125// 126size_t SecureTransportCore::write(const void *data, size_t length) 127{ 128 if (continueHandshake()) 129 return 0; 130 size_t bytesWritten; 131 switch (OSStatus err = SSLWrite(mContext, data, length, &bytesWritten)) { 132 case errSecSuccess: 133 return bytesWritten; 134 case errSSLWouldBlock: 135 return 0; // no data, no error, no fuss 136 default: 137 MacOSError::throwMe(err); 138 } 139} 140 141 142// 143// Continue handshake processing if necessary. 144// Returns true if handshake is in Progress and not yet complete. 145// 146bool SecureTransportCore::continueHandshake() 147{ 148 if (state() == kSSLHandshake) { 149 // still in handshake mode; prod it along 150 secdebug("ssl", "%p continuing handshake", this); 151 switch (OSStatus err = SSLHandshake(mContext)) { 152 case errSecSuccess: 153 case errSSLWouldBlock: 154 break; 155 default: 156 MacOSError::throwMe(err); 157 } 158 IFDEBUG(if (state() != kSSLHandshake) secdebug("ssl", "%p handshake complete", this)); 159 return state() == kSSLHandshake; 160 } else 161 return false; 162} 163 164 165// 166// State access methods 167// 168SSLSessionState SecureTransportCore::state() const 169{ 170 SSLSessionState state; 171 MacOSError::check(SSLGetSessionState(mContext, &state)); 172 return state; 173} 174 175SSLProtocol SecureTransportCore::version() const 176{ 177 SSLProtocol version; 178 MacOSError::check(SSLGetProtocolVersion(mContext, &version)); 179 return version; 180} 181 182void SecureTransportCore::version(SSLProtocol version) 183{ 184 MacOSError::check(SSLSetProtocolVersion(mContext, version)); 185} 186 187size_t SecureTransportCore::numSupportedCiphers() const 188{ 189 size_t numCiphers; 190 MacOSError::check(SSLGetNumberSupportedCiphers(mContext, &numCiphers)); 191 return numCiphers; 192} 193 194void SecureTransportCore::supportedCiphers( 195 SSLCipherSuite *ciphers, 196 size_t &numCiphers) const 197{ 198 MacOSError::check(SSLGetSupportedCiphers(mContext, ciphers, &numCiphers)); 199} 200 201size_t SecureTransportCore::numEnabledCiphers() const 202{ 203 size_t numCiphers; 204 MacOSError::check(SSLGetNumberEnabledCiphers(mContext, &numCiphers)); 205 return numCiphers; 206} 207 208void SecureTransportCore::enabledCiphers( 209 SSLCipherSuite *ciphers, 210 size_t &numCiphers) const 211{ 212 MacOSError::check(SSLGetEnabledCiphers(mContext, ciphers, &numCiphers)); 213} 214 215void SecureTransportCore::enabledCiphers( 216 SSLCipherSuite *ciphers, 217 size_t numCiphers) 218{ 219 MacOSError::check(SSLSetEnabledCiphers(mContext, ciphers, numCiphers)); 220} 221 222bool SecureTransportCore::allowsExpiredCerts() const 223{ 224 Boolean allow; 225 MacOSError::check(SSLGetAllowsExpiredCerts(mContext, &allow)); 226 return allow; 227} 228 229void SecureTransportCore::allowsExpiredCerts(bool allow) 230{ 231 MacOSError::check(SSLSetAllowsExpiredCerts(mContext, allow)); 232} 233 234bool SecureTransportCore::allowsUnknownRoots() const 235{ 236 Boolean allow; 237 MacOSError::check(SSLGetAllowsAnyRoot(mContext, &allow)); 238 return allow; 239} 240 241void SecureTransportCore::allowsUnknownRoots(bool allow) 242{ 243 MacOSError::check(SSLSetAllowsAnyRoot(mContext, allow)); 244} 245 246void SecureTransportCore::peerId(const void *id, size_t length) 247{ 248 MacOSError::check(SSLSetPeerID(mContext, id, length)); 249} 250 251 252// 253// Implement SecureTransport's read/write transport functions. 254// Note that this API is very un-UNIX in that error codes (errSSLClosedGraceful, errSSLWouldBlock) 255// are returned even though data has been produced. 256// 257OSStatus SecureTransportCore::sslReadFunc(SSLConnectionRef connection, 258 void *data, size_t *length) 259{ 260 const SecureTransportCore *stc = reinterpret_cast<const SecureTransportCore *>(connection); 261 try { 262 size_t lengthRequested = *length; 263 *length = stc->ioRead(data, lengthRequested); 264 secdebug("sslconio", "%p read %lu of %lu bytes", stc, *length, lengthRequested); 265 if (*length == lengthRequested) // full deck 266 return errSecSuccess; 267 else if (stc->ioAtEnd()) { 268 secdebug("sslconio", "%p end of source input, returning %lu bytes", 269 stc, *length); 270 return errSSLClosedGraceful; 271 } else 272 return errSSLWouldBlock; 273 } catch (const UnixError &err) { 274 *length = 0; 275 if (err.error == ECONNRESET) 276 return errSSLClosedGraceful; 277 throw; 278 } catch (const CommonError &err) { 279 *length = 0; 280 return err.osStatus(); 281 } catch (...) { 282 *length = 0; 283 return -1; //@@@ generic internal error? 284 } 285} 286 287OSStatus SecureTransportCore::sslWriteFunc(SSLConnectionRef connection, 288 const void *data, size_t *length) 289{ 290 const SecureTransportCore *stc = reinterpret_cast<const SecureTransportCore *>(connection); 291 try { 292 size_t lengthRequested = *length; 293 *length = stc->ioWrite(data, lengthRequested); 294 secdebug("sslconio", "%p wrote %lu of %lu bytes", stc, *length, lengthRequested); 295 return *length == lengthRequested ? OSStatus(errSecSuccess) : OSStatus(errSSLWouldBlock); 296 } catch (const CommonError &err) { 297 *length = 0; 298 return err.osStatus(); 299 } catch (...) { 300 *length = 0; 301 return -1; //@@@ generic internal error? 302 } 303} 304 305 306} // end namespace IPPlusPlus 307} // end namespace Security 308