// // Check to see if a certificate contains a particular field, by OID. This works for extensions, // even ones not recognized by the local CL. It does not return any value, only presence. // bool certificateHasField(SecCertificateRef cert, const CSSM_OID &oid) { assert(cert); CSSM_DATA *value; switch (OSStatus rc = SecCertificateCopyFirstFieldValue(cert, &oid, &value)) { case errSecSuccess: MacOSError::check(SecCertificateReleaseFirstFieldValue(cert, &oid, value)); return true; // extension found by oid case errSecUnknownTag: break; // oid not recognized by CL - continue below default: MacOSError::throwMe(rc); // error: fail } // check the CL's bag of unrecognized extensions CSSM_DATA **values; bool found = false; if (SecCertificateCopyFieldValues(cert, &CSSMOID_X509V3CertificateExtensionCStruct, &values)) return false; // no unrecognized extensions - no match if (values) for (CSSM_DATA **p = values; *p; p++) { const CSSM_X509_EXTENSION *ext = (const CSSM_X509_EXTENSION *)(*p)->Data; if (oid == ext->extnId) { found = true; break; } } MacOSError::check(SecCertificateReleaseFieldValues(cert, &CSSMOID_X509V3CertificateExtensionCStruct, values)); return found; }
// Return the decoded value of the subjectKeyID extension. The caller should // free up the storage allocated in retItem->data. SECStatus CERT_FindSubjectKeyIDExtension (SecCertificateRef cert, SECItem *retItem) { CSSM_DATA_PTR fieldValue = NULL; OSStatus ortn; CSSM_X509_EXTENSION *extp; CE_SubjectKeyID *skid; ortn = SecCertificateCopyFirstFieldValue(cert, &CSSMOID_SubjectKeyIdentifier, &fieldValue); if(ortn || (fieldValue == NULL)) { /* this cert doesn't have that extension */ return SECFailure; } extp = (CSSM_X509_EXTENSION *)fieldValue->Data; skid = (CE_SubjectKeyID *)extp->value.parsedValue; retItem->Data = (uint8 *)PORT_Alloc(skid->Length); retItem->Length = skid->Length; memmove(retItem->Data, skid->Data, retItem->Length); SecCertificateReleaseFirstFieldValue(cert, &CSSMOID_SubjectKeyIdentifier, fieldValue); return SECSuccess; }
// // Retrieve X.509 policy extension OIDs, if any. // This currently ignores policy qualifiers. // bool certificateHasPolicy(SecCertificateRef cert, const CSSM_OID &policyOid) { bool matched = false; assert(cert); CSSM_DATA *data; if (OSStatus rc = SecCertificateCopyFirstFieldValue(cert, &CSSMOID_CertificatePolicies, &data)) MacOSError::throwMe(rc); if (data && data->Data && data->Length == sizeof(CSSM_X509_EXTENSION)) { const CSSM_X509_EXTENSION *ext = (const CSSM_X509_EXTENSION *)data->Data; assert(ext->format == CSSM_X509_DATAFORMAT_PARSED); const CE_CertPolicies *policies = (const CE_CertPolicies *)ext->value.parsedValue; if (policies) for (unsigned int n = 0; n < policies->numPolicies; n++) { const CE_PolicyInformation &cp = policies->policies[n]; if (cp.certPolicyId == policyOid) { matched = true; break; } } } SecCertificateReleaseFirstFieldValue(cert, &CSSMOID_PolicyConstraints, data); return matched; }
/* * Determine the basic signing algorithm, without the digest, component, of * a cert. The returned algorithm will be RSA, DSA, or ECDSA. */ static OSStatus sslCertSignerAlg( SecCertificateRef certRef, CSSM_ALGORITHMS *signerAlg) { OSStatus ortn; CSSM_DATA_PTR fieldPtr; CSSM_X509_ALGORITHM_IDENTIFIER *algId; CSSM_ALGORITHMS sigAlg; /* * Extract the full signature algorithm OID */ *signerAlg = CSSM_ALGID_NONE; ortn = SecCertificateCopyFirstFieldValue(certRef, &CSSMOID_X509V1SignatureAlgorithm, &fieldPtr); if(ortn) { return ortn; } if(fieldPtr->Length != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER)) { sslErrorLog("sslCertSignerAlg() length error\n"); ortn = errSSLCrypto; goto errOut; } algId = (CSSM_X509_ALGORITHM_IDENTIFIER *)fieldPtr->Data; if(!cssmOidToAlg(&algId->algorithm, &sigAlg)) { /* Only way this could happen is if we're given a bad cert */ sslErrorLog("sslCertSignerAlg() bad sigAlg OID\n"); ortn = paramErr; goto errOut; } /* * OK we have the full signature algorithm as a CSSM_ALGORITHMS. * Extract the core signature alg. */ switch(sigAlg) { case CSSM_ALGID_RSA: case CSSM_ALGID_MD2WithRSA: case CSSM_ALGID_MD5WithRSA: case CSSM_ALGID_SHA1WithRSA: case CSSM_ALGID_SHA224WithRSA: case CSSM_ALGID_SHA256WithRSA: case CSSM_ALGID_SHA384WithRSA: case CSSM_ALGID_SHA512WithRSA: *signerAlg = CSSM_ALGID_RSA; break; case CSSM_ALGID_SHA1WithECDSA: case CSSM_ALGID_SHA224WithECDSA: case CSSM_ALGID_SHA256WithECDSA: case CSSM_ALGID_SHA384WithECDSA: case CSSM_ALGID_SHA512WithECDSA: case CSSM_ALGID_ECDSA: case CSSM_ALGID_ECDSA_SPECIFIED: *signerAlg = CSSM_ALGID_ECDSA; break; case CSSM_ALGID_DSA: case CSSM_ALGID_SHA1WithDSA: *signerAlg = CSSM_ALGID_DSA; break; default: sslErrorLog("sslCertSignerAlg() unknown sigAlg\n"); ortn = paramErr; break; } errOut: SecCertificateReleaseFirstFieldValue(certRef, &CSSMOID_X509V1SignatureAlgorithm, fieldPtr); return ortn; }
static bool isSoftwareUpdateDevelopment(SecTrustRef trust) { bool isPolicy = false, isEKU = false; CFArrayRef policies = NULL; /* Policy used to evaluate was SWUpdateSigning */ SecTrustCopyPolicies(trust, &policies); if (policies) { SecPolicyRef swUpdatePolicy = SecPolicyCreateAppleSWUpdateSigning(); if (swUpdatePolicy && CFArrayContainsValue(policies, CFRangeMake(0, CFArrayGetCount(policies)), swUpdatePolicy)) { isPolicy = true; } if (swUpdatePolicy) { CFRelease(swUpdatePolicy); } CFRelease(policies); } if (!isPolicy) { return false; } /* Only error was EKU on the leaf */ CFArrayRef details = SecTrustCopyFilteredDetails(trust); CFIndex ix, count = CFArrayGetCount(details); bool hasDisqualifyingError = false; for (ix = 0; ix < count; ix++) { CFDictionaryRef detail = (CFDictionaryRef)CFArrayGetValueAtIndex(details, ix); if (ix == 0) { // Leaf if (CFDictionaryGetCount(detail) != 1 || // One error CFDictionaryGetValue(detail, CFSTR("ExtendedKeyUsage")) != kCFBooleanFalse) { // kSecPolicyCheckExtendedKeyUsage hasDisqualifyingError = true; break; } } else { if (CFDictionaryGetCount(detail) > 0) { // No errors on other certs hasDisqualifyingError = true; break; } } } CFReleaseSafe(details); if (hasDisqualifyingError) { return false; } /* EKU on the leaf is the Apple Development Code Signing OID */ SecCertificateRef leaf = SecTrustGetCertificateAtIndex(trust, 0); CSSM_DATA *fieldValue = NULL; if (errSecSuccess != SecCertificateCopyFirstFieldValue(leaf, &CSSMOID_ExtendedKeyUsage, &fieldValue)) { return false; } if (fieldValue && fieldValue->Data && fieldValue->Length == sizeof(CSSM_X509_EXTENSION)) { const CSSM_X509_EXTENSION *ext = (const CSSM_X509_EXTENSION *)fieldValue->Data; if (ext->format == CSSM_X509_DATAFORMAT_PARSED) { const CE_ExtendedKeyUsage *ekus = (const CE_ExtendedKeyUsage *)ext->value.parsedValue; if (ekus && (ekus->numPurposes == 1) && ekus->purposes[0].Data && (ekus->purposes[0].Length == CSSMOID_APPLE_EKU_CODE_SIGNING_DEV.Length) && (memcmp(ekus->purposes[0].Data, CSSMOID_APPLE_EKU_CODE_SIGNING_DEV.Data, ekus->purposes[0].Length) == 0)) { isEKU = true; } } } SecCertificateReleaseFirstFieldValue(leaf, &CSSMOID_ExtendedKeyUsage, fieldValue); return isEKU; }