bug 1468909 - enforce that all given RP IDs be valid domain strings in webauthn r=qdot

The webauthn spec mandates that relying party identifiers (RP IDs) are valid
domain strings. This enforces that by ensuring that any passed-in RP IDs parse
correctly when set as the host portion of a URL.

https://w3c.github.io/webauthn/#relying-party-identifier

--HG--
extra : rebase_source : 6be22c9be660db3062f4e8119051cd122bc24a12
This commit is contained in:
David Keeler 2018-06-19 14:29:45 -07:00
Родитель 7a2d7e5d6d
Коммит e3dc094a76
3 изменённых файлов: 64 добавлений и 3 удалений

Просмотреть файл

@ -6,6 +6,7 @@
#include "hasht.h" #include "hasht.h"
#include "nsHTMLDocument.h" #include "nsHTMLDocument.h"
#include "nsIURIMutator.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "WebAuthnCoseIdentifiers.h" #include "WebAuthnCoseIdentifiers.h"
#include "mozilla/dom/AuthenticatorAttestationResponse.h" #include "mozilla/dom/AuthenticatorAttestationResponse.h"
@ -124,11 +125,27 @@ RelaxSameOrigin(nsPIDOMWindowInner* aParent,
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
nsHTMLDocument* html = document->AsHTMLDocument(); nsHTMLDocument* html = document->AsHTMLDocument();
if (!html->IsRegistrableDomainSuffixOfOrEqualTo(aInputRpId, originHost)) { // See if the given RP ID is a valid domain string.
// (We use the document's URI here as a template so we don't have to come up
// with our own scheme, etc. If we can successfully set the host as the given
// RP ID, then it should be a valid domain string.)
nsCOMPtr<nsIURI> inputRpIdURI;
nsresult rv = NS_MutateURI(uri)
.SetHost(NS_ConvertUTF16toUTF8(aInputRpId))
.Finalize(inputRpIdURI);
if (NS_FAILED(rv)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsAutoCString inputRpId;
if (NS_FAILED(inputRpIdURI->GetAsciiHost(inputRpId))) {
return NS_ERROR_FAILURE;
}
if (!html->IsRegistrableDomainSuffixOfOrEqualTo(
NS_ConvertUTF8toUTF16(inputRpId), originHost)) {
return NS_ERROR_DOM_SECURITY_ERR; return NS_ERROR_DOM_SECURITY_ERR;
} }
aRelaxedRpId.Assign(NS_ConvertUTF16toUTF8(aInputRpId)); aRelaxedRpId.Assign(inputRpId);
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -249,6 +249,28 @@
.catch(arrivingHereIsBad); .catch(arrivingHereIsBad);
}, },
// Test with an RP ID that is not a valid domain string
function() {
let rp = { id: document.domain + ":somejunk", name: "none", icon: "none" };
let makeCredentialOptions = {
rp: rp, user: user, challenge: gCredentialChallenge, pubKeyCredParams: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(arrivingHereIsGood);
},
// Test with another RP ID that is not a valid domain string
function() {
let rp = { id: document.domain + ":8888", name: "none", icon: "none" };
let makeCredentialOptions = {
rp: rp, user: user, challenge: gCredentialChallenge, pubKeyCredParams: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(arrivingHereIsGood);
},
// Test with missing rp // Test with missing rp
function() { function() {
let makeCredentialOptions = { let makeCredentialOptions = {

Просмотреть файл

@ -261,7 +261,29 @@
return credm.get({publicKey: publicKeyCredentialRequestOptions}) return credm.get({publicKey: publicKeyCredentialRequestOptions})
.then(arrivingHereIsBad) .then(arrivingHereIsBad)
.catch(expectSecurityError); .catch(expectSecurityError);
} },
function () {
// Test with an rpId that is not a valid domain string
let publicKeyCredentialRequestOptions = {
challenge: chall,
rpId: document.domain + ":somejunk",
allowCredentials: [gTrackedCredential["basic"]]
};
return credm.get({publicKey: publicKeyCredentialRequestOptions})
.then(arrivingHereIsBad)
.catch(arrivingHereIsGood);
},
function () {
// Test with another rpId that is not a valid domain string
let publicKeyCredentialRequestOptions = {
challenge: chall,
rpId: document.domain + ":8888",
allowCredentials: [gTrackedCredential["basic"]]
};
return credm.get({publicKey: publicKeyCredentialRequestOptions})
.then(arrivingHereIsBad)
.catch(arrivingHereIsGood);
},
]; ];
var i = 0; var i = 0;
var runNextTest = () => { var runNextTest = () => {