зеркало из https://github.com/mozilla/pjs.git
Bug 644006: Don't crash on zero-length input to nsNSSCertificateDB::ConstructX509FromBase64. r=honzab
This commit is contained in:
Родитель
0389b18242
Коммит
cc402fa08a
|
@ -1485,65 +1485,54 @@ nsNSSCertificateDB::FindCertByEmailAddress(nsISupports *aToken, const char *aEma
|
|||
|
||||
/* nsIX509Cert constructX509FromBase64 (in string base64); */
|
||||
NS_IMETHODIMP
|
||||
nsNSSCertificateDB::ConstructX509FromBase64(const char * base64, nsIX509Cert **_retval)
|
||||
nsNSSCertificateDB::ConstructX509FromBase64(const char *base64,
|
||||
nsIX509Cert **_retval)
|
||||
{
|
||||
if (!_retval) {
|
||||
return NS_ERROR_FAILURE;
|
||||
NS_ENSURE_ARG_POINTER(_retval);
|
||||
|
||||
// sure would be nice to have a smart pointer class for PL_ allocations
|
||||
// unfortunately, we cannot distinguish out-of-memory from bad-input here
|
||||
PRUint32 len = PL_strlen(base64);
|
||||
char *certDER = PL_Base64Decode(base64, len, NULL);
|
||||
if (!certDER)
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
if (!*certDER) {
|
||||
PL_strfree(certDER);
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
// If we get to this point, we know we had well-formed base64 input;
|
||||
// therefore the input string cannot have been less than two
|
||||
// characters long. Compute the unpadded length of the decoded data.
|
||||
PRUint32 lengthDER = (len * 3) / 4;
|
||||
if (base64[len-1] == '=') {
|
||||
lengthDER--;
|
||||
if (base64[len-2] == '=')
|
||||
lengthDER--;
|
||||
}
|
||||
|
||||
nsNSSShutDownPreventionLock locker;
|
||||
PRUint32 len = PL_strlen(base64);
|
||||
int adjust = 0;
|
||||
SECItem secitem_cert;
|
||||
secitem_cert.type = siDERCertBuffer;
|
||||
secitem_cert.data = (unsigned char*)certDER;
|
||||
secitem_cert.len = lengthDER;
|
||||
|
||||
/* Compute length adjustment */
|
||||
if (base64[len-1] == '=') {
|
||||
adjust++;
|
||||
if (base64[len-2] == '=') adjust++;
|
||||
}
|
||||
CERTCertificate *cert =
|
||||
CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &secitem_cert,
|
||||
nsnull, PR_FALSE, PR_TRUE);
|
||||
PL_strfree(certDER);
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
char *certDER = 0;
|
||||
PRInt32 lengthDER = 0;
|
||||
if (!cert)
|
||||
return (PORT_GetError() == SEC_ERROR_NO_MEMORY)
|
||||
? NS_ERROR_OUT_OF_MEMORY : NS_ERROR_FAILURE;
|
||||
|
||||
certDER = PL_Base64Decode(base64, len, NULL);
|
||||
if (!certDER || !*certDER) {
|
||||
rv = NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
else {
|
||||
lengthDER = (len*3)/4 - adjust;
|
||||
nsNSSCertificate *nsNSS = nsNSSCertificate::Create(cert);
|
||||
CERT_DestroyCertificate(cert);
|
||||
|
||||
SECItem secitem_cert;
|
||||
secitem_cert.type = siDERCertBuffer;
|
||||
secitem_cert.data = (unsigned char*)certDER;
|
||||
secitem_cert.len = lengthDER;
|
||||
if (!nsNSS)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
CERTCertificate *cert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &secitem_cert, nsnull, PR_FALSE, PR_TRUE);
|
||||
|
||||
if (!cert) {
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
else {
|
||||
nsNSSCertificate *nsNSS = nsNSSCertificate::Create(cert);
|
||||
if (!nsNSS) {
|
||||
rv = NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
else {
|
||||
nsresult rv = nsNSS->QueryInterface(NS_GET_IID(nsIX509Cert), (void**)_retval);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && *_retval) {
|
||||
NS_ADDREF(*_retval);
|
||||
}
|
||||
|
||||
NS_RELEASE(nsNSS);
|
||||
}
|
||||
CERT_DestroyCertificate(cert);
|
||||
}
|
||||
}
|
||||
|
||||
if (certDER) {
|
||||
nsCRT::free(certDER);
|
||||
}
|
||||
return rv;
|
||||
return CallQueryInterface(nsNSS, _retval);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -54,6 +54,7 @@ _TEST_FILES = \
|
|||
_CHROME_FILES = \
|
||||
test_bug413909.html \
|
||||
test_bug480619.html \
|
||||
test_bug644006.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html><head>
|
||||
<title>Test bug 644006</title>
|
||||
<script type="text/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
|
||||
</head><body>
|
||||
<script type="application/javascript;version=1.7">
|
||||
const FAILURE = Components.results.NS_ERROR_FAILURE;
|
||||
const ILLEGAL_VALUE = Components.results.NS_ERROR_ILLEGAL_VALUE;
|
||||
|
||||
var certDB = Components.classes["@mozilla.org/security/x509certdb;1"]
|
||||
.getService(Components.interfaces.nsIX509CertDB);
|
||||
|
||||
function excMessage(e)
|
||||
{
|
||||
if ("message" in e && e.message !== null) {
|
||||
let msg = e.message;
|
||||
if ("data" in e && e.data !== null)
|
||||
msg = msg + ": " + e.data;
|
||||
return msg;
|
||||
} else {
|
||||
return e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
function testGood(data)
|
||||
{
|
||||
let label = "CN=" + data.cn;
|
||||
try {
|
||||
let cert = certDB.constructX509FromBase64(data.cert);
|
||||
is(cert.commonName, data.cn, label + ": constructX509 succeeded");
|
||||
} catch (e) {
|
||||
ok(false, label + ": exception: " + excMessage(e));
|
||||
}
|
||||
}
|
||||
|
||||
function testBad(data)
|
||||
{
|
||||
let label = uneval(data.t)
|
||||
try {
|
||||
let cert = certDB.constructX509FromBase64(data.t);
|
||||
ok(false, label + ": constructX509 succeeded");
|
||||
} catch (e) {
|
||||
is(e.result, data.e, label + ": exception: " + excMessage(e));
|
||||
}
|
||||
}
|
||||
|
||||
const badCases = [
|
||||
// wrong type or too short
|
||||
{ t: null, e: ILLEGAL_VALUE },
|
||||
{ t: "", e: ILLEGAL_VALUE },
|
||||
{ t: "=", e: ILLEGAL_VALUE },
|
||||
{ t: "==", e: ILLEGAL_VALUE },
|
||||
// not base64
|
||||
{ t: "forty-four dead stone lions", e: ILLEGAL_VALUE },
|
||||
// not a cert
|
||||
{ t: "Zm9ydHktZm91ciBkZWFkIHN0b25lIGxpb25z", e: FAILURE }
|
||||
];
|
||||
|
||||
// real certs with all three padding levels
|
||||
const goodCases = [
|
||||
{ cn: "A", cert: "MIHhMIGcAgEAMA0GCSqGSIb3DQEBBQUAMAwxCjAIBgNVBAMTAUEwHhcNMTEwMzIzMjMyNTE3WhcNMTEwNDIyMjMyNTE3WjAMMQowCAYDVQQDEwFBMEwwDQYJKoZIhvcNAQEBBQADOwAwOAIxANFm7ZCfYNJViaDWTFuMClX3+9u18VFGiyLfM6xJrxir4QVtQC7VUC/WUGoBUs9COQIDAQABMA0GCSqGSIb3DQEBBQUAAzEAx2+gIwmuYjJO5SyabqIm4lB1MandHH1HQc0y0tUFshBOMESTzQRPSVwPn77a6R9t" },
|
||||
{ cn: "Bo", cert: "MIHjMIGeAgEAMA0GCSqGSIb3DQEBBQUAMA0xCzAJBgNVBAMTAkJvMB4XDTExMDMyMzIzMjYwMloXDTExMDQyMjIzMjYwMlowDTELMAkGA1UEAxMCQm8wTDANBgkqhkiG9w0BAQEFAAM7ADA4AjEA1FoSl9w9HqMqVgk2K0J3OTiRsgHeNsQdPUl6S82ME33gH+E56PcWZA3nse+fpS3NAgMBAAEwDQYJKoZIhvcNAQEFBQADMQAo/e3BvQAmygiATljQ68tWPoWcbMwa1xxAvpWTEc1LOvMqeDBinBUqbAbSmPhGWb4=" },
|
||||
{ cn: "Cid", cert: "MIHlMIGgAgEAMA0GCSqGSIb3DQEBBQUAMA4xDDAKBgNVBAMTA0NpZDAeFw0xMTAzMjMyMzI2MzJaFw0xMTA0MjIyMzI2MzJaMA4xDDAKBgNVBAMTA0NpZDBMMA0GCSqGSIb3DQEBAQUAAzsAMDgCMQDUUxlF5xKN+8KCSsR83sN+SRwJmZdliXsnBB7PU0OgbmOWN0u8yehRkmu39kN9tzcCAwEAATANBgkqhkiG9w0BAQUFAAMxAJ3UScNqRcjHFrNu4nuwRldZLJlVJvRYXp982V4/kYodQEGN4gJ+Qyj+HTsaXy5x/w==" }
|
||||
];
|
||||
|
||||
var i;
|
||||
for (i = 0; i < badCases.length; i++)
|
||||
testBad(badCases[i]);
|
||||
for (i = 0; i < goodCases.length; i++)
|
||||
testGood(goodCases[i]);
|
||||
</script>
|
||||
</body></html>
|
Загрузка…
Ссылка в новой задаче