/*
 * 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;
}
/* void start (in NSSCMSContentCallback cb, in voidPtr arg); */
NS_IMETHODIMP nsCMSDecoder::Start(NSSCMSContentCallback cb, void * arg)
{
  nsNSSShutDownPreventionLock locker;
  if (isAlreadyShutDown())
    return NS_ERROR_NOT_AVAILABLE;

  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Start\n"));
  m_ctx = new PipUIContext();

  m_dcx = NSS_CMSDecoder_Start(0, cb, arg, 0, m_ctx, 0, 0);
  if (!m_dcx) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSDecoder::Start - can't start decoder\n"));
    return NS_ERROR_FAILURE;
  }
  return NS_OK;
}
Exemple #3
0
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;
}
Exemple #4
0
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;
}