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 "nsHTMLDocument.h"
#include "nsIURIMutator.h"
#include "nsThreadUtils.h"
#include "WebAuthnCoseIdentifiers.h"
#include "mozilla/dom/AuthenticatorAttestationResponse.h"
@ -124,11 +125,27 @@ RelaxSameOrigin(nsPIDOMWindowInner* aParent,
return NS_ERROR_FAILURE;
}
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;
}
aRelaxedRpId.Assign(NS_ConvertUTF16toUTF8(aInputRpId));
aRelaxedRpId.Assign(inputRpId);
return NS_OK;
}

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

@ -249,6 +249,28 @@
.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
function() {
let makeCredentialOptions = {

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

@ -261,7 +261,29 @@
return credm.get({publicKey: publicKeyCredentialRequestOptions})
.then(arrivingHereIsBad)
.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 runNextTest = () => {