Ejemplo n.º 1
0
static int
sm_encrypt(CamelCipherContext *context, const char *userid, GPtrArray *recipients, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex)
{
	struct _CamelSMIMEContextPrivate *p = ((CamelSMIMEContext *)context)->priv;
	/*NSSCMSRecipientInfo **recipient_infos;*/
	CERTCertificate **recipient_certs = NULL;
	NSSCMSContentInfo *cinfo;
	PK11SymKey *bulkkey = NULL;
	SECOidTag bulkalgtag;
	int bulkkeysize, i;
	CK_MECHANISM_TYPE type;
	PK11SlotInfo *slot;
	PLArenaPool *poolp;
	NSSCMSMessage *cmsg = NULL;
	NSSCMSEnvelopedData *envd;
 	NSSCMSEncoderContext *enc = NULL;
	CamelStreamMem *mem;
	CamelStream *ostream = NULL;
	CamelDataWrapper *dw;
	CamelContentType *ct;

	poolp = PORT_NewArena(1024);
	if (poolp == NULL) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, g_strerror (ENOMEM));
		return -1;
	}

	/* Lookup all recipients certs, for later working */
	recipient_certs = (CERTCertificate **)PORT_ArenaZAlloc(poolp, sizeof(*recipient_certs[0])*(recipients->len + 1));
	if (recipient_certs == NULL) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, g_strerror (ENOMEM));
		goto fail;
	}

	for (i=0;i<recipients->len;i++) {
		recipient_certs[i] = CERT_FindCertByNicknameOrEmailAddr(p->certdb, recipients->pdata[i]);
		if (recipient_certs[i] == NULL) {
			camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find certificate for `%s'"), recipients->pdata[i]);
			goto fail;
		}
	}

	/* Find a common algorithm, probably 3DES anyway ... */
	if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipient_certs, &bulkalgtag, &bulkkeysize) != SECSuccess) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find common bulk encryption algorithm"));
		goto fail;
	}

	/* Generate a new bulk key based on the common algorithm - expensive */
	type = PK11_AlgtagToMechanism(bulkalgtag);
	slot = PK11_GetBestSlot(type, context);
	if (slot == NULL) {
		/* PORT_GetError(); ?? */
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot allocate slot for encryption bulk key"));
		goto fail;
	}

	bulkkey = PK11_KeyGen(slot, type, NULL, bulkkeysize/8, context);
	PK11_FreeSlot(slot);

	/* Now we can start building the message */
	/* msg->envelopedData->data */
	cmsg = NSS_CMSMessage_Create(NULL);
	if (cmsg == NULL) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Message"));
		goto fail;
	}

	envd = NSS_CMSEnvelopedData_Create(cmsg, bulkalgtag, bulkkeysize);
	if (envd == NULL) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Enveloped data"));
		goto fail;
	}

	cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
	if (NSS_CMSContentInfo_SetContent_EnvelopedData(cmsg, cinfo, envd) != SECSuccess) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS Enveloped data"));
		goto fail;
	}

	cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd);
	if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) != SECSuccess) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS data object"));
		goto fail;
	}

	/* add recipient certs */
	for (i=0;recipient_certs[i];i++) {
		NSSCMSRecipientInfo *ri = NSS_CMSRecipientInfo_Create(cmsg, recipient_certs[i]);

		if (ri == NULL) {
			camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Recipient information"));
			goto fail;
		}

		if (NSS_CMSEnvelopedData_AddRecipient(envd, ri) != SECSuccess) {
			camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add CMS Recipient information"));
			goto fail;
		}
	}

	/* dump it out */
	ostream = camel_stream_mem_new();
	enc = NSS_CMSEncoder_Start(cmsg,
				   sm_write_stream, ostream,
				   NULL, NULL,
				   NULL, NULL,
				   sm_decrypt_key, bulkkey,
				   NULL, NULL);
	if (enc == NULL) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create encoder context"));
		goto fail;
	}

	/* FIXME: Stream the input */
	/* FIXME: Canonicalise the input? */
	mem = (CamelStreamMem *)camel_stream_mem_new();
	camel_data_wrapper_write_to_stream((CamelDataWrapper *)ipart, (CamelStream *)mem);
	if (NSS_CMSEncoder_Update(enc, (char *) mem->buffer->data, mem->buffer->len) != SECSuccess) {
		NSS_CMSEncoder_Cancel(enc);
		camel_object_unref(mem);
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to add data to encoder"));
		goto fail;
	}
	camel_object_unref(mem);

	if (NSS_CMSEncoder_Finish(enc) != SECSuccess) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to encode data"));
		goto fail;
	}

	PK11_FreeSymKey(bulkkey);
	NSS_CMSMessage_Destroy(cmsg);
	for (i=0;recipient_certs[i];i++)
		CERT_DestroyCertificate(recipient_certs[i]);
	PORT_FreeArena(poolp, PR_FALSE);

	dw = camel_data_wrapper_new();
	camel_data_wrapper_construct_from_stream(dw, ostream);
	camel_object_unref(ostream);
	dw->encoding = CAMEL_TRANSFER_ENCODING_BINARY;

	ct = camel_content_type_new("application", "x-pkcs7-mime");
	camel_content_type_set_param(ct, "name", "smime.p7m");
	camel_content_type_set_param(ct, "smime-type", "enveloped-data");
	camel_data_wrapper_set_mime_type_field(dw, ct);
	camel_content_type_unref(ct);

	camel_medium_set_content_object((CamelMedium *)opart, dw);
	camel_object_unref(dw);

	camel_mime_part_set_disposition(opart, "attachment");
	camel_mime_part_set_filename(opart, "smime.p7m");
	camel_mime_part_set_description(opart, "S/MIME Encrypted Message");
	camel_mime_part_set_encoding(opart, CAMEL_TRANSFER_ENCODING_BASE64);

	return 0;

fail:
	if (ostream)
		camel_object_unref(ostream);
	if (cmsg)
		NSS_CMSMessage_Destroy(cmsg);
	if (bulkkey)
		PK11_FreeSymKey(bulkkey);

	if (recipient_certs) {
		for (i=0;recipient_certs[i];i++)
			CERT_DestroyCertificate(recipient_certs[i]);
	}

	PORT_FreeArena(poolp, PR_FALSE);

	return -1;
}
Ejemplo n.º 2
0
NS_IMETHODIMP nsCMSMessage::CreateEncrypted(nsIArray * aRecipientCerts)
{
  nsNSSShutDownPreventionLock locker;
  if (isAlreadyShutDown())
    return NS_ERROR_NOT_AVAILABLE;

  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted\n"));
  NSSCMSContentInfo *cinfo;
  NSSCMSEnvelopedData *envd;
  NSSCMSRecipientInfo *recipientInfo;
  nsZeroTerminatedCertArray recipientCerts;
  SECOidTag bulkAlgTag;
  int keySize;
  PRUint32 i;
  nsCOMPtr<nsIX509Cert2> nssRecipientCert;
  nsresult rv = NS_ERROR_FAILURE;

  // Check the recipient certificates //
  PRUint32 recipientCertCount;
  aRecipientCerts->GetLength(&recipientCertCount);
  PR_ASSERT(recipientCertCount > 0);

  if (!recipientCerts.allocate(recipientCertCount)) {
    goto loser;
  }

  for (i=0; i<recipientCertCount; i++) {
    nsCOMPtr<nsIX509Cert> x509cert = do_QueryElementAt(aRecipientCerts, i);

    nssRecipientCert = do_QueryInterface(x509cert);

    if (!nssRecipientCert)
      return NS_ERROR_FAILURE;

    CERTCertificate *c = nssRecipientCert->GetCert();
    CERTCertificateCleaner rcCleaner(c);
    recipientCerts.set(i, c);
  }
  
  // Find a bulk key algorithm //
  if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipientCerts.getRawArray(), &bulkAlgTag,
                                            &keySize) != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't find bulk alg for recipients\n"));
    rv = NS_ERROR_CMS_ENCRYPT_NO_BULK_ALG;
    goto loser;
  }

  m_cmsMsg = NSS_CMSMessage_Create(NULL);
  if (m_cmsMsg == nsnull) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create new cms message\n"));
    rv = NS_ERROR_OUT_OF_MEMORY;
    goto loser;
  }

  if ((envd = NSS_CMSEnvelopedData_Create(m_cmsMsg, bulkAlgTag, keySize)) == nsnull) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create enveloped data\n"));
    goto loser;
  }

  cinfo = NSS_CMSMessage_GetContentInfo(m_cmsMsg);
  if (NSS_CMSContentInfo_SetContent_EnvelopedData(m_cmsMsg, cinfo, envd) != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create content enveloped data\n"));
    goto loser;
  }

  cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd);
  if (NSS_CMSContentInfo_SetContent_Data(m_cmsMsg, cinfo, nsnull, PR_FALSE) != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't set content data\n"));
    goto loser;
  }

  // Create and attach recipient information //
  for (i=0; i < recipientCertCount; i++) {
    CERTCertificate *rc = recipientCerts.get(i);
    CERTCertificateCleaner rcCleaner(rc);
    if ((recipientInfo = NSS_CMSRecipientInfo_Create(m_cmsMsg, rc)) == nsnull) {
      PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't create recipient info\n"));
      goto loser;
    }
    if (NSS_CMSEnvelopedData_AddRecipient(envd, recipientInfo) != SECSuccess) {
      PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateEncrypted - can't add recipient info\n"));
      goto loser;
    }
  }

  return NS_OK;
loser:
  if (m_cmsMsg) {
    NSS_CMSMessage_Destroy(m_cmsMsg);
    m_cmsMsg = nsnull;
  }

  return rv;
}