NSSCMSSignerInfo* nsCMSMessage::GetTopLevelSignerInfo() { nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) return nsnull; if (!m_cmsMsg) return nsnull; if (!NSS_CMSMessage_IsSigned(m_cmsMsg)) return nsnull; NSSCMSContentInfo *cinfo = NSS_CMSMessage_ContentLevel(m_cmsMsg, 0); if (!cinfo) return nsnull; NSSCMSSignedData *sigd = (NSSCMSSignedData*)NSS_CMSContentInfo_GetContent(cinfo); if (!sigd) return nsnull; PR_ASSERT(NSS_CMSSignedData_SignerInfoCount(sigd) > 0); return NSS_CMSSignedData_GetSignerInfo(sigd, 0); }
static int verify1(struct message *m, int n) { SECItem **digests; NSSCMSMessage *msg; PLArenaPool *poolp; SECAlgorithmID **algids; CERTCertDBHandle *handle; int nlevels, i; int status = 0; int foundsender = 0; char *sender; if ((m = getsig(m, n, &msg)) == NULL) return 1; sender = getsender(m); handle = CERT_GetDefaultCertDB(); nlevels = NSS_CMSMessage_ContentLevelCount(msg); for (i = 0; i < nlevels; i++) { NSSCMSContentInfo *content; SECOidTag tag; content = NSS_CMSMessage_ContentLevel(msg, i); tag = NSS_CMSContentInfo_GetContentTypeTag(content); if (tag == SEC_OID_PKCS7_SIGNED_DATA) { NSSCMSSignedData *data; int nsigners, j; if ((data = NSS_CMSContentInfo_GetContent(content)) == NULL) { fprintf(stderr, "Signed data missing for " "message %d.\n", n); status = -1; break; } if (!NSS_CMSSignedData_HasDigests(data)) { algids = NSS_CMSSignedData_GetDigestAlgs(data); if (getdig(m, n, &digests, &poolp, algids) != OKAY) { status = -1; break; } if (NSS_CMSSignedData_SetDigests(data, algids, digests) != SECSuccess) { fprintf(stderr, "Cannot set digests " "for message %d.\n", n); status = -1; break; } PORT_FreeArena(poolp, PR_FALSE); } if (NSS_CMSSignedData_ImportCerts(data, handle, certUsageEmailSigner, PR_FALSE) != SECSuccess) { fprintf(stderr, "Cannot temporarily import " "certificates for " "message %d.\n", n); status = -1; break; } nsigners = NSS_CMSSignedData_SignerInfoCount(data); if (nsigners == 0) { fprintf(stderr, "Message %d has no signers.\n", n); status = -1; break; } if (!NSS_CMSSignedData_HasDigests(data)) { fprintf(stderr, "Message %d has no digests.\n", n); status = -1; break; } for (j = 0; j < nsigners; j++) { const char *svs; NSSCMSSignerInfo *info; NSSCMSVerificationStatus vs; SECStatus bad; CERTCertificate *cert; const char *addr; int passed = 0; info = NSS_CMSSignedData_GetSignerInfo(data, j); cert = NSS_CMSSignerInfo_GetSigningCertificate (info, handle); bad = NSS_CMSSignedData_VerifySignerInfo(data, j, handle, certUsageEmailSigner); vs = NSS_CMSSignerInfo_GetVerificationStatus (info); svs = NSS_CMSUtil_VerificationStatusToString (vs); addr = CERT_GetCertEmailAddress(&cert->subject); if (sender != NULL && addr != NULL && asccasecmp(sender, addr) == 0) foundsender++; else { addr = CERT_GetFirstEmailAddress(cert); while (sender && addr) { if (!asccasecmp(sender, addr)) { foundsender++; break; } addr = CERT_GetNextEmailAddress (cert, addr); } } if (CERT_VerifyCertNow(handle, cert, PR_TRUE, certUsageEmailSigner, NULL) != SECSuccess) fprintf(stderr, "Bad certificate for " "signer <%s> of " "message %d: %s.\n", addr ? addr : "?", n, bad_cert_str()); else passed++; if (bad) fprintf(stderr, "Bad status for " "signer <%s> of " "message %d: %s.\n", addr ? addr : "?", n, svs); else passed++; if (passed < 2) status = -1; else if (status == 0) status = 1; } } } if (foundsender == 0) { if (sender) { fprintf(stderr, "Signers of message " "%d do not include the sender <%s>\n", n, sender); status = -1; } else fprintf(stderr, "Warning: Message %d has no From: " "header field.\n", n); } else if (status == 1) printf("Message %d was verified successfully.\n", n); if (status == 0) fprintf(stderr, "No verification information found in " "message %d.\n", n); NSS_CMSMessage_Destroy(msg); return status != 1; }
enum okay smime_certsave(struct message *m, int n, FILE *op) { NSSCMSMessage *msg; CERTCertDBHandle *handle; int nlevels, i, cnt = 0; enum okay ok = OKAY; if (nss_init() == STOP) return STOP; if ((m = getsig(m, n, &msg)) == NULL) return 1; handle = CERT_GetDefaultCertDB(); nlevels = NSS_CMSMessage_ContentLevelCount(msg); for (i = 0; i < nlevels; i++) { NSSCMSContentInfo *content; SECOidTag tag; content = NSS_CMSMessage_ContentLevel(msg, i); tag = NSS_CMSContentInfo_GetContentTypeTag(content); if (tag == SEC_OID_PKCS7_SIGNED_DATA) { NSSCMSSignedData *data; int nsigners, j; if ((data = NSS_CMSContentInfo_GetContent(content)) == NULL) { fprintf(stderr, "Signed data missing for " "message %d.\n", n); ok = STOP; break; } if (NSS_CMSSignedData_ImportCerts(data, handle, certUsageEmailSigner, PR_FALSE) != SECSuccess) { fprintf(stderr, "Cannot temporarily import " "certificates for " "message %d.\n", n); ok = STOP; break; } nsigners = NSS_CMSSignedData_SignerInfoCount(data); if (nsigners == 0) { fprintf(stderr, "Message %d has no signers.\n", n); ok = STOP; break; } for (j = 0; j < nsigners; j++) { NSSCMSSignerInfo *info; CERTCertificateList *list; CERTCertificate *cert; int k; info = NSS_CMSSignedData_GetSignerInfo(data, j); list = NSS_CMSSignerInfo_GetCertList(info); if (list) { for (k = 0; k < list->len; k++) { cert = (CERTCertificate *) &list->certs[k]; dumpcert(cert, op); cnt++; } } cert = NSS_CMSSignerInfo_GetSigningCertificate (info, handle); if (cert) { dumpcert(cert, op); cnt++; } } } } NSS_CMSMessage_Destroy(msg); if (cnt == 0) { fprintf(stderr, "No certificates found in message %d.\n", n); ok = STOP; } return ok; }
static CamelCipherValidity * sm_verify_cmsg(CamelCipherContext *context, NSSCMSMessage *cmsg, CamelStream *extstream, CamelException *ex) { struct _CamelSMIMEContextPrivate *p = ((CamelSMIMEContext *)context)->priv; NSSCMSSignedData *sigd = NULL; NSSCMSEnvelopedData *envd; NSSCMSEncryptedData *encd; SECAlgorithmID **digestalgs; NSSCMSDigestContext *digcx; int count, i, nsigners, j; SECItem **digests; PLArenaPool *poolp = NULL; CamelStreamMem *mem; NSSCMSVerificationStatus status; CamelCipherValidity *valid; GString *description; description = g_string_new(""); valid = camel_cipher_validity_new(); camel_cipher_validity_set_valid(valid, TRUE); status = NSSCMSVS_Unverified; /* NB: this probably needs to go into a decoding routine that can be used for processing enveloped data too */ count = NSS_CMSMessage_ContentLevelCount(cmsg); for (i = 0; i < count; i++) { NSSCMSContentInfo *cinfo = NSS_CMSMessage_ContentLevel(cmsg, i); SECOidTag typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo); switch (typetag) { case SEC_OID_PKCS7_SIGNED_DATA: sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo); if (sigd == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("No signed data in signature")); goto fail; } /* need to build digests of the content */ if (!NSS_CMSSignedData_HasDigests(sigd)) { if (extstream == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Digests missing from enveloped data")); goto fail; } if ((poolp = PORT_NewArena(1024)) == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, g_strerror (ENOMEM)); goto fail; } digestalgs = NSS_CMSSignedData_GetDigestAlgs(sigd); digcx = NSS_CMSDigestContext_StartMultiple(digestalgs); if (digcx == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot calculate digests")); goto fail; } mem = (CamelStreamMem *)camel_stream_mem_new(); camel_stream_write_to_stream(extstream, (CamelStream *)mem); NSS_CMSDigestContext_Update(digcx, mem->buffer->data, mem->buffer->len); camel_object_unref(mem); if (NSS_CMSDigestContext_FinishMultiple(digcx, poolp, &digests) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot calculate digests")); goto fail; } if (NSS_CMSSignedData_SetDigests(sigd, digestalgs, digests) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot set message digests")); goto fail; } PORT_FreeArena(poolp, PR_FALSE); poolp = NULL; } /* import all certificates present */ if (NSS_CMSSignedData_ImportCerts(sigd, p->certdb, certUsageEmailSigner, PR_TRUE) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Certificate import failed")); goto fail; } if (NSS_CMSSignedData_ImportCerts(sigd, p->certdb, certUsageEmailRecipient, PR_TRUE) != SECSuccess) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Certificate import failed")); goto fail; } /* check for certs-only message */ nsigners = NSS_CMSSignedData_SignerInfoCount(sigd); if (nsigners == 0) { /* already imported certs above, not sure what usage we should use here or if this isn't handled above */ if (NSS_CMSSignedData_VerifyCertsOnly(sigd, p->certdb, certUsageEmailSigner) != SECSuccess) { g_string_printf(description, _("Certificate is the only message, cannot verify certificates")); } else { status = NSSCMSVS_GoodSignature; g_string_printf(description, _("Certificate is the only message, certificates imported and verified")); } } else { if (!NSS_CMSSignedData_HasDigests(sigd)) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find signature digests")); goto fail; } for (j = 0; j < nsigners; j++) { NSSCMSSignerInfo *si; char *cn, *em; si = NSS_CMSSignedData_GetSignerInfo(sigd, j); NSS_CMSSignedData_VerifySignerInfo(sigd, j, p->certdb, certUsageEmailSigner); status = NSS_CMSSignerInfo_GetVerificationStatus(si); cn = NSS_CMSSignerInfo_GetSignerCommonName(si); em = NSS_CMSSignerInfo_GetSignerEmailAddress(si); g_string_append_printf(description, _("Signer: %s <%s>: %s\n"), cn?cn:"<unknown>", em?em:"<unknown>", sm_status_description(status)); camel_cipher_validity_add_certinfo(valid, CAMEL_CIPHER_VALIDITY_SIGN, cn, em); if (cn) PORT_Free(cn); if (em) PORT_Free(em); if (status != NSSCMSVS_GoodSignature) camel_cipher_validity_set_valid(valid, FALSE); } } break; case SEC_OID_PKCS7_ENVELOPED_DATA: envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent(cinfo); break; case SEC_OID_PKCS7_ENCRYPTED_DATA: encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo); break; case SEC_OID_PKCS7_DATA: break; default: break; } } camel_cipher_validity_set_valid(valid, status == NSSCMSVS_GoodSignature); camel_cipher_validity_set_description(valid, description->str); g_string_free(description, TRUE); return valid; fail: camel_cipher_validity_free(valid); g_string_free(description, TRUE); return NULL; }
nsresult nsCMSMessage::CommonVerifySignature(unsigned char* aDigestData, PRUint32 aDigestDataLen) { nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) return NS_ERROR_NOT_AVAILABLE; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature, content level count %d\n", NSS_CMSMessage_ContentLevelCount(m_cmsMsg))); NSSCMSContentInfo *cinfo = nsnull; NSSCMSSignedData *sigd = nsnull; NSSCMSSignerInfo *si; PRInt32 nsigners; nsresult rv = NS_ERROR_FAILURE; if (!NSS_CMSMessage_IsSigned(m_cmsMsg)) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - not signed\n")); return NS_ERROR_CMS_VERIFY_NOT_SIGNED; } cinfo = NSS_CMSMessage_ContentLevel(m_cmsMsg, 0); if (cinfo) { // I don't like this hard cast. We should check in some way, that we really have this type. sigd = (NSSCMSSignedData*)NSS_CMSContentInfo_GetContent(cinfo); } if (!sigd) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - no content info\n")); rv = NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO; goto loser; } if (aDigestData && aDigestDataLen) { SECItem digest; digest.data = aDigestData; digest.len = aDigestDataLen; if (NSS_CMSSignedData_SetDigestValue(sigd, SEC_OID_SHA1, &digest)) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - bad digest\n")); rv = NS_ERROR_CMS_VERIFY_BAD_DIGEST; goto loser; } } // Import certs. Note that import failure is not a signature verification failure. // if (NSS_CMSSignedData_ImportCerts(sigd, CERT_GetDefaultCertDB(), certUsageEmailRecipient, PR_TRUE) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - can not import certs\n")); } nsigners = NSS_CMSSignedData_SignerInfoCount(sigd); PR_ASSERT(nsigners > 0); si = NSS_CMSSignedData_GetSignerInfo(sigd, 0); // See bug 324474. We want to make sure the signing cert is // still valid at the current time. if (CERT_VerifyCertificateNow(CERT_GetDefaultCertDB(), si->cert, PR_TRUE, certificateUsageEmailSigner, si->cmsg->pwfn_arg, NULL) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not trusted now\n")); rv = NS_ERROR_CMS_VERIFY_UNTRUSTED; goto loser; } // We verify the first signer info, only // if (NSS_CMSSignedData_VerifySignerInfo(sigd, 0, CERT_GetDefaultCertDB(), certUsageEmailSigner) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - unable to verify signature\n")); if (NSSCMSVS_SigningCertNotFound == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not found\n")); rv = NS_ERROR_CMS_VERIFY_NOCERT; } else if(NSSCMSVS_SigningCertNotTrusted == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not trusted at signing time\n")); rv = NS_ERROR_CMS_VERIFY_UNTRUSTED; } else if(NSSCMSVS_Unverified == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - can not verify\n")); rv = NS_ERROR_CMS_VERIFY_ERROR_UNVERIFIED; } else if(NSSCMSVS_ProcessingError == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - processing error\n")); rv = NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; } else if(NSSCMSVS_BadSignature == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - bad signature\n")); rv = NS_ERROR_CMS_VERIFY_BAD_SIGNATURE; } else if(NSSCMSVS_DigestMismatch == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - digest mismatch\n")); rv = NS_ERROR_CMS_VERIFY_DIGEST_MISMATCH; } else if(NSSCMSVS_SignatureAlgorithmUnknown == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - algo unknown\n")); rv = NS_ERROR_CMS_VERIFY_UNKNOWN_ALGO; } else if(NSSCMSVS_SignatureAlgorithmUnsupported == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - algo not supported\n")); rv = NS_ERROR_CMS_VERIFY_UNSUPPORTED_ALGO; } else if(NSSCMSVS_MalformedSignature == si->verificationStatus) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - malformed signature\n")); rv = NS_ERROR_CMS_VERIFY_MALFORMED_SIGNATURE; } goto loser; } // Save the profile. Note that save import failure is not a signature verification failure. // if (NSS_SMIMESignerInfo_SaveSMIMEProfile(si) != SECSuccess) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - unable to save smime profile\n")); } rv = NS_OK; loser: return rv; }
nsresult VerifyCMSDetachedSignatureIncludingCertificate( const SECItem& buffer, const SECItem& detachedDigest, nsresult (*verifyCertificate)(CERTCertificate* cert, void* context, void* pinArg), void *verifyCertificateContext, void* pinArg) { // XXX: missing pinArg is tolerated. if (NS_WARN_IF(!buffer.data && buffer.len > 0) || NS_WARN_IF(!detachedDigest.data && detachedDigest.len > 0) || (!verifyCertificate) || NS_WARN_IF(!verifyCertificateContext)) { return NS_ERROR_INVALID_ARG; } ScopedNSSCMSMessage cmsMsg(NSS_CMSMessage_CreateFromDER(const_cast<SECItem*>(&buffer), nullptr, nullptr, nullptr, nullptr, nullptr, nullptr)); if (!cmsMsg) { return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; } if (!NSS_CMSMessage_IsSigned(cmsMsg.get())) { return NS_ERROR_CMS_VERIFY_NOT_SIGNED; } NSSCMSContentInfo* cinfo = NSS_CMSMessage_ContentLevel(cmsMsg.get(), 0); if (!cinfo) { return NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO; } // signedData is non-owning NSSCMSSignedData* signedData = reinterpret_cast<NSSCMSSignedData*>(NSS_CMSContentInfo_GetContent(cinfo)); if (!signedData) { return NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO; } // Set digest value. if (NSS_CMSSignedData_SetDigestValue(signedData, SEC_OID_SHA1, const_cast<SECItem*>(&detachedDigest))) { return NS_ERROR_CMS_VERIFY_BAD_DIGEST; } // Parse the certificates into CERTCertificate objects held in memory so // verifyCertificate will be able to find them during path building. ScopedCERTCertList certs(CERT_NewCertList()); if (!certs) { return NS_ERROR_OUT_OF_MEMORY; } if (signedData->rawCerts) { for (size_t i = 0; signedData->rawCerts[i]; ++i) { ScopedCERTCertificate cert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), signedData->rawCerts[i], nullptr, false, true)); // Skip certificates that fail to parse if (cert) { if (CERT_AddCertToListTail(certs.get(), cert.get()) == SECSuccess) { cert.forget(); // ownership transfered } else { return NS_ERROR_OUT_OF_MEMORY; } } } } // Get the end-entity certificate. int numSigners = NSS_CMSSignedData_SignerInfoCount(signedData); if (NS_WARN_IF(numSigners != 1)) { return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; } // signer is non-owning. NSSCMSSignerInfo* signer = NSS_CMSSignedData_GetSignerInfo(signedData, 0); if (NS_WARN_IF(!signer)) { return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; } CERTCertificate* signerCert = NSS_CMSSignerInfo_GetSigningCertificate(signer, CERT_GetDefaultCertDB()); if (!signerCert) { return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; } nsresult rv = verifyCertificate(signerCert, verifyCertificateContext, pinArg); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // See NSS_CMSContentInfo_GetContentTypeOID, which isn't exported from NSS. SECOidData* contentTypeOidData = SECOID_FindOID(&signedData->contentInfo.contentType); if (!contentTypeOidData) { return NS_ERROR_CMS_VERIFY_ERROR_PROCESSING; } return MapSECStatus(NSS_CMSSignerInfo_Verify(signer, const_cast<SECItem*>(&detachedDigest), &contentTypeOidData->oid)); }
/* * NSS_CMSSignedData_Encode_AfterData - do all the necessary things to a SignedData * after all the encapsulated data was passed through the encoder. * * In detail: * - create the signatures in all the SignerInfos * * Please note that nothing is done to the Certificates and CRLs in the message - this * is entirely the responsibility of our callers. */ SECStatus NSS_CMSSignedData_Encode_AfterData(NSSCMSSignedData *sigd) { NSSCMSSignerInfo **signerinfos, *signerinfo; NSSCMSContentInfo *cinfo; SECOidTag digestalgtag; SECStatus ret = SECFailure; SECStatus rv; SECItem *contentType; int certcount; int i, ci, cli, n, rci, si; PLArenaPool *poolp; CERTCertificateList *certlist; extern const SEC_ASN1Template NSSCMSSignerInfoTemplate[]; if (!sigd) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } poolp = sigd->cmsg->poolp; cinfo = &(sigd->contentInfo); /* did we have digest calculation going on? */ if (cinfo->privateInfo && cinfo->privateInfo->digcx) { rv = NSS_CMSDigestContext_FinishMultiple(cinfo->privateInfo->digcx, poolp, &(sigd->digests)); /* error has been set by NSS_CMSDigestContext_FinishMultiple */ cinfo->privateInfo->digcx = NULL; if (rv != SECSuccess) goto loser; } signerinfos = sigd->signerInfos; certcount = 0; /* prepare all the SignerInfos (there may be none) */ for (i = 0; i < NSS_CMSSignedData_SignerInfoCount(sigd); i++) { signerinfo = NSS_CMSSignedData_GetSignerInfo(sigd, i); /* find correct digest for this signerinfo */ digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo); n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag); if (n < 0 || sigd->digests == NULL || sigd->digests[n] == NULL) { /* oops - digest not found */ PORT_SetError(SEC_ERROR_DIGEST_NOT_FOUND); goto loser; } /* XXX if our content is anything else but data, we need to force the * presence of signed attributes (RFC2630 5.3 "signedAttributes is a * collection...") */ /* pass contentType here as we want a contentType attribute */ if ((contentType = NSS_CMSContentInfo_GetContentTypeOID(cinfo)) == NULL) goto loser; /* sign the thing */ rv = NSS_CMSSignerInfo_Sign(signerinfo, sigd->digests[n], contentType); if (rv != SECSuccess) goto loser; /* while we're at it, count number of certs in certLists */ certlist = NSS_CMSSignerInfo_GetCertList(signerinfo); if (certlist) certcount += certlist->len; } /* this is a SET OF, so we need to sort them guys */ rv = NSS_CMSArray_SortByDER((void **)signerinfos, NSSCMSSignerInfoTemplate, NULL); if (rv != SECSuccess) goto loser; /* * now prepare certs & crls */ /* count the rest of the certs */ if (sigd->certs != NULL) { for (ci = 0; sigd->certs[ci] != NULL; ci++) certcount++; } if (sigd->certLists != NULL) { for (cli = 0; sigd->certLists[cli] != NULL; cli++) certcount += sigd->certLists[cli]->len; } if (certcount == 0) { sigd->rawCerts = NULL; } else { /* * Combine all of the certs and cert chains into rawcerts. * Note: certcount is an upper bound; we may not need that many slots * but we will allocate anyway to avoid having to do another pass. * (The temporary space saving is not worth it.) * * XXX ARGH - this NEEDS to be fixed. need to come up with a decent * SetOfDERcertficates implementation */ sigd->rawCerts = (SECItem **)PORT_ArenaAlloc(poolp, (certcount + 1) * sizeof(SECItem *)); if (sigd->rawCerts == NULL) return SECFailure; /* * XXX Want to check for duplicates and not add *any* cert that is * already in the set. This will be more important when we start * dealing with larger sets of certs, dual-key certs (signing and * encryption), etc. For the time being we can slide by... * * XXX ARGH - this NEEDS to be fixed. need to come up with a decent * SetOfDERcertficates implementation */ rci = 0; if (signerinfos != NULL) { for (si = 0; signerinfos[si] != NULL; si++) { signerinfo = signerinfos[si]; for (ci = 0; ci < signerinfo->certList->len; ci++) sigd->rawCerts[rci++] = &(signerinfo->certList->certs[ci]); } } if (sigd->certs != NULL) { for (ci = 0; sigd->certs[ci] != NULL; ci++) sigd->rawCerts[rci++] = &(sigd->certs[ci]->derCert); } if (sigd->certLists != NULL) { for (cli = 0; sigd->certLists[cli] != NULL; cli++) { for (ci = 0; ci < sigd->certLists[cli]->len; ci++) sigd->rawCerts[rci++] = &(sigd->certLists[cli]->certs[ci]); } } sigd->rawCerts[rci] = NULL; /* this is a SET OF, so we need to sort them guys - we have the DER already, though */ NSS_CMSArray_Sort((void **)sigd->rawCerts, NSS_CMSUtil_DERCompare, NULL, NULL); } ret = SECSuccess; loser: return ret; }
/* * NSS_CMSSignedData_Encode_BeforeStart - do all the necessary things to a SignedData * before start of encoding. * * In detail: * - find out about the right value to put into sigd->version * - come up with a list of digestAlgorithms (which should be the union of the algorithms * in the signerinfos). * If we happen to have a pre-set list of algorithms (and digest values!), we * check if we have all the signerinfos' algorithms. If not, this is an error. */ SECStatus NSS_CMSSignedData_Encode_BeforeStart(NSSCMSSignedData *sigd) { NSSCMSSignerInfo *signerinfo; SECOidTag digestalgtag; SECItem *dummy; int version; SECStatus rv; PRBool haveDigests = PR_FALSE; int n, i; PLArenaPool *poolp; if (!sigd) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } poolp = sigd->cmsg->poolp; /* we assume that we have precomputed digests if there is a list of algorithms, and */ /* a chunk of data for each of those algorithms */ if (sigd->digestAlgorithms != NULL && sigd->digests != NULL) { for (i = 0; sigd->digestAlgorithms[i] != NULL; i++) { if (sigd->digests[i] == NULL) break; } if (sigd->digestAlgorithms[i] == NULL) /* reached the end of the array? */ haveDigests = PR_TRUE; /* yes: we must have all the digests */ } version = NSS_CMS_SIGNED_DATA_VERSION_BASIC; /* RFC2630 5.1 "version is the syntax version number..." */ if (NSS_CMSContentInfo_GetContentTypeTag(&(sigd->contentInfo)) != SEC_OID_PKCS7_DATA) version = NSS_CMS_SIGNED_DATA_VERSION_EXT; /* prepare all the SignerInfos (there may be none) */ for (i = 0; i < NSS_CMSSignedData_SignerInfoCount(sigd); i++) { signerinfo = NSS_CMSSignedData_GetSignerInfo(sigd, i); /* RFC2630 5.1 "version is the syntax version number..." */ if (NSS_CMSSignerInfo_GetVersion(signerinfo) != NSS_CMS_SIGNER_INFO_VERSION_ISSUERSN) version = NSS_CMS_SIGNED_DATA_VERSION_EXT; /* collect digestAlgorithms from SignerInfos */ /* (we need to know which algorithms we have when the content comes in) */ /* do not overwrite any existing digestAlgorithms (and digest) */ digestalgtag = NSS_CMSSignerInfo_GetDigestAlgTag(signerinfo); n = NSS_CMSAlgArray_GetIndexByAlgTag(sigd->digestAlgorithms, digestalgtag); if (n < 0 && haveDigests) { /* oops, there is a digestalg we do not have a digest for */ /* but we were supposed to have all the digests already... */ goto loser; } else if (n < 0) { /* add the digestAlgorithm & a NULL digest */ rv = NSS_CMSSignedData_AddDigest(poolp, sigd, digestalgtag, NULL); if (rv != SECSuccess) goto loser; } else { /* found it, nothing to do */ } } dummy = SEC_ASN1EncodeInteger(poolp, &(sigd->version), (long)version); if (dummy == NULL) return SECFailure; /* this is a SET OF, so we need to sort them guys */ rv = NSS_CMSArray_SortByDER((void **)sigd->digestAlgorithms, SEC_ASN1_GET(SECOID_AlgorithmIDTemplate), (void **)sigd->digests); if (rv != SECSuccess) return SECFailure; return SECSuccess; loser: return SECFailure; }