From: Apple <opensource@apple.com>
Date: Wed, 10 Jun 2015 05:58:05 +0000 (+0000)
Subject: Security-57031.10.10.tar.gz
X-Git-Tag: os-x-10102^0
X-Git-Url: https://git.saurik.com/apple/security.git/commitdiff_plain/949d2ff02a32bac712f7993d03d527b4925ff882

Security-57031.10.10.tar.gz
---

diff --git a/Security/Security.xcodeproj/xcshareddata/xcschemes/secdtests.xcscheme b/Security/Security.xcodeproj/xcshareddata/xcschemes/secdtests.xcscheme
index 0900729a..7ef30f00 100644
--- a/Security/Security.xcodeproj/xcshareddata/xcschemes/secdtests.xcscheme
+++ b/Security/Security.xcodeproj/xcshareddata/xcschemes/secdtests.xcscheme
@@ -62,6 +62,10 @@
             argument = "-s"
             isEnabled = "NO">
          </CommandLineArgument>
+         <CommandLineArgument
+            argument = "su_07_debugging"
+            isEnabled = "NO">
+         </CommandLineArgument>
          <CommandLineArgument
             argument = "si_33_keychain_backup"
             isEnabled = "NO">
diff --git a/Security/lib/security.exp-in b/Security/lib/security.exp-in
index 25d19b32..4aa9a665 100644
--- a/Security/lib/security.exp-in
+++ b/Security/lib/security.exp-in
@@ -1536,6 +1536,12 @@ _SecInferLabelFromX509Name
 _SecItemAdd
 _SecItemCopyDisplayNames
 _SecItemCopyMatching
+#if TARGET_OS_MAC
+_SecItemAdd_ios
+_SecItemCopyMatching_ios
+_SecItemDelete_ios
+_SecItemUpdate_ios
+#endif
 _SecItemDelete
 _SecItemUpdate
 __SecItemGetPersistentReference
diff --git a/Security/libsecurity_apple_x509_tp/lib/certGroupUtils.cpp b/Security/libsecurity_apple_x509_tp/lib/certGroupUtils.cpp
index 8686e5fd..97700ebf 100644
--- a/Security/libsecurity_apple_x509_tp/lib/certGroupUtils.cpp
+++ b/Security/libsecurity_apple_x509_tp/lib/certGroupUtils.cpp
@@ -634,7 +634,7 @@ CSSM_BOOL tpCompareDomainSuffix(
 
 /*
  * Following a CSSMOID_ECDSA_WithSpecified algorithm is an encoded
- * ECDSA_SigAlgParams containing the digest agorithm OID. Decode and return
+ * ECDSA_SigAlgParams containing the digest algorithm OID. Decode and return
  * a unified ECDSA/digest alg (e.g. CSSM_ALGID_SHA512WithECDSA).
  * Returns nonzero on error.
  */
diff --git a/Security/libsecurity_apple_x509_tp/lib/ocspRequest.cpp b/Security/libsecurity_apple_x509_tp/lib/ocspRequest.cpp
index 6add077c..c609b780 100644
--- a/Security/libsecurity_apple_x509_tp/lib/ocspRequest.cpp
+++ b/Security/libsecurity_apple_x509_tp/lib/ocspRequest.cpp
@@ -1,15 +1,15 @@
 /*
  * Copyright (c) 2004,2011-2012,2014 Apple Inc. All Rights Reserved.
- * 
+ *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The 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,
@@ -17,14 +17,14 @@
  * 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.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
 /*
  * ocspRequest.cpp - OCSP Request class
  */
- 
+
 #include "ocspRequest.h"
 #include "certGroupUtils.h"
 #include "tpdebugging.h"
@@ -47,15 +47,15 @@ static uint8 nullParam[2] = {5, 0};
 #define OCSP_NONCE_SIZE		8
 
 /*
- * The only constructor. Subject and issuer must remain valid for the 
- * lifetime of this object (they are not refcounted). 
+ * The only constructor. Subject and issuer must remain valid for the
+ * lifetime of this object (they are not refcounted).
  */
 OCSPRequest::OCSPRequest(
 	TPCertInfo		&subject,
 	TPCertInfo		&issuer,
 	bool			genNonce)
 		: mCoder(NULL),
-		  mSubject(subject), 
+		  mSubject(subject),
 		  mIssuer(issuer),
 		  mGenNonce(genNonce),
 		  mCertID(NULL)
@@ -81,6 +81,7 @@ const CSSM_DATA *OCSPRequest::encode()
 	CSSM_DATA_PTR	issuerName;
 	CSSM_DATA_PTR	issuerKey;
 	CSSM_KEY_PTR	issuerPubKey;
+	CSSM_DATA		issuerPubKeyBytes;
 	/* from subject */
 	CSSM_DATA_PTR	subjectSerial=NULL;
 
@@ -98,17 +99,17 @@ const CSSM_DATA *OCSPRequest::encode()
 	CSSM_DATA					nonceData = {OCSP_NONCE_SIZE, nonceBytes};
 	OCSPNonce					*nonce = NULL;
 	NSS_CertExtension			*extenArray[2] = {NULL, NULL};
-	
+
 	if(mEncoded.Data) {
 		/* already done */
 		return &mEncoded;
 	}
 
-	/* 
+	/*
 	 * One single request, no extensions
 	 */
 	memset(&singleReq, 0, sizeof(singleReq));
-	
+
 	/* algId refers to the hash we'll perform in issuer name and key */
 	certId.algId.algorithm = CSSMOID_SHA1;
 	certId.algId.parameters.Data = nullParam;
@@ -138,16 +139,17 @@ const CSSM_DATA *OCSPRequest::encode()
 		goto errOut;
 	}
 	issuerPubKey = (CSSM_KEY_PTR)issuerKey->Data;
-	ocspdSha1(issuerPubKey->KeyData.Data, (CC_LONG)issuerPubKey->KeyData.Length, pubKeyHash);
-	
+	ocspdGetPublicKeyBytes(mCoder, issuerPubKey, issuerPubKeyBytes);
+	ocspdSha1(issuerPubKeyBytes.Data, (CC_LONG)issuerPubKeyBytes.Length, pubKeyHash);
+
 	/* build the CertID from those components */
 	certId.issuerNameHash.Data = issuerNameHash;
 	certId.issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH;
 	certId.issuerPubKeyHash.Data = pubKeyHash;
-	certId.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH;	
+	certId.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH;
 	certId.serialNumber = *subjectSerial;
 
-	/* 
+	/*
 	 * Build top level request with one entry in requestList, no signature,
 	 * one optional extension (a nonce)
 	 */
@@ -164,17 +166,17 @@ const CSSM_DATA *OCSPRequest::encode()
 		tbs.requestExtensions = extenArray;
 		SecAsn1AllocCopyItem(mCoder, &nonceData, &mNonce);
 	}
-	
+
 	/* Encode */
