]> git.saurik.com Git - apple/security.git/blobdiff - OSX/libsecurity_smime/lib/cmssiginfo.c
Security-58286.41.2.tar.gz
[apple/security.git] / OSX / libsecurity_smime / lib / cmssiginfo.c
index d375f82dc3e79d6be622e79e28e3d952ebaa2b36..ac389d3cad5861c3e5d40c86b61e626c2cc10dce 100644 (file)
@@ -56,6 +56,7 @@
 #include <AssertMacros.h>
 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
 #include <Security/SecPolicyPriv.h>
+#include <Security/SecItem.h>
 
 #include "tsaSupport.h"
 #include "tsaSupportPriv.h"
@@ -213,12 +214,22 @@ SecCmsSignerInfoCreate(SecCmsMessageRef cmsg, SecIdentityRef identity, SECOidTag
     SecCmsSignerInfoRef signerInfo = NULL;
     SecCertificateRef cert = NULL;
     SecPrivateKeyRef signingKey = NULL;
+    CFDictionaryRef keyAttrs = NULL;
 
     if (SecIdentityCopyCertificate(identity, &cert))
        goto loser;
     if (SecIdentityCopyPrivateKey(identity, &signingKey))
        goto loser;
 
+    /* In some situations, the "Private Key" in the identity is actually a public key. */
+    keyAttrs = SecKeyCopyAttributes(signingKey);
+    if (!keyAttrs)
+        goto loser;
+    CFTypeRef class = CFDictionaryGetValue(keyAttrs, kSecAttrKeyClass);
+    if (!class || (CFGetTypeID(class) != CFStringGetTypeID()) || !CFEqual(class, kSecAttrKeyClassPrivate))
+        goto loser;
+
+
     signerInfo = nss_cmssignerinfo_create(cmsg, SecCmsSignerIDIssuerSN, cert, NULL, NULL, signingKey, digestalgtag);
 
 loser:
@@ -226,6 +237,8 @@ loser:
        CFRelease(cert);
     if (signingKey)
        CFRelease(signingKey);
+    if (keyAttrs)
+        CFRelease(keyAttrs);
 
     return signerInfo;
 }
@@ -267,8 +280,10 @@ nss_cmssignerinfo_create(SecCmsMessageRef cmsg, SecCmsSignerIDSelector type, Sec
         if (!subjKeyID)
             goto loser;
         signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, CSSM_DATA);
-        SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
-                         subjKeyID);
+        if (SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
+                             subjKeyID)) {
+            goto loser;
+        }
         signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey);
         if (!signerinfo->pubKey)
             goto loser;
@@ -323,6 +338,11 @@ SecCmsSignerInfoDestroy(SecCmsSignerInfoRef si)
            (int)CFGetRetainCount(si->timestampCertList));
        CFRelease(si->timestampCertList);
     }
+    if (si->hashAgilityAttrValue != NULL) {
+        dprintfRC("SecCmsSignerInfoDestroy top: hashAgilityAttrValue.rc %d\n",
+                  (int)CFGetRetainCount(si->hashAgilityAttrValue));
+        CFRelease(si->hashAgilityAttrValue);
+    }
     /* XXX storage ??? */
 }
 
@@ -496,11 +516,6 @@ loser:
        SECITEM_FreeItem (&signature, PR_FALSE);
     if (privkey)
        SECKEY_DestroyPrivateKey(privkey);
-    if((algID != NULL) & (algID != &freeAlgID)) {
-       /* this is dicey - this was actually mallocd by either SecCertificate or 
-        * by SecKey...it all boils down to a free() in the end though. */
-       SECOID_DestroyAlgorithmID((SECAlgorithmID *)algID, PR_FALSE);
-    }
     if (tmppoolp)
        PORT_FreeArena(tmppoolp, PR_FALSE);
     return SECFailure;
