tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

AuthenticatorAttestationResponse.cpp (8005B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/dom/AuthenticatorAttestationResponse.h"
      8 
      9 #include "AuthrsBridge_ffi.h"
     10 #include "mozilla/Base64.h"
     11 #include "mozilla/HoldDropJSObjects.h"
     12 #include "mozilla/dom/WebAuthenticationBinding.h"
     13 
     14 namespace mozilla::dom {
     15 
     16 NS_IMPL_CYCLE_COLLECTION_CLASS(AuthenticatorAttestationResponse)
     17 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(
     18    AuthenticatorAttestationResponse, AuthenticatorResponse)
     19  tmp->mAttestationObjectCachedObj = nullptr;
     20 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     21 
     22 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(AuthenticatorAttestationResponse,
     23                                               AuthenticatorResponse)
     24  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
     25  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mAttestationObjectCachedObj)
     26 NS_IMPL_CYCLE_COLLECTION_TRACE_END
     27 
     28 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(
     29    AuthenticatorAttestationResponse, AuthenticatorResponse)
     30 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     31 
     32 NS_IMPL_ADDREF_INHERITED(AuthenticatorAttestationResponse,
     33                         AuthenticatorResponse)
     34 NS_IMPL_RELEASE_INHERITED(AuthenticatorAttestationResponse,
     35                          AuthenticatorResponse)
     36 
     37 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AuthenticatorAttestationResponse)
     38 NS_INTERFACE_MAP_END_INHERITING(AuthenticatorResponse)
     39 
     40 AuthenticatorAttestationResponse::AuthenticatorAttestationResponse(
     41    nsPIDOMWindowInner* aParent)
     42    : AuthenticatorResponse(aParent), mAttestationObjectCachedObj(nullptr) {
     43  mozilla::HoldJSObjects(this);
     44 }
     45 
     46 AuthenticatorAttestationResponse::~AuthenticatorAttestationResponse() {
     47  mozilla::DropJSObjects(this);
     48 }
     49 
     50 JSObject* AuthenticatorAttestationResponse::WrapObject(
     51    JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
     52  return AuthenticatorAttestationResponse_Binding::Wrap(aCx, this, aGivenProto);
     53 }
     54 
     55 void AuthenticatorAttestationResponse::GetAttestationObject(
     56    JSContext* aCx, JS::MutableHandle<JSObject*> aValue, ErrorResult& aRv) {
     57  if (!mAttestationObjectCachedObj) {
     58    mAttestationObjectCachedObj =
     59        ArrayBuffer::Create(aCx, mAttestationObject, aRv);
     60    if (aRv.Failed()) {
     61      return;
     62    }
     63  }
     64  aValue.set(mAttestationObjectCachedObj);
     65 }
     66 
     67 void AuthenticatorAttestationResponse::SetAttestationObject(
     68    const nsTArray<uint8_t>& aBuffer) {
     69  mAttestationObject.Assign(aBuffer);
     70 }
     71 
     72 void AuthenticatorAttestationResponse::GetTransports(
     73    nsTArray<nsString>& aTransports) {
     74  aTransports.Assign(mTransports);
     75 }
     76 
     77 void AuthenticatorAttestationResponse::SetTransports(
     78    const nsTArray<nsString>& aTransports) {
     79  mTransports.Assign(aTransports);
     80 }
     81 
     82 nsresult AuthenticatorAttestationResponse::GetAuthenticatorDataBytes(
     83    nsTArray<uint8_t>& aAuthenticatorData) {
     84  if (!mAttestationObjectParsed) {
     85    nsresult rv = authrs_webauthn_att_obj_constructor(
     86        mAttestationObject, /* anonymize */ false,
     87        getter_AddRefs(mAttestationObjectParsed));
     88    if (NS_FAILED(rv)) {
     89      return rv;
     90    }
     91  }
     92  nsresult rv =
     93      mAttestationObjectParsed->GetAuthenticatorData(aAuthenticatorData);
     94  if (NS_FAILED(rv)) {
     95    return rv;
     96  }
     97  return NS_OK;
     98 }
     99 
    100 void AuthenticatorAttestationResponse::GetAuthenticatorData(
    101    JSContext* aCx, JS::MutableHandle<JSObject*> aValue, ErrorResult& aRv) {
    102  nsTArray<uint8_t> authenticatorData;
    103  nsresult rv = GetAuthenticatorDataBytes(authenticatorData);
    104  if (NS_FAILED(rv)) {
    105    aRv.Throw(rv);
    106    return;
    107  }
    108 
    109  JS::Heap<JSObject*> buffer(ArrayBuffer::Create(aCx, authenticatorData, aRv));
    110  if (aRv.Failed()) {
    111    return;
    112  }
    113  aValue.set(buffer);
    114 }
    115 
    116 nsresult AuthenticatorAttestationResponse::GetPublicKeyBytes(
    117    nsTArray<uint8_t>& aPublicKeyBytes) {
    118  if (!mAttestationObjectParsed) {
    119    nsresult rv = authrs_webauthn_att_obj_constructor(
    120        mAttestationObject, /* anonymize */ false,
    121        getter_AddRefs(mAttestationObjectParsed));
    122    if (NS_FAILED(rv)) {
    123      return rv;
    124    }
    125  }
    126  nsresult rv = mAttestationObjectParsed->GetPublicKey(aPublicKeyBytes);
    127  if (NS_FAILED(rv)) {
    128    return rv;
    129  }
    130  return NS_OK;
    131 }
    132 
    133 void AuthenticatorAttestationResponse::GetPublicKey(
    134    JSContext* aCx, JS::MutableHandle<JSObject*> aValue, ErrorResult& aRv) {
    135  nsTArray<uint8_t> publicKey;
    136  nsresult rv = GetPublicKeyBytes(publicKey);
    137  if (NS_FAILED(rv)) {
    138    if (rv == NS_ERROR_NOT_AVAILABLE) {
    139      aValue.set(nullptr);
    140    } else {
    141      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    142    }
    143    return;
    144  }
    145 
    146  JS::Heap<JSObject*> buffer(ArrayBuffer::Create(aCx, publicKey, aRv));
    147  if (aRv.Failed()) {
    148    return;
    149  }
    150  aValue.set(buffer);
    151 }
    152 
    153 COSEAlgorithmIdentifier AuthenticatorAttestationResponse::GetPublicKeyAlgorithm(
    154    ErrorResult& aRv) {
    155  if (!mAttestationObjectParsed) {
    156    nsresult rv = authrs_webauthn_att_obj_constructor(
    157        mAttestationObject, false, getter_AddRefs(mAttestationObjectParsed));
    158    if (NS_FAILED(rv)) {
    159      aRv.Throw(rv);
    160      return 0;
    161    }
    162  }
    163 
    164  COSEAlgorithmIdentifier alg;
    165  mAttestationObjectParsed->GetPublicKeyAlgorithm(&alg);
    166  return alg;
    167 }
    168 
    169 void AuthenticatorAttestationResponse::ToJSON(
    170    AuthenticatorAttestationResponseJSON& aJSON, ErrorResult& aError) {
    171  nsAutoCString clientDataJSONBase64;
    172  nsresult rv = Base64URLEncode(
    173      mClientDataJSON.Length(),
    174      reinterpret_cast<const uint8_t*>(mClientDataJSON.get()),
    175      mozilla::Base64URLEncodePaddingPolicy::Omit, clientDataJSONBase64);
    176  // This will only fail if the length is so long that it overflows 32-bits
    177  // when calculating the encoded size.
    178  if (NS_FAILED(rv)) {
    179    aError.ThrowDataError("clientDataJSON too long");
    180    return;
    181  }
    182  aJSON.mClientDataJSON.Assign(NS_ConvertUTF8toUTF16(clientDataJSONBase64));
    183 
    184  nsTArray<uint8_t> authenticatorData;
    185  rv = GetAuthenticatorDataBytes(authenticatorData);
    186  if (NS_FAILED(rv)) {
    187    aError.ThrowUnknownError("could not get authenticatorData");
    188    return;
    189  }
    190  nsAutoCString authenticatorDataBase64;
    191  rv = Base64URLEncode(authenticatorData.Length(), authenticatorData.Elements(),
    192                       mozilla::Base64URLEncodePaddingPolicy::Omit,
    193                       authenticatorDataBase64);
    194  if (NS_FAILED(rv)) {
    195    aError.ThrowDataError("authenticatorData too long");
    196    return;
    197  }
    198  aJSON.mAuthenticatorData.Assign(
    199      NS_ConvertUTF8toUTF16(authenticatorDataBase64));
    200 
    201  if (!aJSON.mTransports.Assign(mTransports, mozilla::fallible)) {
    202    aError.Throw(NS_ERROR_OUT_OF_MEMORY);
    203    return;
    204  }
    205 
    206  nsTArray<uint8_t> publicKeyBytes;
    207  rv = GetPublicKeyBytes(publicKeyBytes);
    208  if (NS_SUCCEEDED(rv)) {
    209    nsAutoCString publicKeyBytesBase64;
    210    rv = Base64URLEncode(publicKeyBytes.Length(), publicKeyBytes.Elements(),
    211                         mozilla::Base64URLEncodePaddingPolicy::Omit,
    212                         publicKeyBytesBase64);
    213    if (NS_FAILED(rv)) {
    214      aError.ThrowDataError("publicKey too long");
    215      return;
    216    }
    217    aJSON.mPublicKey.Construct(NS_ConvertUTF8toUTF16(publicKeyBytesBase64));
    218  } else if (rv != NS_ERROR_NOT_AVAILABLE) {
    219    aError.ThrowUnknownError("could not get publicKey");
    220    return;
    221  }
    222 
    223  COSEAlgorithmIdentifier publicKeyAlgorithm = GetPublicKeyAlgorithm(aError);
    224  if (aError.Failed()) {
    225    aError.ThrowUnknownError("could not get publicKeyAlgorithm");
    226    return;
    227  }
    228  aJSON.mPublicKeyAlgorithm = publicKeyAlgorithm;
    229 
    230  nsAutoCString attestationObjectBase64;
    231  rv = Base64URLEncode(
    232      mAttestationObject.Length(), mAttestationObject.Elements(),
    233      mozilla::Base64URLEncodePaddingPolicy::Omit, attestationObjectBase64);
    234  if (NS_FAILED(rv)) {
    235    aError.ThrowDataError("attestationObject too long");
    236    return;
    237  }
    238  aJSON.mAttestationObject.Assign(
    239      NS_ConvertUTF8toUTF16(attestationObjectBase64));
    240 }
    241 
    242 }  // namespace mozilla::dom