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