From 949d2ff02a32bac712f7993d03d527b4925ff882 Mon Sep 17 00:00:00 2001 From: Apple Date: Wed, 10 Jun 2015 05:58:05 +0000 Subject: [PATCH] Security-57031.10.10.tar.gz --- .../xcshareddata/xcschemes/secdtests.xcscheme | 4 + Security/lib/security.exp-in | 6 + .../lib/certGroupUtils.cpp | 2 +- .../lib/ocspRequest.cpp | 40 ++-- .../lib/ocspRequest.h | 32 +-- .../lib/tpOcspCertVfy.cpp | 197 ++++++++++------ .../lib/tpOcspVerify.cpp | 220 +++++++++--------- .../libsecurity_codesigning/lib/SecTask.c | 8 + .../libsecurity_codesigning/lib/SecTaskPriv.h | 10 +- .../lib/StaticCode.cpp | 7 +- .../libsecurity_codesigning/lib/StaticCode.h | 2 + .../lib/security_codesigning.exp | 1 + .../project.pbxproj | 10 +- .../libsecurity_keychain/lib/Certificate.cpp | 136 +++++++++-- .../libsecurity_keychain/lib/Certificate.h | 2 + .../libsecurity_ocspd/common/ocspResponse.cpp | 105 ++++----- .../libsecurity_ocspd/common/ocspResponse.h | 106 ++++----- .../libsecurity_ocspd/common/ocspdUtils.cpp | 139 ++++++++--- .../libsecurity_ocspd/common/ocspdUtils.h | 30 ++- .../CloudKeychainProxy/CKDKVSProxy.m | 2 +- .../SOSCircle/SecureObjectSync/SOSAccount.c | 9 +- .../SOSCircle/SecureObjectSync/SOSAccount.h | 2 +- .../SecureObjectSync/SOSAccountCircles.c | 32 +-- .../SecureObjectSync/SOSAccountFullPeerInfo.c | 4 +- .../SecureObjectSync/SOSAccountPeers.c | 4 +- .../SecureObjectSync/SOSAccountPersistence.c | 3 +- .../SecureObjectSync/SOSAccountPriv.h | 4 +- .../SecureObjectSync/SOSAccountUpdate.c | 30 +-- .../SOSCircle/SecureObjectSync/SOSCircle.c | 13 +- .../SOSCircle/SecureObjectSync/SOSCircle.h | 2 +- .../SOSCircle/SecureObjectSync/SOSEngine.c | 24 +- .../SecureObjectSync/SOSFullPeerInfo.c | 13 +- .../SOSCircle/SecureObjectSync/SOSTransport.c | 1 + .../SecureObjectSync/SOSTransportMessage.c | 2 +- Security/sec/ipc/server.c | 10 + .../Regressions/secd-55-account-circle.c | 2 +- .../Regressions/secd-59-account-cleanup.c | 2 +- Security/sec/securityd/SOSCloudCircleServer.c | 20 +- Security/sec/securityd/SecOTRRemote.c | 4 + Security/utilities/src/debugging.c | 14 +- .../SWCViewController.m | 4 +- 41 files changed, 805 insertions(+), 453 deletions(-) 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"> + + 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 #include +#ifndef NDEBUG +#include +#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; dexnumPurposes; 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(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(); @@ -261,7 +263,7 @@ static SecAsn1OCSPDRequest *tpGenOcspdReq( if(!(optFlags & CSSM_TP_ACTION_OCSP_DISABLE_NET)) { ocspdReq->urls = const_cast(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(numCerts); memset(pending, 0, (numCerts * sizeof(PendingRequest *))); - + for(unsigned dex=0; dextrustSettingsFound()) { /* 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(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; dexcertID, 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(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; dexcertID.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; dexmaxSpecialSlot(); 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 = ""; }; 37DDE33B1947A4F3005CE18B /* dirscanner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = dirscanner.h; sourceTree = ""; }; 37DDE3411947A501005CE18B /* dirscanner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dirscanner.cpp; sourceTree = ""; }; + 48674DE219EC9E610049EB7D /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = "../../../Volumes/Data/Users/murf/Projects/Security/build/Debug-iphoneos/Security.framework"; sourceTree = ""; }; 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 = ""; }; @@ -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 #include #include +#include +#include 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_(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_(mMutex); - CssmDataContainer *data = mData.get(); - if (!data && mKeychain) + CssmDataContainer *data = NULL; + bool hasKeychain = false; + bool verified = false; + { + StLock_(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_(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_(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_(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; dexthisUpdate); 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 +#include #include /* @@ -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 #include +#include #include /* @@ -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 #include +#if TARGET_OS_MAC +#include +#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]; -- 2.45.2