X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/80e2389990082500d76eb566d4946be3e786c3ef..d8f41ccd20de16f8ebe2ccc84d47bf1cb2b26bbb:/libsecurity_apple_x509_tp/lib/TPNetwork.cpp?ds=sidebyside diff --git a/libsecurity_apple_x509_tp/lib/TPNetwork.cpp b/libsecurity_apple_x509_tp/lib/TPNetwork.cpp deleted file mode 100644 index e6895229..00000000 --- a/libsecurity_apple_x509_tp/lib/TPNetwork.cpp +++ /dev/null @@ -1,511 +0,0 @@ -/* - * Copyright (c) 2002-2011 Apple Inc. All Rights Reserved. - * - * The contents of this file constitute Original Code as defined in and are - * subject to the Apple Public Source License Version 1.2 (the 'License'). - * You may not use this file except in compliance with the License. Please obtain - * a copy of the License at http://www.apple.com/publicsource and read it before - * using this file. - * - * This Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS - * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT - * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the - * specific language governing rights and limitations under the License. - */ - - -/* - * TPNetwork.h - LDAP, HTTP and (eventually) other network tools - */ - -#include "TPNetwork.h" -#include "tpdebugging.h" -#include "tpTime.h" -#include "cuEnc64.h" -#include -#include -#include -#include -#include - -#define CA_ISSUERS_OID OID_PKIX, 0x30, 0x02 -#define CA_ISSUERS_OID_LEN OID_PKIX_LENGTH + 2 - -static const uint8 OID_CA_ISSUERS[] = {CA_ISSUERS_OID}; -const CSSM_OID CSSMOID_CA_ISSUERS = {CA_ISSUERS_OID_LEN, (uint8 *)OID_CA_ISSUERS}; - -typedef enum { - LT_Crl = 1, - LT_Cert -} LF_Type; - -static CSSM_RETURN tpDecodeCert( - Allocator &alloc, - CSSM_DATA &rtnBlob) // will be reallocated if needed -{ - const unsigned char *inbuf = (const unsigned char *)rtnBlob.Data; - unsigned inlen = (unsigned)rtnBlob.Length; - unsigned char *outbuf = NULL; - unsigned outlen = 0; - CSSM_RETURN ortn = cuConvertPem(inbuf, inlen, &outbuf, &outlen); - - if(ortn == 0 && outbuf != NULL) { - /* Decoded result needs to be malloc'd via input allocator */ - unsigned char *rtnP = (unsigned char *) alloc.malloc(outlen); - if(rtnP != NULL) { - memcpy(rtnP, outbuf, outlen); - rtnBlob.Data = rtnP; - rtnBlob.Length = outlen; - } - free(outbuf); - alloc.free((void *)inbuf); - } - return ortn; -} - -static CSSM_RETURN tpFetchViaNet( - const CSSM_DATA &url, - const CSSM_DATA *issuer, // optional - LF_Type lfType, - CSSM_TIMESTRING verifyTime, // CRL only - Allocator &alloc, - CSSM_DATA &rtnBlob) // mallocd and RETURNED -{ - if(lfType == LT_Crl) { - return ocspdCRLFetch(alloc, url, issuer, - true, true, // cache r/w both enable - verifyTime, rtnBlob); - } - else { - CSSM_RETURN result = ocspdCertFetch(alloc, url, rtnBlob); - if(result == CSSM_OK) { - /* The data might be in PEM format; if so, convert it here */ - (void)tpDecodeCert(alloc, rtnBlob); - } - return result; - } -} - -static CSSM_RETURN tpCrlViaNet( - const CSSM_DATA &url, - const CSSM_DATA *issuer, // optional, only if cert and CRL have same issuer - TPVerifyContext &vfyCtx, - TPCertInfo &forCert, // for verifyWithContext - TPCrlInfo *&rtnCrl) -{ - TPCrlInfo *crl = NULL; - CSSM_DATA crlData; - CSSM_RETURN crtn; - Allocator &alloc = Allocator::standard(); - char cssmTime[CSSM_TIME_STRLEN+1]; - - rtnCrl = NULL; - - /* verifyTime: we want a CRL that's valid right now. */ - { - StLock _(tpTimeLock()); - timeAtNowPlus(0, TIME_CSSM, cssmTime); - } - - crtn = tpFetchViaNet(url, issuer, LT_Crl, cssmTime, alloc, crlData); - if(crtn) { - return crtn; - } - try { - crl = new TPCrlInfo(vfyCtx.clHand, - vfyCtx.cspHand, - &crlData, - TIC_CopyData, - NULL); // verifyTime = Now - } - catch(...) { - alloc.free(crlData.Data); - - /* - * There is a slight possibility of recovering from this error. In case - * the CRL came from disk cache, flush the cache and try to get the CRL - * from the net. - */ - tpDebug(" bad CRL; flushing from cache and retrying"); - ocspdCRLFlush(url); - crtn = tpFetchViaNet(url, issuer, LT_Crl, cssmTime, alloc, crlData); - if(crtn == CSSM_OK) { - try { - crl = new TPCrlInfo(vfyCtx.clHand, - vfyCtx.cspHand, - &crlData, - TIC_CopyData, - NULL); - tpDebug(" RECOVERY: good CRL obtained from net"); - } - catch(...) { - alloc.free(crlData.Data); - tpDebug(" bad CRL; recovery FAILED (1)"); - return CSSMERR_APPLETP_CRL_NOT_FOUND; - } - } - else { - /* it was in cache but we can't find it on the net */ - tpDebug(" bad CRL; recovery FAILED (2)"); - return CSSMERR_APPLETP_CRL_NOT_FOUND; - } - } - alloc.free(crlData.Data); - - /* - * Full CRL verify. - * The verify time in the TPVerifyContext is the time at which various - * entities (CRL and its own cert chain) are to be verified; that's - * NULL for "right now". The current vfyCtx.verifyTime is the time at - * which the cert's revocation status to be determined; this call to - * verifyWithContextNow() doesn't do that. - */ - crtn = crl->verifyWithContextNow(vfyCtx, &forCert); - if(crtn == CSSM_OK) { - crl->uri(url); - } - else { - delete crl; - crl = NULL; - } - rtnCrl = crl; - return crtn; -} - -static CSSM_RETURN tpIssuerCertViaNet( - const CSSM_DATA &url, - CSSM_CL_HANDLE clHand, - CSSM_CSP_HANDLE cspHand, - const char *verifyTime, - TPCertInfo &subject, - TPCertInfo *&rtnCert) -{ - TPCertInfo *issuer = NULL; - CSSM_DATA certData; - CSSM_RETURN crtn; - Allocator &alloc = Allocator::standard(); - - crtn = tpFetchViaNet(url, NULL, LT_Cert, NULL, alloc, certData); - if(crtn) { - tpErrorLog("tpIssuerCertViaNet: net fetch failed\n"); - return CSSMERR_APPLETP_CERT_NOT_FOUND_FROM_ISSUER; - } - try { - issuer = new TPCertInfo(clHand, - cspHand, - &certData, - TIC_CopyData, - verifyTime); - } - catch(...) { - tpErrorLog("tpIssuerCertViaNet: bad cert via net fetch\n"); - alloc.free(certData.Data); - rtnCert = NULL; - return CSSMERR_APPLETP_BAD_CERT_FROM_ISSUER; - } - alloc.free(certData.Data); - - /* subject/issuer match? */ - if(!issuer->isIssuerOf(subject)) { - tpErrorLog("tpIssuerCertViaNet: wrong issuer cert via net fetch\n"); - crtn = CSSMERR_APPLETP_BAD_CERT_FROM_ISSUER; - } - else { - /* yep, do a sig verify */ - crtn = subject.verifyWithIssuer(issuer); - if(crtn) { - tpErrorLog("tpIssuerCertViaNet: sig verify fail for cert via net " - "fetch\n"); - crtn = CSSMERR_APPLETP_BAD_CERT_FROM_ISSUER; - } - } - if(crtn) { - assert(issuer != NULL); - delete issuer; - issuer = NULL; - } - rtnCert = issuer; - return crtn; -} - -/* - * Fetch a CRL or a cert via a GeneralNames. - * Shared by cert and CRL code to avoid duplicating GeneralNames traversal - * code, despite the awkward interface for this function. - */ -static CSSM_RETURN tpFetchViaGeneralNames( - const CE_GeneralNames *names, - TPCertInfo &forCert, - const CSSM_DATA *issuer, // optional, and only for CRLs - TPVerifyContext *verifyContext, // only for CRLs - CSSM_CL_HANDLE clHand, // only for certs - CSSM_CSP_HANDLE cspHand, // only for certs - const char *verifyTime, // optional - /* exactly one must be non-NULL, that one is returned */ - TPCertInfo **certInfo, - TPCrlInfo **crlInfo) -{ - assert(certInfo || crlInfo); - assert(!certInfo || !crlInfo); - CSSM_RETURN crtn; - - for(unsigned nameDex=0; nameDexnumNames; nameDex++) { - CE_GeneralName *name = &names->generalName[nameDex]; - switch(name->nameType) { - case GNT_URI: - if(name->name.Length < 5) { - continue; - } - if(strncmp((char *)name->name.Data, "ldap:", 5) && - strncmp((char *)name->name.Data, "http:", 5) && - strncmp((char *)name->name.Data, "https:", 6)) { - /* eventually handle other schemes here */ - continue; - } - if(certInfo) { - tpDebug(" fetching cert via net"); - crtn = tpIssuerCertViaNet(name->name, - clHand, - cspHand, - verifyTime, - forCert, - *certInfo); - } - else { - tpDebug(" fetching CRL via net"); - assert(verifyContext != NULL); - crtn = tpCrlViaNet(name->name, - issuer, - *verifyContext, - forCert, - *crlInfo); - } - switch(crtn) { - case CSSM_OK: - case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE: // caller handles - return crtn; - default: - break; - } - /* not found/no good; try again */ - break; - default: - tpCrlDebug(" tpFetchCrlFromNet: unknown" - "nameType (%u)", (unsigned)name->nameType); - break; - } /* switch nameType */ - } /* for each name */ - if(certInfo) { - return CSSMERR_TP_CERTGROUP_INCOMPLETE; - } - else { - return CSSMERR_APPLETP_CRL_NOT_FOUND; - } -} - -/* - * Fetch CRL(s) from specified cert if the cert has a cRlDistributionPoint - * extension. - * - * Return values: - * CSSM_OK - found and returned fully verified CRL - * CSSMERR_APPLETP_CRL_NOT_FOUND - no CRL in cRlDistributionPoint - * Anything else - gross error, typically from last LDAP/HTTP attempt - * - * FIXME - this whole mechanism sort of falls apart if verifyContext.verifyTime - * is non-NULL. How are we supposed to get the CRL which was valid at - * a specified time in the past? - */ -CSSM_RETURN tpFetchCrlFromNet( - TPCertInfo &cert, - TPVerifyContext &vfyCtx, - TPCrlInfo *&crl) // RETURNED -{ - /* does the cert have a cRlDistributionPoint? */ - CSSM_DATA_PTR fieldValue; // mallocd by CL - - CSSM_RETURN crtn = cert.fetchField(&CSSMOID_CrlDistributionPoints, - &fieldValue); - switch(crtn) { - case CSSM_OK: - break; - case CSSMERR_CL_NO_FIELD_VALUES: - /* field not present */ - return CSSMERR_APPLETP_CRL_NOT_FOUND; - default: - /* gross error */ - return crtn; - } - if(fieldValue->Length != sizeof(CSSM_X509_EXTENSION)) { - tpErrorLog("tpFetchCrlFromNet: malformed CSSM_FIELD"); - return CSSMERR_TP_UNKNOWN_FORMAT; - } - CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)fieldValue->Data; - CE_CRLDistPointsSyntax *dps = - (CE_CRLDistPointsSyntax *)cssmExt->value.parsedValue; - TPCrlInfo *rtnCrl = NULL; - - /* default return if we don't find anything */ - crtn = CSSMERR_APPLETP_CRL_NOT_FOUND; - for(unsigned dex=0; dexnumDistPoints; dex++) { - CE_CRLDistributionPoint *dp = &dps->distPoints[dex]; - if(dp->distPointName == NULL) { - continue; - } - /* - * FIXME if this uses an indirect CRL, we need to follow the - * crlIssuer field... TBD. - */ - switch(dp->distPointName->nameType) { - case CE_CDNT_NameRelativeToCrlIssuer: - /* not yet */ - tpErrorLog("tpFetchCrlFromNet: " - "CE_CDNT_NameRelativeToCrlIssuer not implemented\n"); - break; - - case CE_CDNT_FullName: - { - /* - * Since we don't support indirect CRLs (yet), we always pass - * the cert-to-be-verified's issuer as the CRL issuer for - * cache lookup. - */ - CE_GeneralNames *names = dp->distPointName->dpn.fullName; - crtn = tpFetchViaGeneralNames(names, - cert, - cert.issuerName(), - &vfyCtx, - 0, // clHand, use the one in vfyCtx - 0, // cspHand, ditto - vfyCtx.verifyTime, - NULL, - &rtnCrl); - break; - } /* CE_CDNT_FullName */ - - default: - /* not yet */ - tpErrorLog("tpFetchCrlFromNet: " - "unknown distPointName->nameType (%u)\n", - (unsigned)dp->distPointName->nameType); - break; - } /* switch distPointName->nameType */ - if(crtn == CSSM_OK) { - /* i.e., tpFetchViaGeneralNames SUCCEEDED */ - break; - } - } /* for each distPoints */ - - cert.freeField(&CSSMOID_CrlDistributionPoints, fieldValue); - if(crtn == CSSM_OK) { - assert(rtnCrl != NULL); - crl = rtnCrl; - } - return crtn; -} - -/* - * Fetch issuer cert of specified cert if the cert has an issuerAltName - * with a URI. If non-NULL cert is returned, it has passed subject/issuer - * name comparison and signature verification with target cert. - * - * Return values: - * CSSM_OK - found and returned issuer cert - * CSSMERR_TP_CERTGROUP_INCOMPLETE - no URL in issuerAltName - * CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE - found and returned issuer - * cert, but signature verification needs subsequent retry. - * Anything else - gross error, typically from last LDAP/HTTP attempt - */ -CSSM_RETURN tpFetchIssuerFromNet( - TPCertInfo &subject, - CSSM_CL_HANDLE clHand, - CSSM_CSP_HANDLE cspHand, - const char *verifyTime, - TPCertInfo *&issuer) // RETURNED -{ - CSSM_OID_PTR fieldOid = NULL; - CSSM_DATA_PTR fieldValue = NULL; // mallocd by CL - CSSM_RETURN crtn; - bool hasAIA = false; - - /* look for the Authority Info Access extension first */ - fieldOid = (CSSM_OID_PTR)&CSSMOID_AuthorityInfoAccess; - crtn = subject.fetchField(fieldOid, - &fieldValue); - hasAIA = (crtn == CSSM_OK); - if (!hasAIA) { - /* fall back to Issuer Alternative Name extension */ - fieldOid = (CSSM_OID_PTR)&CSSMOID_IssuerAltName; - crtn = subject.fetchField(fieldOid, - &fieldValue); - } - switch(crtn) { - case CSSM_OK: - break; - case CSSMERR_CL_NO_FIELD_VALUES: - /* field not present */ - return CSSMERR_TP_CERTGROUP_INCOMPLETE; - default: - /* gross error */ - return crtn; - } - if(fieldValue->Length != sizeof(CSSM_X509_EXTENSION)) { - tpPolicyError("tpFetchIssuerFromNet: malformed CSSM_FIELD"); - return CSSMERR_TP_UNKNOWN_FORMAT; - } - CSSM_X509_EXTENSION *cssmExt = (CSSM_X509_EXTENSION *)fieldValue->Data; - CE_GeneralNames *names = (CE_GeneralNames *)cssmExt->value.parsedValue; - TPCertInfo *rtnCert = NULL; - if (hasAIA) { /* authority info access */ - CE_AuthorityInfoAccess *access = (CE_AuthorityInfoAccess *)cssmExt->value.parsedValue; - for (uint32 index = 0; access && index < access->numAccessDescriptions; index++) { - CE_AccessDescription *accessDesc = &access->accessDescriptions[index]; - CSSM_OID_PTR methodOid = (CSSM_OID_PTR)&accessDesc->accessMethod; - /* look for the CA Issuers method */ - if(methodOid->Data != NULL && methodOid->Length == CSSMOID_CA_ISSUERS.Length && - !memcmp(methodOid->Data, CSSMOID_CA_ISSUERS.Data, methodOid->Length)) { - CE_GeneralNames aiaNames = { 1, &accessDesc->accessLocation }; - /* attempt to fetch cert from named location */ - crtn = tpFetchViaGeneralNames(&aiaNames, - subject, - NULL, // issuer - not used - NULL, // verifyContext - clHand, - cspHand, - verifyTime, - &rtnCert, - NULL); - if (crtn == CSSM_OK || - crtn == CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE) { - break; // got one - } - } - } - subject.freeField(fieldOid, fieldValue); - } - else { /* issuer alt name */ - crtn = tpFetchViaGeneralNames(names, - subject, - NULL, // issuer - not used - NULL, // verifyContext - clHand, - cspHand, - verifyTime, - &rtnCert, - NULL); - subject.freeField(fieldOid, fieldValue); - } - switch(crtn) { - case CSSM_OK: - case CSSMERR_CSP_APPLE_PUBLIC_KEY_INCOMPLETE: - issuer = rtnCert; - break; - default: - break; - } - return crtn; -} - -