security/nss/lib/smime/cmssiginfo.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/smime/cmssiginfo.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1014 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/*
     1.9 + * CMS signerInfo methods.
    1.10 + */
    1.11 +
    1.12 +#include "cmslocal.h"
    1.13 +
    1.14 +#include "cert.h"
    1.15 +#include "key.h"
    1.16 +#include "secasn1.h"
    1.17 +#include "secitem.h"
    1.18 +#include "secoid.h"
    1.19 +#include "pk11func.h"
    1.20 +#include "prtime.h"
    1.21 +#include "secerr.h"
    1.22 +#include "secder.h"
    1.23 +#include "cryptohi.h"
    1.24 +
    1.25 +#include "smime.h"
    1.26 +
    1.27 +/* =============================================================================
    1.28 + * SIGNERINFO
    1.29 + */
    1.30 +NSSCMSSignerInfo *
    1.31 +nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type, 
    1.32 +	CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey, 
    1.33 +	SECKEYPrivateKey *signingKey, SECOidTag digestalgtag);
    1.34 +
    1.35 +NSSCMSSignerInfo *
    1.36 +NSS_CMSSignerInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg, SECItem *subjKeyID, 
    1.37 +	SECKEYPublicKey *pubKey, SECKEYPrivateKey *signingKey, SECOidTag digestalgtag)
    1.38 +{
    1.39 +    return nss_cmssignerinfo_create(cmsg, NSSCMSSignerID_SubjectKeyID, NULL, subjKeyID, pubKey, signingKey, digestalgtag); 
    1.40 +}
    1.41 +
    1.42 +NSSCMSSignerInfo *
    1.43 +NSS_CMSSignerInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert, SECOidTag digestalgtag)
    1.44 +{
    1.45 +    return nss_cmssignerinfo_create(cmsg, NSSCMSSignerID_IssuerSN, cert, NULL, NULL, NULL, digestalgtag); 
    1.46 +}
    1.47 +
    1.48 +NSSCMSSignerInfo *
    1.49 +nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type, 
    1.50 +	CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey, 
    1.51 +	SECKEYPrivateKey *signingKey, SECOidTag digestalgtag)
    1.52 +{
    1.53 +    void *mark;
    1.54 +    NSSCMSSignerInfo *signerinfo;
    1.55 +    int version;
    1.56 +    PLArenaPool *poolp;
    1.57 +
    1.58 +    poolp = cmsg->poolp;
    1.59 +
    1.60 +    mark = PORT_ArenaMark(poolp);
    1.61 +
    1.62 +    signerinfo = (NSSCMSSignerInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSSignerInfo));
    1.63 +    if (signerinfo == NULL) {
    1.64 +	PORT_ArenaRelease(poolp, mark);
    1.65 +	return NULL;
    1.66 +    }
    1.67 +
    1.68 +
    1.69 +    signerinfo->cmsg = cmsg;
    1.70 +
    1.71 +    switch(type) {
    1.72 +    case NSSCMSSignerID_IssuerSN:
    1.73 +        signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_IssuerSN;
    1.74 +        if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL)
    1.75 +	    goto loser;
    1.76 +        if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL)
    1.77 +	    goto loser;
    1.78 +        break;
    1.79 +    case NSSCMSSignerID_SubjectKeyID:
    1.80 +        signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_SubjectKeyID;
    1.81 +        PORT_Assert(subjKeyID);
    1.82 +        if (!subjKeyID)
    1.83 +            goto loser;
    1.84 +
    1.85 +        signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
    1.86 +        SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
    1.87 +                         subjKeyID);
    1.88 +        signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey);
    1.89 +        if (!signerinfo->signingKey)
    1.90 +            goto loser;
    1.91 +        signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey);
    1.92 +        if (!signerinfo->pubKey)
    1.93 +            goto loser;
    1.94 +        break;
    1.95 +    default:
    1.96 +        goto loser;
    1.97 +    }
    1.98 +
    1.99 +    /* set version right now */
   1.100 +    version = NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN;
   1.101 +    /* RFC2630 5.3 "version is the syntax version number. If the .... " */
   1.102 +    if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID)
   1.103 +	version = NSS_CMS_SIGNER_INFO_VERSION_SUBJKEY;
   1.104 +    (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version);
   1.105 +
   1.106 +    if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess)
   1.107 +	goto loser;
   1.108 +
   1.109 +    PORT_ArenaUnmark(poolp, mark);
   1.110 +    return signerinfo;
   1.111 +
   1.112 +loser:
   1.113 +    PORT_ArenaRelease(poolp, mark);
   1.114 +    return NULL;
   1.115 +}
   1.116 +
   1.117 +/*
   1.118 + * NSS_CMSSignerInfo_Destroy - destroy a SignerInfo data structure
   1.119 + */
   1.120 +void
   1.121 +NSS_CMSSignerInfo_Destroy(NSSCMSSignerInfo *si)
   1.122 +{
   1.123 +    if (si->cert != NULL)
   1.124 +	CERT_DestroyCertificate(si->cert);
   1.125 +
   1.126 +    if (si->certList != NULL) 
   1.127 +	CERT_DestroyCertificateList(si->certList);
   1.128 +
   1.129 +    /* XXX storage ??? */
   1.130 +}
   1.131 +
   1.132 +/*
   1.133 + * NSS_CMSSignerInfo_Sign - sign something
   1.134 + *
   1.135 + */
   1.136 +SECStatus
   1.137 +NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest, 
   1.138 +                       SECItem *contentType)
   1.139 +{
   1.140 +    CERTCertificate *cert;
   1.141 +    SECKEYPrivateKey *privkey = NULL;
   1.142 +    SECOidTag digestalgtag;
   1.143 +    SECOidTag pubkAlgTag;
   1.144 +    SECItem signature = { 0 };
   1.145 +    SECStatus rv;
   1.146 +    PLArenaPool *poolp, *tmppoolp = NULL;
   1.147 +    SECAlgorithmID *algID, freeAlgID;
   1.148 +    CERTSubjectPublicKeyInfo *spki;
   1.149 +
   1.150 +    PORT_Assert (digest != NULL);
   1.151 +
   1.152 +    poolp = signerinfo->cmsg->poolp;
   1.153 +
   1.154 +    switch (signerinfo->signerIdentifier.identifierType) {
   1.155 +    case NSSCMSSignerID_IssuerSN:
   1.156 +        cert = signerinfo->cert;
   1.157 +
   1.158 +        privkey = PK11_FindKeyByAnyCert(cert, signerinfo->cmsg->pwfn_arg);
   1.159 +        if (privkey == NULL)
   1.160 +	    goto loser;
   1.161 +        algID = &cert->subjectPublicKeyInfo.algorithm;
   1.162 +        break;
   1.163 +    case NSSCMSSignerID_SubjectKeyID:
   1.164 +        privkey = signerinfo->signingKey;
   1.165 +        signerinfo->signingKey = NULL;
   1.166 +        spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey);
   1.167 +        SECKEY_DestroyPublicKey(signerinfo->pubKey);
   1.168 +        signerinfo->pubKey = NULL;
   1.169 +        SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm);
   1.170 +        SECKEY_DestroySubjectPublicKeyInfo(spki); 
   1.171 +        algID = &freeAlgID;
   1.172 +        break;
   1.173 +    default:
   1.174 +        goto loser;
   1.175 +    }
   1.176 +    digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
   1.177 +    /*
   1.178 +     * XXX I think there should be a cert-level interface for this,
   1.179 +     * so that I do not have to know about subjectPublicKeyInfo...
   1.180 +     */
   1.181 +    pubkAlgTag = SECOID_GetAlgorithmTag(algID);
   1.182 +    if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID) {
   1.183 +      SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE);
   1.184 +    }
   1.185 +
   1.186 +    if (signerinfo->authAttr != NULL) {
   1.187 +	SECOidTag signAlgTag;
   1.188 +	SECItem encoded_attrs;
   1.189 +
   1.190 +	/* find and fill in the message digest attribute. */
   1.191 +	rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr), 
   1.192 +	                       SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE);
   1.193 +	if (rv != SECSuccess)
   1.194 +	    goto loser;
   1.195 +
   1.196 +	if (contentType != NULL) {
   1.197 +	    /* if the caller wants us to, find and fill in the content type attribute. */
   1.198 +	    rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr), 
   1.199 +	                    SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE);
   1.200 +	    if (rv != SECSuccess)
   1.201 +		goto loser;
   1.202 +	}
   1.203 +
   1.204 +	if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
   1.205 +	    PORT_SetError(SEC_ERROR_NO_MEMORY);
   1.206 +	    goto loser;
   1.207 +	}
   1.208 +
   1.209 +	/*
   1.210 +	 * Before encoding, reorder the attributes so that when they
   1.211 +	 * are encoded, they will be conforming DER, which is required
   1.212 +	 * to have a specific order and that is what must be used for
   1.213 +	 * the hash/signature.  We do this here, rather than building
   1.214 +	 * it into EncodeAttributes, because we do not want to do
   1.215 +	 * such reordering on incoming messages (which also uses
   1.216 +	 * EncodeAttributes) or our old signatures (and other "broken"
   1.217 +	 * implementations) will not verify.  So, we want to guarantee
   1.218 +	 * that we send out good DER encodings of attributes, but not
   1.219 +	 * to expect to receive them.
   1.220 +	 */
   1.221 +	if (NSS_CMSAttributeArray_Reorder(signerinfo->authAttr) != SECSuccess)
   1.222 +	    goto loser;
   1.223 +
   1.224 +	encoded_attrs.data = NULL;
   1.225 +	encoded_attrs.len = 0;
   1.226 +	if (NSS_CMSAttributeArray_Encode(tmppoolp, &(signerinfo->authAttr), 
   1.227 +	                &encoded_attrs) == NULL)
   1.228 +	    goto loser;
   1.229 +
   1.230 +	signAlgTag = SEC_GetSignatureAlgorithmOidTag(privkey->keyType, 
   1.231 +                                                     digestalgtag);
   1.232 +	if (signAlgTag == SEC_OID_UNKNOWN) {
   1.233 +	    PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
   1.234 +	    goto loser;
   1.235 +	}
   1.236 +
   1.237 +	rv = SEC_SignData(&signature, encoded_attrs.data, encoded_attrs.len, 
   1.238 +	                  privkey, signAlgTag);
   1.239 +	PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */
   1.240 +	tmppoolp = 0;
   1.241 +    } else {
   1.242 +	rv = SGN_Digest(privkey, digestalgtag, &signature, digest);
   1.243 +    }
   1.244 +    SECKEY_DestroyPrivateKey(privkey);
   1.245 +    privkey = NULL;
   1.246 +
   1.247 +    if (rv != SECSuccess)
   1.248 +	goto loser;
   1.249 +
   1.250 +    if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature) 
   1.251 +          != SECSuccess)
   1.252 +	goto loser;
   1.253 +
   1.254 +    SECITEM_FreeItem(&signature, PR_FALSE);
   1.255 +
   1.256 +    if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag, 
   1.257 +                              NULL) != SECSuccess)
   1.258 +	goto loser;
   1.259 +
   1.260 +    return SECSuccess;
   1.261 +
   1.262 +loser:
   1.263 +    if (signature.len != 0)
   1.264 +	SECITEM_FreeItem (&signature, PR_FALSE);
   1.265 +    if (privkey)
   1.266 +	SECKEY_DestroyPrivateKey(privkey);
   1.267 +    if (tmppoolp)
   1.268 +	PORT_FreeArena(tmppoolp, PR_FALSE);
   1.269 +    return SECFailure;
   1.270 +}
   1.271 +
   1.272 +SECStatus
   1.273 +NSS_CMSSignerInfo_VerifyCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb,
   1.274 +			    SECCertUsage certusage)
   1.275 +{
   1.276 +    CERTCertificate *cert;
   1.277 +    PRTime stime;
   1.278 +
   1.279 +    if ((cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, certdb)) == NULL) {
   1.280 +	signerinfo->verificationStatus = NSSCMSVS_SigningCertNotFound;
   1.281 +	return SECFailure;
   1.282 +    }
   1.283 +
   1.284 +    /*
   1.285 +     * Get and convert the signing time; if available, it will be used
   1.286 +     * both on the cert verification and for importing the sender
   1.287 +     * email profile.
   1.288 +     */
   1.289 +    if (NSS_CMSSignerInfo_GetSigningTime (signerinfo, &stime) != SECSuccess)
   1.290 +	stime = PR_Now(); /* not found or conversion failed, so check against now */
   1.291 +    
   1.292 +    /*
   1.293 +     * XXX  This uses the signing time, if available.  Additionally, we
   1.294 +     * might want to, if there is no signing time, get the message time
   1.295 +     * from the mail header itself, and use that.  That would require
   1.296 +     * a change to our interface though, and for S/MIME callers to pass
   1.297 +     * in a time (and for non-S/MIME callers to pass in nothing, or
   1.298 +     * maybe make them pass in the current time, always?).
   1.299 +     */
   1.300 +    if (CERT_VerifyCert(certdb, cert, PR_TRUE, certusage, stime, 
   1.301 +                        signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
   1.302 +	signerinfo->verificationStatus = NSSCMSVS_SigningCertNotTrusted;
   1.303 +	return SECFailure;
   1.304 +    }
   1.305 +    return SECSuccess;
   1.306 +}
   1.307 +
   1.308 +/*
   1.309 + * NSS_CMSSignerInfo_Verify - verify the signature of a single SignerInfo
   1.310 + *
   1.311 + * Just verifies the signature. The assumption is that verification of 
   1.312 + * the certificate is done already.
   1.313 + */
   1.314 +SECStatus
   1.315 +NSS_CMSSignerInfo_Verify(NSSCMSSignerInfo *signerinfo, 
   1.316 +                         SECItem *digest,               /* may be NULL */
   1.317 +                         SECItem *contentType)          /* may be NULL */
   1.318 +{
   1.319 +    SECKEYPublicKey *publickey = NULL;
   1.320 +    NSSCMSAttribute *attr;
   1.321 +    SECItem encoded_attrs;
   1.322 +    CERTCertificate *cert;
   1.323 +    NSSCMSVerificationStatus vs = NSSCMSVS_Unverified;
   1.324 +    PLArenaPool *poolp;
   1.325 +    SECOidTag    digestalgtag;
   1.326 +    SECOidTag    pubkAlgTag;
   1.327 +
   1.328 +    if (signerinfo == NULL)
   1.329 +	return SECFailure;
   1.330 +
   1.331 +    /* NSS_CMSSignerInfo_GetSigningCertificate will fail if 2nd parm is NULL 
   1.332 +    ** and cert has not been verified 
   1.333 +    */
   1.334 +    cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, NULL);
   1.335 +    if (cert == NULL) {
   1.336 +	vs = NSSCMSVS_SigningCertNotFound;
   1.337 +	goto loser;
   1.338 +    }
   1.339 +
   1.340 +    if ((publickey = CERT_ExtractPublicKey(cert)) == NULL) {
   1.341 +	vs = NSSCMSVS_ProcessingError;
   1.342 +	goto loser;
   1.343 +    }
   1.344 +
   1.345 +    digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
   1.346 +    pubkAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg));
   1.347 +    if ((pubkAlgTag == SEC_OID_UNKNOWN) || (digestalgtag == SEC_OID_UNKNOWN)) {
   1.348 +	vs = NSSCMSVS_SignatureAlgorithmUnknown;
   1.349 +	goto loser;
   1.350 +    }
   1.351 +
   1.352 +    if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) {
   1.353 +	if (contentType) {
   1.354 +	    /*
   1.355 +	     * Check content type
   1.356 +	     *
   1.357 +	     * RFC2630 sez that if there are any authenticated attributes,
   1.358 +	     * then there must be one for content type which matches the
   1.359 +	     * content type of the content being signed, and there must
   1.360 +	     * be one for message digest which matches our message digest.
   1.361 +	     * So check these things first.
   1.362 +	     */
   1.363 +	    attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
   1.364 +					SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE);
   1.365 +	    if (attr == NULL) {
   1.366 +		vs = NSSCMSVS_MalformedSignature;
   1.367 +		goto loser;
   1.368 +	    }
   1.369 +		
   1.370 +	    if (NSS_CMSAttribute_CompareValue(attr, contentType) == PR_FALSE) {
   1.371 +		vs = NSSCMSVS_MalformedSignature;
   1.372 +		goto loser;
   1.373 +	    }
   1.374 +	}
   1.375 +
   1.376 +	/*
   1.377 +	 * Check digest
   1.378 +	 */
   1.379 +	attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr, 
   1.380 +	                              SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE);
   1.381 +	if (attr == NULL) {
   1.382 +	    vs = NSSCMSVS_MalformedSignature;
   1.383 +	    goto loser;
   1.384 +	}
   1.385 +	if (!digest || 
   1.386 +	    NSS_CMSAttribute_CompareValue(attr, digest) == PR_FALSE) {
   1.387 +	    vs = NSSCMSVS_DigestMismatch;
   1.388 +	    goto loser;
   1.389 +	}
   1.390 +
   1.391 +	if ((poolp = PORT_NewArena (1024)) == NULL) {
   1.392 +	    vs = NSSCMSVS_ProcessingError;
   1.393 +	    goto loser;
   1.394 +	}
   1.395 +
   1.396 +	/*
   1.397 +	 * Check signature
   1.398 +	 *
   1.399 +	 * The signature is based on a digest of the DER-encoded authenticated
   1.400 +	 * attributes.  So, first we encode and then we digest/verify.
   1.401 +	 * we trust the decoder to have the attributes in the right (sorted) 
   1.402 +	 * order
   1.403 +	 */
   1.404 +	encoded_attrs.data = NULL;
   1.405 +	encoded_attrs.len = 0;
   1.406 +
   1.407 +	if (NSS_CMSAttributeArray_Encode(poolp, &(signerinfo->authAttr), 
   1.408 +	                                 &encoded_attrs) == NULL ||
   1.409 +		encoded_attrs.data == NULL || encoded_attrs.len == 0) {
   1.410 +	    vs = NSSCMSVS_ProcessingError;
   1.411 +	    goto loser;
   1.412 +	}
   1.413 +
   1.414 +	vs = (VFY_VerifyDataDirect(encoded_attrs.data, encoded_attrs.len,
   1.415 +		publickey, &(signerinfo->encDigest), pubkAlgTag,
   1.416 +		digestalgtag, NULL, signerinfo->cmsg->pwfn_arg) != SECSuccess) 
   1.417 +		? NSSCMSVS_BadSignature : NSSCMSVS_GoodSignature;
   1.418 +
   1.419 +	PORT_FreeArena(poolp, PR_FALSE);  /* awkward memory management :-( */
   1.420 +
   1.421 +    } else {
   1.422 +	SECItem *sig;
   1.423 +
   1.424 +	/* No authenticated attributes. 
   1.425 +	** The signature is based on the plain message digest. 
   1.426 +	*/
   1.427 +	sig = &(signerinfo->encDigest);
   1.428 +	if (sig->len == 0)
   1.429 +	    goto loser;
   1.430 +
   1.431 +	vs = (!digest || 
   1.432 +	      VFY_VerifyDigestDirect(digest, publickey, sig, pubkAlgTag,
   1.433 +		digestalgtag, signerinfo->cmsg->pwfn_arg) != SECSuccess) 
   1.434 +		? NSSCMSVS_BadSignature : NSSCMSVS_GoodSignature;
   1.435 +    }
   1.436 +
   1.437 +    if (vs == NSSCMSVS_BadSignature) {
   1.438 +	int error = PORT_GetError();
   1.439 +	/*
   1.440 +	 * XXX Change the generic error into our specific one, because
   1.441 +	 * in that case we get a better explanation out of the Security
   1.442 +	 * Advisor.  This is really a bug in the PSM error strings (the
   1.443 +	 * "generic" error has a lousy/wrong message associated with it
   1.444 +	 * which assumes the signature verification was done for the
   1.445 +	 * purposes of checking the issuer signature on a certificate)
   1.446 +	 * but this is at least an easy workaround and/or in the
   1.447 +	 * Security Advisor, which specifically checks for the error
   1.448 +	 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
   1.449 +	 * in that case but does not similarly check for
   1.450 +	 * SEC_ERROR_BAD_SIGNATURE.  It probably should, but then would
   1.451 +	 * probably say the wrong thing in the case that it *was* the
   1.452 +	 * certificate signature check that failed during the cert
   1.453 +	 * verification done above.  Our error handling is really a mess.
   1.454 +	 */
   1.455 +	if (error == SEC_ERROR_BAD_SIGNATURE)
   1.456 +	    PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
   1.457 +	/*
   1.458 +	 * map algorithm failures to NSSCMSVS values 
   1.459 +	 */
   1.460 +	if ((error == SEC_ERROR_PKCS7_KEYALG_MISMATCH) ||
   1.461 +	    (error == SEC_ERROR_INVALID_ALGORITHM)) {
   1.462 +	    /* keep the same error code as 3.11 and before */
   1.463 +	    PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
   1.464 +	    vs = NSSCMSVS_SignatureAlgorithmUnsupported;
   1.465 +	}
   1.466 +    }
   1.467 +
   1.468 +    if (publickey != NULL)
   1.469 +	SECKEY_DestroyPublicKey (publickey);
   1.470 +
   1.471 +    signerinfo->verificationStatus = vs;
   1.472 +
   1.473 +    return (vs == NSSCMSVS_GoodSignature) ? SECSuccess : SECFailure;
   1.474 +
   1.475 +loser:
   1.476 +    if (publickey != NULL)
   1.477 +	SECKEY_DestroyPublicKey (publickey);
   1.478 +
   1.479 +    signerinfo->verificationStatus = vs;
   1.480 +
   1.481 +    PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
   1.482 +    return SECFailure;
   1.483 +}
   1.484 +
   1.485 +NSSCMSVerificationStatus
   1.486 +NSS_CMSSignerInfo_GetVerificationStatus(NSSCMSSignerInfo *signerinfo)
   1.487 +{
   1.488 +    return signerinfo->verificationStatus;
   1.489 +}
   1.490 +
   1.491 +SECOidData *
   1.492 +NSS_CMSSignerInfo_GetDigestAlg(NSSCMSSignerInfo *signerinfo)
   1.493 +{
   1.494 +    SECOidData *algdata;
   1.495 +    SECOidTag   algtag;
   1.496 +
   1.497 +    algdata = SECOID_FindOID (&(signerinfo->digestAlg.algorithm));
   1.498 +    if (algdata == NULL) {
   1.499 +	return algdata;
   1.500 +    }
   1.501 +    /* Windows may have given us a signer algorithm oid instead of a digest 
   1.502 +     * algorithm oid. This call will map to a signer oid to a digest one, 
   1.503 +     * otherwise it leaves the oid alone and let the chips fall as they may
   1.504 +     * if it's not a digest oid.
   1.505 +     */
   1.506 +    algtag = NSS_CMSUtil_MapSignAlgs(algdata->offset);
   1.507 +    if (algtag != algdata->offset) {
   1.508 +	/* if the tags don't match, then we must have received a signer 
   1.509 +	 * algorithID. Now we need to get the oid data for the digest
   1.510 +	 * oid, which the rest of the code is expecting */
   1.511 +	algdata = SECOID_FindOIDByTag(algtag);
   1.512 +    }
   1.513 +
   1.514 +    return algdata;
   1.515 +
   1.516 +}
   1.517 +
   1.518 +SECOidTag
   1.519 +NSS_CMSSignerInfo_GetDigestAlgTag(NSSCMSSignerInfo *signerinfo)
   1.520 +{
   1.521 +    SECOidData *algdata;
   1.522 +
   1.523 +    if (!signerinfo) {
   1.524 +        PORT_SetError(SEC_ERROR_INVALID_ARGS);
   1.525 +        return SEC_OID_UNKNOWN;
   1.526 +    }
   1.527 +
   1.528 +    algdata = NSS_CMSSignerInfo_GetDigestAlg(signerinfo);
   1.529 +    if (algdata != NULL)
   1.530 +	return algdata->offset;
   1.531 +    else
   1.532 +	return SEC_OID_UNKNOWN;
   1.533 +}
   1.534 +
   1.535 +CERTCertificateList *
   1.536 +NSS_CMSSignerInfo_GetCertList(NSSCMSSignerInfo *signerinfo)
   1.537 +{
   1.538 +    return signerinfo->certList;
   1.539 +}
   1.540 +
   1.541 +int
   1.542 +NSS_CMSSignerInfo_GetVersion(NSSCMSSignerInfo *signerinfo)
   1.543 +{
   1.544 +    unsigned long version;
   1.545 +
   1.546 +    /* always take apart the SECItem */
   1.547 +    if (SEC_ASN1DecodeInteger(&(signerinfo->version), &version) != SECSuccess)
   1.548 +	return 0;
   1.549 +    else
   1.550 +	return (int)version;
   1.551 +}
   1.552 +
   1.553 +/*
   1.554 + * NSS_CMSSignerInfo_GetSigningTime - return the signing time,
   1.555 + *				      in UTCTime or GeneralizedTime format,
   1.556 + *                                    of a CMS signerInfo.
   1.557 + *
   1.558 + * sinfo - signerInfo data for this signer
   1.559 + *
   1.560 + * Returns a pointer to XXXX (what?)
   1.561 + * A return value of NULL is an error.
   1.562 + */
   1.563 +SECStatus
   1.564 +NSS_CMSSignerInfo_GetSigningTime(NSSCMSSignerInfo *sinfo, PRTime *stime)
   1.565 +{
   1.566 +    NSSCMSAttribute *attr;
   1.567 +    SECItem *value;
   1.568 +
   1.569 +    if (sinfo == NULL)
   1.570 +	return SECFailure;
   1.571 +
   1.572 +    if (sinfo->signingTime != 0) {
   1.573 +	*stime = sinfo->signingTime;	/* cached copy */
   1.574 +	return SECSuccess;
   1.575 +    }
   1.576 +
   1.577 +    attr = NSS_CMSAttributeArray_FindAttrByOidTag(sinfo->authAttr, SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
   1.578 +    /* XXXX multi-valued attributes NIH */
   1.579 +    if (attr == NULL || (value = NSS_CMSAttribute_GetValue(attr)) == NULL)
   1.580 +	return SECFailure;
   1.581 +    if (DER_DecodeTimeChoice(stime, value) != SECSuccess)
   1.582 +	return SECFailure;
   1.583 +    sinfo->signingTime = *stime;	/* make cached copy */
   1.584 +    return SECSuccess;
   1.585 +}
   1.586 +
   1.587 +/*
   1.588 + * Return the signing cert of a CMS signerInfo.
   1.589 + *
   1.590 + * the certs in the enclosing SignedData must have been imported already
   1.591 + */
   1.592 +CERTCertificate *
   1.593 +NSS_CMSSignerInfo_GetSigningCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb)
   1.594 +{
   1.595 +    CERTCertificate *cert;
   1.596 +    NSSCMSSignerIdentifier *sid;
   1.597 +
   1.598 +    if (signerinfo->cert != NULL)
   1.599 +	return signerinfo->cert;
   1.600 +
   1.601 +    /* no certdb, and cert hasn't been set yet? */
   1.602 +    if (certdb == NULL)
   1.603 +	return NULL;
   1.604 +
   1.605 +    /*
   1.606 +     * This cert will also need to be freed, but since we save it
   1.607 +     * in signerinfo for later, we do not want to destroy it when
   1.608 +     * we leave this function -- we let the clean-up of the entire
   1.609 +     * cinfo structure later do the destroy of this cert.
   1.610 +     */
   1.611 +    sid = &signerinfo->signerIdentifier;
   1.612 +    switch (sid->identifierType) {
   1.613 +    case NSSCMSSignerID_IssuerSN:
   1.614 +	cert = CERT_FindCertByIssuerAndSN(certdb, sid->id.issuerAndSN);
   1.615 +	break;
   1.616 +    case NSSCMSSignerID_SubjectKeyID:
   1.617 +	cert = CERT_FindCertBySubjectKeyID(certdb, sid->id.subjectKeyID);
   1.618 +	break;
   1.619 +    default:
   1.620 +	cert = NULL;
   1.621 +	break;
   1.622 +    }
   1.623 +
   1.624 +    /* cert can be NULL at that point */
   1.625 +    signerinfo->cert = cert;	/* earmark it */
   1.626 +
   1.627 +    return cert;
   1.628 +}
   1.629 +
   1.630 +/*
   1.631 + * NSS_CMSSignerInfo_GetSignerCommonName - return the common name of the signer
   1.632 + *
   1.633 + * sinfo - signerInfo data for this signer
   1.634 + *
   1.635 + * Returns a pointer to allocated memory, which must be freed with PORT_Free.
   1.636 + * A return value of NULL is an error.
   1.637 + */
   1.638 +char *
   1.639 +NSS_CMSSignerInfo_GetSignerCommonName(NSSCMSSignerInfo *sinfo)
   1.640 +{
   1.641 +    CERTCertificate *signercert;
   1.642 +
   1.643 +    /* will fail if cert is not verified */
   1.644 +    if ((signercert = NSS_CMSSignerInfo_GetSigningCertificate(sinfo, NULL)) == NULL)
   1.645 +	return NULL;
   1.646 +
   1.647 +    return (CERT_GetCommonName(&signercert->subject));
   1.648 +}
   1.649 +
   1.650 +/*
   1.651 + * NSS_CMSSignerInfo_GetSignerEmailAddress - return the common name of the signer
   1.652 + *
   1.653 + * sinfo - signerInfo data for this signer
   1.654 + *
   1.655 + * Returns a pointer to allocated memory, which must be freed.
   1.656 + * A return value of NULL is an error.
   1.657 + */
   1.658 +char *
   1.659 +NSS_CMSSignerInfo_GetSignerEmailAddress(NSSCMSSignerInfo *sinfo)
   1.660 +{
   1.661 +    CERTCertificate *signercert;
   1.662 +
   1.663 +    if ((signercert = NSS_CMSSignerInfo_GetSigningCertificate(sinfo, NULL)) == NULL)
   1.664 +	return NULL;
   1.665 +
   1.666 +    if (!signercert->emailAddr || !signercert->emailAddr[0])
   1.667 +	return NULL;
   1.668 +
   1.669 +    return (PORT_Strdup(signercert->emailAddr));
   1.670 +}
   1.671 +
   1.672 +/*
   1.673 + * NSS_CMSSignerInfo_AddAuthAttr - add an attribute to the
   1.674 + * authenticated (i.e. signed) attributes of "signerinfo". 
   1.675 + */
   1.676 +SECStatus
   1.677 +NSS_CMSSignerInfo_AddAuthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
   1.678 +{
   1.679 +    return NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->authAttr), attr);
   1.680 +}
   1.681 +
   1.682 +/*
   1.683 + * NSS_CMSSignerInfo_AddUnauthAttr - add an attribute to the
   1.684 + * unauthenticated attributes of "signerinfo". 
   1.685 + */
   1.686 +SECStatus
   1.687 +NSS_CMSSignerInfo_AddUnauthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
   1.688 +{
   1.689 +    return NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr);
   1.690 +}
   1.691 +
   1.692 +/* 
   1.693 + * NSS_CMSSignerInfo_AddSigningTime - add the signing time to the
   1.694 + * authenticated (i.e. signed) attributes of "signerinfo". 
   1.695 + *
   1.696 + * This is expected to be included in outgoing signed
   1.697 + * messages for email (S/MIME) but is likely useful in other situations.
   1.698 + *
   1.699 + * This should only be added once; a second call will do nothing.
   1.700 + *
   1.701 + * XXX This will probably just shove the current time into "signerinfo"
   1.702 + * but it will not actually get signed until the entire item is
   1.703 + * processed for encoding.  Is this (expected to be small) delay okay?
   1.704 + */
   1.705 +SECStatus
   1.706 +NSS_CMSSignerInfo_AddSigningTime(NSSCMSSignerInfo *signerinfo, PRTime t)
   1.707 +{
   1.708 +    NSSCMSAttribute *attr;
   1.709 +    SECItem stime;
   1.710 +    void *mark;
   1.711 +    PLArenaPool *poolp;
   1.712 +
   1.713 +    poolp = signerinfo->cmsg->poolp;
   1.714 +
   1.715 +    mark = PORT_ArenaMark(poolp);
   1.716 +
   1.717 +    /* create new signing time attribute */
   1.718 +    if (DER_EncodeTimeChoice(NULL, &stime, t) != SECSuccess)
   1.719 +	goto loser;
   1.720 +
   1.721 +    if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_PKCS9_SIGNING_TIME, &stime, PR_FALSE)) == NULL) {
   1.722 +	SECITEM_FreeItem (&stime, PR_FALSE);
   1.723 +	goto loser;
   1.724 +    }
   1.725 +
   1.726 +    SECITEM_FreeItem (&stime, PR_FALSE);
   1.727 +
   1.728 +    if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
   1.729 +	goto loser;
   1.730 +
   1.731 +    PORT_ArenaUnmark (poolp, mark);
   1.732 +
   1.733 +    return SECSuccess;
   1.734 +
   1.735 +loser:
   1.736 +    PORT_ArenaRelease (poolp, mark);
   1.737 +    return SECFailure;
   1.738 +}
   1.739 +
   1.740 +/* 
   1.741 + * NSS_CMSSignerInfo_AddSMIMECaps - add a SMIMECapabilities attribute to the
   1.742 + * authenticated (i.e. signed) attributes of "signerinfo". 
   1.743 + *
   1.744 + * This is expected to be included in outgoing signed
   1.745 + * messages for email (S/MIME).
   1.746 + */
   1.747 +SECStatus
   1.748 +NSS_CMSSignerInfo_AddSMIMECaps(NSSCMSSignerInfo *signerinfo)
   1.749 +{
   1.750 +    NSSCMSAttribute *attr;
   1.751 +    SECItem *smimecaps = NULL;
   1.752 +    void *mark;
   1.753 +    PLArenaPool *poolp;
   1.754 +
   1.755 +    poolp = signerinfo->cmsg->poolp;
   1.756 +
   1.757 +    mark = PORT_ArenaMark(poolp);
   1.758 +
   1.759 +    smimecaps = SECITEM_AllocItem(poolp, NULL, 0);
   1.760 +    if (smimecaps == NULL)
   1.761 +	goto loser;
   1.762 +
   1.763 +    /* create new signing time attribute */
   1.764 +    if (NSS_SMIMEUtil_CreateSMIMECapabilities(poolp, smimecaps) != SECSuccess)
   1.765 +	goto loser;
   1.766 +
   1.767 +    if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_PKCS9_SMIME_CAPABILITIES, smimecaps, PR_TRUE)) == NULL)
   1.768 +	goto loser;
   1.769 +
   1.770 +    if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
   1.771 +	goto loser;
   1.772 +
   1.773 +    PORT_ArenaUnmark (poolp, mark);
   1.774 +    return SECSuccess;
   1.775 +
   1.776 +loser:
   1.777 +    PORT_ArenaRelease (poolp, mark);
   1.778 +    return SECFailure;
   1.779 +}
   1.780 +
   1.781 +/* 
   1.782 + * NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
   1.783 + * authenticated (i.e. signed) attributes of "signerinfo". 
   1.784 + *
   1.785 + * This is expected to be included in outgoing signed messages for email (S/MIME).
   1.786 + */
   1.787 +SECStatus
   1.788 +NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(NSSCMSSignerInfo *signerinfo, CERTCertificate *cert, CERTCertDBHandle *certdb)
   1.789 +{
   1.790 +    NSSCMSAttribute *attr;
   1.791 +    SECItem *smimeekp = NULL;
   1.792 +    void *mark;
   1.793 +    PLArenaPool *poolp;
   1.794 +
   1.795 +    /* verify this cert for encryption */
   1.796 +    if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
   1.797 +	return SECFailure;
   1.798 +    }
   1.799 +
   1.800 +    poolp = signerinfo->cmsg->poolp;
   1.801 +    mark = PORT_ArenaMark(poolp);
   1.802 +
   1.803 +    smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
   1.804 +    if (smimeekp == NULL)
   1.805 +	goto loser;
   1.806 +
   1.807 +    /* create new signing time attribute */
   1.808 +    if (NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs(poolp, smimeekp, cert) != SECSuccess)
   1.809 +	goto loser;
   1.810 +
   1.811 +    if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
   1.812 +	goto loser;
   1.813 +
   1.814 +    if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
   1.815 +	goto loser;
   1.816 +
   1.817 +    PORT_ArenaUnmark (poolp, mark);
   1.818 +    return SECSuccess;
   1.819 +
   1.820 +loser:
   1.821 +    PORT_ArenaRelease (poolp, mark);
   1.822 +    return SECFailure;
   1.823 +}
   1.824 +
   1.825 +/* 
   1.826 + * NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
   1.827 + * authenticated (i.e. signed) attributes of "signerinfo", using the OID preferred by Microsoft.
   1.828 + *
   1.829 + * This is expected to be included in outgoing signed messages for email (S/MIME),
   1.830 + * if compatibility with Microsoft mail clients is wanted.
   1.831 + */
   1.832 +SECStatus
   1.833 +NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(NSSCMSSignerInfo *signerinfo, CERTCertificate *cert, CERTCertDBHandle *certdb)
   1.834 +{
   1.835 +    NSSCMSAttribute *attr;
   1.836 +    SECItem *smimeekp = NULL;
   1.837 +    void *mark;
   1.838 +    PLArenaPool *poolp;
   1.839 +
   1.840 +    /* verify this cert for encryption */
   1.841 +    if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
   1.842 +	return SECFailure;
   1.843 +    }
   1.844 +
   1.845 +    poolp = signerinfo->cmsg->poolp;
   1.846 +    mark = PORT_ArenaMark(poolp);
   1.847 +
   1.848 +    smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
   1.849 +    if (smimeekp == NULL)
   1.850 +	goto loser;
   1.851 +
   1.852 +    /* create new signing time attribute */
   1.853 +    if (NSS_SMIMEUtil_CreateMSSMIMEEncKeyPrefs(poolp, smimeekp, cert) != SECSuccess)
   1.854 +	goto loser;
   1.855 +
   1.856 +    if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
   1.857 +	goto loser;
   1.858 +
   1.859 +    if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
   1.860 +	goto loser;
   1.861 +
   1.862 +    PORT_ArenaUnmark (poolp, mark);
   1.863 +    return SECSuccess;
   1.864 +
   1.865 +loser:
   1.866 +    PORT_ArenaRelease (poolp, mark);
   1.867 +    return SECFailure;
   1.868 +}
   1.869 +
   1.870 +/* 
   1.871 + * NSS_CMSSignerInfo_AddCounterSignature - countersign a signerinfo
   1.872 + *
   1.873 + * 1. digest the DER-encoded signature value of the original signerinfo
   1.874 + * 2. create new signerinfo with correct version, sid, digestAlg
   1.875 + * 3. add message-digest authAttr, but NO content-type
   1.876 + * 4. sign the authAttrs
   1.877 + * 5. DER-encode the new signerInfo
   1.878 + * 6. add the whole thing to original signerInfo's unAuthAttrs
   1.879 + *    as a SEC_OID_PKCS9_COUNTER_SIGNATURE attribute
   1.880 + *
   1.881 + * XXXX give back the new signerinfo?
   1.882 + */
   1.883 +SECStatus
   1.884 +NSS_CMSSignerInfo_AddCounterSignature(NSSCMSSignerInfo *signerinfo,
   1.885 +				    SECOidTag digestalg, CERTCertificate signingcert)
   1.886 +{
   1.887 +    /* XXXX TBD XXXX */
   1.888 +    return SECFailure;
   1.889 +}
   1.890 +
   1.891 +/*
   1.892 + * XXXX the following needs to be done in the S/MIME layer code
   1.893 + * after signature of a signerinfo is verified
   1.894 + */
   1.895 +SECStatus
   1.896 +NSS_SMIMESignerInfo_SaveSMIMEProfile(NSSCMSSignerInfo *signerinfo)
   1.897 +{
   1.898 +    CERTCertificate *cert = NULL;
   1.899 +    SECItem *profile = NULL;
   1.900 +    NSSCMSAttribute *attr;
   1.901 +    SECItem *stime = NULL;
   1.902 +    SECItem *ekp;
   1.903 +    CERTCertDBHandle *certdb;
   1.904 +    int save_error;
   1.905 +    SECStatus rv;
   1.906 +    PRBool must_free_cert = PR_FALSE;
   1.907 +
   1.908 +    certdb = CERT_GetDefaultCertDB();
   1.909 +
   1.910 +    /* sanity check - see if verification status is ok (unverified does not count...) */
   1.911 +    if (signerinfo->verificationStatus != NSSCMSVS_GoodSignature)
   1.912 +	return SECFailure;
   1.913 +
   1.914 +    /* find preferred encryption cert */
   1.915 +    if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr) &&
   1.916 +	(attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
   1.917 +			       SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, PR_TRUE)) != NULL)
   1.918 +    { /* we have a SMIME_ENCRYPTION_KEY_PREFERENCE attribute! */
   1.919 +	ekp = NSS_CMSAttribute_GetValue(attr);
   1.920 +	if (ekp == NULL)
   1.921 +	    return SECFailure;
   1.922 +
   1.923 +	/* we assume that all certs coming with the message have been imported to the */
   1.924 +	/* temporary database */
   1.925 +	cert = NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference(certdb, ekp);
   1.926 +	if (cert == NULL)
   1.927 +	    return SECFailure;
   1.928 +	must_free_cert = PR_TRUE;
   1.929 +    }
   1.930 +
   1.931 +    if (cert == NULL) {
   1.932 +	/* no preferred cert found?
   1.933 +	 * find the cert the signerinfo is signed with instead */
   1.934 +	cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, certdb);
   1.935 +	if (cert == NULL || cert->emailAddr == NULL || !cert->emailAddr[0])
   1.936 +	    return SECFailure;
   1.937 +    }
   1.938 +
   1.939 +    /* verify this cert for encryption (has been verified for signing so far) */
   1.940 +    /* don't verify this cert for encryption. It may just be a signing cert.
   1.941 +     * that's OK, we can still save the S/MIME profile. The encryption cert
   1.942 +     * should have already been saved */
   1.943 +#ifdef notdef
   1.944 +    if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
   1.945 +	if (must_free_cert)
   1.946 +	    CERT_DestroyCertificate(cert);
   1.947 +	return SECFailure;
   1.948 +    }
   1.949 +#endif
   1.950 +
   1.951 +    /* XXX store encryption cert permanently? */
   1.952 +
   1.953 +    /*
   1.954 +     * Remember the current error set because we do not care about
   1.955 +     * anything set by the functions we are about to call.
   1.956 +     */
   1.957 +    save_error = PORT_GetError();
   1.958 +
   1.959 +    if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) {
   1.960 +	attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
   1.961 +				       SEC_OID_PKCS9_SMIME_CAPABILITIES,
   1.962 +				       PR_TRUE);
   1.963 +	profile = NSS_CMSAttribute_GetValue(attr);
   1.964 +	attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
   1.965 +				       SEC_OID_PKCS9_SIGNING_TIME,
   1.966 +				       PR_TRUE);
   1.967 +	stime = NSS_CMSAttribute_GetValue(attr);
   1.968 +    }
   1.969 +
   1.970 +    rv = CERT_SaveSMimeProfile (cert, profile, stime);
   1.971 +    if (must_free_cert)
   1.972 +	CERT_DestroyCertificate(cert);
   1.973 +
   1.974 +    /*
   1.975 +     * Restore the saved error in case the calls above set a new
   1.976 +     * one that we do not actually care about.
   1.977 +     */
   1.978 +    PORT_SetError (save_error);
   1.979 +
   1.980 +    return rv;
   1.981 +}
   1.982 +
   1.983 +/*
   1.984 + * NSS_CMSSignerInfo_IncludeCerts - set cert chain inclusion mode for this signer
   1.985 + */
   1.986 +SECStatus
   1.987 +NSS_CMSSignerInfo_IncludeCerts(NSSCMSSignerInfo *signerinfo, NSSCMSCertChainMode cm, SECCertUsage usage)
   1.988 +{
   1.989 +    if (signerinfo->cert == NULL)
   1.990 +	return SECFailure;
   1.991 +
   1.992 +    /* don't leak if we get called twice */
   1.993 +    if (signerinfo->certList != NULL) {
   1.994 +	CERT_DestroyCertificateList(signerinfo->certList);
   1.995 +	signerinfo->certList = NULL;
   1.996 +    }
   1.997 +
   1.998 +    switch (cm) {
   1.999 +    case NSSCMSCM_None:
  1.1000 +	signerinfo->certList = NULL;
  1.1001 +	break;
  1.1002 +    case NSSCMSCM_CertOnly:
  1.1003 +	signerinfo->certList = CERT_CertListFromCert(signerinfo->cert);
  1.1004 +	break;
  1.1005 +    case NSSCMSCM_CertChain:
  1.1006 +	signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_FALSE);
  1.1007 +	break;
  1.1008 +    case NSSCMSCM_CertChainWithRoot:
  1.1009 +	signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_TRUE);
  1.1010 +	break;
  1.1011 +    }
  1.1012 +
  1.1013 +    if (cm != NSSCMSCM_None && signerinfo->certList == NULL)
  1.1014 +	return SECFailure;
  1.1015 +    
  1.1016 +    return SECSuccess;
  1.1017 +}

mercurial