mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 972582 - Fix broken base64UrlDecode in toolkit/identity. r=MattN, r=warner, sr=mossop
This commit is contained in:
parent
ef02817542
commit
4e64bad547
@ -65,28 +65,6 @@ Base64UrlEncodeImpl(const nsACString & utf8Input, nsACString & result)
|
|||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
|
||||||
Base64UrlDecodeImpl(const nsACString & base64Input, nsACString & result)
|
|
||||||
{
|
|
||||||
nsresult rv = Base64Decode(base64Input, result);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
nsACString::char_type * out = result.BeginWriting();
|
|
||||||
nsACString::size_type length = result.Length();
|
|
||||||
// base64url encoding is defined in RFC 4648. It replaces the last two
|
|
||||||
// alphabet characters of base64 encoding with '-' and '_' respectively.
|
|
||||||
// Reverse that encoding here.
|
|
||||||
for (unsigned int i = 0; i < length; ++i) {
|
|
||||||
if (out[i] == '-') {
|
|
||||||
out[i] = '+';
|
|
||||||
} else if (out[i] == '_') {
|
|
||||||
out[i] = '/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DSA_KEY_TYPE_STRING (NS_LITERAL_CSTRING("DS160"))
|
#define DSA_KEY_TYPE_STRING (NS_LITERAL_CSTRING("DS160"))
|
||||||
#define RSA_KEY_TYPE_STRING (NS_LITERAL_CSTRING("RS256"))
|
#define RSA_KEY_TYPE_STRING (NS_LITERAL_CSTRING("RS256"))
|
||||||
|
|
||||||
@ -260,13 +238,6 @@ IdentityCryptoService::Base64UrlEncode(const nsACString & utf8Input,
|
|||||||
return Base64UrlEncodeImpl(utf8Input, result);
|
return Base64UrlEncodeImpl(utf8Input, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
IdentityCryptoService::Base64UrlDecode(const nsACString & base64Input,
|
|
||||||
nsACString & result)
|
|
||||||
{
|
|
||||||
return Base64UrlDecodeImpl(base64Input, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
KeyPair::KeyPair(SECKEYPrivateKey * privateKey, SECKEYPublicKey * publicKey)
|
KeyPair::KeyPair(SECKEYPrivateKey * privateKey, SECKEYPublicKey * publicKey)
|
||||||
: mPrivateKey(privateKey)
|
: mPrivateKey(privateKey)
|
||||||
, mPublicKey(publicKey)
|
, mPublicKey(publicKey)
|
||||||
|
@ -38,14 +38,13 @@ interface nsIIdentitySignCallback;
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// "@mozilla.org/identity/crypto-service;1"
|
// "@mozilla.org/identity/crypto-service;1"
|
||||||
[scriptable, builtinclass, uuid(17e227c4-2c31-4167-9dd4-f55ddee6a53a)]
|
[scriptable, builtinclass, uuid(f087e6bc-dd33-4f6c-a106-dd786e052ee9)]
|
||||||
interface nsIIdentityCryptoService : nsISupports
|
interface nsIIdentityCryptoService : nsISupports
|
||||||
{
|
{
|
||||||
void generateKeyPair(in AUTF8String algorithm,
|
void generateKeyPair(in AUTF8String algorithm,
|
||||||
in nsIIdentityKeyGenCallback callback);
|
in nsIIdentityKeyGenCallback callback);
|
||||||
|
|
||||||
ACString base64UrlEncode(in AUTF8String toEncode);
|
ACString base64UrlEncode(in AUTF8String toEncode);
|
||||||
ACString base64UrlDecode(in AUTF8String toDecode);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -8,6 +8,9 @@ const Cr = Components.results;
|
|||||||
|
|
||||||
Cu.import("resource://testing-common/httpd.js");
|
Cu.import("resource://testing-common/httpd.js");
|
||||||
|
|
||||||
|
// XXX until bug 937114 is fixed
|
||||||
|
Cu.importGlobalProperties(['atob']);
|
||||||
|
|
||||||
// The following boilerplate makes sure that XPCom calls
|
// The following boilerplate makes sure that XPCom calls
|
||||||
// that use the profile directory work.
|
// that use the profile directory work.
|
||||||
|
|
||||||
@ -68,6 +71,29 @@ function uuid() {
|
|||||||
return uuidGenerator.generateUUID().toString();
|
return uuidGenerator.generateUUID().toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function base64UrlDecode(s) {
|
||||||
|
s = s.replace(/-/g, '+');
|
||||||
|
s = s.replace(/_/g, '/');
|
||||||
|
|
||||||
|
// Replace padding if it was stripped by the sender.
|
||||||
|
// See http://tools.ietf.org/html/rfc4648#section-4
|
||||||
|
switch (s.length % 4) {
|
||||||
|
case 0:
|
||||||
|
break; // No pad chars in this case
|
||||||
|
case 2:
|
||||||
|
s += "==";
|
||||||
|
break; // Two pad chars
|
||||||
|
case 3:
|
||||||
|
s += "=";
|
||||||
|
break; // One pad char
|
||||||
|
default:
|
||||||
|
throw new InputException("Illegal base64url string!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// With correct padding restored, apply the standard base64 decoder
|
||||||
|
return atob(s);
|
||||||
|
}
|
||||||
|
|
||||||
// create a mock "doc" object, which the Identity Service
|
// create a mock "doc" object, which the Identity Service
|
||||||
// uses as a pointer back into the doc object
|
// uses as a pointer back into the doc object
|
||||||
function mock_doc(aIdentity, aOrigin, aDoFunc) {
|
function mock_doc(aIdentity, aOrigin, aDoFunc) {
|
||||||
@ -187,8 +213,8 @@ function setup_provisioning(identity, afterSetupCallback, doneProvisioningCallba
|
|||||||
doneProvisioningCallback(err);
|
doneProvisioningCallback(err);
|
||||||
},
|
},
|
||||||
sandbox: {
|
sandbox: {
|
||||||
// Emulate the free() method on the iframe sandbox
|
// Emulate the free() method on the iframe sandbox
|
||||||
free: function() {}
|
free: function() {}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,6 +13,25 @@ const idService = Cc["@mozilla.org/identity/crypto-service;1"]
|
|||||||
const ALG_DSA = "DS160";
|
const ALG_DSA = "DS160";
|
||||||
const ALG_RSA = "RS256";
|
const ALG_RSA = "RS256";
|
||||||
|
|
||||||
|
const BASE64_URL_ENCODINGS = [
|
||||||
|
// The vectors from RFC 4648 are very silly, but we may as well include them.
|
||||||
|
["", ""],
|
||||||
|
["f", "Zg=="],
|
||||||
|
["fo", "Zm8="],
|
||||||
|
["foo", "Zm9v"],
|
||||||
|
["foob", "Zm9vYg=="],
|
||||||
|
["fooba", "Zm9vYmE="],
|
||||||
|
["foobar", "Zm9vYmFy"],
|
||||||
|
|
||||||
|
// It's quite likely you could get a string like this in an assertion audience
|
||||||
|
["i-like-pie.com", "aS1saWtlLXBpZS5jb20="],
|
||||||
|
|
||||||
|
// A few extra to be really sure
|
||||||
|
["andré@example.com", "YW5kcsOpQGV4YW1wbGUuY29t"],
|
||||||
|
["πόλλ' οἶδ' ἀλώπηξ, ἀλλ' ἐχῖνος ἓν μέγα",
|
||||||
|
"z4DPjM67zrsnIM6_4by2zrQnIOG8gM67z47PgM63zr4sIOG8gM67zrsnIOG8kM-H4b-Wzr3Ov8-CIOG8k869IM68zq3Os86x"],
|
||||||
|
];
|
||||||
|
|
||||||
// When the output of an operation is a
|
// When the output of an operation is a
|
||||||
function do_check_eq_or_slightly_less(x, y) {
|
function do_check_eq_or_slightly_less(x, y) {
|
||||||
do_check_true(x >= y - (3 * 8));
|
do_check_true(x >= y - (3 * 8));
|
||||||
@ -21,7 +40,7 @@ function do_check_eq_or_slightly_less(x, y) {
|
|||||||
function test_base64_roundtrip() {
|
function test_base64_roundtrip() {
|
||||||
let message = "Attack at dawn!";
|
let message = "Attack at dawn!";
|
||||||
let encoded = idService.base64UrlEncode(message);
|
let encoded = idService.base64UrlEncode(message);
|
||||||
let decoded = idService.base64UrlDecode(encoded);
|
let decoded = base64UrlDecode(encoded);
|
||||||
do_check_neq(message, encoded);
|
do_check_neq(message, encoded);
|
||||||
do_check_eq(decoded, message);
|
do_check_eq(decoded, message);
|
||||||
run_next_test();
|
run_next_test();
|
||||||
@ -70,9 +89,33 @@ function test_rsa() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_base64UrlEncode() {
|
||||||
|
for (let [source, target] of BASE64_URL_ENCODINGS) {
|
||||||
|
do_check_eq(target, idService.base64UrlEncode(source));
|
||||||
|
}
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
|
||||||
|
function test_base64UrlDecode() {
|
||||||
|
let utf8Converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||||
|
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||||
|
utf8Converter.charset = "UTF-8";
|
||||||
|
|
||||||
|
// We know the encoding of our inputs - on conversion back out again, make
|
||||||
|
// sure they're the same.
|
||||||
|
for (let [source, target] of BASE64_URL_ENCODINGS) {
|
||||||
|
let result = utf8Converter.ConvertToUnicode(base64UrlDecode(target));
|
||||||
|
result += utf8Converter.Finish();
|
||||||
|
do_check_eq(source, result);
|
||||||
|
}
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
|
||||||
add_test(test_base64_roundtrip);
|
add_test(test_base64_roundtrip);
|
||||||
add_test(test_dsa);
|
add_test(test_dsa);
|
||||||
add_test(test_rsa);
|
add_test(test_rsa);
|
||||||
|
add_test(test_base64UrlEncode);
|
||||||
|
add_test(test_base64UrlDecode);
|
||||||
|
|
||||||
function run_test() {
|
function run_test() {
|
||||||
run_next_test();
|
run_next_test();
|
||||||
|
@ -204,6 +204,29 @@ function test_assertion_lifetime() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function test_audience_encoding_bug972582() {
|
||||||
|
let audience = "i-like-pie.com";
|
||||||
|
|
||||||
|
jwcrypto.generateKeyPair(
|
||||||
|
"DS160",
|
||||||
|
function(err, kp) {
|
||||||
|
do_check_null(err);
|
||||||
|
jwcrypto.generateAssertion("fake-cert", kp, audience,
|
||||||
|
function(err, backedAssertion) {
|
||||||
|
do_check_null(err);
|
||||||
|
|
||||||
|
let [cert, assertion] = backedAssertion.split("~");
|
||||||
|
let components = extractComponents(assertion);
|
||||||
|
do_check_eq(components.payload.aud, audience);
|
||||||
|
|
||||||
|
do_test_finished();
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// End of tests
|
// End of tests
|
||||||
// Helper function follow
|
// Helper function follow
|
||||||
|
|
||||||
@ -221,8 +244,8 @@ function extractComponents(signedObject) {
|
|||||||
let payloadSegment = parts[1];
|
let payloadSegment = parts[1];
|
||||||
let cryptoSegment = parts[2];
|
let cryptoSegment = parts[2];
|
||||||
|
|
||||||
let header = JSON.parse(CryptoService.base64UrlDecode(headerSegment));
|
let header = JSON.parse(base64UrlDecode(headerSegment));
|
||||||
let payload = JSON.parse(CryptoService.base64UrlDecode(payloadSegment));
|
let payload = JSON.parse(base64UrlDecode(payloadSegment));
|
||||||
|
|
||||||
// Ensure well-formed header
|
// Ensure well-formed header
|
||||||
do_check_eq(Object.keys(header).length, 1);
|
do_check_eq(Object.keys(header).length, 1);
|
||||||
@ -246,6 +269,7 @@ let TESTS = [
|
|||||||
test_get_assertion,
|
test_get_assertion,
|
||||||
test_get_assertion_with_offset,
|
test_get_assertion_with_offset,
|
||||||
test_assertion_lifetime,
|
test_assertion_lifetime,
|
||||||
|
test_audience_encoding_bug972582,
|
||||||
];
|
];
|
||||||
|
|
||||||
TESTS = TESTS.concat([test_rsa, test_dsa]);
|
TESTS = TESTS.concat([test_rsa, test_dsa]);
|
||||||
|
Loading…
Reference in New Issue
Block a user