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/. */
7 #include "AuthrsBridge_ffi.h"
8 #include "mozilla/Base64.h"
9 #include "mozilla/HoldDropJSObjects.h"
10 #include "mozilla/dom/AuthenticatorAttestationResponse.h"
11 #include "mozilla/dom/WebAuthenticationBinding.h"
13 namespace mozilla::dom
{
15 NS_IMPL_CYCLE_COLLECTION_CLASS(AuthenticatorAttestationResponse
)
16 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(
17 AuthenticatorAttestationResponse
, AuthenticatorResponse
)
18 tmp
->mAttestationObjectCachedObj
= nullptr;
19 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
21 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(AuthenticatorAttestationResponse
,
22 AuthenticatorResponse
)
23 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
24 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mAttestationObjectCachedObj
)
25 NS_IMPL_CYCLE_COLLECTION_TRACE_END
27 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(
28 AuthenticatorAttestationResponse
, AuthenticatorResponse
)
29 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
31 NS_IMPL_ADDREF_INHERITED(AuthenticatorAttestationResponse
,
32 AuthenticatorResponse
)
33 NS_IMPL_RELEASE_INHERITED(AuthenticatorAttestationResponse
,
34 AuthenticatorResponse
)
36 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AuthenticatorAttestationResponse
)
37 NS_INTERFACE_MAP_END_INHERITING(AuthenticatorResponse
)
39 AuthenticatorAttestationResponse::AuthenticatorAttestationResponse(
40 nsPIDOMWindowInner
* aParent
)
41 : AuthenticatorResponse(aParent
), mAttestationObjectCachedObj(nullptr) {
42 mozilla::HoldJSObjects(this);
45 AuthenticatorAttestationResponse::~AuthenticatorAttestationResponse() {
46 mozilla::DropJSObjects(this);
49 JSObject
* AuthenticatorAttestationResponse::WrapObject(
50 JSContext
* aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
51 return AuthenticatorAttestationResponse_Binding::Wrap(aCx
, this, aGivenProto
);
54 void AuthenticatorAttestationResponse::GetAttestationObject(
55 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aValue
, ErrorResult
& aRv
) {
56 if (!mAttestationObjectCachedObj
) {
57 mAttestationObjectCachedObj
=
58 ArrayBuffer::Create(aCx
, mAttestationObject
, aRv
);
63 aValue
.set(mAttestationObjectCachedObj
);
66 void AuthenticatorAttestationResponse::SetAttestationObject(
67 const nsTArray
<uint8_t>& aBuffer
) {
68 mAttestationObject
.Assign(aBuffer
);
71 void AuthenticatorAttestationResponse::GetTransports(
72 nsTArray
<nsString
>& aTransports
) {
73 aTransports
.Assign(mTransports
);
76 void AuthenticatorAttestationResponse::SetTransports(
77 const nsTArray
<nsString
>& aTransports
) {
78 mTransports
.Assign(aTransports
);
81 nsresult
AuthenticatorAttestationResponse::GetAuthenticatorDataBytes(
82 nsTArray
<uint8_t>& aAuthenticatorData
) {
83 if (!mAttestationObjectParsed
) {
84 nsresult rv
= authrs_webauthn_att_obj_constructor(
85 mAttestationObject
, /* anonymize */ false,
86 getter_AddRefs(mAttestationObjectParsed
));
92 mAttestationObjectParsed
->GetAuthenticatorData(aAuthenticatorData
);
99 void AuthenticatorAttestationResponse::GetAuthenticatorData(
100 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aValue
, ErrorResult
& aRv
) {
101 nsTArray
<uint8_t> authenticatorData
;
102 nsresult rv
= GetAuthenticatorDataBytes(authenticatorData
);
108 JS::Heap
<JSObject
*> buffer(ArrayBuffer::Create(aCx
, authenticatorData
, aRv
));
115 nsresult
AuthenticatorAttestationResponse::GetPublicKeyBytes(
116 nsTArray
<uint8_t>& aPublicKeyBytes
) {
117 if (!mAttestationObjectParsed
) {
118 nsresult rv
= authrs_webauthn_att_obj_constructor(
119 mAttestationObject
, /* anonymize */ false,
120 getter_AddRefs(mAttestationObjectParsed
));
125 nsresult rv
= mAttestationObjectParsed
->GetPublicKey(aPublicKeyBytes
);
132 void AuthenticatorAttestationResponse::GetPublicKey(
133 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aValue
, ErrorResult
& aRv
) {
134 nsTArray
<uint8_t> publicKey
;
135 nsresult rv
= GetPublicKeyBytes(publicKey
);
137 if (rv
== NS_ERROR_NOT_AVAILABLE
) {
140 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
145 JS::Heap
<JSObject
*> buffer(ArrayBuffer::Create(aCx
, publicKey
, aRv
));
152 COSEAlgorithmIdentifier
AuthenticatorAttestationResponse::GetPublicKeyAlgorithm(
154 if (!mAttestationObjectParsed
) {
155 nsresult rv
= authrs_webauthn_att_obj_constructor(
156 mAttestationObject
, false, getter_AddRefs(mAttestationObjectParsed
));
163 COSEAlgorithmIdentifier alg
;
164 mAttestationObjectParsed
->GetPublicKeyAlgorithm(&alg
);
168 void AuthenticatorAttestationResponse::ToJSON(
169 AuthenticatorAttestationResponseJSON
& aJSON
, ErrorResult
& aError
) {
170 nsAutoCString clientDataJSONBase64
;
171 nsresult rv
= Base64URLEncode(
172 mClientDataJSON
.Length(),
173 reinterpret_cast<const uint8_t*>(mClientDataJSON
.get()),
174 mozilla::Base64URLEncodePaddingPolicy::Omit
, clientDataJSONBase64
);
175 // This will only fail if the length is so long that it overflows 32-bits
176 // when calculating the encoded size.
178 aError
.ThrowDataError("clientDataJSON too long");
181 aJSON
.mClientDataJSON
.Assign(NS_ConvertUTF8toUTF16(clientDataJSONBase64
));
183 nsTArray
<uint8_t> authenticatorData
;
184 rv
= GetAuthenticatorDataBytes(authenticatorData
);
186 aError
.ThrowUnknownError("could not get authenticatorData");
189 nsAutoCString authenticatorDataBase64
;
190 rv
= Base64URLEncode(authenticatorData
.Length(), authenticatorData
.Elements(),
191 mozilla::Base64URLEncodePaddingPolicy::Omit
,
192 authenticatorDataBase64
);
194 aError
.ThrowDataError("authenticatorData too long");
197 aJSON
.mAuthenticatorData
.Assign(
198 NS_ConvertUTF8toUTF16(authenticatorDataBase64
));
200 if (!aJSON
.mTransports
.Assign(mTransports
, mozilla::fallible
)) {
201 aError
.Throw(NS_ERROR_OUT_OF_MEMORY
);
205 nsTArray
<uint8_t> publicKeyBytes
;
206 rv
= GetPublicKeyBytes(publicKeyBytes
);
207 if (NS_SUCCEEDED(rv
)) {
208 nsAutoCString publicKeyBytesBase64
;
209 rv
= Base64URLEncode(publicKeyBytes
.Length(), publicKeyBytes
.Elements(),
210 mozilla::Base64URLEncodePaddingPolicy::Omit
,
211 publicKeyBytesBase64
);
213 aError
.ThrowDataError("publicKey too long");
216 aJSON
.mPublicKey
.Construct(NS_ConvertUTF8toUTF16(publicKeyBytesBase64
));
217 } else if (rv
!= NS_ERROR_NOT_AVAILABLE
) {
218 aError
.ThrowUnknownError("could not get publicKey");
222 COSEAlgorithmIdentifier publicKeyAlgorithm
= GetPublicKeyAlgorithm(aError
);
223 if (aError
.Failed()) {
224 aError
.ThrowUnknownError("could not get publicKeyAlgorithm");
227 aJSON
.mPublicKeyAlgorithm
= publicKeyAlgorithm
;
229 nsAutoCString attestationObjectBase64
;
230 rv
= Base64URLEncode(
231 mAttestationObject
.Length(), mAttestationObject
.Elements(),
232 mozilla::Base64URLEncodePaddingPolicy::Omit
, attestationObjectBase64
);
234 aError
.ThrowDataError("attestationObject too long");
237 aJSON
.mAttestationObject
.Assign(
238 NS_ConvertUTF8toUTF16(attestationObjectBase64
));
241 } // namespace mozilla::dom