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