summaryrefslogtreecommitdiffstats
path: root/dom/webauthn/U2FHIDTokenManager.h
diff options
context:
space:
mode:
Diffstat (limited to 'dom/webauthn/U2FHIDTokenManager.h')
-rw-r--r--dom/webauthn/U2FHIDTokenManager.h188
1 files changed, 188 insertions, 0 deletions
diff --git a/dom/webauthn/U2FHIDTokenManager.h b/dom/webauthn/U2FHIDTokenManager.h
new file mode 100644
index 0000000000..4fe2495c31
--- /dev/null
+++ b/dom/webauthn/U2FHIDTokenManager.h
@@ -0,0 +1,188 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_U2FHIDTokenManager_h
+#define mozilla_dom_U2FHIDTokenManager_h
+
+#include "mozilla/dom/U2FTokenTransport.h"
+#include "authenticator/src/u2fhid-capi.h"
+
+/*
+ * U2FHIDTokenManager is a Rust implementation of a secure token manager
+ * for the U2F and WebAuthn APIs, talking to HIDs.
+ */
+
+namespace mozilla::dom {
+
+class U2FAppIds {
+ public:
+ explicit U2FAppIds(const nsTArray<nsTArray<uint8_t>>& aApplications) {
+ mAppIds = rust_u2f_app_ids_new();
+
+ for (auto& app_id : aApplications) {
+ rust_u2f_app_ids_add(mAppIds, app_id.Elements(), app_id.Length());
+ }
+ }
+
+ rust_u2f_app_ids* Get() { return mAppIds; }
+
+ ~U2FAppIds() { rust_u2f_app_ids_free(mAppIds); }
+
+ private:
+ rust_u2f_app_ids* mAppIds;
+};
+
+class U2FKeyHandles {
+ public:
+ explicit U2FKeyHandles(
+ const nsTArray<WebAuthnScopedCredential>& aCredentials) {
+ mKeyHandles = rust_u2f_khs_new();
+
+ for (auto& cred : aCredentials) {
+ rust_u2f_khs_add(mKeyHandles, cred.id().Elements(), cred.id().Length(),
+ cred.transports());
+ }
+ }
+
+ rust_u2f_key_handles* Get() { return mKeyHandles; }
+
+ ~U2FKeyHandles() { rust_u2f_khs_free(mKeyHandles); }
+
+ private:
+ rust_u2f_key_handles* mKeyHandles;
+};
+
+class U2FResult {
+ public:
+ explicit U2FResult(uint64_t aTransactionId, rust_u2f_result* aResult)
+ : mTransactionId(aTransactionId), mResult(aResult) {
+ MOZ_ASSERT(mResult);
+ }
+
+ ~U2FResult() { rust_u2f_res_free(mResult); }
+
+ uint64_t GetTransactionId() { return mTransactionId; }
+
+ bool IsError() { return NS_FAILED(GetError()); }
+
+ nsresult GetError() {
+ switch (rust_u2f_result_error(mResult)) {
+ case U2F_ERROR_UKNOWN:
+ case U2F_ERROR_CONSTRAINT:
+ return NS_ERROR_DOM_UNKNOWN_ERR;
+ case U2F_ERROR_NOT_SUPPORTED:
+ return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
+ case U2F_ERROR_INVALID_STATE:
+ return NS_ERROR_DOM_INVALID_STATE_ERR;
+ case U2F_ERROR_NOT_ALLOWED:
+ return NS_ERROR_DOM_NOT_ALLOWED_ERR;
+ default:
+ return NS_OK;
+ }
+ }
+
+ bool CopyRegistration(nsTArray<uint8_t>& aBuffer) {
+ return CopyBuffer(U2F_RESBUF_ID_REGISTRATION, aBuffer);
+ }
+
+ bool CopyKeyHandle(nsTArray<uint8_t>& aBuffer) {
+ return CopyBuffer(U2F_RESBUF_ID_KEYHANDLE, aBuffer);
+ }
+
+ bool CopySignature(nsTArray<uint8_t>& aBuffer) {
+ return CopyBuffer(U2F_RESBUF_ID_SIGNATURE, aBuffer);
+ }
+
+ bool CopyAppId(nsTArray<uint8_t>& aBuffer) {
+ return CopyBuffer(U2F_RESBUF_ID_APPID, aBuffer);
+ }
+
+ private:
+ bool CopyBuffer(uint8_t aResBufID, nsTArray<uint8_t>& aBuffer) {
+ size_t len;
+ if (!rust_u2f_resbuf_length(mResult, aResBufID, &len)) {
+ return false;
+ }
+
+ if (!aBuffer.SetLength(len, fallible)) {
+ return false;
+ }
+
+ return rust_u2f_resbuf_copy(mResult, aResBufID, aBuffer.Elements());
+ }
+
+ uint64_t mTransactionId;
+ rust_u2f_result* mResult;
+};
+
+class U2FHIDTokenManager final : public U2FTokenTransport {
+ public:
+ explicit U2FHIDTokenManager();
+
+ virtual RefPtr<U2FRegisterPromise> Register(
+ const WebAuthnMakeCredentialInfo& aInfo, bool aForceNoneAttestation,
+ void _status_callback(rust_ctap2_status_update_res*)) override;
+
+ virtual RefPtr<U2FSignPromise> Sign(
+ const WebAuthnGetAssertionInfo& aInfo,
+ void _status_callback(rust_ctap2_status_update_res*)) override;
+
+ void Cancel() override;
+ void Drop() override;
+
+ void HandleRegisterResult(UniquePtr<U2FResult>&& aResult);
+ void HandleSignResult(UniquePtr<U2FResult>&& aResult);
+
+ private:
+ ~U2FHIDTokenManager() = default;
+
+ void ClearPromises() {
+ mRegisterPromise.RejectIfExists(NS_ERROR_DOM_UNKNOWN_ERR, __func__);
+ mSignPromise.RejectIfExists(NS_ERROR_DOM_UNKNOWN_ERR, __func__);
+ }
+
+ class Transaction {
+ public:
+ Transaction(uint64_t aId, const nsTArray<uint8_t>& aRpIdHash,
+ const Maybe<nsTArray<uint8_t>>& aAppIdHash,
+ const nsCString& aClientDataJSON,
+ bool aForceNoneAttestation = false)
+ : mId(aId),
+ mRpIdHash(aRpIdHash.Clone()),
+ mClientDataJSON(aClientDataJSON),
+ mForceNoneAttestation(aForceNoneAttestation) {
+ if (aAppIdHash) {
+ mAppIdHash = Some(aAppIdHash->Clone());
+ } else {
+ mAppIdHash = Nothing();
+ }
+ }
+
+ // The transaction ID.
+ uint64_t mId;
+
+ // The RP ID hash.
+ nsTArray<uint8_t> mRpIdHash;
+
+ // The App ID hash, if the AppID extension was set
+ Maybe<nsTArray<uint8_t>> mAppIdHash;
+
+ // The clientData JSON.
+ nsCString mClientDataJSON;
+
+ // Whether we'll force "none" attestation.
+ bool mForceNoneAttestation;
+ };
+
+ rust_ctap_manager* mU2FManager;
+ Maybe<Transaction> mTransaction;
+ MozPromiseHolder<U2FRegisterPromise> mRegisterPromise;
+ MozPromiseHolder<U2FSignPromise> mSignPromise;
+};
+
+} // namespace mozilla::dom
+
+#endif // mozilla_dom_U2FHIDTokenManager_h