#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 "appleSession.h"
#include <string.h>
#include <Security/SecCertificate.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;
}
#define DEFAULT_MAX_VERSION TLS_Version_1_0
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 = DEFAULT_MAX_VERSION;
}
else {
ctx->protocolSide = SSL_ClientSide;
ctx->reqProtocolVersion = SSL_Version_Undetermined;
}
ctx->negProtocolVersion = SSL_Version_Undetermined;
ctx->maxProtocolVersion = DEFAULT_MAX_VERSION;
ctx->sslTslCalls = &Ssl3Callouts;
ctx->selectedCipherSpec = &SSL_NULL_WITH_NULL_NULL_CipherSpec;
ctx->selectedCipher = ctx->selectedCipherSpec->cipherSpec;
ctx->writeCipher.macRef = ctx->selectedCipherSpec->macAlgorithm;
ctx->readCipher.macRef = ctx->selectedCipherSpec->macAlgorithm;
ctx->readCipher.symCipher = ctx->selectedCipherSpec->cipher;
ctx->writeCipher.symCipher = ctx->selectedCipherSpec->cipher;
ctx->writeCipher.encrypting = 1;
ctx->writePending.encrypting = 1;
ctx->validCipherSpecs = NULL;
ctx->numValidCipherSpecs = 0;
ctx->peerDomainName = NULL;
ctx->peerDomainNameLen = 0;
SSLInitMACPads();
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);
CloseHash(&SSLHashSHA1, &ctx->shaState, ctx);
CloseHash(&SSLHashMD5, &ctx->md5State, ctx);
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);
if(ctx->peerDomainName) {
sslFree(ctx->peerDomainName);
ctx->peerDomainName = NULL;
ctx->peerDomainNameLen = 0;
}
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 0
#if ST_KEYCHAIN_ENABLE && ST_KC_KEYS_NEED_REF
sslFreeKey(ctx->signingKeyCsp, &ctx->signingPrivKey, &ctx->signingKeyRef);
sslFreeKey(ctx->encryptKeyCsp, &ctx->encryptPrivKey, &ctx->encryptKeyRef);
#else
sslFreeKey(ctx->signingKeyCsp, (CSSM_KEY_PTR *)&ctx->signingPrivKey, NULL);
sslFreeKey(ctx->encryptKeyCsp, (CSSM_KEY_PTR *)&ctx->encryptPrivKey, NULL);
#endif
#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);
memset(ctx, 0, sizeof(SSLContext));
sslFree(ctx);
sslCleanupSession();
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
SSLSetPeerDomainName (SSLContextRef ctx,
const char *peerName,
size_t peerNameLen)
{
if(ctx == NULL) {
return paramErr;
}
if(sslIsSessionActive(ctx)) {
return badReqErr;
}
if(ctx->peerDomainName) {
sslFree(ctx->peerDomainName);
}
ctx->peerDomainName = sslMalloc(peerNameLen);
if(ctx->peerDomainName == NULL) {
return memFullErr;
}
memmove(ctx->peerDomainName, peerName, peerNameLen);
ctx->peerDomainNameLen = peerNameLen;
return noErr;
}
OSStatus
SSLGetPeerDomainNameLength (SSLContextRef ctx,
size_t *peerNameLen) {
if(ctx == NULL) {
return paramErr;
}
*peerNameLen = ctx->peerDomainNameLen;
return noErr;
}
OSStatus
SSLGetPeerDomainName (SSLContextRef ctx,
char *peerName, size_t *peerNameLen) {
if(ctx == NULL) {
return paramErr;
}
if(*peerNameLen < ctx->peerDomainNameLen) {
return errSSLBufferOverflow;
}
memmove(peerName, ctx->peerDomainName, ctx->peerDomainNameLen);
*peerNameLen = ctx->peerDomainNameLen;
return noErr;
}
OSStatus
SSLSetProtocolVersion (SSLContextRef ctx,
SSLProtocol version)
{
SSLProtocolVersion versInt;
SSLProtocolVersion versMax;
if(ctx == NULL) {
return paramErr;
}
if(sslIsSessionActive(ctx)) {
return badReqErr;
}
switch(version) {
case kSSLProtocolUnknown:
versInt = SSL_Version_Undetermined;
versMax = DEFAULT_MAX_VERSION;
break;
case kSSLProtocol2:
versInt = versMax = SSL_Version_2_0;
break;
case kSSLProtocol3:
versInt = SSL_Version_Undetermined;
versMax = SSL_Version_3_0;
break;
case kSSLProtocol3Only:
versInt = SSL_Version_3_0_Only;
versMax = SSL_Version_3_0;
break;
case kTLSProtocol1:
versInt = SSL_Version_Undetermined;
versMax = TLS_Version_1_0;
break;
case kTLSProtocol1Only:
versInt = TLS_Version_1_0_Only;
versMax = TLS_Version_1_0;
break;
default:
return paramErr;
}
ctx->reqProtocolVersion = ctx->negProtocolVersion = versInt;
ctx->maxProtocolVersion = versMax;
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 TLS_Version_1_0_Only:
return kTLSProtocol1Only;
case TLS_Version_1_0:
return kTLSProtocol1;
case SSL_Version_3_0_With_2_0_Hello:
return kSSLProtocolUnknown;
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
SSLSetAllowsExpiredCerts(SSLContextRef ctx,
Boolean allowExpired)
{
if(ctx == NULL) {
return paramErr;
}
if(sslIsSessionActive(ctx)) {
return badReqErr;
}
ctx->allowExpiredCerts = allowExpired;
return noErr;
}
OSStatus
SSLGetAllowsExpiredCerts (SSLContextRef ctx,
Boolean *allowExpired)
{
if(ctx == NULL) {
return paramErr;
}
*allowExpired = ctx->allowExpiredCerts;
return noErr;
}
OSStatus SSLSetAllowsAnyRoot(
SSLContextRef ctx,
Boolean anyRoot)
{
if(ctx == NULL) {
return paramErr;
}
ctx->allowAnyRoot = anyRoot;
return noErr;
}
OSStatus
SSLGetAllowsAnyRoot(
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
#if ST_KC_KEYS_NEED_REF
,
&ctx->signingKeyRef
#else
);
#endif
}
#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
#if ST_KC_KEYS_NEED_REF
,
&ctx->encryptKeyRef);
#else
);
#endif
}
#endif
#if ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS
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,
const void *peerID,
size_t peerIDLen)
{
SSLErr serr;
if((ctx == NULL) ||
(peerID == NULL) ||
(peerIDLen == 0)) {
return paramErr;
}
if(sslIsSessionActive(ctx)) {
return badReqErr;
}
SSLFreeBuffer(&ctx->peerID, &ctx->sysCtx);
serr = SSLAllocBuffer(&ctx->peerID, peerIDLen, &ctx->sysCtx);
if(serr) {
return sslErrToOsStatus(serr);
}
memmove(ctx->peerID.data, peerID, peerIDLen);
return noErr;
}
OSStatus
SSLGetPeerID (SSLContextRef ctx,
const void **peerID,
size_t *peerIDLen)
{
*peerID = ctx->peerID.data; *peerIDLen = ctx->peerID.length;
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;
SecCertificateRef cfd;
OSStatus ortn;
CSSM_DATA certData;
SSLCertificate *scert;
if(ctx == NULL) {
return paramErr;
}
*certs = NULL;
numCerts = SSLGetCertificateChainLength(ctx->peerCert);
if(numCerts == 0) {
return noErr;
}
ca = CFArrayCreateMutable(kCFAllocatorDefault,
(CFIndex)numCerts, &kCFTypeArrayCallBacks);
if(ca == NULL) {
return memFullErr;
}
scert = ctx->peerCert;
for(i=0; i<numCerts; i++) {
CASSERT(scert != NULL);
SSLBUF_TO_CSSM(&scert->derCert, &certData);
ortn = SecCertificateCreateFromData(&certData,
CSSM_CERT_X_509v3,
CSSM_CERT_ENCODING_DER,
&cfd);
if(ortn) {
CFRelease(ca);
return ortn;
}
CFArrayInsertValueAtIndex(ca, 0, cfd);
scert = scert->next;
}
*certs = ca;
return noErr;
}