+++ /dev/null
-/*
- * Copyright (c) 2000-2001,2005-2007,2010-2013 Apple Inc. All Rights Reserved.
- *
- * The contents of this file constitute Original Code as defined in and are
- * subject to the Apple Public Source License Version 1.2 (the 'License').
- * You may not use this file except in compliance with the License. Please obtain
- * a copy of the License at http://www.apple.com/publicsource and read it before
- * using this file.
- *
- * This Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
- * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
- * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
- * specific language governing rights and limitations under the License.
- */
-
-
-//
-// securetransport++ - C++ interface to Apple's Secure Transport layer
-//
-#include "securetransport++.h"
-#include <security_utilities/debugging.h>
-
-
-namespace Security {
-namespace IPPlusPlus {
-
-
-//
-// Construct a core object.
-// This creates the Context object and sets the I/O functions.
-//
-SecureTransportCore::SecureTransportCore() : mAtEnd(false)
-{
- MacOSError::check(SSLNewContext(false, &mContext));
- try {
- MacOSError::check(SSLSetIOFuncs(mContext, sslReadFunc, sslWriteFunc));
- MacOSError::check(SSLSetConnection(mContext, this));
- secdebug("ssl", "%p constructed", this);
- } catch (...) {
- SSLDisposeContext(mContext);
- throw;
- }
-}
-
-
-//
-// On destruction, we force a close and destroy the Context.
-//
-SecureTransportCore::~SecureTransportCore()
-{
- SSLDisposeContext(mContext); // ignore error (can't do anything if error)
- secdebug("ssl", "%p destroyed", this);
-}
-
-
-//
-// Open initiates or continues the SSL handshake.
-// In nonblocking mode, open may return while handshake is still in
-// Progress. Keep calling open until state() != errSSLWouldBlock, or
-// go directly to I/O.
-//
-void SecureTransportCore::open()
-{
- switch (OSStatus err = SSLHandshake(mContext)) {
- case errSecSuccess:
- case errSSLWouldBlock:
- secdebug("ssl", "%p open, state=%d", this, state());
- return;
- default:
- MacOSError::throwMe(err);
- }
-}
-
-
-//
-// Close the SSL layer if needed.
-// Note that this does nothing to the underlying I/O layer.
-//
-void SecureTransportCore::close()
-{
- switch (state()) {
- case kSSLHandshake:
- case kSSLConnected:
- secdebug("ssl", "%p closed", this);
- SSLClose(mContext);
- break;
- default:
- break;
- }
-}
-
-
-//
-// Read bytes from the SSL layer. This is the standard FileDescoid
-// read function.
-// Note that if the connection is still handshaking, handshake will proceed
-// and no bytes will be read (yet).
-//
-size_t SecureTransportCore::read(void *data, size_t length)
-{
- if (continueHandshake())
- return 0;
- size_t bytesRead;
- switch (OSStatus err = SSLRead(mContext, data, length, &bytesRead)) {
- case errSecSuccess: // full read
- case errSSLWouldBlock: // partial read
- return bytesRead; // (may be zero in non-blocking scenarios)
- case errSSLClosedGraceful: // means end-of-data, but we may still return some
- case errSSLClosedNoNotify: // peer closed abruptly (not sending SSL layer shutdown)
- if (bytesRead == 0)
- mAtEnd = true; // no more data - set final end-of-data flag
- return bytesRead;
- default:
- MacOSError::throwMe(err);
- }
-}
-
-
-//
-// Write bytes to the SSL layer. This is the standard FileDescoid write function.
-// Note that if the connection is still handshaking, handshake will proceed
-// and no bytes will be written (yet).
-//
-size_t SecureTransportCore::write(const void *data, size_t length)
-{
- if (continueHandshake())
- return 0;
- size_t bytesWritten;
- switch (OSStatus err = SSLWrite(mContext, data, length, &bytesWritten)) {
- case errSecSuccess:
- return bytesWritten;
- case errSSLWouldBlock:
- return 0; // no data, no error, no fuss
- default:
- MacOSError::throwMe(err);
- }
-}
-
-
-//
-// Continue handshake processing if necessary.
-// Returns true if handshake is in Progress and not yet complete.
-//
-bool SecureTransportCore::continueHandshake()
-{
- if (state() == kSSLHandshake) {
- // still in handshake mode; prod it along
- secdebug("ssl", "%p continuing handshake", this);
- switch (OSStatus err = SSLHandshake(mContext)) {
- case errSecSuccess:
- case errSSLWouldBlock:
- break;
- default:
- MacOSError::throwMe(err);
- }
- IFDEBUG(if (state() != kSSLHandshake) secdebug("ssl", "%p handshake complete", this));
- return state() == kSSLHandshake;
- } else
- return false;
-}
-
-
-//
-// State access methods
-//
-SSLSessionState SecureTransportCore::state() const
-{
- SSLSessionState state;
- MacOSError::check(SSLGetSessionState(mContext, &state));
- return state;
-}
-
-SSLProtocol SecureTransportCore::version() const
-{
- SSLProtocol version;
- MacOSError::check(SSLGetProtocolVersion(mContext, &version));
- return version;
-}
-
-void SecureTransportCore::version(SSLProtocol version)
-{
- MacOSError::check(SSLSetProtocolVersion(mContext, version));
-}
-
-size_t SecureTransportCore::numSupportedCiphers() const
-{
- size_t numCiphers;
- MacOSError::check(SSLGetNumberSupportedCiphers(mContext, &numCiphers));
- return numCiphers;
-}
-
-void SecureTransportCore::supportedCiphers(
- SSLCipherSuite *ciphers,
- size_t &numCiphers) const
-{
- MacOSError::check(SSLGetSupportedCiphers(mContext, ciphers, &numCiphers));
-}
-
-size_t SecureTransportCore::numEnabledCiphers() const
-{
- size_t numCiphers;
- MacOSError::check(SSLGetNumberEnabledCiphers(mContext, &numCiphers));
- return numCiphers;
-}
-
-void SecureTransportCore::enabledCiphers(
- SSLCipherSuite *ciphers,
- size_t &numCiphers) const
-{
- MacOSError::check(SSLGetEnabledCiphers(mContext, ciphers, &numCiphers));
-}
-
-void SecureTransportCore::enabledCiphers(
- SSLCipherSuite *ciphers,
- size_t numCiphers)
-{
- MacOSError::check(SSLSetEnabledCiphers(mContext, ciphers, numCiphers));
-}
-
-bool SecureTransportCore::allowsExpiredCerts() const
-{
- Boolean allow;
- MacOSError::check(SSLGetAllowsExpiredCerts(mContext, &allow));
- return allow;
-}
-
-void SecureTransportCore::allowsExpiredCerts(bool allow)
-{
- MacOSError::check(SSLSetAllowsExpiredCerts(mContext, allow));
-}
-
-bool SecureTransportCore::allowsUnknownRoots() const
-{
- Boolean allow;
- MacOSError::check(SSLGetAllowsAnyRoot(mContext, &allow));
- return allow;
-}
-
-void SecureTransportCore::allowsUnknownRoots(bool allow)
-{
- MacOSError::check(SSLSetAllowsAnyRoot(mContext, allow));
-}
-
-void SecureTransportCore::peerId(const void *id, size_t length)
-{
- MacOSError::check(SSLSetPeerID(mContext, id, length));
-}
-
-
-//
-// Implement SecureTransport's read/write transport functions.
-// Note that this API is very un-UNIX in that error codes (errSSLClosedGraceful, errSSLWouldBlock)
-// are returned even though data has been produced.
-//
-OSStatus SecureTransportCore::sslReadFunc(SSLConnectionRef connection,
- void *data, size_t *length)
-{
- const SecureTransportCore *stc = reinterpret_cast<const SecureTransportCore *>(connection);
- try {
- size_t lengthRequested = *length;
- *length = stc->ioRead(data, lengthRequested);
- secdebug("sslconio", "%p read %lu of %lu bytes", stc, *length, lengthRequested);
- if (*length == lengthRequested) // full deck
- return errSecSuccess;
- else if (stc->ioAtEnd()) {
- secdebug("sslconio", "%p end of source input, returning %lu bytes",
- stc, *length);
- return errSSLClosedGraceful;
- } else
- return errSSLWouldBlock;
- } catch (const UnixError &err) {
- *length = 0;
- if (err.error == ECONNRESET)
- return errSSLClosedGraceful;
- throw;
- } catch (const CommonError &err) {
- *length = 0;
- return err.osStatus();
- } catch (...) {
- *length = 0;
- return -1; //@@@ generic internal error?
- }
-}
-
-OSStatus SecureTransportCore::sslWriteFunc(SSLConnectionRef connection,
- const void *data, size_t *length)
-{
- const SecureTransportCore *stc = reinterpret_cast<const SecureTransportCore *>(connection);
- try {
- size_t lengthRequested = *length;
- *length = stc->ioWrite(data, lengthRequested);
- secdebug("sslconio", "%p wrote %lu of %lu bytes", stc, *length, lengthRequested);
- return *length == lengthRequested ? OSStatus(errSecSuccess) : OSStatus(errSSLWouldBlock);
- } catch (const CommonError &err) {
- *length = 0;
- return err.osStatus();
- } catch (...) {
- *length = 0;
- return -1; //@@@ generic internal error?
- }
-}
-
-
-} // end namespace IPPlusPlus
-} // end namespace Security