Exemple #1
0
static FILE *
encode(FILE *ip, FILE **hp, FILE **bp, NSSCMSMessage *msg,
		void    (*cb)(void *, const char *, unsigned long))
{
	NSSCMSEncoderContext	*ctx;
	char	*buf = NULL, *cp;
	size_t	bufsize = 0, buflen, count;
	FILE	*op;

	if (smime_split(ip, hp, bp, -1, 0) == STOP)
		return NULL;
	if ((op = Ftemp(&cp, "Ry", "w+", 0600, 1)) == NULL) {
		perror("tempfile");
		return NULL;
	}
	rm(cp);
	Ftfree(&cp);
	if ((ctx = NSS_CMSEncoder_Start(msg,
			cb, op,
			NULL, NULL,
			password_cb, "Pass phrase:",
			NULL, NULL,
			NULL, NULL)) == NULL) {
		fprintf(stderr, "Cannot create encoder context.\n");
		Fclose(op);
		return NULL;
	}
	count = fsize(*bp);
	while (fgetline(&buf, &bufsize, &count, &buflen, *bp, 0) != NULL) {
		buf[buflen-1] = '\r';
		buf[buflen] = '\n';
		if (NSS_CMSEncoder_Update(ctx, buf, buflen+1) != 0) {
			fprintf(stderr, "Failed to add data to encoder.\n");
			Fclose(op);
			return NULL;
		}
	}
	free(buf);
	if (NSS_CMSEncoder_Finish(ctx) != 0) {
		fprintf(stderr, "Failed to encode data.\n");
		Fclose(op);
		return NULL;
	}
	rewind(*bp);
	cb(op, (void *)-1, 0);
	fflush(op);
	if (ferror(op)) {
		perror("tempfile");
		Fclose(op);
		return NULL;
	}
	rewind(op);
	return op;
}
/* void finish (); */
NS_IMETHODIMP nsCMSEncoder::Finish()
{
  nsNSSShutDownPreventionLock locker;
  if (isAlreadyShutDown())
    return NS_ERROR_NOT_AVAILABLE;

  nsresult rv = NS_OK;
  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Finish\n"));
  if (!m_ecx || NSS_CMSEncoder_Finish(m_ecx) != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSEncoder::Finish - can't finish encoder\n"));
    rv = NS_ERROR_FAILURE;
  }
  m_ecx = nsnull;
  return rv;
}
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;
}
static int
sm_sign(CamelCipherContext *context, const char *userid, CamelCipherHash hash, CamelMimePart *ipart, CamelMimePart *opart, CamelException *ex)
{
	int res = -1;
	NSSCMSMessage *cmsg;
	CamelStream *ostream, *istream;
	SECOidTag sechash;
	NSSCMSEncoderContext *enc;
	CamelDataWrapper *dw;
	CamelContentType *ct;

	switch (hash) {
	case CAMEL_CIPHER_HASH_SHA1:
	case CAMEL_CIPHER_HASH_DEFAULT:
	default:
		sechash = SEC_OID_SHA1;
		break;
	case CAMEL_CIPHER_HASH_MD5:
		sechash = SEC_OID_MD5;
		break;
	}

	cmsg = sm_signing_cmsmessage((CamelSMIMEContext *)context, userid, sechash,
				     ((CamelSMIMEContext *)context)->priv->sign_mode == CAMEL_SMIME_SIGN_CLEARSIGN, ex);
	if (cmsg == NULL)
		return -1;

	ostream = camel_stream_mem_new();

	/* FIXME: stream this, we stream output at least */
	istream = camel_stream_mem_new();
	if (camel_cipher_canonical_to_stream(ipart,
					     CAMEL_MIME_FILTER_CANON_STRIP
					     |CAMEL_MIME_FILTER_CANON_CRLF
					     |CAMEL_MIME_FILTER_CANON_FROM, istream) == -1) {
		camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM,
				     _("Could not generate signing data: %s"), g_strerror(errno));
		goto fail;
	}

	enc = NSS_CMSEncoder_Start(cmsg,
				   sm_write_stream, ostream, /* DER output callback  */
				   NULL, NULL,     /* destination storage  */
				   NULL, NULL,	   /* password callback    */
				   NULL, NULL,     /* decrypt key callback */
				   NULL, NULL );   /* detached digests    */
	if (!enc) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create encoder context"));
		goto fail;
	}

	if (NSS_CMSEncoder_Update(enc, (char *) ((CamelStreamMem *)istream)->buffer->data, ((CamelStreamMem *)istream)->buffer->len) != SECSuccess) {
		NSS_CMSEncoder_Cancel(enc);
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Failed to add data to CMS encoder"));
		goto fail;
	}

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

	res = 0;

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

	if (((CamelSMIMEContext *)context)->priv->sign_mode == CAMEL_SMIME_SIGN_CLEARSIGN) {
		CamelMultipartSigned *mps;
		CamelMimePart *sigpart;

		sigpart = camel_mime_part_new();
		ct = camel_content_type_new("application", "x-pkcs7-signature");
		camel_content_type_set_param(ct, "name", "smime.p7s");
		camel_data_wrapper_set_mime_type_field(dw, ct);
		camel_content_type_unref(ct);

		camel_medium_set_content_object((CamelMedium *)sigpart, dw);

		camel_mime_part_set_filename(sigpart, "smime.p7s");
		camel_mime_part_set_disposition(sigpart, "attachment");
		camel_mime_part_set_encoding(sigpart, CAMEL_TRANSFER_ENCODING_BASE64);

		mps = camel_multipart_signed_new();
		ct = camel_content_type_new("multipart", "signed");
		camel_content_type_set_param(ct, "micalg", camel_cipher_hash_to_id(context, hash));
		camel_content_type_set_param(ct, "protocol", context->sign_protocol);
		camel_data_wrapper_set_mime_type_field((CamelDataWrapper *)mps, ct);
		camel_content_type_unref(ct);
		camel_multipart_set_boundary((CamelMultipart *)mps, NULL);

		mps->signature = sigpart;
		mps->contentraw = istream;
		camel_stream_reset(istream);
		camel_object_ref(istream);

		camel_medium_set_content_object((CamelMedium *)opart, (CamelDataWrapper *)mps);
	} else {
		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", "signed-data");
		camel_data_wrapper_set_mime_type_field(dw, ct);
		camel_content_type_unref(ct);

		camel_medium_set_content_object((CamelMedium *)opart, dw);

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

	camel_object_unref(dw);
fail:
	camel_object_unref(ostream);
	camel_object_unref(istream);

	return res;
}
// nsCMSSecureMessage::SendMessage
nsresult nsCMSSecureMessage::
SendMessage(const char *msg, const char *base64Cert, char ** _retval)
{
  nsNSSShutDownPreventionLock locker;
  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage\n"));
  nsresult rv = NS_OK;
  CERTCertificate *cert = 0;
  NSSCMSMessage *cmsMsg = 0;
  unsigned char *certDER = 0;
  PRInt32 derLen;
  NSSCMSEnvelopedData *env;
  NSSCMSContentInfo *cinfo;
  NSSCMSRecipientInfo *rcpt;
  SECItem item;
  SECItem output;
  PLArenaPool *arena = PORT_NewArena(1024);
  SECStatus s;
  nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext();

  /* Step 0. Create a CMS Message */
  cmsMsg = NSS_CMSMessage_Create(NULL);
  if (!cmsMsg) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't create NSSCMSMessage\n"));
    rv = NS_ERROR_FAILURE;
    goto done;
  }

  /* Step 1.  Import the certificate into NSS */
  rv = decode(base64Cert, &certDER, &derLen);
  if (NS_FAILED(rv)) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't decode / import cert into NSS\n"));
    goto done;
  }

  cert = CERT_DecodeCertFromPackage((char *)certDER, derLen);
  if (!cert) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't decode cert from package\n"));
    rv = NS_ERROR_FAILURE;
    goto done;
  }

