/* * 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 "sslBER.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 version enables. */ #define DEFAULT_SSL2_ENABLE true #define DEFAULT_SSL3_ENABLE true #define DEFAULT_TLS1_ENABLE true 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; ctx->versionSsl2Enable = DEFAULT_SSL2_ENABLE; ctx->versionSsl3Enable = DEFAULT_SSL3_ENABLE; ctx->versionTls1Enable = DEFAULT_TLS1_ENABLE; ctx->negProtocolVersion = SSL_Version_Undetermined; if(isServer) { ctx->protocolSide = SSL_ServerSide; } else { ctx->protocolSide = SSL_ClientSide; } /* 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; /* Default for RSA blinding is ENABLED */ ctx->rsaBlindingEnable = true; *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); if(ctx->peerSecTrust) { CFRelease(ctx->peerSecTrust); ctx->peerSecTrust = NULL; } 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; } #if APPLE_DH SSLFreeBuffer(ctx->dhParamsPrime, ctx); SSLFreeBuffer(ctx->dhParamsGenerator, ctx); SSLFreeBuffer(ctx->dhParamsEncoded, ctx); SSLFreeBuffer(ctx->dhPeerPublic, ctx); SSLFreeBuffer(ctx->dhExchangePublic, ctx); sslFreeKey(ctx->cspHand, &ctx->dhPrivate, NULL); #endif /* APPLE_DH */ 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->cspHand, &ctx->signingPubKey, NULL); sslFreeKey(ctx->cspHand, &ctx->encryptPubKey, NULL); sslFreeKey(ctx->peerPubKeyCsp, &ctx->peerPubKey, NULL); if(ctx->signingPrivKeyRef) { CFRelease(ctx->signingPrivKeyRef); } if(ctx->encryptPrivKeyRef) { CFRelease(ctx->encryptPrivKeyRef); } 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 SSL_HdskStateServerReady: case SSL_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 SSLGetConnection (SSLContextRef ctx, SSLConnectionRef *connection) { if((ctx == NULL) || (connection == NULL)) { return paramErr; } *connection = ctx->ioCtx.ioRef; 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; } /* concert between private SSLProtocolVersion and public SSLProtocol */ static SSLProtocol convertProtToExtern(SSLProtocolVersion prot) { switch(prot) { case SSL_Version_Undetermined: return kSSLProtocolUnknown; case SSL_Version_2_0: return kSSLProtocol2; case SSL_Version_3_0: return kSSLProtocol3; case TLS_Version_1_0: return kTLSProtocol1; default: sslErrorLog("convertProtToExtern: bad prot\n"); return kSSLProtocolUnknown; } /* not reached but make compiler happy */ return kSSLProtocolUnknown; } OSStatus SSLSetProtocolVersionEnabled(SSLContextRef ctx, SSLProtocol protocol, Boolean enable) /* RETURNED */ { if(ctx == NULL) { return paramErr; } if(sslIsSessionActive(ctx)) { /* can't do this with an active session */ return badReqErr; } switch(protocol) { case kSSLProtocol2: ctx->versionSsl2Enable = enable; break; case kSSLProtocol3: ctx->versionSsl3Enable = enable; break; case kTLSProtocol1: ctx->versionTls1Enable = enable; break; case kSSLProtocolAll: ctx->versionTls1Enable = ctx->versionSsl3Enable = ctx->versionSsl2Enable = enable; break; default: return paramErr; } return noErr; } OSStatus SSLGetProtocolVersionEnabled(SSLContextRef ctx, SSLProtocol protocol, Boolean *enable) /* RETURNED */ { if(ctx == NULL) { return paramErr; } switch(protocol) { case kSSLProtocol2: *enable = ctx->versionSsl2Enable; break; case kSSLProtocol3: *enable = ctx->versionSsl3Enable; break; case kTLSProtocol1: *enable = ctx->versionTls1Enable; break; case kSSLProtocolAll: if(ctx->versionTls1Enable && ctx->versionSsl3Enable && ctx->versionSsl2Enable) { *enable = true; } else { *enable = false; } break; default: return paramErr; } return noErr; } /* deprecated */ OSStatus SSLSetProtocolVersion (SSLContextRef ctx, SSLProtocol version) { if(ctx == NULL) { return paramErr; } if(sslIsSessionActive(ctx)) { /* can't do this with an active session */ return badReqErr; } /* convert external representation to three booleans */ switch(version) { case kSSLProtocolUnknown: ctx->versionSsl2Enable = DEFAULT_SSL2_ENABLE; ctx->versionSsl3Enable = DEFAULT_SSL3_ENABLE; ctx->versionTls1Enable = DEFAULT_TLS1_ENABLE; break; case kSSLProtocol2: ctx->versionSsl2Enable = true; ctx->versionSsl3Enable = false; ctx->versionTls1Enable = false; break; case kSSLProtocol3: /* this tells us to do our best, up to 3.0, but allows 2.0 */ ctx->versionSsl2Enable = true; ctx->versionSsl3Enable = true; ctx->versionTls1Enable = false; break; case kSSLProtocol3Only: ctx->versionSsl2Enable = false; ctx->versionSsl3Enable = true; ctx->versionTls1Enable = false; break; case kTLSProtocol1: case kSSLProtocolAll: /* this tells us to do our best, up to TLS, but allows 2.0 or 3.0 */ ctx->versionSsl2Enable = true; ctx->versionSsl3Enable = true; ctx->versionTls1Enable = true; break; case kTLSProtocol1Only: ctx->versionSsl2Enable = false; ctx->versionSsl3Enable = false; ctx->versionTls1Enable = true; break; default: return paramErr; } return noErr; } /* deprecated */ OSStatus SSLGetProtocolVersion (SSLContextRef ctx, SSLProtocol *protocol) /* RETURNED */ { if(ctx == NULL) { return paramErr; } /* translate array of booleans to public value; not all combinations * are legal (i.e., meaningful) for this call */ if(ctx->versionTls1Enable) { if(ctx->versionSsl2Enable) { if(ctx->versionSsl3Enable) { /* traditional 'all enabled' */ *protocol = kTLSProtocol1; return noErr; } else { /* SSL2 true, SSL3 false, TLS1 true - invalid here */ return paramErr; } } else if(ctx->versionSsl3Enable) { /* SSL2 false, SSL3 true, TLS1 true - invalid here */ return paramErr; } else { *protocol = kTLSProtocol1Only; return noErr; } } else { /* TLS1 false */ if(ctx->versionSsl3Enable) { *protocol = ctx->versionSsl2Enable ? kSSLProtocol3 : kSSLProtocol3Only; return noErr; } else if(ctx->versionSsl2Enable) { *protocol = kSSLProtocol2; return noErr; } else { /* * Bogus state - no enables - the API does provide a way * to get into this state. Other than this path, the app * will discover this bogon when attempting to do the * handshake; sslGetMaxProtVersion will detect this. */ return paramErr; } } /* NOT REACHED */ } 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; } sslCertDebug("SSLSetEnableCertVerify %s", enableVerify ? "true" : "false"); 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; } sslCertDebug("SSLSetAllowsExpiredCerts %s", allowExpired ? "true" : "false"); 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; } sslCertDebug("SSLSetAllowsExpiredRoots %s", allowExpired ? "true" : "false"); 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; } sslCertDebug("SSLSetAllowsAnyRoot %s", anyRoot ? "true" : "false"); 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); sslCertDebug("SSLSetTrustedRoot numCerts %d replaceExist %s", (int)numCerts, replaceExisting ? "true" : "false"); 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->signingPrivKeyRef); } 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->encryptPrivKeyRef); } 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; } /* * Specify Diffie-Hellman parameters. Optional; if we are configured to allow * for D-H ciphers and a D-H cipher is negotiated, and this function has not * been called, a set of process-wide parameters will be calculated. However * that can take a long time (30 seconds). */ OSStatus SSLSetDiffieHellmanParams( SSLContextRef ctx, const void *dhParams, size_t dhParamsLen) { if(ctx == NULL) { return paramErr; } if(sslIsSessionActive(ctx)) { return badReqErr; } SSLFreeBuffer(ctx->dhParamsPrime, ctx); SSLFreeBuffer(ctx->dhParamsGenerator, ctx); SSLFreeBuffer(ctx->dhParamsEncoded, ctx); OSStatus ortn; ortn = SSLCopyBufferFromData(dhParams, dhParamsLen, ctx->dhParamsEncoded); if(ortn) { return ortn; } /* decode for use by server over the wire */ SSLBuffer sParams; sParams.data = (UInt8 *)dhParams; sParams.length = dhParamsLen; return sslDecodeDhParams(&sParams, &ctx->dhParamsPrime, &ctx->dhParamsGenerator); } /* * Return parameter block specified in SSLSetDiffieHellmanParams. * Returned data is not copied and belongs to the SSLContextRef. */ OSStatus SSLGetDiffieHellmanParams( SSLContextRef ctx, const void **dhParams, size_t *dhParamsLen) { if(ctx == NULL) { return paramErr; } *dhParams = ctx->dhParamsEncoded.data; *dhParamsLen = ctx->dhParamsEncoded.length; return noErr; } OSStatus SSLSetRsaBlinding( SSLContextRef ctx, Boolean blinding) { if(ctx == NULL) { return paramErr; } ctx->rsaBlindingEnable = blinding; return noErr; } OSStatus SSLGetRsaBlinding( SSLContextRef ctx, Boolean *blinding) { if(ctx == NULL) { return paramErr; } *blinding = ctx->rsaBlindingEnable; return noErr; } OSStatus SSLGetPeerSecTrust( SSLContextRef ctx, SecTrustRef *secTrust) /* RETURNED */ { if(ctx == NULL) { return paramErr; } *secTrust = ctx->peerSecTrust; 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; } OSStatus SSLGetResumableSessionInfo( SSLContextRef ctx, Boolean *sessionWasResumed, // RETURNED void *sessionID, // RETURNED, mallocd by caller size_t *sessionIDLength) // IN/OUT { if((ctx == NULL) || (sessionWasResumed == NULL) || (sessionID == NULL) || (sessionIDLength == NULL) || (*sessionIDLength < MAX_SESSION_ID_LENGTH)) { return paramErr; } if(ctx->sessionMatch) { assert(ctx->sessionID.data != NULL); *sessionWasResumed = true; if(ctx->sessionID.length > *sessionIDLength) { /* really should never happen - means ID > 32 */ return paramErr; } memmove(sessionID, ctx->sessionID.data, ctx->sessionID.length); *sessionIDLength = ctx->sessionID.length; } else { *sessionWasResumed = false; *sessionIDLength = 0; } return noErr; }