X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/67c7378dcb8de24c86b7fedff90b4b496f2e474c..5a719ac813caa6f2ceaa192274fad2e1c2cec162:/SecureTransport/sslContext.cpp diff --git a/SecureTransport/sslContext.cpp b/SecureTransport/sslContext.cpp new file mode 100644 index 00000000..203bc534 --- /dev/null +++ b/SecureTransport/sslContext.cpp @@ -0,0 +1,1033 @@ +/* + * Copyright (c) 2000-2001 Apple Computer, 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. + */ + + +/* + File: sslContext.cpp + + Contains: SSLContext accessors + + Written by: Doug Mitchell + + Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved. + +*/ + +#include "ssl.h" +#include "sslContext.h" +#include "sslMemory.h" +#include +#include "sslDigests.h" +#include "sslDebug.h" +#include "appleCdsa.h" +#include "sslKeychain.h" +#include "sslUtils.h" +#include "cipherSpecs.h" +#include "appleSession.h" +#include +#include +#include + +static void sslFreeDnList( + SSLContext *ctx) +{ + DNListElem *dn, *nextDN; + + dn = ctx->acceptableDNList; + while (dn) + { + SSLFreeBuffer(dn->derDN, ctx); + nextDN = dn->next; + sslFree(dn); + dn = nextDN; + } + ctx->acceptableDNList = NULL; +} + +static OSStatus sslFreeTrustedRoots( + SSLContext *ctx) +{ + unsigned i; + + assert(ctx != NULL); + if((ctx->numTrustedCerts == 0) || (ctx->trustedCerts == NULL)) { + /* they really should both be zero, right? */ + assert((ctx->numTrustedCerts == 0) && (ctx->trustedCerts == NULL)); + } + else { + for(i=0; inumTrustedCerts; i++) { + stFreeCssmData(&ctx->trustedCerts[i], CSSM_FALSE); + } + sslFree(ctx->trustedCerts); + } + ctx->numTrustedCerts = 0; + ctx->trustedCerts = NULL; + sslFreeDnList(ctx); + return noErr; +} + +/* + * Default attempted version. + */ +#define DEFAULT_MAX_VERSION TLS_Version_1_0 + +OSStatus +SSLNewContext (Boolean isServer, + SSLContextRef *contextPtr) /* RETURNED */ +{ + SSLContext *ctx; + OSStatus serr; + + if(contextPtr == NULL) { + return paramErr; + } + *contextPtr = NULL; + ctx = (SSLContext *)sslMalloc(sizeof(SSLContext)); + if(ctx == NULL) { + return memFullErr; + } + /* subsequent errors to errOut: */ + + memset(ctx, 0, sizeof(SSLContext)); + ctx->state = SSL_HdskStateUninit; + ctx->clientCertState = kSSLClientCertNone; + + /* different defaults for client and server ... */ + 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; + /* Default value so we can send and receive hello msgs */ + ctx->sslTslCalls = &Ssl3Callouts; + + /* Initialize the cipher state to NULL_WITH_NULL_NULL */ + 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; + + /* these two are invariant */ + ctx->writeCipher.encrypting = 1; + ctx->writePending.encrypting = 1; + + /* this gets init'd on first call to SSLHandshake() */ + ctx->validCipherSpecs = NULL; + ctx->numValidCipherSpecs = 0; + + ctx->peerDomainName = NULL; + ctx->peerDomainNameLen = 0; + + /* attach to CSP, CL, TP */ + serr = attachToAll(ctx); + if(serr) { + goto errOut; + } + + /* Initial cert verify state: verify with default system roots */ + ctx->enableCertVerify = true; + + /* snag root certs from Keychain, tolerate error */ + addBuiltInCerts(ctx); + + *contextPtr = ctx; + return noErr; + +errOut: + sslFree(ctx); + return serr; +} + + +/* + * Dispose of an SSLContext. + */ +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); + + wait = ctx->recordWriteQueue; + while (wait) + { SSLFreeBuffer(wait->data, ctx); + next = wait->next; + buf.data = (uint8*)wait; + buf.length = sizeof(WaitingRecord); + SSLFreeBuffer(buf, ctx); + wait = next; + } + + SSLFreeBuffer(ctx->dhPeerPublic, ctx); + SSLFreeBuffer(ctx->dhExchangePublic, ctx); + SSLFreeBuffer(ctx->dhPrivate, ctx); + + CloseHash(SSLHashSHA1, ctx->shaState, ctx); + CloseHash(SSLHashMD5, ctx->md5State, ctx); + + SSLFreeBuffer(ctx->sessionID, ctx); + SSLFreeBuffer(ctx->peerID, ctx); + SSLFreeBuffer(ctx->resumableSession, ctx); + SSLFreeBuffer(ctx->preMasterSecret, ctx); + SSLFreeBuffer(ctx->partialReadBuffer, ctx); + SSLFreeBuffer(ctx->fragmentedMessageCache, ctx); + SSLFreeBuffer(ctx->receivedDataBuffer, ctx); + + 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; + + /* + * NOTE: currently, all public keys come from the CL via CSSM_CL_CertGetKeyInfo. + * We really don't know what CSP the CL used to generate a public key (in fact, + * it uses the raw CSP only to get LogicalKeySizeInBits, but we can't know + * that). Thus using e.g. signingKeyCsp (or any other CSP) to free + * signingPubKey is not tecnically accurate. However, our public keys + * are all raw keys, and all Apple CSPs dispose of raw keys in the same + * way. + */ + sslFreeKey(ctx->signingKeyCsp, &ctx->signingPubKey, NULL); + sslFreeKey(ctx->encryptKeyCsp, &ctx->encryptPubKey, NULL); + sslFreeKey(ctx->peerPubKeyCsp, &ctx->peerPubKey, NULL); + + sslFreeTrustedRoots(ctx); + + detachFromAll(ctx); + + memset(ctx, 0, sizeof(SSLContext)); + sslFree(ctx); + sslCleanupSession(); + return noErr; +} + +/* + * Determine the state of an SSL session. + */ +OSStatus +SSLGetSessionState (SSLContextRef context, + SSLSessionState *state) /* RETURNED */ +{ + SSLSessionState rtnState = kSSLIdle; + + if(context == NULL) { + return paramErr; + } + *state = rtnState; + switch(context->state) { + case SSL_HdskStateUninit: + case SSL_HdskStateServerUninit: + case SSL_HdskStateClientUninit: + rtnState = kSSLIdle; + break; + case SSL_HdskStateGracefulClose: + rtnState = kSSLClosed; + break; + case SSL_HdskStateErrorClose: + case SSL_HdskStateNoNotifyClose: + rtnState = kSSLAborted; + break; + case SSL2_HdskStateServerReady: + case SSL2_HdskStateClientReady: + rtnState = kSSLConnected; + break; + default: + assert((context->state >= SSL_HdskStateServerHello) && + (context->state <= SSL2_HdskStateServerFinished)); + rtnState = kSSLHandshake; + break; + + } + *state = rtnState; + return noErr; +} + +OSStatus +SSLSetIOFuncs (SSLContextRef ctx, + SSLReadFunc read, + SSLWriteFunc write) +{ + if(ctx == NULL) { + return paramErr; + } + if(sslIsSessionActive(ctx)) { + /* can't do this with an active session */ + 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)) { + /* can't do this with an active session */ + 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)) { + /* can't do this with an active session */ + return badReqErr; + } + + /* free possible existing name */ + if(ctx->peerDomainName) { + sslFree(ctx->peerDomainName); + } + + /* copy in */ + ctx->peerDomainName = (char *)sslMalloc(peerNameLen); + if(ctx->peerDomainName == NULL) { + return memFullErr; + } + memmove(ctx->peerDomainName, peerName, peerNameLen); + ctx->peerDomainNameLen = peerNameLen; + return noErr; +} + +/* + * Determine the buffer size needed for SSLGetPeerDomainName(). + */ +OSStatus +SSLGetPeerDomainNameLength (SSLContextRef ctx, + size_t *peerNameLen) // RETURNED +{ + if(ctx == NULL) { + return paramErr; + } + *peerNameLen = ctx->peerDomainNameLen; + return noErr; +} + +OSStatus +SSLGetPeerDomainName (SSLContextRef ctx, + char *peerName, // returned here + size_t *peerNameLen) // IN/OUT +{ + 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)) { + /* can't do this with an active session */ + return badReqErr; + } + + /* convert external representation to private */ + switch(version) { + case kSSLProtocolUnknown: + versInt = SSL_Version_Undetermined; + versMax = DEFAULT_MAX_VERSION; + break; + case kSSLProtocol2: + versInt = versMax = SSL_Version_2_0; + break; + case kSSLProtocol3: + /* this tells us to do our best but allows 2.0 */ + 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: + /* this tells us to do our best but allows 2.0 */ + 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; + /* this can happen in an intermediate state while negotiation + * is active...right? */ + case SSL_Version_3_0_With_2_0_Hello: + return kSSLProtocolUnknown; + default: + sslErrorLog("convertProtToExtern: bad prot\n"); + return kSSLProtocolUnknown; + } + /* not reached but make compiler happy */ + return kSSLProtocolUnknown; +} + +OSStatus +SSLGetProtocolVersion (SSLContextRef ctx, + SSLProtocol *protocol) /* RETURNED */ +{ + if(ctx == NULL) { + return paramErr; + } + *protocol = convertProtToExtern(ctx->reqProtocolVersion); + return noErr; +} + +OSStatus +SSLGetNegotiatedProtocolVersion (SSLContextRef ctx, + SSLProtocol *protocol) /* RETURNED */ +{ + if(ctx == NULL) { + return paramErr; + } + *protocol = convertProtToExtern(ctx->negProtocolVersion); + return noErr; +} + +OSStatus +SSLSetEnableCertVerify (SSLContextRef ctx, + Boolean enableVerify) +{ + if(ctx == NULL) { + return paramErr; + } + if(sslIsSessionActive(ctx)) { + /* can't do this with an active session */ + return badReqErr; + } + ctx->enableCertVerify = enableVerify; + return noErr; +} + +OSStatus +SSLGetEnableCertVerify (SSLContextRef ctx, + Boolean *enableVerify) +{ + if(ctx == NULL) { + return paramErr; + } + *enableVerify = ctx->enableCertVerify; + return noErr; +} + +OSStatus +SSLSetAllowsExpiredCerts(SSLContextRef ctx, + Boolean allowExpired) +{ + if(ctx == NULL) { + return paramErr; + } + if(sslIsSessionActive(ctx)) { + /* can't do this with an active session */ + return badReqErr; + } + ctx->allowExpiredCerts = allowExpired; + return noErr; +} + +OSStatus +SSLGetAllowsExpiredCerts (SSLContextRef ctx, + Boolean *allowExpired) +{ + if(ctx == NULL) { + return paramErr; + } + *allowExpired = ctx->allowExpiredCerts; + return noErr; +} + +OSStatus +SSLSetAllowsExpiredRoots(SSLContextRef ctx, + Boolean allowExpired) +{ + if(ctx == NULL) { + return paramErr; + } + if(sslIsSessionActive(ctx)) { + /* can't do this with an active session */ + return badReqErr; + } + ctx->allowExpiredRoots = allowExpired; + return noErr; +} + +OSStatus +SSLGetAllowsExpiredRoots (SSLContextRef ctx, + Boolean *allowExpired) +{ + if(ctx == NULL) { + return paramErr; + } + *allowExpired = ctx->allowExpiredRoots; + 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; +} + +OSStatus +SSLSetTrustedRoots (SSLContextRef ctx, + CFArrayRef trustedRoots, + Boolean replaceExisting) +{ + unsigned dex; + unsigned outDex; + unsigned numIncoming; + uint32 numCerts; + CSSM_DATA_PTR newRoots = NULL; + const CSSM_DATA *existAnchors = NULL; + uint32 numExistAnchors = 0; + OSStatus ortn = noErr; + + if(ctx == NULL) { + return paramErr; + } + if(sslIsSessionActive(ctx)) { + /* can't do this with an active session */ + return badReqErr; + } + numCerts = numIncoming = CFArrayGetCount(trustedRoots); + if(!replaceExisting) { + if(ctx->trustedCerts != NULL) { + /* adding to existing store */ + existAnchors = ctx->trustedCerts; + numExistAnchors = ctx->numTrustedCerts; + } + else { + /* adding to system roots */ + ortn = SecTrustGetCSSMAnchorCertificates(&existAnchors, + &numExistAnchors); + if(ortn) { + /* should never happen */ + return ortn; + } + } + numCerts += numExistAnchors; + } + newRoots = (CSSM_DATA_PTR)sslMalloc(numCerts * sizeof(CSSM_DATA)); + memset(newRoots, 0, numCerts * sizeof(CSSM_DATA)); + + /* Caller's certs first */ + for(dex=0, outDex=0; dexnumTrustedCerts = numCerts; + ctx->trustedCerts = newRoots; + return noErr; + +abort: + sslFree(newRoots); + return ortn; +} + +OSStatus +SSLGetTrustedRoots (SSLContextRef ctx, + CFArrayRef *trustedRoots) /* RETURNED */ +{ + uint32 numCerts; + const CSSM_DATA *certs; + CFMutableArrayRef certArray; + unsigned dex; + SecCertificateRef secCert; + OSStatus ortn; + + if(ctx == NULL) { + return paramErr; + } + if(ctx->trustedCerts != NULL) { + /* use ours */ + certs = ctx->trustedCerts; + numCerts = ctx->numTrustedCerts; + } + else { + /* use default system roots */ + OSStatus ortn = SecTrustGetCSSMAnchorCertificates(&certs, + &numCerts); + if(ortn) { + /* should never happen */ + return ortn; + } + } + + certArray = CFArrayCreateMutable(kCFAllocatorDefault, + (CFIndex)numCerts, &kCFTypeArrayCallBacks); + if(certArray == NULL) { + return memFullErr; + } + for(dex=0; dexclientAuth = auth; + switch(auth) { + case kNeverAuthenticate: + ctx->tryClientAuth = false; + break; + case kAlwaysAuthenticate: + case kTryAuthenticate: + ctx->tryClientAuth = true; + break; + } + return noErr; +} + +OSStatus +SSLGetClientCertificateState (SSLContextRef ctx, + SSLClientCertificateState *clientState) +{ + if(ctx == NULL) { + return paramErr; + } + *clientState = ctx->clientCertState; + return noErr; +} + +OSStatus +SSLSetCertificate (SSLContextRef ctx, + CFArrayRef certRefs) +{ + /* + * -- free localCerts if we have any + * -- Get raw cert data, convert to ctx->localCert + * -- get pub, priv keys from certRef[0] + * -- validate cert chain + */ + if(ctx == NULL) { + return paramErr; + } + if(sslIsSessionActive(ctx)) { + /* can't do this with an active session */ + return badReqErr; + } + return parseIncomingCerts(ctx, + certRefs, + &ctx->localCert, + &ctx->signingPubKey, + &ctx->signingPrivKey, + &ctx->signingKeyCsp + #if ST_KC_KEYS_NEED_REF + , + &ctx->signingKeyRef + #else + ); + #endif +} + +OSStatus +SSLSetEncryptionCertificate (SSLContextRef ctx, + CFArrayRef certRefs) +{ + /* + * -- free encryptCert if we have any + * -- Get raw cert data, convert to ctx->encryptCert + * -- get pub, priv keys from certRef[0] + * -- validate cert chain + */ + if(ctx == NULL) { + return paramErr; + } + if(sslIsSessionActive(ctx)) { + /* can't do this with an active session */ + return badReqErr; + } + return parseIncomingCerts(ctx, + certRefs, + &ctx->encryptCert, + &ctx->encryptPubKey, + &ctx->encryptPrivKey, + &ctx->encryptKeyCsp + #if ST_KC_KEYS_NEED_REF + , + &ctx->encryptKeyRef); + #else + ); + #endif +} + +#if ST_MANAGES_TRUSTED_ROOTS + +/* + * Add (optional, additional) trusted root certs. + */ +OSStatus +SSLSetTrustedRootCertKC (SSLContextRef ctx, + KCRef keyChainRef, + Boolean deleteExisting) +{ + /* + * -- free trustedCerts if deleteExisting + * -- Get raw cert data, add to ctx->trustedCerts + * -- verify that each of these is a valid (self-verifying) + * root cert + * -- add each subject name to acceptableDNList + */ + if((ctx == NULL) || (keyChainRef == nil)) { + return paramErr; + } + if(sslIsSessionActive(ctx)) { + /* can't do this with an active session */ + 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)) { + /* can't do this with an active session */ + return badReqErr; + } + if(ctx->newRootCertKc != NULL) { + /* can't do this multiple times */ + return badReqErr; + } + ctx->newRootCertKc = keyChainRef; + ctx->accessCreds = accessCreds; + return noErr; +} +#endif /* ST_MANAGES_TRUSTED_ROOTS */ + +OSStatus +SSLSetPeerID (SSLContext *ctx, + const void *peerID, + size_t peerIDLen) +{ + OSStatus serr; + + /* copy peerId to context->peerId */ + if((ctx == NULL) || + (peerID == NULL) || + (peerIDLen == 0)) { + return paramErr; + } + if(sslIsSessionActive(ctx)) { + /* can't do this with an active session */ + return badReqErr; + } + SSLFreeBuffer(ctx->peerID, ctx); + serr = SSLAllocBuffer(ctx->peerID, peerIDLen, ctx); + if(serr) { + return serr; + } + memmove(ctx->peerID.data, peerID, peerIDLen); + return noErr; +} + +OSStatus +SSLGetPeerID (SSLContextRef ctx, + const void **peerID, + size_t *peerIDLen) +{ + *peerID = ctx->peerID.data; // may be NULL + *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; +} + +/* + * Add an acceptable distinguished name (client authentication only). + */ +OSStatus +SSLAddDistinguishedName( + SSLContextRef ctx, + const void *derDN, + size_t derDNLen) +{ + DNListElem *dn; + OSStatus err; + + dn = (DNListElem *)sslMalloc(sizeof(DNListElem)); + if(dn == NULL) { + return memFullErr; + } + if ((err = SSLAllocBuffer(dn->derDN, derDNLen, ctx)) != 0) + return err; + memcpy(dn->derDN.data, derDN, derDNLen); + dn->next = ctx->acceptableDNList; + ctx->acceptableDNList = dn; + return noErr; +} + +/* + * Request peer certificates. Valid anytime, subsequent to + * a handshake attempt. + */ +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; + + /* + * Copy peerCert, a chain of SSLCertificates, to a CFArray of + * CFDataRefs, each of which is one DER-encoded cert. + */ + numCerts = SSLGetCertificateChainLength(ctx->peerCert); + if(numCerts == 0) { + return noErr; + } + ca = CFArrayCreateMutable(kCFAllocatorDefault, + (CFIndex)numCerts, &kCFTypeArrayCallBacks); + if(ca == NULL) { + return memFullErr; + } + + /* + * Caller gets leaf cert first, the opposite of the way we store them. + */ + scert = ctx->peerCert; + for(i=0; (unsigned)iderCert, &certData); + ortn = SecCertificateCreateFromData(&certData, + CSSM_CERT_X_509v3, + CSSM_CERT_ENCODING_DER, + &cfd); + if(ortn) { + CFRelease(ca); + return ortn; + } + /* insert at head of array */ + CFArrayInsertValueAtIndex(ca, 0, cfd); + scert = scert->next; + } + *certs = ca; + return noErr; +} + +OSStatus SSLInternalMasterSecret( + SSLContextRef ctx, + void *secret, // mallocd by caller, SSL_MASTER_SECRET_SIZE + size_t *secretSize) // in/out +{ + if((ctx == NULL) || (secret == NULL) || (secretSize == NULL)) { + return paramErr; + } + if(*secretSize < SSL_MASTER_SECRET_SIZE) { + return paramErr; + } + memmove(secret, ctx->masterSecret, SSL_MASTER_SECRET_SIZE); + *secretSize = SSL_MASTER_SECRET_SIZE; + return noErr; +} + +OSStatus SSLInternalServerRandom( + SSLContextRef ctx, + void *rand, // mallocd by caller, SSL_CLIENT_SRVR_RAND_SIZE + size_t *randSize) // in/out +{ + if((ctx == NULL) || (rand == NULL) || (randSize == NULL)) { + return paramErr; + } + if(*randSize < SSL_CLIENT_SRVR_RAND_SIZE) { + return paramErr; + } + memmove(rand, ctx->serverRandom, SSL_CLIENT_SRVR_RAND_SIZE); + *randSize = SSL_CLIENT_SRVR_RAND_SIZE; + return noErr; +} + +OSStatus SSLInternalClientRandom( + SSLContextRef ctx, + void *rand, // mallocd by caller, SSL_CLIENT_SRVR_RAND_SIZE + size_t *randSize) // in/out +{ + if((ctx == NULL) || (rand == NULL) || (randSize == NULL)) { + return paramErr; + } + if(*randSize < SSL_CLIENT_SRVR_RAND_SIZE) { + return paramErr; + } + memmove(rand, ctx->clientRandom, SSL_CLIENT_SRVR_RAND_SIZE); + *randSize = SSL_CLIENT_SRVR_RAND_SIZE; + return noErr; +} + + +