mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1756500
- Implement key verification for origin trials. r=keeler,nkulatova
Somewhat straight-forward. Add a test key so that we can add some tests for this. Differential Revision: https://phabricator.services.mozilla.com/D139402
This commit is contained in:
parent
93ce20c599
commit
6ea61a050a
@ -862,7 +862,7 @@ nsresult CryptoKey::PrivateKeyToJwk(SECKEYPrivateKey* aPrivKey,
|
||||
}
|
||||
|
||||
UniqueSECKEYPublicKey CreateECPublicKey(const SECItem* aKeyData,
|
||||
const nsString& aNamedCurve) {
|
||||
const nsAString& aNamedCurve) {
|
||||
UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
|
||||
if (!arena) {
|
||||
return nullptr;
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "secitem.h"
|
||||
#include "secoid.h"
|
||||
#include "secoidt.h"
|
||||
#include "ScopedNSSTypes.h"
|
||||
|
||||
struct JSStructuredCloneReader;
|
||||
struct JSStructuredCloneWriter;
|
||||
@ -128,8 +129,7 @@ const SECItem SEC_OID_DATA_EC_DH = {
|
||||
siBuffer, (unsigned char*)id_ecDH,
|
||||
static_cast<unsigned int>(mozilla::ArrayLength(id_ecDH))};
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace mozilla::dom {
|
||||
|
||||
inline bool ReadBuffer(JSStructuredCloneReader* aReader,
|
||||
CryptoBuffer& aBuffer) {
|
||||
@ -273,7 +273,7 @@ inline bool CheckEncodedECParameters(const SECItem* aEcParams) {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline SECItem* CreateECParamsForCurve(const nsString& aNamedCurve,
|
||||
inline SECItem* CreateECParamsForCurve(const nsAString& aNamedCurve,
|
||||
PLArenaPool* aArena) {
|
||||
MOZ_ASSERT(aArena);
|
||||
SECOidTag curveOIDTag;
|
||||
@ -313,7 +313,10 @@ inline SECItem* CreateECParamsForCurve(const nsString& aNamedCurve,
|
||||
return params;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
// Implemented in CryptoKey.cpp
|
||||
UniqueSECKEYPublicKey CreateECPublicKey(const SECItem* aKeyData,
|
||||
const nsAString& aNamedCurve);
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
||||
#endif // mozilla_dom_WebCryptoCommon_h
|
||||
|
@ -16,37 +16,107 @@
|
||||
#include "js/Wrapper.h"
|
||||
#include "nsGlobalWindowInner.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "mozilla/dom/WebCryptoCommon.h"
|
||||
#include "mozilla/StaticPrefs_dom.h"
|
||||
#include "ScopedNSSTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
LazyLogModule sOriginTrialsLog("OriginTrials");
|
||||
#define LOG(...) MOZ_LOG(sOriginTrialsLog, LogLevel::Debug, (__VA_ARGS__))
|
||||
|
||||
// This is the EcdsaP256 public key from this key pair:
|
||||
//
|
||||
// * https://github.com/emilio/origin-trial-token/blob/64f03749e2e8c58f811f67044cecc7d6955fd51a/tools/test-keys/test-ecdsa.pkcs8
|
||||
// * https://github.com/emilio/origin-trial-token/blob/64f03749e2e8c58f811f67044cecc7d6955fd51a/tools/test-keys/test-ecdsa.pub
|
||||
//
|
||||
// See that repo for tools for key and token generation and signing.
|
||||
static const unsigned char kTestKey[65] = {
|
||||
0x4, 0x4a, 0xae, 0x76, 0x64, 0x24, 0xa0, 0x55, 0xc4, 0x66, 0xe,
|
||||
0x43, 0x32, 0x4c, 0x1d, 0x85, 0x8, 0x63, 0x6a, 0x93, 0xd4, 0x1d,
|
||||
0xf, 0xfc, 0xb4, 0x2c, 0x77, 0x3d, 0xe6, 0x87, 0xdc, 0xeb, 0x46,
|
||||
0xcd, 0xcf, 0x88, 0xd0, 0xe3, 0x39, 0x8f, 0xe5, 0x17, 0xb8, 0xc8,
|
||||
0xd7, 0xd3, 0xdc, 0x32, 0x7c, 0x4f, 0x8, 0x8b, 0x61, 0x19, 0xdd,
|
||||
0xc0, 0x2, 0x5f, 0x11, 0x20, 0x6b, 0x44, 0xcf, 0x2a, 0x64,
|
||||
};
|
||||
|
||||
constexpr auto kEcAlgorithm =
|
||||
NS_LITERAL_STRING_FROM_CSTRING(WEBCRYPTO_NAMED_CURVE_P256);
|
||||
|
||||
bool VerifySignature(const uint8_t* aSignature, uintptr_t aSignatureLen,
|
||||
const uint8_t* aData, uintptr_t aDataLen,
|
||||
void* aUserData) {
|
||||
MOZ_RELEASE_ASSERT(aSignatureLen == 64);
|
||||
// TODO(emilio): Implement.
|
||||
return false;
|
||||
LOG("VerifySignature()\n");
|
||||
|
||||
if (!StaticPrefs::dom_origin_trials_test_key_enabled()) {
|
||||
// TODO(emilio): Implement.
|
||||
return false;
|
||||
}
|
||||
|
||||
const SECItem rawKey{siBuffer, const_cast<unsigned char*>(kTestKey),
|
||||
sizeof(kTestKey)};
|
||||
MOZ_RELEASE_ASSERT(rawKey.data[0] == EC_POINT_FORM_UNCOMPRESSED);
|
||||
UniqueSECKEYPublicKey pubKey = dom::CreateECPublicKey(&rawKey, kEcAlgorithm);
|
||||
if (NS_WARN_IF(!pubKey)) {
|
||||
LOG(" Failed to create public key?");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(aDataLen > UINT_MAX)) {
|
||||
LOG(" Way too large data.");
|
||||
return false;
|
||||
}
|
||||
|
||||
const SECItem signature{siBuffer, const_cast<unsigned char*>(aSignature),
|
||||
unsigned(aSignatureLen)};
|
||||
const SECItem data{siBuffer, const_cast<unsigned char*>(aData),
|
||||
unsigned(aDataLen)};
|
||||
|
||||
// SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE
|
||||
const SECStatus result = PK11_VerifyWithMechanism(
|
||||
pubKey.get(), CKM_ECDSA_SHA256, nullptr, &signature, &data, nullptr);
|
||||
if (NS_WARN_IF(result != SECSuccess)) {
|
||||
LOG(" Failed to verify data.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MatchesOrigin(const uint8_t* aOrigin, size_t aOriginLen, bool aIsSubdomain,
|
||||
bool aIsThirdParty, bool aIsUsageSubset, void* aUserData) {
|
||||
const nsDependentCSubstring origin(reinterpret_cast<const char*>(aOrigin),
|
||||
aOriginLen);
|
||||
|
||||
LOG("MatchesOrigin(%d, %d, %d, %s)\n", aIsThirdParty, aIsSubdomain,
|
||||
aIsUsageSubset, nsCString(origin).get());
|
||||
|
||||
if (aIsThirdParty || aIsSubdomain || aIsUsageSubset) {
|
||||
// TODO(emilio): Support third-party tokens and so on.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* principal = static_cast<nsIPrincipal*>(aUserData);
|
||||
nsDependentCSubstring origin(reinterpret_cast<const char*>(aOrigin),
|
||||
aOriginLen);
|
||||
nsCOMPtr<nsIURI> originURI;
|
||||
if (NS_WARN_IF(NS_FAILED(NS_NewURI(getter_AddRefs(originURI), origin)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return principal->IsSameOrigin(originURI);
|
||||
if (NS_WARN_IF(!principal->IsSameOrigin(originURI))) {
|
||||
LOG("Origin doesn't match\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void OriginTrials::UpdateFromToken(const nsAString& aBase64EncodedToken,
|
||||
nsIPrincipal* aPrincipal) {
|
||||
if (!StaticPrefs::dom_origin_trials_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG("OriginTrials::UpdateFromToken()\n");
|
||||
|
||||
nsAutoCString decodedToken;
|
||||
nsresult rv = mozilla::Base64Decode(aBase64EncodedToken, decodedToken);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -61,10 +131,12 @@ void OriginTrials::UpdateFromToken(const nsAString& aBase64EncodedToken,
|
||||
};
|
||||
auto result = origin_trials_ffi::origin_trials_parse_and_validate_token(
|
||||
decodedTokenSpan.data(), decodedTokenSpan.size(), ¶ms);
|
||||
if (!result.IsOk()) {
|
||||
if (NS_WARN_IF(!result.IsOk())) {
|
||||
LOG(" result = %d\n", int(result.tag));
|
||||
return; // TODO(emilio): Maybe report to console or what not?
|
||||
}
|
||||
OriginTrial trial = result.AsOk().trial;
|
||||
LOG(" result = Ok(%d)\n", int(trial));
|
||||
mEnabledTrials += trial;
|
||||
}
|
||||
|
||||
@ -73,6 +145,7 @@ bool OriginTrials::IsEnabled(JSContext* aCx, JSObject* aObject,
|
||||
if (nsContentUtils::ThreadsafeIsSystemCaller(aCx)) {
|
||||
return true;
|
||||
}
|
||||
LOG("OriginTrials::IsEnabled(%d)\n", int(aTrial));
|
||||
if (NS_IsMainThread()) {
|
||||
if (auto* win = xpc::WindowGlobalOrNull(js::UncheckedUnwrap(aObject))) {
|
||||
if (dom::Document* doc = win->GetExtantDoc()) {
|
||||
@ -86,4 +159,6 @@ bool OriginTrials::IsEnabled(JSContext* aCx, JSObject* aObject,
|
||||
return false;
|
||||
}
|
||||
|
||||
#undef LOG
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -2873,6 +2873,18 @@
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# Whether origin trials are enabled.
|
||||
- name: dom.origin-trials.enabled
|
||||
type: bool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# Whether we use the test key to verify tokens.
|
||||
- name: dom.origin-trials.test-key.enabled
|
||||
type: bool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# Is support for Window.paintWorklet enabled?
|
||||
- name: dom.paintWorklet.enabled
|
||||
type: bool
|
||||
|
Loading…
Reference in New Issue
Block a user