SECStatus NSS_CMSSignedData_Decode_BeforeData(NSSCMSSignedData *sigd) { if (!sigd) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* set up the digests */ if (sigd->digestAlgorithms != NULL && sigd->digests == NULL) { /* if digests are already there, do nothing */ sigd->contentInfo.digcx = NSS_CMSDigestContext_StartMultiple(sigd->digestAlgorithms); if (sigd->contentInfo.digcx == NULL) return SECFailure; } return SECSuccess; }
SECStatus NSS_CMSSignedData_Encode_BeforeData(NSSCMSSignedData *sigd) { if (!sigd) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } /* set up the digests */ if (sigd->digests && sigd->digests[0]) { sigd->contentInfo.digcx = NULL; /* don't attempt to make new ones. */ } else if (sigd->digestAlgorithms != NULL) { sigd->contentInfo.digcx = NSS_CMSDigestContext_StartMultiple(sigd->digestAlgorithms); if (sigd->contentInfo.digcx == NULL) return SECFailure; } return SECSuccess; }
SECStatus NSS_CMSSignedData_Decode_BeforeData(NSSCMSSignedData *sigd) { SECStatus rv; if (!sigd) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } rv = NSS_CMSContentInfo_Private_Init(&sigd->contentInfo); if (rv != SECSuccess) { return SECFailure; } /* handle issue with Windows 2003 servers and kerberos */ if (sigd->digestAlgorithms != NULL) { int i; for (i=0; sigd->digestAlgorithms[i] != NULL; i++) { SECAlgorithmID *algid = sigd->digestAlgorithms[i]; SECOidTag senttag= SECOID_FindOIDTag(&algid->algorithm); SECOidTag maptag = NSS_CMSUtil_MapSignAlgs(senttag); if (maptag != senttag) { SECOidData *hashoid = SECOID_FindOIDByTag(maptag); rv = SECITEM_CopyItem(sigd->cmsg->poolp, &algid->algorithm ,&hashoid->oid); if (rv != SECSuccess) { return rv; } } } } /* set up the digests */ if (sigd->digestAlgorithms != NULL && sigd->digests == NULL) { /* if digests are already there, do nothing */ sigd->contentInfo.privateInfo->digcx = NSS_CMSDigestContext_StartMultiple(sigd->digestAlgorithms); if (sigd->contentInfo.privateInfo->digcx == NULL) return SECFailure; } return SECSuccess; }
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; }