securetransport++.cpp [plain text]
#include "securetransport++.h"
#include <security_utilities/debugging.h>
namespace Security {
namespace IPPlusPlus {
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;
}
}
SecureTransportCore::~SecureTransportCore()
{
SSLDisposeContext(mContext); secdebug("ssl", "%p destroyed", this);
}
void SecureTransportCore::open()
{
switch (OSStatus err = SSLHandshake(mContext)) {
case noErr:
case errSSLWouldBlock:
secdebug("ssl", "%p open, state=%d", this, state());
return;
default:
MacOSError::throwMe(err);
}
}
void SecureTransportCore::close()
{
switch (state()) {
case kSSLHandshake:
case kSSLConnected:
secdebug("ssl", "%p closed", this);
SSLClose(mContext);
break;
default:
break;
}
}
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 noErr: case errSSLWouldBlock: return bytesRead; case errSSLClosedGraceful: case errSSLClosedNoNotify: if (bytesRead == 0)
mAtEnd = true; return bytesRead;
default:
MacOSError::throwMe(err);
}
}
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 noErr:
return bytesWritten;
case errSSLWouldBlock:
return 0; default:
MacOSError::throwMe(err);
}
}
bool SecureTransportCore::continueHandshake()
{
if (state() == kSSLHandshake) {
secdebug("ssl", "%p continuing handshake", this);
switch (OSStatus err = SSLHandshake(mContext)) {
case noErr:
case errSSLWouldBlock:
break;
default:
MacOSError::throwMe(err);
}
IFDEBUG(if (state() != kSSLHandshake) secdebug("ssl", "%p handshake complete", this));
return state() == kSSLHandshake;
} else
return false;
}
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));
}
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) return noErr;
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; }
}
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(noErr) : OSStatus(errSSLWouldBlock);
} catch (const CommonError &err) {
*length = 0;
return err.osStatus();
} catch (...) {
*length = 0;
return -1; }
}
} }