Пример #1
0
static NSSCMSMessage *
sm_signing_cmsmessage(CamelSMIMEContext *context, const char *nick, SECOidTag hash, int detached, CamelException *ex)
{
	struct _CamelSMIMEContextPrivate *p = context->priv;
	NSSCMSMessage *cmsg = NULL;
	NSSCMSContentInfo *cinfo;
	NSSCMSSignedData *sigd;
	NSSCMSSignerInfo *signerinfo;
	CERTCertificate *cert= NULL, *ekpcert = NULL;

	if ((cert = CERT_FindUserCertByUsage(p->certdb,
					     (char *)nick,
					     certUsageEmailSigner,
					     PR_FALSE,
					     NULL)) == NULL) {
		camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find certificate for '%s'"), nick);
		return NULL;
	}

	cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
	if (cmsg == NULL) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS message"));
		goto fail;
	}

	if ((sigd = NSS_CMSSignedData_Create(cmsg)) == NULL) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS signed data"));
		goto fail;
	}

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

	/* if !detatched, the contentinfo will alloc a data item for us */
	cinfo = NSS_CMSSignedData_GetContentInfo(sigd);
	if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, detached) != SECSuccess) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot attach CMS data"));
		goto fail;
	}

	signerinfo = NSS_CMSSignerInfo_Create(cmsg, cert, hash);
	if (signerinfo == NULL) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot create CMS Signer information"));
		goto fail;
	}

	/* we want the cert chain included for this one */
	if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain, certUsageEmailSigner) != SECSuccess) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot find certificate chain"));
		goto fail;
	}

	/* SMIME RFC says signing time should always be added */
	if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) != SECSuccess) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add CMS Signing time"));
		goto fail;
	}

#if 0
	/* this can but needn't be added.  not sure what general usage is */
	if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) {
		fprintf(stderr, "ERROR: cannot add SMIMECaps attribute.\n");
		goto loser;
	}
#endif

	/* Check if we need to send along our return encrypt cert, rfc2633 2.5.3 */
	if (p->send_encrypt_key_prefs) {
		CERTCertificate *enccert = NULL;

		if (p->encrypt_key) {
			/* encrypt key has its own nick */
			if ((ekpcert = CERT_FindUserCertByUsage(
				     p->certdb,
				     p->encrypt_key,
				     certUsageEmailRecipient, PR_FALSE, NULL)) == NULL) {
				camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Encryption certificate for '%s' does not exist"), p->encrypt_key);
				goto fail;
			}
			enccert = ekpcert;
		} else if (CERT_CheckCertUsage(cert, certUsageEmailRecipient) == SECSuccess) {
			/* encrypt key is signing key */
			enccert = cert;
		} else {
			/* encrypt key uses same nick */
			if ((ekpcert = CERT_FindUserCertByUsage(
				     p->certdb, (char *)nick,
				     certUsageEmailRecipient, PR_FALSE, NULL)) == NULL) {
				camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Encryption certificate for '%s' does not exist"), nick);
				goto fail;
			}
			enccert = ekpcert;
		}

		if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, enccert, p->certdb) != SECSuccess) {
			camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add SMIMEEncKeyPrefs attribute"));
			goto fail;
		}

		if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, enccert, p->certdb) != SECSuccess) {
			camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add MS SMIMEEncKeyPrefs attribute"));
			goto fail;
		}

		if (ekpcert != NULL && NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) {
			camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add encryption certificate"));
			goto fail;
		}
	}

	if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) {
		camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot add CMS Signer information"));
		goto fail;
	}

	if (ekpcert)
		CERT_DestroyCertificate(ekpcert);

	if (cert)
		CERT_DestroyCertificate(cert);

	return cmsg;
