Skip to content

Commit

Permalink
AuthenticatorResponseData should use the modern serialization format
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=262890
rdar://116679067

Reviewed by Brady Eidson.

The change ports AuthenticatorResponseData to the new serialization format.

* Source/WebCore/Modules/webauthn/AuthenticatorResponseData.h:
(WebCore::AuthenticatorResponseData::AuthenticatorResponseData):
(WebCore::AuthenticatorResponseData::getSerializableForm const):
(WebCore::encodeArrayBuffer): Deleted.
(WebCore::decodeArrayBuffer): Deleted.
(WebCore::AuthenticatorResponseData::encode const): Deleted.
(WebCore::AuthenticatorResponseData::decode): Deleted.
* Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in:

Canonical link: https://commits.webkit.org/270315@main
  • Loading branch information
gavin-apple committed Nov 7, 2023
1 parent 7ebe5b8 commit b87b869
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 111 deletions.
166 changes: 55 additions & 111 deletions Source/WebCore/Modules/webauthn/AuthenticatorResponseData.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,52 @@ namespace WebCore {

class AuthenticatorResponse;

struct AuthenticatorResponseBaseData {
RefPtr<ArrayBuffer> rawId;
std::optional<AuthenticationExtensionsClientOutputs> extensionOutputs;
};

struct AuthenticatorAttestationResponseData {
RefPtr<ArrayBuffer> rawId;
std::optional<AuthenticationExtensionsClientOutputs> extensionOutputs;
RefPtr<ArrayBuffer> attestationObject;
Vector<WebCore::AuthenticatorTransport> transports;
};

struct AuthenticatorAssertionResponseData {
RefPtr<ArrayBuffer> rawId;
std::optional<AuthenticationExtensionsClientOutputs> extensionOutputs;
RefPtr<ArrayBuffer> authenticatorData;
RefPtr<ArrayBuffer> signature;
RefPtr<ArrayBuffer> userHandle;
};

using AuthenticatorResponseDataSerializableForm = std::variant<std::nullptr_t, AuthenticatorResponseBaseData, AuthenticatorAttestationResponseData, AuthenticatorAssertionResponseData>;

struct AuthenticatorResponseData {
bool isAuthenticatorAttestationResponse;
AuthenticatorResponseData() = default;
AuthenticatorResponseData(const AuthenticatorResponseDataSerializableForm& data)
{
WTF::switchOn(data, [](std::nullptr_t) {
}, [&](const AuthenticatorResponseBaseData& v) {
rawId = v.rawId;
extensionOutputs = v.extensionOutputs;
}, [&](const AuthenticatorAttestationResponseData& v) {
isAuthenticatorAttestationResponse = true;
rawId = v.rawId;
extensionOutputs = v.extensionOutputs;
attestationObject = v.attestationObject;
transports = v.transports;
}, [&](const AuthenticatorAssertionResponseData& v) {
rawId = v.rawId;
extensionOutputs = v.extensionOutputs;
authenticatorData = v.authenticatorData;
signature = v.signature;
userHandle = v.userHandle;
});
}

bool isAuthenticatorAttestationResponse { false };

// AuthenticatorResponse
RefPtr<ArrayBuffer> rawId;
Expand All @@ -55,120 +99,20 @@ struct AuthenticatorResponseData {

Vector<WebCore::AuthenticatorTransport> transports;

template<class Encoder> void encode(Encoder&) const;
template<class Decoder> static std::optional<AuthenticatorResponseData> decode(Decoder&);
};

template<class Encoder>
static void encodeArrayBuffer(Encoder& encoder, const ArrayBuffer& buffer)
{
encoder << std::span(reinterpret_cast<const uint8_t*>(buffer.data()), buffer.byteLength());
}

template<class Decoder>
RefPtr<ArrayBuffer> WARN_UNUSED_RETURN decodeArrayBuffer(Decoder& decoder)
{
std::optional<std::span<const uint8_t>> buffer;
decoder >> buffer;
if (!buffer)
return nullptr;
return ArrayBuffer::tryCreate(buffer->data(), buffer->size_bytes());
}

template<class Encoder>
void AuthenticatorResponseData::encode(Encoder& encoder) const
{
if (!rawId) {
encoder << true;
return;
}
encoder << false;
encodeArrayBuffer(encoder, *rawId);
encoder << extensionOutputs;

encoder << isAuthenticatorAttestationResponse;
AuthenticatorResponseDataSerializableForm getSerializableForm() const
{
if (!rawId)
return nullptr;

if (isAuthenticatorAttestationResponse && attestationObject) {
encodeArrayBuffer(encoder, *attestationObject);
encoder << transports;
return;
}
if (isAuthenticatorAttestationResponse && attestationObject)
return AuthenticatorAttestationResponseData { rawId, extensionOutputs, attestationObject, transports };

if (!authenticatorData || !signature)
return;
encodeArrayBuffer(encoder, *authenticatorData);
encodeArrayBuffer(encoder, *signature);
if (!authenticatorData || !signature)
return AuthenticatorResponseBaseData { rawId, extensionOutputs };

if (!userHandle) {
encoder << false;
return;
return AuthenticatorAssertionResponseData { rawId, extensionOutputs, authenticatorData, signature, userHandle };
}
encoder << true;
encodeArrayBuffer(encoder, *userHandle);
}

template<class Decoder>
std::optional<AuthenticatorResponseData> AuthenticatorResponseData::decode(Decoder& decoder)
{
AuthenticatorResponseData result;

std::optional<bool> isEmpty;
decoder >> isEmpty;
if (!isEmpty)
return std::nullopt;
if (isEmpty.value())
return result;

result.rawId = decodeArrayBuffer(decoder);
if (!result.rawId)
return std::nullopt;

std::optional<std::optional<AuthenticationExtensionsClientOutputs>> extensionOutputs;
decoder >> extensionOutputs;
if (!extensionOutputs)
return std::nullopt;
result.extensionOutputs = WTFMove(*extensionOutputs);

std::optional<bool> isAuthenticatorAttestationResponse;
decoder >> isAuthenticatorAttestationResponse;
if (!isAuthenticatorAttestationResponse)
return std::nullopt;
result.isAuthenticatorAttestationResponse = isAuthenticatorAttestationResponse.value();

if (result.isAuthenticatorAttestationResponse) {
result.attestationObject = decodeArrayBuffer(decoder);
if (!result.attestationObject)
return std::nullopt;

std::optional<Vector<AuthenticatorTransport>> transports;
decoder >> transports;
if (!transports)
return std::nullopt;
result.transports = WTFMove(*transports);
return result;
}

result.authenticatorData = decodeArrayBuffer(decoder);
if (!result.authenticatorData)
return std::nullopt;

result.signature = decodeArrayBuffer(decoder);
if (!result.signature)
return std::nullopt;

std::optional<bool> hasUserHandle;
decoder >> hasUserHandle;
if (!hasUserHandle)
return std::nullopt;
if (!*hasUserHandle)
return result;

result.userHandle = decodeArrayBuffer(decoder);
if (!result.userHandle)
return std::nullopt;

return result;
}
};

} // namespace WebCore

Expand Down
27 changes: 27 additions & 0 deletions Source/WebKit/Shared/WebCoreArgumentCoders.serialization.in
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,33 @@ struct WebCore::WebLockManagerSnapshot {
};

#if ENABLE(WEB_AUTHN)

[CustomHeader] struct WebCore::AuthenticatorResponseBaseData {
RefPtr<JSC::ArrayBuffer> rawId;
std::optional<WebCore::AuthenticationExtensionsClientOutputs> extensionOutputs;
};

[CustomHeader] struct WebCore::AuthenticatorAttestationResponseData {
RefPtr<JSC::ArrayBuffer> rawId;
std::optional<WebCore::AuthenticationExtensionsClientOutputs> extensionOutputs;
RefPtr<JSC::ArrayBuffer> attestationObject;
Vector<WebCore::AuthenticatorTransport> transports;
};

[CustomHeader] struct WebCore::AuthenticatorAssertionResponseData {
RefPtr<JSC::ArrayBuffer> rawId;
std::optional<WebCore::AuthenticationExtensionsClientOutputs> extensionOutputs;
RefPtr<JSC::ArrayBuffer> authenticatorData;
RefPtr<JSC::ArrayBuffer> signature;
RefPtr<JSC::ArrayBuffer> userHandle;
};

using WebCore::AuthenticatorResponseDataSerializableForm = std::variant<std::nullptr_t, WebCore::AuthenticatorResponseDataBase, WebCore::AuthenticatorAttestationResponseData, WebCore::AuthenticatorAssertionResponseData>;

struct WebCore::AuthenticatorResponseData {
WebCore::AuthenticatorResponseDataSerializableForm getSerializableForm();
};

[Nested] struct WebCore::AuthenticationExtensionsClientInputs::LargeBlobInputs {
String support;
std::optional<bool> read;
Expand Down

0 comments on commit b87b869

Please sign in to comment.