#if 0
  cert->dbhandle = CERT_GetDefaultCertDB();  /* work-around */
#endif

  /* Step 2.  Get a signature cert */

  /* Step 3. Build inner (signature) content */

  /* Step 4. Build outer (enveloped) content */
  env = NSS_CMSEnvelopedData_Create(cmsMsg, SEC_OID_DES_EDE3_CBC, 0);
  if (!env) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't create envelope data\n"));
    rv = NS_ERROR_FAILURE;
    goto done;
  }

  cinfo = NSS_CMSEnvelopedData_GetContentInfo(env);
  item.data = (unsigned char *)msg;
  item.len = strlen(msg);  /* XPCOM equiv?? */
  s = NSS_CMSContentInfo_SetContent_Data(cmsMsg, cinfo, 0, PR_FALSE);
  if (s != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't set content data\n"));
    rv = NS_ERROR_FAILURE;
    goto done;
  }

  rcpt = NSS_CMSRecipientInfo_Create(cmsMsg, cert);
  if (!rcpt) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't create recipient info\n"));
    rv = NS_ERROR_FAILURE;
    goto done;
  }

  s = NSS_CMSEnvelopedData_AddRecipient(env, rcpt);
  if (s != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't add recipient\n"));
    rv = NS_ERROR_FAILURE;
    goto done;
  }

  /* Step 5. Add content to message */
  cinfo = NSS_CMSMessage_GetContentInfo(cmsMsg);
  s = NSS_CMSContentInfo_SetContent_EnvelopedData(cmsMsg, cinfo, env);
  if (s != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't set content enveloped data\n"));
    rv = NS_ERROR_FAILURE;
    goto done;
  }
  
  /* Step 6. Encode */
  NSSCMSEncoderContext *ecx;

  output.data = 0; output.len = 0;
  ecx = NSS_CMSEncoder_Start(cmsMsg, 0, 0, &output, arena,
            0, ctx, 0, 0, 0, 0);
  if (!ecx) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't start cms encoder\n"));
    rv = NS_ERROR_FAILURE;
    goto done;
  }

  s = NSS_CMSEncoder_Update(ecx, msg, strlen(msg));
  if (s != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't update encoder\n"));
    rv = NS_ERROR_FAILURE;
    goto done;
  }

  s = NSS_CMSEncoder_Finish(ecx);
  if (s != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSSecureMessage::SendMessage - can't finish encoder\n"));
    rv = NS_ERROR_FAILURE;
    goto done;
  }

  /* Step 7. Base64 encode and return the result */
  rv = encode(output.data, output.len, _retval);

