diff --git a/mailnews/mime/src/mimecms.cpp b/mailnews/mime/src/mimecms.cpp index 4e2d2a768b1..8e0096df5cf 100644 --- a/mailnews/mime/src/mimecms.cpp +++ b/mailnews/mime/src/mimecms.cpp @@ -225,6 +225,8 @@ MimeCMSHeadersAndCertsMatch(MimeObject *obj, */ if (content_info) { + // Extract any address contained in the cert. + // This will be used for testing, whether the cert contains no addresses at all. content_info->GetSignerEmailAddress (getter_Copies(cert_addr)); } @@ -283,53 +285,54 @@ MimeCMSHeadersAndCertsMatch(MimeObject *obj, /* Now compare them -- consider it a match if the address in the cert matches either the - address in the From or Sender field; and if the name in the cert - matches either the name in the From or Sender field. - - Consider it a match if the cert does not contain a name (address.) - But do not consider it a match if the cert contains a name (address) - but the message headers do not. + address in the From or Sender field */ - /* ====================================================================== - First check the addresses. - */ + PRBool foundFrom = PR_FALSE; + PRBool foundSender = PR_FALSE; - /* If there is no addr in the cert, it can not match and we fail. */ + /* If there is no addr in the cert at all, it can not match and we fail. */ if (!cert_addr) - match = PR_FALSE; - - /* If there is both a from and sender address, and if neither of - them match, then error. */ - else if (from_addr && *from_addr && - sender_addr && *sender_addr) - { - if (nsCRT::strcasecmp(cert_addr, from_addr) && - nsCRT::strcasecmp(cert_addr, sender_addr)) - match = PR_FALSE; - } - /* If there is a from but no sender, and it doesn't match, then error. */ - else if (from_addr && *from_addr) - { - if (nsCRT::strcasecmp(cert_addr, from_addr)) - match = PR_FALSE; - } - /* If there is a sender but no from, and it doesn't match, then error. */ - else if (sender_addr && *sender_addr) - { - if (nsCRT::strcasecmp(cert_addr, sender_addr)) - match = PR_FALSE; - } - /* Else there are no addresses at all -- error. */ + { + match = PR_FALSE; + } else - { - match = PR_FALSE; - } + { + nsCOMPtr signerCert; + content_info->GetSignerCert(getter_AddRefs(signerCert)); + if (signerCert) + { + if (from_addr && *from_addr) + { + NS_ConvertASCIItoUCS2 ucs2From(from_addr); + if (NS_FAILED(signerCert->ContainsEmailAddress(ucs2From, &foundFrom))) + { + foundFrom = PR_FALSE; + } + } + + if (sender_addr && *sender_addr) + { + NS_ConvertASCIItoUCS2 ucs2Sender(sender_addr); + if (NS_FAILED(signerCert->ContainsEmailAddress(ucs2Sender, &foundSender))) + { + foundSender = PR_FALSE; + } + } + } + + if (!foundSender && !foundFrom) + { + match = PR_FALSE; + } + } if (sender_email_addr_return) { - if (match && cert_addr) - *sender_email_addr_return = nsCRT::strdup(cert_addr); + if (match && foundFrom) + *sender_email_addr_return = nsCRT::strdup(from_addr); + if (match && foundSender) + *sender_email_addr_return = nsCRT::strdup(sender_addr); else if (from_addr && *from_addr) *sender_email_addr_return = nsCRT::strdup(from_addr); else if (sender_addr && *sender_addr) diff --git a/security/manager/ssl/public/nsIX509Cert.idl b/security/manager/ssl/public/nsIX509Cert.idl index 10d932078b1..9b177968517 100644 --- a/security/manager/ssl/public/nsIX509Cert.idl +++ b/security/manager/ssl/public/nsIX509Cert.idl @@ -55,6 +55,27 @@ interface nsIX509Cert : nsISupports { */ readonly attribute AString emailAddress; + /** + * Obtain a list of all email addresses + * contained in the certificate. + * + * @param length The number of strings in the returned array. + * @return An array of email addresses. + */ + void getEmailAddresses(out unsigned long length, + [retval, array, size_is(length)] out wstring addresses); + + /** + * Check whether a given address is contained in the certificate. + * The comparison will convert the email address to lowercase. + * The behaviour for non ASCII characters is undefined. + * + * @param aEmailAddress The address to search for. + * + * @return True if the address is contained in the certificate. + */ + boolean containsEmailAddress(in AString aEmailAddress); + /** * The subject owning the certificate. */ diff --git a/security/manager/ssl/src/nsNSSCertificate.cpp b/security/manager/ssl/src/nsNSSCertificate.cpp index 904a1013c53..1d821342f1f 100644 --- a/security/manager/ssl/src/nsNSSCertificate.cpp +++ b/security/manager/ssl/src/nsNSSCertificate.cpp @@ -62,6 +62,8 @@ #include "nsUsageArrayHelper.h" #include "nsICertificateDialogs.h" #include "nsNSSCertHelper.h" +#include "nsISupportsPrimitives.h" +#include "nsUnicharUtils.h" #include "nspr.h" extern "C" { @@ -413,6 +415,7 @@ nsNSSCertificate::GetNickname(nsAString &_nickname) if (isAlreadyShutDown()) return NS_ERROR_NOT_AVAILABLE; +// XXX kaie: this is bad. We return a non localizable hardcoded string. const char *nickname = (mCert->nickname) ? mCert->nickname : "(no nickname)"; _nickname = NS_ConvertUTF8toUCS2(nickname); return NS_OK; @@ -425,11 +428,86 @@ nsNSSCertificate::GetEmailAddress(nsAString &_emailAddress) if (isAlreadyShutDown()) return NS_ERROR_NOT_AVAILABLE; +// XXX kaie: this is bad. We return a non localizable hardcoded string. +// And agents could be confused, assuming the email address == "(no nickname)" const char *email = (mCert->emailAddr) ? mCert->emailAddr : "(no email address)"; _emailAddress = NS_ConvertUTF8toUCS2(email); return NS_OK; } +NS_IMETHODIMP +nsNSSCertificate::GetEmailAddresses(PRUint32 *aLength, PRUnichar*** aAddresses) +{ + nsNSSShutDownPreventionLock locker; + if (isAlreadyShutDown()) + return NS_ERROR_NOT_AVAILABLE; + + NS_ENSURE_ARG(aLength); + NS_ENSURE_ARG(aAddresses); + + *aLength = 0; + + const char *aAddr; + for (aAddr = CERT_GetFirstEmailAddress(mCert) + ; + aAddr + ; + aAddr = CERT_GetNextEmailAddress(mCert, aAddr)) + { + ++(*aLength); + } + + *aAddresses = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * (*aLength)); + if (!aAddresses) + return NS_ERROR_OUT_OF_MEMORY; + + PRUint32 iAddr; + for (aAddr = CERT_GetFirstEmailAddress(mCert), iAddr = 0 + ; + aAddr + ; + aAddr = CERT_GetNextEmailAddress(mCert, aAddr), ++iAddr) + { + (*aAddresses)[iAddr] = ToNewUnicode(NS_ConvertUTF8toUCS2(aAddr)); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsNSSCertificate::ContainsEmailAddress(const nsAString &aEmailAddress, PRBool *result) +{ + nsNSSShutDownPreventionLock locker; + if (isAlreadyShutDown()) + return NS_ERROR_NOT_AVAILABLE; + + NS_ENSURE_ARG(result); + *result = PR_FALSE; + + const char *aAddr = nsnull; + for (aAddr = CERT_GetFirstEmailAddress(mCert) + ; + aAddr + ; + aAddr = CERT_GetNextEmailAddress(mCert, aAddr)) + { + NS_ConvertUTF8toUCS2 certAddr(aAddr); + ToLowerCase(certAddr); + + nsAutoString testAddr(aEmailAddress); + ToLowerCase(testAddr); + + if (certAddr == testAddr) + { + *result = PR_TRUE; + break; + } + + } + + return NS_OK; +} + NS_IMETHODIMP nsNSSCertificate::GetCommonName(nsAString &aCommonName) {