b=119418 Fix handling of opaque signed S/Mime messages.

Also fixes some other S/Mime issues, as described in the bug.
r=ddrinan/ducarroz/darin sr=alecf


git-svn-id: svn://10.0.0.236/trunk@118829 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
kaie%netscape.com 2002-04-12 04:26:40 +00:00
parent 72e0339f45
commit 77d80e392f
7 changed files with 195 additions and 81 deletions

View File

@ -155,7 +155,7 @@ function onLoad()
str = bundle.getString(sigInfo);
}
else if (sigInfo_clueless) {
str = bundle.getString("SIClueless") + " " + gSignatureStatus;
str = bundle.getString("SIClueless") + " (" + gSignatureStatus + ")";
}
setText("signatureExplanation", str);

View File

@ -213,7 +213,6 @@ MimeCMSHeadersAndCertsMatch(MimeObject *obj,
nsXPIDLCString from_name;
nsXPIDLCString sender_addr;
nsXPIDLCString sender_name;
nsXPIDLCString cert_name;
nsXPIDLCString cert_addr;
PRBool match = PR_TRUE;
@ -221,11 +220,11 @@ MimeCMSHeadersAndCertsMatch(MimeObject *obj,
*/
if (content_info)
{
content_info->GetSignerCommonName (getter_Copies(cert_name));
content_info->GetSignerEmailAddress (getter_Copies(cert_addr));
}
if (!cert_name && !cert_addr) goto DONE;
if (!cert_addr)
goto DONE;
/* Find the headers of the MimeMessage which is the parent (or grandparent)
of this object (remember, crypto objects nest.) */
@ -450,42 +449,104 @@ MimeCMS_eof (void *crypto_closure, PRBool abort_p)
PR_SetError(0, 0);
rv = data->decoder_context->Finish(getter_AddRefs(data->content_info));
nsCOMPtr<nsIX509Cert> recipientCert;
/* Is the content info encrypted? */
if (data->content_info) {
data->ci_is_encrypted = PR_TRUE;
data->content_info->GetEncryptionCert(getter_AddRefs(recipientCert));
}
if (NS_FAILED(rv))
data->verify_error = PR_GetError();
PRInt32 maxNestLevel = 0;
if (data->smimeHeaderSink) {
data->smimeHeaderSink->MaxWantedNesting(&maxNestLevel);
data->decoder_context = 0;
if (aNestLevel >= maxNestLevel)
{
PRInt32 status = nsICMSMessageErrors::GENERAL_ERROR;
if (data->ci_is_encrypted
&& !data->verify_error
&& !data->decode_error
&& NS_SUCCEEDED(rv))
{
status = nsICMSMessageErrors::SUCCESS;
nsCOMPtr<nsIX509Cert> certOfInterest;
if (!data->smimeHeaderSink)
return 0;
PRInt32 maxNestLevel = 0;
data->smimeHeaderSink->MaxWantedNesting(&maxNestLevel);
if (aNestLevel > maxNestLevel)
return 0;
PRInt32 status = nsICMSMessageErrors::SUCCESS;
if (data->verify_error
|| data->decode_error
|| NS_FAILED(rv))
{
status = nsICMSMessageErrors::GENERAL_ERROR;
}
if (!data->content_info)
{
status = nsICMSMessageErrors::GENERAL_ERROR;
// Although a CMS message could be either encrypted or opaquely signed,
// what we see is most likely encrypted, because if it were
// signed only, we probably would have been able to decode it.
data->ci_is_encrypted = PR_TRUE;
}
else
{
rv = data->content_info->ContentIsEncrypted(&data->ci_is_encrypted);
if (NS_SUCCEEDED(rv) && data->ci_is_encrypted) {
data->content_info->GetEncryptionCert(getter_AddRefs(certOfInterest));
}
else {
// Existing logic in mimei assumes, if !ci_is_encrypted, then it is signed.
// Make sure it indeed is signed.
PRBool testIsSigned;
rv = data->content_info->ContentIsSigned(&testIsSigned);
if (NS_FAILED(rv) || !testIsSigned) {
// Neither signed nor encrypted?
// We are unable to understand what we got, do not try to indicate S/Mime status.
return 0;
}
data->smimeHeaderSink->EncryptionStatus(
aNestLevel,
status,
recipientCert
);
rv = data->content_info->VerifySignature();
if (NS_FAILED(rv)) {
if (NS_ERROR_MODULE_SECURITY == NS_ERROR_GET_MODULE(rv)) {
status = NS_ERROR_GET_CODE(rv);
}
else if (NS_ERROR_NOT_IMPLEMENTED == rv) {
status = nsICMSMessageErrors::VERIFY_ERROR_PROCESSING;
}
}
else {
if (MimeCMSHeadersAndCertsMatch(data->self,
data->content_info,
&data->sender_addr))
{
status = nsICMSMessageErrors::SUCCESS;
}
else
{
status = nsICMSMessageErrors::VERIFY_HEADER_MISMATCH;
}
}
data->content_info->GetSignerCert(getter_AddRefs(certOfInterest));
}
}
data->decoder_context = 0;
if (data->ci_is_encrypted)
{
data->smimeHeaderSink->EncryptionStatus(
aNestLevel,
status,
certOfInterest
);
}
else
{
data->smimeHeaderSink->SignedStatus(
aNestLevel,
status,
certOfInterest
);
}
return 0;
}

View File

@ -452,7 +452,8 @@ mime_find_class (const char *content_type, MimeHeaders *hdrs,
}
#ifdef ENABLE_SMIME
else if (!nsCRT::strcasecmp(content_type, APPLICATION_XPKCS7_MIME))
else if (!nsCRT::strcasecmp(content_type, APPLICATION_XPKCS7_MIME)
|| !nsCRT::strcasecmp(content_type, APPLICATION_PKCS7_MIME))
clazz = (MimeObjectClass *)&mimeEncryptedCMSClass;
#endif
/* A few types which occur in the real world and which we would otherwise

View File

@ -509,7 +509,7 @@ MimeMultCMS_generate (void *crypto_closure)
if (data->smimeHeaderSink) {
data->smimeHeaderSink->MaxWantedNesting(&maxNestLevel);
if (aNestLevel >= maxNestLevel)
if (aNestLevel <= maxNestLevel)
{
data->smimeHeaderSink->SignedStatus(aNestLevel, signature_status, signerCert);
}

View File

@ -83,6 +83,7 @@
#define APPLICATION_X509_USER_CERT "application/x-x509-user-cert"
#define APPLICATION_X509_CRL "application/x-pkcs7-crl"
#define APPLICATION_XPKCS7_MIME "application/x-pkcs7-mime"
#define APPLICATION_PKCS7_MIME "application/pkcs7-mime"
#define APPLICATION_XPKCS7_SIGNATURE "application/x-pkcs7-signature"
#define APPLICATION_WWW_FORM_URLENCODED "application/x-www-form-urlencoded"
#define APPLICATION_OLEOBJECT "application/oleobject"

View File

@ -117,62 +117,99 @@ nsCMSMessage::~nsCMSMessage()
NS_IMETHODIMP nsCMSMessage::VerifySignature()
{
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifySignature\n"));
return NS_ERROR_NOT_IMPLEMENTED;
return CommonVerifySignature(nsnull, 0);
}
NSSCMSSignerInfo* nsCMSMessage::GetTopLevelSignerInfo()
{
if (!m_cmsMsg)
return nsnull;
if (!NSS_CMSMessage_IsSigned(m_cmsMsg))
return nsnull;
NSSCMSContentInfo *cinfo = NSS_CMSMessage_ContentLevel(m_cmsMsg, 0);
if (!cinfo)
return nsnull;
NSSCMSSignedData *sigd = (NSSCMSSignedData*)NSS_CMSContentInfo_GetContent(cinfo);
if (!sigd)
return nsnull;
PR_ASSERT(NSS_CMSSignedData_SignerInfoCount(sigd) > 0);
return NSS_CMSSignedData_GetSignerInfo(sigd, 0);
}
NS_IMETHODIMP nsCMSMessage::GetSignerEmailAddress(char * * aEmail)
{
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerEmailAddress\n"));
return NS_ERROR_NOT_IMPLEMENTED;
NS_ENSURE_ARG(aEmail);
NSSCMSSignerInfo *si = GetTopLevelSignerInfo();
if (!si)
return NS_ERROR_FAILURE;
*aEmail = NSS_CMSSignerInfo_GetSignerEmailAddress(si);
return NS_OK;
}
NS_IMETHODIMP nsCMSMessage::GetSignerCommonName(char ** aName)
{
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerCommonName\n"));
return NS_ERROR_NOT_IMPLEMENTED;
NS_ENSURE_ARG(aName);
NSSCMSSignerInfo *si = GetTopLevelSignerInfo();
if (!si)
return NS_ERROR_FAILURE;
*aName = NSS_CMSSignerInfo_GetSignerCommonName(si);
return NS_OK;
}
NS_IMETHODIMP nsCMSMessage::ContentIsEncrypted(int *)
NS_IMETHODIMP nsCMSMessage::ContentIsEncrypted(PRBool *isEncrypted)
{
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::ContentIsEncrypted\n"));
return NS_ERROR_NOT_IMPLEMENTED;
NS_ENSURE_ARG(isEncrypted);
if (!m_cmsMsg)
return NS_ERROR_FAILURE;
*isEncrypted = NSS_CMSMessage_IsEncrypted(m_cmsMsg);
return NS_OK;
}
NS_IMETHODIMP nsCMSMessage::ContentIsSigned(int *)
NS_IMETHODIMP nsCMSMessage::ContentIsSigned(PRBool *isSigned)
{
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::ContentIsSigned\n"));
return NS_ERROR_NOT_IMPLEMENTED;
NS_ENSURE_ARG(isSigned);
if (!m_cmsMsg)
return NS_ERROR_FAILURE;
*isSigned = NSS_CMSMessage_IsSigned(m_cmsMsg);
return NS_OK;
}
NS_IMETHODIMP nsCMSMessage::GetSignerCert(nsIX509Cert **scert)
{
if (!m_cmsMsg)
return NS_ERROR_FAILURE;
if (!NSS_CMSMessage_IsSigned(m_cmsMsg))
return NS_ERROR_FAILURE;
NSSCMSContentInfo *cinfo = NSS_CMSMessage_ContentLevel(m_cmsMsg, 0);
if (!cinfo)
return NS_ERROR_FAILURE;
NSSCMSSignedData *sigd = (NSSCMSSignedData*)NSS_CMSContentInfo_GetContent(cinfo);
if (!sigd)
return NS_ERROR_FAILURE;
PR_ASSERT(NSS_CMSSignedData_SignerInfoCount(sigd) > 0);
NSSCMSSignerInfo *si = NSS_CMSSignedData_GetSignerInfo(sigd, 0);
NSSCMSSignerInfo *si = GetTopLevelSignerInfo();
if (!si)
return NS_ERROR_FAILURE;
if (si->cert) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerCert got signer cert\n"));
*scert = new nsNSSCertificate(si->cert);
if (*scert) {
(*scert)->AddRef();
}
}
else {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::GetSignerCert no signer cert, do we have a cert list? %s\n",
(si->certList != nsnull ? "yes" : "no") ));
*scert = nsnull;
}
@ -186,42 +223,54 @@ NS_IMETHODIMP nsCMSMessage::GetEncryptionCert(nsIX509Cert **ecert)
NS_IMETHODIMP nsCMSMessage::VerifyDetachedSignature(unsigned char* aDigestData, PRUint32 aDigestDataLen)
{
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature\n"));
if (!aDigestData || !aDigestDataLen)
return NS_ERROR_FAILURE;
return CommonVerifySignature(aDigestData, aDigestDataLen);
}
nsresult nsCMSMessage::CommonVerifySignature(unsigned char* aDigestData, PRUint32 aDigestDataLen)
{
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature, content level count %d\n", NSS_CMSMessage_ContentLevelCount(m_cmsMsg)));
NSSCMSContentInfo *cinfo = nsnull;
NSSCMSSignedData *sigd = nsnull;
NSSCMSSignerInfo *si;
SECItem digest;
PRInt32 nsigners;
nsresult rv = NS_ERROR_FAILURE;
digest.data = aDigestData;
digest.len = aDigestDataLen;
if (NSS_CMSMessage_IsSigned(m_cmsMsg) == PR_FALSE) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - not signed\n"));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - not signed\n"));
return NS_ERROR_CMS_VERIFY_NOT_SIGNED;
}
cinfo = NSS_CMSMessage_ContentLevel(m_cmsMsg, 0);
if (cinfo) {
// I don't like this hard cast. We should check in some way, that we really have this type.
sigd = (NSSCMSSignedData*)NSS_CMSContentInfo_GetContent(cinfo);
}
if (!sigd) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - no content info\n"));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - no content info\n"));
rv = NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO;
goto loser;
}
if (NSS_CMSSignedData_SetDigestValue(sigd, SEC_OID_SHA1, &digest)) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - bad digest\n"));
rv = NS_ERROR_CMS_VERIFY_BAD_DIGEST;
goto loser;
if (aDigestData && aDigestDataLen)
{
SECItem digest;
digest.data = aDigestData;
digest.len = aDigestDataLen;
if (NSS_CMSSignedData_SetDigestValue(sigd, SEC_OID_SHA1, &digest)) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - bad digest\n"));
rv = NS_ERROR_CMS_VERIFY_BAD_DIGEST;
goto loser;
}
}
// Import certs. Note that import failure is not a signature verification failure. //
if (NSS_CMSSignedData_ImportCerts(sigd, CERT_GetDefaultCertDB(), certUsageEmailSigner, PR_TRUE) != SECSuccess) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - can not import certs\n"));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - can not import certs\n"));
}
nsigners = NSS_CMSSignedData_SignerInfoCount(sigd);
@ -230,42 +279,42 @@ NS_IMETHODIMP nsCMSMessage::VerifyDetachedSignature(unsigned char* aDigestData,
// We verify the first signer info, only //
if (NSS_CMSSignedData_VerifySignerInfo(sigd, 0, CERT_GetDefaultCertDB(), certUsageEmailSigner) != SECSuccess) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - unable to verify signature\n"));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - unable to verify signature\n"));
if (NSSCMSVS_SigningCertNotFound == si->verificationStatus) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - signing cert not found\n"));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not found\n"));
rv = NS_ERROR_CMS_VERIFY_NOCERT;
}
else if(NSSCMSVS_SigningCertNotTrusted == si->verificationStatus) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - signing cert not trusted\n"));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - signing cert not trusted\n"));
rv = NS_ERROR_CMS_VERIFY_UNTRUSTED;
}
else if(NSSCMSVS_Unverified == si->verificationStatus) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - can not verify\n"));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - can not verify\n"));
rv = NS_ERROR_CMS_VERIFY_ERROR_UNVERIFIED;
}
else if(NSSCMSVS_ProcessingError == si->verificationStatus) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - processing error\n"));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - processing error\n"));
rv = NS_ERROR_CMS_VERIFY_ERROR_PROCESSING;
}
else if(NSSCMSVS_BadSignature == si->verificationStatus) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - bad signature\n"));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - bad signature\n"));
rv = NS_ERROR_CMS_VERIFY_BAD_SIGNATURE;
}
else if(NSSCMSVS_DigestMismatch == si->verificationStatus) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - digest mismatch\n"));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - digest mismatch\n"));
rv = NS_ERROR_CMS_VERIFY_DIGEST_MISMATCH;
}
else if(NSSCMSVS_SignatureAlgorithmUnknown == si->verificationStatus) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - algo unknown\n"));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - algo unknown\n"));
rv = NS_ERROR_CMS_VERIFY_UNKNOWN_ALGO;
}
else if(NSSCMSVS_SignatureAlgorithmUnsupported == si->verificationStatus) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - algo not supported\n"));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - algo not supported\n"));
rv = NS_ERROR_CMS_VERIFY_UNSUPPORTED_ALGO;
}
else if(NSSCMSVS_MalformedSignature == si->verificationStatus) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - malformed signature\n"));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - malformed signature\n"));
rv = NS_ERROR_CMS_VERIFY_MALFORMED_SIGNATURE;
}
@ -274,7 +323,7 @@ NS_IMETHODIMP nsCMSMessage::VerifyDetachedSignature(unsigned char* aDigestData,
// Save the profile. Note that save import failure is not a signature verification failure. //
if (NSS_SMIMESignerInfo_SaveSMIMEProfile(si) != SECSuccess) {
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::VerifyDetachedSignature - unable to save smime profile\n"));
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("nsCMSMessage::CommonVerifySignature - unable to save smime profile\n"));
}
rv = NS_OK;

View File

@ -79,6 +79,8 @@ public:
NSSCMSMessage* getCMS() {return m_cmsMsg;};
private:
NSSCMSMessage * m_cmsMsg;
NSSCMSSignerInfo* GetTopLevelSignerInfo();
nsresult CommonVerifySignature(unsigned char* aDigestData, PRUint32 aDigestDataLen);
};