fail:
	if (ekpcert)
		CERT_DestroyCertificate(ekpcert);

	if (cert)
		CERT_DestroyCertificate(cert);

	NSS_CMSMessage_Destroy(cmsg);

	return NULL;
}
Пример #2
0
FILE *
smime_sign(FILE *ip, struct header *headp)
{
	NSSCMSMessage	*msg;
	NSSCMSContentInfo	*content;
	NSSCMSSignedData	*data;
	NSSCMSSignerInfo	*info;
	CERTCertificate	*cert;
	CERTCertDBHandle	*handle;
	FILE	*hp, *bp, *sp;
	char	*addr;

	if (nss_init() != OKAY)
		return NULL;
	if ((addr = myorigin(headp)) == NULL) {
		fprintf(stderr, "No \"from\" address for signing specified\n");
		return NULL;
	}
	if ((cert = get_signer_cert(addr)) == NULL)
		return NULL;
	handle = CERT_GetDefaultCertDB();
	if ((msg = NSS_CMSMessage_Create(NULL)) == NULL) {
		fprintf(stderr, "Cannot create CMS message.\n");
		return NULL;
	}
	if ((data = NSS_CMSSignedData_Create(msg)) == NULL) {
		fprintf(stderr, "Cannot create CMS signed data.\n");
		return NULL;
	}
	content = NSS_CMSMessage_GetContentInfo(msg);
	if (NSS_CMSContentInfo_SetContent_SignedData(msg, content, data)
			!= SECSuccess) {
		fprintf(stderr, "Cannot attach CMS signed data.\n");
		return NULL;
	}
	content = NSS_CMSSignedData_GetContentInfo(data);
	if (NSS_CMSContentInfo_SetContent_Data(msg, content, NULL, PR_TRUE)
			!= SECSuccess) {
		fprintf(stderr, "Cannot attach CMS data.\n");
		return NULL;
	}
	if ((info = NSS_CMSSignerInfo_Create(msg, cert, SEC_OID_SHA1)) == 0) {
		fprintf(stderr, "Cannot create signed information.\n");
		return NULL;
	}
	if (NSS_CMSSignerInfo_IncludeCerts(info, NSSCMSCM_CertOnly,
				certUsageEmailSigner) != SECSuccess) {
		fprintf(stderr, "Cannot include certificate.\n");
		return NULL;
	}
	if (NSS_CMSSignerInfo_AddSigningTime(info, PR_Now()) != SECSuccess) {
		fprintf(stderr, "Cannot add signing time.\n");
		return NULL;
	}
	if (NSS_CMSSignerInfo_AddSMIMECaps(info) != SECSuccess) {
		fprintf(stderr, "Cannot add S/MIME capabilities.\n");
		return NULL;
	}
	NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(info, cert, handle);
	NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(info, cert, handle);
	if (NSS_CMSSignedData_AddCertificate(data, cert) != SECSuccess) {
		fprintf(stderr, "Cannot add encryption certificate.\n");
		return NULL;
	}
	if (NSS_CMSSignedData_AddSignerInfo(data, info) != SECSuccess) {
		fprintf(stderr, "Cannot add signer information.\n");
		return NULL;
	}
	CERT_DestroyCertificate(cert);
	if ((sp = encode(ip, &hp, &bp, msg, base64_cb)) == NULL) {
		NSS_CMSMessage_Destroy(msg);
		return NULL;
	}
	NSS_CMSMessage_Destroy(msg);
	return smime_sign_assemble(hp, bp, sp);
}
Пример #3
0
NS_IMETHODIMP nsCMSMessage::CreateSigned(nsIX509Cert* aSigningCert, nsIX509Cert* aEncryptCert, unsigned char* aDigestData, PRUint32 aDigestDataLen)
{
  nsNSSShutDownPreventionLock locker;
  if (isAlreadyShutDown())
    return NS_ERROR_NOT_AVAILABLE;

  PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned\n"));
  NSSCMSContentInfo *cinfo;
  NSSCMSSignedData *sigd;
  NSSCMSSignerInfo *signerinfo;
  CERTCertificate *scert = nsnull, *ecert = nsnull;
  nsCOMPtr<nsIX509Cert2> aSigningCert2 = do_QueryInterface(aSigningCert);
  nsresult rv = NS_ERROR_FAILURE;

  /* Get the certs */
  if (aSigningCert2) {
    scert = aSigningCert2->GetCert();
  }
  if (!scert) {
    return NS_ERROR_FAILURE;
  }

  if (aEncryptCert) {
    nsCOMPtr<nsIX509Cert2> aEncryptCert2 = do_QueryInterface(aEncryptCert);
    if (aEncryptCert2) {
      ecert = aEncryptCert2->GetCert();
    }
  }

  CERTCertificateCleaner ecertCleaner(ecert);
  CERTCertificateCleaner scertCleaner(scert);

  /*
   * create the message object
   */
  m_cmsMsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */
  if (m_cmsMsg == NULL) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create new message\n"));
    rv = NS_ERROR_OUT_OF_MEMORY;
    goto loser;
  }

  /*
   * build chain of objects: message->signedData->data
   */
  if ((sigd = NSS_CMSSignedData_Create(m_cmsMsg)) == NULL) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create signed data\n"));
    goto loser;
  }
  cinfo = NSS_CMSMessage_GetContentInfo(m_cmsMsg);
  if (NSS_CMSContentInfo_SetContent_SignedData(m_cmsMsg, cinfo, sigd) 
          != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set content signed data\n"));
    goto loser;
  }

  cinfo = NSS_CMSSignedData_GetContentInfo(sigd);

  /* we're always passing data in and detaching optionally */
  if (NSS_CMSContentInfo_SetContent_Data(m_cmsMsg, cinfo, nsnull, PR_TRUE) 
          != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set content data\n"));
    goto loser;
  }

  /* 
   * create & attach signer information
   */
  if ((signerinfo = NSS_CMSSignerInfo_Create(m_cmsMsg, scert, SEC_OID_SHA1)) 
          == NULL) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't create signer info\n"));
    goto loser;
  }

  /* we want the cert chain included for this one */
  if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain, 
                                       certUsageEmailSigner) 
          != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't include signer cert chain\n"));
    goto loser;
  }

  if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) 
	      != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add signing time\n"));
    goto loser;
  }

  if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add smime caps\n"));
    goto loser;
  }

  if (ecert) {
    if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ecert, 
	                                    CERT_GetDefaultCertDB())
	  != SECSuccess) {
      PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add smime enc key prefs\n"));
      goto loser;
    }

    if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ecert, 
	                                    CERT_GetDefaultCertDB())
	  != SECSuccess) {
      PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add MS smime enc key prefs\n"));
      goto loser;
    }

    // If signing and encryption cert are identical, don't add it twice.
    PRBool addEncryptionCert =
      (ecert && (!scert || !CERT_CompareCerts(ecert, scert)));

    if (addEncryptionCert &&
        NSS_CMSSignedData_AddCertificate(sigd, ecert) != SECSuccess) {
      PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add own encryption certificate\n"));
      goto loser;
    }
  }

  if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) {
    PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't add signer info\n"));
    goto loser;
  }

  // Finally, add the pre-computed digest if passed in
  if (aDigestData) {
    SECItem digest;

    digest.data = aDigestData;
    digest.len = aDigestDataLen;

    if (NSS_CMSSignedData_SetDigestValue(sigd, SEC_OID_SHA1, &digest)) {
      PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CreateSigned - can't set digest value\n"));
      goto loser;
    }
  }

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