diff options
Diffstat (limited to 'dom/webauthn/U2FHIDTokenManager.h')
-rw-r--r-- | dom/webauthn/U2FHIDTokenManager.h | 188 |
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 |