mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-12 09:01:16 +00:00
bug 1461037 - lossily convert invalid UTF8 in certificates for display purposes r=jcj
In debug builds, we assert if any UTF8-to-UTF16 conversion fails. If we have invalid UTF8 in a certificate, we don't want to assert. So, we now lossily convert invalid UTF8 in certificates for any display purposes. This also handles fields that are supposed to be ASCII in a similar way. MozReview-Commit-ID: 6TdVPDTmNlh --HG-- extra : rebase_source : 17000bd0671551bbdae534a4eaf4946c1b0beb83
This commit is contained in:
parent
723ab85b29
commit
ca855468dd
@ -19,6 +19,7 @@
|
||||
#include "nsNSSCertTrust.h"
|
||||
#include "nsNSSCertValidity.h"
|
||||
#include "nsNSSCertificate.h"
|
||||
#include "nsReadableUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "prerror.h"
|
||||
#include "secder.h"
|
||||
@ -754,25 +755,30 @@ ProcessExtKeyUsage(SECItem* extData, nsAString& text)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
LossyUTF8ToUTF16(const char* str, uint32_t len, /*out*/ nsAString& result)
|
||||
{
|
||||
nsDependentCSubstring substring(str, len);
|
||||
if (IsUTF8(substring)) {
|
||||
result.Assign(NS_ConvertUTF8toUTF16(substring));
|
||||
} else {
|
||||
char16_t* newUTF16(ToNewUnicode(substring));
|
||||
result.Adopt(newUTF16);
|
||||
}
|
||||
}
|
||||
|
||||
static nsresult
|
||||
ProcessRDN(CERTRDN* rdn, nsAString& finalString)
|
||||
{
|
||||
nsresult rv;
|
||||
CERTAVA** avas;
|
||||
CERTAVA* ava;
|
||||
nsString avavalue;
|
||||
nsString type;
|
||||
nsAutoString temp;
|
||||
const char16_t* params[2];
|
||||
|
||||
avas = rdn->avas;
|
||||
while ((ava = *avas++) != 0) {
|
||||
rv = GetOIDText(&ava->type, type);
|
||||
CERTAVA** avas = rdn->avas;
|
||||
for (auto i = 0; avas[i]; i++) {
|
||||
CERTAVA* ava = avas[i];
|
||||
nsAutoString type;
|
||||
nsresult rv = GetOIDText(&ava->type, type);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// This function returns a string in UTF8 format.
|
||||
UniqueSECItem decodeItem(CERT_DecodeAVAValue(&ava->value));
|
||||
if (!decodeItem) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -791,10 +797,13 @@ ProcessRDN(CERTRDN* rdn, nsAString& finalString)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
avavalue = NS_ConvertUTF8toUTF16(escapedValue.get());
|
||||
nsAutoString avaValue;
|
||||
LossyUTF8ToUTF16(escapedValue.get(), strlen(escapedValue.get()), avaValue);
|
||||
|
||||
const char16_t* params[2];
|
||||
params[0] = type.get();
|
||||
params[1] = avavalue.get();
|
||||
params[1] = avaValue.get();
|
||||
nsAutoString temp;
|
||||
PIPBundleFormatStringFromName("AVATemplate", params, 2, temp);
|
||||
finalString += temp + NS_LITERAL_STRING("\n");
|
||||
}
|
||||
@ -852,8 +861,13 @@ ProcessIA5String(const SECItem& extData,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
text.AppendASCII(BitwiseCast<char*, unsigned char*>(item.data),
|
||||
AssertedCast<uint32_t>(item.len));
|
||||
// Yes this is supposed to be ASCII and not UTF8, but this is just for display
|
||||
// purposes.
|
||||
nsAutoString utf16;
|
||||
const char* str = BitwiseCast<char*, unsigned char*>(item.data);
|
||||
uint32_t len = AssertedCast<uint32_t>(item.len);
|
||||
LossyUTF8ToUTF16(str, len, utf16);
|
||||
text.Append(utf16);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -898,16 +912,20 @@ ProcessGeneralName(const UniquePLArenaPool& arena, CERTGeneralName* current,
|
||||
}
|
||||
ProcessRawBytes(¤t->name.OthName.name, value);
|
||||
break;
|
||||
case certRFC822Name:
|
||||
case certRFC822Name: {
|
||||
GetPIPNSSBundleString("CertDumpRFC822Name", key);
|
||||
value.AssignASCII((char*)current->name.other.data,
|
||||
current->name.other.len);
|
||||
const char* str = reinterpret_cast<const char*>(current->name.other.data);
|
||||
uint32_t len = current->name.other.len;
|
||||
LossyUTF8ToUTF16(str, len, value);
|
||||
break;
|
||||
case certDNSName:
|
||||
}
|
||||
case certDNSName: {
|
||||
GetPIPNSSBundleString("CertDumpDNSName", key);
|
||||
value.AssignASCII((char*)current->name.other.data,
|
||||
current->name.other.len);
|
||||
const char* str = reinterpret_cast<const char*>(current->name.other.data);
|
||||
uint32_t len = current->name.other.len;
|
||||
LossyUTF8ToUTF16(str, len, value);
|
||||
break;
|
||||
}
|
||||
case certX400Address:
|
||||
GetPIPNSSBundleString("CertDumpX400Address", key);
|
||||
ProcessRawBytes(¤t->name.other, value);
|
||||
@ -924,11 +942,13 @@ ProcessGeneralName(const UniquePLArenaPool& arena, CERTGeneralName* current,
|
||||
GetPIPNSSBundleString("CertDumpEDIPartyName", key);
|
||||
ProcessRawBytes(¤t->name.other, value);
|
||||
break;
|
||||
case certURI:
|
||||
case certURI: {
|
||||
GetPIPNSSBundleString("CertDumpURI", key);
|
||||
value.AssignASCII((char*)current->name.other.data,
|
||||
current->name.other.len);
|
||||
const char* str = reinterpret_cast<const char*>(current->name.other.data);
|
||||
uint32_t len = current->name.other.len;
|
||||
LossyUTF8ToUTF16(str, len, value);
|
||||
break;
|
||||
}
|
||||
case certIPAddress: {
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
PRStatus status = PR_FAILURE;
|
||||
@ -1091,11 +1111,15 @@ ProcessUserNotice(SECItem* derNotice, nsAString& text)
|
||||
switch (notice->noticeReference.organization.type) {
|
||||
case siAsciiString:
|
||||
case siVisibleString:
|
||||
case siUTF8String:
|
||||
text.Append(NS_ConvertUTF8toUTF16(
|
||||
(const char*)notice->noticeReference.organization.data,
|
||||
notice->noticeReference.organization.len));
|
||||
case siUTF8String: {
|
||||
const char* str = reinterpret_cast<const char*>(
|
||||
notice->noticeReference.organization.data);
|
||||
uint32_t len = notice->noticeReference.organization.len;
|
||||
nsAutoString utf16;
|
||||
LossyUTF8ToUTF16(str, len, utf16);
|
||||
text.Append(utf16);
|
||||
break;
|
||||
}
|
||||
case siBMPString:
|
||||
AppendBMPtoUTF16(arena,
|
||||
notice->noticeReference.organization.data,
|
||||
@ -1125,10 +1149,15 @@ ProcessUserNotice(SECItem* derNotice, nsAString& text)
|
||||
switch (notice->displayText.type) {
|
||||
case siAsciiString:
|
||||
case siVisibleString:
|
||||
case siUTF8String:
|
||||
text.Append(NS_ConvertUTF8toUTF16((const char*)notice->displayText.data,
|
||||
notice->displayText.len));
|
||||
case siUTF8String: {
|
||||
const char* str =
|
||||
reinterpret_cast<const char*>(notice->displayText.data);
|
||||
uint32_t len = notice->displayText.len;
|
||||
nsAutoString utf16;
|
||||
LossyUTF8ToUTF16(str, len, utf16);
|
||||
text.Append(utf16);
|
||||
break;
|
||||
}
|
||||
case siBMPString:
|
||||
AppendBMPtoUTF16(
|
||||
arena, notice->displayText.data, notice->displayText.len, text);
|
||||
|
@ -19,6 +19,9 @@ nsresult
|
||||
GetCertFingerprintByOidTag(CERTCertificate* nsscert, SECOidTag aOidTag,
|
||||
nsCString& fp);
|
||||
|
||||
void
|
||||
LossyUTF8ToUTF16(const char* str, uint32_t len, /*out*/ nsAString& result);
|
||||
|
||||
// Must be used on the main thread only.
|
||||
nsresult
|
||||
GetPIPNSSBundleString(const char* stringName, nsAString& result);
|
||||
|
@ -362,12 +362,13 @@ nsNSSCertificate::GetDisplayName(nsAString& aDisplayName)
|
||||
mCert->emailAddr
|
||||
};
|
||||
|
||||
nsAutoCString nameOption;
|
||||
for (auto nameOptionPtr : nameOptions) {
|
||||
nameOption.Assign(nameOptionPtr);
|
||||
if (nameOption.Length() > 0 && IsUTF8(nameOption)) {
|
||||
CopyUTF8toUTF16(nameOption, aDisplayName);
|
||||
return NS_OK;
|
||||
for (auto nameOption : nameOptions) {
|
||||
if (nameOption) {
|
||||
size_t len = strlen(nameOption);
|
||||
if (len > 0) {
|
||||
LossyUTF8ToUTF16(nameOption, len, aDisplayName);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -378,7 +379,7 @@ NS_IMETHODIMP
|
||||
nsNSSCertificate::GetEmailAddress(nsAString& aEmailAddress)
|
||||
{
|
||||
if (mCert->emailAddr) {
|
||||
CopyUTF8toUTF16(mCert->emailAddr, aEmailAddress);
|
||||
LossyUTF8ToUTF16(mCert->emailAddr, strlen(mCert->emailAddr), aEmailAddress);
|
||||
} else {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
|
||||
@ -398,28 +399,23 @@ nsNSSCertificate::GetEmailAddresses(uint32_t* aLength, char16_t*** aAddresses)
|
||||
|
||||
*aLength = 0;
|
||||
|
||||
const char* aAddr;
|
||||
for (aAddr = CERT_GetFirstEmailAddress(mCert.get())
|
||||
;
|
||||
aAddr
|
||||
;
|
||||
aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr))
|
||||
{
|
||||
for (const char* aAddr = CERT_GetFirstEmailAddress(mCert.get());
|
||||
aAddr;
|
||||
aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr)) {
|
||||
++(*aLength);
|
||||
}
|
||||
|
||||
*aAddresses = (char16_t**) moz_xmalloc(sizeof(char16_t*) * (*aLength));
|
||||
if (!*aAddresses)
|
||||
if (!*aAddresses) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
uint32_t iAddr;
|
||||
for (aAddr = CERT_GetFirstEmailAddress(mCert.get()), iAddr = 0
|
||||
;
|
||||
aAddr
|
||||
;
|
||||
aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr), ++iAddr)
|
||||
{
|
||||
(*aAddresses)[iAddr] = ToNewUnicode(NS_ConvertUTF8toUTF16(aAddr));
|
||||
uint32_t iAddr = 0;
|
||||
for (const char* aAddr = CERT_GetFirstEmailAddress(mCert.get());
|
||||
aAddr;
|
||||
aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr)) {
|
||||
(*aAddresses)[iAddr] = ToNewUnicode(nsDependentCString(aAddr));
|
||||
iAddr++;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -432,25 +428,20 @@ nsNSSCertificate::ContainsEmailAddress(const nsAString& aEmailAddress,
|
||||
NS_ENSURE_ARG(result);
|
||||
*result = false;
|
||||
|
||||
const char* aAddr = nullptr;
|
||||
for (aAddr = CERT_GetFirstEmailAddress(mCert.get())
|
||||
;
|
||||
aAddr
|
||||
;
|
||||
aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr))
|
||||
{
|
||||
NS_ConvertUTF8toUTF16 certAddr(aAddr);
|
||||
for (const char* aAddr = CERT_GetFirstEmailAddress(mCert.get());
|
||||
aAddr;
|
||||
aAddr = CERT_GetNextEmailAddress(mCert.get(), aAddr)) {
|
||||
nsAutoString certAddr;
|
||||
LossyUTF8ToUTF16(aAddr, strlen(aAddr), certAddr);
|
||||
ToLowerCase(certAddr);
|
||||
|
||||
nsAutoString testAddr(aEmailAddress);
|
||||
ToLowerCase(testAddr);
|
||||
|
||||
if (certAddr == testAddr)
|
||||
{
|
||||
if (certAddr == testAddr) {
|
||||
*result = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -463,7 +454,7 @@ nsNSSCertificate::GetCommonName(nsAString& aCommonName)
|
||||
if (mCert) {
|
||||
UniquePORTString commonName(CERT_GetCommonName(&mCert->subject));
|
||||
if (commonName) {
|
||||
aCommonName = NS_ConvertUTF8toUTF16(commonName.get());
|
||||
LossyUTF8ToUTF16(commonName.get(), strlen(commonName.get()), aCommonName);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
@ -476,7 +467,8 @@ nsNSSCertificate::GetOrganization(nsAString& aOrganization)
|
||||
if (mCert) {
|
||||
UniquePORTString organization(CERT_GetOrgName(&mCert->subject));
|
||||
if (organization) {
|
||||
aOrganization = NS_ConvertUTF8toUTF16(organization.get());
|
||||
LossyUTF8ToUTF16(organization.get(), strlen(organization.get()),
|
||||
aOrganization);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
@ -489,7 +481,7 @@ nsNSSCertificate::GetIssuerCommonName(nsAString& aCommonName)
|
||||
if (mCert) {
|
||||
UniquePORTString commonName(CERT_GetCommonName(&mCert->issuer));
|
||||
if (commonName) {
|
||||
aCommonName = NS_ConvertUTF8toUTF16(commonName.get());
|
||||
LossyUTF8ToUTF16(commonName.get(), strlen(commonName.get()), aCommonName);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
@ -502,7 +494,8 @@ nsNSSCertificate::GetIssuerOrganization(nsAString& aOrganization)
|
||||
if (mCert) {
|
||||
UniquePORTString organization(CERT_GetOrgName(&mCert->issuer));
|
||||
if (organization) {
|
||||
aOrganization = NS_ConvertUTF8toUTF16(organization.get());
|
||||
LossyUTF8ToUTF16(organization.get(), strlen(organization.get()),
|
||||
aOrganization);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
@ -515,7 +508,8 @@ nsNSSCertificate::GetIssuerOrganizationUnit(nsAString& aOrganizationUnit)
|
||||
if (mCert) {
|
||||
UniquePORTString organizationUnit(CERT_GetOrgUnitName(&mCert->issuer));
|
||||
if (organizationUnit) {
|
||||
aOrganizationUnit = NS_ConvertUTF8toUTF16(organizationUnit.get());
|
||||
LossyUTF8ToUTF16(organizationUnit.get(), strlen(organizationUnit.get()),
|
||||
aOrganizationUnit);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
@ -528,7 +522,8 @@ nsNSSCertificate::GetOrganizationalUnit(nsAString& aOrganizationalUnit)
|
||||
if (mCert) {
|
||||
UniquePORTString orgunit(CERT_GetOrgUnitName(&mCert->subject));
|
||||
if (orgunit) {
|
||||
aOrganizationalUnit = NS_ConvertUTF8toUTF16(orgunit.get());
|
||||
LossyUTF8ToUTF16(orgunit.get(), strlen(orgunit.get()),
|
||||
aOrganizationalUnit);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
@ -539,7 +534,8 @@ nsNSSCertificate::GetSubjectName(nsAString& _subjectName)
|
||||
{
|
||||
_subjectName.Truncate();
|
||||
if (mCert->subjectName) {
|
||||
_subjectName = NS_ConvertUTF8toUTF16(mCert->subjectName);
|
||||
LossyUTF8ToUTF16(mCert->subjectName, strlen(mCert->subjectName),
|
||||
_subjectName);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -639,7 +635,7 @@ nsNSSCertificate::GetIssuerName(nsAString& _issuerName)
|
||||
{
|
||||
_issuerName.Truncate();
|
||||
if (mCert->issuerName) {
|
||||
_issuerName = NS_ConvertUTF8toUTF16(mCert->issuerName);
|
||||
LossyUTF8ToUTF16(mCert->issuerName, strlen(mCert->issuerName), _issuerName);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ TEST_DIRS += [
|
||||
'test_cert_signatures',
|
||||
'test_cert_trust',
|
||||
'test_cert_version',
|
||||
'test_cert_utf8',
|
||||
'test_certDB_import',
|
||||
'test_content_signing',
|
||||
'test_ct',
|
||||
|
@ -570,6 +570,8 @@ class Certificate(object):
|
||||
directoryName = stringToDN(name,
|
||||
tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 4))
|
||||
generalName['directoryName'] = directoryName
|
||||
elif '@' in name:
|
||||
generalName['rfc822Name'] = name
|
||||
else:
|
||||
# The string may have things like '\0' (i.e. a slash
|
||||
# followed by the number zero) that have to be decoded into
|
||||
|
108
security/manager/ssl/tests/unit/test_cert_utf8.js
Normal file
108
security/manager/ssl/tests/unit/test_cert_utf8.js
Normal file
@ -0,0 +1,108 @@
|
||||
// -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
"use strict";
|
||||
|
||||
do_get_profile();
|
||||
|
||||
const gCertDB = Cc["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Ci.nsIX509CertDB);
|
||||
|
||||
function run_test() {
|
||||
const pem =
|
||||
"MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgN" +
|
||||
"VBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRpZmljYWNpw7NuIE" +
|
||||
"RpZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwaQUMgUmHDrXogQ2VydGljw" +
|
||||
"6FtYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAwNDAyMjE0MjAyWjB7MQswCQYDVQQG" +
|
||||
"EwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2FtZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWd" +
|
||||
"pdGFsIC0gQ2VydGljw6FtYXJhIFMuQS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbW" +
|
||||
"FyYSBTLkEuMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPU" +
|
||||
"ZYILrgIem08kBeGqentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9" +
|
||||
"JlsYhBzLfDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpO" +
|
||||
"QY5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4Ny+LvB" +
|
||||
"2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ54v5aHxwD6Mq0" +
|
||||
"Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+bMMCm8Ibbq0nXl21Ii/kD" +
|
||||
"wFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48jilSH5L887uvDdUhfHjlvgWJsxS3" +
|
||||
"EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++EjYfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkX" +
|
||||
"kwwakfU5tTohVTP92dsxA7SH2JD/ztA/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5" +
|
||||
"lw1omdMEWux+IBkAC1vImHFrEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxE" +
|
||||
"Cp1bczwmPS9KvqfJpxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1U" +
|
||||
"dDwEB/wQEAwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmD" +
|
||||
"CBlTCBkgYEVR0gADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFyYS5jb" +
|
||||
"20vZHBjLzBaBggrBgEFBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW507WFzIGRlIGVz" +
|
||||
"dGUgY2VydGlmaWNhZG8gc2UgcHVlZGVuIGVuY29udHJhciBlbiBsYSBEUEMuMA0GCSqGSIb" +
|
||||
"3DQEBBQUAA4ICAQBclLW4RZFNjmEfAygPU3zmpFmps4p6xbD/CHwso3EcIRNnoZUSQDWDg4" +
|
||||
"902zNc8El2CoFS3UnUmjIz75uny3XlesuXEpBcunvFm9+7OSPI/5jOCk0iAUgHforA1SBCl" +
|
||||
"ETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb" +
|
||||
"0hfpKv6DExdA7ohiZVvVO2Dpezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/Ey" +
|
||||
"XyVo3bHwi2ErN0o42gzmRkBDI8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNE" +
|
||||
"CW8DYSwaN0jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpO" +
|
||||
"e9+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJDW2Za" +
|
||||
"iogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/RL5hRqGEPQg" +
|
||||
"nTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35rMDOhYil/SrnhLecUIw" +
|
||||
"4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxkBYn8eNZcLCZDqQ==";
|
||||
let cert = gCertDB.constructX509FromBase64(pem);
|
||||
// This certificate contains a string that claims to be compatible with UTF-8
|
||||
// but isn't. Getting the asn1 structure of it exercises the code path that
|
||||
// decodes this value. If we don't assert in debug builds, presumably we
|
||||
// handled this value safely.
|
||||
notEqual(cert.ASN1Structure, null,
|
||||
"accessing nsIX509Cert.ASN1Structure shouldn't assert");
|
||||
|
||||
// This certificate has a number of placeholder byte sequences that we can
|
||||
// replace with invalid UTF-8 to ensure that we handle these cases safely.
|
||||
let certificateToAlterFile =
|
||||
do_get_file("test_cert_utf8/certificateToAlter.pem", false);
|
||||
let certificateBytesToAlter =
|
||||
atob(pemToBase64(readFile(certificateToAlterFile)));
|
||||
testUTF8InField("issuerName", "ISSUER CN", certificateBytesToAlter);
|
||||
testUTF8InField("issuerOrganization", "ISSUER O", certificateBytesToAlter);
|
||||
testUTF8InField("issuerOrganizationUnit", "ISSUER OU",
|
||||
certificateBytesToAlter);
|
||||
testUTF8InField("issuerCommonName", "ISSUER CN", certificateBytesToAlter);
|
||||
testUTF8InField("organization", "SUBJECT O", certificateBytesToAlter);
|
||||
testUTF8InField("organizationalUnit", "SUBJECT OU", certificateBytesToAlter);
|
||||
testUTF8InField("subjectName", "SUBJECT CN", certificateBytesToAlter);
|
||||
testUTF8InField("displayName", "SUBJECT CN", certificateBytesToAlter);
|
||||
testUTF8InField("commonName", "SUBJECT CN", certificateBytesToAlter);
|
||||
testUTF8InField("emailAddress", "SUBJECT EMAILADDRESS",
|
||||
certificateBytesToAlter);
|
||||
testUTF8InField("subjectAltNames", "SUBJECT ALT DNSNAME",
|
||||
certificateBytesToAlter);
|
||||
testUTF8InField("subjectAltNames", "SUBJECT ALT RFC822@NAME",
|
||||
certificateBytesToAlter);
|
||||
}
|
||||
|
||||
// Every (issuer, serial number) pair must be unique. If NSS ever encounters two
|
||||
// different (in terms of encoding) certificates with the same values for this
|
||||
// pair, it will refuse to import it (even as a temporary certificate). Since
|
||||
// we're creating a number of different certificates, we need to ensure this
|
||||
// pair is always unique. The easiest way to do this is to change the issuer
|
||||
// distinguished name each time. To make sure this doesn't introduce additional
|
||||
// UTF8 issues, always use a printable ASCII value.
|
||||
var gUniqueIssuerCounter = 32;
|
||||
|
||||
function testUTF8InField(field, replacementPrefix, certificateBytesToAlter) {
|
||||
let toReplace = `${replacementPrefix} REPLACE ME`;
|
||||
let replacement = "";
|
||||
for (let i = 0; i < toReplace.length; i++) {
|
||||
replacement += "\xEB";
|
||||
}
|
||||
let bytes = certificateBytesToAlter.replace(toReplace, replacement);
|
||||
let uniqueIssuerReplacement = "ALWAYS MAKE ME UNIQU" +
|
||||
String.fromCharCode(gUniqueIssuerCounter);
|
||||
bytes = bytes.replace("ALWAYS MAKE ME UNIQUE", uniqueIssuerReplacement);
|
||||
ok(gUniqueIssuerCounter < 127,
|
||||
"should have enough ASCII replacements to make a unique issuer DN");
|
||||
gUniqueIssuerCounter++;
|
||||
let cert = gCertDB.constructX509(bytes);
|
||||
notEqual(cert[field], null, `accessing nsIX509Cert.${field} shouldn't fail`);
|
||||
notEqual(cert.ASN1Structure, null,
|
||||
"accessing nsIX509Cert.ASN1Structure shouldn't assert");
|
||||
notEqual(cert.getEmailAddresses({}), null,
|
||||
"calling nsIX509Cert.getEmailAddresses() shouldn't assert");
|
||||
ok(!cert.containsEmailAddress("test@test.test"),
|
||||
"calling nsIX509Cert.containsEmailAddress() shouldn't assert");
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID7zCCAtegAwIBAgIUI3hIT6C3aep3bBYeGkq34MtwHEswDQYJKoZIhvcNAQEL
|
||||
BQAwfDEcMBoGA1UECgwTSVNTVUVSIE8gUkVQTEFDRSBNRTEdMBsGA1UECwwUSVNT
|
||||
VUVSIE9VIFJFUExBQ0UgTUUxHTAbBgNVBAMMFElTU1VFUiBDTiBSRVBMQUNFIE1F
|
||||
MR4wHAYDVQQHDBVBTFdBWVMgTUFLRSBNRSBVTklRVUUwIhgPMjAxNjExMjcwMDAw
|
||||
MDBaGA8yMDE5MDIwNTAwMDAwMFowgY8xHTAbBgNVBAoMFFNVQkpFQ1QgTyBSRVBM
|
||||
QUNFIE1FMR4wHAYDVQQLDBVTVUJKRUNUIE9VIFJFUExBQ0UgTUUxHjAcBgNVBAMM
|
||||
FVNVQkpFQ1QgQ04gUkVQTEFDRSBNRTEuMCwGCSqGSIb3DQEJARYfU1VCSkVDVCBF
|
||||
TUFJTEFERFJFU1MgUkVQTEFDRSBNRTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBALqIUahEjhbWQf1utogGNhA9PBPZ6uQ1SrTs9WhXbCR7wcclqODYH72x
|
||||
nAabbhqG8mvir1p1a2pkcQh6pVqnRYf3HNUknAJ+zUP8HmnQOCApk6sgw0nk27lM
|
||||
wmtsDu0Vgg/xfq1pGrHTAjqLKkHup3DgDw2N/WYLK7AkkqR9uYhheZCxV5A90jvF
|
||||
4LhIH6g304hD7ycW2FW3ZlqqfgKQLzp7EIAGJMwcbJetlmFbt+KWEsB1MaMMkd20
|
||||
yvf8rR0l0wnvuRcOp2jhs3svIm9p47SKlWEd7ibWJZ2rkQhONsscJAQsvxaLL+Xx
|
||||
j5kXMbiz/kkj+nJRxDHVA6zaGAo17Y0CAwEAAaNRME8wTQYDVR0RBEYwRIIeU1VC
|
||||
SkVDVCBBTFQgRE5TTkFNRSBSRVBMQUNFIE1FgSJTVUJKRUNUIEFMVCBSRkM4MjJA
|
||||
TkFNRSBSRVBMQUNFIE1FMA0GCSqGSIb3DQEBCwUAA4IBAQBdamlx/6oYDTbf06KN
|
||||
6tiBVCtf5GloczF8q+nfLMx90KICCeOLwNLD+Czm8vpImcMMDX2xEGM6aVZ+AGr+
|
||||
4Ez004u/WxfIWTIxF5hrlvH7UC3TukQetZzw6xjypbRzTlN74U0cqKmcBQAC7+6P
|
||||
sx+mWWajv0zSvMiz8XWf5Da7qFNYNqP6msdiaPRiS4ng6OADCeA3ntKTjpMH6cdB
|
||||
nDuCs9FsLwi5DR5/eYcpe8b/tZPHtkNZqZM7etb7tc8klYRcRAxdCKAR3d3W3Ay9
|
||||
OlDGqd6uv6oQLsm0eeZM5Udm9X+RjK2b51Fz00WED3RZ10IA6Hy41ucTfoMJLjEw
|
||||
dBD8
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,3 @@
|
||||
issuer:/O=ISSUER O REPLACE ME/OU=ISSUER OU REPLACE ME/CN=ISSUER CN REPLACE ME/L=ALWAYS MAKE ME UNIQUE
|
||||
subject:/O=SUBJECT O REPLACE ME/OU=SUBJECT OU REPLACE ME/CN=SUBJECT CN REPLACE ME/emailAddress=SUBJECT EMAILADDRESS REPLACE ME
|
||||
extension:subjectAlternativeName:SUBJECT ALT DNSNAME REPLACE ME,SUBJECT ALT RFC822@NAME REPLACE ME
|
13
security/manager/ssl/tests/unit/test_cert_utf8/moz.build
Normal file
13
security/manager/ssl/tests/unit/test_cert_utf8/moz.build
Normal file
@ -0,0 +1,13 @@
|
||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# Temporarily disabled. See bug 1256495.
|
||||
#test_certificates = (
|
||||
# 'certificateToAlter.pem',
|
||||
#)
|
||||
#
|
||||
#for test_certificate in test_certificates:
|
||||
# GeneratedTestCertificate(test_certificate)
|
@ -15,6 +15,7 @@ support-files =
|
||||
test_cert_signatures/**
|
||||
test_cert_trust/**
|
||||
test_cert_version/**
|
||||
test_cert_utf8/**
|
||||
test_certDB_import/**
|
||||
test_certviewer_invalid_oids/**
|
||||
test_content_signing/**
|
||||
@ -63,6 +64,7 @@ run-sequentially = hardcoded ports
|
||||
[test_cert_signatures.js]
|
||||
[test_cert_trust.js]
|
||||
[test_cert_version.js]
|
||||
[test_cert_utf8.js]
|
||||
[test_certDB_export_pkcs12.js]
|
||||
[test_certDB_export_pkcs12_with_master_password.js]
|
||||
[test_certDB_import.js]
|
||||
|
Loading…
Reference in New Issue
Block a user