security/nss/lib/smime/cmssiginfo.c

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 /*
michael@0 6 * CMS signerInfo methods.
michael@0 7 */
michael@0 8
michael@0 9 #include "cmslocal.h"
michael@0 10
michael@0 11 #include "cert.h"
michael@0 12 #include "key.h"
michael@0 13 #include "secasn1.h"
michael@0 14 #include "secitem.h"
michael@0 15 #include "secoid.h"
michael@0 16 #include "pk11func.h"
michael@0 17 #include "prtime.h"
michael@0 18 #include "secerr.h"
michael@0 19 #include "secder.h"
michael@0 20 #include "cryptohi.h"
michael@0 21
michael@0 22 #include "smime.h"
michael@0 23
michael@0 24 /* =============================================================================
michael@0 25 * SIGNERINFO
michael@0 26 */
michael@0 27 NSSCMSSignerInfo *
michael@0 28 nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type,
michael@0 29 CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey,
michael@0 30 SECKEYPrivateKey *signingKey, SECOidTag digestalgtag);
michael@0 31
michael@0 32 NSSCMSSignerInfo *
michael@0 33 NSS_CMSSignerInfo_CreateWithSubjKeyID(NSSCMSMessage *cmsg, SECItem *subjKeyID,
michael@0 34 SECKEYPublicKey *pubKey, SECKEYPrivateKey *signingKey, SECOidTag digestalgtag)
michael@0 35 {
michael@0 36 return nss_cmssignerinfo_create(cmsg, NSSCMSSignerID_SubjectKeyID, NULL, subjKeyID, pubKey, signingKey, digestalgtag);
michael@0 37 }
michael@0 38
michael@0 39 NSSCMSSignerInfo *
michael@0 40 NSS_CMSSignerInfo_Create(NSSCMSMessage *cmsg, CERTCertificate *cert, SECOidTag digestalgtag)
michael@0 41 {
michael@0 42 return nss_cmssignerinfo_create(cmsg, NSSCMSSignerID_IssuerSN, cert, NULL, NULL, NULL, digestalgtag);
michael@0 43 }
michael@0 44
michael@0 45 NSSCMSSignerInfo *
michael@0 46 nss_cmssignerinfo_create(NSSCMSMessage *cmsg, NSSCMSSignerIDSelector type,
michael@0 47 CERTCertificate *cert, SECItem *subjKeyID, SECKEYPublicKey *pubKey,
michael@0 48 SECKEYPrivateKey *signingKey, SECOidTag digestalgtag)
michael@0 49 {
michael@0 50 void *mark;
michael@0 51 NSSCMSSignerInfo *signerinfo;
michael@0 52 int version;
michael@0 53 PLArenaPool *poolp;
michael@0 54
michael@0 55 poolp = cmsg->poolp;
michael@0 56
michael@0 57 mark = PORT_ArenaMark(poolp);
michael@0 58
michael@0 59 signerinfo = (NSSCMSSignerInfo *)PORT_ArenaZAlloc(poolp, sizeof(NSSCMSSignerInfo));
michael@0 60 if (signerinfo == NULL) {
michael@0 61 PORT_ArenaRelease(poolp, mark);
michael@0 62 return NULL;
michael@0 63 }
michael@0 64
michael@0 65
michael@0 66 signerinfo->cmsg = cmsg;
michael@0 67
michael@0 68 switch(type) {
michael@0 69 case NSSCMSSignerID_IssuerSN:
michael@0 70 signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_IssuerSN;
michael@0 71 if ((signerinfo->cert = CERT_DupCertificate(cert)) == NULL)
michael@0 72 goto loser;
michael@0 73 if ((signerinfo->signerIdentifier.id.issuerAndSN = CERT_GetCertIssuerAndSN(poolp, cert)) == NULL)
michael@0 74 goto loser;
michael@0 75 break;
michael@0 76 case NSSCMSSignerID_SubjectKeyID:
michael@0 77 signerinfo->signerIdentifier.identifierType = NSSCMSSignerID_SubjectKeyID;
michael@0 78 PORT_Assert(subjKeyID);
michael@0 79 if (!subjKeyID)
michael@0 80 goto loser;
michael@0 81
michael@0 82 signerinfo->signerIdentifier.id.subjectKeyID = PORT_ArenaNew(poolp, SECItem);
michael@0 83 SECITEM_CopyItem(poolp, signerinfo->signerIdentifier.id.subjectKeyID,
michael@0 84 subjKeyID);
michael@0 85 signerinfo->signingKey = SECKEY_CopyPrivateKey(signingKey);
michael@0 86 if (!signerinfo->signingKey)
michael@0 87 goto loser;
michael@0 88 signerinfo->pubKey = SECKEY_CopyPublicKey(pubKey);
michael@0 89 if (!signerinfo->pubKey)
michael@0 90 goto loser;
michael@0 91 break;
michael@0 92 default:
michael@0 93 goto loser;
michael@0 94 }
michael@0 95
michael@0 96 /* set version right now */
michael@0 97 version = NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN;
michael@0 98 /* RFC2630 5.3 "version is the syntax version number. If the .... " */
michael@0 99 if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID)
michael@0 100 version = NSS_CMS_SIGNER_INFO_VERSION_SUBJKEY;
michael@0 101 (void)SEC_ASN1EncodeInteger(poolp, &(signerinfo->version), (long)version);
michael@0 102
michael@0 103 if (SECOID_SetAlgorithmID(poolp, &signerinfo->digestAlg, digestalgtag, NULL) != SECSuccess)
michael@0 104 goto loser;
michael@0 105
michael@0 106 PORT_ArenaUnmark(poolp, mark);
michael@0 107 return signerinfo;
michael@0 108
michael@0 109 loser:
michael@0 110 PORT_ArenaRelease(poolp, mark);
michael@0 111 return NULL;
michael@0 112 }
michael@0 113
michael@0 114 /*
michael@0 115 * NSS_CMSSignerInfo_Destroy - destroy a SignerInfo data structure
michael@0 116 */
michael@0 117 void
michael@0 118 NSS_CMSSignerInfo_Destroy(NSSCMSSignerInfo *si)
michael@0 119 {
michael@0 120 if (si->cert != NULL)
michael@0 121 CERT_DestroyCertificate(si->cert);
michael@0 122
michael@0 123 if (si->certList != NULL)
michael@0 124 CERT_DestroyCertificateList(si->certList);
michael@0 125
michael@0 126 /* XXX storage ??? */
michael@0 127 }
michael@0 128
michael@0 129 /*
michael@0 130 * NSS_CMSSignerInfo_Sign - sign something
michael@0 131 *
michael@0 132 */
michael@0 133 SECStatus
michael@0 134 NSS_CMSSignerInfo_Sign(NSSCMSSignerInfo *signerinfo, SECItem *digest,
michael@0 135 SECItem *contentType)
michael@0 136 {
michael@0 137 CERTCertificate *cert;
michael@0 138 SECKEYPrivateKey *privkey = NULL;
michael@0 139 SECOidTag digestalgtag;
michael@0 140 SECOidTag pubkAlgTag;
michael@0 141 SECItem signature = { 0 };
michael@0 142 SECStatus rv;
michael@0 143 PLArenaPool *poolp, *tmppoolp = NULL;
michael@0 144 SECAlgorithmID *algID, freeAlgID;
michael@0 145 CERTSubjectPublicKeyInfo *spki;
michael@0 146
michael@0 147 PORT_Assert (digest != NULL);
michael@0 148
michael@0 149 poolp = signerinfo->cmsg->poolp;
michael@0 150
michael@0 151 switch (signerinfo->signerIdentifier.identifierType) {
michael@0 152 case NSSCMSSignerID_IssuerSN:
michael@0 153 cert = signerinfo->cert;
michael@0 154
michael@0 155 privkey = PK11_FindKeyByAnyCert(cert, signerinfo->cmsg->pwfn_arg);
michael@0 156 if (privkey == NULL)
michael@0 157 goto loser;
michael@0 158 algID = &cert->subjectPublicKeyInfo.algorithm;
michael@0 159 break;
michael@0 160 case NSSCMSSignerID_SubjectKeyID:
michael@0 161 privkey = signerinfo->signingKey;
michael@0 162 signerinfo->signingKey = NULL;
michael@0 163 spki = SECKEY_CreateSubjectPublicKeyInfo(signerinfo->pubKey);
michael@0 164 SECKEY_DestroyPublicKey(signerinfo->pubKey);
michael@0 165 signerinfo->pubKey = NULL;
michael@0 166 SECOID_CopyAlgorithmID(NULL, &freeAlgID, &spki->algorithm);
michael@0 167 SECKEY_DestroySubjectPublicKeyInfo(spki);
michael@0 168 algID = &freeAlgID;
michael@0 169 break;
michael@0 170 default:
michael@0 171 goto loser;
michael@0 172 }
michael@0 173 digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
michael@0 174 /*
michael@0 175 * XXX I think there should be a cert-level interface for this,
michael@0 176 * so that I do not have to know about subjectPublicKeyInfo...
michael@0 177 */
michael@0 178 pubkAlgTag = SECOID_GetAlgorithmTag(algID);
michael@0 179 if (signerinfo->signerIdentifier.identifierType == NSSCMSSignerID_SubjectKeyID) {
michael@0 180 SECOID_DestroyAlgorithmID(&freeAlgID, PR_FALSE);
michael@0 181 }
michael@0 182
michael@0 183 if (signerinfo->authAttr != NULL) {
michael@0 184 SECOidTag signAlgTag;
michael@0 185 SECItem encoded_attrs;
michael@0 186
michael@0 187 /* find and fill in the message digest attribute. */
michael@0 188 rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr),
michael@0 189 SEC_OID_PKCS9_MESSAGE_DIGEST, digest, PR_FALSE);
michael@0 190 if (rv != SECSuccess)
michael@0 191 goto loser;
michael@0 192
michael@0 193 if (contentType != NULL) {
michael@0 194 /* if the caller wants us to, find and fill in the content type attribute. */
michael@0 195 rv = NSS_CMSAttributeArray_SetAttr(poolp, &(signerinfo->authAttr),
michael@0 196 SEC_OID_PKCS9_CONTENT_TYPE, contentType, PR_FALSE);
michael@0 197 if (rv != SECSuccess)
michael@0 198 goto loser;
michael@0 199 }
michael@0 200
michael@0 201 if ((tmppoolp = PORT_NewArena (1024)) == NULL) {
michael@0 202 PORT_SetError(SEC_ERROR_NO_MEMORY);
michael@0 203 goto loser;
michael@0 204 }
michael@0 205
michael@0 206 /*
michael@0 207 * Before encoding, reorder the attributes so that when they
michael@0 208 * are encoded, they will be conforming DER, which is required
michael@0 209 * to have a specific order and that is what must be used for
michael@0 210 * the hash/signature. We do this here, rather than building
michael@0 211 * it into EncodeAttributes, because we do not want to do
michael@0 212 * such reordering on incoming messages (which also uses
michael@0 213 * EncodeAttributes) or our old signatures (and other "broken"
michael@0 214 * implementations) will not verify. So, we want to guarantee
michael@0 215 * that we send out good DER encodings of attributes, but not
michael@0 216 * to expect to receive them.
michael@0 217 */
michael@0 218 if (NSS_CMSAttributeArray_Reorder(signerinfo->authAttr) != SECSuccess)
michael@0 219 goto loser;
michael@0 220
michael@0 221 encoded_attrs.data = NULL;
michael@0 222 encoded_attrs.len = 0;
michael@0 223 if (NSS_CMSAttributeArray_Encode(tmppoolp, &(signerinfo->authAttr),
michael@0 224 &encoded_attrs) == NULL)
michael@0 225 goto loser;
michael@0 226
michael@0 227 signAlgTag = SEC_GetSignatureAlgorithmOidTag(privkey->keyType,
michael@0 228 digestalgtag);
michael@0 229 if (signAlgTag == SEC_OID_UNKNOWN) {
michael@0 230 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
michael@0 231 goto loser;
michael@0 232 }
michael@0 233
michael@0 234 rv = SEC_SignData(&signature, encoded_attrs.data, encoded_attrs.len,
michael@0 235 privkey, signAlgTag);
michael@0 236 PORT_FreeArena(tmppoolp, PR_FALSE); /* awkward memory management :-( */
michael@0 237 tmppoolp = 0;
michael@0 238 } else {
michael@0 239 rv = SGN_Digest(privkey, digestalgtag, &signature, digest);
michael@0 240 }
michael@0 241 SECKEY_DestroyPrivateKey(privkey);
michael@0 242 privkey = NULL;
michael@0 243
michael@0 244 if (rv != SECSuccess)
michael@0 245 goto loser;
michael@0 246
michael@0 247 if (SECITEM_CopyItem(poolp, &(signerinfo->encDigest), &signature)
michael@0 248 != SECSuccess)
michael@0 249 goto loser;
michael@0 250
michael@0 251 SECITEM_FreeItem(&signature, PR_FALSE);
michael@0 252
michael@0 253 if (SECOID_SetAlgorithmID(poolp, &(signerinfo->digestEncAlg), pubkAlgTag,
michael@0 254 NULL) != SECSuccess)
michael@0 255 goto loser;
michael@0 256
michael@0 257 return SECSuccess;
michael@0 258
michael@0 259 loser:
michael@0 260 if (signature.len != 0)
michael@0 261 SECITEM_FreeItem (&signature, PR_FALSE);
michael@0 262 if (privkey)
michael@0 263 SECKEY_DestroyPrivateKey(privkey);
michael@0 264 if (tmppoolp)
michael@0 265 PORT_FreeArena(tmppoolp, PR_FALSE);
michael@0 266 return SECFailure;
michael@0 267 }
michael@0 268
michael@0 269 SECStatus
michael@0 270 NSS_CMSSignerInfo_VerifyCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb,
michael@0 271 SECCertUsage certusage)
michael@0 272 {
michael@0 273 CERTCertificate *cert;
michael@0 274 PRTime stime;
michael@0 275
michael@0 276 if ((cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, certdb)) == NULL) {
michael@0 277 signerinfo->verificationStatus = NSSCMSVS_SigningCertNotFound;
michael@0 278 return SECFailure;
michael@0 279 }
michael@0 280
michael@0 281 /*
michael@0 282 * Get and convert the signing time; if available, it will be used
michael@0 283 * both on the cert verification and for importing the sender
michael@0 284 * email profile.
michael@0 285 */
michael@0 286 if (NSS_CMSSignerInfo_GetSigningTime (signerinfo, &stime) != SECSuccess)
michael@0 287 stime = PR_Now(); /* not found or conversion failed, so check against now */
michael@0 288
michael@0 289 /*
michael@0 290 * XXX This uses the signing time, if available. Additionally, we
michael@0 291 * might want to, if there is no signing time, get the message time
michael@0 292 * from the mail header itself, and use that. That would require
michael@0 293 * a change to our interface though, and for S/MIME callers to pass
michael@0 294 * in a time (and for non-S/MIME callers to pass in nothing, or
michael@0 295 * maybe make them pass in the current time, always?).
michael@0 296 */
michael@0 297 if (CERT_VerifyCert(certdb, cert, PR_TRUE, certusage, stime,
michael@0 298 signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
michael@0 299 signerinfo->verificationStatus = NSSCMSVS_SigningCertNotTrusted;
michael@0 300 return SECFailure;
michael@0 301 }
michael@0 302 return SECSuccess;
michael@0 303 }
michael@0 304
michael@0 305 /*
michael@0 306 * NSS_CMSSignerInfo_Verify - verify the signature of a single SignerInfo
michael@0 307 *
michael@0 308 * Just verifies the signature. The assumption is that verification of
michael@0 309 * the certificate is done already.
michael@0 310 */
michael@0 311 SECStatus
michael@0 312 NSS_CMSSignerInfo_Verify(NSSCMSSignerInfo *signerinfo,
michael@0 313 SECItem *digest, /* may be NULL */
michael@0 314 SECItem *contentType) /* may be NULL */
michael@0 315 {
michael@0 316 SECKEYPublicKey *publickey = NULL;
michael@0 317 NSSCMSAttribute *attr;
michael@0 318 SECItem encoded_attrs;
michael@0 319 CERTCertificate *cert;
michael@0 320 NSSCMSVerificationStatus vs = NSSCMSVS_Unverified;
michael@0 321 PLArenaPool *poolp;
michael@0 322 SECOidTag digestalgtag;
michael@0 323 SECOidTag pubkAlgTag;
michael@0 324
michael@0 325 if (signerinfo == NULL)
michael@0 326 return SECFailure;
michael@0 327
michael@0 328 /* NSS_CMSSignerInfo_GetSigningCertificate will fail if 2nd parm is NULL
michael@0 329 ** and cert has not been verified
michael@0 330 */
michael@0 331 cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, NULL);
michael@0 332 if (cert == NULL) {
michael@0 333 vs = NSSCMSVS_SigningCertNotFound;
michael@0 334 goto loser;
michael@0 335 }
michael@0 336
michael@0 337 if ((publickey = CERT_ExtractPublicKey(cert)) == NULL) {
michael@0 338 vs = NSSCMSVS_ProcessingError;
michael@0 339 goto loser;
michael@0 340 }
michael@0 341
michael@0 342 digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo);
michael@0 343 pubkAlgTag = SECOID_GetAlgorithmTag(&(signerinfo->digestEncAlg));
michael@0 344 if ((pubkAlgTag == SEC_OID_UNKNOWN) || (digestalgtag == SEC_OID_UNKNOWN)) {
michael@0 345 vs = NSSCMSVS_SignatureAlgorithmUnknown;
michael@0 346 goto loser;
michael@0 347 }
michael@0 348
michael@0 349 if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) {
michael@0 350 if (contentType) {
michael@0 351 /*
michael@0 352 * Check content type
michael@0 353 *
michael@0 354 * RFC2630 sez that if there are any authenticated attributes,
michael@0 355 * then there must be one for content type which matches the
michael@0 356 * content type of the content being signed, and there must
michael@0 357 * be one for message digest which matches our message digest.
michael@0 358 * So check these things first.
michael@0 359 */
michael@0 360 attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
michael@0 361 SEC_OID_PKCS9_CONTENT_TYPE, PR_TRUE);
michael@0 362 if (attr == NULL) {
michael@0 363 vs = NSSCMSVS_MalformedSignature;
michael@0 364 goto loser;
michael@0 365 }
michael@0 366
michael@0 367 if (NSS_CMSAttribute_CompareValue(attr, contentType) == PR_FALSE) {
michael@0 368 vs = NSSCMSVS_MalformedSignature;
michael@0 369 goto loser;
michael@0 370 }
michael@0 371 }
michael@0 372
michael@0 373 /*
michael@0 374 * Check digest
michael@0 375 */
michael@0 376 attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
michael@0 377 SEC_OID_PKCS9_MESSAGE_DIGEST, PR_TRUE);
michael@0 378 if (attr == NULL) {
michael@0 379 vs = NSSCMSVS_MalformedSignature;
michael@0 380 goto loser;
michael@0 381 }
michael@0 382 if (!digest ||
michael@0 383 NSS_CMSAttribute_CompareValue(attr, digest) == PR_FALSE) {
michael@0 384 vs = NSSCMSVS_DigestMismatch;
michael@0 385 goto loser;
michael@0 386 }
michael@0 387
michael@0 388 if ((poolp = PORT_NewArena (1024)) == NULL) {
michael@0 389 vs = NSSCMSVS_ProcessingError;
michael@0 390 goto loser;
michael@0 391 }
michael@0 392
michael@0 393 /*
michael@0 394 * Check signature
michael@0 395 *
michael@0 396 * The signature is based on a digest of the DER-encoded authenticated
michael@0 397 * attributes. So, first we encode and then we digest/verify.
michael@0 398 * we trust the decoder to have the attributes in the right (sorted)
michael@0 399 * order
michael@0 400 */
michael@0 401 encoded_attrs.data = NULL;
michael@0 402 encoded_attrs.len = 0;
michael@0 403
michael@0 404 if (NSS_CMSAttributeArray_Encode(poolp, &(signerinfo->authAttr),
michael@0 405 &encoded_attrs) == NULL ||
michael@0 406 encoded_attrs.data == NULL || encoded_attrs.len == 0) {
michael@0 407 vs = NSSCMSVS_ProcessingError;
michael@0 408 goto loser;
michael@0 409 }
michael@0 410
michael@0 411 vs = (VFY_VerifyDataDirect(encoded_attrs.data, encoded_attrs.len,
michael@0 412 publickey, &(signerinfo->encDigest), pubkAlgTag,
michael@0 413 digestalgtag, NULL, signerinfo->cmsg->pwfn_arg) != SECSuccess)
michael@0 414 ? NSSCMSVS_BadSignature : NSSCMSVS_GoodSignature;
michael@0 415
michael@0 416 PORT_FreeArena(poolp, PR_FALSE); /* awkward memory management :-( */
michael@0 417
michael@0 418 } else {
michael@0 419 SECItem *sig;
michael@0 420
michael@0 421 /* No authenticated attributes.
michael@0 422 ** The signature is based on the plain message digest.
michael@0 423 */
michael@0 424 sig = &(signerinfo->encDigest);
michael@0 425 if (sig->len == 0)
michael@0 426 goto loser;
michael@0 427
michael@0 428 vs = (!digest ||
michael@0 429 VFY_VerifyDigestDirect(digest, publickey, sig, pubkAlgTag,
michael@0 430 digestalgtag, signerinfo->cmsg->pwfn_arg) != SECSuccess)
michael@0 431 ? NSSCMSVS_BadSignature : NSSCMSVS_GoodSignature;
michael@0 432 }
michael@0 433
michael@0 434 if (vs == NSSCMSVS_BadSignature) {
michael@0 435 int error = PORT_GetError();
michael@0 436 /*
michael@0 437 * XXX Change the generic error into our specific one, because
michael@0 438 * in that case we get a better explanation out of the Security
michael@0 439 * Advisor. This is really a bug in the PSM error strings (the
michael@0 440 * "generic" error has a lousy/wrong message associated with it
michael@0 441 * which assumes the signature verification was done for the
michael@0 442 * purposes of checking the issuer signature on a certificate)
michael@0 443 * but this is at least an easy workaround and/or in the
michael@0 444 * Security Advisor, which specifically checks for the error
michael@0 445 * SEC_ERROR_PKCS7_BAD_SIGNATURE and gives more explanation
michael@0 446 * in that case but does not similarly check for
michael@0 447 * SEC_ERROR_BAD_SIGNATURE. It probably should, but then would
michael@0 448 * probably say the wrong thing in the case that it *was* the
michael@0 449 * certificate signature check that failed during the cert
michael@0 450 * verification done above. Our error handling is really a mess.
michael@0 451 */
michael@0 452 if (error == SEC_ERROR_BAD_SIGNATURE)
michael@0 453 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
michael@0 454 /*
michael@0 455 * map algorithm failures to NSSCMSVS values
michael@0 456 */
michael@0 457 if ((error == SEC_ERROR_PKCS7_KEYALG_MISMATCH) ||
michael@0 458 (error == SEC_ERROR_INVALID_ALGORITHM)) {
michael@0 459 /* keep the same error code as 3.11 and before */
michael@0 460 PORT_SetError(SEC_ERROR_PKCS7_BAD_SIGNATURE);
michael@0 461 vs = NSSCMSVS_SignatureAlgorithmUnsupported;
michael@0 462 }
michael@0 463 }
michael@0 464
michael@0 465 if (publickey != NULL)
michael@0 466 SECKEY_DestroyPublicKey (publickey);
michael@0 467
michael@0 468 signerinfo->verificationStatus = vs;
michael@0 469
michael@0 470 return (vs == NSSCMSVS_GoodSignature) ? SECSuccess : SECFailure;
michael@0 471
michael@0 472 loser:
michael@0 473 if (publickey != NULL)
michael@0 474 SECKEY_DestroyPublicKey (publickey);
michael@0 475
michael@0 476 signerinfo->verificationStatus = vs;
michael@0 477
michael@0 478 PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE);
michael@0 479 return SECFailure;
michael@0 480 }
michael@0 481
michael@0 482 NSSCMSVerificationStatus
michael@0 483 NSS_CMSSignerInfo_GetVerificationStatus(NSSCMSSignerInfo *signerinfo)
michael@0 484 {
michael@0 485 return signerinfo->verificationStatus;
michael@0 486 }
michael@0 487
michael@0 488 SECOidData *
michael@0 489 NSS_CMSSignerInfo_GetDigestAlg(NSSCMSSignerInfo *signerinfo)
michael@0 490 {
michael@0 491 SECOidData *algdata;
michael@0 492 SECOidTag algtag;
michael@0 493
michael@0 494 algdata = SECOID_FindOID (&(signerinfo->digestAlg.algorithm));
michael@0 495 if (algdata == NULL) {
michael@0 496 return algdata;
michael@0 497 }
michael@0 498 /* Windows may have given us a signer algorithm oid instead of a digest
michael@0 499 * algorithm oid. This call will map to a signer oid to a digest one,
michael@0 500 * otherwise it leaves the oid alone and let the chips fall as they may
michael@0 501 * if it's not a digest oid.
michael@0 502 */
michael@0 503 algtag = NSS_CMSUtil_MapSignAlgs(algdata->offset);
michael@0 504 if (algtag != algdata->offset) {
michael@0 505 /* if the tags don't match, then we must have received a signer
michael@0 506 * algorithID. Now we need to get the oid data for the digest
michael@0 507 * oid, which the rest of the code is expecting */
michael@0 508 algdata = SECOID_FindOIDByTag(algtag);
michael@0 509 }
michael@0 510
michael@0 511 return algdata;
michael@0 512
michael@0 513 }
michael@0 514
michael@0 515 SECOidTag
michael@0 516 NSS_CMSSignerInfo_GetDigestAlgTag(NSSCMSSignerInfo *signerinfo)
michael@0 517 {
michael@0 518 SECOidData *algdata;
michael@0 519
michael@0 520 if (!signerinfo) {
michael@0 521 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 522 return SEC_OID_UNKNOWN;
michael@0 523 }
michael@0 524
michael@0 525 algdata = NSS_CMSSignerInfo_GetDigestAlg(signerinfo);
michael@0 526 if (algdata != NULL)
michael@0 527 return algdata->offset;
michael@0 528 else
michael@0 529 return SEC_OID_UNKNOWN;
michael@0 530 }
michael@0 531
michael@0 532 CERTCertificateList *
michael@0 533 NSS_CMSSignerInfo_GetCertList(NSSCMSSignerInfo *signerinfo)
michael@0 534 {
michael@0 535 return signerinfo->certList;
michael@0 536 }
michael@0 537
michael@0 538 int
michael@0 539 NSS_CMSSignerInfo_GetVersion(NSSCMSSignerInfo *signerinfo)
michael@0 540 {
michael@0 541 unsigned long version;
michael@0 542
michael@0 543 /* always take apart the SECItem */
michael@0 544 if (SEC_ASN1DecodeInteger(&(signerinfo->version), &version) != SECSuccess)
michael@0 545 return 0;
michael@0 546 else
michael@0 547 return (int)version;
michael@0 548 }
michael@0 549
michael@0 550 /*
michael@0 551 * NSS_CMSSignerInfo_GetSigningTime - return the signing time,
michael@0 552 * in UTCTime or GeneralizedTime format,
michael@0 553 * of a CMS signerInfo.
michael@0 554 *
michael@0 555 * sinfo - signerInfo data for this signer
michael@0 556 *
michael@0 557 * Returns a pointer to XXXX (what?)
michael@0 558 * A return value of NULL is an error.
michael@0 559 */
michael@0 560 SECStatus
michael@0 561 NSS_CMSSignerInfo_GetSigningTime(NSSCMSSignerInfo *sinfo, PRTime *stime)
michael@0 562 {
michael@0 563 NSSCMSAttribute *attr;
michael@0 564 SECItem *value;
michael@0 565
michael@0 566 if (sinfo == NULL)
michael@0 567 return SECFailure;
michael@0 568
michael@0 569 if (sinfo->signingTime != 0) {
michael@0 570 *stime = sinfo->signingTime; /* cached copy */
michael@0 571 return SECSuccess;
michael@0 572 }
michael@0 573
michael@0 574 attr = NSS_CMSAttributeArray_FindAttrByOidTag(sinfo->authAttr, SEC_OID_PKCS9_SIGNING_TIME, PR_TRUE);
michael@0 575 /* XXXX multi-valued attributes NIH */
michael@0 576 if (attr == NULL || (value = NSS_CMSAttribute_GetValue(attr)) == NULL)
michael@0 577 return SECFailure;
michael@0 578 if (DER_DecodeTimeChoice(stime, value) != SECSuccess)
michael@0 579 return SECFailure;
michael@0 580 sinfo->signingTime = *stime; /* make cached copy */
michael@0 581 return SECSuccess;
michael@0 582 }
michael@0 583
michael@0 584 /*
michael@0 585 * Return the signing cert of a CMS signerInfo.
michael@0 586 *
michael@0 587 * the certs in the enclosing SignedData must have been imported already
michael@0 588 */
michael@0 589 CERTCertificate *
michael@0 590 NSS_CMSSignerInfo_GetSigningCertificate(NSSCMSSignerInfo *signerinfo, CERTCertDBHandle *certdb)
michael@0 591 {
michael@0 592 CERTCertificate *cert;
michael@0 593 NSSCMSSignerIdentifier *sid;
michael@0 594
michael@0 595 if (signerinfo->cert != NULL)
michael@0 596 return signerinfo->cert;
michael@0 597
michael@0 598 /* no certdb, and cert hasn't been set yet? */
michael@0 599 if (certdb == NULL)
michael@0 600 return NULL;
michael@0 601
michael@0 602 /*
michael@0 603 * This cert will also need to be freed, but since we save it
michael@0 604 * in signerinfo for later, we do not want to destroy it when
michael@0 605 * we leave this function -- we let the clean-up of the entire
michael@0 606 * cinfo structure later do the destroy of this cert.
michael@0 607 */
michael@0 608 sid = &signerinfo->signerIdentifier;
michael@0 609 switch (sid->identifierType) {
michael@0 610 case NSSCMSSignerID_IssuerSN:
michael@0 611 cert = CERT_FindCertByIssuerAndSN(certdb, sid->id.issuerAndSN);
michael@0 612 break;
michael@0 613 case NSSCMSSignerID_SubjectKeyID:
michael@0 614 cert = CERT_FindCertBySubjectKeyID(certdb, sid->id.subjectKeyID);
michael@0 615 break;
michael@0 616 default:
michael@0 617 cert = NULL;
michael@0 618 break;
michael@0 619 }
michael@0 620
michael@0 621 /* cert can be NULL at that point */
michael@0 622 signerinfo->cert = cert; /* earmark it */
michael@0 623
michael@0 624 return cert;
michael@0 625 }
michael@0 626
michael@0 627 /*
michael@0 628 * NSS_CMSSignerInfo_GetSignerCommonName - return the common name of the signer
michael@0 629 *
michael@0 630 * sinfo - signerInfo data for this signer
michael@0 631 *
michael@0 632 * Returns a pointer to allocated memory, which must be freed with PORT_Free.
michael@0 633 * A return value of NULL is an error.
michael@0 634 */
michael@0 635 char *
michael@0 636 NSS_CMSSignerInfo_GetSignerCommonName(NSSCMSSignerInfo *sinfo)
michael@0 637 {
michael@0 638 CERTCertificate *signercert;
michael@0 639
michael@0 640 /* will fail if cert is not verified */
michael@0 641 if ((signercert = NSS_CMSSignerInfo_GetSigningCertificate(sinfo, NULL)) == NULL)
michael@0 642 return NULL;
michael@0 643
michael@0 644 return (CERT_GetCommonName(&signercert->subject));
michael@0 645 }
michael@0 646
michael@0 647 /*
michael@0 648 * NSS_CMSSignerInfo_GetSignerEmailAddress - return the common name of the signer
michael@0 649 *
michael@0 650 * sinfo - signerInfo data for this signer
michael@0 651 *
michael@0 652 * Returns a pointer to allocated memory, which must be freed.
michael@0 653 * A return value of NULL is an error.
michael@0 654 */
michael@0 655 char *
michael@0 656 NSS_CMSSignerInfo_GetSignerEmailAddress(NSSCMSSignerInfo *sinfo)
michael@0 657 {
michael@0 658 CERTCertificate *signercert;
michael@0 659
michael@0 660 if ((signercert = NSS_CMSSignerInfo_GetSigningCertificate(sinfo, NULL)) == NULL)
michael@0 661 return NULL;
michael@0 662
michael@0 663 if (!signercert->emailAddr || !signercert->emailAddr[0])
michael@0 664 return NULL;
michael@0 665
michael@0 666 return (PORT_Strdup(signercert->emailAddr));
michael@0 667 }
michael@0 668
michael@0 669 /*
michael@0 670 * NSS_CMSSignerInfo_AddAuthAttr - add an attribute to the
michael@0 671 * authenticated (i.e. signed) attributes of "signerinfo".
michael@0 672 */
michael@0 673 SECStatus
michael@0 674 NSS_CMSSignerInfo_AddAuthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
michael@0 675 {
michael@0 676 return NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->authAttr), attr);
michael@0 677 }
michael@0 678
michael@0 679 /*
michael@0 680 * NSS_CMSSignerInfo_AddUnauthAttr - add an attribute to the
michael@0 681 * unauthenticated attributes of "signerinfo".
michael@0 682 */
michael@0 683 SECStatus
michael@0 684 NSS_CMSSignerInfo_AddUnauthAttr(NSSCMSSignerInfo *signerinfo, NSSCMSAttribute *attr)
michael@0 685 {
michael@0 686 return NSS_CMSAttributeArray_AddAttr(signerinfo->cmsg->poolp, &(signerinfo->unAuthAttr), attr);
michael@0 687 }
michael@0 688
michael@0 689 /*
michael@0 690 * NSS_CMSSignerInfo_AddSigningTime - add the signing time to the
michael@0 691 * authenticated (i.e. signed) attributes of "signerinfo".
michael@0 692 *
michael@0 693 * This is expected to be included in outgoing signed
michael@0 694 * messages for email (S/MIME) but is likely useful in other situations.
michael@0 695 *
michael@0 696 * This should only be added once; a second call will do nothing.
michael@0 697 *
michael@0 698 * XXX This will probably just shove the current time into "signerinfo"
michael@0 699 * but it will not actually get signed until the entire item is
michael@0 700 * processed for encoding. Is this (expected to be small) delay okay?
michael@0 701 */
michael@0 702 SECStatus
michael@0 703 NSS_CMSSignerInfo_AddSigningTime(NSSCMSSignerInfo *signerinfo, PRTime t)
michael@0 704 {
michael@0 705 NSSCMSAttribute *attr;
michael@0 706 SECItem stime;
michael@0 707 void *mark;
michael@0 708 PLArenaPool *poolp;
michael@0 709
michael@0 710 poolp = signerinfo->cmsg->poolp;
michael@0 711
michael@0 712 mark = PORT_ArenaMark(poolp);
michael@0 713
michael@0 714 /* create new signing time attribute */
michael@0 715 if (DER_EncodeTimeChoice(NULL, &stime, t) != SECSuccess)
michael@0 716 goto loser;
michael@0 717
michael@0 718 if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_PKCS9_SIGNING_TIME, &stime, PR_FALSE)) == NULL) {
michael@0 719 SECITEM_FreeItem (&stime, PR_FALSE);
michael@0 720 goto loser;
michael@0 721 }
michael@0 722
michael@0 723 SECITEM_FreeItem (&stime, PR_FALSE);
michael@0 724
michael@0 725 if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
michael@0 726 goto loser;
michael@0 727
michael@0 728 PORT_ArenaUnmark (poolp, mark);
michael@0 729
michael@0 730 return SECSuccess;
michael@0 731
michael@0 732 loser:
michael@0 733 PORT_ArenaRelease (poolp, mark);
michael@0 734 return SECFailure;
michael@0 735 }
michael@0 736
michael@0 737 /*
michael@0 738 * NSS_CMSSignerInfo_AddSMIMECaps - add a SMIMECapabilities attribute to the
michael@0 739 * authenticated (i.e. signed) attributes of "signerinfo".
michael@0 740 *
michael@0 741 * This is expected to be included in outgoing signed
michael@0 742 * messages for email (S/MIME).
michael@0 743 */
michael@0 744 SECStatus
michael@0 745 NSS_CMSSignerInfo_AddSMIMECaps(NSSCMSSignerInfo *signerinfo)
michael@0 746 {
michael@0 747 NSSCMSAttribute *attr;
michael@0 748 SECItem *smimecaps = NULL;
michael@0 749 void *mark;
michael@0 750 PLArenaPool *poolp;
michael@0 751
michael@0 752 poolp = signerinfo->cmsg->poolp;
michael@0 753
michael@0 754 mark = PORT_ArenaMark(poolp);
michael@0 755
michael@0 756 smimecaps = SECITEM_AllocItem(poolp, NULL, 0);
michael@0 757 if (smimecaps == NULL)
michael@0 758 goto loser;
michael@0 759
michael@0 760 /* create new signing time attribute */
michael@0 761 if (NSS_SMIMEUtil_CreateSMIMECapabilities(poolp, smimecaps) != SECSuccess)
michael@0 762 goto loser;
michael@0 763
michael@0 764 if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_PKCS9_SMIME_CAPABILITIES, smimecaps, PR_TRUE)) == NULL)
michael@0 765 goto loser;
michael@0 766
michael@0 767 if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
michael@0 768 goto loser;
michael@0 769
michael@0 770 PORT_ArenaUnmark (poolp, mark);
michael@0 771 return SECSuccess;
michael@0 772
michael@0 773 loser:
michael@0 774 PORT_ArenaRelease (poolp, mark);
michael@0 775 return SECFailure;
michael@0 776 }
michael@0 777
michael@0 778 /*
michael@0 779 * NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
michael@0 780 * authenticated (i.e. signed) attributes of "signerinfo".
michael@0 781 *
michael@0 782 * This is expected to be included in outgoing signed messages for email (S/MIME).
michael@0 783 */
michael@0 784 SECStatus
michael@0 785 NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(NSSCMSSignerInfo *signerinfo, CERTCertificate *cert, CERTCertDBHandle *certdb)
michael@0 786 {
michael@0 787 NSSCMSAttribute *attr;
michael@0 788 SECItem *smimeekp = NULL;
michael@0 789 void *mark;
michael@0 790 PLArenaPool *poolp;
michael@0 791
michael@0 792 /* verify this cert for encryption */
michael@0 793 if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
michael@0 794 return SECFailure;
michael@0 795 }
michael@0 796
michael@0 797 poolp = signerinfo->cmsg->poolp;
michael@0 798 mark = PORT_ArenaMark(poolp);
michael@0 799
michael@0 800 smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
michael@0 801 if (smimeekp == NULL)
michael@0 802 goto loser;
michael@0 803
michael@0 804 /* create new signing time attribute */
michael@0 805 if (NSS_SMIMEUtil_CreateSMIMEEncKeyPrefs(poolp, smimeekp, cert) != SECSuccess)
michael@0 806 goto loser;
michael@0 807
michael@0 808 if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
michael@0 809 goto loser;
michael@0 810
michael@0 811 if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
michael@0 812 goto loser;
michael@0 813
michael@0 814 PORT_ArenaUnmark (poolp, mark);
michael@0 815 return SECSuccess;
michael@0 816
michael@0 817 loser:
michael@0 818 PORT_ArenaRelease (poolp, mark);
michael@0 819 return SECFailure;
michael@0 820 }
michael@0 821
michael@0 822 /*
michael@0 823 * NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs - add a SMIMEEncryptionKeyPreferences attribute to the
michael@0 824 * authenticated (i.e. signed) attributes of "signerinfo", using the OID preferred by Microsoft.
michael@0 825 *
michael@0 826 * This is expected to be included in outgoing signed messages for email (S/MIME),
michael@0 827 * if compatibility with Microsoft mail clients is wanted.
michael@0 828 */
michael@0 829 SECStatus
michael@0 830 NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(NSSCMSSignerInfo *signerinfo, CERTCertificate *cert, CERTCertDBHandle *certdb)
michael@0 831 {
michael@0 832 NSSCMSAttribute *attr;
michael@0 833 SECItem *smimeekp = NULL;
michael@0 834 void *mark;
michael@0 835 PLArenaPool *poolp;
michael@0 836
michael@0 837 /* verify this cert for encryption */
michael@0 838 if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
michael@0 839 return SECFailure;
michael@0 840 }
michael@0 841
michael@0 842 poolp = signerinfo->cmsg->poolp;
michael@0 843 mark = PORT_ArenaMark(poolp);
michael@0 844
michael@0 845 smimeekp = SECITEM_AllocItem(poolp, NULL, 0);
michael@0 846 if (smimeekp == NULL)
michael@0 847 goto loser;
michael@0 848
michael@0 849 /* create new signing time attribute */
michael@0 850 if (NSS_SMIMEUtil_CreateMSSMIMEEncKeyPrefs(poolp, smimeekp, cert) != SECSuccess)
michael@0 851 goto loser;
michael@0 852
michael@0 853 if ((attr = NSS_CMSAttribute_Create(poolp, SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE, smimeekp, PR_TRUE)) == NULL)
michael@0 854 goto loser;
michael@0 855
michael@0 856 if (NSS_CMSSignerInfo_AddAuthAttr(signerinfo, attr) != SECSuccess)
michael@0 857 goto loser;
michael@0 858
michael@0 859 PORT_ArenaUnmark (poolp, mark);
michael@0 860 return SECSuccess;
michael@0 861
michael@0 862 loser:
michael@0 863 PORT_ArenaRelease (poolp, mark);
michael@0 864 return SECFailure;
michael@0 865 }
michael@0 866
michael@0 867 /*
michael@0 868 * NSS_CMSSignerInfo_AddCounterSignature - countersign a signerinfo
michael@0 869 *
michael@0 870 * 1. digest the DER-encoded signature value of the original signerinfo
michael@0 871 * 2. create new signerinfo with correct version, sid, digestAlg
michael@0 872 * 3. add message-digest authAttr, but NO content-type
michael@0 873 * 4. sign the authAttrs
michael@0 874 * 5. DER-encode the new signerInfo
michael@0 875 * 6. add the whole thing to original signerInfo's unAuthAttrs
michael@0 876 * as a SEC_OID_PKCS9_COUNTER_SIGNATURE attribute
michael@0 877 *
michael@0 878 * XXXX give back the new signerinfo?
michael@0 879 */
michael@0 880 SECStatus
michael@0 881 NSS_CMSSignerInfo_AddCounterSignature(NSSCMSSignerInfo *signerinfo,
michael@0 882 SECOidTag digestalg, CERTCertificate signingcert)
michael@0 883 {
michael@0 884 /* XXXX TBD XXXX */
michael@0 885 return SECFailure;
michael@0 886 }
michael@0 887
michael@0 888 /*
michael@0 889 * XXXX the following needs to be done in the S/MIME layer code
michael@0 890 * after signature of a signerinfo is verified
michael@0 891 */
michael@0 892 SECStatus
michael@0 893 NSS_SMIMESignerInfo_SaveSMIMEProfile(NSSCMSSignerInfo *signerinfo)
michael@0 894 {
michael@0 895 CERTCertificate *cert = NULL;
michael@0 896 SECItem *profile = NULL;
michael@0 897 NSSCMSAttribute *attr;
michael@0 898 SECItem *stime = NULL;
michael@0 899 SECItem *ekp;
michael@0 900 CERTCertDBHandle *certdb;
michael@0 901 int save_error;
michael@0 902 SECStatus rv;
michael@0 903 PRBool must_free_cert = PR_FALSE;
michael@0 904
michael@0 905 certdb = CERT_GetDefaultCertDB();
michael@0 906
michael@0 907 /* sanity check - see if verification status is ok (unverified does not count...) */
michael@0 908 if (signerinfo->verificationStatus != NSSCMSVS_GoodSignature)
michael@0 909 return SECFailure;
michael@0 910
michael@0 911 /* find preferred encryption cert */
michael@0 912 if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr) &&
michael@0 913 (attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
michael@0 914 SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE, PR_TRUE)) != NULL)
michael@0 915 { /* we have a SMIME_ENCRYPTION_KEY_PREFERENCE attribute! */
michael@0 916 ekp = NSS_CMSAttribute_GetValue(attr);
michael@0 917 if (ekp == NULL)
michael@0 918 return SECFailure;
michael@0 919
michael@0 920 /* we assume that all certs coming with the message have been imported to the */
michael@0 921 /* temporary database */
michael@0 922 cert = NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference(certdb, ekp);
michael@0 923 if (cert == NULL)
michael@0 924 return SECFailure;
michael@0 925 must_free_cert = PR_TRUE;
michael@0 926 }
michael@0 927
michael@0 928 if (cert == NULL) {
michael@0 929 /* no preferred cert found?
michael@0 930 * find the cert the signerinfo is signed with instead */
michael@0 931 cert = NSS_CMSSignerInfo_GetSigningCertificate(signerinfo, certdb);
michael@0 932 if (cert == NULL || cert->emailAddr == NULL || !cert->emailAddr[0])
michael@0 933 return SECFailure;
michael@0 934 }
michael@0 935
michael@0 936 /* verify this cert for encryption (has been verified for signing so far) */
michael@0 937 /* don't verify this cert for encryption. It may just be a signing cert.
michael@0 938 * that's OK, we can still save the S/MIME profile. The encryption cert
michael@0 939 * should have already been saved */
michael@0 940 #ifdef notdef
michael@0 941 if (CERT_VerifyCert(certdb, cert, PR_TRUE, certUsageEmailRecipient, PR_Now(), signerinfo->cmsg->pwfn_arg, NULL) != SECSuccess) {
michael@0 942 if (must_free_cert)
michael@0 943 CERT_DestroyCertificate(cert);
michael@0 944 return SECFailure;
michael@0 945 }
michael@0 946 #endif
michael@0 947
michael@0 948 /* XXX store encryption cert permanently? */
michael@0 949
michael@0 950 /*
michael@0 951 * Remember the current error set because we do not care about
michael@0 952 * anything set by the functions we are about to call.
michael@0 953 */
michael@0 954 save_error = PORT_GetError();
michael@0 955
michael@0 956 if (!NSS_CMSArray_IsEmpty((void **)signerinfo->authAttr)) {
michael@0 957 attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
michael@0 958 SEC_OID_PKCS9_SMIME_CAPABILITIES,
michael@0 959 PR_TRUE);
michael@0 960 profile = NSS_CMSAttribute_GetValue(attr);
michael@0 961 attr = NSS_CMSAttributeArray_FindAttrByOidTag(signerinfo->authAttr,
michael@0 962 SEC_OID_PKCS9_SIGNING_TIME,
michael@0 963 PR_TRUE);
michael@0 964 stime = NSS_CMSAttribute_GetValue(attr);
michael@0 965 }
michael@0 966
michael@0 967 rv = CERT_SaveSMimeProfile (cert, profile, stime);
michael@0 968 if (must_free_cert)
michael@0 969 CERT_DestroyCertificate(cert);
michael@0 970
michael@0 971 /*
michael@0 972 * Restore the saved error in case the calls above set a new
michael@0 973 * one that we do not actually care about.
michael@0 974 */
michael@0 975 PORT_SetError (save_error);
michael@0 976
michael@0 977 return rv;
michael@0 978 }
michael@0 979
michael@0 980 /*
michael@0 981 * NSS_CMSSignerInfo_IncludeCerts - set cert chain inclusion mode for this signer
michael@0 982 */
michael@0 983 SECStatus
michael@0 984 NSS_CMSSignerInfo_IncludeCerts(NSSCMSSignerInfo *signerinfo, NSSCMSCertChainMode cm, SECCertUsage usage)
michael@0 985 {
michael@0 986 if (signerinfo->cert == NULL)
michael@0 987 return SECFailure;
michael@0 988
michael@0 989 /* don't leak if we get called twice */
michael@0 990 if (signerinfo->certList != NULL) {
michael@0 991 CERT_DestroyCertificateList(signerinfo->certList);
michael@0 992 signerinfo->certList = NULL;
michael@0 993 }
michael@0 994
michael@0 995 switch (cm) {
michael@0 996 case NSSCMSCM_None:
michael@0 997 signerinfo->certList = NULL;
michael@0 998 break;
michael@0 999 case NSSCMSCM_CertOnly:
michael@0 1000 signerinfo->certList = CERT_CertListFromCert(signerinfo->cert);
michael@0 1001 break;
michael@0 1002 case NSSCMSCM_CertChain:
michael@0 1003 signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_FALSE);
michael@0 1004 break;
michael@0 1005 case NSSCMSCM_CertChainWithRoot:
michael@0 1006 signerinfo->certList = CERT_CertChainFromCert(signerinfo->cert, usage, PR_TRUE);
michael@0 1007 break;
michael@0 1008 }
michael@0 1009
michael@0 1010 if (cm != NSSCMSCM_None && signerinfo->certList == NULL)
michael@0 1011 return SECFailure;
michael@0 1012
michael@0 1013 return SECSuccess;
michael@0 1014 }

mercurial