+++ /dev/null
-/*
- * 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;
-}