#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"
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:
CFRelease(cert);
if (signingKey)
CFRelease(signingKey);
+ if (keyAttrs)
+ CFRelease(keyAttrs);
return signerInfo;
}
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;
(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 ??? */
}
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;
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)
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;
}
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 :-( */
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))
OSStatus rux = SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(signerinfo,timeStampPolicy);
dprintf("SecCmsSignerInfoVerifyUnAuthAttrs Status: %ld\n", (long)rux);
if (rux) {
- syslog(LOG_ERR, "SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy failed: %d", (int)rux);
goto loser;
}
}
* 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);
}
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.
*
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;
if ((signercert = SecCmsSignerInfoGetSigningCertificate(sinfo, NULL)) == NULL)
return NULL;
- SecCertificateCopyCommonName(signercert, &commonName);
+ if (errSecSuccess != SecCertificateCopyCommonName(signercert, &commonName)) {
+ return NULL;
+ }
return commonName;
}
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
/* 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;