+/*!
+ @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;
+}
+