@@ -586,11 +601,11 @@ OSStatus
 SecCmsSignerInfoVerifyWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeStampPolicy, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType)
 {
     SecPublicKeyRef publickey = NULL;
-    SecCmsAttribute *attr;
+    SecCmsAttribute *attr = NULL;
     CSSM_DATA encoded_attrs;
-    SecCertificateRef cert;
+    SecCertificateRef cert = NULL;
     SecCmsVerificationStatus vs = SecCmsVSUnverified;
-    PLArenaPool *poolp;
+    PLArenaPool *poolp = NULL;
     SECOidTag digestAlgTag, digestEncAlgTag;
     
     if (signerinfo == NULL)
@@ -607,8 +622,10 @@ SecCmsSignerInfoVerifyWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeSt
     dprintfRC("SecCmsSignerInfoVerify top: cert %p cert.rc %d\n", cert, (int)CFGetRetainCount(cert));
     
     debugShowSigningCertificate(signerinfo);
-    
-    if (SecCertificateCopyPublicKey(cert, &publickey)) {
+
+    OSStatus status;
+    if ((status = SecCertificateCopyPublicKey(cert, &publickey))) {
+        syslog(LOG_ERR, "SecCmsSignerInfoVerifyWithPolicy: copy public key failed %d", (int)status);
        vs = SecCmsVSProcessingError;
        goto loser;
     }
@@ -685,15 +702,13 @@ SecCmsSignerInfoVerifyWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeSt
            goto loser;
        }
 
-        SECStatus err = SECSuccess;
-       vs = ((err = VFY_VerifyData (encoded_attrs.Data, (int)encoded_attrs.Length,
+       vs = (VFY_VerifyData (encoded_attrs.Data, (int)encoded_attrs.Length,
                        publickey, &(signerinfo->encDigest),
                        digestAlgTag, digestEncAlgTag,
-                       signerinfo->cmsg->pwfn_arg)) != SECSuccess) ? SecCmsVSBadSignature : SecCmsVSGoodSignature;
+                       signerinfo->cmsg->pwfn_arg) != SECSuccess) ? SecCmsVSBadSignature : SecCmsVSGoodSignature;
 
         dprintf("VFY_VerifyData (authenticated attributes): %s\n",
             (vs == SecCmsVSGoodSignature)?"SecCmsVSGoodSignature":"SecCmsVSBadSignature");
-        if (vs != SecCmsVSGoodSignature) syslog(LOG_ERR, "VFY_VerifyData (authenticated attributes) failed: %d", err);
 
        PORT_FreeArena(poolp, PR_FALSE);        /* awkward memory management :-( */
 
@@ -705,14 +720,12 @@ SecCmsSignerInfoVerifyWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeSt
        if (sig->Length == 0)
            goto loser;
 
-        SECStatus err = SECSuccess;
-       vs = ((err = VFY_VerifyDigest(digest, publickey, sig,
+       vs = (VFY_VerifyDigest(digest, publickey, sig,
                        digestAlgTag, digestEncAlgTag,
-                       signerinfo->cmsg->pwfn_arg)) != SECSuccess) ? SecCmsVSBadSignature : SecCmsVSGoodSignature;
+                       signerinfo->cmsg->pwfn_arg) != SECSuccess) ? SecCmsVSBadSignature : SecCmsVSGoodSignature;
 
         dprintf("VFY_VerifyData (plain message digest): %s\n",
             (vs == SecCmsVSGoodSignature)?"SecCmsVSGoodSignature":"SecCmsVSBadSignature");
-        if (vs != SecCmsVSGoodSignature) syslog(LOG_ERR, "VFY_VerifyDigest (plain message digest) failed: %d", err);
     }
     
     if (!SecCmsArrayIsEmpty((void **)signerinfo->unAuthAttr))
@@ -721,7 +734,6 @@ SecCmsSignerInfoVerifyWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeSt
         OSStatus rux = SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(signerinfo,timeStampPolicy);
         dprintf("SecCmsSignerInfoVerifyUnAuthAttrs Status: %ld\n", (long)rux);
         if (rux) {
-            syslog(LOG_ERR, "SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy failed: %d", (int)rux);
             goto loser;
         }
     }
@@ -743,7 +755,6 @@ SecCmsSignerInfoVerifyWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeSt
         * certificate signature check that failed during the cert
         * verification done above.  Our error handling is really a mess.
         */
-        syslog(LOG_ERR, "SecCmsSignerInforVerify bad signature PORT_GetError: %d", PORT_GetError());
        if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE)
            PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
     }
@@ -923,6 +934,44 @@ xit:
     return status;
 }
 
