WebKit Bugzilla
Attachment 358358 Details for
Bug 193150
: [WebAuthN] Import U2F command/response converters from Chromium
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-193150-20190104132734.patch (text/plain), 120.51 KB, created by
Jiewen Tan
on 2019-01-04 13:27:35 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Jiewen Tan
Created:
2019-01-04 13:27:35 PST
Size:
120.51 KB
patch
obsolete
>Subversion Revision: 239526 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index 9f38d7c2da25675ddc78a8de754b2899f34e33cb..62e2fb152d43e36b8e51165c408d25a7a0e61418 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,65 @@ >+2019-01-04 Jiewen Tan <jiewen_tan@apple.com> >+ >+ [WebAuthN] Import U2F command/response converters from Chromium >+ https://bugs.webkit.org/show_bug.cgi?id=193150 >+ <rdar://problem/47054028> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ This patch imports Chromium's U2F command/response converters: >+ https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#u2f-interoperability >+ 1. It directly imports the following files and suit them to WebKit's coding style: >+ https://cs.chromium.org/chromium/src/device/fido/u2f_command_constructor.cc?l=1&rcl=db624110317d01efa78cd32e7be1524190e1beb0 >+ https://cs.chromium.org/chromium/src/device/fido/u2f_command_constructor.h?rcl=db624110317d01efa78cd32e7be1524190e1beb0 >+ https://cs.chromium.org/chromium/src/device/fido/u2f_command_constructor_unittest.cc?rcl=db624110317d01efa78cd32e7be1524190e1beb0 >+ 2. It gathers the following methods into U2fResponseConverter: >+ AuthenticatorMakeCredentialResponse::CreateFromU2fRegisterResponse() >+ AuthenticatorGetAssertionResponse::CreateFromU2fSignResponse() >+ 3. It also updates FidoConstants.h, FidoTestData.h and CtapResponseTest.cpp accordingly. >+ >+ Besides importing stuffs from Chroimum, it also gathers a bunch of constants and helper functions into WebAuthenticationConstants.h >+ and WebAuthenticationUtils.h. It also fixes Bug 183534: 2) and 7). >+ >+ Covered by API tests. >+ >+ * Modules/webauthn/AuthenticatorCoordinator.cpp: >+ (WebCore::AuthenticatorCoordinatorInternal::produceClientDataJsonHash): >+ * Modules/webauthn/WebAuthenticationConstants.h: Copied from Source/WebCore/Modules/webauthn/COSEConstants.h. >+ * Modules/webauthn/WebAuthenticationUtils.cpp: Added. >+ (WebCore::convertBytesToVector): >+ (WebCore::produceRpIdHash): >+ (WebCore::encodeES256PublicKeyAsCBOR): >+ (WebCore::buildAttestedCredentialData): >+ (WebCore::buildAuthData): >+ (WebCore::buildAttestationObject): >+ * Modules/webauthn/WebAuthenticationUtils.h: Renamed from Source/WebCore/Modules/webauthn/COSEConstants.h. >+ * Modules/webauthn/fido/DeviceResponseConverter.cpp: >+ (fido::getCredentialId): >+ (fido::readCTAPGetInfoResponse): >+ * Modules/webauthn/fido/FidoConstants.h: >+ * Modules/webauthn/fido/U2fCommandConstructor.cpp: Added. >+ (fido::WebCore::constructU2fRegisterCommand): >+ (fido::WebCore::constructU2fSignCommand): >+ (fido::isConvertibleToU2fRegisterCommand): >+ (fido::isConvertibleToU2fSignCommand): >+ (fido::convertToU2fRegisterCommand): >+ (fido::convertToU2fCheckOnlySignCommand): >+ (fido::convertToU2fSignCommand): >+ (fido::constructBogusU2fRegistrationCommand): >+ * Modules/webauthn/fido/U2fCommandConstructor.h: Added. >+ * Modules/webauthn/fido/U2fResponseConverter.cpp: Added. >+ (fido::WebCore::extractECPublicKeyFromU2fRegistrationResponse): >+ (fido::WebCore::extractCredentialIdFromU2fRegistrationResponse): >+ (fido::WebCore::createAttestedCredentialDataFromU2fRegisterResponse): >+ (fido::WebCore::parseX509Length): >+ (fido::WebCore::createFidoAttestationStatementFromU2fRegisterResponse): >+ (fido::readU2fRegisterResponse): >+ (fido::readFromU2fSignResponse): >+ * Modules/webauthn/fido/U2fResponseConverter.h: Added. >+ * Modules/webgpu/WebGPUCommandBuffer.cpp: >+ * Sources.txt: >+ * WebCore.xcodeproj/project.pbxproj: >+ > 2018-12-21 Zalan Bujtas <zalan@apple.com> > > [iOS] Using file upload can trigger a crash under RenderThemeIOS::paintFileUploadIconDecorations() >diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog >index 1a222fc62adc11507ca7e04ee1159a49e4f964b8..59697614b42e0e2d8de7f9835fe34a0515b11309 100644 >--- a/Source/WebKit/ChangeLog >+++ b/Source/WebKit/ChangeLog >@@ -1,3 +1,21 @@ >+2019-01-04 Jiewen Tan <jiewen_tan@apple.com> >+ >+ [WebAuthN] Import U2F command/response converters from Chromium >+ https://bugs.webkit.org/show_bug.cgi?id=193150 >+ <rdar://problem/47054028> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Moves helper functions to WebAuthenticationUtils. >+ >+ * UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm: >+ (WebKit::LocalAuthenticatorInternal::produceHashSet): >+ (WebKit::LocalAuthenticator::continueMakeCredentialAfterAttested): >+ (): Deleted. >+ (WebKit::LocalAuthenticatorInternal::buildAuthData): Deleted. >+ * UIProcess/WebAuthentication/Mock/MockHidConnection.cpp: >+ (WebKit::MockHidConnection::feedReports): >+ > 2018-12-21 Alex Christensen <achristensen@webkit.org> > > Expand use of sourceApplicationAuditData >diff --git a/Source/WebCore/Modules/webauthn/AuthenticatorCoordinator.cpp b/Source/WebCore/Modules/webauthn/AuthenticatorCoordinator.cpp >index 43f16b01c87db3458a28e3c4768be4dfcd3907c4..78307991667d083b6a5f06b520a2de91b94bbcc0 100644 >--- a/Source/WebCore/Modules/webauthn/AuthenticatorCoordinator.cpp >+++ b/Source/WebCore/Modules/webauthn/AuthenticatorCoordinator.cpp >@@ -73,7 +73,6 @@ static Ref<ArrayBuffer> produceClientDataJson(ClientDataType type, const BufferS > > static Vector<uint8_t> produceClientDataJsonHash(const ArrayBuffer& clientDataJson) > { >- // FIXME: This might be platform dependent. > auto crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256); > crypto->addBytes(clientDataJson.data(), clientDataJson.byteLength()); > return crypto->computeHash(); >diff --git a/Source/WebCore/Modules/webauthn/COSEConstants.h b/Source/WebCore/Modules/webauthn/COSEConstants.h >deleted file mode 100644 >index f46fc4c03ee4ccb697328183e52e6897d5413e33..0000000000000000000000000000000000000000 >--- a/Source/WebCore/Modules/webauthn/COSEConstants.h >+++ /dev/null >@@ -1,43 +0,0 @@ >-/* >- * Copyright (C) 2018 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: >- * 1. Redistributions of source code must retain the above copyright >- * notice, this list of conditions and the following disclaimer. >- * 2. 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. >- * >- * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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. >- */ >- >-#pragma once >- >-namespace COSE { >- >-// See RFC 8152 - CBOR Object Signing and Encryption <https://tools.ietf.org/html/rfc8152> >-// Labels >-const int64_t alg = 3; >-const int64_t crv = -1; >-const int64_t kty = 1; >-const int64_t x = -2; >-const int64_t y = -3; >- >-// Values >-const int64_t EC2 = 2; >-const int64_t ES256 = -7; >-const int64_t P_256 = 1; >- >-} // namespace COSE >diff --git a/Source/WebCore/Modules/webauthn/WebAuthenticationConstants.h b/Source/WebCore/Modules/webauthn/WebAuthenticationConstants.h >new file mode 100644 >index 0000000000000000000000000000000000000000..6145261ac0281aa3e0ecca7833632a165f725509 >--- /dev/null >+++ b/Source/WebCore/Modules/webauthn/WebAuthenticationConstants.h >@@ -0,0 +1,70 @@ >+/* >+ * Copyright (C) 2018 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: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. 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. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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. >+ */ >+ >+#pragma once >+ >+namespace COSE { >+ >+// See RFC 8152 - CBOR Object Signing and Encryption <https://tools.ietf.org/html/rfc8152> >+// Labels >+const int64_t alg = 3; >+const int64_t crv = -1; >+const int64_t kty = 1; >+const int64_t x = -2; >+const int64_t y = -3; >+ >+// Values >+const int64_t EC2 = 2; >+const int64_t ES256 = -7; >+const int64_t P_256 = 1; >+ >+} // namespace COSE >+ >+namespace WebCore { >+ >+// Length of the SHA-256 hash of the RP ID asssociated with the credential: >+// https://www.w3.org/TR/webauthn/#sec-authenticator-data >+const size_t rpIdHashLength = 32; >+ >+// Length of the flags: >+// https://www.w3.org/TR/webauthn/#sec-authenticator-data >+const size_t flagsLength = 1; >+ >+// Length of the signature counter, 32-bit unsigned big-endian integer: >+// https://www.w3.org/TR/webauthn/#sec-authenticator-data >+const size_t signCounterLength = 4; >+ >+// Length of the AAGUID of the authenticator: >+// https://www.w3.org/TR/webauthn/#sec-attested-credential-data >+const size_t aaguidLength = 16; >+ >+// Length of the byte length L of Credential ID, 16-bit unsigned big-endian >+// integer: https://www.w3.org/TR/webauthn/#sec-attested-credential-data >+const size_t credentialIdLengthLength = 2; >+ >+// Per Section 2.3.5 of http://www.secg.org/sec1-v2.pdf >+const size_t ES256FieldElementLength = 32; >+ >+} // namespace WebCore >diff --git a/Source/WebCore/Modules/webauthn/WebAuthenticationUtils.cpp b/Source/WebCore/Modules/webauthn/WebAuthenticationUtils.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..13326191ac2fe610b00d0446bb7a0dffc38d639b >--- /dev/null >+++ b/Source/WebCore/Modules/webauthn/WebAuthenticationUtils.cpp >@@ -0,0 +1,128 @@ >+/* >+ * Copyright (C) 2019 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: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. 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. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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" >+#include "WebAuthenticationUtils.h" >+ >+#if ENABLE(WEB_AUTHN) >+ >+#include "CBORWriter.h" >+#include "WebAuthenticationConstants.h" >+#include <pal/crypto/CryptoDigest.h> >+#include <wtf/text/WTFString.h> >+ >+namespace WebCore { >+ >+Vector<uint8_t> convertBytesToVector(const uint8_t byteArray[], const size_t length) >+{ >+ Vector<uint8_t> result; >+ result.append(byteArray, length); >+ return result; >+} >+ >+Vector<uint8_t> produceRpIdHash(const String& rpId) >+{ >+ auto crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256); >+ auto rpIdUtf8 = rpId.utf8(); >+ crypto->addBytes(rpIdUtf8.data(), rpIdUtf8.length()); >+ return crypto->computeHash(); >+} >+ >+Vector<uint8_t> encodeES256PublicKeyAsCBOR(Vector<uint8_t>&& x, Vector<uint8_t>&& y) >+{ >+ cbor::CBORValue::MapValue publicKeyMap; >+ publicKeyMap[cbor::CBORValue(COSE::kty)] = cbor::CBORValue(COSE::EC2); >+ publicKeyMap[cbor::CBORValue(COSE::alg)] = cbor::CBORValue(COSE::ES256); >+ publicKeyMap[cbor::CBORValue(COSE::crv)] = cbor::CBORValue(COSE::P_256); >+ publicKeyMap[cbor::CBORValue(COSE::x)] = cbor::CBORValue(WTFMove(x)); >+ publicKeyMap[cbor::CBORValue(COSE::y)] = cbor::CBORValue(WTFMove(y)); >+ >+ auto cosePublicKey = cbor::CBORWriter::write(cbor::CBORValue(WTFMove(publicKeyMap))); >+ ASSERT(cosePublicKey); >+ return *cosePublicKey; >+} >+ >+Vector<uint8_t> buildAttestedCredentialData(const Vector<uint8_t>& aaguid, const Vector<uint8_t>& credentialId, const Vector<uint8_t>& coseKey) >+{ >+ Vector<uint8_t> attestedCredentialData; >+ attestedCredentialData.reserveInitialCapacity(aaguidLength + credentialIdLengthLength + credentialId.size() + coseKey.size()); >+ >+ // aaguid >+ ASSERT(aaguid.size() == aaguidLength); >+ attestedCredentialData.appendVector(aaguid); >+ >+ // credentialIdLength >+ ASSERT(credentialId.size() <= std::numeric_limits<uint16_t>::max()); >+ attestedCredentialData.append(credentialId.size() >> 8 & 0xff); >+ attestedCredentialData.append(credentialId.size() & 0xff); >+ >+ // credentialId >+ attestedCredentialData.appendVector(credentialId); >+ >+ // credentialPublicKey >+ attestedCredentialData.appendVector(coseKey); >+ >+ return attestedCredentialData; >+} >+ >+Vector<uint8_t> buildAuthData(const String& rpId, const uint8_t flags, const uint32_t counter, const Vector<uint8_t>& optionalAttestedCredentialData) >+{ >+ Vector<uint8_t> authData; >+ authData.reserveInitialCapacity(rpIdHashLength + flagsLength + signCounterLength + optionalAttestedCredentialData.size()); >+ >+ // RP ID hash >+ authData.appendVector(produceRpIdHash(rpId)); >+ >+ // FLAGS >+ authData.append(flags); >+ >+ // COUNTER >+ authData.append(counter >> 24 & 0xff); >+ authData.append(counter >> 16 & 0xff); >+ authData.append(counter >> 8 & 0xff); >+ authData.append(counter & 0xff); >+ >+ // ATTESTED CRED. DATA >+ authData.appendVector(optionalAttestedCredentialData); >+ >+ return authData; >+} >+ >+Vector<uint8_t> buildAttestationObject(Vector<uint8_t>&& authData, String&& format, cbor::CBORValue::MapValue&& statementMap) >+{ >+ cbor::CBORValue::MapValue attestationObjectMap; >+ attestationObjectMap[cbor::CBORValue("authData")] = cbor::CBORValue(WTFMove(authData)); >+ attestationObjectMap[cbor::CBORValue("fmt")] = cbor::CBORValue(WTFMove(format)); >+ attestationObjectMap[cbor::CBORValue("attStmt")] = cbor::CBORValue(WTFMove(statementMap)); >+ >+ auto attestationObject = cbor::CBORWriter::write(cbor::CBORValue(WTFMove(attestationObjectMap))); >+ ASSERT(attestationObject); >+ return *attestationObject; >+} >+ >+ >+} // namespace WebCore >+ >+#endif // ENABLE(WEB_AUTHN) >diff --git a/Source/WebCore/Modules/webauthn/WebAuthenticationUtils.h b/Source/WebCore/Modules/webauthn/WebAuthenticationUtils.h >new file mode 100644 >index 0000000000000000000000000000000000000000..17f022e16078217b1918001807d31bcf708a2170 >--- /dev/null >+++ b/Source/WebCore/Modules/webauthn/WebAuthenticationUtils.h >@@ -0,0 +1,53 @@ >+/* >+ * Copyright (C) 2019 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: >+ * 1. Redistributions of source code must retain the above copyright >+ * notice, this list of conditions and the following disclaimer. >+ * 2. 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. >+ * >+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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. >+ */ >+ >+#pragma once >+ >+#if ENABLE(WEB_AUTHN) >+ >+#include "CBORValue.h" >+#include <wtf/Forward.h> >+ >+namespace WebCore { >+ >+WEBCORE_EXPORT Vector<uint8_t> convertBytesToVector(const uint8_t byteArray[], const size_t length); >+ >+// Produce a SHA-256 hash of the given RP ID. >+WEBCORE_EXPORT Vector<uint8_t> produceRpIdHash(const String& rpId); >+ >+WEBCORE_EXPORT Vector<uint8_t> encodeES256PublicKeyAsCBOR(Vector<uint8_t>&& x, Vector<uint8_t>&& y); >+ >+// https://www.w3.org/TR/webauthn/#attested-credential-data >+WEBCORE_EXPORT Vector<uint8_t> buildAttestedCredentialData(const Vector<uint8_t>& aaguid, const Vector<uint8_t>& credentialId, const Vector<uint8_t>& coseKey); >+ >+// https://www.w3.org/TR/webauthn/#sec-authenticator-data >+WEBCORE_EXPORT Vector<uint8_t> buildAuthData(const String& rpId, const uint8_t flags, const uint32_t counter, const Vector<uint8_t>& optionalAttestedCredentialData); >+ >+// https://www.w3.org/TR/webauthn/#attestation-object >+WEBCORE_EXPORT Vector<uint8_t> buildAttestationObject(Vector<uint8_t>&& authData, String&& format, cbor::CBORValue::MapValue&& statementMap); >+ >+} // namespace WebCore >+ >+#endif // ENABLE(WEB_AUTHN) >diff --git a/Source/WebCore/Modules/webauthn/fido/DeviceResponseConverter.cpp b/Source/WebCore/Modules/webauthn/fido/DeviceResponseConverter.cpp >index a404a120ce46121394c7247e30e910f4ee3d3fda..d036717867dd1f8e995667623ab5ff7454f45a2f 100644 >--- a/Source/WebCore/Modules/webauthn/fido/DeviceResponseConverter.cpp >+++ b/Source/WebCore/Modules/webauthn/fido/DeviceResponseConverter.cpp >@@ -35,6 +35,7 @@ > #include "AuthenticatorSupportedOptions.h" > #include "CBORReader.h" > #include "CBORWriter.h" >+#include "WebAuthenticationConstants.h" > #include <wtf/StdSet.h> > #include <wtf/Vector.h> > >@@ -65,17 +66,17 @@ CtapDeviceResponseCode getResponseCode(const Vector<uint8_t>& buffer) > > static Vector<uint8_t> getCredentialId(const Vector<uint8_t>& authenticatorData) > { >- const size_t credentialIdLengthOffset = kRpIdHashLength + kFlagsLength + kSignCounterLength + kAaguidLength; >+ const size_t credentialIdLengthOffset = rpIdHashLength + flagsLength + signCounterLength + aaguidLength; > >- if (authenticatorData.size() < credentialIdLengthOffset + kCredentialIdLengthLength) >+ if (authenticatorData.size() < credentialIdLengthOffset + credentialIdLengthLength) > return { }; > size_t credentialIdLength = (static_cast<size_t>(authenticatorData[credentialIdLengthOffset]) << 8) | static_cast<size_t>(authenticatorData[credentialIdLengthOffset + 1]); > >- if (authenticatorData.size() < credentialIdLengthOffset + kCredentialIdLengthLength + credentialIdLength) >+ if (authenticatorData.size() < credentialIdLengthOffset + credentialIdLengthLength + credentialIdLength) > return { }; > Vector<uint8_t> credentialId; > credentialId.reserveInitialCapacity(credentialIdLength); >- auto beginIt = authenticatorData.begin() + credentialIdLengthOffset + kCredentialIdLengthLength; >+ auto beginIt = authenticatorData.begin() + credentialIdLengthOffset + credentialIdLengthLength; > credentialId.appendRange(beginIt, beginIt + credentialIdLength); > return credentialId; > } >@@ -205,7 +206,7 @@ Optional<AuthenticatorGetInfoResponse> readCTAPGetInfoResponse(const Vector<uint > return WTF::nullopt; > > it = responseMap.find(CBOR(3)); >- if (it == responseMap.end() || !it->second.isByteString() || it->second.getByteString().size() != kAaguidLength) >+ if (it == responseMap.end() || !it->second.isByteString() || it->second.getByteString().size() != aaguidLength) > return WTF::nullopt; > > AuthenticatorGetInfoResponse response(WTFMove(protocolVersions), Vector<uint8_t>(it->second.getByteString())); >diff --git a/Source/WebCore/Modules/webauthn/fido/FidoConstants.h b/Source/WebCore/Modules/webauthn/fido/FidoConstants.h >index 69b9199206fa0691d24806cf7d26535656315f24..530a174867ea53db7c000e53144b29cff4b61c1f 100644 >--- a/Source/WebCore/Modules/webauthn/fido/FidoConstants.h >+++ b/Source/WebCore/Modules/webauthn/fido/FidoConstants.h >@@ -41,25 +41,14 @@ enum class ProtocolVersion { > kUnknown, > }; > >-// Length of the SHA-256 hash of the RP ID asssociated with the credential: >-// https://www.w3.org/TR/webauthn/#sec-authenticator-data >-constexpr size_t kRpIdHashLength = 32; >- >-// Length of the flags: >-// https://www.w3.org/TR/webauthn/#sec-authenticator-data >-constexpr size_t kFlagsLength = 1; >- >-// Length of the signature counter, 32-bit unsigned big-endian integer: >-// https://www.w3.org/TR/webauthn/#sec-authenticator-data >-constexpr size_t kSignCounterLength = 4; >- >-// Length of the AAGUID of the authenticator: >-// https://www.w3.org/TR/webauthn/#sec-attested-credential-data >-constexpr size_t kAaguidLength = 16; >- >-// Length of the byte length L of Credential ID, 16-bit unsigned big-endian >-// integer: https://www.w3.org/TR/webauthn/#sec-attested-credential-data >-constexpr size_t kCredentialIdLengthLength = 2; >+// Length of the U2F challenge/application parameter: >+// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#registration-request-message---u2f_register >+constexpr size_t kU2fChallengeParamLength = 32; >+constexpr size_t kU2fApplicationParamLength = 32; >+// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#registration-response-message-success >+constexpr size_t kReservedLength = 1; >+constexpr size_t kU2fKeyHandleLengthOffset = 66; >+constexpr size_t kU2fKeyHandleOffset = 67; > > // CTAP protocol device response code, as specified in > // https://fidoalliance.org/specs/fido-v2.0-ps-20170927/fido-client-to-authenticator-protocol-v2.0-ps-20170927.html#error-responses >@@ -134,6 +123,19 @@ enum class FidoHidDeviceCommand : uint8_t { > > bool isFidoHidDeviceCommand(FidoHidDeviceCommand); > >+// Parameters for fake U2F registration used to check for user presence. >+const uint8_t kBogusAppParam[] = { >+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, >+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, >+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 >+}; >+ >+const uint8_t kBogusChallenge[] = { >+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, >+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, >+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42 >+}; >+ > // String key values for CTAP request optional parameters and > // AuthenticatorGetInfo response. > const char kResidentKeyMapKey[] = "rk"; >@@ -170,6 +172,15 @@ const size_t kHidMaxMessageSize = 7609; > // CTAP/U2F devices only provide a single report so specify a report ID of 0 here. > const uint8_t kHidReportId = 0x00; > >+// U2F APDU encoding constants, as specified in >+// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#authentication-messages >+ >+// P1 instructions. >+constexpr uint8_t kP1EnforceUserPresenceAndSign = 0x03; >+constexpr uint8_t kP1CheckOnly = 0x07; >+ >+constexpr size_t kMaxKeyHandleLength = 255; >+ > // Authenticator API commands supported by CTAP devices, as specified in > // https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html#authenticator-api > enum class CtapRequestCommand : uint8_t { >@@ -181,6 +192,16 @@ enum class CtapRequestCommand : uint8_t { > kAuthenticatorReset = 0x07, > }; > >+// APDU instruction code for U2F request encoding. >+// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#command-and-parameter-values >+enum class U2fApduInstruction : uint8_t { >+ kRegister = 0x01, >+ kSign = 0x02, >+ kVersion = 0x03, >+ kVendorFirst = 0x40, >+ kVenderLast = 0xBF, >+}; >+ > // String key values for attestation object as a response to MakeCredential > // request. > const char kFormatKey[] = "fmt"; >diff --git a/Source/WebCore/Modules/webauthn/fido/U2fCommandConstructor.cpp b/Source/WebCore/Modules/webauthn/fido/U2fCommandConstructor.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..12a969c343c59983ce09db7f966987d54d91bdac >--- /dev/null >+++ b/Source/WebCore/Modules/webauthn/fido/U2fCommandConstructor.cpp >@@ -0,0 +1,133 @@ >+// Copyright 2018 The Chromium Authors. All rights reserved. >+// Copyright (C) 2019 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" >+#include "U2fCommandConstructor.h" >+ >+#if ENABLE(WEB_AUTHN) >+ >+#include "ApduCommand.h" >+#include "FidoConstants.h" >+#include "PublicKeyCredentialCreationOptions.h" >+#include "PublicKeyCredentialRequestOptions.h" >+#include "UserVerificationRequirement.h" >+#include "WebAuthenticationConstants.h" >+#include "WebAuthenticationUtils.h" >+#include <wtf/Optional.h> >+ >+namespace fido { >+using namespace WebCore; >+ >+namespace { >+ >+static Vector<uint8_t> constructU2fRegisterCommand(const Vector<uint8_t>& applicationParameter, const Vector<uint8_t>& challengeParameter) >+{ >+ Vector<uint8_t> data; >+ data.reserveInitialCapacity(kU2fChallengeParamLength + kU2fApplicationParamLength); >+ data.appendVector(challengeParameter); >+ data.appendVector(applicationParameter); >+ >+ apdu::ApduCommand command; >+ command.setIns(static_cast<uint8_t>(U2fApduInstruction::kRegister)); >+ command.setData(WTFMove(data)); >+ command.setResponseLength(apdu::ApduCommand::kApduMaxResponseLength); >+ return command.getEncodedCommand(); >+} >+ >+static Optional<Vector<uint8_t>> constructU2fSignCommand(const Vector<uint8_t>& applicationParameter, const Vector<uint8_t>& challengeParameter, const Vector<uint8_t>& keyHandle, bool checkOnly) >+{ >+ if (keyHandle.size() > kMaxKeyHandleLength) >+ return WTF::nullopt; >+ >+ Vector<uint8_t> data; >+ data.reserveInitialCapacity(kU2fChallengeParamLength + kU2fApplicationParamLength + 1 + keyHandle.size()); >+ data.appendVector(challengeParameter); >+ data.appendVector(applicationParameter); >+ data.append(static_cast<uint8_t>(keyHandle.size())); >+ data.appendVector(keyHandle); >+ >+ apdu::ApduCommand command; >+ command.setIns(static_cast<uint8_t>(U2fApduInstruction::kSign)); >+ command.setP1(checkOnly ? kP1CheckOnly : kP1EnforceUserPresenceAndSign); >+ command.setData(WTFMove(data)); >+ command.setResponseLength(apdu::ApduCommand::kApduMaxResponseLength); >+ return command.getEncodedCommand(); >+} >+ >+} // namespace >+ >+bool isConvertibleToU2fRegisterCommand(const PublicKeyCredentialCreationOptions& request) >+{ >+ if (request.authenticatorSelection && (request.authenticatorSelection->userVerification == UserVerificationRequirement::Required || request.authenticatorSelection->requireResidentKey)) >+ return false; >+ >+ for (const auto& parameters : request.pubKeyCredParams) { >+ if (parameters.alg == COSE::ES256) >+ return true; >+ } >+ return false; >+} >+ >+bool isConvertibleToU2fSignCommand(const PublicKeyCredentialRequestOptions& request) >+{ >+ return (request.userVerification != UserVerificationRequirement::Required) && !request.allowCredentials.isEmpty(); >+} >+ >+Optional<Vector<uint8_t>> convertToU2fRegisterCommand(const Vector<uint8_t>& clientDataHash, const PublicKeyCredentialCreationOptions& request) >+{ >+ if (!isConvertibleToU2fRegisterCommand(request)) >+ return WTF::nullopt; >+ >+ return constructU2fRegisterCommand(produceRpIdHash(request.rp.id), clientDataHash); >+} >+ >+Optional<Vector<uint8_t>> convertToU2fCheckOnlySignCommand(const Vector<uint8_t>& clientDataHash, const PublicKeyCredentialCreationOptions& request, const PublicKeyCredentialDescriptor& keyHandle) >+{ >+ if (keyHandle.type != PublicKeyCredentialType::PublicKey) >+ return WTF::nullopt; >+ >+ return constructU2fSignCommand(produceRpIdHash(request.rp.id), clientDataHash, keyHandle.idVector, true /* checkOnly */); >+} >+ >+Optional<Vector<uint8_t>> convertToU2fSignCommand(const Vector<uint8_t>& clientDataHash, const PublicKeyCredentialRequestOptions& request, const Vector<uint8_t>& keyHandle, bool checkOnly) >+{ >+ if (!isConvertibleToU2fSignCommand(request)) >+ return WTF::nullopt; >+ >+ return constructU2fSignCommand(produceRpIdHash(request.rpId), clientDataHash, keyHandle, checkOnly); >+} >+ >+Vector<uint8_t> constructBogusU2fRegistrationCommand() >+{ >+ return constructU2fRegisterCommand(convertBytesToVector(kBogusAppParam, sizeof(kBogusAppParam)), convertBytesToVector(kBogusChallenge, sizeof(kBogusChallenge))); >+} >+ >+} // namespace fido >+ >+#endif // ENABLE(WEB_AUTHN) >diff --git a/Source/WebCore/Modules/webauthn/fido/U2fCommandConstructor.h b/Source/WebCore/Modules/webauthn/fido/U2fCommandConstructor.h >new file mode 100644 >index 0000000000000000000000000000000000000000..07e16e5cf575a2e840c94b052e99aa5457b86efd >--- /dev/null >+++ b/Source/WebCore/Modules/webauthn/fido/U2fCommandConstructor.h >@@ -0,0 +1,71 @@ >+// Copyright 2018 The Chromium Authors. All rights reserved. >+// Copyright (C) 2019 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. >+ >+#pragma once >+ >+#if ENABLE(WEB_AUTHN) >+ >+#include <wtf/Forward.h> >+ >+namespace WebCore { >+struct PublicKeyCredentialCreationOptions; >+struct PublicKeyCredentialDescriptor; >+struct PublicKeyCredentialRequestOptions; >+} >+ >+namespace fido { >+ >+// Checks whether the request can be translated to valid U2F request >+// parameter. Namely, U2F request does not support resident key and >+// user verification, and ES256 algorithm must be used for public key >+// credential. >+// https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#u2f-authenticatorMakeCredential-interoperability >+WEBCORE_EXPORT bool isConvertibleToU2fRegisterCommand(const WebCore::PublicKeyCredentialCreationOptions&); >+ >+// Checks whether user verification is not required and that allow list is >+// not empty. >+// https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#u2f-authenticatorGetAssertion-interoperability >+WEBCORE_EXPORT bool isConvertibleToU2fSignCommand(const WebCore::PublicKeyCredentialRequestOptions&); >+ >+// Extracts APDU encoded U2F register command from PublicKeyCredentialCreationOptions. >+WEBCORE_EXPORT Optional<Vector<uint8_t>> convertToU2fRegisterCommand(const Vector<uint8_t>& clientDataHash, const WebCore::PublicKeyCredentialCreationOptions&); >+ >+// Extracts APDU encoded U2F check only sign command from >+// PublicKeyCredentialCreationOptions. Invoked when U2F register operation includes key >+// handles in exclude list. >+WEBCORE_EXPORT Optional<Vector<uint8_t>> convertToU2fCheckOnlySignCommand(const Vector<uint8_t>& clientDataHash, const WebCore::PublicKeyCredentialCreationOptions&, const WebCore::PublicKeyCredentialDescriptor&); >+ >+// Extracts APDU encoded U2F sign command from PublicKeyCredentialRequestOptions. >+WEBCORE_EXPORT Optional<Vector<uint8_t>> convertToU2fSignCommand(const Vector<uint8_t>& clientDataHash, const WebCore::PublicKeyCredentialRequestOptions&, const Vector<uint8_t>& keyHandle, bool checkOnly = false); >+ >+WEBCORE_EXPORT Vector<uint8_t> constructBogusU2fRegistrationCommand(); >+ >+} // namespace fido >+ >+#endif // ENABLE(WEB_AUTHN) >diff --git a/Source/WebCore/Modules/webauthn/fido/U2fResponseConverter.cpp b/Source/WebCore/Modules/webauthn/fido/U2fResponseConverter.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..c45a1711799021356ba785cef16c28a91a301be0 >--- /dev/null >+++ b/Source/WebCore/Modules/webauthn/fido/U2fResponseConverter.cpp >@@ -0,0 +1,194 @@ >+// Copyright 2018 The Chromium Authors. All rights reserved. >+// Copyright (C) 2019 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" >+#include "U2fResponseConverter.h" >+ >+#if ENABLE(WEB_AUTHN) >+ >+#include "CommonCryptoDERUtilities.h" >+#include "FidoConstants.h" >+#include "WebAuthenticationConstants.h" >+#include "WebAuthenticationUtils.h" >+ >+namespace fido { >+using namespace WebCore; >+ >+namespace { >+ >+// In a U2F registration response, the key is in X9.62 format: >+// - a constant 0x04 prefix to indicate an uncompressed key >+// - the 32-byte x coordinate >+// - the 32-byte y coordinate. >+const uint8_t uncompressedKey = 0x04; >+// https://www.w3.org/TR/webauthn/#flags >+const uint8_t makeCredentialFlags = 0b01000001; // UP and AT are set. >+// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#registration-response-message-success >+const uint8_t minSignatureLength = 71; >+const uint8_t maxSignatureLength = 73; >+// https://fidoalliance.org/specs/fido-u2f-v1.2-ps-20170411/fido-u2f-raw-message-formats-v1.2-ps-20170411.html#authentication-response-message-success >+const size_t flagIndex = 0; >+const size_t counterIndex = 1; >+const size_t signatureIndex = 5; >+ >+static Vector<uint8_t> extractECPublicKeyFromU2fRegistrationResponse(const Vector<uint8_t>& u2fData) >+{ >+ size_t pos = kReservedLength; >+ if (u2fData.size() <= pos || u2fData[pos] != uncompressedKey) >+ return { }; >+ pos++; >+ >+ if (u2fData.size() < pos + 2 * ES256FieldElementLength) >+ return { }; >+ >+ Vector<uint8_t> x; >+ x.append(u2fData.data() + pos, ES256FieldElementLength); >+ pos += ES256FieldElementLength; >+ >+ Vector<uint8_t> y; >+ y.append(u2fData.data() + pos, ES256FieldElementLength); >+ >+ return encodeES256PublicKeyAsCBOR(WTFMove(x), WTFMove(y)); >+} >+ >+static Vector<uint8_t> extractCredentialIdFromU2fRegistrationResponse(const Vector<uint8_t>& u2fData) >+{ >+ size_t pos = kU2fKeyHandleLengthOffset; >+ if (u2fData.size() <= pos) >+ return { }; >+ size_t credentialIdLength = u2fData[pos]; >+ pos++; >+ >+ if (u2fData.size() < pos + credentialIdLength) >+ return { }; >+ Vector<uint8_t> credentialId; >+ credentialId.append(u2fData.data() + pos, credentialIdLength); >+ return credentialId; >+} >+ >+static Vector<uint8_t> createAttestedCredentialDataFromU2fRegisterResponse(const Vector<uint8_t>& u2fData, const Vector<uint8_t>& publicKey) >+{ >+ auto credentialId = extractCredentialIdFromU2fRegistrationResponse(u2fData); >+ if (credentialId.isEmpty()) >+ return { }; >+ >+ return buildAttestedCredentialData(Vector<uint8_t>(aaguidLength, 0), credentialId, publicKey); >+} >+ >+static size_t parseX509Length(const Vector<uint8_t>& u2fData, size_t offset) >+{ >+ if (u2fData.size() <= offset || u2fData[offset] != SequenceMark) >+ return 0; >+ offset++; >+ >+ if (u2fData.size() <= offset) >+ return 0; >+ const auto sequenceLengthLength = bytesUsedToEncodedLength(u2fData[offset]); >+ >+ if (sequenceLengthLength > sizeof(size_t) || (u2fData.size() < offset + sequenceLengthLength)) >+ return 0; >+ size_t sequenceLength = sequenceLengthLength == 1 ? u2fData[offset] : 0; >+ offset++; >+ for (auto i = sequenceLengthLength - 1; i; i--, offset++) >+ sequenceLength += u2fData[offset] << (i - 1) * 8; >+ >+ return sequenceLength + sequenceLengthLength + sizeof(SequenceMark); >+} >+ >+static cbor::CBORValue::MapValue createFidoAttestationStatementFromU2fRegisterResponse(const Vector<uint8_t>& u2fData, size_t offset) >+{ >+ auto x509Length = parseX509Length(u2fData, offset); >+ if (!x509Length || u2fData.size() < offset + x509Length) >+ return { }; >+ >+ Vector<uint8_t> x509; >+ x509.append(u2fData.data() + offset, x509Length); >+ offset += x509Length; >+ >+ Vector<uint8_t> signature; >+ signature.append(u2fData.data() + offset, u2fData.size() - offset); >+ if (signature.size() < minSignatureLength || signature.size() > maxSignatureLength) >+ return { }; >+ >+ cbor::CBORValue::MapValue attestationStatementMap; >+ attestationStatementMap[cbor::CBORValue("sig")] = cbor::CBORValue(WTFMove(signature)); >+ Vector<cbor::CBORValue> cborArray; >+ cborArray.append(cbor::CBORValue(WTFMove(x509))); >+ attestationStatementMap[cbor::CBORValue("x5c")] = cbor::CBORValue(WTFMove(cborArray)); >+ >+ return attestationStatementMap; >+} >+ >+} // namespace >+ >+Optional<PublicKeyCredentialData> readU2fRegisterResponse(const String& rpId, const Vector<uint8_t>& u2fData) >+{ >+ auto publicKey = extractECPublicKeyFromU2fRegistrationResponse(u2fData); >+ if (publicKey.isEmpty()) >+ return WTF::nullopt; >+ >+ auto attestedCredentialData = createAttestedCredentialDataFromU2fRegisterResponse(u2fData, publicKey); >+ if (attestedCredentialData.isEmpty()) >+ return WTF::nullopt; >+ >+ // Extract the credentialId for packing into the response data. >+ auto credentialId = extractCredentialIdFromU2fRegistrationResponse(u2fData); >+ ASSERT(!credentialId.isEmpty()); >+ >+ // The counter is zeroed out for Register requests. >+ auto authData = buildAuthData(rpId, makeCredentialFlags, 0, attestedCredentialData); >+ >+ auto fidoAttestationStatement = createFidoAttestationStatementFromU2fRegisterResponse(u2fData, kU2fKeyHandleOffset + credentialId.size()); >+ if (fidoAttestationStatement.empty()) >+ return WTF::nullopt; >+ >+ auto attestationObject = buildAttestationObject(WTFMove(authData), "fido-u2f", WTFMove(fidoAttestationStatement)); >+ >+ return PublicKeyCredentialData { ArrayBuffer::create(credentialId.data(), credentialId.size()), true, nullptr, ArrayBuffer::create(attestationObject.data(), attestationObject.size()), nullptr, nullptr, nullptr }; >+} >+ >+Optional<PublicKeyCredentialData> readFromU2fSignResponse(const String& rpId, const Vector<uint8_t>& keyHandle, const Vector<uint8_t>& u2fData) >+{ >+ if (keyHandle.isEmpty() || u2fData.size() <= signatureIndex) >+ return WTF::nullopt; >+ >+ // 1 byte flags, 4 bytes counter >+ auto flags = u2fData[flagIndex]; >+ uint32_t counter = u2fData[counterIndex] << 24; >+ counter += u2fData[counterIndex + 1] << 16; >+ counter += u2fData[counterIndex + 2] << 8; >+ counter += u2fData[counterIndex + 3]; >+ auto authData = buildAuthData(rpId, flags, counter, { }); >+ >+ return PublicKeyCredentialData { ArrayBuffer::create(keyHandle.data(), keyHandle.size()), false, nullptr, nullptr, ArrayBuffer::create(authData.data(), authData.size()), ArrayBuffer::create(u2fData.data() + signatureIndex, u2fData.size() - signatureIndex), nullptr }; >+} >+ >+} // namespace fido >+ >+#endif // ENABLE(WEB_AUTHN) >diff --git a/Source/WebCore/Modules/webauthn/fido/U2fResponseConverter.h b/Source/WebCore/Modules/webauthn/fido/U2fResponseConverter.h >new file mode 100644 >index 0000000000000000000000000000000000000000..d6a41f873d8bbc4f9a5a0f07e30d67f27df2abcc >--- /dev/null >+++ b/Source/WebCore/Modules/webauthn/fido/U2fResponseConverter.h >@@ -0,0 +1,49 @@ >+// Copyright 2018 The Chromium Authors. All rights reserved. >+// Copyright (C) 2019 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. >+ >+#pragma once >+ >+#if ENABLE(WEB_AUTHN) >+ >+#include "PublicKeyCredentialData.h" >+#include <wtf/Forward.h> >+ >+namespace fido { >+ >+// Converts a U2F register response to WebAuthN makeCredential response. >+// https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#u2f-authenticatorMakeCredential-interoperability >+WEBCORE_EXPORT Optional<WebCore::PublicKeyCredentialData> readU2fRegisterResponse(const String& rpId, const Vector<uint8_t>& u2fData); >+ >+// Converts a U2F authentication response to WebAuthN getAssertion response. >+// https://fidoalliance.org/specs/fido-v2.0-id-20180227/fido-client-to-authenticator-protocol-v2.0-id-20180227.html#u2f-authenticatorGetAssertion-interoperability >+WEBCORE_EXPORT Optional<WebCore::PublicKeyCredentialData> readFromU2fSignResponse(const String& rpId, const Vector<uint8_t>& keyHandle, const Vector<uint8_t>& u2fData); >+ >+} // namespace fido >+ >+#endif // ENABLE(WEB_AUTHN) >diff --git a/Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.cpp b/Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.cpp >index dbb803be27321b9be6cdf59d911afbc033842942..04de7d2a62b7ec3d15981c609628e553e33a8b54 100644 >--- a/Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.cpp >+++ b/Source/WebCore/Modules/webgpu/WebGPUCommandBuffer.cpp >@@ -31,6 +31,7 @@ > #include "GPUCommandBuffer.h" > #include "GPURenderPassDescriptor.h" > #include "GPURenderPassEncoder.h" >+#include "GPURenderPipeline.h" > #include "Logging.h" > #include "WebGPURenderPassDescriptor.h" > #include "WebGPURenderPassEncoder.h" >diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt >index e7d934ad27f1bfa91231e1d86df0b7419d838b90..ea295789c5bfc88181a14f325057bac045af8698 100644 >--- a/Source/WebCore/Sources.txt >+++ b/Source/WebCore/Sources.txt >@@ -256,6 +256,7 @@ Modules/webaudio/WaveShaperProcessor.cpp > Modules/webauthn/AuthenticatorCoordinator.cpp > Modules/webauthn/AuthenticatorCoordinatorClient.cpp > Modules/webauthn/PublicKeyCredential.cpp >+Modules/webauthn/WebAuthenticationUtils.cpp > Modules/webauthn/apdu/ApduCommand.cpp > Modules/webauthn/apdu/ApduResponse.cpp > Modules/webauthn/cbor/CBORReader.cpp >@@ -269,6 +270,8 @@ Modules/webauthn/fido/FidoConstants.cpp > Modules/webauthn/fido/FidoHidMessage.cpp > Modules/webauthn/fido/FidoHidPacket.cpp > Modules/webauthn/fido/FidoParsingUtils.cpp >+Modules/webauthn/fido/U2fCommandConstructor.cpp >+Modules/webauthn/fido/U2fResponseConverter.cpp > > Modules/webdatabase/ChangeVersionWrapper.cpp > Modules/webdatabase/DOMWindowWebDatabase.cpp >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index de452c062a6ba26f47327077fc1f99acfcfd8ceb..d917b580c03848f64765ce7e886847a71e1b1208 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -1783,6 +1783,9 @@ > 571252691E524EB1008FF369 /* CryptoAlgorithmAES_CFB.h in Headers */ = {isa = PBXBuildFile; fileRef = 571252681E524EB1008FF369 /* CryptoAlgorithmAES_CFB.h */; }; > 57152B5A21CB3E88000C37CA /* ApduCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 57152B5821CB2E3B000C37CA /* ApduCommand.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 57152B5C21CC1902000C37CA /* ApduResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 57152B5621CB2E3A000C37CA /* ApduResponse.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 57152B6E21CD995D000C37CA /* U2fCommandConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 57152B6C21CD995C000C37CA /* U2fCommandConstructor.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 57152B7C21DD8BA1000C37CA /* U2fResponseConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = 57152B7A21DD8BA1000C37CA /* U2fResponseConverter.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 57152B8021DDA581000C37CA /* WebAuthenticationUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 57152B7E21DDA581000C37CA /* WebAuthenticationUtils.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 571F21891DA57C54005C9EFD /* JSSubtleCrypto.h in Headers */ = {isa = PBXBuildFile; fileRef = 571F21881DA57C54005C9EFD /* JSSubtleCrypto.h */; }; > 572093D31DDCEB9A00310AB0 /* CryptoAlgorithmAesCbcCfbParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 572093D21DDCEB9A00310AB0 /* CryptoAlgorithmAesCbcCfbParams.h */; }; > 5721A9871ECE53B10081295A /* CryptoDigestAlgorithm.h in Headers */ = {isa = PBXBuildFile; fileRef = 5721A9861ECE53B10081295A /* CryptoDigestAlgorithm.h */; }; >@@ -1816,8 +1819,8 @@ > 573489391DAC6B6E00DC0667 /* CryptoAlgorithmParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 573489381DAC6B6D00DC0667 /* CryptoAlgorithmParameters.h */; }; > 5739E12F1DAC7F7800E14383 /* JSCryptoAlgorithmParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 5739E12E1DAC7F7800E14383 /* JSCryptoAlgorithmParameters.h */; }; > 573F5332216806E10045587A /* FidoHidMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 57BAF28A2167D303008E954E /* FidoHidMessage.h */; settings = {ATTRIBUTES = (Private, ); }; }; >- 573F533721680D150045587A /* FidoParsingUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 573F533521680D140045587A /* FidoParsingUtils.h */; }; >- 574F55E1204F3B23002948C6 /* COSEConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 574F55DC204F3732002948C6 /* COSEConstants.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 573F533721680D150045587A /* FidoParsingUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 573F533521680D140045587A /* FidoParsingUtils.h */; settings = {ATTRIBUTES = (Private, ); }; }; >+ 574F55E1204F3B23002948C6 /* WebAuthenticationConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = 574F55DC204F3732002948C6 /* WebAuthenticationConstants.h */; settings = {ATTRIBUTES = (Private, ); }; }; > 5750A9751E68D00000705C4A /* CryptoKeyEC.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A9731E68D00000705C4A /* CryptoKeyEC.h */; }; > 5750A97E1E6A13EF00705C4A /* CryptoAlgorithmEcKeyParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A97D1E6A13EF00705C4A /* CryptoAlgorithmEcKeyParams.h */; }; > 5750A9821E6A150800705C4A /* JSEcKeyParams.h in Headers */ = {isa = PBXBuildFile; fileRef = 5750A9801E6A150800705C4A /* JSEcKeyParams.h */; }; >@@ -8592,6 +8595,12 @@ > 57152B5621CB2E3A000C37CA /* ApduResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ApduResponse.h; path = Modules/webauthn/apdu/ApduResponse.h; sourceTree = SOURCE_ROOT; }; > 57152B5721CB2E3A000C37CA /* ApduCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ApduCommand.cpp; path = Modules/webauthn/apdu/ApduCommand.cpp; sourceTree = SOURCE_ROOT; }; > 57152B5821CB2E3B000C37CA /* ApduCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ApduCommand.h; path = Modules/webauthn/apdu/ApduCommand.h; sourceTree = SOURCE_ROOT; }; >+ 57152B6A21CD995C000C37CA /* U2fCommandConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = U2fCommandConstructor.cpp; sourceTree = "<group>"; }; >+ 57152B6C21CD995C000C37CA /* U2fCommandConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = U2fCommandConstructor.h; sourceTree = "<group>"; }; >+ 57152B7A21DD8BA1000C37CA /* U2fResponseConverter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = U2fResponseConverter.h; sourceTree = "<group>"; }; >+ 57152B7B21DD8BA1000C37CA /* U2fResponseConverter.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = U2fResponseConverter.cpp; sourceTree = "<group>"; }; >+ 57152B7E21DDA581000C37CA /* WebAuthenticationUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebAuthenticationUtils.h; sourceTree = "<group>"; }; >+ 57152B7F21DDA581000C37CA /* WebAuthenticationUtils.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebAuthenticationUtils.cpp; sourceTree = "<group>"; }; > 571F21881DA57C54005C9EFD /* JSSubtleCrypto.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSubtleCrypto.h; sourceTree = "<group>"; }; > 571F218A1DA57C7A005C9EFD /* JSSubtleCrypto.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSubtleCrypto.cpp; sourceTree = "<group>"; }; > 572093D11DDCEA4B00310AB0 /* AesCbcCfbParams.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = AesCbcCfbParams.idl; sourceTree = "<group>"; }; >@@ -8658,7 +8667,7 @@ > 573F533621680D150045587A /* FidoParsingUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FidoParsingUtils.cpp; sourceTree = "<group>"; }; > 574AC7531DAC367D00E9744C /* CryptoAlgorithmParameters.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CryptoAlgorithmParameters.idl; sourceTree = "<group>"; }; > 574D42791D594FF6002CF50E /* GlobalCrypto.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GlobalCrypto.idl; sourceTree = "<group>"; }; >- 574F55DC204F3732002948C6 /* COSEConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = COSEConstants.h; sourceTree = "<group>"; }; >+ 574F55DC204F3732002948C6 /* WebAuthenticationConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebAuthenticationConstants.h; sourceTree = "<group>"; }; > 574F55E2204F3CBF002948C6 /* LocalAuthentication.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LocalAuthentication.framework; path = System/Library/Frameworks/LocalAuthentication.framework; sourceTree = SDKROOT; }; > 5750A9721E68D00000705C4A /* CryptoKeyEC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CryptoKeyEC.cpp; sourceTree = "<group>"; }; > 5750A9731E68D00000705C4A /* CryptoKeyEC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CryptoKeyEC.h; sourceTree = "<group>"; }; >@@ -19320,6 +19329,10 @@ > 578A4C0A2167D29600D08F34 /* FidoHidPacket.h */, > 573F533621680D150045587A /* FidoParsingUtils.cpp */, > 573F533521680D140045587A /* FidoParsingUtils.h */, >+ 57152B6A21CD995C000C37CA /* U2fCommandConstructor.cpp */, >+ 57152B6C21CD995C000C37CA /* U2fCommandConstructor.h */, >+ 57152B7B21DD8BA1000C37CA /* U2fResponseConverter.cpp */, >+ 57152B7A21DD8BA1000C37CA /* U2fResponseConverter.h */, > ); > path = fido; > sourceTree = "<group>"; >@@ -19379,7 +19392,6 @@ > 57303BD120087A8300355965 /* AuthenticatorResponse.idl */, > 57DCED8C21487EDB0016B847 /* AuthenticatorTransport.h */, > 57DCED8E21487EDB0016B847 /* AuthenticatorTransport.idl */, >- 574F55DC204F3732002948C6 /* COSEConstants.h */, > 57D8462C1FEAF68F00CA3682 /* PublicKeyCredential.cpp */, > 57D8462B1FEAF68F00CA3682 /* PublicKeyCredential.h */, > 57D8462D1FEAF68F00CA3682 /* PublicKeyCredential.idl */, >@@ -19394,6 +19406,9 @@ > 57303BF02009846100355965 /* PublicKeyCredentialType.idl */, > 572B402321768D85000AD43E /* UserVerificationRequirement.h */, > 572B402521768D85000AD43E /* UserVerificationRequirement.idl */, >+ 574F55DC204F3732002948C6 /* WebAuthenticationConstants.h */, >+ 57152B7F21DDA581000C37CA /* WebAuthenticationUtils.cpp */, >+ 57152B7E21DDA581000C37CA /* WebAuthenticationUtils.h */, > ); > path = webauthn; > sourceTree = "<group>"; >@@ -28246,7 +28261,6 @@ > 3F8020371E9E47C500DEC61D /* CoreAudioCaptureDeviceManager.h in Headers */, > 07AFF4221EFB144900B545B3 /* CoreAudioCaptureSourceIOS.h in Headers */, > CD7D33481C7A16BF00041293 /* CoreVideoSoftLink.h in Headers */, >- 574F55E1204F3B23002948C6 /* COSEConstants.h in Headers */, > 862F129E18C1576F005C54AF /* CountedUserActivity.h in Headers */, > A80E6D040A1989CA007FB8C5 /* Counter.h in Headers */, > BC5EB9790E82069200B25965 /* CounterContent.h in Headers */, >@@ -31630,6 +31644,8 @@ > 4BAFD0E1219242A000C0AB64 /* TypedOMCSSUnitValue.h in Headers */, > 4BAFD0D921921EA000C0AB64 /* TypedOMCSSUnparsedValue.h in Headers */, > 93309E1A099E64920056E581 /* TypingCommand.h in Headers */, >+ 57152B6E21CD995D000C37CA /* U2fCommandConstructor.h in Headers */, >+ 57152B7C21DD8BA1000C37CA /* U2fResponseConverter.h in Headers */, > 85031B4E0A44EFC700F992E0 /* UIEvent.h in Headers */, > 83FE7CA71DA9F1A70037237C /* UIEventInit.h in Headers */, > 85031B4F0A44EFC700F992E0 /* UIEventWithKeyState.h in Headers */, >@@ -31736,6 +31752,8 @@ > 417F7AEE2139BF6800FBA7EC /* WebAudioBufferList.h in Headers */, > 41B2A6261EF1BF6D002B9D7A /* WebAudioSourceProvider.h in Headers */, > 07D637401BB0B11300256CE9 /* WebAudioSourceProviderAVFObjC.h in Headers */, >+ 574F55E1204F3B23002948C6 /* WebAuthenticationConstants.h in Headers */, >+ 57152B8021DDA581000C37CA /* WebAuthenticationUtils.h in Headers */, > 1F36EA9C1E21BA1700621E25 /* WebBackgroundTaskController.h in Headers */, > A5B81CB51FAA44620037D1E6 /* WebConsoleAgent.h in Headers */, > 9BBA2CAB1F679E0C00FD1C1E /* WebContentReader.h in Headers */, >diff --git a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm >index 0257c0d8a6bb229049f314be01dc9498d71825f4..efc3e160b48bc6e3b7dae544a522347c978b9328 100644 >--- a/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm >+++ b/Source/WebKit/UIProcess/WebAuthentication/Cocoa/LocalAuthenticator.mm >@@ -30,11 +30,12 @@ > > #import <Security/SecItem.h> > #import <WebCore/CBORWriter.h> >-#import <WebCore/COSEConstants.h> > #import <WebCore/ExceptionData.h> > #import <WebCore/PublicKeyCredentialCreationOptions.h> > #import <WebCore/PublicKeyCredentialData.h> > #import <WebCore/PublicKeyCredentialRequestOptions.h> >+#import <WebCore/WebAuthenticationConstants.h> >+#import <WebCore/WebAuthenticationUtils.h> > #import <pal/crypto/CryptoDigest.h> > #import <wtf/HashSet.h> > #import <wtf/RetainPtr.h> >@@ -50,50 +51,10 @@ namespace LocalAuthenticatorInternal { > // See https://www.w3.org/TR/webauthn/#flags. > const uint8_t makeCredentialFlags = 0b01000101; // UP, UV and AT are set. > const uint8_t getAssertionFlags = 0b00000101; // UP and UV are set. >-// FIXME(rdar://problem/38320512): Define Apple AAGUID. >-const uint8_t AAGUID[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // 16 bytes > // Credential ID is currently SHA-1 of the corresponding public key. >-// FIXME(183534): Assume little endian here. >-const union { >- uint16_t integer; >- uint8_t bytes[2]; >-} credentialIdLength = {0x0014}; >-const size_t ES256KeySizeInBytes = 32; >-const size_t authDataPrefixFixedSize = 37; // hash(32) + flags(1) + counter(4) >+const uint16_t credentialIdLength = 20; > > #if PLATFORM(IOS_FAMILY) >-// https://www.w3.org/TR/webauthn/#sec-authenticator-data >-static Vector<uint8_t> buildAuthData(const String& rpId, const uint8_t flags, uint32_t counter, const Vector<uint8_t>& optionalAttestedCredentialData) >-{ >- Vector<uint8_t> authData; >- authData.reserveInitialCapacity(authDataPrefixFixedSize + optionalAttestedCredentialData.size()); >- >- // RP ID hash >- auto crypto = PAL::CryptoDigest::create(PAL::CryptoDigest::Algorithm::SHA_256); >- // FIXME(183534): Test IDN. >- ASSERT(rpId.isAllASCII()); >- auto asciiRpId = rpId.ascii(); >- crypto->addBytes(asciiRpId.data(), asciiRpId.length()); >- authData = crypto->computeHash(); >- >- // FLAGS >- authData.append(flags); >- >- // COUNTER >- // FIXME(183534): Assume little endian here. >- union { >- uint32_t integer; >- uint8_t bytes[4]; >- } counterUnion; >- counterUnion.integer = counter; >- authData.append(counterUnion.bytes, sizeof(counterUnion.bytes)); >- >- // ATTESTED CRED. DATA >- authData.appendVector(optionalAttestedCredentialData); >- >- return authData; >-} >- > static inline bool emptyTransportsOrContain(const Vector<AuthenticatorTransport>& transports, AuthenticatorTransport target) > { > return transports.isEmpty() ? true : transports.contains(target); >@@ -105,7 +66,7 @@ static inline HashSet<String> produceHashSet(const Vector<PublicKeyCredentialDes > for (auto& credentialDescriptor : credentialDescriptors) { > if (emptyTransportsOrContain(credentialDescriptor.transports, AuthenticatorTransport::Internal) > && credentialDescriptor.type == PublicKeyCredentialType::PublicKey >- && credentialDescriptor.idVector.size() == credentialIdLength.integer) >+ && credentialDescriptor.idVector.size() == credentialIdLength) > result.add(String(reinterpret_cast<const char*>(credentialDescriptor.idVector.data()), credentialDescriptor.idVector.size())); > } > return result; >@@ -307,22 +268,10 @@ void LocalAuthenticator::continueMakeCredentialAfterAttested(SecKeyRef privateKe > // FIXME(183533): store the counter. > uint32_t counter = 0; > >- // FIXME(183534): attestedCredentialData could throttle. > // Step 11. https://www.w3.org/TR/webauthn/#attested-credential-data >- Vector<uint8_t> attestedCredentialData; >+ // credentialPublicKey >+ Vector<uint8_t> cosePublicKey; > { >- // aaguid >- attestedCredentialData.append(AAGUID, sizeof(AAGUID)); >- >- // credentialIdLength >- ASSERT(credentialId.size() == credentialIdLength.integer); >- // FIXME(183534): Assume little endian here. >- attestedCredentialData.append(credentialIdLength.bytes, sizeof(uint16_t)); >- >- // credentialId >- attestedCredentialData.appendVector(credentialId); >- >- // credentialPublicKey > RetainPtr<CFDataRef> publicKeyDataRef; > { > auto publicKey = adoptCF(SecKeyCopyPublicKey(privateKey)); >@@ -334,29 +283,18 @@ void LocalAuthenticator::continueMakeCredentialAfterAttested(SecKeyRef privateKe > receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s }); > return; > } >- ASSERT(((NSData *)publicKeyDataRef.get()).length == (1 + 2 * ES256KeySizeInBytes)); // 04 | X | Y >+ ASSERT(((NSData *)publicKeyDataRef.get()).length == (1 + 2 * ES256FieldElementLength)); // 04 | X | Y > } > > // COSE Encoding >- // FIXME(183535): Improve CBOR encoder to work with bytes directly. >- Vector<uint8_t> x(ES256KeySizeInBytes); >- [(NSData *)publicKeyDataRef.get() getBytes: x.data() range:NSMakeRange(1, ES256KeySizeInBytes)]; >- Vector<uint8_t> y(ES256KeySizeInBytes); >- [(NSData *)publicKeyDataRef.get() getBytes: y.data() range:NSMakeRange(1 + ES256KeySizeInBytes, ES256KeySizeInBytes)]; >- cbor::CBORValue::MapValue publicKeyMap; >- publicKeyMap[cbor::CBORValue(COSE::kty)] = cbor::CBORValue(COSE::EC2); >- publicKeyMap[cbor::CBORValue(COSE::alg)] = cbor::CBORValue(COSE::ES256); >- publicKeyMap[cbor::CBORValue(COSE::crv)] = cbor::CBORValue(COSE::P_256); >- publicKeyMap[cbor::CBORValue(COSE::x)] = cbor::CBORValue(WTFMove(x)); >- publicKeyMap[cbor::CBORValue(COSE::y)] = cbor::CBORValue(WTFMove(y)); >- auto cosePublicKey = cbor::CBORWriter::write(cbor::CBORValue(WTFMove(publicKeyMap))); >- if (!cosePublicKey) { >- LOG_ERROR("Couldn't encode the public key into COSE binaries."); >- receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s }); >- return; >- } >- attestedCredentialData.appendVector(cosePublicKey.value()); >+ Vector<uint8_t> x(ES256FieldElementLength); >+ [(NSData *)publicKeyDataRef.get() getBytes: x.data() range:NSMakeRange(1, ES256FieldElementLength)]; >+ Vector<uint8_t> y(ES256FieldElementLength); >+ [(NSData *)publicKeyDataRef.get() getBytes: y.data() range:NSMakeRange(1 + ES256FieldElementLength, ES256FieldElementLength)]; >+ cosePublicKey = encodeES256PublicKeyAsCBOR(WTFMove(x), WTFMove(y)); > } >+ // FIXME(rdar://problem/38320512): Define Apple AAGUID. >+ auto attestedCredentialData = buildAttestedCredentialData(Vector<uint8_t>(aaguidLength, 0), credentialId, cosePublicKey); > > // Step 12. > auto authData = buildAuthData(requestData().creationOptions.rp.id, makeCredentialFlags, counter, attestedCredentialData); >@@ -386,19 +324,9 @@ void LocalAuthenticator::continueMakeCredentialAfterAttested(SecKeyRef privateKe > cborArray.append(cbor::CBORValue(toVector((NSData *)adoptCF(SecCertificateCopyData((__bridge SecCertificateRef)certificates[i])).get()))); > attestationStatementMap[cbor::CBORValue("x5c")] = cbor::CBORValue(WTFMove(cborArray)); > } >+ auto attestationObject = buildAttestationObject(WTFMove(authData), "Apple", WTFMove(attestationStatementMap)); > >- cbor::CBORValue::MapValue attestationObjectMap; >- attestationObjectMap[cbor::CBORValue("authData")] = cbor::CBORValue(authData); >- attestationObjectMap[cbor::CBORValue("fmt")] = cbor::CBORValue("Apple"); >- attestationObjectMap[cbor::CBORValue("attStmt")] = cbor::CBORValue(WTFMove(attestationStatementMap)); >- auto attestationObject = cbor::CBORWriter::write(cbor::CBORValue(WTFMove(attestationObjectMap))); >- if (!attestationObject) { >- LOG_ERROR("Couldn't encode the attestation object."); >- receiveRespond(ExceptionData { UnknownError, "Unknown internal error."_s }); >- return; >- } >- >- receiveRespond(PublicKeyCredentialData { ArrayBuffer::create(credentialId.data(), credentialId.size()), true, nullptr, ArrayBuffer::create(attestationObject.value().data(), attestationObject.value().size()), nullptr, nullptr, nullptr }); >+ receiveRespond(PublicKeyCredentialData { ArrayBuffer::create(credentialId.data(), credentialId.size()), true, nullptr, ArrayBuffer::create(attestationObject.data(), attestationObject.size()), nullptr, nullptr, nullptr }); > #endif // !PLATFORM(IOS_FAMILY) > } > >diff --git a/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp b/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp >index b7fc80862581a99f5196a712c57a4fc0ca19a2c3..0b17699bdde9784b4c7863d9d7be9245465f2a64 100644 >--- a/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp >+++ b/Source/WebKit/UIProcess/WebAuthentication/Mock/MockHidConnection.cpp >@@ -31,6 +31,7 @@ > #include <WebCore/AuthenticatorGetInfoResponse.h> > #include <WebCore/CBORReader.h> > #include <WebCore/FidoConstants.h> >+#include <WebCore/WebAuthenticationConstants.h> > #include <wtf/BlockPtr.h> > #include <wtf/CryptographicallyRandomNumber.h> > #include <wtf/RunLoop.h> >@@ -202,7 +203,7 @@ void MockHidConnection::feedReports() > > Optional<FidoHidMessage> message; > if (m_stage == Mock::Stage::Info && m_subStage == Mock::SubStage::Msg) { >- auto infoData = encodeAsCBOR(AuthenticatorGetInfoResponse({ ProtocolVersion::kCtap }, Vector<uint8_t>(kAaguidLength, 0u))); >+ auto infoData = encodeAsCBOR(AuthenticatorGetInfoResponse({ ProtocolVersion::kCtap }, Vector<uint8_t>(aaguidLength, 0u))); > infoData.insert(0, static_cast<uint8_t>(CtapDeviceResponseCode::kSuccess)); // Prepend status code. > if (stagesMatch() && m_configuration.hid->error == Mock::Error::WrongChannelId) > message = FidoHidMessage::create(m_currentChannel - 1, FidoHidDeviceCommand::kCbor, infoData); >diff --git a/Tools/ChangeLog b/Tools/ChangeLog >index 09e26b9dce86ab08d1713043dd658433e3806307..17d7c1850c7f1e34f94aaca32f5457e79055ab0c 100644 >--- a/Tools/ChangeLog >+++ b/Tools/ChangeLog >@@ -1,3 +1,28 @@ >+2019-01-04 Jiewen Tan <jiewen_tan@apple.com> >+ >+ [WebAuthN] Import U2F command/response converters from Chromium >+ https://bugs.webkit.org/show_bug.cgi?id=193150 >+ <rdar://problem/47054028> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Adds API tests. >+ >+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: >+ * TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp: >+ (TestWebKitAPI::getTestAttestedCredentialDataBytes): >+ (TestWebKitAPI::getTestAuthenticatorDataBytes): >+ (TestWebKitAPI::getTestAttestationObjectBytes): >+ (TestWebKitAPI::getTestSignResponse): >+ (TestWebKitAPI::getTestU2fRegisterResponse): >+ (TestWebKitAPI::TEST): >+ (TestWebKitAPI::convertToVector): Deleted. >+ * TestWebKitAPI/Tests/WebCore/FidoTestData.h: >+ * TestWebKitAPI/Tests/WebCore/U2fCommandConstructorTest.cpp: Added. >+ (TestWebKitAPI::constructMakeCredentialRequest): >+ (TestWebKitAPI::constructGetAssertionRequest): >+ (TestWebKitAPI::TEST): >+ > 2018-12-21 Jiewen Tan <jiewen_tan@apple.com> > > [WebAuthN] userPresence should always be true >diff --git a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >index 2314328fed4ea1119fe35d1a59cf54dcaeee9227..f8af61a3693dbc9e5990183931aebdae835cfda8 100644 >--- a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >+++ b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj >@@ -258,6 +258,7 @@ > 5714ECBB1CA8BFE400051AC8 /* DownloadRequestOriginalURLFrame.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5714ECBA1CA8BFD100051AC8 /* DownloadRequestOriginalURLFrame.html */; }; > 5714ECBD1CA8C22A00051AC8 /* DownloadRequestOriginalURL2.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 5714ECBC1CA8C21800051AC8 /* DownloadRequestOriginalURL2.html */; }; > 57152B5E21CC2045000C37CA /* ApduTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57152B5D21CC2045000C37CA /* ApduTest.cpp */; }; >+ 57152B7821DD4E8D000C37CA /* U2fCommandConstructorTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 57D1D75E21DCB7A80093E86A /* U2fCommandConstructorTest.cpp */; }; > 571F7FD01F2961FB00946648 /* IndexedDBStructuredCloneBackwardCompatibility.sqlite3-wal in Copy Resources */ = {isa = PBXBuildFile; fileRef = 571F7FCF1F2961E100946648 /* IndexedDBStructuredCloneBackwardCompatibility.sqlite3-wal */; }; > 572B403421769A88000AD43E /* CtapRequestTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 572B403321769A88000AD43E /* CtapRequestTest.cpp */; }; > 572B404421781B43000AD43E /* CtapResponseTest.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 572B404321781B42000AD43E /* CtapResponseTest.cpp */; }; >@@ -1629,6 +1630,7 @@ > 5797FE2F1EB15A5F00B2F4A0 /* NavigationClientDefaultCrypto.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NavigationClientDefaultCrypto.cpp; sourceTree = "<group>"; }; > 5797FE321EB15A8900B2F4A0 /* navigation-client-default-crypto.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "navigation-client-default-crypto.html"; sourceTree = "<group>"; }; > 5798E2AF1CAF5C2800C5CBA0 /* ProvisionalURLNotChange.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ProvisionalURLNotChange.mm; sourceTree = "<group>"; }; >+ 57D1D75E21DCB7A80093E86A /* U2fCommandConstructorTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = U2fCommandConstructorTest.cpp; sourceTree = "<group>"; }; > 57F10D921C7E7B3800ECDF30 /* IsNavigationActionTrusted.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = IsNavigationActionTrusted.mm; sourceTree = "<group>"; }; > 57F4AA9F208FA83D00A68E9E /* SSLKeyGenerator.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = SSLKeyGenerator.mm; sourceTree = "<group>"; }; > 57F56A5B1C7F8A4000F31D7E /* IsNavigationActionTrusted.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = IsNavigationActionTrusted.html; sourceTree = "<group>"; }; >@@ -2668,6 +2670,7 @@ > 93A258981F92FF15003E510C /* TextCodec.cpp */, > CDC2C7141797089D00E627FB /* TimeRanges.cpp */, > 7AD3FE8D1D75FB8D00B169A4 /* TransformationMatrix.cpp */, >+ 57D1D75E21DCB7A80093E86A /* U2fCommandConstructorTest.cpp */, > E3A1E77E21B25B39008C6007 /* URLParserTextEncoding.cpp */, > 9C64DC311D76198A004B598E /* YouTubePluginReplacement.cpp */, > ); >@@ -4180,6 +4183,7 @@ > CE3524F91B1441C40028A7C5 /* TextFieldDidBeginAndEndEditing.cpp in Sources */, > 7CCE7EDD1A411A9200447C4C /* TimeRanges.cpp in Sources */, > 7CCE7ED31A411A7E00447C4C /* TypingStyleCrash.mm in Sources */, >+ 57152B7821DD4E8D000C37CA /* U2fCommandConstructorTest.cpp in Sources */, > 5CB40B4E1F4B98D3007DC7B9 /* UIDelegate.mm in Sources */, > F46849BE1EEF58E400B937FE /* UIPasteboardTests.mm in Sources */, > E3A1E77F21B25B39008C6007 /* URLParserTextEncoding.cpp in Sources */, >diff --git a/Tools/TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp b/Tools/TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp >index 5aaa05da2012005ad6e55e9ca212b581522de982..de3f209293309c4bbc2320086b4aaf960dec4b8a 100644 >--- a/Tools/TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp >+++ b/Tools/TestWebKitAPI/Tests/WebCore/CtapResponseTest.cpp >@@ -37,8 +37,11 @@ > #include <WebCore/CBORWriter.h> > #include <WebCore/DeviceResponseConverter.h> > #include <WebCore/FidoConstants.h> >+#include <WebCore/U2fResponseConverter.h> >+#include <WebCore/WebAuthenticationUtils.h> > > namespace TestWebKitAPI { >+using namespace WebCore; > using namespace fido; > > constexpr uint8_t kTestAuthenticatorGetInfoResponseWithNoVersion[] = { >@@ -216,10 +219,107 @@ constexpr uint8_t kTestAuthenticatorGetInfoResponseWithIncorrectAaguid[] = { > 0x81, 0x01, > }; > >+// The attested credential data, excluding the public key bytes. Append >+// with kTestECPublicKeyCOSE to get the complete attestation data. >+constexpr uint8_t kTestAttestedCredentialDataPrefix[] = { >+ // 16-byte aaguid >+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, >+ 0x00, 0x00, 0x00, 0x00, >+ // 2-byte length >+ 0x00, 0x40, >+ // 64-byte key handle >+ 0x3E, 0xBD, 0x89, 0xBF, 0x77, 0xEC, 0x50, 0x97, 0x55, 0xEE, 0x9C, 0x26, >+ 0x35, 0xEF, 0xAA, 0xAC, 0x7B, 0x2B, 0x9C, 0x5C, 0xEF, 0x17, 0x36, 0xC3, >+ 0x71, 0x7D, 0xA4, 0x85, 0x34, 0xC8, 0xC6, 0xB6, 0x54, 0xD7, 0xFF, 0x94, >+ 0x5F, 0x50, 0xB5, 0xCC, 0x4E, 0x78, 0x05, 0x5B, 0xDD, 0x39, 0x6B, 0x64, >+ 0xF7, 0x8D, 0xA2, 0xC5, 0xF9, 0x62, 0x00, 0xCC, 0xD4, 0x15, 0xCD, 0x08, >+ 0xFE, 0x42, 0x00, 0x38, >+}; >+ >+// The authenticator data, excluding the attested credential data bytes. Append >+// with attested credential data to get the complete authenticator data. >+constexpr uint8_t kTestAuthenticatorDataPrefix[] = { >+ // sha256 hash of rp id. >+ 0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7, >+ 0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF, >+ 0x01, 0x3D, 0xE9, 0x6D, 0x4E, 0xFB, 0x17, 0xDE, >+ // flags (TUP and AT bits set) >+ 0x41, >+ // counter >+ 0x00, 0x00, 0x00, 0x00 >+}; >+ >+// Components of the CBOR needed to form an authenticator object. >+// Combined diagnostic notation: >+// {"fmt": "fido-u2f", "attStmt": {"sig": h'30...}, "authData": h'D4C9D9...'} >+constexpr uint8_t kFormatFidoU2fCBOR[] = { >+ // map(3) >+ 0xA3, >+ // text(3) >+ 0x63, >+ // "fmt" >+ 0x66, 0x6D, 0x74, >+ // text(8) >+ 0x68, >+ // "fido-u2f" >+ 0x66, 0x69, 0x64, 0x6F, 0x2D, 0x75, 0x32, 0x66 >+}; >+ >+constexpr uint8_t kAttStmtCBOR[] = { >+ // text(7) >+ 0x67, >+ // "attStmt" >+ 0x61, 0x74, 0x74, 0x53, 0x74, 0x6D, 0x74 >+}; >+ >+constexpr uint8_t kAuthDataCBOR[] = { >+ // text(8) >+ 0x68, >+ // "authData" >+ 0x61, 0x75, 0x74, 0x68, 0x44, 0x61, 0x74, 0x61, >+ // bytes(196). i.e., the authenticator_data byte array corresponding to >+ // kTestAuthenticatorDataPrefix|, |kTestAttestedCredentialDataPrefix|, >+ // and test_data::kTestECPublicKeyCOSE. >+ 0x58, 0xC4 >+}; >+ > constexpr uint8_t kTestDeviceAaguid[] = { > 0xF8, 0xA0, 0x11, 0xF3, 0x8C, 0x0A, 0x4D, 0x15, 0x80, 0x06, 0x17, 0x11, 0x1F, 0x9E, 0xDC, 0x7D > }; > >+Vector<uint8_t> getTestAttestedCredentialDataBytes() >+{ >+ // Combine kTestAttestedCredentialDataPrefix and kTestECPublicKeyCOSE. >+ auto testAttestedData = convertBytesToVector(kTestAttestedCredentialDataPrefix, sizeof(kTestAttestedCredentialDataPrefix)); >+ testAttestedData.append(TestData::kTestECPublicKeyCOSE, sizeof(TestData::kTestECPublicKeyCOSE)); >+ return testAttestedData; >+} >+ >+Vector<uint8_t> getTestAuthenticatorDataBytes() >+{ >+ // Build the test authenticator data. >+ auto testAuthenticatorData = convertBytesToVector(kTestAuthenticatorDataPrefix, sizeof(kTestAuthenticatorDataPrefix)); >+ auto testAttestedData = getTestAttestedCredentialDataBytes(); >+ testAuthenticatorData.appendVector(testAttestedData); >+ return testAuthenticatorData; >+} >+ >+Vector<uint8_t> getTestAttestationObjectBytes() >+{ >+ auto testAuthenticatorObject = convertBytesToVector(kFormatFidoU2fCBOR, sizeof(kFormatFidoU2fCBOR)); >+ testAuthenticatorObject.append(kAttStmtCBOR, sizeof(kAttStmtCBOR)); >+ testAuthenticatorObject.append(TestData::kU2fAttestationStatementCBOR, sizeof(TestData::kU2fAttestationStatementCBOR)); >+ testAuthenticatorObject.append(kAuthDataCBOR, sizeof(kAuthDataCBOR)); >+ auto testAuthenticatorData = getTestAuthenticatorDataBytes(); >+ testAuthenticatorObject.appendVector(testAuthenticatorData); >+ return testAuthenticatorObject; >+} >+ >+Vector<uint8_t> getTestSignResponse() >+{ >+ return convertBytesToVector(TestData::kTestU2fSignResponse, sizeof(TestData::kTestU2fSignResponse)); >+} >+ > // Get a subset of the response for testing error handling. > Vector<uint8_t> getTestCorruptedSignResponse(size_t length) > { >@@ -239,11 +339,13 @@ Vector<uint8_t> getTestCredentialRawIdBytes() > return testCredentialRawIdBytes; > } > >-Vector<uint8_t> convertToVector(const uint8_t byteArray[], const size_t length) >+// Return a malformed U2fRegisterResponse. >+Vector<uint8_t> getTestU2fRegisterResponse(size_t prefixSize, const uint8_t appendix[], size_t appendixSize) > { > Vector<uint8_t> result; >- result.reserveInitialCapacity(length); >- result.append(byteArray, length); >+ result.reserveInitialCapacity(prefixSize + appendixSize); >+ result.append(TestData::kTestU2fRegisterResponse, prefixSize); >+ result.append(appendix, appendixSize); > return result; > } > >@@ -251,9 +353,9 @@ Vector<uint8_t> convertToVector(const uint8_t byteArray[], const size_t length) > // https://fidoalliance.org/specs/fido-v2.0-ps-20170927/fido-client-to-authenticator-protocol-v2.0-ps-20170927.html#commands > TEST(CTAPResponseTest, TestReadMakeCredentialResponse) > { >- auto makeCredentialResponse = readCTAPMakeCredentialResponse(convertToVector(TestData::kTestMakeCredentialResponse, sizeof(TestData::kTestMakeCredentialResponse))); >+ auto makeCredentialResponse = readCTAPMakeCredentialResponse(convertBytesToVector(TestData::kTestMakeCredentialResponse, sizeof(TestData::kTestMakeCredentialResponse))); > ASSERT_TRUE(makeCredentialResponse); >- auto cborAttestationObject = cbor::CBORReader::read(convertToVector(reinterpret_cast<uint8_t*>(makeCredentialResponse->attestationObject->data()), makeCredentialResponse->attestationObject->byteLength())); >+ auto cborAttestationObject = cbor::CBORReader::read(convertBytesToVector(reinterpret_cast<uint8_t*>(makeCredentialResponse->attestationObject->data()), makeCredentialResponse->attestationObject->byteLength())); > ASSERT_TRUE(cborAttestationObject); > ASSERT_TRUE(cborAttestationObject->isMap()); > >@@ -266,7 +368,7 @@ TEST(CTAPResponseTest, TestReadMakeCredentialResponse) > it = attestationObjectMap.find(cbor::CBORValue(kAuthDataKey)); > ASSERT_TRUE(it != attestationObjectMap.end()); > ASSERT_TRUE(it->second.isByteString()); >- EXPECT_EQ(it->second.getByteString(), convertToVector(TestData::kCtap2MakeCredentialAuthData, sizeof(TestData::kCtap2MakeCredentialAuthData))); >+ EXPECT_EQ(it->second.getByteString(), convertBytesToVector(TestData::kCtap2MakeCredentialAuthData, sizeof(TestData::kCtap2MakeCredentialAuthData))); > > it = attestationObjectMap.find(cbor::CBORValue(kAttestationStatementKey)); > ASSERT_TRUE(it != attestationObjectMap.end()); >@@ -282,7 +384,7 @@ TEST(CTAPResponseTest, TestReadMakeCredentialResponse) > attStmtIt = attestationStatementMap.find(cbor::CBORValue("sig")); > ASSERT_TRUE(attStmtIt != attestationStatementMap.end()); > ASSERT_TRUE(attStmtIt->second.isByteString()); >- EXPECT_EQ(attStmtIt->second.getByteString(), convertToVector(TestData::kCtap2MakeCredentialSignature, sizeof(TestData::kCtap2MakeCredentialSignature))); >+ EXPECT_EQ(attStmtIt->second.getByteString(), convertBytesToVector(TestData::kCtap2MakeCredentialSignature, sizeof(TestData::kCtap2MakeCredentialSignature))); > > attStmtIt = attestationStatementMap.find(cbor::CBORValue("x5c")); > ASSERT_TRUE(attStmtIt != attestationStatementMap.end()); >@@ -290,7 +392,7 @@ TEST(CTAPResponseTest, TestReadMakeCredentialResponse) > ASSERT_TRUE(certificate.isArray()); > ASSERT_EQ(certificate.getArray().size(), 1u); > ASSERT_TRUE(certificate.getArray()[0].isByteString()); >- EXPECT_EQ(certificate.getArray()[0].getByteString(), convertToVector(TestData::kCtap2MakeCredentialCertificate, sizeof(TestData::kCtap2MakeCredentialCertificate))); >+ EXPECT_EQ(certificate.getArray()[0].getByteString(), convertBytesToVector(TestData::kCtap2MakeCredentialCertificate, sizeof(TestData::kCtap2MakeCredentialCertificate))); > EXPECT_EQ(makeCredentialResponse->rawId->byteLength(), sizeof(TestData::kCtap2MakeCredentialCredentialId)); > EXPECT_EQ(memcmp(makeCredentialResponse->rawId->data(), TestData::kCtap2MakeCredentialCredentialId, sizeof(TestData::kCtap2MakeCredentialCredentialId)), 0); > } >@@ -299,7 +401,7 @@ TEST(CTAPResponseTest, TestReadMakeCredentialResponse) > // https://fidoalliance.org/specs/fido-v2.0-ps-20170927/fido-client-to-authenticator-protocol-v2.0-ps-20170927.html > TEST(CTAPResponseTest, TestReadGetAssertionResponse) > { >- auto getAssertionResponse = readCTAPGetAssertionResponse(convertToVector(TestData::kDeviceGetAssertionResponse, sizeof(TestData::kDeviceGetAssertionResponse))); >+ auto getAssertionResponse = readCTAPGetAssertionResponse(convertBytesToVector(TestData::kDeviceGetAssertionResponse, sizeof(TestData::kDeviceGetAssertionResponse))); > ASSERT_TRUE(getAssertionResponse); > > EXPECT_EQ(getAssertionResponse->authenticatorData->byteLength(), sizeof(TestData::kCtap2GetAssertionAuthData)); >@@ -308,9 +410,156 @@ TEST(CTAPResponseTest, TestReadGetAssertionResponse) > EXPECT_EQ(memcmp(getAssertionResponse->signature->data(), TestData::kCtap2GetAssertionSignature, sizeof(TestData::kCtap2GetAssertionSignature)), 0); > } > >+// Test that U2F register response is properly parsed. >+TEST(CTAPResponseTest, TestParseRegisterResponseData) >+{ >+ auto response = readU2fRegisterResponse(TestData::kRelyingPartyId, convertBytesToVector(TestData::kTestU2fRegisterResponse, sizeof(TestData::kTestU2fRegisterResponse))); >+ ASSERT_TRUE(response); >+ EXPECT_EQ(response->rawId->byteLength(), sizeof(TestData::kU2fSignKeyHandle)); >+ EXPECT_EQ(memcmp(response->rawId->data(), TestData::kU2fSignKeyHandle, sizeof(TestData::kU2fSignKeyHandle)), 0); >+ EXPECT_TRUE(response->isAuthenticatorAttestationResponse); >+ auto expectedAttestationObject = getTestAttestationObjectBytes(); >+ EXPECT_EQ(response->attestationObject->byteLength(), expectedAttestationObject.size()); >+ EXPECT_EQ(memcmp(response->attestationObject->data(), expectedAttestationObject.data(), expectedAttestationObject.size()), 0); >+} >+ >+// Test malformed user public key. >+TEST(CTAPResponseTest, TestParseIncorrectRegisterResponseData1) >+{ >+ const uint8_t testData1[] = { 0x05 }; >+ auto response = readU2fRegisterResponse(TestData::kRelyingPartyId, convertBytesToVector(testData1, sizeof(testData1))); >+ EXPECT_FALSE(response); >+ >+ const uint8_t testData2[] = { 0x05, 0x00 }; >+ response = readU2fRegisterResponse(TestData::kRelyingPartyId, convertBytesToVector(testData2, sizeof(testData2))); >+ EXPECT_FALSE(response); >+ >+ const uint8_t testData3[] = { 0x05, 0x04, 0x00 }; >+ response = readU2fRegisterResponse(TestData::kRelyingPartyId, convertBytesToVector(testData3, sizeof(testData3))); >+ EXPECT_FALSE(response); >+} >+ >+// Test malformed key handle. >+TEST(CTAPResponseTest, TestParseIncorrectRegisterResponseData2) >+{ >+ auto response = readU2fRegisterResponse(TestData::kRelyingPartyId, getTestU2fRegisterResponse(kU2fKeyHandleLengthOffset, nullptr, 0)); >+ EXPECT_FALSE(response); >+ >+ const uint8_t testData[] = { 0x40 }; >+ response = readU2fRegisterResponse(TestData::kRelyingPartyId, getTestU2fRegisterResponse(kU2fKeyHandleLengthOffset, testData, sizeof(testData))); >+ EXPECT_FALSE(response); >+} >+ >+// Test malformed X.509. >+TEST(CTAPResponseTest, TestParseIncorrectRegisterResponseData3) >+{ >+ const auto prefix = kU2fKeyHandleOffset + 64; >+ auto response = readU2fRegisterResponse(TestData::kRelyingPartyId, getTestU2fRegisterResponse(prefix, nullptr, 0)); >+ EXPECT_FALSE(response); >+ >+ const uint8_t testData1[] = { 0x40 }; >+ response = readU2fRegisterResponse(TestData::kRelyingPartyId, getTestU2fRegisterResponse(prefix, testData1, sizeof(testData1))); >+ EXPECT_FALSE(response); >+ >+ const uint8_t testData2[] = { 0x30 }; >+ response = readU2fRegisterResponse(TestData::kRelyingPartyId, getTestU2fRegisterResponse(prefix, testData2, sizeof(testData2))); >+ EXPECT_FALSE(response); >+ >+ const uint8_t testData3[] = { 0x30, 0x82 }; >+ response = readU2fRegisterResponse(TestData::kRelyingPartyId, getTestU2fRegisterResponse(prefix, testData3, sizeof(testData3))); >+ EXPECT_FALSE(response); >+ >+ const uint8_t testData4[] = { 0x30, 0xC1 }; >+ response = readU2fRegisterResponse(TestData::kRelyingPartyId, getTestU2fRegisterResponse(prefix, testData4, sizeof(testData4))); >+ EXPECT_FALSE(response); >+ >+ const uint8_t testData5[] = { 0x30, 0x82, 0x02, 0x4A }; >+ response = readU2fRegisterResponse(TestData::kRelyingPartyId, getTestU2fRegisterResponse(prefix, testData5, sizeof(testData5))); >+ EXPECT_FALSE(response); >+} >+ >+// Test malformed signature. >+TEST(CTAPResponseTest, TestParseIncorrectRegisterResponseData4) >+{ >+ const auto prefix = sizeof(TestData::kTestU2fRegisterResponse); >+ auto response = readU2fRegisterResponse(TestData::kRelyingPartyId, getTestU2fRegisterResponse(prefix - 71, nullptr, 0)); >+ EXPECT_FALSE(response); >+ >+ const uint8_t testData[] = { 0x40, 0x40, 0x40 }; >+ response = readU2fRegisterResponse(TestData::kRelyingPartyId, getTestU2fRegisterResponse(prefix, testData, sizeof(testData))); >+ EXPECT_FALSE(response); >+} >+ >+// Test malformed X.509 but pass. >+TEST(CTAPResponseTest, TestParseIncorrectRegisterResponseData5) >+{ >+ const auto prefix = kU2fKeyHandleOffset + 64; >+ const auto signatureSize = 71; >+ const auto suffix = sizeof(TestData::kTestU2fRegisterResponse) - signatureSize; >+ >+ Vector<uint8_t> testData1; >+ testData1.append(TestData::kTestU2fRegisterResponse, prefix); >+ testData1.append(0x30); >+ testData1.append(0x01); >+ testData1.append(0x00); >+ testData1.append(TestData::kTestU2fRegisterResponse + suffix, signatureSize); >+ auto response = readU2fRegisterResponse(TestData::kRelyingPartyId, testData1); >+ EXPECT_TRUE(response); >+ >+ Vector<uint8_t> testData2; >+ testData2.append(TestData::kTestU2fRegisterResponse, prefix); >+ testData2.append(0x30); >+ testData2.append(0x81); >+ testData2.append(0x01); >+ testData2.append(0x00); >+ testData2.append(TestData::kTestU2fRegisterResponse + suffix, signatureSize); >+ response = readU2fRegisterResponse(TestData::kRelyingPartyId, testData2); >+ EXPECT_TRUE(response); >+} >+ >+// Tests that U2F authenticator data is properly serialized. >+TEST(CTAPResponseTest, TestParseSignResponseData) >+{ >+ auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestSignResponse()); >+ ASSERT_TRUE(response); >+ EXPECT_EQ(response->rawId->byteLength(), sizeof(TestData::kU2fSignKeyHandle)); >+ EXPECT_EQ(memcmp(response->rawId->data(), TestData::kU2fSignKeyHandle, sizeof(TestData::kU2fSignKeyHandle)), 0); >+ EXPECT_FALSE(response->isAuthenticatorAttestationResponse); >+ EXPECT_EQ(response->authenticatorData->byteLength(), sizeof(TestData::kTestSignAuthenticatorData)); >+ EXPECT_EQ(memcmp(response->authenticatorData->data(), TestData::kTestSignAuthenticatorData, sizeof(TestData::kTestSignAuthenticatorData)), 0); >+ EXPECT_EQ(response->signature->byteLength(), sizeof(TestData::kU2fSignature)); >+ EXPECT_EQ(memcmp(response->signature->data(), TestData::kU2fSignature, sizeof(TestData::kU2fSignature)), 0); >+} >+ >+TEST(CTAPResponseTest, TestParseU2fSignWithNullKeyHandle) >+{ >+ auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, Vector<uint8_t>(), getTestSignResponse()); >+ EXPECT_FALSE(response); >+} >+ >+TEST(CTAPResponseTest, TestParseU2fSignWithNullResponse) >+{ >+ auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), Vector<uint8_t>()); >+ EXPECT_FALSE(response); >+} >+ >+TEST(CTAPResponseTest, TestParseU2fSignWithCorruptedCounter) >+{ >+ // A sign response of less than 5 bytes. >+ auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestCorruptedSignResponse(3)); >+ EXPECT_FALSE(response); >+} >+ >+TEST(CTAPResponseTest, TestParseU2fSignWithCorruptedSignature) >+{ >+ // A sign response no more than 5 bytes. >+ auto response = readFromU2fSignResponse(TestData::kRelyingPartyId, getTestCredentialRawIdBytes(), getTestCorruptedSignResponse(5)); >+ EXPECT_FALSE(response); >+} >+ > TEST(CTAPResponseTest, TestReadGetInfoResponse) > { >- auto getInfoResponse = readCTAPGetInfoResponse(convertToVector(TestData::kTestGetInfoResponsePlatformDevice, sizeof(TestData::kTestGetInfoResponsePlatformDevice))); >+ auto getInfoResponse = readCTAPGetInfoResponse(convertBytesToVector(TestData::kTestGetInfoResponsePlatformDevice, sizeof(TestData::kTestGetInfoResponsePlatformDevice))); > ASSERT_TRUE(getInfoResponse); > ASSERT_TRUE(getInfoResponse->maxMsgSize()); > EXPECT_EQ(*getInfoResponse->maxMsgSize(), 1200u); >@@ -325,14 +574,14 @@ TEST(CTAPResponseTest, TestReadGetInfoResponse) > > TEST(CTAPResponseTest, TestReadGetInfoResponseWithIncorrectFormat) > { >- EXPECT_FALSE(readCTAPGetInfoResponse(convertToVector(kTestAuthenticatorGetInfoResponseWithNoVersion, sizeof(kTestAuthenticatorGetInfoResponseWithNoVersion)))); >- EXPECT_FALSE(readCTAPGetInfoResponse(convertToVector(kTestAuthenticatorGetInfoResponseWithDuplicateVersion, sizeof(kTestAuthenticatorGetInfoResponseWithDuplicateVersion)))); >- EXPECT_FALSE(readCTAPGetInfoResponse(convertToVector(kTestAuthenticatorGetInfoResponseWithIncorrectAaguid, sizeof(kTestAuthenticatorGetInfoResponseWithIncorrectAaguid)))); >+ EXPECT_FALSE(readCTAPGetInfoResponse(convertBytesToVector(kTestAuthenticatorGetInfoResponseWithNoVersion, sizeof(kTestAuthenticatorGetInfoResponseWithNoVersion)))); >+ EXPECT_FALSE(readCTAPGetInfoResponse(convertBytesToVector(kTestAuthenticatorGetInfoResponseWithDuplicateVersion, sizeof(kTestAuthenticatorGetInfoResponseWithDuplicateVersion)))); >+ EXPECT_FALSE(readCTAPGetInfoResponse(convertBytesToVector(kTestAuthenticatorGetInfoResponseWithIncorrectAaguid, sizeof(kTestAuthenticatorGetInfoResponseWithIncorrectAaguid)))); > } > > TEST(CTAPResponseTest, TestSerializeGetInfoResponse) > { >- AuthenticatorGetInfoResponse response({ ProtocolVersion::kCtap, ProtocolVersion::kU2f }, convertToVector(kTestDeviceAaguid, sizeof(kTestDeviceAaguid))); >+ AuthenticatorGetInfoResponse response({ ProtocolVersion::kCtap, ProtocolVersion::kU2f }, convertBytesToVector(kTestDeviceAaguid, sizeof(kTestDeviceAaguid))); > response.setExtensions({ "uvm", "hmac-secret" }); > AuthenticatorSupportedOptions options; > options.setSupportsResidentKey(true); >diff --git a/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h b/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h >index 60d37f5a7a9c0468f19094b179a67940f7c48d1d..38e03c886b5969acadea8d3e50170bce26d07d8c 100644 >--- a/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h >+++ b/Tools/TestWebKitAPI/Tests/WebCore/FidoTestData.h >@@ -42,10 +42,30 @@ namespace TestData { > constexpr uint8_t kClientDataHash[] = { > 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xec, 0x17, 0x20, 0x2e, 0x42, > 0x50, 0x5f, 0x8e, 0xd2, 0xb1, 0x6a, 0xe2, 0x2f, 0x16, 0xbb, 0x05, >- 0xb8, 0x8c, 0x25, 0xdb, 0x9e, 0x60, 0x26, 0x45, 0xf1, 0x41}; >+ 0xb8, 0x8c, 0x25, 0xdb, 0x9e, 0x60, 0x26, 0x45, 0xf1, 0x41 >+}; > > constexpr uint8_t kUserId[] = {0x10, 0x98, 0x23, 0x72, 0x35, 0x40, 0x98, 0x72}; > >+constexpr char kRelyingPartyId[] = "acme.com"; >+ >+constexpr uint8_t kU2fRegisterCommandApdu[] = { >+ // CLA, INS, P1, P2 APDU instructions >+ 0x00, 0x01, 0x00, 0x00, >+ // Data length in 3 bytes in big endian order. >+ 0x00, 0x00, 0x40, >+ // Challenge parameter -- see kClientDataHash >+ 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xec, 0x17, 0x20, 0x2e, 0x42, >+ 0x50, 0x5f, 0x8e, 0xd2, 0xb1, 0x6a, 0xe2, 0x2f, 0x16, 0xbb, 0x05, >+ 0xb8, 0x8c, 0x25, 0xdb, 0x9e, 0x60, 0x26, 0x45, 0xf1, 0x41, >+ // Application parameter >+ 0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7, >+ 0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF, >+ 0x01, 0x3D, 0xE9, 0x6D, 0x4E, 0xFB, 0x17, 0xDE, >+ // Max response length >+ 0x00, 0x00, >+}; >+ > // Sample U2F sign request parameters used in example 7 of the CTAP spec. > // https://fidoalliance.org/specs/fido-v2.0-ps-20170927/fido-client-to-authenticator-protocol-v2.0-ps-20170927.html#using-the-ctap2-authenticatormakecredential-command-with-ctap1-u2f-authenticators > constexpr uint8_t kU2fSignKeyHandle[] = { >@@ -57,8 +77,169 @@ constexpr uint8_t kU2fSignKeyHandle[] = { > 0xCC, 0xD4, 0x15, 0xCD, 0x08, 0xFE, 0x42, 0x00, 0x38, > }; > >+// Signed signature of above |kU2fSignKeyHandle|. >+constexpr uint8_t kU2fSignature[] = { >+ 0x30, 0x44, 0x02, 0x20, 0x7B, 0xDE, 0x0A, 0x52, 0xAC, 0x1F, 0x4C, 0x8B, >+ 0x27, 0xE0, 0x03, 0xA3, 0x70, 0xCD, 0x66, 0xA4, 0xC7, 0x11, 0x8D, 0xD2, >+ 0x2D, 0x54, 0x47, 0x83, 0x5F, 0x45, 0xB9, 0x9C, 0x68, 0x42, 0x3F, 0xF7, >+ 0x02, 0x20, 0x3C, 0x51, 0x7B, 0x47, 0x87, 0x7F, 0x85, 0x78, 0x2D, 0xE1, >+ 0x00, 0x86, 0xA7, 0x83, 0xD1, 0xE7, 0xDF, 0x4E, 0x36, 0x39, 0xE7, 0x71, >+ 0xF5, 0xF6, 0xAF, 0xA3, 0x5A, 0xAD, 0x53, 0x73, 0x85, 0x8E, >+}; >+ >+constexpr uint8_t kU2fSignCommandApdu[] = { >+ // CLA, INS, P1, P2 APDU instruction parameters >+ 0x00, 0x02, 0x03, 0x00, >+ // Data Length (3 bytes in big endian order) >+ 0x00, 0x00, 0x81, >+ // Challenge parameter -- see kClientDataHash >+ 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xec, 0x17, 0x20, 0x2e, 0x42, >+ 0x50, 0x5f, 0x8e, 0xd2, 0xb1, 0x6a, 0xe2, 0x2f, 0x16, 0xbb, 0x05, >+ 0xb8, 0x8c, 0x25, 0xdb, 0x9e, 0x60, 0x26, 0x45, 0xf1, 0x41, >+ // Application parameter >+ 0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7, >+ 0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF, >+ 0x01, 0x3D, 0xE9, 0x6D, 0x4E, 0xFB, 0x17, 0xDE, >+ // Key handle length >+ 0x40, >+ // Key handle >+ 0x3E, 0xBD, 0x89, 0xBF, 0x77, 0xEC, 0x50, 0x97, 0x55, 0xEE, 0x9C, 0x26, >+ 0x35, 0xEF, 0xAA, 0xAC, 0x7B, 0x2B, 0x9C, 0x5C, 0xEF, 0x17, 0x36, 0xC3, >+ 0x71, 0x7D, 0xA4, 0x85, 0x34, 0xC8, 0xC6, 0xB6, 0x54, 0xD7, 0xFF, 0x94, >+ 0x5F, 0x50, 0xB5, 0xCC, 0x4E, 0x78, 0x05, 0x5B, 0xDD, 0x39, 0x6B, 0x64, >+ 0xF7, 0x8D, 0xA2, 0xC5, 0xF9, 0x62, 0x00, 0xCC, 0xD4, 0x15, 0xCD, 0x08, >+ 0xFE, 0x42, 0x00, 0x38, >+ // Max response length >+ 0x00, 0x00, >+}; >+ >+constexpr uint8_t kU2fCheckOnlySignCommandApdu[] = { >+ // CLA, INS, P1, P2 APDU instruction parameters >+ 0x00, 0x02, 0x07, 0x00, >+ // Data Length (3 bytes in big endian order). >+ 0x00, 0x00, 0x81, >+ // Challenge parameter -- see kClientDataHash >+ 0x68, 0x71, 0x34, 0x96, 0x82, 0x22, 0xec, 0x17, 0x20, 0x2e, 0x42, >+ 0x50, 0x5f, 0x8e, 0xd2, 0xb1, 0x6a, 0xe2, 0x2f, 0x16, 0xbb, 0x05, >+ 0xb8, 0x8c, 0x25, 0xdb, 0x9e, 0x60, 0x26, 0x45, 0xf1, 0x41, >+ // Application parameter >+ 0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7, >+ 0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF, >+ 0x01, 0x3D, 0xE9, 0x6D, 0x4E, 0xFB, 0x17, 0xDE, >+ // Key handle length >+ 0x40, >+ // Key handle >+ 0x3E, 0xBD, 0x89, 0xBF, 0x77, 0xEC, 0x50, 0x97, 0x55, 0xEE, 0x9C, 0x26, >+ 0x35, 0xEF, 0xAA, 0xAC, 0x7B, 0x2B, 0x9C, 0x5C, 0xEF, 0x17, 0x36, 0xC3, >+ 0x71, 0x7D, 0xA4, 0x85, 0x34, 0xC8, 0xC6, 0xB6, 0x54, 0xD7, 0xFF, 0x94, >+ 0x5F, 0x50, 0xB5, 0xCC, 0x4E, 0x78, 0x05, 0x5B, 0xDD, 0x39, 0x6B, 0x64, >+ 0xF7, 0x8D, 0xA2, 0xC5, 0xF9, 0x62, 0x00, 0xCC, 0xD4, 0x15, 0xCD, 0x08, >+ 0xFE, 0x42, 0x00, 0x38, >+ // Max response length >+ 0x00, 0x00, >+}; >+ >+constexpr uint8_t kU2fFakeRegisterCommand[] = { >+ // CLA, INS, P1, P2 APDU instructions >+ 0x00, 0x01, 0x00, 0x00, >+ // Data length in 3 bytes in big endian order. >+ 0x00, 0x00, 0x40, >+ // Bogus challenge parameter >+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, >+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, >+ 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, >+ // Bogus application parameter >+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, >+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, >+ 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, >+ // Maximum response length >+ 0x00, 0x00, >+}; >+ > // U2F responses --------------------------------------------------------------- > >+// U2F response blob produced by a U2F registration request used in example 6 >+// of the CTAP spec. >+// https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-client-to-authenticator-protocol-v2.0-rd-20170927.html >+constexpr uint8_t kTestU2fRegisterResponse[] = { >+ // Reserved byte >+ 0x05, >+ // User public key >+ 0x04, 0xE8, 0x76, 0x25, 0x89, 0x6E, 0xE4, 0xE4, 0x6D, 0xC0, 0x32, 0x76, >+ 0x6E, 0x80, 0x87, 0x96, 0x2F, 0x36, 0xDF, 0x9D, 0xFE, 0x8B, 0x56, 0x7F, >+ 0x37, 0x63, 0x01, 0x5B, 0x19, 0x90, 0xA6, 0x0E, 0x14, 0x27, 0xDE, 0x61, >+ 0x2D, 0x66, 0x41, 0x8B, 0xDA, 0x19, 0x50, 0x58, 0x1E, 0xBC, 0x5C, 0x8C, >+ 0x1D, 0xAD, 0x71, 0x0C, 0xB1, 0x4C, 0x22, 0xF8, 0xC9, 0x70, 0x45, 0xF4, >+ 0x61, 0x2F, 0xB2, 0x0C, 0x91, >+ // Key handle length >+ 0x40, >+ // Key handle >+ 0x3E, 0xBD, 0x89, 0xBF, 0x77, 0xEC, 0x50, 0x97, 0x55, 0xEE, 0x9C, 0x26, >+ 0x35, 0xEF, 0xAA, 0xAC, 0x7B, 0x2B, 0x9C, 0x5C, 0xEF, 0x17, 0x36, 0xC3, >+ 0x71, 0x7D, 0xA4, 0x85, 0x34, 0xC8, 0xC6, 0xB6, 0x54, 0xD7, 0xFF, 0x94, >+ 0x5F, 0x50, 0xB5, 0xCC, 0x4E, 0x78, 0x05, 0x5B, 0xDD, 0x39, 0x6B, 0x64, >+ 0xF7, 0x8D, 0xA2, 0xC5, 0xF9, 0x62, 0x00, 0xCC, 0xD4, 0x15, 0xCD, 0x08, >+ 0xFE, 0x42, 0x00, 0x38, >+ // X.509 Certificate >+ 0x30, 0x82, 0x02, 0x4A, 0x30, 0x82, 0x01, 0x32, 0xA0, 0x03, >+ 0x02, 0x01, 0x02, 0x02, 0x04, 0x04, 0x6C, 0x88, 0x22, 0x30, 0x0D, 0x06, >+ 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, >+ 0x30, 0x2E, 0x31, 0x2C, 0x30, 0x2A, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, >+ 0x23, 0x59, 0x75, 0x62, 0x69, 0x63, 0x6F, 0x20, 0x55, 0x32, 0x46, 0x20, >+ 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, 0x20, 0x53, 0x65, 0x72, 0x69, >+ 0x61, 0x6C, 0x20, 0x34, 0x35, 0x37, 0x32, 0x30, 0x30, 0x36, 0x33, 0x31, >+ 0x30, 0x20, 0x17, 0x0D, 0x31, 0x34, 0x30, 0x38, 0x30, 0x31, 0x30, 0x30, >+ 0x30, 0x30, 0x30, 0x30, 0x5A, 0x18, 0x0F, 0x32, 0x30, 0x35, 0x30, 0x30, >+ 0x39, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5A, 0x30, 0x2C, >+ 0x31, 0x2A, 0x30, 0x28, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0C, 0x21, 0x59, >+ 0x75, 0x62, 0x69, 0x63, 0x6F, 0x20, 0x55, 0x32, 0x46, 0x20, 0x45, 0x45, >+ 0x20, 0x53, 0x65, 0x72, 0x69, 0x61, 0x6C, 0x20, 0x32, 0x34, 0x39, 0x31, >+ 0x38, 0x32, 0x33, 0x32, 0x34, 0x37, 0x37, 0x30, 0x30, 0x59, 0x30, 0x13, >+ 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x08, 0x2A, >+ 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x3C, >+ 0xCA, 0xB9, 0x2C, 0xCB, 0x97, 0x28, 0x7E, 0xE8, 0xE6, 0x39, 0x43, 0x7E, >+ 0x21, 0xFC, 0xD6, 0xB6, 0xF1, 0x65, 0xB2, 0xD5, 0xA3, 0xF3, 0xDB, 0x13, >+ 0x1D, 0x31, 0xC1, 0x6B, 0x74, 0x2B, 0xB4, 0x76, 0xD8, 0xD1, 0xE9, 0x90, >+ 0x80, 0xEB, 0x54, 0x6C, 0x9B, 0xBD, 0xF5, 0x56, 0xE6, 0x21, 0x0F, 0xD4, >+ 0x27, 0x85, 0x89, 0x9E, 0x78, 0xCC, 0x58, 0x9E, 0xBE, 0x31, 0x0F, 0x6C, >+ 0xDB, 0x9F, 0xF4, 0xA3, 0x3B, 0x30, 0x39, 0x30, 0x22, 0x06, 0x09, 0x2B, >+ 0x06, 0x01, 0x04, 0x01, 0x82, 0xC4, 0x0A, 0x02, 0x04, 0x15, 0x31, 0x2E, >+ 0x33, 0x2E, 0x36, 0x2E, 0x31, 0x2E, 0x34, 0x2E, 0x31, 0x2E, 0x34, 0x31, >+ 0x34, 0x38, 0x32, 0x2E, 0x31, 0x2E, 0x32, 0x30, 0x13, 0x06, 0x0B, 0x2B, >+ 0x06, 0x01, 0x04, 0x01, 0x82, 0xE5, 0x1C, 0x02, 0x01, 0x01, 0x04, 0x04, >+ 0x03, 0x02, 0x04, 0x30, 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, >+ 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, >+ 0x9F, 0x9B, 0x05, 0x22, 0x48, 0xBC, 0x4C, 0xF4, 0x2C, 0xC5, 0x99, 0x1F, >+ 0xCA, 0xAB, 0xAC, 0x9B, 0x65, 0x1B, 0xBE, 0x5B, 0xDC, 0xDC, 0x8E, 0xF0, >+ 0xAD, 0x2C, 0x1C, 0x1F, 0xFB, 0x36, 0xD1, 0x87, 0x15, 0xD4, 0x2E, 0x78, >+ 0xB2, 0x49, 0x22, 0x4F, 0x92, 0xC7, 0xE6, 0xE7, 0xA0, 0x5C, 0x49, 0xF0, >+ 0xE7, 0xE4, 0xC8, 0x81, 0xBF, 0x2E, 0x94, 0xF4, 0x5E, 0x4A, 0x21, 0x83, >+ 0x3D, 0x74, 0x56, 0x85, 0x1D, 0x0F, 0x6C, 0x14, 0x5A, 0x29, 0x54, 0x0C, >+ 0x87, 0x4F, 0x30, 0x92, 0xC9, 0x34, 0xB4, 0x3D, 0x22, 0x2B, 0x89, 0x62, >+ 0xC0, 0xF4, 0x10, 0xCE, 0xF1, 0xDB, 0x75, 0x89, 0x2A, 0xF1, 0x16, 0xB4, >+ 0x4A, 0x96, 0xF5, 0xD3, 0x5A, 0xDE, 0xA3, 0x82, 0x2F, 0xC7, 0x14, 0x6F, >+ 0x60, 0x04, 0x38, 0x5B, 0xCB, 0x69, 0xB6, 0x5C, 0x99, 0xE7, 0xEB, 0x69, >+ 0x19, 0x78, 0x67, 0x03, 0xC0, 0xD8, 0xCD, 0x41, 0xE8, 0xF7, 0x5C, 0xCA, >+ 0x44, 0xAA, 0x8A, 0xB7, 0x25, 0xAD, 0x8E, 0x79, 0x9F, 0xF3, 0xA8, 0x69, >+ 0x6A, 0x6F, 0x1B, 0x26, 0x56, 0xE6, 0x31, 0xB1, 0xE4, 0x01, 0x83, 0xC0, >+ 0x8F, 0xDA, 0x53, 0xFA, 0x4A, 0x8F, 0x85, 0xA0, 0x56, 0x93, 0x94, 0x4A, >+ 0xE1, 0x79, 0xA1, 0x33, 0x9D, 0x00, 0x2D, 0x15, 0xCA, 0xBD, 0x81, 0x00, >+ 0x90, 0xEC, 0x72, 0x2E, 0xF5, 0xDE, 0xF9, 0x96, 0x5A, 0x37, 0x1D, 0x41, >+ 0x5D, 0x62, 0x4B, 0x68, 0xA2, 0x70, 0x7C, 0xAD, 0x97, 0xBC, 0xDD, 0x17, >+ 0x85, 0xAF, 0x97, 0xE2, 0x58, 0xF3, 0x3D, 0xF5, 0x6A, 0x03, 0x1A, 0xA0, >+ 0x35, 0x6D, 0x8E, 0x8D, 0x5E, 0xBC, 0xAD, 0xC7, 0x4E, 0x07, 0x16, 0x36, >+ 0xC6, 0xB1, 0x10, 0xAC, 0xE5, 0xCC, 0x9B, 0x90, 0xDF, 0xEA, 0xCA, 0xE6, >+ 0x40, 0xFF, 0x1B, 0xB0, 0xF1, 0xFE, 0x5D, 0xB4, 0xEF, 0xF7, 0xA9, 0x5F, >+ 0x06, 0x07, 0x33, 0xF5, >+ // Signature >+ 0x30, 0x45, 0x02, 0x20, 0x32, 0x47, 0x79, 0xC6, 0x8F, 0x33, 0x80, 0x28, >+ 0x8A, 0x11, 0x97, 0xB6, 0x09, 0x5F, 0x7A, 0x6E, 0xB9, 0xB1, 0xB1, 0xC1, >+ 0x27, 0xF6, 0x6A, 0xE1, 0x2A, 0x99, 0xFE, 0x85, 0x32, 0xEC, 0x23, 0xB9, >+ 0x02, 0x21, 0x00, 0xE3, 0x95, 0x16, 0xAC, 0x4D, 0x61, 0xEE, 0x64, 0x04, >+ 0x4D, 0x50, 0xB4, 0x15, 0xA6, 0xA4, 0xD4, 0xD8, 0x4B, 0xA6, 0xD8, 0x95, >+ 0xCB, 0x5A, 0xB7, 0xA1, 0xAA, 0x7D, 0x08, 0x1D, 0xE3, 0x41, 0xFA, >+}; >+ > // EC public key encoded in COSE_Key format extracted from above > // |kTestU2fRegisterResponse|. > constexpr uint8_t kTestECPublicKeyCOSE[] = { >@@ -204,6 +385,19 @@ constexpr uint8_t kTestU2fSignResponse[] = { > 0xF5, 0xF6, 0xAF, 0xA3, 0x5A, 0xAD, 0x53, 0x73, 0x85, 0x8E, > }; > >+// The authenticator data for sign responses extracted from above >+// |kTestU2fSignResponse|. >+constexpr uint8_t kTestSignAuthenticatorData[] = { >+ // SHA256 hash of kTestRelyingPartyId >+ 0x11, 0x94, 0x22, 0x8D, 0xA8, 0xFD, 0xBD, 0xEE, 0xFD, 0x26, 0x1B, 0xD7, >+ 0xB6, 0x59, 0x5C, 0xFD, 0x70, 0xA5, 0x0D, 0x70, 0xC6, 0x40, 0x7B, 0xCF, >+ 0x01, 0x3D, 0xE9, 0x6D, 0x4E, 0xFB, 0x17, 0xDE, >+ // Flags (TUP bit set) >+ 0x01, >+ // Counter >+ 0x00, 0x00, 0x00, 0x3B, >+}; >+ > // CTAP requests --------------------------------------------------------------- > constexpr uint8_t kCtapMakeCredentialRequest[] = { > // authenticatorMakeCredential command >diff --git a/Tools/TestWebKitAPI/Tests/WebCore/U2fCommandConstructorTest.cpp b/Tools/TestWebKitAPI/Tests/WebCore/U2fCommandConstructorTest.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..7d745f9bbc64ae1e166e223b632b73b1896993ec >--- /dev/null >+++ b/Tools/TestWebKitAPI/Tests/WebCore/U2fCommandConstructorTest.cpp >@@ -0,0 +1,226 @@ >+// Copyright 2018 The Chromium Authors. All rights reserved. >+// Copyright (C) 2019 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"; >+ rp.name = "acme.com"; >+ >+ PublicKeyCredentialCreationOptions::UserEntity user; >+ user.idVector = convertBytesToVector(TestData::kUserId, sizeof(TestData::kUserId)); >+ user.name = "johnpsmith@example.com"; >+ user.displayName = "John P. Smith"; >+ user.icon = "https://pics.acme.com/00/p/aBjjjpqPb.png"; >+ >+ PublicKeyCredentialCreationOptions::Parameters params; >+ params.type = PublicKeyCredentialType::PublicKey; >+ params.alg = COSE::ES256; >+ >+ PublicKeyCredentialCreationOptions options; >+ options.rp = WTFMove(rp); >+ options.user = WTFMove(user); >+ options.pubKeyCredParams.append(WTFMove(params)); >+ >+ return options; >+} >+ >+PublicKeyCredentialRequestOptions constructGetAssertionRequest() >+{ >+ PublicKeyCredentialRequestOptions options; >+ options.rpId = "acme.com"; >+ 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, TestConvertCtapMakeCredentialToU2fCheckOnlySign) >+{ >+ auto makeCredentialParam = constructMakeCredentialRequest(); >+ PublicKeyCredentialDescriptor credentialDescriptor; >+ credentialDescriptor.type = PublicKeyCredentialType::PublicKey; >+ credentialDescriptor.idVector = convertBytesToVector(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.idVector = convertBytesToVector(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"; >+ rp.name = "acme.com"; >+ >+ PublicKeyCredentialCreationOptions::UserEntity user; >+ user.idVector = convertBytesToVector(TestData::kUserId, sizeof(TestData::kUserId)); >+ user.name = "johnpsmith@example.com"; >+ user.displayName = "John P. Smith"; >+ user.icon = "https://pics.acme.com/00/p/aBjjjpqPb.png"; >+ >+ 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.idVector = convertBytesToVector(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, convertBytesToVector(TestData::kU2fSignKeyHandle, sizeof(TestData::kU2fSignKeyHandle))); >+ ASSERT_TRUE(u2fSignCommand); >+ EXPECT_EQ(*u2fSignCommand, convertBytesToVector(TestData::kU2fSignCommandApdu, sizeof(TestData::kU2fSignCommandApdu))); >+} >+ >+TEST(U2fCommandConstructorTest, TestU2fSignAllowListRequirement) >+{ >+ auto getAssertionReq = constructGetAssertionRequest(); >+ EXPECT_FALSE(isConvertibleToU2fSignCommand(getAssertionReq)); >+} >+ >+TEST(U2fCommandConstructorTest, TestU2fSignUserVerificationRequirement) >+{ >+ auto getAssertionReq = constructGetAssertionRequest(); >+ PublicKeyCredentialDescriptor credentialDescriptor; >+ credentialDescriptor.type = PublicKeyCredentialType::PublicKey; >+ credentialDescriptor.idVector = convertBytesToVector(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.idVector = convertBytesToVector(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, keyHandle); >+ EXPECT_TRUE(validSignCommand); >+ >+ keyHandle.append(0xff); >+ const auto invalidSignCommand = convertToU2fSignCommand(convertBytesToVector(TestData::kClientDataHash, sizeof(TestData::kClientDataHash)), getAssertionReq, keyHandle); >+ EXPECT_FALSE(invalidSignCommand); >+} >+ >+TEST(U2fCommandConstructorTest, TestConstructBogusU2fRegistrationCommand) >+{ >+ EXPECT_EQ(constructBogusU2fRegistrationCommand(), convertBytesToVector(TestData::kU2fFakeRegisterCommand, sizeof(TestData::kU2fFakeRegisterCommand))); >+} >+ >+} // namespace TestWebKitAPI >+ >+#endif // ENABLE(WEB_AUTHN) >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index d94c4558eb4853cbc8741dc558a873be294eef05..0103939edb9e16942a73a8ca8f8436fac5ee1943 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,18 @@ >+2019-01-04 Jiewen Tan <jiewen_tan@apple.com> >+ >+ [WebAuthN] Import U2F command/response converters from Chromium >+ https://bugs.webkit.org/show_bug.cgi?id=193150 >+ <rdar://problem/47054028> >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ Fixes Bug 183534: >+ 7) Change little endian bytes (ARM and x86 default) to big endian as requested by the spec. >+ >+ * http/wpt/webauthn/public-key-credential-create-success-hid.https.html: >+ * http/wpt/webauthn/public-key-credential-get-success-hid.https.html: >+ * http/wpt/webauthn/resources/util.js: >+ > 2018-12-21 Justin Michaud <justin_michaud@apple.com> > > CSS variables don't work for colors in "border" property >diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-hid.https.html b/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-hid.https.html >index 957c274d544e9dd7ae73ea22ae27744e7e855f7e..5d93b807a44c53734a7f5d811df6013562c05c7c 100644 >--- a/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-hid.https.html >+++ b/LayoutTests/http/wpt/webauthn/public-key-credential-create-success-hid.https.html >@@ -22,7 +22,7 @@ > const attestationObject = CBOR.decode(credential.response.attestationObject); > assert_equals(attestationObject.fmt, "packed"); > // Check authData >- const authData = decodeAuthData(attestationObject.authData, false); >+ const authData = decodeAuthData(attestationObject.authData); > assert_equals(bytesToHexString(authData.rpIdHash), "46cc7fb9679d55b2db9092e1c8d9e5e1d02b7580f0b4812c770962e1e48f5ad8"); > assert_equals(authData.flags, 65); > assert_equals(authData.counter, 78); >diff --git a/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https.html b/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https.html >index 1f13ded838489bacf08a773476284e64fcf24011..67db831007f7a2c5045d72dae3e1cd8001cc24d0 100644 >--- a/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https.html >+++ b/LayoutTests/http/wpt/webauthn/public-key-credential-get-success-hid.https.html >@@ -18,7 +18,7 @@ > assert_equals(credential.response.userHandle, null); > > // Check authData >- const authData = decodeAuthData(new Uint8Array(credential.response.authenticatorData), false); >+ const authData = decodeAuthData(new Uint8Array(credential.response.authenticatorData)); > assert_equals(bytesToHexString(authData.rpIdHash), "46cc7fb9679d55b2db9092e1c8d9e5e1d02b7580f0b4812c770962e1e48f5ad8"); > assert_equals(authData.flags, 1); > assert_equals(authData.counter, 80); >diff --git a/LayoutTests/http/wpt/webauthn/resources/util.js b/LayoutTests/http/wpt/webauthn/resources/util.js >index cd5980d96c7682fe832e6779487810175473b765..83f4b48adcf25b7004e9701f47f013f8a059afab 100644 >--- a/LayoutTests/http/wpt/webauthn/resources/util.js >+++ b/LayoutTests/http/wpt/webauthn/resources/util.js >@@ -134,7 +134,7 @@ function hexStringToUint8Array(hexString) > return arrayBuffer; > } > >-function decodeAuthData(authDataUint8Array, littleEndian = true) >+function decodeAuthData(authDataUint8Array) > { > let authDataObject = { }; > let pos = 0; >@@ -158,10 +158,7 @@ function decodeAuthData(authDataUint8Array, littleEndian = true) > size = 4; > if (pos + size > authDataUint8Array.byteLength) > return { }; >- if (littleEndian) >- authDataObject.counter = new Uint32Array(authDataUint8Array.slice(pos, pos + size))[0]; >- else >- authDataObject.counter = (authDataUint8Array[pos] << 24) + (authDataUint8Array[pos + 1] << 16) + (authDataUint8Array[pos + 2] << 8) + authDataUint8Array[pos + 3]; >+ authDataObject.counter = (authDataUint8Array[pos] << 24) + (authDataUint8Array[pos + 1] << 16) + (authDataUint8Array[pos + 2] << 8) + authDataUint8Array[pos + 3]; > pos = pos + size; > > if (pos == authDataUint8Array.byteLength) >@@ -178,10 +175,7 @@ function decodeAuthData(authDataUint8Array, littleEndian = true) > size = 2; > if (pos + size > authDataUint8Array.byteLength) > return { }; >- if (littleEndian) >- authDataObject.l = new Uint16Array(authDataUint8Array.slice(pos, pos + size))[0]; >- else >- authDataObject.l = (authDataUint8Array[pos] << 8) + authDataUint8Array[pos + 1]; >+ authDataObject.l = (authDataUint8Array[pos] << 8) + authDataUint8Array[pos + 1]; > pos = pos + size; > > // Credential ID
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 193150
:
358358
|
358399
|
358470