+/* AgileHash ::= SEQUENCE {
+ hashType OBJECT IDENTIFIER,
+ hashValues OCTET STRING }
+ */
+typedef struct {
+ SecAsn1Item digestOID;
+ SecAsn1Item digestValue;
+} CMSAppleAgileHash;
+
+static const SecAsn1Template CMSAppleAgileHashTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(CMSAppleAgileHash) },
+ { SEC_ASN1_OBJECT_ID,
+ offsetof(CMSAppleAgileHash, digestOID), },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(CMSAppleAgileHash, digestValue), },
+ { 0, }
+};
+
+static OSStatus CMSAddAgileHashToDictionary(CFMutableDictionaryRef dictionary, SecAsn1Item *DERAgileHash) {
+ PLArenaPool *tmppoolp = NULL;
+ OSStatus status = errSecSuccess;
+ CMSAppleAgileHash agileHash;
+ CFDataRef digestValue = NULL;
+ CFNumberRef digestTag = NULL;
+
+ tmppoolp = PORT_NewArena(1024);
+ if (tmppoolp == NULL) {
+ return errSecAllocate;
+ }
+
+ if ((status = SEC_ASN1DecodeItem(tmppoolp, &agileHash, CMSAppleAgileHashTemplate, DERAgileHash)) != errSecSuccess) {
+ goto loser;
+ }
+
+ int64_t tag = SECOID_FindOIDTag(&agileHash.digestOID);
+ digestTag = CFNumberCreate(NULL, kCFNumberSInt64Type, &tag);
+ digestValue = CFDataCreate(NULL, agileHash.digestValue.Data, agileHash.digestValue.Length);
+ CFDictionaryAddValue(dictionary, digestTag, digestValue);
+
+loser:
+ CFReleaseNull(digestValue);
+ CFReleaseNull(digestTag);
+ if (tmppoolp) {
+ PORT_FreeArena(tmppoolp, PR_FALSE);
+ }
+ return status;
+}
+
+/*!
+ @function
+ @abstract Return the data in the signed Codesigning Hash Agility V2 attribute.
+ @param sinfo SignerInfo data for this signer, pointer to a CFDictionaryRef for attribute values
+ @discussion Returns a CFDictionaryRef containing the values 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
+SecCmsSignerInfoGetAppleCodesigningHashAgilityV2(SecCmsSignerInfoRef sinfo, CFDictionaryRef *sdict)
+{
+ SecCmsAttribute *attr;
+
+ if (sinfo == NULL || sdict == NULL) {
+ return errSecParam;
+ }
+
+ *sdict = NULL;
+
+ if (sinfo->hashAgilityV2AttrValues != NULL) {
+ *sdict = sinfo->hashAgilityV2AttrValues; /* cached copy */
+ return SECSuccess;
+ }
+
+ attr = SecCmsAttributeArrayFindAttrByOidTag(sinfo->authAttr, SEC_OID_APPLE_HASH_AGILITY_V2, PR_TRUE);
+
+ /* attribute not found */
+ if (attr == NULL) {
+ return SECSuccess;
+ }
+
+ /* attrValues SET OF AttributeValue
+ * AttributeValue ::= ANY
+ */
+ CSSM_DATA_PTR *values = attr->values;
+ if (values == NULL) { /* There must be values */
+ return errSecDecode;
+ }
+
+ CFMutableDictionaryRef agileHashValues = CFDictionaryCreateMutable(NULL, SecCmsArrayCount((void **)values),
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ while (*values != NULL) {
+ (void)CMSAddAgileHashToDictionary(agileHashValues, *values++);
+ }
+ if (CFDictionaryGetCount(agileHashValues) != SecCmsArrayCount((void **)attr->values)) {
+ CFReleaseNull(agileHashValues);
+ return errSecDecode;
+ }
+
+ sinfo->hashAgilityV2AttrValues = agileHashValues; /* make cached copy */
+ if (sinfo->hashAgilityV2AttrValues) {
+ *sdict = sinfo->hashAgilityV2AttrValues;
+ return SECSuccess;
+ }
+ return errSecAllocate;
+}
+
+/*
+ * SecCmsSignerInfoGetAppleExpirationTime - return the expiration time,
+ * in UTCTime format, of a CMS signerInfo.
+ *
+ * sinfo - signerInfo data for this signer
+ *
+ * Returns a pointer to XXXX (what?)
+ * A return value of NULL is an error.
+ */
+OSStatus
+SecCmsSignerInfoGetAppleExpirationTime(SecCmsSignerInfoRef sinfo, CFAbsoluteTime *etime)
+{
+ SecCmsAttribute *attr = NULL;
+ SecAsn1Item * value = NULL;
+
+ if (sinfo == NULL || etime == NULL) {
+ return SECFailure;
+ }
+
+ if (sinfo->expirationTime != 0) {
+ *etime = sinfo->expirationTime; /* cached copy */
+ return SECSuccess;
+ }
+
+ attr = SecCmsAttributeArrayFindAttrByOidTag(sinfo->authAttr, SEC_OID_APPLE_EXPIRATION_TIME, PR_TRUE);
+ if (attr == NULL || (value = SecCmsAttributeGetValue(attr)) == NULL) {
+ return SECFailure;
+ }
+ if (DER_UTCTimeToCFDate(value, etime) != SECSuccess) {
+ return SECFailure;
+ }
+ sinfo->expirationTime = *etime; /* make cached copy */
+ return SECSuccess;
+}
+