]> git.saurik.com Git - apple/security.git/blobdiff - Security/libsecurity_smime/lib/cmssiginfo.c
Security-57336.1.9.tar.gz
[apple/security.git] / Security / libsecurity_smime / lib / cmssiginfo.c
diff --git a/Security/libsecurity_smime/lib/cmssiginfo.c b/Security/libsecurity_smime/lib/cmssiginfo.c
deleted file mode 100644 (file)
index efb4eeb..0000000
+++ /dev/null
@@ -1,1432 +0,0 @@
-/*
- * The contents of this file are subject to the Mozilla Public
- * License Version 1.1 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.mozilla.org/MPL/
- * 
- * Software distributed under the License is distributed on an "AS
- * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * rights and limitations under the License.
- * 
- * The Original Code is the Netscape security libraries.
- * 
- * The Initial Developer of the Original Code is Netscape
- * Communications Corporation.  Portions created by Netscape are 
- * Copyright (C) 1994-2000 Netscape Communications Corporation.  All
- * Rights Reserved.
- * 
- * Contributor(s):
- * 
- * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License Version 2 or later (the
- * "GPL"), in which case the provisions of the GPL are applicable 
- * instead of those above.  If you wish to allow use of your 
- * version of this file only under the terms of the GPL and not to
- * allow others to use your version of this file under the MPL,
- * indicate your decision by deleting the provisions above and
- * replace them with the notice and other provisions required by
- * the GPL.  If you do not delete the provisions above, a recipient
- * may use your version of this file under either the MPL or the
- * GPL.
- */
-
-/*
- * CMS signerInfo methods.
- */
-
-#include <Security/SecCmsSignerInfo.h>
-#include "SecSMIMEPriv.h"
-
-#include "cmslocal.h"
-
-#include "cert.h"
-#include "secitem.h"
-#include "secoid.h"
-#include "cryptohi.h"
-
-#include <security_asn1/secasn1.h>
-#include <security_asn1/secerr.h>
-#include <Security/SecKeychain.h>
-#include <Security/SecIdentity.h>
-#include <Security/SecCertificatePriv.h>
-#include <Security/SecKeyPriv.h>
-#include <CoreFoundation/CFTimeZone.h>
-#include <utilities/SecCFWrappers.h>
-#include <AssertMacros.h>
-#include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
-#include <Security/SecPolicyPriv.h>
-
-#include "tsaSupport.h"
-#include "tsaSupportPriv.h"
-
-#define HIDIGIT(v) (((v) / 10) + '0')    
-#define LODIGIT(v) (((v) % 10) + '0')     
-
-#define ISDIGIT(dig) (((dig) >= '0') && ((dig) <= '9'))
-#define CAPTURE(var,p,label)                              \
-{                                                         \
-    if (!ISDIGIT((p)[0]) || !ISDIGIT((p)[1])) goto label; \
-    (var) = ((p)[0] - '0') * 10 + ((p)[1] - '0');         \
-}
-
-#ifndef NDEBUG
-#define SIGINFO_DEBUG  1
-#endif
-
-#if    SIGINFO_DEBUG
-#define dprintf(args...)      printf(args)
-#else
-#define dprintf(args...)
-#endif
-
-#if RELEASECOUNTDEBUG
-#define dprintfRC(args...)    dprintf(args)
-#else
-#define dprintfRC(args...)
-#endif
-
-static OSStatus
-DER_UTCTimeToCFDate(const CSSM_DATA_PTR utcTime, CFAbsoluteTime *date)
-{
-    CFGregorianDate gdate;
-    char *string = (char *)utcTime->Data;
-    long year, month, mday, hour, minute, second, hourOff, minOff;
-    CFTimeZoneRef timeZone;
-
-    /* Verify time is formatted properly and capture information */
-    second = 0;
-    hourOff = 0;
-    minOff = 0;
-    CAPTURE(year,string+0,loser);
-    if (year < 50) {
-        /* ASSUME that year # is in the 2000's, not the 1900's */
-        year += 100;
-    }
-    CAPTURE(month,string+2,loser);
-    if ((month == 0) || (month > 12)) goto loser;
-    CAPTURE(mday,string+4,loser);
-    if ((mday == 0) || (mday > 31)) goto loser;
-    CAPTURE(hour,string+6,loser);
-    if (hour > 23) goto loser;
-    CAPTURE(minute,string+8,loser);
-    if (minute > 59) goto loser;
-    if (ISDIGIT(string[10])) {
-        CAPTURE(second,string+10,loser);
-        if (second > 59) goto loser;
-        string += 2;
-    }
-    if (string[10] == '+') {
-        CAPTURE(hourOff,string+11,loser);
-        if (hourOff > 23) goto loser;
-        CAPTURE(minOff,string+13,loser);
-        if (minOff > 59) goto loser;
-    } else if (string[10] == '-') {
-        CAPTURE(hourOff,string+11,loser);
-        if (hourOff > 23) goto loser;
-        hourOff = -hourOff;
-        CAPTURE(minOff,string+13,loser);
-        if (minOff > 59) goto loser;
-        minOff = -minOff;
-    } else if (string[10] != 'Z') {
-        goto loser;
-    }
-
-    gdate.year = (SInt32)(year + 1900);
-    gdate.month = month;
-    gdate.day = mday;
-    gdate.hour = hour;
-    gdate.minute = minute;
-    gdate.second = second;
-
-    if (hourOff == 0 && minOff == 0)
-       timeZone = NULL; /* GMT */
-    else
-    {
-       timeZone = CFTimeZoneCreateWithTimeIntervalFromGMT(NULL, (hourOff * 60 + minOff) * 60);
-    }
-
-    *date = CFGregorianDateGetAbsoluteTime(gdate, timeZone);
-    if (timeZone)
-       CFRelease(timeZone);
-
-    return SECSuccess;
-
-loser:
-    return SECFailure;
-}
-
-static OSStatus
-DER_CFDateToUTCTime(CFAbsoluteTime date, CSSM_DATA_PTR utcTime)
-{
-    CFGregorianDate gdate =  CFAbsoluteTimeGetGregorianDate(date, NULL /* GMT */);
-    unsigned char *d;
-    SInt8 second;
-
-    utcTime->Length = 13;
-    utcTime->Data = d = PORT_Alloc(13);
-    if (!utcTime->Data)
-       return SECFailure;
-
-    /* UTC time does not handle the years before 1950 */
-    if (gdate.year < 1950)
-            return SECFailure;
-
-    /* remove the century since it's added to the year by the
-       CFAbsoluteTimeGetGregorianDate routine, but is not needed for UTC time */
-    gdate.year %= 100;
-    second = gdate.second + 0.5;
-
-    d[0] = HIDIGIT(gdate.year);
-    d[1] = LODIGIT(gdate.year);
-    d[2] = HIDIGIT(gdate.month);   
-    d[3] = LODIGIT(gdate.month);
-    d[4] = HIDIGIT(gdate.day);
-    d[5] = LODIGIT(gdate.day);
-    d[6] = HIDIGIT(gdate.hour);
-    d[7] = LODIGIT(gdate.hour);  
-    d[8] = HIDIGIT(gdate.minute);
-    d[9] = LODIGIT(gdate.minute);
-    d[10] = HIDIGIT(second);
-    d[11] = LODIGIT(second);
-    d[12] = 'Z';
-    return SECSuccess;
-}
-
-/* =============================================================================
- * SIGNERINFO
- */
-SecCmsSignerInfoRef
-nss_cmssignerinfo_create(SecCmsMessageRef cmsg, SecCmsSignerIDSelector type, SecCertificateRef cert, CSSM_DATA_PTR subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag);
-
-SecCmsSignerInfoRef
-SecCmsSignerInfoCreateWithSubjKeyID(SecCmsMessageRef cmsg, CSSM_DATA_PTR subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag)
-{
-    return nss_cmssignerinfo_create(cmsg, SecCmsSignerIDSubjectKeyID, NULL, subjKeyID, pubKey, signingKey, digestalgtag); 
-}
-
-SecCmsSignerInfoRef
-SecCmsSignerInfoCreate(SecCmsMessageRef cmsg, SecIdentityRef identity, SECOidTag digestalgtag)
-{
-    SecCmsSignerInfoRef signerInfo = NULL;
-    SecCertificateRef cert = NULL;
-    SecPrivateKeyRef signingKey = NULL;
-
-    if (SecIdentityCopyCertificate(identity, &cert))
-       goto loser;
-    if (SecIdentityCopyPrivateKey(identity, &signingKey))
-       goto loser;
-
-    signerInfo = nss_cmssignerinfo_create(cmsg, SecCmsSignerIDIssuerSN, cert, NULL, NULL, signingKey, digestalgtag);
-
-loser:
-    if (cert)
-       CFRelease(cert);
-    if (signingKey)
-       CFRelease(signingKey);
-
-    return signerInfo;
-}
-
-SecCmsSignerInfoRef
-nss_cmssignerinfo_create(SecCmsMessageRef cmsg, SecCmsSignerIDSelector type, SecCertificateRef cert, CSSM_DATA_PTR subjKeyID, SecPublicKeyRef pubKey, SecPrivateKeyRef signingKey, SECOidTag digestalgtag)
-{
-    void *mark;
-    SecCmsSignerInfoRef signerinfo;
-    int version;
-    PLArenaPool *poolp;
-
-    poolp = cmsg->poolp;
-
-    mark = PORT_ArenaMark(poolp);
-
-    signerinfo = (SecCmsSignerInfoRef)PORT_ArenaZAlloc(poolp, sizeof(SecCmsSignerInfo));
-    if (signerinfo == NULL) {
-       PORT_ArenaRelease(poolp, mark);
-       return NULL;
-    }
-
-
-    signerinfo->cmsg = cmsg;
-
-    switch(type) {
-    case SecCmsSignerIDIssuerSN:
-        signerinfo->signerIdentifier.identifierType = SecCmsSignerIDIssuerSN;
-        if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL)
-           goto loser;
-        if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL)
-           goto loser;
-       dprintfRC("nss_cmssignerinfo_create: SecCmsSignerIDIssuerSN: cert.rc %d\n",
-           (int)CFGetRetainCount(signerinfo->cert));
-        break;
-    case SecCmsSignerIDSubjectKeyID:
-        signerinfo->signerIdentifier.identifierType = SecCmsSignerIDSubjectKeyID;
-        PORT_Assert(subjKeyID);
-        if (!subjKeyID)
-            goto loser;
-        signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, CSSM_DATA);
-        SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
-                         subjKeyID);
-        signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey);
-        if (!signerinfo->pubKey)
-            goto loser;
-        break;
-    default:
-        goto loser;
-    }
-
-    if (!signingKey)
-       goto loser;
-
-    signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey);
-    if (!signerinfo->signingKey)
-       goto loser;
-
-    /* set version right now */
-    version = SEC_CMS_SIGNER_INFO_VERSION_ISSUERSN;
-    /* RFC2630 5.3 "version is the syntax version number. If the .... " */
-    if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID)
-       version = SEC_CMS_SIGNER_INFO_VERSION_SUBJKEY;
-    (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version);
-
-    if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess)
-       goto loser;
-
-    PORT_ArenaUnmark(poolp, mark);
-    return signerinfo;
-
-loser:
-    PORT_ArenaRelease(poolp, mark);
-    return NULL;
-}
-
-/*
- * SecCmsSignerInfoDestroy - destroy a SignerInfo data structure
- */
-void
-SecCmsSignerInfoDestroy(SecCmsSignerInfoRef si)
-{
-    if (si->cert != NULL) {
-       dprintfRC("SecCmsSignerInfoDestroy top: certp %p cert.rc %d\n",
-           si->cert, (int)CFGetRetainCount(si->cert));
-       CERT_DestroyCertificate(si->cert);
-    }
-    if (si->certList != NULL) {
-       dprintfRC("SecCmsSignerInfoDestroy top: certList.rc %d\n",
-           (int)CFGetRetainCount(si->certList));
-       CFRelease(si->certList);
-    }
-    if (si->timestampCertList != NULL) {
-       dprintfRC("SecCmsSignerInfoDestroy top: timestampCertList.rc %d\n",
-           (int)CFGetRetainCount(si->timestampCertList));
-       CFRelease(si->timestampCertList);
-    }
-    /* XXX storage ??? */
-}
-
-/*
- * SecCmsSignerInfoSign - sign something
- *
- */
-OSStatus
-SecCmsSignerInfoSign(SecCmsSignerInfoRef signerinfo, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType)
-{
-    SecCertificateRef cert;
-    SecPrivateKeyRef privkey = NULL;
-    SECOidTag digestalgtag;
-    SECOidTag pubkAlgTag;
-    CSSM_DATA signature = { 0 };
-    OSStatus rv;
-    PLArenaPool *poolp, *tmppoolp = NULL;
-    const SECAlgorithmID *algID;
-    SECAlgorithmID freeAlgID;
-    //CERTSubjectPublicKeyInfo *spki;
-
-    PORT_Assert (digest != NULL);
-
-    poolp = signerinfo->cmsg->poolp;
-
-    switch (signerinfo->signerIdentifier.identifierType) {
-    case SecCmsSignerIDIssuerSN:
-        privkey = signerinfo->signingKey;
-        signerinfo->signingKey = NULL;
-        cert = signerinfo->cert;
-       if (SecCertificateGetAlgorithmID(cert,&algID)) {
-           PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
-           goto loser;
-        }
-        break;
-    case SecCmsSignerIDSubjectKeyID:
-        privkey = signerinfo->signingKey;
-        signerinfo->signingKey = NULL;
-#if 0
-        spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey);
-        SECKEY_DestroyPublicKey(signerinfo->pubKey);
-        signerinfo->pubKey = NULL;
-        SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm);
-        SECKEY_DestroySubjectPublicKeyInfo(spki);
-        algID = &freeAlgID;
-#else
-       if (SecKeyGetAlgorithmID(signerinfo->pubKey,&algID)) {
-           PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
-           goto loser;
-        }
-       CFRelease(signerinfo->pubKey);
-        signerinfo->pubKey = NULL;
-#endif
-        break;
-    default:
-        PORT_SetError(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE);
-        goto loser;
-    }
-    digestalgtag = SecCmsSignerInfoGetDigestAlgTag(signerinfo);
-    /*
-     * XXX I think there should be a cert-level interface for this,
-     * so that I do not have to know about subjectPublicKeyInfo...
-     */
-    pubkAlgTag = SECOID_GetAlgorithmTag(algID);
-    if (signerinfo->signerIdentifier.identifierType == SecCmsSignerIDSubjectKeyID) {
-      SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE);
-    }
-
-#if 0
-    // @@@ Not yet
-    /* Fortezza MISSI have weird signature formats.  
-     * Map them to standard DSA formats 
-     */
-    pubkAlgTag = PK11_FortezzaMapSig(pubkAlgTag);
-#endif
-
-    if (signerinfo->authAttr != NULL) {
-       CSSM_DATA encoded_attrs;
-
-       /* find and fill in the message digest attribute. */
-       rv = SecCmsAttributeArraySetAttr(poolp, &(signerinfo->authAttr), 
-                              SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE);
-       if (rv != SECSuccess)
-           goto loser;
-
-       if (contentType != NULL) {
-           /* if the caller wants us to, find and fill in the content type attribute. */
-           rv = SecCmsAttributeArraySetAttr(poolp, &(signerinfo->authAttr), 
-                           SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE);
-           if (rv != SECSuccess)
-               goto loser;
-       }
-
-       if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
-           PORT_SetError(SEC_ERROR_NO_MEMORY);
-           goto loser;
-       }
-
-       /*
-        * Before encoding, reorder the attributes so that when they
-        * are encoded, they will be conforming DER, which is required
-        * to have a specific order and that is what must be used for
-        * the hash/signature.  We do this here, rather than building
-        * it into EncodeAttributes, because we do not want to do
-        * such reordering on incoming messages (which also uses
-        * EncodeAttributes) or our old signatures (and other "broken"
-        * implementations) will not verify.  So, we want to guarantee
-        * that we send out good DER encodings of attributes, but not
-        * to expect to receive them.
-        */
-       if (SecCmsAttributeArrayReorder(signerinfo->authAttr) != SECSuccess)
-           goto loser;
-
-       encoded_attrs.Data = NULL;
-       encoded_attrs.Length = 0;
-       if (SecCmsAttributeArrayEncode(tmppoolp, &(signerinfo->authAttr), 
-                       &encoded_attrs) == NULL)
-           goto loser;
-
-       rv = SEC_SignData(&signature, encoded_attrs.Data, (int)encoded_attrs.Length,
-                         privkey, digestalgtag, pubkAlgTag);
-       PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */
-       tmppoolp = 0;
-    } else {
-       rv = SGN_Digest(privkey, digestalgtag, pubkAlgTag, &signature, digest);
-    }
-    SECKEY_DestroyPrivateKey(privkey);
-    privkey = NULL;
-
-    if (rv != SECSuccess)
-       goto loser;
-
-    if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature) 
-          != SECSuccess)
-       goto loser;
-
-    SECITEM_FreeItem(&signature, PR_FALSE);
-
-    if(pubkAlgTag == SEC_OID_EC_PUBLIC_KEY) {
-       /*
-        * RFC 3278 section section 2.1.1 states that the signatureAlgorithm 
-        * field contains the full ecdsa-with-SHA1 OID, not plain old ecPublicKey 
-        * as would appear in other forms of signed datas. However Microsoft doesn't 
-        * do this, it puts ecPublicKey there, and if we put ecdsa-with-SHA1 there, 
-        * MS can't verify - presumably because it takes the digest of the digest 
-        * before feeding it to ECDSA.
-        * We handle this with a preference; default if it's not there is 
-        * "Microsoft compatibility mode". 
-        */
-       if(!SecCmsMsEcdsaCompatMode()) {
-           pubkAlgTag = SEC_OID_ECDSA_WithSHA1;
-       }
-       /* else violating the spec for compatibility */
-    }
-
-    if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag, 
-                              NULL) != SECSuccess)
-       goto loser;
-
-    return SECSuccess;
-
-loser:
-    if (signature.Length != 0)
-       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;
-}
-
-OSStatus
-SecCmsSignerInfoVerifyCertificate(SecCmsSignerInfoRef signerinfo, SecKeychainRef keychainOrArray,
-                                 CFTypeRef policies, SecTrustRef *trustRef)
-{
-    SecCertificateRef cert;
-    CFAbsoluteTime stime;
-    OSStatus rv;
-    CSSM_DATA_PTR *otherCerts;
-    
-    if ((cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, keychainOrArray)) == NULL) {
-       dprintf("SecCmsSignerInfoVerifyCertificate: no signing cert\n");
-       signerinfo->verificationStatus = SecCmsVSSigningCertNotFound;
-       return SECFailure;
-    }
-
-    /*
-     * Get and convert the signing time; if available, it will be used
-     * both on the cert verification and for importing the sender
-     * email profile.
-     */
-    CFTypeRef timeStampPolicies=SecPolicyCreateAppleTimeStampingAndRevocationPolicies(policies);
-    if (SecCmsSignerInfoGetTimestampTimeWithPolicy(signerinfo, timeStampPolicies, &stime) != SECSuccess)
-        if (SecCmsSignerInfoGetSigningTime(signerinfo, &stime) != SECSuccess)
-            stime = CFAbsoluteTimeGetCurrent();
-    CFReleaseSafe(timeStampPolicies);
-
-    rv = SecCmsSignedDataRawCerts(signerinfo->sigd, &otherCerts);
-    if(rv) {
-       return rv;
-    }
-    rv = CERT_VerifyCert(keychainOrArray, cert, otherCerts, policies, stime, trustRef);
-    dprintfRC("SecCmsSignerInfoVerifyCertificate after vfy: certp %p cert.rc %d\n",
-           cert, (int)CFGetRetainCount(cert));
-    if (rv || !trustRef)
-    {
-       if (PORT_GetError() == SEC_ERROR_UNTRUSTED_CERT)
-       {
-           /* Signature or digest level verificationStatus errors should supercede certificate level errors, so only change the verificationStatus if the status was GoodSignature. */
-           if (signerinfo->verificationStatus == SecCmsVSGoodSignature)
-               signerinfo->verificationStatus = SecCmsVSSigningCertNotTrusted;
-       }
-    }
-    /* FIXME isn't this leaking the cert? */
-    dprintf("SecCmsSignerInfoVerifyCertificate: CertVerify rtn %d\n", (int)rv);
-    return rv;
-}
-
-static void debugShowSigningCertificate(SecCmsSignerInfoRef signerinfo)
-{
-#if SIGINFO_DEBUG
-    CFStringRef cn = SecCmsSignerInfoGetSignerCommonName(signerinfo);
-    if (cn)
-    {
-        char *ccn = cfStringToChar(cn);
-        if (ccn)
-        {
-            dprintf("SecCmsSignerInfoVerify: cn: %s\n", ccn);
-            free(ccn);
-        }
-        CFRelease(cn);
-    }
-#endif
-}
-
-/*
- * SecCmsSignerInfoVerify - verify the signature of a single SignerInfo
- *
- * Just verifies the signature. The assumption is that verification of the certificate
- * is done already.
- */
-OSStatus
-SecCmsSignerInfoVerify(SecCmsSignerInfoRef signerinfo, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType)
-{
-    return SecCmsSignerInfoVerifyWithPolicy(signerinfo,NULL, digest,contentType);
-}
-
-OSStatus
-SecCmsSignerInfoVerifyWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeStampPolicy, CSSM_DATA_PTR digest, CSSM_DATA_PTR contentType)
-{
-    SecPublicKeyRef publickey = NULL;
-    SecCmsAttribute *attr;
-    CSSM_DATA encoded_attrs;
-    SecCertificateRef cert;
-    SecCmsVerificationStatus vs = SecCmsVSUnverified;
-    PLArenaPool *poolp;
-    SECOidTag digestAlgTag, digestEncAlgTag;
-    
-    if (signerinfo == NULL)
-       return SECFailure;
-    
-    /* SecCmsSignerInfoGetSigningCertificate will fail if 2nd parm is NULL and */
-    /* cert has not been verified */
-    if ((cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, NULL)) == NULL) {
-       dprintf("SecCmsSignerInfoVerify: no signing cert\n");
-       vs = SecCmsVSSigningCertNotFound;
-       goto loser;
-    }
-
-    dprintfRC("SecCmsSignerInfoVerify top: cert %p cert.rc %d\n", cert, (int)CFGetRetainCount(cert));
-    
-    debugShowSigningCertificate(signerinfo);
-    
-    if (SecCertificateCopyPublicKey(cert, &publickey)) {
-       vs = SecCmsVSProcessingError;
-       goto loser;
-    }
-
-    digestAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestAlg));
-    digestEncAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg));
-    
-    /*
-     * Gross hack necessitated by RFC 3278 section 2.1.1, which states 
-     * that the signature algorithm (here, digestEncAlg) contains ecdsa_with-SHA1, 
-     * *not* (as in all other algorithms) the raw signature algorithm, e.g. 
-     * pkcs1RSAEncryption.
-     */
-    if(digestEncAlgTag == SEC_OID_ECDSA_WithSHA1) {
-       digestEncAlgTag = SEC_OID_EC_PUBLIC_KEY;
-    }
-    
-    if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr)) {
-       if (contentType) {
-           /*
-            * Check content type
-            *
-            * RFC2630 sez that if there are any authenticated attributes,
-            * then there must be one for content type which matches the
-            * content type of the content being signed, and there must
-            * be one for message digest which matches our message digest.
-            * So check these things first.
-            */
-           if ((attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr,
-                                       SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE)) == NULL)
-           {
-               vs = SecCmsVSMalformedSignature;
-               goto loser;
-           }
-               
-           if (SecCmsAttributeCompareValue(attr, contentType) == PR_FALSE) {
-               vs = SecCmsVSMalformedSignature;
-               goto loser;
-           }
-       }
-
-       /*
-        * Check digest
-        */
-       if ((attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr, SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE)) == NULL)
-       {
-           vs = SecCmsVSMalformedSignature;
-           goto loser;
-       }
-       if (SecCmsAttributeCompareValue(attr, digest) == PR_FALSE) {
-           vs = SecCmsVSDigestMismatch;
-           goto loser;
-       }
-
-       if ((poolp = PORT_NewArena (1024)) == NULL) {
-           vs = SecCmsVSProcessingError;
-           goto loser;
-       }
-
-       /*
-        * Check signature
-        *
-        * The signature is based on a digest of the DER-encoded authenticated
-        * attributes.  So, first we encode and then we digest/verify.
-        * we trust the decoder to have the attributes in the right (sorted) order
-        */
-       encoded_attrs.Data = NULL;
-       encoded_attrs.Length = 0;
-
-       if (SecCmsAttributeArrayEncode(poolp, &(signerinfo->authAttr), &encoded_attrs) == NULL ||
-               encoded_attrs.Data == NULL || encoded_attrs.Length == 0)
-       {
-           vs = SecCmsVSProcessingError;
-           goto loser;
-       }
-
-       vs = (VFY_VerifyData (encoded_attrs.Data, (int)encoded_attrs.Length,
-                       publickey, &(signerinfo->encDigest),
-                       digestAlgTag, digestEncAlgTag,
-                       signerinfo->cmsg->pwfn_arg) != SECSuccess) ? SecCmsVSBadSignature : SecCmsVSGoodSignature;
-
-        dprintf("VFY_VerifyData (authenticated attributes): %s\n",
-            (vs == SecCmsVSGoodSignature)?"SecCmsVSGoodSignature":"SecCmsVSBadSignature");
-
-       PORT_FreeArena(poolp, PR_FALSE);        /* awkward memory management :-( */
-
-    } else {
-       CSSM_DATA_PTR sig;
-
-       /* No authenticated attributes. The signature is based on the plain message digest. */
-       sig = &(signerinfo->encDigest);
-       if (sig->Length == 0)
-           goto loser;
-
-       vs = (VFY_VerifyDigest(digest, publickey, sig,
-                       digestAlgTag, digestEncAlgTag,
-                       signerinfo->cmsg->pwfn_arg) != SECSuccess) ? SecCmsVSBadSignature : SecCmsVSGoodSignature;
-
-        dprintf("VFY_VerifyData (plain message digest): %s\n",
-            (vs == SecCmsVSGoodSignature)?"SecCmsVSGoodSignature":"SecCmsVSBadSignature");
-    }
-    
-    if (!SecCmsArrayIsEmpty((void **)signerinfo->unAuthAttr))
-    {
-        dprintf("found an unAuthAttr\n");
-        OSStatus rux = SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(signerinfo,timeStampPolicy);
-        dprintf("SecCmsSignerInfoVerifyUnAuthAttrs Status: %ld\n", (long)rux);
-        if (rux)
-            goto loser;
-    }
-
-    if (vs == SecCmsVSBadSignature) {
-       /*
-        * XXX Change the generic error into our specific one, because
-        * in that case we get a better explanation out of the Security
-        * Advisor.  This is really a bug in our error strings (the
-        * "generic" error has a lousy/wrong message associated with it
-        * which assumes the signature verification was done for the
-        * purposes of checking the issuer signature on a certificate)
-        * but this is at least an easy workaround and/or in the
-        * Security Advisor, which specifically checks for the error
-        * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
-        * in that case but does not similarly check for
-        * SEC_ERROR_BAD_SIGNATURE.  It probably should, but then would
-        * probably say the wrong thing in the case that it *was* the
-        * certificate signature check that failed during the cert
-        * verification done above.  Our error handling is really a mess.
-        */
-       if (PORT_GetError() == SEC_ERROR_BAD_SIGNATURE)
-           PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
-    }
-
-    if (publickey != NULL)
-       CFRelease(publickey);
-
-    signerinfo->verificationStatus = vs;
-    dprintfRC("SecCmsSignerInfoVerify end: cerp %p cert.rc %d\n",
-           cert, (int)CFGetRetainCount(cert));
-
-    dprintf("verificationStatus: %d\n", vs);
-
-    return (vs == SecCmsVSGoodSignature) ? SECSuccess : SECFailure;
-
-loser:
-    if (publickey != NULL)
-       SECKEY_DestroyPublicKey (publickey);
-
-    dprintf("verificationStatus2: %d\n", vs);
-    signerinfo->verificationStatus = vs;
-
-    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
-    return SECFailure;
-}
-
-OSStatus
-SecCmsSignerInfoVerifyUnAuthAttrs(SecCmsSignerInfoRef signerinfo) {
-    return SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(signerinfo, NULL);
-}
-
-OSStatus
-SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(SecCmsSignerInfoRef signerinfo,CFTypeRef timeStampPolicy)
-{
-    /*
-        unAuthAttr is an array of attributes; we expect to
-        see just one: the timestamp blob. If we have an unAuthAttr,
-        but don't see a timestamp, return an error since we have
-        no other cases where this would be present.
-    */
-
-    SecCmsAttribute *attr = NULL;    
-    OSStatus status = SECFailure;
-    
-    require(signerinfo, xit);
-    attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->unAuthAttr,
-        SEC_OID_PKCS9_TIMESTAMP_TOKEN, PR_TRUE);
-    if (attr == NULL)
-    {
-        status = errSecTimestampMissing;
-        goto xit;
-    }
-
-    dprintf("found an id-ct-TSTInfo\n");
-    // Don't check the nonce in this case
-    status = decodeTimeStampTokenWithPolicy(signerinfo, timeStampPolicy, (attr->values)[0], &signerinfo->encDigest, 0);
-xit:
-    return status;
-}
-
-CSSM_DATA *
-SecCmsSignerInfoGetEncDigest(SecCmsSignerInfoRef signerinfo)
-{
-    return &signerinfo->encDigest;
-}
-
-SecCmsVerificationStatus
-SecCmsSignerInfoGetVerificationStatus(SecCmsSignerInfoRef signerinfo)
-{
-    return signerinfo->verificationStatus;
-}
-
-SECOidData *
-SecCmsSignerInfoGetDigestAlg(SecCmsSignerInfoRef signerinfo)
-{
-    return SECOID_FindOID (&(signerinfo->digestAlg.algorithm));
-}
-
-SECOidTag
-SecCmsSignerInfoGetDigestAlgTag(SecCmsSignerInfoRef signerinfo)
-{
-    SECOidData *algdata;
-
-    algdata = SECOID_FindOID (&(signerinfo->digestAlg.algorithm));
-    if (algdata != NULL)
-       return algdata->offset;
-    else
-       return SEC_OID_UNKNOWN;
-}
-
-CFArrayRef
-SecCmsSignerInfoGetCertList(SecCmsSignerInfoRef signerinfo)
-{
-    dprintfRC("SecCmsSignerInfoGetCertList: certList.rc %d\n",
-           (int)CFGetRetainCount(signerinfo->certList));
-    return signerinfo->certList;
-}
-
-CFArrayRef
-SecCmsSignerInfoGetTimestampCertList(SecCmsSignerInfoRef signerinfo)
-{
-    dprintfRC("SecCmsSignerInfoGetCertList: timestampCertList.rc %d\n",
-           (int)CFGetRetainCount(signerinfo->timestampCertList));
-    return signerinfo->timestampCertList;
-}
-
-
-
-int
-SecCmsSignerInfoGetVersion(SecCmsSignerInfoRef signerinfo)
-{
-    unsigned long version;
-
-    /* always take apart the CSSM_DATA */
-    if (SEC_ASN1DecodeInteger(&(signerinfo->version), &version) != SECSuccess)
-       return 0;
-    else
-       return (int)version;
-}
-
-/*
- * SecCmsSignerInfoGetSigningTime - return the signing 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
-SecCmsSignerInfoGetSigningTime(SecCmsSignerInfoRef sinfo, CFAbsoluteTime *stime)
-{
-    SecCmsAttribute *attr;
-    CSSM_DATA_PTR value;
-
-    if (sinfo == NULL)
-       return paramErr;
-
-    if (sinfo->signingTime != 0) {
-       *stime = sinfo->signingTime;    /* cached copy */
-       return SECSuccess;
-    }
-
-    attr = SecCmsAttributeArrayFindAttrByOidTag(sinfo->authAttr, SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
-    /* XXXX multi-valued attributes NIH */
-    if (attr == NULL || (value = SecCmsAttributeGetValue(attr)) == NULL)
-       return errSecSigningTimeMissing;
-    if (DER_UTCTimeToCFDate(value, stime) != SECSuccess)
-       return errSecSigningTimeMissing;
-    sinfo->signingTime = *stime;       /* make cached copy */
-    return SECSuccess;
-}
-
-OSStatus
-SecCmsSignerInfoGetTimestampTime(SecCmsSignerInfoRef sinfo, CFAbsoluteTime *stime)
-{
-    return SecCmsSignerInfoGetTimestampTimeWithPolicy(sinfo, NULL, stime);
-}
-
-OSStatus
-SecCmsSignerInfoGetTimestampTimeWithPolicy(SecCmsSignerInfoRef sinfo, CFTypeRef timeStampPolicy, CFAbsoluteTime *stime)
-{
-    OSStatus status = paramErr;
-    
-    require(sinfo && stime, xit);
-
-    if (sinfo->timestampTime != 0)
-    {
-       *stime = sinfo->timestampTime;  /* cached copy */
-       return noErr;
-    }
-
-    // A bit heavyweight if haven't already called verify
-    status = SecCmsSignerInfoVerifyUnAuthAttrsWithPolicy(sinfo,timeStampPolicy);
-    *stime = sinfo->timestampTime;
-xit:
-    return status;
-}
-
-/*
- * Return the signing cert of a CMS signerInfo.
- *
- * the certs in the enclosing SignedData must have been imported already
- */
-SecCertificateRef
-SecCmsSignerInfoGetSigningCertificate(SecCmsSignerInfoRef signerinfo, SecKeychainRef keychainOrArray)
-{
-    SecCertificateRef cert;
-    SecCmsSignerIdentifier *sid;
-    OSStatus ortn;
-    CSSM_DATA_PTR *rawCerts;
-    
-    if (signerinfo->cert != NULL) {
-       dprintfRC("SecCmsSignerInfoGetSigningCertificate top: cert %p cert.rc %d\n",
-           signerinfo->cert, (int)CFGetRetainCount(signerinfo->cert));
-       return signerinfo->cert;
-    }
-    ortn = SecCmsSignedDataRawCerts(signerinfo->sigd, &rawCerts);
-    if(ortn) {
-       return NULL;
-    }
-    dprintf("SecCmsSignerInfoGetSigningCertificate: numRawCerts %d\n", 
-       SecCmsArrayCount((void **)rawCerts));
-    
-    /*
-     * This cert will also need to be freed, but since we save it
-     * in signerinfo for later, we do not want to destroy it when
-     * we leave this function -- we let the clean-up of the entire
-     * cinfo structure later do the destroy of this cert.
-     */
-    sid = &signerinfo->signerIdentifier;
-    switch (sid->identifierType) {
-    case SecCmsSignerIDIssuerSN:
-       cert = CERT_FindCertByIssuerAndSN(keychainOrArray, rawCerts, signerinfo->cmsg->poolp,
-           sid->id.issuerAndSN);
-       break;
-    case SecCmsSignerIDSubjectKeyID:
-       cert = CERT_FindCertBySubjectKeyID(keychainOrArray, rawCerts, sid->id.subjectKeyID);
-       break;
-    default:
-       cert = NULL;
-       break;
-    }
-
-    /* cert can be NULL at that point */
-    signerinfo->cert = cert;   /* earmark it */
-    dprintfRC("SecCmsSignerInfoGetSigningCertificate end: certp %p cert.rc %d\n",
-           signerinfo->cert, (int)CFGetRetainCount(signerinfo->cert));
-
-    return cert;
-}
-
-/*
- * SecCmsSignerInfoGetSignerCommonName - return the common name of the signer
- *
- * sinfo - signerInfo data for this signer
- *
- * Returns a CFStringRef containing the common name of the signer.
- * A return value of NULL is an error.
- */
-CFStringRef
-SecCmsSignerInfoGetSignerCommonName(SecCmsSignerInfoRef sinfo)
-{
-    SecCertificateRef signercert;
-    CFStringRef commonName = NULL;
-    
-    /* will fail if cert is not verified */
-    if ((signercert = SecCmsSignerInfoGetSigningCertificate(sinfo, NULL)) == NULL)
-       return NULL;
-
-    SecCertificateCopyCommonName(signercert, &commonName);
-
-    return commonName;
-}
-
-/*
- * SecCmsSignerInfoGetSignerEmailAddress - return the email address of the signer
- *
- * sinfo - signerInfo data for this signer
- *
- * Returns a CFStringRef containing the name of the signer.
- * A return value of NULL is an error.
- */
-CFStringRef
-SecCmsSignerInfoGetSignerEmailAddress(SecCmsSignerInfoRef sinfo)
-{
-    SecCertificateRef signercert;
-    CFStringRef emailAddress = NULL;
-
-    if ((signercert = SecCmsSignerInfoGetSigningCertificate(sinfo, NULL)) == NULL)
-       return NULL;
-
-    SecCertificateGetEmailAddress(signercert, &emailAddress);
-
-    return emailAddress;
-}
-
-
-/*
- * SecCmsSignerInfoAddAuthAttr - add an attribute to the
- * authenticated (i.e. signed) attributes of "signerinfo". 
- */
-OSStatus
-SecCmsSignerInfoAddAuthAttr(SecCmsSignerInfoRef signerinfo, SecCmsAttribute *attr)
-{
-    return SecCmsAttributeArrayAddAttr(signerinfo->cmsg->poolp, &(signerinfo->authAttr), attr);
-}
-
-/*
- * SecCmsSignerInfoAddUnauthAttr - add an attribute to the
- * unauthenticated attributes of "signerinfo". 
- */
-OSStatus
-SecCmsSignerInfoAddUnauthAttr(SecCmsSignerInfoRef signerinfo, SecCmsAttribute *attr)
-{
-    return SecCmsAttributeArrayAddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr);
-}
-
-/* 
- * SecCmsSignerInfoAddSigningTime - add the signing time to the
- * authenticated (i.e. signed) attributes of "signerinfo". 
- *
- * This is expected to be included in outgoing signed
- * messages for email (S/MIME) but is likely useful in other situations.
- *
- * This should only be added once; a second call will do nothing.
- *
- * XXX This will probably just shove the current time into "signerinfo"
- * but it will not actually get signed until the entire item is
- * processed for encoding.  Is this (expected to be small) delay okay?
- */
-OSStatus
-SecCmsSignerInfoAddSigningTime(SecCmsSignerInfoRef signerinfo, CFAbsoluteTime t)
-{
-    SecCmsAttribute *attr;
-    CSSM_DATA stime;
-    void *mark;
-    PLArenaPool *poolp;
-
-    poolp = signerinfo->cmsg->poolp;
-
-    mark = PORT_ArenaMark(poolp);
-
-    /* create new signing time attribute */
-    if (DER_CFDateToUTCTime(t, &stime) != SECSuccess)
-       goto loser;
-
-    if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_PKCS9_SIGNING_TIME, &stime, PR_FALSE)) == NULL) {
-       SECITEM_FreeItem (&stime, PR_FALSE);
-       goto loser;
-    }
-
-    SECITEM_FreeItem (&stime, PR_FALSE);
-
-    if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess)
-       goto loser;
-
-    PORT_ArenaUnmark (poolp, mark);
-
-    return SECSuccess;
-
-loser:
-    PORT_ArenaRelease (poolp, mark);
-    return SECFailure;
-}
-
-/* 
- * SecCmsSignerInfoAddSMIMECaps - add a SMIMECapabilities attribute to the
- * authenticated (i.e. signed) attributes of "signerinfo". 
- *
- * This is expected to be included in outgoing signed
- * messages for email (S/MIME).
- */
-OSStatus
-SecCmsSignerInfoAddSMIMECaps(SecCmsSignerInfoRef signerinfo)
-{
-    SecCmsAttribute *attr;
-    CSSM_DATA_PTR smimecaps = NULL;
-    void *mark;
-    PLArenaPool *poolp;
-
-    poolp = signerinfo->cmsg->poolp;
-
-    mark = PORT_ArenaMark(poolp);
-
-    smimecaps = SECITEM_AllocItem(poolp, NULL, 0);
-    if (smimecaps == NULL)
-       goto loser;
-
-    /* create new signing time attribute */
-#if 1
-    // @@@ We don't do Fortezza yet.
-    if (SecSMIMECreateSMIMECapabilities((SecArenaPoolRef)poolp, smimecaps, PR_FALSE) != SECSuccess)
-#else
-    if (SecSMIMECreateSMIMECapabilities(poolp, smimecaps,
-                           PK11_FortezzaHasKEA(signerinfo->cert)) != SECSuccess)
-#endif
-       goto loser;
-
-    if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_PKCS9_SMIME_CAPABILITIES, smimecaps, PR_TRUE)) == NULL)
-       goto loser;
-
-    if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess)
-       goto loser;
-
-    PORT_ArenaUnmark (poolp, mark);
-    return SECSuccess;
-
-loser:
-    PORT_ArenaRelease (poolp, mark);
-    return SECFailure;
-}
-
-/* 
- * SecCmsSignerInfoAddSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
- * authenticated (i.e. signed) attributes of "signerinfo". 
- *
- * This is expected to be included in outgoing signed messages for email (S/MIME).
- */
-OSStatus
-SecCmsSignerInfoAddSMIMEEncKeyPrefs(SecCmsSignerInfoRef signerinfo, SecCertificateRef cert, SecKeychainRef keychainOrArray)
-{
-    SecCmsAttribute *attr;
-    CSSM_DATA_PTR smimeekp = NULL;
-    void *mark;
-    PLArenaPool *poolp;
-
-#if 0
-    CFTypeRef policy;
-
-    /* verify this cert for encryption */
-    policy = CERT_PolicyForCertUsage(certUsageEmailRecipient);
-    if (CERT_VerifyCert(keychainOrArray, cert, policy, CFAbsoluteTimeGetCurrent(), NULL) != SECSuccess) {
-       CFRelease(policy);
-       return SECFailure;
-    }
-    CFRelease(policy);
-#endif
-
-    poolp = signerinfo->cmsg->poolp;
-    mark = PORT_ArenaMark(poolp);
-
-    smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
-    if (smimeekp == NULL)
-       goto loser;
-
-    /* create new signing time attribute */
-    if (SecSMIMECreateSMIMEEncKeyPrefs((SecArenaPoolRef)poolp, smimeekp, cert) != SECSuccess)
-       goto loser;
-
-    if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
-       goto loser;
-
-    if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess)
-       goto loser;
-
-    PORT_ArenaUnmark (poolp, mark);
-    return SECSuccess;
-
-loser:
-    PORT_ArenaRelease (poolp, mark);
-    return SECFailure;
-}
-
-/* 
- * SecCmsSignerInfoAddMSSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
- * authenticated (i.e. signed) attributes of "signerinfo", using the OID prefered by Microsoft.
- *
- * This is expected to be included in outgoing signed messages for email (S/MIME),
- * if compatibility with Microsoft mail clients is wanted.
- */
-OSStatus
-SecCmsSignerInfoAddMSSMIMEEncKeyPrefs(SecCmsSignerInfoRef signerinfo, SecCertificateRef cert, SecKeychainRef keychainOrArray)
-{
-    SecCmsAttribute *attr;
-    CSSM_DATA_PTR smimeekp = NULL;
-    void *mark;
-    PLArenaPool *poolp;
-
-#if 0
-    CFTypeRef policy;
-
-    /* verify this cert for encryption */
-    policy = CERT_PolicyForCertUsage(certUsageEmailRecipient);
-    if (CERT_VerifyCert(keychainOrArray, cert, policy, CFAbsoluteTimeGetCurrent(), NULL) != SECSuccess) {
-       CFRelease(policy);
-       return SECFailure;
-    }
-    CFRelease(policy);
-#endif
-
-    poolp = signerinfo->cmsg->poolp;
-    mark = PORT_ArenaMark(poolp);
-
-    smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
-    if (smimeekp == NULL)
-       goto loser;
-
-    /* create new signing time attribute */
-    if (SecSMIMECreateMSSMIMEEncKeyPrefs((SecArenaPoolRef)poolp, smimeekp, cert) != SECSuccess)
-       goto loser;
-
-    if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
-       goto loser;
-
-    if (SecCmsSignerInfoAddAuthAttr(signerinfo, attr) != SECSuccess)
-       goto loser;
-
-    PORT_ArenaUnmark (poolp, mark);
-    return SECSuccess;
-
-loser:
-    PORT_ArenaRelease (poolp, mark);
-    return SECFailure;
-}
-
-/* 
- * SecCmsSignerInfoAddTimeStamp - add time stamp to the
- * unauthenticated (i.e. unsigned) attributes of "signerinfo". 
- *
- * This will initially be used for time stamping signed applications
- * by using a Time Stamping Authority. It may also be included in outgoing signed
- * messages for email (S/MIME), and may be useful in other situations.
- *
- * This should only be added once; a second call will do nothing.
- *
- */
-/*
-Countersignature attribute values have ASN.1 type Countersignature:
-      Countersignature ::= SignerInfo
-   Countersignature values have the same meaning as SignerInfo values
-   for ordinary signatures, except that:
-   1.  The signedAttributes field MUST NOT contain a content-type
-       attribute; there is no content type for countersignatures.
-   2.  The signedAttributes field MUST contain a message-digest
-       attribute if it contains any other attributes.
-   3.  The input to the message-digesting process is the contents octets
-       of the DER encoding of the signatureValue field of the SignerInfo
-       value with which the attribute is associated.
-*/
-
-/*!
-    @function
-    @abstract Create a timestamp unsigned attribute with a TimeStampToken.
-*/
-
-OSStatus
-SecCmsSignerInfoAddTimeStamp(SecCmsSignerInfoRef signerinfo, CSSM_DATA *tstoken)
-{
-    SecCmsAttribute *attr;
-    PLArenaPool *poolp = signerinfo->cmsg->poolp;
-    void *mark = PORT_ArenaMark(poolp);
-
-    // We have already encoded this ourselves, so last param is PR_TRUE
-    if ((attr = SecCmsAttributeCreate(poolp, SEC_OID_PKCS9_TIMESTAMP_TOKEN, tstoken, PR_TRUE)) == NULL)
-        goto loser;
-
-    if (SecCmsSignerInfoAddUnauthAttr(signerinfo, attr) != SECSuccess)
-       goto loser;
-
-    PORT_ArenaUnmark (poolp, mark);
-
-    return SECSuccess;
-
-loser:
-    PORT_ArenaRelease (poolp, mark);
-    return SECFailure;
-}
-
-/* 
- * SecCmsSignerInfoAddCounterSignature - countersign a signerinfo
- *
- * 1. digest the DER-encoded signature value of the original signerinfo
- * 2. create new signerinfo with correct version, sid, digestAlg
- * 3. add message-digest authAttr, but NO content-type
- * 4. sign the authAttrs
- * 5. DER-encode the new signerInfo
- * 6. add the whole thing to original signerInfo's unAuthAttrs
- *    as a SEC_OID_PKCS9_COUNTER_SIGNATURE attribute
- *
- * XXXX give back the new signerinfo?
- */
-OSStatus
-SecCmsSignerInfoAddCounterSignature(SecCmsSignerInfoRef signerinfo,
-                                   SECOidTag digestalg, SecIdentityRef identity)
-{
-    /* XXXX TBD XXXX */
-    return SECFailure;
-}
-
-/*
- * XXXX the following needs to be done in the S/MIME layer code
- * after signature of a signerinfo is verified
- */
-OSStatus
-SecCmsSignerInfoSaveSMIMEProfile(SecCmsSignerInfoRef signerinfo)
-{
-    SecCertificateRef cert = NULL;
-    CSSM_DATA_PTR profile = NULL;
-    SecCmsAttribute *attr;
-    CSSM_DATA_PTR utc_stime = NULL;
-    CSSM_DATA_PTR ekp;
-    int save_error;
-    OSStatus rv;
-    Boolean must_free_cert = PR_FALSE;
-    OSStatus status;
-    SecKeychainRef keychainOrArray;
-    
-    status = SecKeychainCopyDefault(&keychainOrArray);
-
-    /* sanity check - see if verification status is ok (unverified does not count...) */
-    if (signerinfo->verificationStatus != SecCmsVSGoodSignature)
-        return SECFailure;
-
-    /* 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! */
-       ekp = SecCmsAttributeGetValue(attr);
-       if (ekp == NULL)
-           return SECFailure;
-
-       /* we assume that all certs coming with the message have been imported to the */
-       /* temporary database */
-       cert = SecSMIMEGetCertFromEncryptionKeyPreference(keychainOrArray, ekp);
-       if (cert == NULL)
-           return SECFailure;
-       must_free_cert = PR_TRUE;
-    }
-
-    if (cert == NULL) {
-       /* no preferred cert found?
-        * find the cert the signerinfo is signed with instead */
-       CFStringRef emailAddress=NULL;
-
-       cert = SecCmsSignerInfoGetSigningCertificate(signerinfo, keychainOrArray);
-       if (cert == NULL)
-           return SECFailure;
-       if (SecCertificateGetEmailAddress(cert,&emailAddress))
-           return SECFailure;
-    }
-
-    /* verify this cert for encryption (has been verified for signing so far) */    /* don't verify this cert for encryption. It may just be a signing cert.
-     * that's OK, we can still save the S/MIME profile. The encryption cert
-     * should have already been saved */
-#ifdef notdef
-    if (CERT_VerifyCert(keychainOrArray, cert, certUsageEmailRecipient, CFAbsoluteTimeGetCurrent(), NULL) != SECSuccess) {
-       if (must_free_cert)
-           CERT_DestroyCertificate(cert);
-       return SECFailure;
-    }
-#endif
-
-    /* XXX store encryption cert permanently? */
-
-    /*
-     * Remember the current error set because we do not care about
-     * anything set by the functions we are about to call.
-     */
-    save_error = PORT_GetError();
-
-    if (!SecCmsArrayIsEmpty((void **)signerinfo->authAttr)) {
-       attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr,
-                                      SEC_OID_PKCS9_SMIME_CAPABILITIES,
-                                      PR_TRUE);
-       profile = SecCmsAttributeGetValue(attr);
-       attr = SecCmsAttributeArrayFindAttrByOidTag(signerinfo->authAttr,
-                                      SEC_OID_PKCS9_SIGNING_TIME,
-                                      PR_TRUE);
-       utc_stime = SecCmsAttributeGetValue(attr);
-    }
-
-    rv = CERT_SaveSMimeProfile (cert, profile, utc_stime);
-    if (must_free_cert)
-       CERT_DestroyCertificate(cert);
-
-    /*
-     * Restore the saved error in case the calls above set a new
-     * one that we do not actually care about.
-     */
-    PORT_SetError (save_error);
-
-    return rv;
-}
-
-/*
- * SecCmsSignerInfoIncludeCerts - set cert chain inclusion mode for this signer
- */
-OSStatus
-SecCmsSignerInfoIncludeCerts(SecCmsSignerInfoRef signerinfo, SecCmsCertChainMode cm, SECCertUsage usage)
-{
-    if (signerinfo->cert == NULL)
-       return SECFailure;
-
-    /* don't leak if we get called twice */
-    if (signerinfo->certList != NULL) {
-       CFRelease(signerinfo->certList);
-       signerinfo->certList = NULL;
-    }
-
-    switch (cm) {
-    case SecCmsCMNone:
-       signerinfo->certList = NULL;
-       break;
-    case SecCmsCMCertOnly:
-       signerinfo->certList = CERT_CertListFromCert(signerinfo->cert);
-       break;
-    case SecCmsCMCertChain:
-       signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_FALSE);
-       break;
-    case SecCmsCMCertChainWithRoot:
-       signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_TRUE);
-       break;
-    }
-
-    if (cm != SecCmsCMNone && signerinfo->certList == NULL)
-       return SECFailure;
-    
-    return SECSuccess;
-}