]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_smime/lib/cert.c
Security-58286.260.20.tar.gz
[apple/security.git] / OSX / libsecurity_smime / lib / cert.c
index d00935a2362ab0f3e177b4545c1a8f88a522a47f..2f3bc4ae696b71644ec5a946d169cc0c029daf45 100644 (file)
@@ -34,7 +34,7 @@
 #include <Security/SecIdentityPriv.h>
 #include <Security/SecIdentitySearch.h>
 #include <Security/SecCertificatePriv.h>
-#include <Security/SecPolicySearch.h>
+#include <Security/SecPolicyPriv.h>
 #include <Security/oidsalg.h>
 #include <Security/cssmapi.h>
 #include <Security/oidscert.h>
@@ -244,82 +244,64 @@ endNewClass()
 
 CFArrayRef CERT_CertChainFromCert(SecCertificateRef cert, SECCertUsage usage, Boolean includeRoot)
 {
-    SecPolicySearchRef searchRef = NULL;
     SecPolicyRef policy = NULL;
     CFArrayRef wrappedCert = NULL;
     SecTrustRef trust = NULL;
-    CFArrayRef certChain = NULL;
-    CSSM_TP_APPLE_EVIDENCE_INFO *statusChain;
-    CFDataRef actionData = NULL;
+    CFMutableArrayRef certs = NULL;
     OSStatus status = 0;
+    SecTrustResultType trustResult = kSecTrustResultInvalid;
 
     if (!cert)
        goto loser;
 
-    status = SecPolicySearchCreate(CSSM_CERT_X_509v3, &CSSMOID_APPLE_X509_BASIC, NULL, &searchRef);
-    if (status)
-       goto loser;
-    status = SecPolicySearchCopyNext(searchRef, &policy);
-    if (status)
-       goto loser;
+    policy = SecPolicyCreateBasicX509();
+    if (!policy)
+        goto loser;
 
     wrappedCert = CERT_CertListFromCert(cert);
     status = SecTrustCreateWithCertificates(wrappedCert, policy, &trust);
     if (status)
        goto loser;
 
-    /* Tell SecTrust that we don't care if any certs in the chain have expired,
-       nor do we want to stop when encountering a cert with a trust setting;
-       we always want to build the full chain.
-    */
-    CSSM_APPLE_TP_ACTION_DATA localActionData = {
-        CSSM_APPLE_TP_ACTION_VERSION,
-        CSSM_TP_ACTION_ALLOW_EXPIRED | CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT
-    };
-    actionData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (const UInt8 *)&localActionData, sizeof(localActionData), kCFAllocatorNull);
-    if (!actionData)
-        goto loser;
-
-    status = SecTrustSetParameters(trust, CSSM_TP_ACTION_DEFAULT, actionData);
-    if (status)
-        goto loser;
-
-    status = SecTrustEvaluate(trust, NULL);
+    /* SecTrustEvaluate will build us the best chain available using its heuristics.
+     * We'll ignore the trust result. */
+    status = SecTrustEvaluate(trust, &trustResult);
     if (status)
        goto loser;
+    CFIndex idx, count = SecTrustGetCertificateCount(trust);
+
+    /* If we weren't able to build a chain to a self-signed cert, warn. */
+    Boolean isSelfSigned = false;
+    SecCertificateRef lastCert = SecTrustGetCertificateAtIndex(trust, count - 1);
+    if (lastCert && (0 == SecCertificateIsSelfSigned(lastCert, &isSelfSigned)) && !isSelfSigned) {
+        CFStringRef commonName = NULL;
+        (void)SecCertificateCopyCommonName(cert, &commonName);
+        fprintf(stderr, "Warning: unable to build chain to self-signed root for signer \"%s\"",
+                commonName ? CFStringGetCStringPtr(commonName, kCFStringEncodingUTF8) : "");
+        if (commonName) { CFRelease(commonName); }
+    }
 
-    status = SecTrustGetResult(trust, NULL, &certChain, &statusChain);
-    if (status)
-       goto loser;
+    /* We don't drop the root if there is only 1 certificate in the chain. */
+    if (!includeRoot && count > 1) { count--; }
 
-    /* We don't drop the root if there is only 1 (self signed) certificate in the chain. */
-    if (!includeRoot && CFArrayGetCount(certChain) > 1)
-    {
-       CFMutableArrayRef subChain =  CFArrayCreateMutableCopy(NULL, 0, certChain);
-       CFRelease(certChain);
-       certChain = subChain;
-       if (subChain)
-           CFArrayRemoveValueAtIndex(subChain, CFArrayGetCount(subChain) - 1);
-    }
+    certs = CFArrayCreateMutable(kCFAllocatorDefault, count, &kCFTypeArrayCallBacks);
+    for(idx = 0; idx < count; idx++)
+        CFArrayAppendValue(certs, SecTrustGetCertificateAtIndex(trust, idx));
 
 loser:
-    if (searchRef)
-       CFRelease(searchRef);
     if (policy)
        CFRelease(policy);
     if (wrappedCert)
        CFRelease(wrappedCert);
     if (trust)
        CFRelease(trust);