+/*!
+     @function
+     @abstract Return the data in the signed Codesigning Hash Agility attribute.
+     @param sinfo SignerInfo data for this signer, pointer to a CFDataRef for attribute value
+     @discussion Returns a CFDataRef containing the value of the attribute
+     @result A return value of errSecInternal is an error trying to look up the oid.
+             A status value of success with null result data indicates the attribute was not present.
+ */
+OSStatus
+SecCmsSignerInfoGetAppleCodesigningHashAgility(SecCmsSignerInfoRef sinfo, CFDataRef *sdata)
+{
+    SecCmsAttribute *attr;
+    CSSM_DATA_PTR value;
+
+    if (sinfo == NULL || sdata == NULL)
+        return paramErr;
+
+    *sdata = NULL;
+
+    if (sinfo->hashAgilityAttrValue != NULL) {
+        *sdata = sinfo->hashAgilityAttrValue;  /* cached copy */
+        return SECSuccess;
+    }
+
+    attr = SecCmsAttributeArrayFindAttrByOidTag(sinfo->authAttr, SEC_OID_APPLE_HASH_AGILITY, PR_TRUE);
+
+    /* attribute not found */
+    if (attr == NULL || (value = SecCmsAttributeGetValue(attr)) == NULL)
+        return SECSuccess;
+
+    sinfo->hashAgilityAttrValue = CFDataCreate(NULL, value->Data, value->Length);      /* make cached copy */
+    if (sinfo->hashAgilityAttrValue) {
+        *sdata = sinfo->hashAgilityAttrValue;
+        return SECSuccess;
+    }
+    return errSecAllocate;
+}
+
 /*
  * Return the signing cert of a CMS signerInfo.
  *
@@ -957,11 +1006,11 @@ SecCmsSignerInfoGetSigningCertificate(SecCmsSignerInfoRef signerinfo, SecKeychai
     sid = &signerinfo->signerIdentifier;
     switch (sid->identifierType) {
     case SecCmsSignerIDIssuerSN:
-       cert = CERT_FindCertByIssuerAndSN(keychainOrArray, rawCerts, signerinfo->cmsg->poolp,
+       cert = CERT_FindCertByIssuerAndSN(keychainOrArray, rawCerts, signerinfo->sigd->certs, signerinfo->cmsg->poolp,
            sid->id.issuerAndSN);
        break;
     case SecCmsSignerIDSubjectKeyID:
-       cert = CERT_FindCertBySubjectKeyID(keychainOrArray, rawCerts, sid->id.subjectKeyID);
+       cert = CERT_FindCertBySubjectKeyID(keychainOrArray, rawCerts, signerinfo->sigd->certs, sid->id.subjectKeyID);
        break;
     default:
        cert = NULL;
@@ -994,7 +1043,9 @@ SecCmsSignerInfoGetSignerCommonName(SecCmsSignerInfoRef sinfo)
     if ((signercert = SecCmsSignerInfoGetSigningCertificate(sinfo, NULL)) == NULL)
        return NULL;
 
-    SecCertificateCopyCommonName(signercert, &commonName);
+    if (errSecSuccess != SecCertificateCopyCommonName(signercert, &commonName)) {
+        return NULL;
+    }
 
     return commonName;
 }
@@ -1315,6 +1366,84 @@ SecCmsSignerInfoAddCounterSignature(SecCmsSignerInfoRef signerinfo,
     return SECFailure;
 }
 
+/*!
+     @function
+     @abstract Add the Apple Codesigning Hash Agility attribute to the authenticated (i.e. signed) attributes of "signerinfo".
+     @discussion This is expected to be included in outgoing signed Apple code signatures.
+ */
+OSStatus
+SecCmsSignerInfoAddAppleCodesigningHashAgility(SecCmsSignerInfoRef signerinfo, CFDataRef attrValue)
+{
+    SecCmsAttribute *attr;
+    PLArenaPool *poolp = signerinfo->cmsg->poolp;
+    void *mark = PORT_ArenaMark(poolp);
+    OSStatus status = SECFailure;
+
+    /* The value is required for this attribute. */
+    if (!attrValue) {
+        status = errSecParam;
+        goto loser;
+    }
+
+    /*
+     * SecCmsAttributeCreate makes a copy of the data in value, so
+     * we don't need to copy into the CSSM_DATA struct.
+     */
+    CSSM_DATA value;
+    value.Length = CFDataGetLength(attrValue);
+    value.Data = (uint8_t *)CFDataGetBytePtr(attrValue);
+
+    if ((attr = SecCmsAttributeCreate(poolp,
+                                      SEC_OID_APPLE_HASH_AGILITY,
+                                      &value,
+                                      PR_FALSE)) == NULL) {
+        status = errSecAllocate;
+        goto loser;
+    }
+
+    if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess) {
+        status = errSecInternalError;
+        goto loser;
+    }
+
+    PORT_ArenaUnmark(poolp, mark);
+    return SECSuccess;
+
+loser:
+    PORT_ArenaRelease(poolp, mark);
+    return status;
+}
+
+SecCertificateRef SecCmsSignerInfoCopyCertFromEncryptionKeyPreference(SecCmsSignerInfoRef signerinfo) {
+    SecCertificateRef cert = NULL;
+    SecCmsAttribute *attr;
+    CSSM_DATA_PTR ekp;
+    SecKeychainRef keychainOrArray;
+
+    (void)SecKeychainCopyDefault(&keychainOrArray);
+
+    /* sanity check - see if verification status is ok (unverified does not count...) */
+    if (signerinfo->verificationStatus != SecCmsVSGoodSignature)
+        return NULL;
+
+    /* find preferred encryption cert */
+    if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr) &&
+        (attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr,
+                                                     SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, PR_TRUE)) != NULL)
+    { /* we have a SMIME_ENCRYPTION_KEY_PREFERENCE attribute! Find the cert. */
+        ekp = SecCmsAttributeGetValue(attr);
+        if (ekp == NULL)
+            return NULL;
+
+        CSSM_DATA_PTR *rawCerts = NULL;
+        if (signerinfo->sigd) {
+            rawCerts = signerinfo->sigd->rawCerts;
+        }
+        cert = SecSMIMEGetCertFromEncryptionKeyPreference(keychainOrArray, rawCerts, ekp);
+    }
+    return cert;
+}
+
 /*
  * XXXX the following needs to be done in the S/MIME layer code
  * after signature of a signerinfo is verified
@@ -1350,7 +1479,7 @@ SecCmsSignerInfoSaveSMIMEProfile(SecCmsSignerInfoRef signerinfo)
 
        /* we assume that all certs coming with the message have been imported to the */
        /* temporary database */
-       cert = SecSMIMEGetCertFromEncryptionKeyPreference(keychainOrArray, ekp);
+       cert = SecSMIMEGetCertFromEncryptionKeyPreference(keychainOrArray, NULL, ekp);
        if (cert == NULL)
            return SECFailure;
        must_free_cert = PR_TRUE;