-	if(SecAsn1EncodeItem(mCoder, &signedReq, kSecAsn1OCSPSignedRequestTemplate, 
+	if(SecAsn1EncodeItem(mCoder, &signedReq, kSecAsn1OCSPSignedRequestTemplate,
 			&mEncoded)) {
 		tpErrorLog("OCSPRequest::encode: error encoding OCSP req\n");
 		crtn = CSSMERR_TP_INTERNAL_ERROR;
 		goto errOut;
 	}
 	/* save a copy of the CertID */
-	mCertID = new OCSPClientCertID(*issuerName, issuerPubKey->KeyData, *subjectSerial);
-	
+	mCertID = new OCSPClientCertID(*issuerName, issuerPubKeyBytes, *subjectSerial);
+
 errOut:
 	if(issuerName) {
 		mIssuer.freeField(&CSSMOID_X509V1IssuerNameStd, issuerName);
diff --git a/Security/libsecurity_apple_x509_tp/lib/ocspRequest.h b/Security/libsecurity_apple_x509_tp/lib/ocspRequest.h
index 7d68fd0d..8341dc63 100644
--- a/Security/libsecurity_apple_x509_tp/lib/ocspRequest.h
+++ b/Security/libsecurity_apple_x509_tp/lib/ocspRequest.h
@@ -1,15 +1,15 @@
 /*
  * Copyright (c) 2004,2011,2014 Apple Inc. All Rights Reserved.
- * 
+ *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The 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,
@@ -17,14 +17,14 @@
  * 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.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
 /*
  * ocspRequest.h - OCSP Request class
  */
- 
+
 #ifndef	_OCSP_REQUEST_H_
 #define _OCSP_REQUEST_H_
 
@@ -39,35 +39,35 @@ class OCSPRequest
 	NOCOPY(OCSPRequest)
 public:
 	/*
-	 * The only constructor. Subject and issuer must remain valid for the 
-	 * lifetime of this object (they are not refcounted). 
+	 * The only constructor. Subject and issuer must remain valid for the
+	 * lifetime of this object (they are not refcounted).
 	 */
 	OCSPRequest(
 		TPCertInfo		&subject,
 		TPCertInfo		&issuer,
 		bool			genNonce);
-		
+
 	~OCSPRequest();
-	
-	/* 
+
+	/*
 	 * Obtain encoded OCSP request suitable for posting to responder.
 	 * This object owns and maintains the memory.
 	 */
 	const CSSM_DATA *encode();
 
-	/* 
+	/*
 	 * Obtain this request's nonce (which we randomly generate at encode() time),
 	 * This object owns and maintains the memory. Result is NULL} if we
-	 * didn't generate a nonce. 
+	 * didn't generate a nonce.
 	 */
 	const CSSM_DATA *nonce();
-			
-	/* 
+
+	/*
 	 * Obtain this request's CertID. Used to look up matching SingleResponse
 	 * in the OCSPResponse.
 	 */
 	OCSPClientCertID	*certID();
-	
+
 private:
 	SecAsn1CoderRef		mCoder;
 	TPCertInfo			&mSubject;
@@ -76,7 +76,7 @@ private:
 	CSSM_DATA			mNonce;
 	CSSM_DATA			mEncoded;	/* lazily evaluated */
 	OCSPClientCertID	*mCertID;	/* calculated during encode() */
-	
+
 };
 
 #endif	/* _OCSP_REQUEST_H_ */
diff --git a/Security/libsecurity_apple_x509_tp/lib/tpOcspCertVfy.cpp b/Security/libsecurity_apple_x509_tp/lib/tpOcspCertVfy.cpp
index 6fdb9e69..5356ca77 100644
--- a/Security/libsecurity_apple_x509_tp/lib/tpOcspCertVfy.cpp
+++ b/Security/libsecurity_apple_x509_tp/lib/tpOcspCertVfy.cpp
@@ -1,15 +1,15 @@
 /*
  * Copyright (c) 2004,2011-2012,2014 Apple Inc. All Rights Reserved.
- * 
+ *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The 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,
@@ -17,7 +17,7 @@
  * 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.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
@@ -32,11 +32,15 @@
 #include <CommonCrypto/CommonDigest.h>
 #include <security_ocspd/ocspdUtils.h>
 
+#ifndef	NDEBUG
+#include <Security/SecCertificate.h>
+#endif
+
 /*
  * Is signerCert authorized to sign OCSP responses by issuerCert? IssuerCert is
- * assumed to be (i.e., must, but we don't check that here) the signer of the 
+ * assumed to be (i.e., must, but we don't check that here) the signer of the
  * cert being verified, which is not in the loop for this op. Just a bool returned;
- * it's autoritized or it's not. 
+ * it's authorized or it's not.
  */
 static bool tpIsAuthorizedOcspSigner(
 	TPCertInfo &issuerCert,		// issuer of cert being verified
@@ -47,28 +51,67 @@ static bool tpIsAuthorizedOcspSigner(
 	bool				ourRtn = false;
 	CE_ExtendedKeyUsage *eku = NULL;
 	bool				foundEku = false;
-	
-	/* 
+
+	/*
 	 * First see if issuerCert issued signerCert (No signature vfy yet, just
 	 * subject/issuer check).
 	 */
 	if(!issuerCert.isIssuerOf(signerCert)) {
+#ifndef	NDEBUG
+		SecCertificateRef issuerRef = NULL;
+		SecCertificateRef signerRef = NULL;
+		const CSSM_DATA *issuerData = issuerCert.itemData();
+		const CSSM_DATA *signerData = signerCert.itemData();
+		crtn = SecCertificateCreateFromData(issuerData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_BER, &issuerRef);
+		crtn = SecCertificateCreateFromData(signerData, CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_BER, &signerRef);
+		CFStringRef issuerName = SecCertificateCopySubjectSummary(issuerRef);
+		CFStringRef signerName = SecCertificateCopySubjectSummary(signerRef);
+		if(issuerName) {
+			CFIndex maxLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(issuerName), kCFStringEncodingUTF8) + 1;
+			char* buf = (char*) malloc(maxLength);
+			if (buf) {
+				if (CFStringGetCString(issuerName, buf, (CFIndex)maxLength, kCFStringEncodingUTF8)) {
+					tpOcspDebug("tpIsAuthorizedOcspSigner: issuerCert \"%s\"", buf);
+				}
+				free(buf);
+			}
+			CFRelease(issuerName);
+		}
+		if(signerName) {
+			CFIndex maxLength = CFStringGetMaximumSizeForEncoding(CFStringGetLength(signerName), kCFStringEncodingUTF8) + 1;
+			char* buf = (char*) malloc(maxLength);
+			if (buf) {
+				if (CFStringGetCString(signerName, buf, (CFIndex)maxLength, kCFStringEncodingUTF8)) {
+					tpOcspDebug("tpIsAuthorizedOcspSigner: signerCert \"%s\"", buf);
+				}
+				free(buf);
+			}
+			CFRelease(signerName);
+		}
+		if(issuerRef) {
+			CFRelease(issuerRef);
+		}
+		if(signerRef) {
+			CFRelease(signerRef);
+		}
+#endif
+		tpOcspDebug("tpIsAuthorizedOcspSigner: signer is not issued by issuerCert");
 		return false;
 	}
-	
+
 	/* Fetch ExtendedKeyUse field from signerCert */
 	crtn = signerCert.fetchField(&CSSMOID_ExtendedKeyUsage, &fieldValue);
 	if(crtn) {
 		tpOcspDebug("tpIsAuthorizedOcspSigner: signer is issued by issuer, no EKU");
 		return false;
-	}	
+	}
 	CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)fieldValue->Data;
 	if(cssmExt->format != CSSM_X509_DATAFORMAT_PARSED) {
 		tpOcspDebug("tpIsAuthorizedOcspSigner: bad extension format");
 		goto errOut;
 	}
 	eku = (CE_ExtendedKeyUsage *)cssmExt->value.parsedValue;
-	
+
 	/* Look for OID_KP_OCSPSigning */
 	for(unsigned dex=0; dex<eku->numPurposes; dex++) {
 		if(tpCompareCssmData(&eku->purposes[dex], &CSSMOID_OCSPSigning)) {
@@ -82,9 +125,9 @@ static bool tpIsAuthorizedOcspSigner(
 		goto errOut;
 	}
 
-	/* 
-	 * OK, signerCert is authorized by *someone* to sign OCSP requests, and 
-	 * it claims to be issued by issuer. Sig verify to be sure. 
+	/*
+	 * OK, signerCert is authorized by *someone* to sign OCSP requests, and
+	 * it claims to be issued by issuer. Sig verify to be sure.
 	 * FIXME this is not handling partial public keys, which would be a colossal
 	 * mess to handle in this module...so we don't.
 	 */
@@ -104,8 +147,8 @@ errOut:
 	return ourRtn;
 }
 
-/* 
- * Check ResponderID linkage between an OCSPResponse and a cert we believe to 
+/*
+ * Check ResponderID linkage between an OCSPResponse and a cert we believe to
  * be the issuer of both that response and the cert being verified. Returns
  * true if OK.
  */
@@ -116,14 +159,14 @@ bool tpOcspResponderIDCheck(
 {
 	bool shouldBeSigner = false;
 	if(ocspResp.responderIDTag() == RIT_Name) {
-		/* 
+		/*
 		 * Name inside response must == signer's SubjectName.
 		 * Note we can't use signer.subjectName(); that's normalized.
 		 */
 
 		const CSSM_DATA *respIdName = ocspResp.encResponderName();
 		CSSM_DATA *subjectName = NULL;
-		CSSM_RETURN crtn = signer.fetchField(&CSSMOID_X509V1SubjectNameStd, 
+		CSSM_RETURN crtn = signer.fetchField(&CSSMOID_X509V1SubjectNameStd,
 			&subjectName);
 		if(crtn) {
 			/* bad cert */
@@ -141,11 +184,13 @@ bool tpOcspResponderIDCheck(
 	}
 	else {
 		/* ResponderID.byKey must == SHA1(signer's public key) */
-		const CSSM_KEY *pubKey = signer.pubKey();
+		const CSSM_KEY_PTR pubKey = signer.pubKey();
 		assert(pubKey != NULL);
 		uint8 digest[CC_SHA1_DIGEST_LENGTH];
 		CSSM_DATA keyHash = {CC_SHA1_DIGEST_LENGTH, digest};
-		ocspdSha1(pubKey->KeyData.Data, (CC_LONG)pubKey->KeyData.Length, digest);
+		CSSM_DATA pubKeyBytes = {0, NULL};
+		ocspdGetPublicKeyBytes(NULL, pubKey, pubKeyBytes);
+		ocspdSha1(pubKeyBytes.Data, (CC_LONG)pubKeyBytes.Length, digest);
 		const CSSM_DATA *respKeyHash = &ocspResp.responderID().byKey;
 		if(tpCompareCssmData(&keyHash, respKeyHash)) {
 			tpOcspDebug("tpOcspResponderIDCheck: good ResponderID.byKey");
@@ -159,9 +204,9 @@ bool tpOcspResponderIDCheck(
 }
 
 /*
- * Verify the signature of an OCSP response. Caller is responsible for all other 
+ * Verify the signature of an OCSP response. Caller is responsible for all other
  * verification of the response, this is just the crypto.
- * Returns true on success. 
+ * Returns true on success.
  */
 static bool tpOcspResponseSigVerify(
 	TPVerifyContext		&vfyCtx,
@@ -172,18 +217,18 @@ static bool tpOcspResponseSigVerify(
 	const SecAsn1OCSPBasicResponse &basicResp = ocspResp.basicResponse();
 	const CSSM_OID *algOid = &basicResp.algId.algorithm;
 	CSSM_ALGORITHMS sigAlg;
-	
+
 	if(!cssmOidToAlg(algOid, &sigAlg)) {
 		tpOcspDebug("tpOcspResponseSigVerify: unknown signature algorithm");
 	}
-	
+
 	/* signer's public key from the cert */
 	const CSSM_KEY *pubKey = signer.pubKey();
-	
+
 	/* signature: on decode, length is in BITS */
 	CSSM_DATA sig = basicResp.sig;
 	sig.Length /= 8;
-	
+
 	CSSM_RETURN crtn;
 	CSSM_CC_HANDLE sigHand;
 	bool ourRtn = false;
@@ -220,14 +265,14 @@ typedef enum {
 typedef enum {
 	OCT_Local,		// LocalResponder - no checking other than signature
 	OCT_Issuer,		// it's the issuer of the cert being verified
-	OCT_Provided,	// came with response, provenance unknown 
+	OCT_Provided,	// came with response, provenance unknown
 } OcspCertType;
 
 /*
- * Did specified cert issue the OCSP response? 
+ * Did specified cert issue the OCSP response?
  *
  * This implements the algorithm described in RFC2560, section 4.2.2.2,
- * "Authorized Responders". It sees if the cert could be the issuer of the 
+ * "Authorized Responders". It sees if the cert could be the issuer of the
  * OCSP response per that algorithm; then if it could, it performs signature
  * verification.
  */
@@ -237,12 +282,12 @@ static OcspIssuerStatus tpIsOcspIssuer(
 	/* on input specify at least one of the following two */
 	const CSSM_DATA		*signerData,
 	TPCertInfo			*signer,
-	OcspCertType		certType,		// where rawCert came from 
+	OcspCertType		certType,		// where rawCert came from
 	TPCertInfo			*issuer,		// OPTIONAL, if known
 	TPCertInfo			**signerRtn)	// optionally RETURNED if at all possible
 {
 	assert((signerData != NULL) || (signer != NULL));
-	
+
 	/* get signer as TPCertInfo if caller hasn't provided */
 	TPCertInfo *tmpSigner = NULL;
 	if(signer == NULL) {
@@ -262,14 +307,14 @@ static OcspIssuerStatus tpIsOcspIssuer(
 	if(signerRtn != NULL) {
 		*signerRtn = signer;
 	}
-	
-	/* 
+
+	/*
 	 * Qualification of "this can be the signer" depends on where the
 	 * signer came from.
 	 */
 	bool shouldBeSigner = false;
 	OcspIssuerStatus ourRtn = OIS_No;
-	
+
 	switch(certType) {
 		case OCT_Local:			// caller trusts this and thinks it's the signer
 			shouldBeSigner = true;
@@ -280,12 +325,12 @@ static OcspIssuerStatus tpIsOcspIssuer(
 			break;
 		case OCT_Provided:
 		{
-			/* 
+			/*
 			 * This cert came with the response.
 			 */
 			if(issuer == NULL) {
-				/* 
-				 * careful, might not know the issuer...how would this path ever 
+				/*
+				 * careful, might not know the issuer...how would this path ever
 				 * work then? I don't think it needs to because you can NOT
 				 * do OCSP on a cert without its issuer in hand.
 				 */
@@ -300,12 +345,12 @@ static OcspIssuerStatus tpIsOcspIssuer(
 	if(!shouldBeSigner) {
 		goto errOut;
 	}
-	
+
 	/* verify the signature */
 	if(tpOcspResponseSigVerify(vfyCtx, ocspResp, *signer)) {
 		ourRtn = OIS_Good;
 	}
-	
+
 errOut:
 	if((signerRtn == NULL) && (tmpSigner != NULL)) {
 		delete tmpSigner;
@@ -317,19 +362,19 @@ errOut:
 OcspRespStatus tpVerifyOcspResp(
 	TPVerifyContext		&vfyCtx,
 	SecNssCoder			&coder,
-	TPCertInfo			*issuer,		// issuer of the related cert, may be issuer of 
-										//   reply, may not be known 
+	TPCertInfo			*issuer,		// issuer of the related cert, may be issuer of
+										//   reply, may not be known
 	OCSPResponse		&ocspResp,
-	CSSM_RETURN			&cssmErr)		// possible per-cert error 
+	CSSM_RETURN			&cssmErr)		// possible per-cert error
 {
 	OcspRespStatus	ourRtn = ORS_Unknown;
 	CSSM_RETURN		crtn;
-		
+
 	tpOcspDebug("tpVerifyOcspResp top");
-	
+
 	switch(ocspResp.responseStatus()) {
-		case RS_Success: 
-			crtn = CSSM_OK; 
+		case RS_Success:
+			crtn = CSSM_OK;
 			break;
 		case RS_MalformedRequest:
 			crtn = CSSMERR_APPLETP_OCSP_RESP_MALFORMED_REQ;
@@ -357,7 +402,7 @@ OcspRespStatus tpVerifyOcspResp(
 		return ORS_Unknown;
 	}
 	cssmErr = CSSM_OK;
-	
+
 	/* one of our main jobs is to locate the signer of the response, here */
 	TPCertInfo *signerInfo = NULL;
 	TPCertInfo *signerInfoTBD = NULL;		// if non NULL at end, we delete
@@ -366,45 +411,45 @@ OcspRespStatus tpVerifyOcspResp(
 	CSSM_BOOL verifiedToRoot;
 	CSSM_BOOL verifiedToAnchor;
 	CSSM_BOOL verifiedViaTrustSetting;
-	
+
 	const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts = vfyCtx.ocspOpts;
 	OcspIssuerStatus issuerStat;
-	
-	/* 
+
+	/*
 	 * Set true if we ever find an apparent issuer which does not correctly
 	 * pass signature verify. If true and we never success, that's a XXX error.
 	 */
 	bool foundBadIssuer = false;
 	bool foundLocalResponder = false;
 	uint32 numSignerCerts = ocspResp.numSignerCerts();
-	
+
 	/*
-	 * This cert group, allocated by AppleTPSession::CertGroupVerify(), 
+	 * This cert group, allocated by AppleTPSession::CertGroupVerify(),
 	 * serves two functions here:
 	 *
 	 * -- it accumulates certs we get from the net (as parts of OCSP responses)
 	 *    for user in verifying OCSPResponse-related certs.
-	 *    TPCertGroup::buildCertGroup() uses this group as one of the many 
+	 *    TPCertGroup::buildCertGroup() uses this group as one of the many
 	 *    sources of certs when building a cert chain.
 	 *
-	 * -- it provides a container into which to stash TPCertInfos which 
+	 * -- it provides a container into which to stash TPCertInfos which
 	 *    persist at least as long as the TPVerifyContext; it's of type TGO_Group,
-	 *    so all of the certs added to it get freed when the group does. 
+	 *    so all of the certs added to it get freed when the group does.
 	 */
 	assert(vfyCtx.signerCerts != NULL);
-	
+
 	TPCertGroup &gatheredCerts = vfyCtx.gatheredCerts;
-	
+
 	/* set up for disposal of TPCertInfos created by TPCertGroup::buildCertGroup() */
 	TPCertGroup	certsToBeFreed(vfyCtx.alloc, TGO_Group);
-	
-	/* 
+
+	/*
 	 * First job is to find the cert which signed this response.
 	 * Give priority to caller's LocalResponderCert.
 	 */
 	if((ocspOpts != NULL) && (ocspOpts->LocalResponderCert != NULL)) {
 		TPCertInfo *responderInfo = NULL;
-		issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp, 
+		issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp,
 			ocspOpts->LocalResponderCert, NULL,
 			OCT_Local, issuer, &responderInfo);
 		switch(issuerStat) {
@@ -425,9 +470,9 @@ OcspRespStatus tpVerifyOcspResp(
 				break;
 		}
 	}
-	
+
 	if((signerInfo == NULL) && (numSignerCerts != 0)) {
-		/* 
+		/*
 		 * App did not specify a local responder (or provided a bad one)
 		 * and the response came with some certs. Try those.
 		 */
@@ -436,7 +481,7 @@ OcspRespStatus tpVerifyOcspResp(
 			const CSSM_DATA *certData = ocspResp.signerCert(dex);
 			if(signerInfo == NULL) {
 				/* stop trying this after we succeed... */
-				issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp, 
+				issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp,
 					certData, NULL,
 					OCT_Provided, issuer, &respCert);
 				switch(issuerStat) {
@@ -453,7 +498,7 @@ OcspRespStatus tpVerifyOcspResp(
 				}
 			}
 			else {
-				/* 
+				/*
 				 * At least add this cert to certGroup for verification.
 				 * OcspCert will own the TPCertInfo.
 				 */
@@ -471,13 +516,13 @@ OcspRespStatus tpVerifyOcspResp(
 			}
 		}
 	}
-	
+
 	if((signerInfo == NULL) && (issuer != NULL)) {
-		/* 
+		/*
 		 * Haven't found it yet, try the actual issuer
 		 */
-		issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp, 
-			NULL, issuer, 
+		issuerStat = tpIsOcspIssuer(vfyCtx, ocspResp,
+			NULL, issuer,
 			OCT_Issuer, issuer, NULL);
 		switch(issuerStat) {
 			case OIS_BadSig:
@@ -492,7 +537,7 @@ OcspRespStatus tpVerifyOcspResp(
 				break;
 		}
 	}
-		
+
 	if(signerInfo == NULL) {
 		if((issuer != NULL) && !issuer->isStatusFatal(CSSMERR_APPLETP_OCSP_NO_SIGNER)) {
 			/* user wants to proceed without verifying! */
@@ -521,10 +566,10 @@ OcspRespStatus tpVerifyOcspResp(
 		ourRtn = ORS_Good;
 		goto errOut;
 	}
-	
-	/* 
-	 * Last remaining task is to verify the signer, and all the certs back to 
-	 * an anchor 
+
+	/*
+	 * Last remaining task is to verify the signer, and all the certs back to
+	 * an anchor
 	 */
 
 	/* start from scratch with both of these groups */
@@ -547,7 +592,7 @@ OcspRespStatus tpVerifyOcspResp(
 			vfyCtx.policyStr,
 			vfyCtx.policyStrLen,
 			kSecTrustSettingsKeyUseSignRevocation,
-			verifiedToRoot,	
+			verifiedToRoot,
 			verifiedToAnchor,
 			verifiedViaTrustSetting);
 	if(crtn) {
@@ -582,9 +627,9 @@ OcspRespStatus tpVerifyOcspResp(
 		tpOcspDebug("tpVerifyOcspResp SUCCESS; chain verified");
 		ourRtn = ORS_Good;
 	}
-	
+
 	/* FIXME policy verify? */
-	
+
 errOut:
 	delete signerInfoTBD;
 	/* any other cleanup? */
diff --git a/Security/libsecurity_apple_x509_tp/lib/tpOcspVerify.cpp b/Security/libsecurity_apple_x509_tp/lib/tpOcspVerify.cpp
index e17e7cf0..ae11caf6 100644
--- a/Security/libsecurity_apple_x509_tp/lib/tpOcspVerify.cpp
+++ b/Security/libsecurity_apple_x509_tp/lib/tpOcspVerify.cpp
@@ -1,15 +1,15 @@
 /*
  * Copyright (c) 2004,2011-2012,2014 Apple Inc. All Rights Reserved.
- * 
+ *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The 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,
@@ -17,14 +17,14 @@
  * 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.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
 /*
  * tpOcspVerify.cpp - top-level OCSP verification
  */
- 
+
 #include "tpOcspVerify.h"
 #include "tpdebugging.h"
 #include "ocspRequest.h"
@@ -42,7 +42,7 @@
 
 #pragma mark ---- private routines ----
 
-/* 
+/*
  * Get a smart CertID for specified cert and issuer
  */
 static CSSM_RETURN tpOcspGetCertId(
@@ -54,8 +54,9 @@ static CSSM_RETURN tpOcspGetCertId(
 	CSSM_DATA_PTR issuerSubject = NULL;
 	CSSM_DATA_PTR issuerPubKeyData = NULL;
 	CSSM_KEY_PTR issuerPubKey;
+	CSSM_DATA issuerPubKeyBytes;
 	CSSM_DATA_PTR subjectSerial = NULL;
-	
+
 	crtn = subject.fetchField(&CSSMOID_X509V1SerialNumber, &subjectSerial);
 	if(crtn) {
 		return crtn;
@@ -70,25 +71,26 @@ static CSSM_RETURN tpOcspGetCertId(
 	}
 	assert(issuerPubKeyData->Length == sizeof(CSSM_KEY));
 	issuerPubKey = (CSSM_KEY_PTR)issuerPubKeyData->Data;
-	certID = new OCSPClientCertID(*issuerSubject, issuerPubKey->KeyData, *subjectSerial);
-	
+	ocspdGetPublicKeyBytes(NULL, issuerPubKey, issuerPubKeyBytes);
+	certID = new OCSPClientCertID(*issuerSubject, issuerPubKeyBytes, *subjectSerial);
+
 	subject.freeField(&CSSMOID_X509V1SerialNumber, subjectSerial);
 	issuer.freeField(&CSSMOID_X509V1IssuerNameStd, issuerSubject);
 	issuer.freeField(&CSSMOID_CSSMKeyStruct, issuerPubKeyData);
 	return CSSM_OK;
 }
 
-/* 
+/*
  * Examine cert, looking for AuthorityInfoAccess, with id-ad-ocsp URIs. Create
- * an NULL_terminated array of CSSM_DATAs containing the URIs if found. 
+ * an NULL_terminated array of CSSM_DATAs containing the URIs if found.
  */
 static CSSM_DATA **tpOcspUrlsFromCert(
-	TPCertInfo &subject, 
+	TPCertInfo &subject,
 	SecNssCoder &coder)
 {
 	CSSM_DATA_PTR extField = NULL;
 	CSSM_RETURN crtn;
-	
+
 	crtn = subject.fetchField(&CSSMOID_AuthorityInfoAccess, &extField);
 	if(crtn) {
 		tpOcspDebug("tpOcspUrlsFromCert: no AIA extension");
@@ -103,8 +105,8 @@ static CSSM_DATA **tpOcspUrlsFromCert(
 		tpErrorLog("tpOcspUrlsFromCert: malformed CSSM_X509_EXTENSION");
 		return NULL;
 	}
-	
-	CE_AuthorityInfoAccess *aia = 
+
+	CE_AuthorityInfoAccess *aia =
 		(CE_AuthorityInfoAccess *)cssmExt->value.parsedValue;
 	CSSM_DATA **urls = NULL;
 	unsigned numUrls = 0;
@@ -118,7 +120,7 @@ static CSSM_DATA **tpOcspUrlsFromCert(
 			tpErrorLog("tpOcspUrlsFromCert: CSSMOID_AD_OCSP, but not type URI");
 			continue;
 		}
-		
+
 		/* got one */
 		if(urls == NULL) {
 			urls = coder.mallocn<CSSM_DATA_PTR>(2);
@@ -148,7 +150,7 @@ static CSSM_DATA **tpOcspUrlsFromCert(
 	return urls;
 }
 
-/* 
+/*
  * Create an SecAsn1OCSPDRequest for one cert. This consists of:
  *
  * -- cooking up an OCSPRequest if net fetch is enabled or a local responder
@@ -170,7 +172,7 @@ static SecAsn1OCSPDRequest *tpGenOcspdReq(
 	OCSPClientCertID		*certID = NULL;
 	CSSM_RETURN				crtn;
 	bool					deleteCertID = false;
-	
+
 	/* gather options or their defaults */
 	CSSM_APPLE_TP_OCSP_OPT_FLAGS optFlags = 0;
 	const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts = vfyCtx.ocspOpts;
@@ -183,16 +185,16 @@ static SecAsn1OCSPDRequest *tpGenOcspdReq(
 	}
 	bool genNonce = optFlags & CSSM_TP_OCSP_GEN_NONCE ? true : false;
 	bool requireRespNonce = optFlags & CSSM_TP_OCSP_REQUIRE_RESP_NONCE ? true : false;
-	
-	/* 
+
+	/*
 	 * One degenerate case in case we can't really do anything.
 	 * If no URI and no local responder, only proceed if cache is not disabled
 	 * and we're requiring full OCSP per cert.
 	 */
 	if( ( (optFlags & CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE) ||
 		  !(optFlags & CSSM_TP_ACTION_OCSP_REQUIRE_PER_CERT)
-		) && 
-	   (localResponder == NULL) &&  
+		) &&
+	   (localResponder == NULL) &&
 	   (urls == NULL)) {
 	   tpOcspDebug("tpGenOcspdReq: no route to OCSP; NULL return");
 	   return NULL;
@@ -213,7 +215,7 @@ static SecAsn1OCSPDRequest *tpGenOcspdReq(
 			}
 		}
 	}
-	
+
 	/* certID needed one way or the other */
 	if(certID == NULL) {
 		crtn = tpOcspGetCertId(subject, issuer, certID);
@@ -222,7 +224,7 @@ static SecAsn1OCSPDRequest *tpGenOcspdReq(
 		}
 		deleteCertID = true;
 	}
-	
+
 	/*
 	 * Create the SecAsn1OCSPDRequest. All fields optional.
 	 */
@@ -234,10 +236,10 @@ static SecAsn1OCSPDRequest *tpGenOcspdReq(
 		ocspdReq->cacheWriteDisable->Data[0] = 0xff;
 		ocspdReq->cacheWriteDisable->Length = 1;
 	}
-	/* 
-	 * Note we're enforcing a not-so-obvious policy here: if nonce match is 
-	 * required, disk cache reads by ocspd are disabled. In-core cache is 
-	 * still enabled and hits in that cache do NOT require nonce matches. 
+	/*
+	 * Note we're enforcing a not-so-obvious policy here: if nonce match is
+	 * required, disk cache reads by ocspd are disabled. In-core cache is
+	 * still enabled and hits in that cache do NOT require nonce matches.
 	 */
 	if((optFlags & CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE) || requireRespNonce) {
 		ocspdReq->cacheReadDisable = coder.mallocn<CSSM_DATA>();
@@ -261,7 +263,7 @@ static SecAsn1OCSPDRequest *tpGenOcspdReq(
 	if(!(optFlags & CSSM_TP_ACTION_OCSP_DISABLE_NET)) {
 		ocspdReq->urls = const_cast<CSSM_DATA **>(urls);
 	}
-	
+
 errOut:
 	delete ocspReq;
 	if(deleteCertID) {
@@ -274,9 +276,9 @@ static bool revocationTimeAfterVerificationTime(CFAbsoluteTime revokedTime, CSSM
 {
     // Return true if the revocation time is after the specified verification time (i.e. "good")
     // If verifyTime not specified, use now for the verifyTime
-    
+
     CFAbsoluteTime verifyTime = 0;
-    
+
     if (verifyTimeStr)
     {
         CFDateRef cfVerifyTime = NULL;  // made with CFDateCreate
@@ -288,7 +290,7 @@ static bool revocationTimeAfterVerificationTime(CFAbsoluteTime revokedTime, CSSM
                 CFRelease(cfVerifyTime);
             }
     }
-    
+
     if (verifyTime == 0)
         verifyTime = CFAbsoluteTimeGetCurrent();
 
@@ -308,13 +310,13 @@ static CSSM_RETURN tpApplySingleResp(
 {
 	SecAsn1OCSPCertStatusTag certStatus = singleResp.certStatus();
 	CSSM_RETURN crtn = CSSM_OK;
-    if ((certStatus == CS_Revoked) && 
+    if ((certStatus == CS_Revoked) &&
         revocationTimeAfterVerificationTime(singleResp.revokedTime(), verifyTime))
     {
         tpOcspDebug("tpApplySingleResp: CS_Revoked for cert %u, but revoked after verification time", dex);
         certStatus = CS_Good;
     }
-    
+
 	switch(certStatus) {
 		case CS_Good:
 			tpOcspDebug("tpApplySingleResp: CS_Good for cert %u", dex);
@@ -346,7 +348,7 @@ static CSSM_RETURN tpApplySingleResp(
 			tpOcspDebug("tpApplySingleResp: CS_Unknown for cert %u", dex);
 			break;
 		default:
-			tpOcspDebug("tpApplySingleResp: BAD certStatus (%d) for cert %u", 
+			tpOcspDebug("tpApplySingleResp: BAD certStatus (%d) for cert %u",
 					(int)certStatus, dex);
 			if(cert.addStatusCode(CSSMERR_APPLETP_OCSP_STATUS_UNRECOGNIZED)) {
 				crtn = CSSMERR_APPLETP_OCSP_STATUS_UNRECOGNIZED;
@@ -356,20 +358,20 @@ static CSSM_RETURN tpApplySingleResp(
 	return crtn;
 }
 
-/* 
+/*
  * An exceptional case: synchronously flush the OCSPD cache and send a new
- * resquest for just this one cert. 
+ * resquest for just this one cert.
  */
 static OCSPResponse *tpOcspFlushAndReFetch(
-	TPVerifyContext		&vfyCtx, 
-	SecNssCoder			&coder, 
+	TPVerifyContext		&vfyCtx,
+	SecNssCoder			&coder,
 	TPCertInfo			&subject,
-	TPCertInfo			&issuer, 
+	TPCertInfo			&issuer,
 	OCSPClientCertID	&certID)
 {
 	const CSSM_DATA *derCertID = certID.encode();
 	CSSM_RETURN crtn;
-	
+
 	crtn = ocspdCacheFlush(*derCertID);
 	if(crtn) {
 		#ifndef	NDEBUG
@@ -377,7 +379,7 @@ static OCSPResponse *tpOcspFlushAndReFetch(
 		#endif
 		return NULL;
 	}
-	
+
 	/* Cook up an OCSPDRequests, one request, just for this */
 	/* send it to ocsdp */
 	/* munge reply into an OCSPRsponse and return it */
@@ -395,14 +397,14 @@ public:
 		CSSM_DATA **u,
 		unsigned dex);
 	~PendingRequest()	{}
-	
+
 	TPCertInfo			&subject;
 	TPCertInfo			&issuer;
 	OCSPClientCertID	&certID;	// owned by caller
 	CSSM_DATA			**urls;		// owner-managed array of URLs obtained from subject's
-									// AuthorityInfoAccess.id-ad-ocsp. 
-	CSSM_DATA			nonce;		// owner-managed copy of this requests' nonce, if it 
-									//   has one 
+									// AuthorityInfoAccess.id-ad-ocsp.
+	CSSM_DATA			nonce;		// owner-managed copy of this requests' nonce, if it
+									//   has one
 	unsigned			dex;		// in inputCerts, for debug
 	bool				processed;
 };
@@ -413,7 +415,7 @@ PendingRequest::PendingRequest(
 		OCSPClientCertID &cid,
 		CSSM_DATA **u,
 		unsigned dx)
-		: subject(subj), issuer(iss), certID(cid), 
+		: subject(subj), issuer(iss), certID(cid),
 		  urls(u), dex(dx), processed(false)
 {
 	nonce.Data = NULL;
@@ -424,11 +426,11 @@ PendingRequest::PendingRequest(
 
 CSSM_RETURN tpVerifyCertGroupWithOCSP(
 	TPVerifyContext	&vfyCtx,
-	TPCertGroup 	&certGroup)		// to be verified 
+	TPCertGroup 	&certGroup)		// to be verified
 {
 	assert(vfyCtx.clHand != 0);
 	assert(vfyCtx.policy == kRevokeOcsp);
-	
+
 	CSSM_RETURN ourRtn = CSSM_OK;
 	OcspRespStatus respStat;
 	SecNssCoder coder;
@@ -446,7 +448,7 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 		return CSSM_OK;
 	}
 	numCerts--;
-	
+
 	/* gather options or their defaults */
 	CSSM_APPLE_TP_OCSP_OPT_FLAGS optFlags = 0;
 	const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts = vfyCtx.ocspOpts;
@@ -457,7 +459,7 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 	bool genNonce = false;			// in outgoing request
 	bool requireRespNonce = false;	// in incoming response
 	PRErrorCode prtn;
-	
+
 	if(ocspOpts != NULL) {
 		optFlags = vfyCtx.ocspOpts->Flags;
 		localResponder = ocspOpts->LocalResponder;
@@ -480,23 +482,23 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 		tpErrorLog("tpVerifyCertGroupWithOCSP: requireRespNonce, !genNonce\n");
 		return CSSMERR_TP_INVALID_REQUEST_INPUTS;
 	}
-	
-	tpOcspDebug("tpVerifyCertGroupWithOCSP numCerts %u optFlags 0x%lx", 
+
+	tpOcspDebug("tpVerifyCertGroupWithOCSP numCerts %u optFlags 0x%lx",
 		numCerts, (unsigned long)optFlags);
-		
+
 	/*
 	 * create list of pendingRequests parallel to certGroup
 	 */
 	PendingRequest **pending = coder.mallocn<PendingRequest *>(numCerts);
 	memset(pending, 0, (numCerts * sizeof(PendingRequest *)));
-	
+
 	for(unsigned dex=0; dex<numCerts; dex++) {
 		OCSPClientCertID *certID = NULL;
 		TPCertInfo *subject = certGroup.certAtIndex(dex);
-		
+
 		if(subject->trustSettingsFound()) {
 			/* functionally equivalent to root - we're done */
-			tpOcspDebug("...tpVerifyCertGroupWithOCSP: terminate per user trust at %u", 
+			tpOcspDebug("...tpVerifyCertGroupWithOCSP: terminate per user trust at %u",
 				(unsigned)dex);
 			goto postOcspd;
 		}
@@ -507,35 +509,35 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 				"aborting\n");
 			goto errOut;
 		}
-		
-		/* 
+
+		/*
 		 * We use the URLs in the subject cert's AuthorityInfoAccess extension
 		 * for two things - mainly to get the URL(s) for actual OCSP transactions,
 		 * but also for CSSM_TP_ACTION_OCSP_REQUIRE_IF_RESP_PRESENT processing.
 		 * So, we do the per-cert processing to get them right now even if we
-		 * wind up using a local responder or getting verification from cache. 
+		 * wind up using a local responder or getting verification from cache.
 		 */
 		CSSM_DATA **urls = tpOcspUrlsFromCert(*subject, coder);
 		pending[dex] = new PendingRequest(*subject, *issuer, *certID, urls, dex);
 	}
 	/* subsequent errors to errOut: */
-	
-	/* 
-	 * Create empty SecAsn1OCSPDRequests big enough for all certs 
+
+	/*
+	 * Create empty SecAsn1OCSPDRequests big enough for all certs
 	 */
 	ocspdReqs.requests = coder.mallocn<SecAsn1OCSPDRequest *>(numCerts + 1);
 	memset(ocspdReqs.requests, 0, (numCerts + 1) * sizeof(SecAsn1OCSPDRequest *));
 	ocspdReqs.version.Data = &version;
 	ocspdReqs.version.Length = 1;
-	
-	/* 
+
+	/*
 	 * For each cert, either obtain a cached OCSPResponse, or create
-	 * a request to get one. 
+	 * a request to get one.
 	 *
 	 * NOTE: in-core cache reads (via tpOcspCacheLookup() do NOT involve a
 	 * nonce check, no matter what the app says. If nonce checking is required by the
 	 * app, responses don't get added to cache if the nonce doesn't match, but once
-	 * a response is validated and added to cache it's fair game for that task. 
+	 * a response is validated and added to cache it's fair game for that task.
 	 */
 	for(unsigned dex=0; dex<numCerts; dex++) {
 		PendingRequest *pendReq = pending[dex];
@@ -544,7 +546,7 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 			singleResp = tpOcspCacheLookup(pendReq->certID, localResponder);
 		}
 		if(singleResp) {
-			tpOcspDebug("...tpVerifyCertGroupWithOCSP: localCache hit (1) dex %u", 
+			tpOcspDebug("...tpVerifyCertGroupWithOCSP: localCache hit (1) dex %u",
 				(unsigned)dex);
 			crtn = tpApplySingleResp(*singleResp, pendReq->subject, dex, optFlags,
 				vfyCtx.verifyTime, pendReq->processed);
@@ -558,19 +560,19 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 				continue;
 			}
 			if(crtn) {
-				/* 
-				 * This indicates a bad cached response. Well that's kinda weird, let's 
+				/*
+				 * This indicates a bad cached response. Well that's kinda weird, let's
 				 * just flush this out and try a normal transaction.
 				 */
 				tpOcspCacheFlush(pendReq->certID);
 			}
 		}
-		
-		/* 
+
+		/*
 		 * Prepare a request for ocspd
 		 */
-		SecAsn1OCSPDRequest *ocspdReq = tpGenOcspdReq(vfyCtx, coder, 
-			pendReq->subject, pendReq->issuer, pendReq->certID, 
+		SecAsn1OCSPDRequest *ocspdReq = tpGenOcspdReq(vfyCtx, coder,
+			pendReq->subject, pendReq->issuer, pendReq->certID,
 			const_cast<const CSSM_DATA **>(pendReq->urls),
 			pendReq->nonce);
 		if(ocspdReq == NULL) {
@@ -584,7 +586,7 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 		/* no candidates for OCSP: almost done */
 		goto postOcspd;
 	}
-	
+
 	/* ship requests off to ocspd, get ocspReplies back */
 	if(coder.encodeItem(&ocspdReqs, kSecAsn1OCSPDRequestsTemplate, derOcspdRequests)) {
 		tpErrorLog("tpVerifyCertGroupWithOCSP: error encoding ocspdReqs\n");
@@ -597,17 +599,17 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 		#ifndef	NDEBUG
 		cssmPerror("ocspdFetch", crtn);
 		#endif
-		/* But this is not necessarily fatal...update per-cert status and check 
+		/* But this is not necessarily fatal...update per-cert status and check
 		 * caller requirements below */
 		goto postOcspd;
 	}
 	memset(&ocspdReplies, 0, sizeof(ocspdReplies));
-	prtn = coder.decodeItem(derOcspdReplies, kSecAsn1OCSPDRepliesTemplate, 
+	prtn = coder.decodeItem(derOcspdReplies, kSecAsn1OCSPDRepliesTemplate,
 		&ocspdReplies);
 	/* we're done with this, mallocd in ocspdFetch() */
 	vfyCtx.alloc.free(derOcspdReplies.Data);
 	if(prtn) {
-		/* 
+		/*
 		 * This can happen when an OCSP server provides bad data...we cannot
 		 * determine which cert is associated with this bad response;
 		 * just flag it with the first one and proceed to the loop that
@@ -625,12 +627,12 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 		}
 		goto errOut;
 	}
-	
+
 	/* process each reply */
 	numReplies = ocspdArraySize((const void **)ocspdReplies.replies);
 	for(unsigned dex=0; dex<numReplies; dex++) {
 		SecAsn1OCSPDReply *reply = ocspdReplies.replies[dex];
-		
+
 		/* Cook up our version of an OCSPResponse from the encoded data */
 		OCSPResponse *ocspResp = NULL;
 		try {
@@ -641,15 +643,15 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 			/* what the heck, keep going */
 			continue;
 		}
-		
-		/* 
-		 * Find matching subject cert if possible (it's technically optional for 
+
+		/*
+		 * Find matching subject cert if possible (it's technically optional for
 		 * verification of the response in some cases, e.g., local responder).
 		 */
 		PendingRequest *pendReq = NULL;				// fully qualified
 		PendingRequest *reqWithIdMatch = NULL;		// CertID match only, not nonce
 		for(unsigned pdex=0; pdex<numCerts; pdex++) {
-		
+
 			/* first check ID match; that is required no matter what */
 			if((pending[pdex])->certID.compareToExist(reply->certID)) {
 				reqWithIdMatch = pending[pdex];
@@ -660,24 +662,24 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 			if(!genNonce) {
 				/* that's good enough */
 				pendReq = reqWithIdMatch;
-				tpOcspDebug("OCSP processs reply: CertID match, no nonce");
+				tpOcspDebug("OCSP process reply: CertID match, no nonce");
 				break;
 			}
 			if(tpCompareCssmData(&reqWithIdMatch->nonce, ocspResp->nonce())) {
-				tpOcspDebug("OCSP processs reply: nonce MATCH");
+				tpOcspDebug("OCSP process reply: nonce MATCH");
 				pendReq = reqWithIdMatch;
 				break;
 			}
-			
+
 			/*
-			 * In this case we keep going; if we never find a match, then we can 
+			 * In this case we keep going; if we never find a match, then we can
 			 * use reqWithIdMatch if !requireRespNonce.
 			 */
-			tpOcspDebug("OCSP processs reply: certID match, nonce MISMATCH");
+			tpOcspDebug("OCSP process reply: certID match, nonce MISMATCH");
 		}
 		if(pendReq == NULL) {
 			if(requireRespNonce) {
-				tpOcspDebug("OCSP processs reply: tossing out response due to "
+				tpOcspDebug("OCSP process reply: tossing out response due to "
 						"requireRespNonce");
 				delete ocspResp;
 				if(ourRtn == CSSM_OK) {
@@ -690,7 +692,7 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 				 * Nonce mismatch but caller thinks that's OK. Log it and proceed.
 				 */
 				assert(genNonce);
-				tpOcspDebug("OCSP processs reply: using bad nonce due to !requireRespNonce");
+				tpOcspDebug("OCSP process reply: using bad nonce due to !requireRespNonce");
 				pendReq = reqWithIdMatch;
 				pendReq->subject.addStatusCode(CSSMERR_APPLETP_OCSP_NONCE_MISMATCH);
 			}
@@ -699,7 +701,7 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 		if(pendReq != NULL) {
 			issuer = &pendReq->issuer;
 		}
-		
+
 		/* verify response and either throw out or add to local cache */
 		respStat = tpVerifyOcspResp(vfyCtx, coder, issuer, *ocspResp, crtn);
 		switch(respStat) {
@@ -715,9 +717,9 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 				continue;
 			case ORS_Bad:
 				delete ocspResp;
-				/* 
-				 * An exceptional case: synchronously flush the OCSPD cache and send a 
-				 * new request for just this one cert. 
+				/*
+				 * An exceptional case: synchronously flush the OCSPD cache and send a
+				 * new request for just this one cert.
 				 * FIXME: does this really buy us anything? A DOS attacker who managed
 				 * to get this bogus response into our cache is likely to be able
 				 * to do it again and again.
@@ -746,21 +748,21 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 					goto errOut;
 				}
 				/* Voila! Recovery. Proceed. */
-				tpOcspDebug("tpVerifyCertGroupWithOCSP: refetch for cert %u SUCCEEDED", 
+				tpOcspDebug("tpVerifyCertGroupWithOCSP: refetch for cert %u SUCCEEDED",
 						dex);
 				break;
 		} /* switch response status */
-		
+
 		if(!cacheWriteDisable) {
 			tpOcspCacheAdd(reply->ocspResp, localResponder);
 		}
-		
+
 		/* attempt to apply to pendReq */
 		if(pendReq != NULL) {
-			OCSPSingleResponse *singleResp = 
+			OCSPSingleResponse *singleResp =
 				ocspResp->singleResponseFor(pendReq->certID);
 			if(singleResp) {
-				crtn = tpApplySingleResp(*singleResp, pendReq->subject, pendReq->dex, 
+				crtn = tpApplySingleResp(*singleResp, pendReq->subject, pendReq->dex,
 					optFlags, vfyCtx.verifyTime, pendReq->processed);
 				if(crtn && (ourRtn == CSSM_OK)) {
 					ourRtn = crtn;
@@ -768,8 +770,8 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 				delete singleResp;
 			}
 		}	/* a reply which matches a pending request */
-		
-		/* 
+
+		/*
 		 * Done with this - note local OCSP response cache doesn't store this
 		 * object; it stores an encoded copy.
 		 */
@@ -778,9 +780,9 @@ CSSM_RETURN tpVerifyCertGroupWithOCSP(
 
 postOcspd:
 
-	/* 
-	 * Now process each cert which hasn't had an OCSP response applied to it. 
-	 * This can happen if we get back replies which are not strictly in 1-1 sync with 
+	/*
+	 * Now process each cert which hasn't had an OCSP response applied to it.
+	 * This can happen if we get back replies which are not strictly in 1-1 sync with
 	 * our requests but which nevertheless contain valid info for more than one
 	 * cert each.
 	 */
@@ -788,7 +790,7 @@ postOcspd:
 		PendingRequest *pendReq = pending[dex];
 		if(pendReq == NULL) {
 			/* i.e. terminated due to user trust */
-			tpOcspDebug("...tpVerifyCertGroupWithOCSP: NULL pendReq dex %u", 
+			tpOcspDebug("...tpVerifyCertGroupWithOCSP: NULL pendReq dex %u",
 					(unsigned)dex);
 			break;
 		}
@@ -801,9 +803,9 @@ postOcspd:
 			singleResp = tpOcspCacheLookup(pendReq->certID, localResponder);
 		}
 		if(singleResp) {
-			tpOcspDebug("...tpVerifyCertGroupWithOCSP: localCache (2) hit dex %u", 
+			tpOcspDebug("...tpVerifyCertGroupWithOCSP: localCache (2) hit dex %u",
 					(unsigned)dex);
-			crtn = tpApplySingleResp(*singleResp, pendReq->subject, dex, optFlags, 
+			crtn = tpApplySingleResp(*singleResp, pendReq->subject, dex, optFlags,
 					vfyCtx.verifyTime, pendReq->processed);
 			if(crtn) {
 				if(ourRtn == CSSM_OK) {
@@ -856,7 +858,7 @@ postOcspd:
 			}
 		}
 	}
-errOut:	
+errOut:
 	for(unsigned dex=0; dex<numCerts; dex++) {
 		PendingRequest *pendReq = pending[dex];
 		if(pendReq == NULL) {
diff --git a/Security/libsecurity_codesigning/lib/SecTask.c b/Security/libsecurity_codesigning/lib/SecTask.c
index f3a36d2a..581fa91e 100644
--- a/Security/libsecurity_codesigning/lib/SecTask.c
+++ b/Security/libsecurity_codesigning/lib/SecTask.c
@@ -290,3 +290,11 @@ CFDictionaryRef SecTaskCopyValuesForEntitlements(SecTaskRef task, CFArrayRef ent
 
 	return values;
 }
+
+Boolean SecTaskEntitlementsValidated(SecTaskRef task) {
+    // TODO: Cache the result
+    uint32_t csflags = 0;
+    const uint32_t mask = CS_VALID | CS_KILL | CS_ENTITLEMENTS_VALIDATED;
+    int rc = csops_task(task, CS_OPS_STATUS, &csflags, sizeof(csflags));
+    return rc != -1 && ((csflags & mask) == mask);
+}
diff --git a/Security/libsecurity_codesigning/lib/SecTaskPriv.h b/Security/libsecurity_codesigning/lib/SecTaskPriv.h
index 80bc0479..0190ee5b 100644
--- a/Security/libsecurity_codesigning/lib/SecTaskPriv.h
+++ b/Security/libsecurity_codesigning/lib/SecTaskPriv.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Apple Inc. All Rights Reserved.
+ * Copyright (c) 2013-2014 Apple Inc. All Rights Reserved.
  * 
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -41,6 +41,14 @@ extern "C" {
 */
 OSStatus SecTaskValidateForRequirement(SecTaskRef task, CFStringRef requirement);
 
+/*!
+    @function SecTaskEntitlementsValidated
+    @abstract Check whether entitlements can be trusted or not.  If this returns
+    false the tasks entitlements must not be used for anything security sensetive.
+    @param task A previously created SecTask object
+*/
+Boolean SecTaskEntitlementsValidated(SecTaskRef task);
+
 #if defined(__cplusplus)
 }
 #endif
diff --git a/Security/libsecurity_codesigning/lib/StaticCode.cpp b/Security/libsecurity_codesigning/lib/StaticCode.cpp
index 7a5fb176..f7503184 100644
--- a/Security/libsecurity_codesigning/lib/StaticCode.cpp
+++ b/Security/libsecurity_codesigning/lib/StaticCode.cpp
@@ -417,11 +417,16 @@ CFDataRef SecStaticCode::signature()
 void SecStaticCode::validateDirectory()
 {
 	// echo previous outcome, if any
-	if (!validated())
+	// track revocation separately, as it may not have been checked
+	// during the initial validation
+	if (!validated() || ((mValidationFlags & kSecCSEnforceRevocationChecks) && !revocationChecked()))
 		try {
 			// perform validation (or die trying)
 			CODESIGN_EVAL_STATIC_DIRECTORY(this);
 			mValidationExpired = verifySignature();
+			if (mValidationFlags & kSecCSEnforceRevocationChecks)
+				mRevocationChecked = true;
+
 			for (CodeDirectory::SpecialSlot slot = codeDirectory()->maxSpecialSlot(); slot >= 1; --slot)
 				if (mCache[slot])	// if we already loaded that resource...
 					validateComponent(slot, errorForSlot(slot)); // ... then check it now
diff --git a/Security/libsecurity_codesigning/lib/StaticCode.h b/Security/libsecurity_codesigning/lib/StaticCode.h
index 9974a3d5..b9eac887 100644
--- a/Security/libsecurity_codesigning/lib/StaticCode.h
+++ b/Security/libsecurity_codesigning/lib/StaticCode.h
@@ -150,6 +150,7 @@ public:
 	void resetValidity();						// clear validation caches (if something may have changed)
 	
 	bool validated() const	{ return mValidated; }
+	bool revocationChecked() const { return mRevocationChecked; }
 	bool valid() const
 		{ assert(validated()); return mValidated && (mValidationResult == errSecSuccess); }
 	bool validatedExecutable() const	{ return mExecutableValidated; }
@@ -211,6 +212,7 @@ private:
 	
 	// master validation state
 	bool mValidated;					// core validation was attempted
+	bool mRevocationChecked;			// the signature was checked for revocation
 	OSStatus mValidationResult;			// outcome of core validation
 	bool mValidationExpired;			// outcome had expired certificates
 	
diff --git a/Security/libsecurity_codesigning/lib/security_codesigning.exp b/Security/libsecurity_codesigning/lib/security_codesigning.exp
index e865acbd..7a907d31 100644
--- a/Security/libsecurity_codesigning/lib/security_codesigning.exp
+++ b/Security/libsecurity_codesigning/lib/security_codesigning.exp
@@ -133,6 +133,7 @@ _SecTaskCreateWithAuditToken
 _SecTaskCreateFromSelf
 _SecTaskCopyValueForEntitlement
 _SecTaskCopyValuesForEntitlements
+_SecTaskEntitlementsValidated
 _SecTaskValidateForRequirement
 
 # Assessments
diff --git a/Security/libsecurity_codesigning/libsecurity_codesigning.xcodeproj/project.pbxproj b/Security/libsecurity_codesigning/libsecurity_codesigning.xcodeproj/project.pbxproj
index b42baeda..bd92c79d 100644
--- a/Security/libsecurity_codesigning/libsecurity_codesigning.xcodeproj/project.pbxproj
+++ b/Security/libsecurity_codesigning/libsecurity_codesigning.xcodeproj/project.pbxproj
@@ -73,6 +73,7 @@
 		18B965951472FE30005A4D2E /* cdbuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = C2D383150A237F47005C63A2 /* cdbuilder.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		37DDE33C1947A4F3005CE18B /* dirscanner.h in Headers */ = {isa = PBXBuildFile; fileRef = 37DDE33B1947A4F3005CE18B /* dirscanner.h */; };
 		37DDE3421947A501005CE18B /* dirscanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 37DDE3411947A501005CE18B /* dirscanner.cpp */; };
+		48674DE319EC9E610049EB7D /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 48674DE219EC9E610049EB7D /* Security.framework */; };
 		7A4FAF1B19C215DF00D297CB /* CrashReporterSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A4FAF1A19C215DF00D297CB /* CrashReporterSupport.framework */; };
 		7A9DA65C1948D1BA004635E6 /* opaquewhitelist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7A9DA65A1948D1BA004635E6 /* opaquewhitelist.cpp */; };
 		7A9DA65D1948D1BA004635E6 /* opaquewhitelist.h in Headers */ = {isa = PBXBuildFile; fileRef = 7A9DA65B1948D1BA004635E6 /* opaquewhitelist.h */; };
@@ -372,6 +373,7 @@
 		184461A2146E9AD100B12992 /* release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = release.xcconfig; sourceTree = "<group>"; };
 		37DDE33B1947A4F3005CE18B /* dirscanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dirscanner.h; sourceTree = "<group>"; };
 		37DDE3411947A501005CE18B /* dirscanner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dirscanner.cpp; sourceTree = "<group>"; };
+		48674DE219EC9E610049EB7D /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = "../../../Volumes/Data/Users/murf/Projects/Security/build/Debug-iphoneos/Security.framework"; sourceTree = "<group>"; };
 		4CA1FEBE052A3C8100F22E42 /* libsecurity_codesigning.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libsecurity_codesigning.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		7A4FAF1A19C215DF00D297CB /* CrashReporterSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CrashReporterSupport.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.Internal.sdk/System/Library/PrivateFrameworks/CrashReporterSupport.framework; sourceTree = DEVELOPER_DIR; };
 		7A9DA65A1948D1BA004635E6 /* opaquewhitelist.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = opaquewhitelist.cpp; sourceTree = "<group>"; };
@@ -631,6 +633,7 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				48674DE319EC9E610049EB7D /* Security.framework in Frameworks */,
 				7A4FAF1B19C215DF00D297CB /* CrashReporterSupport.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -934,6 +937,7 @@
 		C2CC30EF0B8519CF005FA59D /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				48674DE219EC9E610049EB7D /* Security.framework */,
 				C200424915D425B7004AE0A1 /* libsecurity_codesigning.a */,
 				C200424A15D425B7004AE0A1 /* libsecurity_utilities.a */,
 				C2CC30A00B8519CC005FA59D /* CoreFoundation.framework */,
@@ -1682,7 +1686,7 @@
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
 				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_MODULES = NO;
 				CLANG_ENABLE_OBJC_ARC = YES;
 				CLANG_WARN_BOOL_CONVERSION = YES;
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
@@ -1693,6 +1697,7 @@
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+					"/Volumes/Data/Users/murf/Projects/Security/build/Debug-iphoneos",
 				);
 				GCC_C_LANGUAGE_STANDARD = gnu99;
 				GCC_DYNAMIC_NO_PIC = NO;
@@ -1725,7 +1730,7 @@
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
 				CLANG_CXX_LIBRARY = "libc++";
-				CLANG_ENABLE_MODULES = YES;
+				CLANG_ENABLE_MODULES = NO;
 				CLANG_ENABLE_OBJC_ARC = YES;
 				CLANG_WARN_BOOL_CONVERSION = YES;
 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
@@ -1738,6 +1743,7 @@
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks",
+					"/Volumes/Data/Users/murf/Projects/Security/build/Debug-iphoneos",
 				);
 				GCC_C_LANGUAGE_STANDARD = gnu99;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
diff --git a/Security/libsecurity_keychain/lib/Certificate.cpp b/Security/libsecurity_keychain/lib/Certificate.cpp
index 76d6c1ce..1b625a49 100644
--- a/Security/libsecurity_keychain/lib/Certificate.cpp
+++ b/Security/libsecurity_keychain/lib/Certificate.cpp
@@ -2,14 +2,14 @@
  * Copyright (c) 2002-2007,2011-2014 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The 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,
@@ -17,7 +17,7 @@
  * 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.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
@@ -36,6 +36,8 @@
 #include <vector>
 #include <CommonCrypto/CommonDigestSPI.h>
 #include <SecBase.h>
+#include <libDER/libDER.h>
+#include <libDER/DER_Decode.h>
 
 using namespace KeychainCore;
 
@@ -56,7 +58,8 @@ Certificate::Certificate(const CSSM_DATA &data, CSSM_CERT_TYPE type, CSSM_CERT_E
 	mV1SubjectPublicKeyCStructValue(NULL),
 	mV1SubjectNameCStructValue(NULL),
 	mV1IssuerNameCStructValue(NULL),
-	mSha1Hash(NULL)
+	mSha1Hash(NULL),
+	mEncodingVerified(false)
 {
 	if (data.Length == 0 || data.Data == NULL)
 		MacOSError::throwMe(errSecParam);
@@ -72,7 +75,8 @@ Certificate::Certificate(const Keychain &keychain, const PrimaryKey &primaryKey,
 	mV1SubjectPublicKeyCStructValue(NULL),
 	mV1SubjectNameCStructValue(NULL),
 	mV1IssuerNameCStructValue(NULL),
-	mSha1Hash(NULL)
+	mSha1Hash(NULL),
+	mEncodingVerified(false)
 {
 }
 
@@ -107,7 +111,8 @@ Certificate::Certificate(const Keychain &keychain, const PrimaryKey &primaryKey)
 	mV1SubjectPublicKeyCStructValue(NULL),
 	mV1SubjectNameCStructValue(NULL),
 	mV1IssuerNameCStructValue(NULL),
-	mSha1Hash(NULL)
+	mSha1Hash(NULL),
+	mEncodingVerified(false)
 {
 	// @@@ In this case we don't know the type...
 }
@@ -123,7 +128,8 @@ Certificate::Certificate(Certificate &certificate) :
 	mV1SubjectPublicKeyCStructValue(NULL),
 	mV1SubjectNameCStructValue(NULL),
 	mV1IssuerNameCStructValue(NULL),
-	mSha1Hash(NULL)
+	mSha1Hash(NULL),
+	mEncodingVerified(false)
 {
 }
 
@@ -707,22 +713,124 @@ Certificate::populateAttributes()
 	mPopulated = true;
 }
 
+bool
+Certificate::verifyEncoding(CSSM_DATA_PTR data)
+{
+	bool verified = false;
+	CSSM_SIZE verifiedLength = 0;
+	{
+		StLock<Mutex>_(mMutex);
+		if (!data || !data->Data || !data->Length) {
+			mEncodingVerified = false;
+			return false;
+		}
+		verified = mEncodingVerified;
+		if (verified) {
+			return true;
+		}
+
+		// Note: the Certificate class supports X509v1 through X509v3 certs,
+		// with CSSM_CERT_ENCODING_BER or CSSM_CERT_ENCODING_DER encoding.
+		// Any other types/encodings would need additional verification code here.
+
+		if (mHaveTypeAndEncoding) {
+			if (mType < CSSM_CERT_X_509v1 || mType > CSSM_CERT_X_509v3) {
+				secdebug("Certificate", "verifyEncoding: certificate has custom type (%d)", (int)mType);
+			}
+			if (mEncoding < CSSM_CERT_ENCODING_BER || mEncoding > CSSM_CERT_ENCODING_DER) {
+				secdebug("Certificate", "verifyEncoding: certificate has custom encoding (%d)", (int)mEncoding);
+			}
+		}
+
+		// attempt to decode the top-level ASN.1 sequence
+		const DERItem der = { (DERByte *)data->Data, (DERSize)data->Length };
+		DERDecodedInfo derInfo;
+		// sanity check the first byte to avoid decoding a non-DER blob
+		if ((DERByte)0x30 != *(der.data)) {
+			return false;
+		}
+		DERReturn drtn = DERDecodeItem(&der, &derInfo);
+		if (drtn == DR_Success) {
+			CSSM_SIZE tagLength = (CSSM_SIZE)((uintptr_t)derInfo.content.data - (uintptr_t)der.data);
+			CSSM_SIZE derLength = (CSSM_SIZE)derInfo.content.length + tagLength;
+			if (derLength != data->Length) {
+				secdebug("Certificate", "Certificate DER length is %d, but data length is %d",
+						(int)derLength, (int)data->Length);
+				// will adjust data size if DER length is positive, but smaller than actual length
+				if ((derLength > 0) && (derLength < data->Length)) {
+					verifiedLength = derLength;
+					secdebug("Certificate", "Will adjust certificate data length to %d",
+							(int)derLength);
+				}
+				else {
+					secdebug("Certificate", "Certificate encoding invalid (DER length is %d)",
+							(int)derLength);
+					return false;
+				}
+			}
+			verified = mEncodingVerified = true;
+		}
+		else {
+			// failure to decode provided data as DER sequence
+			secdebug("Certificate", "Certificate not in DER encoding (error %d)",
+					(int)drtn);
+			return false;
+		}
+	}
+
+	if (verifiedLength > 0) {
+		// setData acquires the mMutex lock, so we call it while not holding the lock
+		setData((UInt32)verifiedLength, data->Data);
+		secdebug("Certificate", "Adjusted certificate data length to %d",
+				(int)verifiedLength);
+	}
+
+	return verified;
+}
+
 const CssmData &
 Certificate::data()
 {
-	StLock<Mutex>_(mMutex);
-	CssmDataContainer *data = mData.get();
-	if (!data && mKeychain)
+	CssmDataContainer *data = NULL;
+	bool hasKeychain = false;
+	bool verified = false;
+	{
+		StLock<Mutex>_(mMutex);
+		data = mData.get();
+		hasKeychain = (mKeychain != NULL);
+		verified = mEncodingVerified;
+	}
+
+	// If data has been set but not yet verified, verify it now.
+	if (!verified && data) {
+		// verifyEncoding might modify mData, so refresh the data container
+		verified = verifyEncoding(data);
+		{
+			StLock<Mutex>_(mMutex);
+			data = mData.get();
+		}
+	}
+
+	// If data isn't set at this point, try to read it from the db record
+	if (!data && hasKeychain)
 	{
 	    // Make sure mUniqueId is set.
 		dbUniqueRecord();
 		CssmDataContainer _data;
-		mData = NULL;
-		/* new data allocated by CSPDL, implicitly freed by CssmDataContainer */
-		mUniqueId->get(NULL, &_data);
+		{
+			StLock<Mutex>_(mMutex);
+			mData = NULL;
+			/* new data allocated by CSPDL, implicitly freed by CssmDataContainer */
+			mUniqueId->get(NULL, &_data);
+		}
 		/* this saves a copy to be freed at destruction and to be passed to caller */
 		setData((UInt32)_data.length(), _data.data());
-		return *mData.get();
+		// verifyEncoding might modify mData, so refresh the data container
+		verified = verifyEncoding(&_data);
+		{
+			StLock<Mutex>_(mMutex);
+			data = mData.get();
+		}
 	}
 
 	// If the data hasn't been set we can't return it.
diff --git a/Security/libsecurity_keychain/lib/Certificate.h b/Security/libsecurity_keychain/lib/Certificate.h
index 7c478976..867cd480 100644
--- a/Security/libsecurity_keychain/lib/Certificate.h
+++ b/Security/libsecurity_keychain/lib/Certificate.h
@@ -124,6 +124,7 @@ protected:
 
 	void addSubjectKeyIdentifier();
 	void populateAttributes();
+	bool verifyEncoding(CSSM_DATA_PTR data);
 
 private:
 	bool mHaveTypeAndEncoding;
@@ -140,6 +141,7 @@ private:
     CSSM_DATA_PTR mV1SubjectNameCStructValue;
     CSSM_DATA_PTR mV1IssuerNameCStructValue;
 	CFDataRef mSha1Hash;
+	bool mEncodingVerified;
 };
 
 } // end namespace KeychainCore
diff --git a/Security/libsecurity_ocspd/common/ocspResponse.cpp b/Security/libsecurity_ocspd/common/ocspResponse.cpp
index bce02bc4..b1f09b05 100644
--- a/Security/libsecurity_ocspd/common/ocspResponse.cpp
+++ b/Security/libsecurity_ocspd/common/ocspResponse.cpp
@@ -1,15 +1,15 @@
 /*
  * Copyright (c) 2004,2011-2012,2014 Apple Inc. All Rights Reserved.
- * 
+ *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The 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,
@@ -17,7 +17,7 @@
  * 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.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
@@ -77,7 +77,7 @@ OCSPClientCertID::OCSPClientCertID(
 	allocCopyData(issuerPubKey, mIssuerPubKey);
 	allocCopyData(subjectSerial, mSubjectSerial);
 }
-		
+
 OCSPClientCertID::~OCSPClientCertID()
 {
 	freeData(mIssuerName);
@@ -85,7 +85,7 @@ OCSPClientCertID::~OCSPClientCertID()
 	freeData(mSubjectSerial);
 	freeData(mEncoded);
 }
-	
+
 /* preencoded DER NULL */
 static uint8 nullParam[2] = {5, 0};
 
@@ -97,11 +97,11 @@ const CSSM_DATA *OCSPClientCertID::encode()
 	if(mEncoded.Data != NULL) {
 		return &mEncoded;
 	}
-	
+
 	SecAsn1OCSPCertID	certID;
 	uint8				issuerNameHash[CC_SHA1_DIGEST_LENGTH];
 	uint8				pubKeyHash[CC_SHA1_DIGEST_LENGTH];
-	
+
 	/* algId refers to the hash we'll perform in issuer name and key */
 	certID.algId.algorithm = CSSMOID_SHA1;
 	certID.algId.parameters.Data = nullParam;
@@ -109,32 +109,33 @@ const CSSM_DATA *OCSPClientCertID::encode()
 
 	/* SHA1(issuerName) */
 	ocspdSha1(mIssuerName.Data, (CC_LONG)mIssuerName.Length, issuerNameHash);
-	/* SHA1(issuer public key) */
+
+	/* SHA1(issuer public key bytes) */
 	ocspdSha1(mIssuerPubKey.Data, (CC_LONG)mIssuerPubKey.Length, pubKeyHash);
-	
+
 	/* build the CertID from those components */
 	certID.issuerNameHash.Data = issuerNameHash;
 	certID.issuerNameHash.Length = CC_SHA1_DIGEST_LENGTH;
 	certID.issuerPubKeyHash.Data = pubKeyHash;
-	certID.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH;	
+	certID.issuerPubKeyHash.Length = CC_SHA1_DIGEST_LENGTH;
 	certID.serialNumber = mSubjectSerial;
-	
+
 	/* encode */
 	SecAsn1CoderRef coder;
 	SecAsn1CoderCreate(&coder);
-	
+
 	CSSM_DATA tmp = {0, NULL};
 	SecAsn1EncodeItem(coder, &certID, kSecAsn1OCSPCertIDTemplate, &tmp);
 	allocCopyData(tmp, mEncoded);
 	SecAsn1CoderRelease(coder);
 	return &mEncoded;
 }
-		
+
 /*
  * Does this object refer to the same cert as specified SecAsn1OCSPCertID?
- * This is the main purpose of this class's existence; this function works 
+ * This is the main purpose of this class's existence; this function works
  * even if specified SecAsn1OCSPCertID uses a different hash algorithm
- * than we do, since we keep copies of our basic components. 
+ * than we do, since we keep copies of our basic components.
  *
  * Returns true if compare successful.
  */
@@ -152,7 +153,7 @@ bool OCSPClientCertID::compareToExist(
 	const CSSM_OID *alg = &exist.algId.algorithm;
 	uint8 digest[OCSPD_MAX_DIGEST_LEN];
 	CSSM_DATA digestData = {0, digest};
-	
+
 	if(ocspdCompareCssmData(alg, &CSSMOID_SHA1)) {
 		hf = ocspdSha1;
 		digestData.Length = CC_SHA1_DIGEST_LENGTH;
@@ -169,7 +170,7 @@ bool OCSPClientCertID::compareToExist(
 	else {
 		return false;
 	}
-	
+
 	/* generate digests using exist's hash algorithm */
 	hf(mIssuerName.Data, (CC_LONG)mIssuerName.Length, digest);
 	if(!ocspdCompareCssmData(&digestData, &exist.issuerNameHash)) {
@@ -179,7 +180,7 @@ bool OCSPClientCertID::compareToExist(
 	if(!ocspdCompareCssmData(&digestData, &exist.issuerPubKeyHash)) {
 		return false;
 	}
-	
+
 	return true;
 }
 
@@ -189,7 +190,7 @@ bool OCSPClientCertID::compareToExist(
 	SecAsn1CoderRef coder;
 	SecAsn1OCSPCertID certID;
 	bool brtn = false;
-	
+
 	SecAsn1CoderCreate(&coder);
 	memset(&certID, 0, sizeof(certID));
 	if(SecAsn1DecodeData(coder, &exist, kSecAsn1OCSPCertIDTemplate, &certID)) {
@@ -216,7 +217,7 @@ OCSPSingleResponse::OCSPSingleResponse(
 		mExtensions(NULL)
 {
 	assert(resp != NULL);
-	
+
 	SecAsn1CoderCreate(&mCoder);
 	if((resp->certStatus.Data == NULL) || (resp->certStatus.Length == 0)) {
 		ocspdErrorLog("OCSPSingleResponse: bad certStatus\n");
@@ -227,7 +228,7 @@ OCSPSingleResponse::OCSPSingleResponse(
 		/* decode further to get SecAsn1OCSPRevokedInfo */
 		SecAsn1OCSPCertStatus certStatus;
 		memset(&certStatus, 0, sizeof(certStatus));
-		if(SecAsn1DecodeData(mCoder, &resp->certStatus, 
+		if(SecAsn1DecodeData(mCoder, &resp->certStatus,
 				kSecAsn1OCSPCertStatusRevokedTemplate, &certStatus)) {
 			ocspdErrorLog("OCSPSingleResponse: err decoding certStatus\n");
 			CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
@@ -249,7 +250,7 @@ OCSPSingleResponse::OCSPSingleResponse(
 		mNextUpdate = genTimeToCFAbsTime(resp->nextUpdate);
 	}
 	mExtensions = new OCSPExtensions(resp->singleExtensions);
-	ocspdDebug("OCSPSingleResponse: status %d reason %d", (int)mCertStatus, 
+	ocspdDebug("OCSPSingleResponse: status %d reason %d", (int)mCertStatus,
 		(int)mCrlReason);
 }
 
@@ -293,7 +294,7 @@ CFAbsoluteTime OCSPSingleResponse::archiveCutoff()
 OCSPResponse::OCSPResponse(
 	const CSSM_DATA &resp,
 	CFTimeInterval defaultTTL)		// default time-to-live in seconds
-		: mLatestNextUpdate(NULL_TIME), 
+		: mLatestNextUpdate(NULL_TIME),
 		  mExpireTime(NULL_TIME),
 		  mExtensions(NULL)
 {
@@ -305,12 +306,12 @@ OCSPResponse::OCSPResponse(
 	mResponderIdTag = (SecAsn1OCSPResponderIDTag)0;		// invalid
 	mEncResponderName.Data = NULL;
 	mEncResponderName.Length = 0;
-	
+
 	if(SecAsn1DecodeData(mCoder, &resp, kSecAsn1OCSPResponseTemplate, &mTopResp)) {
 		ocspdErrorLog("OCSPResponse: decode failure at top level\n");
 		CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
 	}
-	
+
 	/* remainder is valid only on RS_Success */
 	if((mTopResp.responseStatus.Data == NULL) ||
 	   (mTopResp.responseStatus.Length == 0)) {
@@ -318,7 +319,7 @@ OCSPResponse::OCSPResponse(
 		CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
 	}
 	if(mTopResp.responseStatus.Data[0] != RS_Success) {
-		/* not a failure of our constructor; this object is now useful, but 
+		/* not a failure of our constructor; this object is now useful, but
 		 * only for this one byte of status info */
 		return;
 	}
@@ -332,16 +333,16 @@ OCSPResponse::OCSPResponse(
 		ocspdErrorLog("OCSPResponse: unknown responseType\n");
 		CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
 	}
-	
+
 	/* decode the SecAsn1OCSPBasicResponse */
 	if(SecAsn1DecodeData(mCoder, &mTopResp.responseBytes->response,
 			kSecAsn1OCSPBasicResponseTemplate, &mBasicResponse)) {
 		ocspdErrorLog("OCSPResponse: decode failure at SecAsn1OCSPBasicResponse\n");
 		CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
 	}
-	
+
 	/* signature and cert evaluation done externally */
-	
+
 	/* decode the SecAsn1OCSPResponseData */
 	if(SecAsn1DecodeData(mCoder, &mBasicResponse.tbsResponseData,
 			kSecAsn1OCSPResponseDataTemplate, &mResponseData)) {
@@ -352,17 +353,17 @@ OCSPResponse::OCSPResponse(
 		ocspdErrorLog("OCSPResponse: bad responderID\n");
 		CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
 	}
-		
+
 	/* choice processing for ResponderID */
 	mResponderIdTag = (SecAsn1OCSPResponderIDTag)
 		(mResponseData.responderID.Data[0] & SEC_ASN1_TAGNUM_MASK);
 	const SecAsn1Template *templ;
 	switch(mResponderIdTag) {
-		case RIT_Name: 
-			templ = kSecAsn1OCSPResponderIDAsNameTemplate; 
+		case RIT_Name:
+			templ = kSecAsn1OCSPResponderIDAsNameTemplate;
 			break;
-		case RIT_Key: 
-			templ = kSecAsn1OCSPResponderIDAsKeyTemplate; 
+		case RIT_Key:
+			templ = kSecAsn1OCSPResponderIDAsKeyTemplate;
 			break;
 		default:
 			ocspdErrorLog("OCSPResponse: bad responderID tag\n");
@@ -372,14 +373,14 @@ OCSPResponse::OCSPResponse(
 		ocspdErrorLog("OCSPResponse: decode failure at responderID\n");
 		CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
 	}
-	
+
 	/* check temporal validity */
 	if(!calculateValidity(defaultTTL)) {
 		/* Whoops, abort */
 		CssmError::throwMe(CSSMERR_APPLETP_OCSP_BAD_RESPONSE);
 	}
-	
-	/* 
+
+	/*
 	 * Individual responses looked into when we're asked for a specific one
 	 * via singleResponse()
 	 */
@@ -428,8 +429,8 @@ const CSSM_DATA *OCSPResponse::signerCert(uint32 dex)
 	return mBasicResponse.certs[dex];
 }
 
-/* 
- * Obtain a OCSPSingleResponse for a given "smart" CertID. 
+/*
+ * Obtain a OCSPSingleResponse for a given "smart" CertID.
  */
 OCSPSingleResponse *OCSPResponse::singleResponseFor(OCSPClientCertID &matchCertID)
 {
@@ -453,7 +454,7 @@ OCSPSingleResponse *OCSPResponse::singleResponseFor(OCSPClientCertID &matchCertI
 }
 
 /*
- * If responderID is of form RIT_Name, return the encoded version of the 
+ * If responderID is of form RIT_Name, return the encoded version of the
  * NSS_Name (for comparison with issuer's subjectName). Evaluated lazily,
  * once, in mCoder space.
  */
@@ -474,8 +475,8 @@ const CSSM_DATA *OCSPResponse::encResponderName()
 	return &mEncResponderName;
 }
 
-/* 
- * Obtain a OCSPSingleResponse for a given raw encoded CertID. 
+/*
+ * Obtain a OCSPSingleResponse for a given raw encoded CertID.
  */
 OCSPSingleResponse *OCSPResponse::singleResponseFor(const CSSM_DATA &matchCertID)
 {
@@ -506,29 +507,29 @@ OCSPSingleResponse *OCSPResponse::singleResponseFor(const CSSM_DATA &matchCertID
 
 }
 
-/* 
+/*
  * Calculate temporal validity; set mLatestNextUpdate and mExpireTime. Only
- * called from constructor. Returns true if valid, else returns false. 
+ * called from constructor. Returns true if valid, else returns false.
  */
 bool OCSPResponse::calculateValidity(CFTimeInterval defaultTTL)
 {
 	mLatestNextUpdate = NULL_TIME;
 	CFAbsoluteTime now = CFAbsoluteTimeGetCurrent();
-	
+
 	unsigned numResponses = ocspdArraySize((const void **)mResponseData.responses);
 	for(unsigned dex=0; dex<numResponses; dex++) {
 		SecAsn1OCSPSingleResponse *resp = mResponseData.responses[dex];
-		
-		/* 
-		 * First off, a thisUpdate later than 'now' invalidates the whole response. 
+
+		/*
+		 * First off, a thisUpdate later than 'now' invalidates the whole response.
 		 */
 		CFAbsoluteTime thisUpdate = genTimeToCFAbsTime(&resp->thisUpdate);
 		if(thisUpdate > now) {
 			ocspdErrorLog("OCSPResponse::calculateValidity: thisUpdate not passed\n");
 			return false;
 		}
-		
-		/* 
+
+		/*
 		 * Accumulate latest nextUpdate
 		 */
 		if(resp->nextUpdate != NULL) {
@@ -538,7 +539,7 @@ bool OCSPResponse::calculateValidity(CFTimeInterval defaultTTL)
 			}
 		}
 	}
-	
+
 	CFAbsoluteTime defaultExpire = now + defaultTTL;
 	if(mLatestNextUpdate == NULL_TIME) {
 		/* absolute expire time = current time plus default TTL */
diff --git a/Security/libsecurity_ocspd/common/ocspResponse.h b/Security/libsecurity_ocspd/common/ocspResponse.h
index 5c0de2f6..bb40695b 100644
--- a/Security/libsecurity_ocspd/common/ocspResponse.h
+++ b/Security/libsecurity_ocspd/common/ocspResponse.h
@@ -1,15 +1,15 @@
 /*
  * Copyright (c) 2004,2011,2014 Apple Inc. All Rights Reserved.
- * 
+ *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The 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,
@@ -17,14 +17,14 @@
  * 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.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
 /*
  * ocspResponse.h - OCSP Response class
  */
- 
+
 #ifndef	_OCSP_RESPONSE_H_
 #define _OCSP_RESPONSE_H_
 
@@ -38,10 +38,10 @@
 #define CrlReason_NONE		((CE_CrlReason)-1)
 
 /*
- * CertIDs can be represented differently by two peers even though they refer to 
- * the same cert. Client can use SHA1 hash and server can use MD5, for example. 
+ * CertIDs can be represented differently by two peers even though they refer to
+ * the same cert. Client can use SHA1 hash and server can use MD5, for example.
  * So all of our code which creates a CertID based on known, existing subject and
- * issuer certs uses one of these "smart" certIDs which can encode itself and also 
+ * issuer certs uses one of these "smart" certIDs which can encode itself and also
  * compare against any form of existing SecAsn1OCSPCertID.
  */
 class OCSPClientCertID
@@ -56,31 +56,31 @@ public:
 		const CSSM_DATA			&issuerName,
 		const CSSM_DATA			&issuerPubKey,
 		const CSSM_DATA			&subjectSerial);
-		
+
 	~OCSPClientCertID();
-	
+
 	/*
 	 * DER encode.
 	 */
 	const CSSM_DATA *encode();
-		
+
 	/*
 	 * Does this object refer to the same cert as specified SecAsn1OCSPCertID?
-	 * This is the main purpose of this class's existence; this function works 
+	 * This is the main purpose of this class's existence; this function works
 	 * even if specified SecAsn1OCSPCertID uses a different hash algorithm
-	 * than we do, since we keep copies of our basic components. 
+	 * than we do, since we keep copies of our basic components.
 	 *
 	 * Returns true if compare successful.
 	 */
 	bool compareToExist(
 		const SecAsn1OCSPCertID	&exist);
-		
-	/* 
+
+	/*
 	 * Convenience function, like compareToExist, with a raw encoded CertID.
 	 */
-	bool compareToExist( 
+	bool compareToExist(
 		const CSSM_DATA	&exist);
-		
+
 private:
 	CSSM_DATA mIssuerName;
 	CSSM_DATA mIssuerPubKey;
@@ -89,11 +89,11 @@ private:
 };
 
 /*
- * Object representing one SecAsn1OCSPSingleResponse, i.e., the portion of 
+ * Object representing one SecAsn1OCSPSingleResponse, i.e., the portion of
  * an OCSP response associated with a single CertID. These are created and
  * vended solely by an OCSPResponse object. The client which gets them from
  * an OCSPResponse (via singleResponse()) must delete the object when finished
- * with it. 
+ * with it.
  */
 class OCSPSingleResponse
 {
@@ -103,7 +103,7 @@ public:
 	~OCSPSingleResponse();
 	friend class OCSPResponse;
 protected:
-	
+
 	OCSPSingleResponse(
 		SecAsn1OCSPSingleResponse	*resp);
 public:
@@ -112,17 +112,17 @@ public:
 		CFAbsoluteTime				nextUpdate()	{ return mNextUpdate; }
 		CFAbsoluteTime				revokedTime()	{ return mRevokedTime; }
 		CE_CrlReason				crlReason()		{ return mCrlReason; }
-		
+
 		/* Extension accessors - all are optional */
-		
+
 		/* CRL Reference */
 		const CSSM_DATA				*crlUrl();
 		const CSSM_DATA				*crlNum();
 		CFAbsoluteTime				crlTime();			/* may be NULL_TIME */
-		
+
 		/* archive cutoff */
 		CFAbsoluteTime				archiveCutoff();
-		
+
 		/* service locator not implemented yet */
 private:
 		SecAsn1CoderRef				mCoder;
@@ -130,42 +130,42 @@ private:
 		CFAbsoluteTime				mThisUpdate;
 		CFAbsoluteTime				mNextUpdate;		/* may be NULL_TIME */
 		CFAbsoluteTime				mRevokedTime;		/* != NULL_TIME for CS_Revoked */
-		CE_CrlReason				mCrlReason;		
+		CE_CrlReason				mCrlReason;
 		OCSPExtensions				*mExtensions;
 };
 
 /*
- * OCSPResponse maintains its own temporal validity status based on the values of 
+ * OCSPResponse maintains its own temporal validity status based on the values of
  * all of the enclosed SingleResponses' thisUpdate and (optional) nextUpdate
  * fields, in addition to a default time-to-live (TTL) value passed to
  * OCSPResponse's constructor.
  *
- * First, all of the thisUpdate fields are checked during OCSPResponse's constructor. 
+ * First, all of the thisUpdate fields are checked during OCSPResponse's constructor.
  * if any of these are later than the current time, the entire response is considered
- * invalid and the constructor throws a CssmError(CSSMERR_APPLETP_OCSP_BAD_RESPONSE). 
- * Subsequent to construction, all thisUpdate fields are ignored. 
+ * invalid and the constructor throws a CssmError(CSSMERR_APPLETP_OCSP_BAD_RESPONSE).
+ * Subsequent to construction, all thisUpdate fields are ignored.
  *
- * The NextUpdate times are handled as follows. 
+ * The NextUpdate times are handled as follows.
  *
- * 1. An OCSPResponse's latestNextUpdate is defined as the latest of all of the 
- *    nextUpdate fields in its SingleResponses. This is evaluated during construction. 
+ * 1. An OCSPResponse's latestNextUpdate is defined as the latest of all of the
+ *    nextUpdate fields in its SingleResponses. This is evaluated during construction.
  *
- * 2. An OCSPResponse's latestNextUpdate is NULL_TIME if none of its SingleResponses 
- *    contain any nextUpdate (this field is in fact optional). 
+ * 2. An OCSPResponse's latestNextUpdate is NULL_TIME if none of its SingleResponses
+ *    contain any nextUpdate (this field is in fact optional).
  *
- * 3. The caller of OCSPResponse's constructor passes in a default time-to-live 
- *    (TTL) in seconds; call this defaultTTL. Call the time at which the 
+ * 3. The caller of OCSPResponse's constructor passes in a default time-to-live
+ *    (TTL) in seconds; call this defaultTTL. Call the time at which the
  *    constructor is called, PLUS defaultTTL, "defaultExpire".
- * 
+ *
  * -- If the OCSPResponse's latestNextUpdate is NULL_TIME then expireTime() returns
  *    defaultExpire.
  *
- * -- Otherwise, expireTime() returns the lesser of (latestNextUpdate, 
+ * -- Otherwise, expireTime() returns the lesser of (latestNextUpdate,
  *    defaultExpire).
  *
  * Note that this mechanism is used by both the TP's in-core cache and ocspd's
  * on-disk cache; the two have different default TTLs values but the mechanism
- * for calcuating expireTime() is identical. 
+ * for calcuating expireTime() is identical.
  */
 class OCSPResponse
 {
@@ -175,11 +175,11 @@ public:
 	OCSPResponse(
 		const CSSM_DATA &resp,
 		CFTimeInterval defaultTTL);		// default time-to-live in seconds
-		
+
 	~OCSPResponse();
-	
-	/* 
-	 * Info obtained during decode (which is done immediately during constructor) 
+
+	/*
+	 * Info obtained during decode (which is done immediately during constructor)
 	 */
 	SecAsn1OCSPResponseStatus	responseStatus();
 	const CSSM_DATA				*nonce();			/* NULL means not present */
@@ -187,13 +187,13 @@ public:
 	CSSM_RETURN					sigStatus();
 	uint32						numSignerCerts();
 	const CSSM_DATA				*signerCert(uint32 dex);
-	
-	/* 
-	 * Obtain a OCSPSingleResponse for a given CertID. 
+
+	/*
+	 * Obtain a OCSPSingleResponse for a given CertID.
 	 */
 	OCSPSingleResponse			*singleResponseFor(OCSPClientCertID &certID);
 	OCSPSingleResponse			*singleResponseFor(const CSSM_DATA &matchCertID);
-	
+
 	CFAbsoluteTime				expireTime()		{ return mExpireTime; }
 
 	/*
@@ -205,18 +205,18 @@ public:
 	SecAsn1OCSPResponderIDTag		responderIDTag()	{ return mResponderIdTag; }
 
 	const CSSM_DATA					*encResponderName();
-	
+
 private:
 	bool						calculateValidity(CFTimeInterval defaultTTL);
-	
+
 	SecAsn1CoderRef				mCoder;
 	CFAbsoluteTime				mLatestNextUpdate;
 	CFAbsoluteTime				mExpireTime;
-	CSSM_DATA					mEncResponderName;	// encoded ResponderId.byName, 
+	CSSM_DATA					mEncResponderName;	// encoded ResponderId.byName,
 													// if responder is in that format,
 													// lazily evaluated
-	/* 
-	 * Fields we decode - all in mCoder's memory space 
+	/*
+	 * Fields we decode - all in mCoder's memory space
 	 */
 	SecAsn1OCSPResponse			mTopResp;
 	SecAsn1OCSPBasicResponse	mBasicResponse;
@@ -224,6 +224,6 @@ private:
 	SecAsn1OCSPResponderID		mResponderId;		// we have to decode
 	SecAsn1OCSPResponderIDTag	mResponderIdTag;	// IDs previous field
 	OCSPExtensions				*mExtensions;
-};	
+};
 #endif	/* _OCSP_RESPONSE_H_ */
 
diff --git a/Security/libsecurity_ocspd/common/ocspdUtils.cpp b/Security/libsecurity_ocspd/common/ocspdUtils.cpp
index cee4b180..efbdb8a6 100644
--- a/Security/libsecurity_ocspd/common/ocspdUtils.cpp
+++ b/Security/libsecurity_ocspd/common/ocspdUtils.cpp
@@ -2,14 +2,14 @@
  * Copyright (c) 2000,2002,2011-2012,2014 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The 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,
@@ -17,15 +17,18 @@
  * 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.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
-/* 
+/*
  * ocspUtils.cpp - common utilities for OCSPD
  */
 
 #include "ocspdUtils.h"
+#include "ocspdDebug.h"
+#include <Security/cssmerr.h>
+#include <Security/keyTemplates.h>
 #include <CoreFoundation/CoreFoundation.h>
 
 /*
@@ -34,8 +37,8 @@
 CSSM_BOOL ocspdCompareCssmData(
 	const CSSM_DATA *data1,
 	const CSSM_DATA *data2)
-{	
-	if((data1 == NULL) || (data1->Data == NULL) || 
+{
+	if((data1 == NULL) || (data1->Data == NULL) ||
 	   (data2 == NULL) || (data2->Data == NULL) ||
 	   (data1->Length != data2->Length)) {
 		return CSSM_FALSE;
@@ -53,8 +56,8 @@ CSSM_BOOL ocspdCompareCssmData(
 
 /*
  * Convert a generalized time string, with a 4-digit year and no trailing
- * fractional seconds or time zone info, to a CFAbsoluteTime. Returns 
- * NULL_TIME (0.0) on error. 
+ * fractional seconds or time zone info, to a CFAbsoluteTime. Returns
+ * NULL_TIME (0.0) on error.
  */
 static CFAbsoluteTime parseGenTime(
 	const uint8 *str,
@@ -63,7 +66,7 @@ static CFAbsoluteTime parseGenTime(
 	if((str == NULL) || (len == 0)) {
     	return NULL_TIME;
   	}
-	
+
   	/* tolerate NULL terminated or not */
   	if(str[len - 1] == '\0') {
   		len--;
@@ -75,7 +78,7 @@ static CFAbsoluteTime parseGenTime(
 	CFGregorianDate greg;
 	memset(&greg, 0, sizeof(greg));
 	const uint8 *cp = str;
-	
+
 	/* YEAR */
 	szTemp[0] = *cp++;
 	szTemp[1] = *cp++;
@@ -84,7 +87,7 @@ static CFAbsoluteTime parseGenTime(
 	szTemp[4] = '\0';
 	len -= 4;
 	greg.year = atoi(szTemp);
-	
+
 	/* MONTH - CFGregorianDate ranges 1..12, just like the string */
 	if(len < 2) {
 		return NULL_TIME;
@@ -104,7 +107,7 @@ static CFAbsoluteTime parseGenTime(
 	szTemp[2] = '\0';
 	greg.day = atoi( szTemp );
 	len -= 2;
-	
+
 	if(len >= 2) {
 		/* HOUR 0..23 */
 		szTemp[0] = *cp++;
@@ -134,7 +137,7 @@ static CFAbsoluteTime parseGenTime(
 
 /*
  * Parse a GeneralizedTime string into a CFAbsoluteTime. Returns NULL on parse error.
- * Fractional parts of a second are discarded. 
+ * Fractional parts of a second are discarded.
  */
 CFAbsoluteTime genTimeToCFAbsTime(
 	const CSSM_DATA *strData)
@@ -142,20 +145,20 @@ CFAbsoluteTime genTimeToCFAbsTime(
 	if((strData == NULL) || (strData->Data == NULL) || (strData->Length == 0)) {
     	return NULL_TIME;
   	}
-	
+
 	uint8 *timeStr = strData->Data;
 	size_t timeStrLen = strData->Length;
-  	
+
   	/* tolerate NULL terminated or not */
   	if(timeStr[timeStrLen - 1] == '\0') {
   		timeStrLen--;
   	}
-	
+
 	/* start with a fresh editable copy */
 	uint8 *str = (uint8 *)malloc(timeStrLen);
 	uint32 strLen = 0;
-	
-	/* 
+
+	/*
 	 * If there is a decimal point, strip it and all trailing digits off
 	 */
 	const uint8 *inCp = timeStr;
@@ -166,7 +169,7 @@ CFAbsoluteTime genTimeToCFAbsTime(
 	bool minusOffset = false;
 	bool isGMT = false;
 	size_t toGo = timeStrLen;
-	
+
 	do {
 		if(*inCp == '.') {
 			if(foundDecimal) {
@@ -176,7 +179,7 @@ CFAbsoluteTime genTimeToCFAbsTime(
 				}
 			}
 			foundDecimal++;
-			
+
 			/* skip the decimal point... */
 			inCp++;
 			toGo--;
@@ -213,19 +216,19 @@ CFAbsoluteTime genTimeToCFAbsTime(
 			toGo--;
 		}
 	} while(toGo != 0);
-	
+
 	if(str[strLen - 1] == 'Z') {
 		isGMT = true;
 		strLen--;
 	}
-	
+
 	CFAbsoluteTime absTime;
 	absTime = parseGenTime(str, strLen);
 	free(str);
 	if(absTime == NULL_TIME) {
 		return NULL_TIME;
 	}
-	
+
 	/* post processing needed? */
 	if(isGMT) {
 		/* Nope, string was in GMT */
@@ -253,7 +256,7 @@ CFAbsoluteTime genTimeToCFAbsTime(
 	return absTime;
 }
 
-/* 
+/*
  * Convert CFAbsoluteTime to generalized time string, GMT format (4 digit year,
  * trailing 'Z'). Caller allocated the output which is GENERAL_TIME_STRLEN+1 bytes.
  */
@@ -266,10 +269,10 @@ void cfAbsTimeToGgenTime(
 	CFGregorianDate greg = CFAbsoluteTimeGetGregorianDate(absTime, tz);
 	int seconds = (int)greg.second;
 	sprintf(genTime, "%04d%02d%02d%02d%02d%02dZ",
-				(int)greg.year, greg.month, greg.day, greg.hour, 
+				(int)greg.year, greg.month, greg.day, greg.hour,
 				greg.minute, seconds);
 }
- 
+
 void ocspdSha1(
 	const void		*data,
 	CC_LONG			len,
@@ -328,3 +331,87 @@ unsigned ocspdArraySize(
     }
     return count;
 }
+
+/* Fill out a CSSM_DATA with the subset of public key bytes from the given
+ * CSSM_KEY_PTR which should be hashed to produce the issuerKeyHash field
+ * of a CertID in an OCSP request.
+ *
+ * For RSA keys, this simply copies the input key pointer and length.
+ * For EC keys, we need to further deconstruct the SubjectPublicKeyInfo
+ * to obtain the key bytes (i.e. curve point) for hashing.
+ *
+ * Returns CSSM_OK on success, or non-zero error if the bytes could not
+ * be retrieved.
+ */
+CSSM_RETURN ocspdGetPublicKeyBytes(
+	SecAsn1CoderRef coder,		// optional
+	CSSM_KEY_PTR publicKey,		// input public key
+	CSSM_DATA &publicKeyBytes)	// filled in by this function
+{
+	CSSM_RETURN crtn = CSSM_OK;
+	SecAsn1CoderRef _coder = NULL;
+
+	if(publicKey == NULL) {
+		crtn = CSSMERR_CSP_INVALID_KEY_POINTER;
+		goto exit;
+	}
+
+	if(coder == NULL) {
+		crtn = SecAsn1CoderCreate(&_coder);
+		if(crtn) {
+			goto exit;
+		}
+		coder = _coder;
+	}
+
+	publicKeyBytes.Length = publicKey->KeyData.Length;
+	publicKeyBytes.Data = publicKey->KeyData.Data;
+
+	if(publicKey->KeyHeader.AlgorithmId == CSSM_ALGID_ECDSA) {
+		/*
+		 * For an EC key, publicKey->KeyData is a SubjectPublicKeyInfo
+		 * ASN.1 sequence that includes the algorithm identifier.
+		 * We only want to return the bit string portion of the key here.
+		 */
+		SecAsn1PubKeyInfo pkinfo;
+		memset(&pkinfo, 0, sizeof(pkinfo));
+		if(SecAsn1Decode(coder,
+			publicKey->KeyData.Data,
+			publicKey->KeyData.Length,
+			kSecAsn1SubjectPublicKeyInfoTemplate,
+			&pkinfo) == 0) {
+			if(pkinfo.subjectPublicKey.Length &&
+			   pkinfo.subjectPublicKey.Data) {
+				publicKeyBytes.Length = pkinfo.subjectPublicKey.Length >> 3;
+				publicKeyBytes.Data = pkinfo.subjectPublicKey.Data;
+				/*
+				 * Important: if we allocated the SecAsn1Coder, the memory
+				 * being pointed to by pkinfo.subjectPublicKey.Data will be
+				 * deallocated when the coder is released below. We want to
+				 * point to the identical data inside the caller's public key,
+				 * now that the decoder has identified it for us.
+				 */
+				if(publicKeyBytes.Length <= publicKey->KeyData.Length) {
+					publicKeyBytes.Data = (uint8*)((uintptr_t)publicKey->KeyData.Data +
+						(publicKey->KeyData.Length - publicKeyBytes.Length));
+					goto exit;
+				}
+				/* intentional fallthrough to error exit */
+			}
+			ocspdErrorLog("ocspdGetPublicKeyBytes: invalid SecAsn1PubKeyInfo\n");
+			crtn = CSSMERR_CSP_INVALID_KEY_POINTER;
+		}
+		else {
+			/* Unable to decode using kSecAsn1SubjectPublicKeyInfoTemplate.
+			 * This may or may not be an error; just return the unchanged key.
+			 */
+			ocspdErrorLog("ocspdGetPublicKeyBytes: unable to decode SubjectPublicKeyInfo\n");
+		}
+	}
+
+exit:
+	if(_coder) {
+		SecAsn1CoderRelease(_coder);
+	}
+	return crtn;
+}
diff --git a/Security/libsecurity_ocspd/common/ocspdUtils.h b/Security/libsecurity_ocspd/common/ocspdUtils.h
index 57691aca..63d4f4d5 100644
--- a/Security/libsecurity_ocspd/common/ocspdUtils.h
+++ b/Security/libsecurity_ocspd/common/ocspdUtils.h
@@ -2,14 +2,14 @@
  * Copyright (c) 2000,2002,2011,2014 Apple Inc. All Rights Reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * compliance with the License. Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this
  * file.
- * 
+ *
  * The 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,
@@ -17,11 +17,11 @@
  * 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.
- * 
+ *
  * @APPLE_LICENSE_HEADER_END@
  */
 
-/* 
+/*
  * ocspUtils.h - common utilities for OCSPD
  */
 #ifndef	_OCSPD_UTILS_H_
@@ -33,6 +33,7 @@ extern "C" {
 
 #include <CommonCrypto/CommonDigest.h>
 #include <Security/cssmtype.h>
+#include <Security/SecAsn1Coder.h>
 #include <CoreFoundation/CoreFoundation.h>
 
 /*
@@ -43,15 +44,15 @@ CSSM_BOOL ocspdCompareCssmData(
 	const CSSM_DATA *data2);
 
 /*
- * Parse a GeneralizedTime string into a CFAbsoluteTime. Returns NULL_TIME on 
- * parse error. Fractional parts of a second are discarded. 
+ * Parse a GeneralizedTime string into a CFAbsoluteTime. Returns NULL_TIME on
+ * parse error. Fractional parts of a second are discarded.
  */
-#define NULL_TIME	0.0	
+#define NULL_TIME	0.0
 
 CFAbsoluteTime genTimeToCFAbsTime(
 	const CSSM_DATA *strData);
 
-/* 
+/*
  * Convert CFAbsoluteTime to generalized time string, GMT format (4 digit year,
  * trailing 'Z'). Caller allocated the output which is GENERAL_TIME_STRLEN bytes plus
  * a NULL.
@@ -87,11 +88,22 @@ void ocspdSHA256(
 unsigned ocspdArraySize(
 	const void **array);
 
+/*
+ * Fill out a CSSM_DATA with the subset of public key bytes from the given
+ * CSSM_KEY_PTR which should be hashed to produce the issuerKeyHash field
+ * of a CertID in an OCSP request.
+ */
+CSSM_RETURN ocspdGetPublicKeyBytes(
+	SecAsn1CoderRef coder,
+	CSSM_KEY_PTR publicKey,
+	CSSM_DATA &publicKeyBytes); // filled out by this function
+
+
 #define CFRELEASE(cf)	\
 	if(cf != NULL) {	\
 		CFRelease(cf);	\
 	}
-	
+
 #ifdef	__cplusplus
 }
 #endif
diff --git a/Security/sec/SOSCircle/CloudKeychainProxy/CKDKVSProxy.m b/Security/sec/SOSCircle/CloudKeychainProxy/CKDKVSProxy.m
index 2f02cd7f..a9dbaa67 100644
--- a/Security/sec/SOSCircle/CloudKeychainProxy/CKDKVSProxy.m
+++ b/Security/sec/SOSCircle/CloudKeychainProxy/CKDKVSProxy.m
@@ -638,7 +638,7 @@ static const int64_t kSyncTimerLeeway = (NSEC_PER_MSEC * 250);      // 250ms lee
 
             _inCallout = YES;
             if (!_oldInCallout)
-                secnotice("deaf", ">>>>>>>>>>> WTFBBQ _oldInCallout is NO and we're heading in to the callout!");
+                secnotice("deaf", ">>>>>>>>>>> _oldInCallout is NO and we're heading in to the callout!");
 
             _shadowPendingKeys = [NSMutableSet set];
             _shadowSyncWithPeersPending = NO;
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSAccount.c b/Security/sec/SOSCircle/SecureObjectSync/SOSAccount.c
index 4a601f47..52d4a632 100644
--- a/Security/sec/SOSCircle/SecureObjectSync/SOSAccount.c
+++ b/Security/sec/SOSCircle/SecureObjectSync/SOSAccount.c
@@ -77,6 +77,7 @@ bool SOSAccountUpdateGestalt(SOSAccountRef account, CFDictionaryRef new_gestalt)
         if (SOSFullPeerInfoUpdateGestalt(full_peer, new_gestalt, NULL)) {
             SOSAccountModifyCircle(account, SOSCircleGetName(circle),
                                    NULL, ^(SOSCircleRef circle_to_change) {
+                                       secnotice("circleChange", "Calling SOSCircleUpdatePeerInfo for gestalt change");
                                        return SOSCircleUpdatePeerInfo(circle_to_change, SOSFullPeerInfoGetPeerInfo(full_peer));
                                    });
         };
@@ -125,6 +126,7 @@ static void SOSAccountDestroy(CFTypeRef aObj) {
 }
 
 void SOSAccountSetToNew(SOSAccountRef a) {
+    secnotice("accountChange", "Setting Account to New");
     CFAllocatorRef allocator = CFGetAllocator(a);
     CFReleaseNull(a->circle_identities);
     CFReleaseNull(a->circles);
@@ -467,6 +469,7 @@ void SOSAccountAddSyncablePeerBlock(SOSAccountRef a, CFStringRef ds_name, SOSAcc
 bool sosAccountLeaveCircle(SOSAccountRef account, SOSCircleRef circle, CFErrorRef* error) {
     SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInCircle(account, circle, NULL);
     if(!fpi) return false;
+    if(!SOSFullPeerInfoValidate(fpi, NULL)) return false;
 	CFErrorRef localError = NULL;
 	SOSPeerInfoRef retire_peer = SOSFullPeerInfoPromoteToRetiredAndCopy(fpi, &localError);
     CFStringRef retire_id = SOSPeerInfoGetPeerID(retire_peer);
@@ -619,9 +622,11 @@ SOSCCStatus SOSAccountIsInCircles(SOSAccountRef account, CFErrorRef* error) {
 //
 
 static bool SOSAccountResetThisCircleToOffering(SOSAccountRef account, SOSCircleRef circle, SecKeyRef user_key, CFErrorRef *error) {
-    SOSFullPeerInfoRef myCirclePeer = SOSAccountGetMyFullPeerInCircle(account, circle, error);
+    SOSFullPeerInfoRef myCirclePeer = SOSAccountMakeMyFullPeerInCircleNamed(account, SOSCircleGetName(circle), error);
     if (!myCirclePeer)
         return false;
+    if(!SOSFullPeerInfoValidate(myCirclePeer, NULL)) return false;
+
     
     SOSAccountModifyCircle(account, SOSCircleGetName(circle), error, ^(SOSCircleRef circle) {
         bool result = false;
@@ -712,7 +717,7 @@ static bool SOSAccountJoinThisCircle(SOSAccountRef account, SecKeyRef user_key,
     __block bool result = false;
     __block SOSFullPeerInfoRef cloud_full_peer = NULL;
 
-    SOSFullPeerInfoRef myCirclePeer = SOSAccountGetMyFullPeerInCircle(account, circle, error);
+    SOSFullPeerInfoRef myCirclePeer = SOSAccountMakeMyFullPeerInCircleNamed(account, SOSCircleGetName(circle), error);
     
     require_action_quiet(myCirclePeer, fail,
                          SOSCreateErrorWithFormat(kSOSErrorPeerNotFound, NULL, error, NULL, CFSTR("Can't find/create peer for circle: %@"), circle));
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSAccount.h b/Security/sec/SOSCircle/SecureObjectSync/SOSAccount.h
index 2b4a32ef..fe361d17 100644
--- a/Security/sec/SOSCircle/SecureObjectSync/SOSAccount.h
+++ b/Security/sec/SOSCircle/SecureObjectSync/SOSAccount.h
@@ -100,7 +100,7 @@ SOSPeerInfoRef SOSAccountGetMyPeerInCircle(SOSAccountRef account, SOSCircleRef c
 SOSPeerInfoRef SOSAccountGetMyPeerInCircleNamed(SOSAccountRef account, CFStringRef circle, CFErrorRef* error);
 
 SOSFullPeerInfoRef SOSAccountGetMyFullPeerInCircle(SOSAccountRef account, SOSCircleRef circle, CFErrorRef* error);
-SOSFullPeerInfoRef SOSAccountGetMyFullPeerInCircleNamed(SOSAccountRef account, CFStringRef name, CFErrorRef *error);
+SOSFullPeerInfoRef SOSAccountMakeMyFullPeerInCircleNamed(SOSAccountRef account, CFStringRef name, CFErrorRef *error);
 
 //
 // MARK: Credential management
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c
index 47cba02a..c4010795 100644
--- a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c
+++ b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountCircles.c
@@ -80,25 +80,31 @@ static bool SOSAccountInflateTransportsForCircle(SOSAccountRef account, CFString
     SOSTransportKeyParameterRef tKey = NULL;
     SOSTransportCircleRef tCircle = NULL;
     SOSTransportMessageRef tMessage = NULL;
+    
+#if 0 // IDS_FUTURE
+    // Solve determining transport type without fullpeer
     SOSFullPeerInfoRef fpi = SOSAccountGetMyFullPeerInCircleNamed(account, circleName, error);
     require_quiet(fpi, fail);
     SOSPeerInfoRef myPeer = SOSFullPeerInfoGetPeerInfo(fpi);
     require_quiet(myPeer, fail);
     CFStringRef type = SOSPeerInfoGetTransportType(myPeer);
     if(CFStringCompare(type, CFSTR("KVS"), 0) == kCFCompareEqualTo){
-        tKey = (SOSTransportKeyParameterRef)SOSTransportKeyParameterKVSCreate(account, error);
-        tCircle = (SOSTransportCircleRef)SOSTransportCircleKVSCreate(account, circleName, error);
-        tMessage = (SOSTransportMessageRef)SOSTransportMessageKVSCreate(account, circleName, error);
-        require_quiet(tKey, fail);
-        require_quiet(tCircle, fail);
-        require_quiet(tMessage, fail);
-        
-        CFRetainAssign(account->key_transport, (SOSTransportKeyParameterRef)tKey);
-        CFDictionarySetValue(account->circle_transports, circleName, tCircle);
-        CFDictionarySetValue(account->message_transports, circleName, tMessage);
+#endif
+    tKey = (SOSTransportKeyParameterRef)SOSTransportKeyParameterKVSCreate(account, error);
+    tCircle = (SOSTransportCircleRef)SOSTransportCircleKVSCreate(account, circleName, error);
+    tMessage = (SOSTransportMessageRef)SOSTransportMessageKVSCreate(account, circleName, error);
+    require_quiet(tKey, fail);
+    require_quiet(tCircle, fail);
+    require_quiet(tMessage, fail);
+    
+    CFRetainAssign(account->key_transport, (SOSTransportKeyParameterRef)tKey);
+    CFDictionarySetValue(account->circle_transports, circleName, tCircle);
+    CFDictionarySetValue(account->message_transports, circleName, tMessage);
+#if 0 // IDS_FUTURE
     }
-    
+#endif
     success = true;
+
 fail:
     CFReleaseNull(tKey);
     CFReleaseNull(tCircle);
@@ -125,9 +131,9 @@ SOSCircleRef SOSAccountEnsureCircle(SOSAccountRef a, CFStringRef name, CFErrorRe
 
         SOSUpdateKeyInterest();
     }
-    
+
     require_quiet(SOSAccountInflateTransportsForCircle(a, name, error), fail);
-    
+   
 fail:
     CFReleaseNull(localError);
     return circle;
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountFullPeerInfo.c b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountFullPeerInfo.c
index 45d2cf43..aea17555 100644
--- a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountFullPeerInfo.c
+++ b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountFullPeerInfo.c
@@ -103,7 +103,7 @@ bool SOSAccountIsAccountIdentity(SOSAccountRef account, SOSPeerInfoRef peer_info
 
 
 
-SOSFullPeerInfoRef SOSAccountGetMyFullPeerInCircleNamed(SOSAccountRef account, CFStringRef name, CFErrorRef *error) {
+SOSFullPeerInfoRef SOSAccountMakeMyFullPeerInCircleNamed(SOSAccountRef account, CFStringRef name, CFErrorRef *error) {
     if (CFDictionaryGetValue(account->circles, name) == NULL) {
         SOSCreateErrorWithFormat(kSOSErrorNoCircle, NULL, error, NULL, CFSTR("No circle named '%@'"), name);
         return NULL;
@@ -139,7 +139,7 @@ SOSFullPeerInfoRef SOSAccountGetMyFullPeerInCircleNamed(SOSAccountRef account, C
 
 
 SOSFullPeerInfoRef SOSAccountGetMyFullPeerInCircle(SOSAccountRef account, SOSCircleRef circle, CFErrorRef* error) {
-    return SOSAccountGetMyFullPeerInCircleNamed(account, SOSCircleGetName(circle), error);
+    return SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, SOSCircleGetName(circle), error);
 }
 
 
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountPeers.c b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountPeers.c
index d0e0ca03..5f41f26d 100644
--- a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountPeers.c
+++ b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountPeers.c
@@ -49,14 +49,14 @@ bool SOSAccountDestroyCirclePeerInfo(SOSAccountRef account, SOSCircleRef circle,
 }
 
 SOSPeerInfoRef SOSAccountGetMyPeerInCircle(SOSAccountRef account, SOSCircleRef circle, CFErrorRef* error) {
-    SOSFullPeerInfoRef fpi =  SOSAccountGetMyFullPeerInCircleNamed(account, SOSCircleGetName(circle), error);
+    SOSFullPeerInfoRef fpi =  SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, SOSCircleGetName(circle), error);
     
     return fpi ? SOSFullPeerInfoGetPeerInfo(fpi) : NULL;
 }
 
 SOSPeerInfoRef SOSAccountGetMyPeerInCircleNamed(SOSAccountRef account, CFStringRef name, CFErrorRef *error)
 {
-    SOSFullPeerInfoRef fpi =  SOSAccountGetMyFullPeerInCircleNamed(account, name, error);
+    SOSFullPeerInfoRef fpi =  SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, name, error);
     
     return fpi ? SOSFullPeerInfoGetPeerInfo(fpi) : NULL;
 }
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.c b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.c
index c9eaa4f3..ebaed87f 100644
--- a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.c
+++ b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountPersistence.c
@@ -339,7 +339,7 @@ SOSAccountRef SOSAccountCreateFromDER(CFAllocatorRef allocator,
                     if (fullPeerInfoData) {
                         SOSFullPeerInfoRef full_peer = SOSFullPeerInfoCreateFromData(kCFAllocatorDefault, fullPeerInfoData, error);
                         require_action_quiet(full_peer, fail, success = false);
-                        
+                    
                         CFDictionaryAddValue(account->circle_identities, circleName, full_peer);
                         CFReleaseNull(full_peer);
                     }
@@ -352,6 +352,7 @@ SOSAccountRef SOSAccountCreateFromDER(CFAllocatorRef allocator,
     CFReleaseNull(array);
     
     require_quiet(success, fail);
+    
     require_action_quiet(SOSAccountEnsureFactoryCircles(account), fail,
                          SOSCreateError(kSOSErrorBadFormat, CFSTR("Cannot EnsureFactoryCircles"), (error != NULL) ? *error : NULL, error));
     
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountPriv.h b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountPriv.h
index 91d84a14..39be45d2 100644
--- a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountPriv.h
+++ b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountPriv.h
@@ -178,7 +178,7 @@ void SOSAccountForEachKnownCircle(SOSAccountRef account,
 
 int SOSAccountCountCircles(SOSAccountRef a);
 
-SOSFullPeerInfoRef SOSAccountGetMyFullPeerInCircleNamed(SOSAccountRef account, CFStringRef name, CFErrorRef *error);
+SOSFullPeerInfoRef SOSAccountMakeMyFullPeerInCircleNamed(SOSAccountRef account, CFStringRef name, CFErrorRef *error);
 
 bool SOSAccountDestroyCirclePeerInfoNamed(SOSAccountRef account, CFStringRef name, CFErrorRef* error);
 
@@ -234,7 +234,7 @@ SOSFullPeerInfoRef SOSAccountGetMyFullPeerInCircleNamedIfPresent(SOSAccountRef a
 
 bool SOSAccountIsAccountIdentity(SOSAccountRef account, SOSPeerInfoRef peer_info, CFErrorRef *error);
 
-SOSFullPeerInfoRef SOSAccountGetMyFullPeerInCircleNamed(SOSAccountRef account, CFStringRef name, CFErrorRef *error);
+SOSFullPeerInfoRef SOSAccountMakeMyFullPeerInCircleNamed(SOSAccountRef account, CFStringRef name, CFErrorRef *error);
 
 SOSFullPeerInfoRef SOSAccountGetMyFullPeerInCircle(SOSAccountRef account, SOSCircleRef circle, CFErrorRef* error);
 
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.c b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.c
index ad7cae8e..5b23afa5 100644
--- a/Security/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.c
+++ b/Security/sec/SOSCircle/SecureObjectSync/SOSAccountUpdate.c
@@ -268,8 +268,10 @@ bool SOSAccountHandleUpdateCircle(SOSAccountRef account, SOSCircleRef prospectiv
         // SOSAccountDestroyCirclePeerInfo(account, oldCircle, NULL);
     }
     
-    SOSFullPeerInfoRef me_full = SOSAccountGetMyFullPeerInCircle(account, oldCircle, NULL);
-    SOSPeerInfoRef     me = SOSFullPeerInfoGetPeerInfo(me_full);
+    // Changed to just get the fullpeerinfo if present.  We don't want to make up FPIs here.
+    SOSPeerInfoRef     me = NULL;
+    SOSFullPeerInfoRef me_full = SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, SOSCircleGetName(oldCircle), NULL);
+    if(me_full) me = SOSFullPeerInfoGetPeerInfo(me_full);
     
     SOSTransportCircleRef transport = (SOSTransportCircleRef)CFDictionaryGetValue(account->circle_transports, SOSCircleGetName(prospective_circle));
 
@@ -354,16 +356,18 @@ bool SOSAccountHandleUpdateCircle(SOSAccountRef account, SOSCircleRef prospectiv
         
         if (me && SOSCircleHasPeer(oldCircle, me, NULL)) {
             if (sosAccountLeaveCircle(account, newCircle, error)) {
-                account->departure_code = leave_reason;
                 circleToPush = newCircle;
-                circle_action = accept;
-                me = NULL;
-                me_full = NULL;
+            } else {
+                secnotice("signing", "Can't leave circle %@, but dumping identities", oldCircle);
+                success = false;
             }
-        }
-        else {
+            account->departure_code = leave_reason;
+            circle_action = accept;
+            me = NULL;
+            me_full = NULL;
+        } else {
             // We are not in this circle, but we need to update account with it, since we got it from cloud
-            secnotice("updatecircle", "We are not in this circle, but we need to update account with it");
+            secnotice("signing", "We are not in this circle, but we need to update account with it");
             circle_action = accept;
         }
     }
@@ -408,7 +412,7 @@ bool SOSAccountHandleUpdateCircle(SOSAccountRef account, SOSCircleRef prospectiv
                 me = NULL;
                 me_full = NULL;
             } else {
-                SOSCircleRequestReadmission(newCircle, account->user_public, me_full, NULL);
+                SOSCircleRequestReadmission(newCircle, account->user_public, me, NULL);
                 writeUpdate = true;
             }
         }
@@ -419,7 +423,7 @@ bool SOSAccountHandleUpdateCircle(SOSAccountRef account, SOSCircleRef prospectiv
         
         secnotice("signing", "%@, Accepting circle: %@", concStr, newCircle);
         
-        if (me_full && account->user_public_trusted
+        if (me && account->user_public_trusted
             && SOSCircleHasApplicant(oldCircle, me, NULL)
             && SOSCircleCountPeers(newCircle) > 0
             && !SOSCircleHasPeer(newCircle, me, NULL) && !SOSCircleHasApplicant(newCircle, me, NULL)) {
@@ -427,7 +431,7 @@ bool SOSAccountHandleUpdateCircle(SOSAccountRef account, SOSCircleRef prospectiv
             // We were applying and we weren't accepted.
             // Our application is declared lost, let us reapply.
             
-            if (SOSCircleRequestReadmission(newCircle, account->user_public, me_full, NULL))
+            if (SOSCircleRequestReadmission(newCircle, account->user_public, me, NULL))
                 writeUpdate = true;
         }
         
@@ -461,7 +465,7 @@ bool SOSAccountHandleUpdateCircle(SOSAccountRef account, SOSCircleRef prospectiv
     
     
     if (circleToPush != NULL) {
-        secnotice("circleUpdate", "Pushing:[%s] %@", local_remote, circleToPush);
+        secnotice("signing", "Pushing:[%s] %@", local_remote, circleToPush);
         CFDataRef circle_data = SOSCircleCopyEncodedData(circleToPush, kCFAllocatorDefault, error);
         if (circle_data) {
             success &= SOSTransportCirclePostCircle(transport, SOSCircleGetName(circleToPush), circle_data, error);
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSCircle.c b/Security/sec/SOSCircle/SecureObjectSync/SOSCircle.c
index ff085161..3f167d23 100644
--- a/Security/sec/SOSCircle/SecureObjectSync/SOSCircle.c
+++ b/Security/sec/SOSCircle/SecureObjectSync/SOSCircle.c
@@ -910,6 +910,7 @@ SOSPeerInfoRef SOSCircleCopyPeerWithID(SOSCircleRef circle, CFStringRef peerid,
 }
 
 bool SOSCircleHasPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, CFErrorRef *error) {
+    if(!peerInfo) return false;
     return SOSCircleHasPeerWithID(circle, SOSPeerInfoGetPeerID(peerInfo), error);
 }
 
@@ -980,11 +981,10 @@ bool SOSCircleRemoveRetired(SOSCircleRef circle, CFErrorRef *error) {
     return true;
 }
 
-static bool SOSCircleRecordAdmissionRequest(SOSCircleRef circle, SecKeyRef user_pubkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
+static bool SOSCircleRecordAdmissionRequest(SOSCircleRef circle, SecKeyRef user_pubkey, SOSPeerInfoRef requestorPeerInfo, CFErrorRef *error) {
     SOSCircleAssertStable(circle);
     
-    SOSPeerInfoRef requestorPeerInfo = SOSFullPeerInfoGetPeerInfo(requestor);
-    bool isPeer = SOSCircleHasPeer(circle, SOSFullPeerInfoGetPeerInfo(requestor), error);
+    bool isPeer = SOSCircleHasPeer(circle, requestorPeerInfo, error);
     
     require_action_quiet(!isPeer, fail, SOSCreateError(kSOSErrorAlreadyPeer, CFSTR("Cannot request admission when already a peer"), NULL, error));
     
@@ -998,12 +998,11 @@ fail:
     
 }
 
-bool SOSCircleRequestReadmission(SOSCircleRef circle, SecKeyRef user_pubkey, SOSFullPeerInfoRef requestor, CFErrorRef *error) {
+bool SOSCircleRequestReadmission(SOSCircleRef circle, SecKeyRef user_pubkey, SOSPeerInfoRef peer, CFErrorRef *error) {
     bool success = false;
     
-    SOSPeerInfoRef peer = SOSFullPeerInfoGetPeerInfo(requestor);
     require_quiet(SOSPeerInfoApplicationVerify(peer, user_pubkey, error), fail);
-    success = SOSCircleRecordAdmissionRequest(circle, user_pubkey, requestor, error);
+    success = SOSCircleRecordAdmissionRequest(circle, user_pubkey, peer, error);
 fail:
     return success;
 }
@@ -1016,7 +1015,7 @@ bool SOSCircleRequestAdmission(SOSCircleRef circle, SecKeyRef user_privkey, SOSF
 
     require(SOSFullPeerInfoPromoteToApplication(requestor, user_privkey, error), fail);
     
-    success = SOSCircleRecordAdmissionRequest(circle, user_pubkey, requestor, error);
+    success = SOSCircleRecordAdmissionRequest(circle, user_pubkey, SOSFullPeerInfoGetPeerInfo(requestor), error);
 fail:
     CFReleaseNull(user_pubkey);
     return success;
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSCircle.h b/Security/sec/SOSCircle/SecureObjectSync/SOSCircle.h
index 84fc7b72..c20a6242 100644
--- a/Security/sec/SOSCircle/SecureObjectSync/SOSCircle.h
+++ b/Security/sec/SOSCircle/SecureObjectSync/SOSCircle.h
@@ -104,7 +104,7 @@ bool SOSCircleHasActiveValidPeer(SOSCircleRef circle, SOSPeerInfoRef peerInfo, S
 bool SOSCircleResetToOffering(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error);
 bool SOSCircleResetToEmpty(SOSCircleRef circle, CFErrorRef *error);
 bool SOSCircleRequestAdmission(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef requestor, CFErrorRef *error);
-bool SOSCircleRequestReadmission(SOSCircleRef circle, SecKeyRef user_pubkey, SOSFullPeerInfoRef requestor, CFErrorRef *error);
+bool SOSCircleRequestReadmission(SOSCircleRef circle, SecKeyRef user_pubkey, SOSPeerInfoRef requestor, CFErrorRef *error);
 
 bool SOSCircleAcceptRequest(SOSCircleRef circle, SecKeyRef user_privkey, SOSFullPeerInfoRef device_approver, SOSPeerInfoRef peerInfo, CFErrorRef *error);
 bool SOSCircleRejectRequest(SOSCircleRef circle, SOSFullPeerInfoRef device_approver, SOSPeerInfoRef peerInfo, CFErrorRef *error);
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSEngine.c b/Security/sec/SOSCircle/SecureObjectSync/SOSEngine.c
index 3ae44455..a033cad8 100644
--- a/Security/sec/SOSCircle/SecureObjectSync/SOSEngine.c
+++ b/Security/sec/SOSCircle/SecureObjectSync/SOSEngine.c
@@ -352,18 +352,14 @@ static void SOSEngineSetTrustedPeers(SOSEngineRef engine, CFStringRef myPeerID,
                     CFReleaseSafe(mfadd);
                 };
 
-                if (source == kSOSDataSourceSOSTransaction) {
-                    processUpdates();
-                } else {
-                    // WARNING: This will deadlock the engine if you call a
-                    // SecItem API function while holding the engine lock!
-                    // However making this async right now isn't safe yet either
-                    // Due to some code in the enginer using Get v/s copy to
-                    // access some of the values that would be modified
-                    // asynchronously here since the engine is coded as if
-                    // running on a serial queue.
-                    dispatch_sync(engine->queue, processUpdates);
-                }
+                // WARNING: This will deadlock the engine if you call a
+                // SecItem API function while holding the engine lock!
+                // However making this async right now isn't safe yet either
+                // Due to some code in the enginer using Get v/s copy to
+                // access some of the values that would be modified
+                // asynchronously here since the engine is coded as if
+                // running on a serial queue.
+                dispatch_sync(engine->queue, processUpdates);
             });
         } else {
             SOSDataSourceSetNotifyPhaseBlock(engine->dataSource, ^(SOSDataSourceRef ds, SOSTransactionRef txn, SOSDataSourceTransactionPhase phase, SOSDataSourceTransactionSource source, struct SOSDigestVector *removals, struct SOSDigestVector *additions) {
@@ -907,8 +903,10 @@ bool SOSEngineHandleMessage(SOSEngineRef engine, CFStringRef peerID,
     __block bool somethingChanged = false;
     SOSMessageRef message = SOSMessageCreateWithData(kCFAllocatorDefault, raw_message, error);
     result = message && SOSDataSourceWith(engine->dataSource, error, ^(SOSTransactionRef txn, bool *commit) {
-        result = SOSEngineHandleMessage_locked(engine, peerID, message, txn, commit, &somethingChanged, error);
+        dispatch_sync(engine->queue, ^{
+            result = SOSEngineHandleMessage_locked(engine, peerID, message, txn, commit, &somethingChanged, error);
         });
+    });
     CFReleaseSafe(message);
     if (somethingChanged)
         SecKeychainChanged(false);
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c b/Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c
index a293c10f..a59314c8 100644
--- a/Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c
+++ b/Security/sec/SOSCircle/SecureObjectSync/SOSFullPeerInfo.c
@@ -139,7 +139,6 @@ exit:
 SOSFullPeerInfoRef SOSFullPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErrorRef* error,
                                         const uint8_t** der_p, const uint8_t *der_end) {
     SOSFullPeerInfoRef fpi = CFTypeAllocate(SOSFullPeerInfo, struct __OpaqueSOSFullPeerInfo, allocator);
-    SecKeyRef device_key = NULL;
     
     const uint8_t *sequence_end;
     
@@ -149,18 +148,12 @@ SOSFullPeerInfoRef SOSFullPeerInfoCreateFromDER(CFAllocatorRef allocator, CFErro
     require_quiet(fpi->peer_info != NULL, fail);
 
     *der_p = der_decode_data(allocator, kCFPropertyListImmutable, &fpi->key_ref, error, *der_p, sequence_end);
-    
-    OSStatus result = SecKeyFindWithPersistentRef(fpi->key_ref, &device_key);
-
-    require_quiet(result == errSecSuccess, fail);
     require_quiet(*der_p != NULL, fail);
     
-    CFReleaseNull(device_key);
     return fpi;
 
 fail:
     CFReleaseNull(fpi);
-    CFReleaseNull(device_key);
     return NULL;
 }
 
@@ -236,7 +229,11 @@ fail:
 
 
 bool SOSFullPeerInfoValidate(SOSFullPeerInfoRef peer, CFErrorRef* error) {
-    return true;
+    SecKeyRef device_key = NULL;
+    OSStatus result = SecKeyFindWithPersistentRef(peer->key_ref, &device_key);
+    CFReleaseNull(device_key);
+    if(result == errSecSuccess) return true;
+    return false;
 }
 
 bool SOSFullPeerInfoPurgePersistentKey(SOSFullPeerInfoRef fullPeer, CFErrorRef* error) {
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSTransport.c b/Security/sec/SOSCircle/SecureObjectSync/SOSTransport.c
index 478a22a4..723d4b75 100644
--- a/Security/sec/SOSCircle/SecureObjectSync/SOSTransport.c
+++ b/Security/sec/SOSCircle/SecureObjectSync/SOSTransport.c
@@ -228,6 +228,7 @@ CFMutableArrayRef SOSTransportDispatchMessages(SOSAccountRef account, CFDictiona
     CFMutableArrayRef handledKeys = CFArrayCreateMutableForCFTypes(kCFAllocatorDefault);
     
     if(CFDictionaryContainsKey(updates, kSOSKVSAccountChangedKey)){
+        secnotice("accountChange", "SOSTransportDispatchMessages received kSOSKVSAccountChangedKey");
         // While changing accounts we may modify the key params array. To avoid stepping on ourselves we
         // copy the list for iteration.
         CFArrayRef originalKeyParams = CFArrayCreateCopy(kCFAllocatorDefault, SOSGetTransportKeyParameters());
diff --git a/Security/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c b/Security/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c
index 2130e61e..0fcb2f05 100644
--- a/Security/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c
+++ b/Security/sec/SOSCircle/SecureObjectSync/SOSTransportMessage.c
@@ -37,7 +37,7 @@ static void SOSTransportMessageDestroy(CFTypeRef aObj){
     if (transport->destroy)
         transport->destroy(transport);
     
-    CFReleaseSafe(transport->engine);
+    CFReleaseSafe(transport->account);
 }
 
 SOSAccountRef SOSTransportMessageGetAccount(SOSTransportMessageRef transport){
diff --git a/Security/sec/ipc/server.c b/Security/sec/ipc/server.c
index 4a26d2d7..0ea6e155 100644
--- a/Security/sec/ipc/server.c
+++ b/Security/sec/ipc/server.c
@@ -65,6 +65,10 @@
 #include <xpc/private.h>
 #include <xpc/xpc.h>
 
+#if TARGET_OS_MAC
+#include <Security/SecTaskPriv.h>
+#endif
+
 static CFStringRef SecTaskCopyStringForEntitlement(SecTaskRef task,
     CFStringRef entitlement)
 {
@@ -122,6 +126,12 @@ static CFArrayRef SecTaskCopyAccessGroups(SecTaskRef task) {
     CFStringRef appID = SecTaskCopyApplicationIdentifier(task);
     CFIndex kagLen = keychainAccessGroups ? CFArrayGetCount(keychainAccessGroups) : 0;
     CFIndex asagLen = appleSecurityApplicationGroups ? CFArrayGetCount(appleSecurityApplicationGroups) : 0;
+#if TARGET_OS_MAC
+    if ((appID || asagLen) && !SecTaskEntitlementsValidated(task)) {
+        CFReleaseNull(appID);
+        asagLen = 0;
+    }
+#endif
     CFIndex len = kagLen + asagLen + (appID ? 1 : 0);
     if (len) {
         groups = CFArrayCreateMutable(kCFAllocatorDefault, len, &kCFTypeArrayCallBacks);
diff --git a/Security/sec/securityd/Regressions/secd-55-account-circle.c b/Security/sec/securityd/Regressions/secd-55-account-circle.c
index 39b31e84..af74e6fd 100644
--- a/Security/sec/securityd/Regressions/secd-55-account-circle.c
+++ b/Security/sec/securityd/Regressions/secd-55-account-circle.c
@@ -49,7 +49,7 @@
 
 #include "SOSAccountTesting.h"
 
-static int kTestTestCount = 304;
+static int kTestTestCount = 298;
 
 static void tests(void)
 {
diff --git a/Security/sec/securityd/Regressions/secd-59-account-cleanup.c b/Security/sec/securityd/Regressions/secd-59-account-cleanup.c
index 43f2d394..bb01b0c8 100644
--- a/Security/sec/securityd/Regressions/secd-59-account-cleanup.c
+++ b/Security/sec/securityd/Regressions/secd-59-account-cleanup.c
@@ -102,7 +102,7 @@ static void tests(void)
     ok(peers && CFArrayGetCount(peers) == 2, "See two peers %@ (%@)", peers, error);
     CFReleaseNull(peers);
     
-    SOSFullPeerInfoRef fpiAlice = SOSAccountGetMyFullPeerInCircleNamed(alice_account, circle_name, NULL);
+    SOSFullPeerInfoRef fpiAlice = SOSAccountGetMyFullPeerInCircleNamedIfPresent(alice_account, circle_name, NULL);
     CFStringRef alice_id = CFStringCreateCopy(NULL, SOSPeerInfoGetPeerID(SOSFullPeerInfoGetPeerInfo(fpiAlice)));
     
     ok(SOSAccountLeaveCircles(alice_account, &error), "Alice Leaves (%@)", error);
diff --git a/Security/sec/securityd/SOSCloudCircleServer.c b/Security/sec/securityd/SOSCloudCircleServer.c
index 8aa8d45f..a68bb0ed 100644
--- a/Security/sec/securityd/SOSCloudCircleServer.c
+++ b/Security/sec/securityd/SOSCloudCircleServer.c
@@ -292,6 +292,11 @@ static void SOSKeychainAccountEnsureSaved(SOSAccountRef account)
     static CFDataRef sLastSavedAccountData = NULL;
 
     CFErrorRef saveError = NULL;
+    
+    if(SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, CFSTR("ak"), NULL) == NULL) {
+        return;
+    }
+    
 	SOSCCCircleIsOn_UpdateArtifact(SOSAccountIsInCircles(account, NULL));
 
     CFDataRef accountAsData = SOSAccountCopyEncodedData(account, kCFAllocatorDefault, &saveError);
@@ -353,11 +358,22 @@ static SOSAccountRef SOSKeychainAccountCreateSharedAccount(CFDictionaryRef our_g
 
         account = SOSAccountCreateFromData(kCFAllocatorDefault, savedAccount, factory, &inflationError);
 
+        if(account && SOSAccountGetMyFullPeerInCircleNamedIfPresent(account, CFSTR("ak"), NULL) == NULL) {
+            SOSAccountRef newAccount = SOSAccountCreate(kCFAllocatorDefault, our_gestalt, factory);
+            
+            if (!newAccount) {
+                secnotice("repair_account", "Tried to repair bad account - got null account");
+            } else {
+                account = newAccount;
+            }
+        }
+
         if (account){
             SOSAccountUpdateGestalt(account, our_gestalt);
-        }
-        else
+        } else {
             secerror("Got error inflating account: %@", inflationError);
+        }
+        
         CFReleaseNull(inflationError);
     }
     CFReleaseSafe(savedAccount);
diff --git a/Security/sec/securityd/SecOTRRemote.c b/Security/sec/securityd/SecOTRRemote.c
index d1ec5dcb..20616cb0 100644
--- a/Security/sec/securityd/SecOTRRemote.c
+++ b/Security/sec/securityd/SecOTRRemote.c
@@ -49,6 +49,10 @@ CFDataRef SecOTRSessionCreateRemote_internal(CFDataRef publicAccountData, CFData
     });
     
     SecKeyRef privateKeyRef = SOSFullPeerInfoCopyDeviceKey(full_peer_info, error);
+    if(!privateKeyRef) {
+        secnotice("otr_keysetup", "Could not get private key for FullPeerInfo");
+        return NULL;
+    }
     
     CFStringRef publicKeyString = CFStringCreateFromExternalRepresentation(kCFAllocatorDefault, publicPeerId, kCFStringEncodingUTF8);
     __block SOSPeerInfoRef peer_info = NULL;
diff --git a/Security/utilities/src/debugging.c b/Security/utilities/src/debugging.c
index 2d421599..68ab7122 100644
--- a/Security/utilities/src/debugging.c
+++ b/Security/utilities/src/debugging.c
@@ -379,6 +379,18 @@ static void setup_environment_scopes() {
     ApplyScopeListForIDC(cur_scope, kScopeIDEnvironment);
 }
 
+#define XPCSCOPESTRWANT "api,account,accountChange,circle,circleChange,circleCreat,flush,fresh,keygen,signing,talkwithkvs"
+#define XPCSCOPESTRDONTWANT "-event,http,item,keytrace,lockassertions,otr_keysetup,securityd,server,serverxpc,session,sync,titc,transport,trust,updates,xpc"
+static void setup_xpcdefault_scopes() {
+    
+    CFDictionaryRef noticeLogging = CFDictionaryCreateForCFTypes(kCFAllocatorDefault,
+                        CFSTR(ASL_STRING_NOTICE), CFSTR(XPCSCOPESTRDONTWANT), NULL);
+    
+    ApplyScopeDictionaryForID(noticeLogging, kScopeIDXPC);
+    
+    CFReleaseNull(noticeLogging);
+}
+
 void __security_debug_init(void) {
     static dispatch_once_t sdOnceToken;
 
@@ -386,10 +398,10 @@ void __security_debug_init(void) {
         setup_environment_scopes();
         setup_config_settings();
         setup_defaults_settings();
+        //setup_xpcdefault_scopes();
     });
 }
 
-
 // MARK: Log handler recording (e.g. grabbing security logging and sending it to test results).
 static void clean_aslclient(void *client)
 {
diff --git a/SharedWebCredentialViewService/SWCViewController.m b/SharedWebCredentialViewService/SWCViewController.m
index 87c85b42..208270eb 100755
--- a/SharedWebCredentialViewService/SWCViewController.m
+++ b/SharedWebCredentialViewService/SWCViewController.m
@@ -88,7 +88,7 @@ const NSString* SWC_SERVER_KEY   = @"srvr";
         
         self.textLabel.textColor = [UIColor blackColor];
         self.textLabel.textAlignment = NSTextAlignmentLeft;
-        self.textLabel.AdjustsFontSizeToFitWidth = YES;
+        self.textLabel.adjustsFontSizeToFitWidth = YES;
         self.textLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
         
         NSString *title = [dict objectForKey:SWC_ACCOUNT_KEY];
@@ -96,7 +96,7 @@ const NSString* SWC_SERVER_KEY   = @"srvr";
         
         self.detailTextLabel.textColor = [UIColor darkGrayColor];
         self.detailTextLabel.textAlignment = NSTextAlignmentLeft;
-        self.detailTextLabel.AdjustsFontSizeToFitWidth = YES;
+        self.detailTextLabel.adjustsFontSizeToFitWidth = YES;
         self.detailTextLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
         
         NSString *subtitle = [dict objectForKey:SWC_SERVER_KEY];