/* void update (in string bug, in long len); */ NS_IMETHODIMP nsCMSDecoder::Update(const char *buf, PRInt32 len) { nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) return NS_ERROR_NOT_AVAILABLE; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Update\n")); NSS_CMSDecoder_Update(m_dcx, (char *)buf, len); return NS_OK; }
/* * nsCMSSecureMessage::ReceiveMessage */ nsresult nsCMSSecureMessage:: ReceiveMessage(const char *msg, char **_retval) { nsNSSShutDownPreventionLock locker; PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage\n")); nsresult rv = NS_OK; NSSCMSDecoderContext *dcx; unsigned char *der = 0; PRInt32 derLen; NSSCMSMessage *cmsMsg = 0; SECItem *content; nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); /* Step 1. Decode the base64 wrapper */ rv = decode(msg, &der, &derLen); if (NS_FAILED(rv)) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage - can't base64 decode\n")); goto done; } dcx = NSS_CMSDecoder_Start(0, 0, 0, /* pw */ 0, ctx, /* key */ 0, 0); if (!dcx) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage - can't start decoder\n")); rv = NS_ERROR_FAILURE; goto done; } (void)NSS_CMSDecoder_Update(dcx, (char *)der, derLen); cmsMsg = NSS_CMSDecoder_Finish(dcx); if (!cmsMsg) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage - can't finish decoder\n")); rv = NS_ERROR_FAILURE; /* Memory leak on dcx?? */ goto done; } content = NSS_CMSMessage_GetContent(cmsMsg); if (!content) { PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::ReceiveMessage - can't get content\n")); rv = NS_ERROR_FAILURE; goto done; } /* Copy the data */ *_retval = (char*)malloc(content->len+1); memcpy(*_retval, content->data, content->len); (*_retval)[content->len] = 0; done: if (der) free(der); if (cmsMsg) NSS_CMSMessage_Destroy(cmsMsg); return rv; }
static struct message * getsig(struct message *m, int n, NSSCMSMessage **msg) { struct message *x; char *ct, *pt, *boundary = NULL, *cte; char *buf = NULL; size_t bufsize = 0, buflen, count, boundlen = -1; int part; FILE *fp; NSSCMSDecoderContext *decctx; struct str in, out; char *to, *cc; int inhdr, binary; int detached = 1; loop: if ((ct = hfield("content-type", m)) == NULL) goto not; if (strncmp(ct, "application/x-pkcs7-mime", 24) == 0 || strncmp(ct, "application/pkcs7-mime", 22) == 0) { to = hfield("to", m); cc = hfield("cc", m); if ((x = smime_decrypt(m, to, cc, 1)) == NULL) return NULL; if (x != (struct message *)-1) { m = x; goto loop; } detached = 0; } else if (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) { not: fprintf(stderr, "Message %d is not an S/MIME signed message.\n", n); return NULL; } else boundlen = strlen(boundary); if ((decctx = NSS_CMSDecoder_Start(NULL, NULL, NULL, password_cb, "Pass phrase:", NULL, NULL)) == NULL) { fprintf(stderr, "Cannot start decoder.\n"); return NULL; } if ((fp = setinput(&mb, m, NEED_BODY)) == NULL) { return NULL; } count = m->m_size; part = 0; inhdr = 1; binary = 0; while (fgetline(&buf, &bufsize, &count, &buflen, fp, 0) != NULL) { if (detached && boundary && buflen >= boundlen + 1 && strncmp(buf, boundary, boundlen) == 0) { if (buf[boundlen] == '\n') { part++; inhdr = 1; binary = 0; if (part >= 3) { fprintf(stderr, "Message %d has too " "many parts.\n", n); free(buf); return NULL; } continue; } if (buf[boundlen] == '-' && buf[boundlen+1] == '-' && buf[boundlen+2] == '\n') break; } else if (buf[0] == '\n') { inhdr = 0; continue; } if ((!detached || part == 2) && inhdr == 0) { if (binary) NSS_CMSDecoder_Update(decctx, buf, buflen); else { in.s = buf; in.l = buflen; mime_fromb64_b(&in, &out, 0, fp); NSS_CMSDecoder_Update(decctx, out.s, out.l); free(out.s); } } if (buflen == 1 && buf[0] == '\n') inhdr = 0; if (inhdr && (cte = thisfield(buf, "content-transfer-encoding")) != NULL && ascncasecmp(cte, "binary", 7) == 0) binary = 1; } free(buf); if ((*msg = NSS_CMSDecoder_Finish(decctx)) == NULL) { fprintf(stderr, "Failed to decode signature for message %d.\n", n); return NULL; } return m; }
struct message * smime_decrypt(struct message *m, const char *to, const char *cc, int signcall) { NSSCMSDecoderContext *ctx; NSSCMSMessage *msg; FILE *op, *hp, *bp; char *buf = NULL; size_t bufsize = 0, buflen, count; char *cp; struct str in, out; FILE *yp; long size; int i, nlevels; int binary = 0; if ((yp = setinput(&mb, m, NEED_BODY)) == NULL) return NULL; if (nss_init() != OKAY) return NULL; if ((op = Ftemp(&cp, "Rp", "w+", 0600, 1)) == NULL) { perror("tempfile"); return NULL; } rm(cp); Ftfree(&cp); if ((ctx = NSS_CMSDecoder_Start(NULL, decoder_cb, op, password_cb, "Pass phrase:", NULL, NULL)) == NULL) { fprintf(stderr, "Cannot start decoder.\n"); return NULL; } size = m->m_size; if ((smime_split(yp, &hp, &bp, size, 1)) == STOP) return NULL; count = fsize(bp); while (fgetline(&buf, &bufsize, &count, &buflen, bp, 0) != NULL) { if (buf[0] == '\n') break; if ((cp = thisfield(buf, "content-transfer-encoding")) != NULL) if (ascncasecmp(cp, "binary", 7) == 0) binary = 1; } while (fgetline(&buf, &bufsize, &count, &buflen, bp, 0) != NULL) { if (binary) NSS_CMSDecoder_Update(ctx, buf, buflen); else { in.s = buf; in.l = buflen; mime_fromb64_b(&in, &out, 0, bp); NSS_CMSDecoder_Update(ctx, out.s, out.l); free(out.s); } } free(buf); if ((msg = NSS_CMSDecoder_Finish(ctx)) == NULL) { fprintf(stderr, "Failed to decode message.\n"); Fclose(hp); Fclose(bp); return NULL; } 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_DATA) { const char *fld = "X-Encryption-Cipher"; SECOidTag alg; int keysize; alg = NSS_CMSContentInfo_GetContentEncAlgTag(content); keysize = NSS_CMSContentInfo_GetBulkKeySize(content); fseek(hp, 0L, SEEK_END); switch (alg) { case 0: if (signcall) { NSS_CMSMessage_Destroy(msg); Fclose(hp); Fclose(bp); setinput(&mb, m, NEED_BODY); return (struct message *)-1; } fprintf(hp, "%s: none\n", fld); break; case SEC_OID_RC2_CBC: fprintf(hp, "%s: RC2, %d bits\n", fld, keysize); break; case SEC_OID_DES_CBC: fprintf(hp, "%s: DES, 56 bits\n", fld); break; case SEC_OID_DES_EDE3_CBC: fprintf(hp, "%s: 3DES, 112/168 bits\n", fld); break; case SEC_OID_FORTEZZA_SKIPJACK: fprintf(hp, "%s: Fortezza\n", fld); break; default: fprintf(hp, "%s: unknown type %lu\n", fld, (unsigned long)alg); } fflush(hp); rewind(hp); } } NSS_CMSMessage_Destroy(msg); fflush(op); rewind(op); Fclose(bp); return smime_decrypt_assemble(m, hp, op); }
static CamelCipherValidity * sm_decrypt(CamelCipherContext *context, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex) { NSSCMSDecoderContext *dec; NSSCMSMessage *cmsg; CamelStreamMem *istream; CamelStream *ostream; CamelCipherValidity *valid = NULL; /* FIXME: This assumes the content is only encrypted. Perhaps its ok for this api to do this ... */ ostream = camel_stream_mem_new(); camel_stream_mem_set_secure((CamelStreamMem *)ostream); /* FIXME: stream this to the decoder incrementally */ istream = (CamelStreamMem *)camel_stream_mem_new(); camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)ipart), (CamelStream *)istream); camel_stream_reset((CamelStream *)istream); dec = NSS_CMSDecoder_Start(NULL, sm_write_stream, ostream, /* content callback */ NULL, NULL, NULL, NULL); /* decrypt key callback */ if (NSS_CMSDecoder_Update(dec, (char *) istream->buffer->data, istream->buffer->len) != SECSuccess) { printf("decoder update failed\n"); } camel_object_unref(istream); cmsg = NSS_CMSDecoder_Finish(dec); if (cmsg == NULL) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Decoder failed, error %d"), PORT_GetError()); goto fail; } #if 0 /* not sure if we really care about this? */ if (!NSS_CMSMessage_IsEncrypted(cmsg)) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("S/MIME Decrypt: No encrypted content found")); NSS_CMSMessage_Destroy(cmsg); goto fail; } #endif camel_stream_reset(ostream); camel_data_wrapper_construct_from_stream((CamelDataWrapper *)opart, ostream); if (NSS_CMSMessage_IsSigned(cmsg)) { valid = sm_verify_cmsg(context, cmsg, NULL, ex); } else { valid = camel_cipher_validity_new(); valid->encrypt.description = g_strdup(_("Encrypted content")); valid->encrypt.status = CAMEL_CIPHER_VALIDITY_ENCRYPT_ENCRYPTED; } NSS_CMSMessage_Destroy(cmsg); fail: camel_object_unref(ostream); return valid; }
static CamelCipherValidity * sm_verify(CamelCipherContext *context, CamelMimePart *ipart, CamelException *ex) { NSSCMSDecoderContext *dec; NSSCMSMessage *cmsg; CamelStreamMem *mem; CamelStream *constream = NULL; CamelCipherValidity *valid = NULL; CamelContentType *ct; const char *tmp; CamelMimePart *sigpart; CamelDataWrapper *dw; dw = camel_medium_get_content_object((CamelMedium *)ipart); ct = dw->mime_type; /* FIXME: we should stream this to the decoder */ mem = (CamelStreamMem *)camel_stream_mem_new(); if (camel_content_type_is(ct, "multipart", "signed")) { CamelMultipart *mps = (CamelMultipart *)dw; tmp = camel_content_type_param(ct, "protocol"); if (!CAMEL_IS_MULTIPART_SIGNED(mps) || tmp == NULL || (g_ascii_strcasecmp(tmp, context->sign_protocol) != 0 && g_ascii_strcasecmp(tmp, "application/pkcs7-signature") != 0)) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot verify message signature: Incorrect message format")); goto fail; } constream = camel_multipart_signed_get_content_stream((CamelMultipartSigned *)mps, ex); if (constream == NULL) goto fail; sigpart = camel_multipart_get_part(mps, CAMEL_MULTIPART_SIGNED_SIGNATURE); if (sigpart == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot verify message signature: Incorrect message format")); goto fail; } } else if (camel_content_type_is(ct, "application", "x-pkcs7-mime")) { sigpart = ipart; } else { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot verify message signature: Incorrect message format")); goto fail; } dec = NSS_CMSDecoder_Start(NULL, NULL, NULL, /* content callback */ NULL, NULL, /* password callback */ NULL, NULL); /* decrypt key callback */ camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)sigpart), (CamelStream *)mem); (void)NSS_CMSDecoder_Update(dec, (char *) mem->buffer->data, mem->buffer->len); cmsg = NSS_CMSDecoder_Finish(dec); if (cmsg == NULL) { camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Decoder failed")); goto fail; } valid = sm_verify_cmsg(context, cmsg, constream, ex); NSS_CMSMessage_Destroy(cmsg); fail: camel_object_unref(mem); if (constream) camel_object_unref(constream); return valid; }
/* TODO: This is suboptimal, but the only other solution is to pass around NSSCMSMessages */ guint32 camel_smime_context_describe_part(CamelSMIMEContext *context, CamelMimePart *part) { guint32 flags = 0; CamelContentType *ct; const char *tmp; if (!part) return flags; ct = camel_mime_part_get_content_type(part); if (camel_content_type_is(ct, "multipart", "signed")) { tmp = camel_content_type_param(ct, "protocol"); if (tmp && (g_ascii_strcasecmp(tmp, ((CamelCipherContext *)context)->sign_protocol) == 0 || g_ascii_strcasecmp(tmp, "application/pkcs7-signature") == 0)) flags = CAMEL_SMIME_SIGNED; } else if (camel_content_type_is(ct, "application", "x-pkcs7-mime")) { CamelStreamMem *istream; NSSCMSMessage *cmsg; NSSCMSDecoderContext *dec; /* FIXME: stream this to the decoder incrementally */ istream = (CamelStreamMem *)camel_stream_mem_new(); camel_data_wrapper_decode_to_stream(camel_medium_get_content_object((CamelMedium *)part), (CamelStream *)istream); camel_stream_reset((CamelStream *)istream); dec = NSS_CMSDecoder_Start(NULL, NULL, NULL, NULL, NULL, /* password callback */ NULL, NULL); /* decrypt key callback */ NSS_CMSDecoder_Update(dec, (char *) istream->buffer->data, istream->buffer->len); camel_object_unref(istream); cmsg = NSS_CMSDecoder_Finish(dec); if (cmsg) { if (NSS_CMSMessage_IsSigned(cmsg)) { printf("message is signed\n"); flags |= CAMEL_SMIME_SIGNED; } if (NSS_CMSMessage_IsEncrypted(cmsg)) { printf("message is encrypted\n"); flags |= CAMEL_SMIME_ENCRYPTED; } #if 0 if (NSS_CMSMessage_ContainsCertsOrCrls(cmsg)) { printf("message contains certs or crls\n"); flags |= CAMEL_SMIME_CERTS; } #endif NSS_CMSMessage_Destroy(cmsg); } else { printf("Message could not be parsed\n"); } } return flags; }