#include "ssl.h"
#include "sslctx.h"
#include "sslalloc.h"
#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
#include "digests.h"
#include "sslDebug.h"
#include "appleCdsa.h"
#include "appleGlue.h"
#include "sslKeychain.h"
#include "sslutil.h"
#include "cipherSpecs.h"
#include <string.h>
static void sslFreeDnList(
SSLContext *ctx)
{
DNListElem *dn, *nextDN;
SSLBuffer buf;
dn = ctx->acceptableDNList;
while (dn)
{
SSLFreeBuffer(&dn->derDN, &ctx->sysCtx);
nextDN = dn->next;
buf.data = (uint8*)dn;
buf.length = sizeof(DNListElem);
SSLFreeBuffer(&buf, &ctx->sysCtx);
dn = nextDN;
}
ctx->acceptableDNList = NULL;
}
static SSLErr sslFreeTrustedRoots(
SSLContext *ctx)
{
int i;
CASSERT(ctx != NULL);
if((ctx->numTrustedCerts == 0) || (ctx->trustedCerts == NULL)) {
CASSERT((ctx->numTrustedCerts == 0) && (ctx->trustedCerts == NULL));
}
else {
for(i=0; i<ctx->numTrustedCerts; i++) {
stFreeCssmData(&ctx->trustedCerts[i], CSSM_FALSE);
}
sslFree(ctx->trustedCerts);
}
ctx->numTrustedCerts = 0;
ctx->trustedCerts = NULL;
sslFreeDnList(ctx);
return SSLNoErr;
}
OSStatus
SSLNewContext (Boolean isServer,
SSLContextRef *contextPtr)
{
SSLContext *ctx;
OSStatus oerr;
SSLErr serr;
if(contextPtr == NULL) {
return paramErr;
}
*contextPtr = NULL;
ctx = (SSLContext *)sslMalloc(sizeof(SSLContext));
if(ctx == NULL) {
return memFullErr;
}
memset(ctx, 0, sizeof(SSLContext));
ctx->state = SSLUninitialized;
if(isServer) {
ctx->protocolSide = SSL_ServerSide;
ctx->reqProtocolVersion = SSL_Version_3_0;
}
else {
ctx->protocolSide = SSL_ClientSide;
ctx->reqProtocolVersion = SSL_Version_Undetermined;
}
ctx->negProtocolVersion = SSL_Version_Undetermined;
ctx->selectedCipherSpec = &SSL_NULL_WITH_NULL_NULL_CipherSpec;
ctx->selectedCipher = ctx->selectedCipherSpec->cipherSpec;
ctx->writeCipher.hash = ctx->selectedCipherSpec->macAlgorithm;
ctx->readCipher.hash = ctx->selectedCipherSpec->macAlgorithm;
ctx->readCipher.symCipher = ctx->selectedCipherSpec->cipher;
ctx->writeCipher.symCipher = ctx->selectedCipherSpec->cipher;
#if _APPLE_CDSA_
ctx->writeCipher.encrypting = 1;
ctx->writePending.encrypting = 1;
#endif
ctx->validCipherSpecs = NULL;
ctx->numValidCipherSpecs = 0;
SSLInitMACPads();
if(cfSetUpAllocators(ctx)) {
oerr = memFullErr;
goto errOut;
}
serr = attachToAll(ctx);
if(serr) {
oerr = sslErrToOsStatus(serr);
goto errOut;
}
addBuiltInCerts(ctx);
*contextPtr = ctx;
return noErr;
errOut:
sslFree(ctx);
return oerr;
}
OSStatus
SSLDisposeContext (SSLContext *ctx)
{
WaitingRecord *wait, *next;
SSLBuffer buf;
if(ctx == NULL) {
return paramErr;
}
sslDeleteCertificateChain(ctx->localCert, ctx);
sslDeleteCertificateChain(ctx->encryptCert, ctx);
sslDeleteCertificateChain(ctx->peerCert, ctx);
ctx->localCert = ctx->encryptCert = ctx->peerCert = NULL;
SSLFreeBuffer(&ctx->partialReadBuffer, &ctx->sysCtx);
wait = ctx->recordWriteQueue;
while (wait)
{ SSLFreeBuffer(&wait->data, &ctx->sysCtx);
next = wait->next;
buf.data = (uint8*)wait;
buf.length = sizeof(WaitingRecord);
SSLFreeBuffer(&buf, &ctx->sysCtx);
wait = next;
}
SSLFreeBuffer(&ctx->dhPeerPublic, &ctx->sysCtx);
SSLFreeBuffer(&ctx->dhExchangePublic, &ctx->sysCtx);
SSLFreeBuffer(&ctx->dhPrivate, &ctx->sysCtx);
SSLFreeBuffer(&ctx->shaState, &ctx->sysCtx);
SSLFreeBuffer(&ctx->md5State, &ctx->sysCtx);
SSLFreeBuffer(&ctx->sessionID, &ctx->sysCtx);
SSLFreeBuffer(&ctx->peerID, &ctx->sysCtx);
SSLFreeBuffer(&ctx->resumableSession, &ctx->sysCtx);
SSLFreeBuffer(&ctx->preMasterSecret, &ctx->sysCtx);
SSLFreeBuffer(&ctx->partialReadBuffer, &ctx->sysCtx);
SSLFreeBuffer(&ctx->fragmentedMessageCache, &ctx->sysCtx);
SSLFreeBuffer(&ctx->receivedDataBuffer, &ctx->sysCtx);
SSLDisposeCipherSuite(&ctx->readCipher, ctx);
SSLDisposeCipherSuite(&ctx->writeCipher, ctx);
SSLDisposeCipherSuite(&ctx->readPending, ctx);
SSLDisposeCipherSuite(&ctx->writePending, ctx);
sslFree(ctx->validCipherSpecs);
ctx->validCipherSpecs = NULL;
ctx->numValidCipherSpecs = 0;
#if ST_KEYCHAIN_ENABLE
sslFreeKey(ctx->signingKeyCsp, &ctx->signingPrivKey, &ctx->signingKeyRef);
sslFreeKey(ctx->encryptKeyCsp, &ctx->encryptPrivKey, &ctx->encryptKeyRef);
#else
sslFreeKey(ctx->signingKeyCsp, &ctx->signingPrivKey, NULL);
sslFreeKey(ctx->encryptKeyCsp, &ctx->encryptPrivKey, NULL);
#endif
sslFreeKey(ctx->signingKeyCsp, &ctx->signingPubKey, NULL);
sslFreeKey(ctx->encryptKeyCsp, &ctx->encryptPubKey, NULL);
sslFreeKey(ctx->peerPubKeyCsp, &ctx->peerPubKey, NULL);
#if SSL_DEBUG
if(ctx->rootCertName != NULL) {
sslFree(ctx->rootCertName);
}
#endif
sslFreeTrustedRoots(ctx);
detachFromAll(ctx);
cfTearDownAllocators(ctx);
memset(ctx, 0, sizeof(SSLContext));
sslFree(ctx);
return noErr;
}
OSStatus
SSLGetSessionState (SSLContextRef context,
SSLSessionState *state)
{
SSLSessionState rtnState = kSSLIdle;
if(context == NULL) {
return paramErr;
}
*state = rtnState;
switch(context->state) {
case SSLUninitialized:
case HandshakeServerUninit:
case HandshakeClientUninit:
rtnState = kSSLIdle;
break;
case SSLGracefulClose:
rtnState = kSSLClosed;
break;
case SSLErrorClose:
case SSLNoNotifyClose:
rtnState = kSSLAborted;
break;
case HandshakeServerReady:
case HandshakeClientReady:
rtnState = kSSLConnected;
break;
default:
CASSERT((context->state >= HandshakeServerHello) &&
(context->state <= HandshakeSSL2ServerFinished));
rtnState = kSSLHandshake;
break;
}
*state = rtnState;
return noErr;
}
OSStatus
SSLSetIOFuncs (SSLContextRef ctx,
SSLReadFunc read,
SSLWriteFunc write)
{
if(ctx == NULL) {
return paramErr;
}
if(sslIsSessionActive(ctx)) {
return badReqErr;
}
ctx->ioCtx.read = read;
ctx->ioCtx.write = write;
return noErr;
}
OSStatus
SSLSetConnection (SSLContextRef ctx,
SSLConnectionRef connection)
{
if(ctx == NULL) {
return paramErr;
}
if(sslIsSessionActive(ctx)) {
return badReqErr;
}
ctx->ioCtx.ioRef = connection;
return noErr;
}
OSStatus
SSLSetProtocolVersion (SSLContextRef ctx,
SSLProtocol version)
{
SSLProtocolVersion versInt;
if(ctx == NULL) {
return paramErr;
}
if(sslIsSessionActive(ctx)) {
return badReqErr;
}
switch(version) {
case kSSLProtocolUnknown:
versInt = SSL_Version_Undetermined;
break;
case kSSLProtocol2:
versInt = SSL_Version_2_0;
break;
case kSSLProtocol3:
versInt = SSL_Version_Undetermined;
break;
case kSSLProtocol3Only:
versInt = SSL_Version_3_0_Only;
break;
default:
return paramErr;
}
ctx->reqProtocolVersion = ctx->negProtocolVersion = versInt;
return noErr;
}
static SSLProtocol convertProtToExtern(SSLProtocolVersion prot)
{
switch(prot) {
case SSL_Version_Undetermined:
return kSSLProtocolUnknown;
case SSL_Version_3_0_Only:
return kSSLProtocol3Only;
case SSL_Version_2_0:
return kSSLProtocol2;
case SSL_Version_3_0:
return kSSLProtocol3;
case SSL_Version_3_0_With_2_0_Hello:
sslPanic("How did we get SSL_Version_3_0_With_2_0_Hello?");
default:
sslPanic("convertProtToExtern: bad prot");
}
return kSSLProtocolUnknown;
}
OSStatus
SSLGetProtocolVersion (SSLContextRef ctx,
SSLProtocol *protocol)
{
if(ctx == NULL) {
return paramErr;
}
*protocol = convertProtToExtern(ctx->reqProtocolVersion);
return noErr;
}
OSStatus
SSLGetNegotiatedProtocolVersion (SSLContextRef ctx,
SSLProtocol *protocol)
{
if(ctx == NULL) {
return paramErr;
}
*protocol = convertProtToExtern(ctx->negProtocolVersion);
return noErr;
}
OSStatus
SSLSetAllowExpiredCerts (SSLContextRef ctx,
Boolean allowExpired)
{
if(ctx == NULL) {
return paramErr;
}
if(sslIsSessionActive(ctx)) {
return badReqErr;
}
ctx->allowExpiredCerts = allowExpired;
return noErr;
}
OSStatus
SSLGetAllowExpiredCerts (SSLContextRef ctx,
Boolean *allowExpired)
{
if(ctx == NULL) {
return paramErr;
}
*allowExpired = ctx->allowExpiredCerts;
return noErr;
}
OSStatus SSLSetAllowAnyRoot(
SSLContextRef ctx,
Boolean anyRoot)
{
if(ctx == NULL) {
return paramErr;
}
ctx->allowAnyRoot = anyRoot;
return noErr;
}
OSStatus
SSLGetAllowAnyRoot(
SSLContextRef ctx,
Boolean *anyRoot)
{
if(ctx == NULL) {
return paramErr;
}
*anyRoot = ctx->allowAnyRoot;
return noErr;
}
#if ST_SERVER_MODE_ENABLE
OSStatus
SSLSetClientSideAuthenticate (SSLContext *ctx,
SSLAuthenticate auth)
{
if(ctx == NULL) {
return paramErr;
}
if(sslIsSessionActive(ctx)) {
return badReqErr;
}
ctx->clientAuth = auth;
switch(auth) {
case kNeverAuthenticate:
ctx->tryClientAuth = false;
break;
case kAlwaysAuthenticate:
case kTryAuthenticate:
ctx->tryClientAuth = true;
break;
}
return noErr;
}
#endif
#if (ST_SERVER_MODE_ENABLE || ST_CLIENT_AUTHENTICATION)
OSStatus
SSLSetCertificate (SSLContextRef ctx,
CFArrayRef certRefs)
{
if(ctx == NULL) {
return paramErr;
}
if(sslIsSessionActive(ctx)) {
return badReqErr;
}
return parseIncomingCerts(ctx,
certRefs,
&ctx->localCert,
&ctx->signingPubKey,
&ctx->signingPrivKey,
&ctx->signingKeyCsp,
&ctx->signingKeyRef);
}
#endif
#if ST_SERVER_MODE_ENABLE
OSStatus
SSLSetEncryptionCertificate (SSLContextRef ctx,
CFArrayRef certRefs)
{
if(ctx == NULL) {
return paramErr;
}
if(sslIsSessionActive(ctx)) {
return badReqErr;
}
return parseIncomingCerts(ctx,
certRefs,
&ctx->encryptCert,
&ctx->encryptPubKey,
&ctx->encryptPrivKey,
&ctx->encryptKeyCsp,
&ctx->encryptKeyRef);
}
#endif
#if ST_KEYCHAIN_ENABLE
OSStatus
SSLSetTrustedRootCertKC (SSLContextRef ctx,
KCRef keyChainRef,
Boolean deleteExisting)
{
if((ctx == NULL) || (keyChainRef == nil)) {
return paramErr;
}
if(sslIsSessionActive(ctx)) {
return badReqErr;
}
if(deleteExisting) {
sslFreeTrustedRoots(ctx);
}
return parseTrustedKeychain(ctx, keyChainRef);
}
OSStatus
SSLSetNewRootKC (SSLContextRef ctx,
KCRef keyChainRef,
void *accessCreds)
{
if((ctx == NULL) || (keyChainRef == nil)) {
return paramErr;
}
if(sslIsSessionActive(ctx)) {
return badReqErr;
}
if(ctx->newRootCertKc != NULL) {
return badReqErr;
}
ctx->newRootCertKc = keyChainRef;
ctx->accessCreds = accessCreds;
return noErr;
}
#endif
OSStatus
SSLSetPeerID (SSLContext *ctx,
CFDataRef peerID)
{
SSLErr serr;
uint32 len;
if((ctx == NULL) ||
(peerID == NULL) ||
((len = CFDataGetLength(peerID)) == 0)) {
return paramErr;
}
if(sslIsSessionActive(ctx)) {
return badReqErr;
}
SSLFreeBuffer(&ctx->peerID, &ctx->sysCtx);
serr = SSLAllocBuffer(&ctx->peerID, len, &ctx->sysCtx);
if(serr) {
return sslErrToOsStatus(serr);
}
memmove(ctx->peerID.data, CFDataGetBytePtr(peerID), len);
ctx->peerID.length = len;
return noErr;
}
OSStatus
SSLGetNegotiatedCipher (SSLContextRef ctx,
SSLCipherSuite *cipherSuite)
{
if(ctx == NULL) {
return paramErr;
}
if(!sslIsSessionActive(ctx)) {
return badReqErr;
}
*cipherSuite = (SSLCipherSuite)ctx->selectedCipher;
return noErr;
}
#if 0
static SSLErr
SSLAddDistinguishedName(SSLContext *ctx, SSLBuffer derDN)
{ SSLBuffer dnBuf;
DNListElem *dn;
SSLErr err;
if ((err = SSLAllocBuffer(&dnBuf, sizeof(DNListElem), &ctx->sysCtx)) != 0)
return err;
dn = (DNListElem*)dnBuf.data;
if ((err = SSLAllocBuffer(&dn->derDN, derDN.length, &ctx->sysCtx)) != 0)
{ SSLFreeBuffer(&dnBuf, &ctx->sysCtx);
return err;
}
memcpy(dn->derDN.data, derDN.data, derDN.length);
dn->next = ctx->acceptableDNList;
ctx->acceptableDNList = dn;
return SSLNoErr;
}
#endif
OSStatus
SSLGetPeerCertificates (SSLContextRef ctx,
CFArrayRef *certs)
{
uint32 numCerts;
CFMutableArrayRef ca;
CFIndex i;
CFDataRef cfd;
SSLCertificate *scert;
if(ctx == NULL) {
return paramErr;
}
*certs = NULL;
numCerts = SSLGetCertificateChainLength(ctx->peerCert);
if(numCerts == 0) {
return noErr;
}
ca = CFArrayCreateMutable(ctx->cfAllocatorRef,
(CFIndex)numCerts, &kCFTypeArrayCallBacks);
if(ca == NULL) {
return memFullErr;
}
scert = ctx->peerCert;
for(i=0; i<numCerts; i++) {
CASSERT(scert != NULL);
cfd = CFDataCreate(ctx->cfAllocatorRef,
scert->derCert.data,
scert->derCert.length);
if(cfd == NULL) {
CFRelease(ca);
return memFullErr;
}
CFArrayAppendValue(ca, cfd);
scert = scert->next;
}
*certs = ca;
return noErr;
}