blob: 3a050e5ac1ba09f007479bb4b2ea19f1b74a363f [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Copyright (C) 2019-2021 Apple Inc. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "config.h"
#if ENABLE(WEB_AUTHN)
#include "FidoTestData.h"
#include <WebCore/FidoConstants.h>
#include <WebCore/PublicKeyCredentialCreationOptions.h>
#include <WebCore/PublicKeyCredentialRequestOptions.h>
#include <WebCore/U2fCommandConstructor.h>
#include <WebCore/WebAuthenticationConstants.h>
#include <WebCore/WebAuthenticationUtils.h>
namespace TestWebKitAPI {
using namespace WebCore;
using namespace fido;
PublicKeyCredentialCreationOptions constructMakeCredentialRequest()
{
PublicKeyCredentialCreationOptions::RpEntity rp;
rp.id = "acme.com"_s;
rp.name = "acme.com"_s;
PublicKeyCredentialCreationOptions::UserEntity user;
user.id = WebCore::toBufferSource(TestData::kUserId, sizeof(TestData::kUserId));
user.name = "johnpsmith@example.com"_s;
user.displayName = "John P. Smith"_s;
user.icon = "https://pics.acme.com/00/p/aBjjjpqPb.png"_s;
PublicKeyCredentialCreationOptions::Parameters params;
params.type = PublicKeyCredentialType::PublicKey;
params.alg = COSE::ES256;
AuthenticationExtensionsClientInputs extensions;
extensions.googleLegacyAppidSupport = false;
PublicKeyCredentialCreationOptions options;
options.rp = WTFMove(rp);
options.user = WTFMove(user);
options.pubKeyCredParams.append(WTFMove(params));
options.extensions = WTFMove(extensions);
return options;
}
PublicKeyCredentialCreationOptions constructMakeCredentialRequestWithGoogleLegacyAppidSupport()
{
auto options = constructMakeCredentialRequest();
options.extensions->googleLegacyAppidSupport = true;
return options;
}
PublicKeyCredentialRequestOptions constructGetAssertionRequest()
{
PublicKeyCredentialRequestOptions options;
options.rpId = "acme.com"_s;
return options;
}
TEST(U2fCommandConstructorTest, TestConvertCtapMakeCredentialToU2fRegister)
{
const auto makeCredentialParam = constructMakeCredentialRequest();
EXPECT_TRUE(isConvertibleToU2fRegisterCommand(makeCredentialParam));
const auto u2fRegisterCommand = convertToU2fRegisterCommand(convertBytesToVector(TestData::kClientDataHash, sizeof(TestData::kClientDataHash)), makeCredentialParam);
ASSERT_TRUE(u2fRegisterCommand);
EXPECT_EQ(*u2fRegisterCommand, convertBytesToVector(TestData::kU2fRegisterCommandApdu, sizeof(TestData::kU2fRegisterCommandApdu)));
}
TEST(U2fCommandConstructorTest, TestConvertCtapMakeCredentialToU2fRegisterWithGoogleLegacyAppidSupport)
{
const auto makeCredentialParam = constructMakeCredentialRequestWithGoogleLegacyAppidSupport();
EXPECT_TRUE(isConvertibleToU2fRegisterCommand(makeCredentialParam));
const auto u2fRegisterCommand = convertToU2fRegisterCommand(convertBytesToVector(TestData::kClientDataHash, sizeof(TestData::kClientDataHash)), makeCredentialParam);
ASSERT_TRUE(u2fRegisterCommand);
EXPECT_EQ(*u2fRegisterCommand, convertBytesToVector(TestData::kU2fRegisterCommandApduWithGoogleLegacyAppidSupport, sizeof(TestData::kU2fRegisterCommandApduWithGoogleLegacyAppidSupport)));
}
TEST(U2fCommandConstructorTest, TestConvertCtapMakeCredentialToU2fCheckOnlySign)
{
auto makeCredentialParam = constructMakeCredentialRequest();
PublicKeyCredentialDescriptor credentialDescriptor;
credentialDescriptor.type = PublicKeyCredentialType::PublicKey;
credentialDescriptor.id = WebCore::toBufferSource(TestData::kU2fSignKeyHandle, sizeof(TestData::kU2fSignKeyHandle));
Vector<PublicKeyCredentialDescriptor> excludeList;
excludeList.append(credentialDescriptor);
makeCredentialParam.excludeCredentials = WTFMove(excludeList);
EXPECT_TRUE(isConvertibleToU2fRegisterCommand(makeCredentialParam));
const auto u2fCheckOnlySign = convertToU2fCheckOnlySignCommand(convertBytesToVector(TestData::kClientDataHash, sizeof(TestData::kClientDataHash)), makeCredentialParam, credentialDescriptor);
ASSERT_TRUE(u2fCheckOnlySign);
EXPECT_EQ(*u2fCheckOnlySign, convertBytesToVector(TestData::kU2fCheckOnlySignCommandApdu, sizeof(TestData::kU2fCheckOnlySignCommandApdu)));
}
TEST(U2fCommandConstructorTest, TestConvertCtapMakeCredentialToU2fCheckOnlySignWithInvalidCredentialType)
{
auto makeCredentialParam = constructMakeCredentialRequest();
PublicKeyCredentialDescriptor credentialDescriptor;
credentialDescriptor.type = static_cast<PublicKeyCredentialType>(-1);
credentialDescriptor.id = WebCore::toBufferSource(TestData::kU2fSignKeyHandle, sizeof(TestData::kU2fSignKeyHandle));
Vector<PublicKeyCredentialDescriptor> excludeList;
excludeList.append(credentialDescriptor);
makeCredentialParam.excludeCredentials = WTFMove(excludeList);
EXPECT_TRUE(isConvertibleToU2fRegisterCommand(makeCredentialParam));
const auto u2fCheckOnlySign = convertToU2fCheckOnlySignCommand(convertBytesToVector(TestData::kClientDataHash, sizeof(TestData::kClientDataHash)), makeCredentialParam, credentialDescriptor);
EXPECT_FALSE(u2fCheckOnlySign);
}
TEST(U2fCommandConstructorTest, TestU2fRegisterCredentialAlgorithmRequirement)
{
PublicKeyCredentialCreationOptions::RpEntity rp;
rp.id = "acme.com"_s;
rp.name = "acme.com"_s;
PublicKeyCredentialCreationOptions::UserEntity user;
user.id = WebCore::toBufferSource(TestData::kUserId, sizeof(TestData::kUserId));
user.name = "johnpsmith@example.com"_s;
user.displayName = "John P. Smith"_s;
user.icon = "https://pics.acme.com/00/p/aBjjjpqPb.png"_s;
PublicKeyCredentialCreationOptions::Parameters params;
params.type = PublicKeyCredentialType::PublicKey;
params.alg = -257;
PublicKeyCredentialCreationOptions makeCredentialParam;
makeCredentialParam.rp = WTFMove(rp);
makeCredentialParam.user = WTFMove(user);
makeCredentialParam.pubKeyCredParams.append(WTFMove(params));
EXPECT_FALSE(isConvertibleToU2fRegisterCommand(makeCredentialParam));
}
TEST(U2fCommandConstructorTest, TestU2fRegisterUserVerificationRequirement)
{
auto makeCredentialParam = constructMakeCredentialRequest();
PublicKeyCredentialCreationOptions::AuthenticatorSelectionCriteria selection;
selection.userVerification = UserVerificationRequirement::Required;
makeCredentialParam.authenticatorSelection = WTFMove(selection);
EXPECT_FALSE(isConvertibleToU2fRegisterCommand(makeCredentialParam));
}
TEST(U2fCommandConstructorTest, TestU2fRegisterResidentKeyRequirement)
{
auto makeCredentialParam = constructMakeCredentialRequest();
PublicKeyCredentialCreationOptions::AuthenticatorSelectionCriteria selection;
selection.requireResidentKey = true;
makeCredentialParam.authenticatorSelection = WTFMove(selection);
EXPECT_FALSE(isConvertibleToU2fRegisterCommand(makeCredentialParam));
}
TEST(U2fCommandConstructorTest, TestConvertCtapGetAssertionToU2fSignRequest)
{
auto getAssertionReq = constructGetAssertionRequest();
PublicKeyCredentialDescriptor credentialDescriptor;
credentialDescriptor.type = PublicKeyCredentialType::PublicKey;
credentialDescriptor.id = WebCore::toBufferSource(TestData::kU2fSignKeyHandle, sizeof(TestData::kU2fSignKeyHandle));
Vector<PublicKeyCredentialDescriptor> allowedList;
allowedList.append(WTFMove(credentialDescriptor));
getAssertionReq.allowCredentials = WTFMove(allowedList);
EXPECT_TRUE(isConvertibleToU2fSignCommand(getAssertionReq));
const auto u2fSignCommand = convertToU2fSignCommand(convertBytesToVector(TestData::kClientDataHash, sizeof(TestData::kClientDataHash)), getAssertionReq, WebCore::toBufferSource(TestData::kU2fSignKeyHandle, sizeof(TestData::kU2fSignKeyHandle)));
ASSERT_TRUE(u2fSignCommand);
EXPECT_EQ(*u2fSignCommand, convertBytesToVector(TestData::kU2fSignCommandApdu, sizeof(TestData::kU2fSignCommandApdu)));
}
TEST(U2fCommandConstructorTest, TestConvertCtapGetAssertionWithAppIDToU2fSignRequest)
{
auto getAssertionReq = constructGetAssertionRequest();
PublicKeyCredentialDescriptor credentialDescriptor;
credentialDescriptor.type = PublicKeyCredentialType::PublicKey;
credentialDescriptor.id = WebCore::toBufferSource(TestData::kU2fSignKeyHandle, sizeof(TestData::kU2fSignKeyHandle));
Vector<PublicKeyCredentialDescriptor> allowedList;
allowedList.append(WTFMove(credentialDescriptor));
getAssertionReq.allowCredentials = WTFMove(allowedList);
EXPECT_TRUE(isConvertibleToU2fSignCommand(getAssertionReq));
// AppID
WebCore::AuthenticationExtensionsClientInputs extensions;
extensions.appid = "https://www.example.com/appid"_s;
getAssertionReq.extensions = WTFMove(extensions);
const auto u2fSignCommand = convertToU2fSignCommand(convertBytesToVector(TestData::kClientDataHash, sizeof(TestData::kClientDataHash)), getAssertionReq, WebCore::toBufferSource(TestData::kU2fSignKeyHandle, sizeof(TestData::kU2fSignKeyHandle)), true);
ASSERT_TRUE(u2fSignCommand);
EXPECT_EQ(*u2fSignCommand, convertBytesToVector(TestData::kU2fAppIDSignCommandApdu, sizeof(TestData::kU2fAppIDSignCommandApdu)));
}
TEST(U2fCommandConstructorTest, TestU2fSignAllowListRequirement)
{
auto getAssertionReq = constructGetAssertionRequest();
EXPECT_FALSE(isConvertibleToU2fSignCommand(getAssertionReq));
}
TEST(U2fCommandConstructorTest, TestU2fSignUserVerificationRequirement)
{
auto getAssertionReq = constructGetAssertionRequest();
PublicKeyCredentialDescriptor credentialDescriptor;
credentialDescriptor.type = PublicKeyCredentialType::PublicKey;
credentialDescriptor.id = WebCore::toBufferSource(TestData::kU2fSignKeyHandle, sizeof(TestData::kU2fSignKeyHandle));
Vector<PublicKeyCredentialDescriptor> allowedList;
allowedList.append(WTFMove(credentialDescriptor));
getAssertionReq.allowCredentials = WTFMove(allowedList);
getAssertionReq.userVerification = UserVerificationRequirement::Required;
EXPECT_FALSE(isConvertibleToU2fSignCommand(getAssertionReq));
}
TEST(U2fCommandConstructorTest, TestCreateSignWithIncorrectKeyHandle)
{
auto getAssertionReq = constructGetAssertionRequest();
PublicKeyCredentialDescriptor credentialDescriptor;
credentialDescriptor.type = PublicKeyCredentialType::PublicKey;
credentialDescriptor.id = WebCore::toBufferSource(TestData::kU2fSignKeyHandle, sizeof(TestData::kU2fSignKeyHandle));
Vector<PublicKeyCredentialDescriptor> allowedList;
allowedList.append(WTFMove(credentialDescriptor));
getAssertionReq.allowCredentials = WTFMove(allowedList);
ASSERT_TRUE(isConvertibleToU2fSignCommand(getAssertionReq));
Vector<uint8_t> keyHandle(kMaxKeyHandleLength, 0xff);
const auto validSignCommand = convertToU2fSignCommand(convertBytesToVector(TestData::kClientDataHash, sizeof(TestData::kClientDataHash)), getAssertionReq, WebCore::toBufferSource(keyHandle.data(), keyHandle.size()));
EXPECT_TRUE(validSignCommand);
keyHandle.append(0xff);
const auto invalidSignCommand = convertToU2fSignCommand(convertBytesToVector(TestData::kClientDataHash, sizeof(TestData::kClientDataHash)), getAssertionReq, WebCore::toBufferSource(keyHandle.data(), keyHandle.size()));
EXPECT_FALSE(invalidSignCommand);
}
TEST(U2fCommandConstructorTest, TestConstructBogusU2fRegistrationCommand)
{
EXPECT_EQ(constructBogusU2fRegistrationCommand(), convertBytesToVector(TestData::kU2fFakeRegisterCommand, sizeof(TestData::kU2fFakeRegisterCommand)));
}
} // namespace TestWebKitAPI
#endif // ENABLE(WEB_AUTHN)