done:
  if (certDER) nsCRT::free((char *)certDER);
  if (cert) CERT_DestroyCertificate(cert);
  if (cmsMsg) NSS_CMSMessage_Destroy(cmsMsg);
  if (arena) PORT_FreeArena(arena, PR_FALSE);  /* PR_FALSE? */

  return rv;
}
Exemple #6
0
NS_IMETHODIMP
nsNSSCertificate::ExportAsCMS(uint32_t chainMode,
                              uint32_t *aLength, uint8_t **aArray)
{
  NS_ENSURE_ARG(aLength);
  NS_ENSURE_ARG(aArray);

  nsNSSShutDownPreventionLock locker;
  if (isAlreadyShutDown())
    return NS_ERROR_NOT_AVAILABLE;

  if (!mCert)
    return NS_ERROR_FAILURE;

  switch (chainMode) {
    case nsIX509Cert3::CMS_CHAIN_MODE_CertOnly:
    case nsIX509Cert3::CMS_CHAIN_MODE_CertChain:
    case nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot:
      break;
    default:
      return NS_ERROR_INVALID_ARG;
  };

  PLArenaPool *arena = PORT_NewArena(1024);
  PLArenaPoolCleanerFalseParam arenaCleaner(arena);
  if (!arena) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
           ("nsNSSCertificate::ExportAsCMS - out of memory\n"));
    return NS_ERROR_OUT_OF_MEMORY;
  }

  NSSCMSMessage *cmsg = NSS_CMSMessage_Create(nullptr);
  NSSCMSMessageCleaner cmsgCleaner(cmsg);
  if (!cmsg) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
           ("nsNSSCertificate::ExportAsCMS - can't create CMS message\n"));
    return NS_ERROR_OUT_OF_MEMORY;
  }

  /*
   * first, create SignedData with the certificate only (no chain)
   */
  NSSCMSSignedData *sigd = NSS_CMSSignedData_CreateCertsOnly(cmsg, mCert, false);
  NSSCMSSignedDataCleaner sigdCleaner(sigd);
  if (!sigd) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
           ("nsNSSCertificate::ExportAsCMS - can't create SignedData\n"));
    return NS_ERROR_FAILURE;
  }

  /*
   * Calling NSS_CMSSignedData_CreateCertsOnly() will not allow us
   * to specify the inclusion of the root, but CERT_CertChainFromCert() does.
   * Since CERT_CertChainFromCert() also includes the certificate itself,
   * we have to start at the issuing cert (to avoid duplicate certs
   * in the SignedData).
   */
  if (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChain ||
      chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot) {
    CERTCertificate *issuerCert = CERT_FindCertIssuer(mCert, PR_Now(), certUsageAnyCA);
    CERTCertificateCleaner issuerCertCleaner(issuerCert);
    /*
     * the issuerCert of a self signed root is the cert itself,
     * so make sure we're not adding duplicates, again
     */
    if (issuerCert && issuerCert != mCert) {
      bool includeRoot = 
        (chainMode == nsIX509Cert3::CMS_CHAIN_MODE_CertChainWithRoot);
      CERTCertificateList *certChain = CERT_CertChainFromCert(issuerCert, certUsageAnyCA, includeRoot);
      CERTCertificateListCleaner certChainCleaner(certChain);
      if (certChain) {
        if (NSS_CMSSignedData_AddCertList(sigd, certChain) == SECSuccess) {
          certChainCleaner.detach();
        }
        else {
          PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
                 ("nsNSSCertificate::ExportAsCMS - can't add chain\n"));
          return NS_ERROR_FAILURE;
        }
      }
      else { 
        /* try to add the issuerCert, at least */
        if (NSS_CMSSignedData_AddCertificate(sigd, issuerCert)
            == SECSuccess) {
          issuerCertCleaner.detach();
        }
        else {
          PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
                 ("nsNSSCertificate::ExportAsCMS - can't add issuer cert\n"));
          return NS_ERROR_FAILURE;
        }
      }
    }
  }

  NSSCMSContentInfo *cinfo = NSS_CMSMessage_GetContentInfo(cmsg);
  if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd)
       == SECSuccess) {
    sigdCleaner.detach();
  }
  else {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
           ("nsNSSCertificate::ExportAsCMS - can't attach SignedData\n"));
    return NS_ERROR_FAILURE;
  }

  SECItem certP7 = { siBuffer, nullptr, 0 };
  NSSCMSEncoderContext *ecx = NSS_CMSEncoder_Start(cmsg, nullptr, nullptr, &certP7, arena,
                                                   nullptr, nullptr, nullptr, nullptr, nullptr,
                                                   nullptr);
  if (!ecx) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
           ("nsNSSCertificate::ExportAsCMS - can't create encoder context\n"));
    return NS_ERROR_FAILURE;
  }

  if (NSS_CMSEncoder_Finish(ecx) != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
           ("nsNSSCertificate::ExportAsCMS - failed to add encoded data\n"));
    return NS_ERROR_FAILURE;
  }

  *aArray = (uint8_t*)nsMemory::Alloc(certP7.len);
  if (!*aArray)
    return NS_ERROR_OUT_OF_MEMORY;

  memcpy(*aArray, certP7.data, certP7.len);
  *aLength = certP7.len;
  return NS_OK;
}
Exemple #7
0
UtlBoolean SmimeBody::nssSmimeEncrypt(int numResipientCerts,
                           const char* derPublicKeyCerts[],
                           int derPublicKeyCertLengths[],
                           const char* dataToEncrypt,
                           int dataToEncryptLength,
                           UtlBoolean encryptedDataInBase64Format,
                           UtlString& encryptedData)
{
    UtlBoolean encryptionSucceeded = FALSE;
    encryptedData.remove(0);

#ifdef ENABLE_NSS_SMIME

    // nickname can be NULL as we are not putting this in a database
    char *nickname = NULL;
    // copyDER = true so we copy the DER format cert passed in so memory
    // is internally alloc'd and freed
    PRBool copyDER = true;

    // Create an envelope or container for the encrypted data
    SECOidTag algorithm = SEC_OID_DES_EDE3_CBC; // or  SEC_OID_AES_128_CBC
    // Should be able to get the key size from the cert somehow
    int keysize = 1024;
    NSSCMSMessage* cmsMessage = NSS_CMSMessage_Create(NULL);
    NSSCMSEnvelopedData* myEnvelope =
        NSS_CMSEnvelopedData_Create(cmsMessage, algorithm, keysize);

    // Do the following for each recipient if there is more than one.
    // For each recipient:
    for(int certIndex = 0; certIndex < numResipientCerts; certIndex++)
    {
        // Convert the DER to a NSS CERT
        SECItem derFormatCertItem;
        SECItem* derFormatCertItemPtr = &derFormatCertItem;
        derFormatCertItem.data = (unsigned char*) derPublicKeyCerts[certIndex];
        derFormatCertItem.len = derPublicKeyCertLengths[certIndex];
        CERTCertificate* myCertFromDer = NULL;
        myCertFromDer = __CERT_DecodeDERCertificate(&derFormatCertItem,
                                                   copyDER,
                                                   nickname);

        // Add just the recipient Subject key Id, if it exists to the envelope
        // This is the minimal information needed to identify which recipient
        // the the symetric/session key is encrypted for
        NSSCMSRecipientInfo* recipientInfo = NULL;

        // Add the full set of recipient information including
        // the Cert. issuer location and org. info.
        recipientInfo =
            NSS_CMSRecipientInfo_Create(cmsMessage, myCertFromDer);

        if(recipientInfo)
        {
            if(NSS_CMSEnvelopedData_AddRecipient(myEnvelope , recipientInfo) !=
                SECSuccess)
            {
                NSS_CMSEnvelopedData_Destroy(myEnvelope);
                myEnvelope = NULL;
                NSS_CMSRecipientInfo_Destroy(recipientInfo);
            }
        }
        // No recipientInfo
        else
        {
            NSS_CMSEnvelopedData_Destroy(myEnvelope);
            myEnvelope = NULL;
        }

    } //end for each recipient

    // Get the content out of the envelop
    NSSCMSContentInfo* envelopContentInfo =
       NSS_CMSEnvelopedData_GetContentInfo(myEnvelope);

    //TODO: why are we copying or setting the content pointer from the envelope into the msg????????
    if (NSS_CMSContentInfo_SetContent_Data(cmsMessage,
                                           envelopContentInfo,
                                           NULL,
                                           PR_FALSE) !=
        SECSuccess)
    {
        // release cmsg and other stuff
        NSS_CMSEnvelopedData_Destroy(myEnvelope);
        myEnvelope = NULL;
    }

    //TODO: why are we copying or setting the content pointer from the message and
    // putting it back into the msg????????
    NSSCMSContentInfo* messageContentInfo =
        NSS_CMSMessage_GetContentInfo(cmsMessage);
    if(NSS_CMSContentInfo_SetContent_EnvelopedData(cmsMessage,
                                                   messageContentInfo,
                                                   myEnvelope) !=
       SECSuccess)
    {
        // release cmsg and other stuff
        NSS_CMSEnvelopedData_Destroy(myEnvelope);
        myEnvelope = NULL;
    }

    if(cmsMessage)
    {
        // Create an encoder  and context to do the encryption.
        // The encodedItem will stort the encoded result
        //SECItem encodedItem;
        //encodedItem.data = NULL;
        //encodedItem.len = 0;
        //SECITEM_AllocItem(NULL, &encodedItem, 0);
        printf("start encoder\n");
        NSSCMSEncoderContext* encoderContext =
            NSS_CMSEncoder_Start(cmsMessage, nssOutToUtlString, &encryptedData, NULL,
                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL);

        // Add encrypted content
        printf("update encoder\n");
        NSS_CMSEncoder_Update(encoderContext, dataToEncrypt, dataToEncryptLength);

        // Finished encrypting
        printf("finish encoder\n");
        NSS_CMSEncoder_Finish(encoderContext);

        myEnvelope = NULL;

        if(encryptedData.length() > 0)
        {
            encryptionSucceeded = TRUE;
        }

        // Clean up the message memory, the envelop gets cleaned up
        // with the message
        NSS_CMSMessage_Destroy(cmsMessage);
        cmsMessage = NULL;
    }

#else
    Os::Logger::instance().log(FAC_SIP, PRI_ERR, "SmimeBody::nssSmimeEncrypt invoked with ENABLE_NSS_SMIME not defined");
#endif

    return(encryptionSucceeded);
}