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
= ArrayBuffer::Create(
58 aCx
, mAttestationObject
.Length(), mAttestationObject
.Elements());
59 if (!mAttestationObjectCachedObj
) {
60 aRv
.NoteJSContextException(aCx
);
64 aValue
.set(mAttestationObjectCachedObj
);
67 void AuthenticatorAttestationResponse::SetAttestationObject(
68 const nsTArray
<uint8_t>& aBuffer
) {
69 mAttestationObject
.Assign(aBuffer
);
72 void AuthenticatorAttestationResponse::GetTransports(
73 nsTArray
<nsString
>& aTransports
) {
74 aTransports
.Assign(mTransports
);
77 void AuthenticatorAttestationResponse::SetTransports(
78 const nsTArray
<nsString
>& aTransports
) {
79 mTransports
.Assign(aTransports
);
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
));
93 mAttestationObjectParsed
->GetAuthenticatorData(aAuthenticatorData
);
100 void AuthenticatorAttestationResponse::GetAuthenticatorData(
101 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aValue
, ErrorResult
& aRv
) {
102 nsTArray
<uint8_t> authenticatorData
;
103 nsresult rv
= GetAuthenticatorDataBytes(authenticatorData
);
109 JS::Heap
<JSObject
*> buffer(ArrayBuffer::Create(
110 aCx
, authenticatorData
.Length(), authenticatorData
.Elements()));
112 aRv
.NoteJSContextException(aCx
);
118 nsresult
AuthenticatorAttestationResponse::GetPublicKeyBytes(
119 nsTArray
<uint8_t>& aPublicKeyBytes
) {
120 if (!mAttestationObjectParsed
) {
121 nsresult rv
= authrs_webauthn_att_obj_constructor(
122 mAttestationObject
, /* anonymize */ false,
123 getter_AddRefs(mAttestationObjectParsed
));
128 nsresult rv
= mAttestationObjectParsed
->GetPublicKey(aPublicKeyBytes
);
135 void AuthenticatorAttestationResponse::GetPublicKey(
136 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aValue
, ErrorResult
& aRv
) {
137 nsTArray
<uint8_t> publicKey
;
138 nsresult rv
= GetPublicKeyBytes(publicKey
);
140 if (rv
== NS_ERROR_NOT_AVAILABLE
) {
143 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
148 JS::Heap
<JSObject
*> buffer(
149 ArrayBuffer::Create(aCx
, publicKey
.Length(), publicKey
.Elements()));
151 aRv
.NoteJSContextException(aCx
);
157 COSEAlgorithmIdentifier
AuthenticatorAttestationResponse::GetPublicKeyAlgorithm(
159 if (!mAttestationObjectParsed
) {
160 nsresult rv
= authrs_webauthn_att_obj_constructor(
161 mAttestationObject
, false, getter_AddRefs(mAttestationObjectParsed
));
168 COSEAlgorithmIdentifier alg
;
169 mAttestationObjectParsed
->GetPublicKeyAlgorithm(&alg
);
173 void AuthenticatorAttestationResponse::ToJSON(
174 AuthenticatorAttestationResponseJSON
& aJSON
, ErrorResult
& aError
) {
175 nsAutoCString clientDataJSONBase64
;
176 nsresult rv
= Base64URLEncode(
177 mClientDataJSON
.Length(),
178 reinterpret_cast<const uint8_t*>(mClientDataJSON
.get()),
179 mozilla::Base64URLEncodePaddingPolicy::Omit
, clientDataJSONBase64
);
180 // This will only fail if the length is so long that it overflows 32-bits
181 // when calculating the encoded size.
183 aError
.ThrowDataError("clientDataJSON too long");
186 aJSON
.mClientDataJSON
.Assign(NS_ConvertUTF8toUTF16(clientDataJSONBase64
));
188 nsTArray
<uint8_t> authenticatorData
;
189 rv
= GetAuthenticatorDataBytes(authenticatorData
);
191 aError
.ThrowUnknownError("could not get authenticatorData");
194 nsAutoCString authenticatorDataBase64
;
195 rv
= Base64URLEncode(authenticatorData
.Length(), authenticatorData
.Elements(),
196 mozilla::Base64URLEncodePaddingPolicy::Omit
,
197 authenticatorDataBase64
);
199 aError
.ThrowDataError("authenticatorData too long");
202 aJSON
.mAuthenticatorData
.Assign(
203 NS_ConvertUTF8toUTF16(authenticatorDataBase64
));
205 if (!aJSON
.mTransports
.Assign(mTransports
, mozilla::fallible
)) {
206 aError
.Throw(NS_ERROR_OUT_OF_MEMORY
);
210 nsTArray
<uint8_t> publicKeyBytes
;
211 rv
= GetPublicKeyBytes(publicKeyBytes
);
212 if (NS_SUCCEEDED(rv
)) {
213 nsAutoCString publicKeyBytesBase64
;
214 rv
= Base64URLEncode(publicKeyBytes
.Length(), publicKeyBytes
.Elements(),
215 mozilla::Base64URLEncodePaddingPolicy::Omit
,
216 publicKeyBytesBase64
);
218 aError
.ThrowDataError("publicKey too long");
221 aJSON
.mPublicKey
.Construct(NS_ConvertUTF8toUTF16(publicKeyBytesBase64
));
222 } else if (rv
!= NS_ERROR_NOT_AVAILABLE
) {
223 aError
.ThrowUnknownError("could not get publicKey");
227 COSEAlgorithmIdentifier publicKeyAlgorithm
= GetPublicKeyAlgorithm(aError
);
228 if (aError
.Failed()) {
229 aError
.ThrowUnknownError("could not get publicKeyAlgorithm");
232 aJSON
.mPublicKeyAlgorithm
= publicKeyAlgorithm
;
234 nsAutoCString attestationObjectBase64
;
235 rv
= Base64URLEncode(
236 mAttestationObject
.Length(), mAttestationObject
.Elements(),
237 mozilla::Base64URLEncodePaddingPolicy::Omit
, attestationObjectBase64
);
239 aError
.ThrowDataError("attestationObject too long");
242 aJSON
.mAttestationObject
.Assign(
243 NS_ConvertUTF8toUTF16(attestationObjectBase64
));
246 } // namespace mozilla::dom