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