-    if (actionData)
-       CFRelease(actionData);
-    if (certChain && status)
+    if (certs && status)
     {
-       CFRelease(certChain);
-       certChain = NULL;
+       CFRelease(certs);
+       certs = NULL;
     }
 
-    return certChain;
+    return certs;
 }
 
 CFArrayRef CERT_CertListFromCert(SecCertificateRef cert)
@@ -337,9 +319,7 @@ CFArrayRef CERT_DupCertList(CFArrayRef oldList)
 // Extract a public key object from a SubjectPublicKeyInfo
 SecPublicKeyRef CERT_ExtractPublicKey(SecCertificateRef cert)
 {
-    SecPublicKeyRef keyRef = NULL;
-    SecCertificateCopyPublicKey(cert,&keyRef);
-    return keyRef;
+    return SecCertificateCopyKey(cert);
 }
 
 SECStatus CERT_CheckCertUsage (SecCertificateRef cert,unsigned char usage)
@@ -376,9 +356,7 @@ SecCertificateRef CERT_FindCertByDERCert(SecKeychainRef keychainOrArray, const S
     return cert;
 }
 
-static int compareCssmData(
-    const CSSM_DATA *d1,
-    const CSSM_DATA *d2)
+int CERT_CompareCssmData(const CSSM_DATA *d1, const CSSM_DATA *d2)
 {
     if((d1 == NULL) || (d2 == NULL)) {
        return 0;
@@ -395,9 +373,9 @@ static int compareCssmData(
 // Generate a certificate key from the issuer and serialnumber, then look it up in the database.
 // Return the cert if found. "issuerAndSN" is the issuer and serial number to look for
 SecCertificateRef CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray, 
-    CSSM_DATA_PTR *rawCerts, PRArenaPool *pl, const SecCmsIssuerAndSN *issuerAndSN)
+    CSSM_DATA_PTR *rawCerts, CFArrayRef certList, PRArenaPool *pl, const SecCmsIssuerAndSN *issuerAndSN)
 {
-    SecCertificateRef certificate;
+    SecCertificateRef certificate = NULL;
     int numRawCerts = SecCmsArrayCount((void **)rawCerts);
     int dex;
     OSStatus ortn;
@@ -417,11 +395,11 @@ SecCertificateRef CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray,
            CFRelease(certificate);
            continue;
        }
-       if(!compareCssmData(&isn->derIssuer, &issuerAndSN->derIssuer)) {
+       if(!CERT_CompareCssmData(&isn->derIssuer, &issuerAndSN->derIssuer)) {
            CFRelease(certificate);
            continue;
        }
-       if(!compareCssmData(&isn->serialNumber, &issuerAndSN->serialNumber)) {
+       if(!CERT_CompareCssmData(&isn->serialNumber, &issuerAndSN->serialNumber)) {
            CFRelease(certificate);
            continue;
        }
@@ -429,6 +407,27 @@ SecCertificateRef CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray,
        dprintf("CERT_FindCertByIssuerAndSN: found cert %p\n", certificate);
        return certificate;
     }
+
+    /* Search the user-added certList */
+    if (certList && CFArrayGetCount(certList)) {
+        CFIndex c, count = CFArrayGetCount(certList);
+        for (c = 0; c < count; c++) {
+            SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certList, c);
+            SecCmsIssuerAndSN *isn = CERT_GetCertIssuerAndSN(pl, cert);
+            if(isn == NULL) {
+                continue;
+            }
+            if(!CERT_CompareCssmData(&isn->derIssuer, &issuerAndSN->derIssuer)) {
+                continue;
+            }
+            if(!CERT_CompareCssmData(&isn->serialNumber, &issuerAndSN->serialNumber)) {
+                continue;
+            }
+            certificate = cert;
+            break;
+        }
+        if (certificate) { return certificate; }
+    }
     
     /* now search keychain(s) */
     OSStatus status = SecCertificateFindByIssuerAndSN(keychainOrArray, &issuerAndSN->derIssuer,
@@ -443,7 +442,7 @@ SecCertificateRef CERT_FindCertByIssuerAndSN (CFTypeRef keychainOrArray,
 }
 
 SecCertificateRef CERT_FindCertBySubjectKeyID (CFTypeRef keychainOrArray, 
-    CSSM_DATA_PTR *rawCerts, const SECItem *subjKeyID)
+    CSSM_DATA_PTR *rawCerts, CFArrayRef certList, const SECItem *subjKeyID)
 {
     SecCertificateRef certificate;
     int numRawCerts = SecCmsArrayCount((void **)rawCerts);
@@ -467,7 +466,7 @@ SecCertificateRef CERT_FindCertBySubjectKeyID (CFTypeRef keychainOrArray,
            /* not present */
            continue;
        }
-       match = compareCssmData(subjKeyID, &skid);
+       match = CERT_CompareCssmData(subjKeyID, &skid);
        SECITEM_FreeItem(&skid, PR_FALSE);
        if(match) {
            /* got it */
@@ -476,6 +475,23 @@ SecCertificateRef CERT_FindCertBySubjectKeyID (CFTypeRef keychainOrArray,
        CFRelease(certificate);
     }
 
+    /* Search the user-added certList */
+    if (certList && CFArrayGetCount(certList)) {
+        CFDataRef subjectkeyid = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, subjKeyID->Data, subjKeyID->Length, kCFAllocatorNull);
+        CFIndex c, count = CFArrayGetCount(certList);
+        for (c = 0; c < count; c++) {
+            SecCertificateRef cert = (SecCertificateRef)CFArrayGetValueAtIndex(certList, c);
+            CFDataRef skid = (cert) ? SecCertificateGetSubjectKeyID(cert) : NULL;
+            if (skid && CFEqual(skid, subjectkeyid)) {
+                CFRetain(cert);
+                certificate = cert;
+                break;
+            }
+        }
+        if (subjectkeyid) { CFRelease(subjectkeyid); };
+        if (certificate) { return certificate; }
+    }
+
     /* now search keychain(s) */
     OSStatus status = SecCertificateFindBySubjectKeyID(keychainOrArray,subjKeyID,&certificate);
     if (status)
@@ -488,12 +504,15 @@ SecCertificateRef CERT_FindCertBySubjectKeyID (CFTypeRef keychainOrArray,
 }
 
 static SecIdentityRef
-CERT_FindIdentityByCertificate (CFTypeRef keychainOrArray, SecCertificateRef certificate)
+CERT_FindIdentityByCertificate (CFTypeRef keychainOrArray, SecCertificateRef CF_CONSUMED certificate)
 {
     SecIdentityRef  identity = NULL;
     SecIdentityCreateWithCertificate(keychainOrArray, certificate, &identity);
     if (!identity)
        PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
+    if (certificate) {
+        CFRelease(certificate);
+    }
 
     return identity;
 }
@@ -501,7 +520,7 @@ CERT_FindIdentityByCertificate (CFTypeRef keychainOrArray, SecCertificateRef cer
 SecIdentityRef
 CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAndSN *issuerAndSN)
 {
-    SecCertificateRef certificate = CERT_FindCertByIssuerAndSN(keychainOrArray, NULL, NULL, issuerAndSN);
+    SecCertificateRef certificate = CERT_FindCertByIssuerAndSN(keychainOrArray, NULL, NULL, NULL, issuerAndSN);
     if (!certificate)
        return NULL;
 
@@ -511,7 +530,7 @@ CERT_FindIdentityByIssuerAndSN (CFTypeRef keychainOrArray, const SecCmsIssuerAnd
 SecIdentityRef
 CERT_FindIdentityBySubjectKeyID (CFTypeRef keychainOrArray, const SECItem *subjKeyID)
 {
-    SecCertificateRef certificate = CERT_FindCertBySubjectKeyID(keychainOrArray, NULL, subjKeyID);
+    SecCertificateRef certificate = CERT_FindCertBySubjectKeyID(keychainOrArray, NULL, NULL, subjKeyID);
     if (!certificate)
        return NULL;
 
@@ -806,10 +825,7 @@ loser:
 CFTypeRef
 CERT_PolicyForCertUsage(SECCertUsage certUsage)
 {
-    SecPolicySearchRef search = NULL;
     SecPolicyRef policy = NULL;
-    const CSSM_OID *policyOID;
-    OSStatus rv;
 
     switch (certUsage)
     {
@@ -820,35 +836,25 @@ CERT_PolicyForCertUsage(SECCertUsage certUsage)
        goto loser;
        break;
     case certUsageSSLClient:
+        policy = SecPolicyCreateSSL(false, NULL);
+        break;
     case certUsageSSLServer:
-       policyOID = &CSSMOID_APPLE_TP_SSL;
-       break;
-    case certUsageUserCertImport:
-       policyOID = &CSSMOID_APPLE_TP_CSR_GEN;
+        policy = SecPolicyCreateSSL(true, NULL);
        break;
     case certUsageStatusResponder:
-       policyOID = &CSSMOID_APPLE_TP_REVOCATION_OCSP;
+        policy = SecPolicyCreateOCSPSigner();
        break;
     case certUsageObjectSigner:
     case certUsageProtectedObjectSigner:
-       policyOID = &CSSMOID_APPLE_ISIGN;
-       break;
+    case certUsageUserCertImport:
     case certUsageEmailSigner:
     case certUsageEmailRecipient:
-       policyOID = &CSSMOID_APPLE_X509_BASIC;
+        policy = SecPolicyCreateBasicX509();
        break;
     default:
        goto loser;
     }
-    rv = SecPolicySearchCreate(CSSM_CERT_X_509v3, policyOID, NULL, &search);
-    if (rv)
-       goto loser;
-
-    rv = SecPolicySearchCopyNext(search, &policy);
-    if (rv)
-       goto loser;
 
 loser:
-    if(search) CFRelease(search);
     return policy;
 }