/* * NSS_CMSSignedData_Decode_AfterData - do all the necessary things to a * SignedData after all the encapsulated data was passed through the decoder. */ SECStatus NSS_CMSSignedData_Decode_AfterData(NSSCMSSignedData *sigd) { SECStatus rv = SECSuccess; if (!sigd) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* did we have digest calculation going on? */ if (sigd->contentInfo.privateInfo && sigd->contentInfo.privateInfo->digcx) { rv = NSS_CMSDigestContext_FinishMultiple(sigd->contentInfo.privateInfo->digcx, sigd->cmsg->poolp, &(sigd->digests)); /* error set by NSS_CMSDigestContext_FinishMultiple */ sigd->contentInfo.privateInfo->digcx = NULL; } return rv; }
static enum okay getdig(struct message *m, int n, SECItem ***digests, PLArenaPool **poolp, SECAlgorithmID **algids) { char *ct, *pt, *boundary; char *buf = NULL; size_t bufsize = 0, buflen, count, boundlen; int part; int nl; FILE *fp; NSSCMSDigestContext *digctx; *poolp = PORT_NewArena(1024); if ((ct = hfield("content-type", m)) == NULL || strncmp(ct, "multipart/signed", 16) || (pt = mime_getparam("protocol", ct)) == NULL || strcmp(pt, "application/x-pkcs7-signature") && strcmp(pt, "application/pkcs7-signature") || (boundary = mime_getboundary(ct)) == NULL) { fprintf(stderr, "Message %d is not an S/MIME signed message.\n", n); return STOP; } boundlen = strlen(boundary); if ((digctx = NSS_CMSDigestContext_StartMultiple(algids)) == NULL) { fprintf(stderr, "Cannot start digest computation.\n"); return STOP; } if ((fp = setinput(&mb, m, NEED_BODY)) == NULL) { return STOP; } count = m->m_size; part = 0; nl = 0; while (fgetline(&buf, &bufsize, &count, &buflen, fp, 0) != NULL) { if (buflen >= boundlen + 1 && strncmp(buf, boundary, boundlen) == 0) { if (buf[boundlen] == '\n') { if (++part >= 2) break; continue; } if (buf[boundlen] == '-' && buf[boundlen+1] == '-' && buf[boundlen+2] == '\n') break; } if (part == 1) { if (nl) { NSS_CMSDigestContext_Update(digctx, (unsigned char *)"\r\n", 2); nl = 0; } if (buf[buflen-1] == '\n') { nl = 1; buflen--; } NSS_CMSDigestContext_Update(digctx, (unsigned char *)buf, buflen); continue; } } free(buf); if (NSS_CMSDigestContext_FinishMultiple(digctx, *poolp, digests) != SECSuccess) { fprintf(stderr, "Error creating digest for message %d\n", n); return STOP; } return OKAY; }
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; }
/* * 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; }