Bug 1874684 - Part 6: Limit day length calculations to safe integers. r=mgaudet
[gecko.git] / dom / webauthn / AuthenticatorAttestationResponse.cpp
blob7fe493dae32adfab1e37dfd031b810084d294114
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);
59 if (aRv.Failed()) {
60 return;
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));
87 if (NS_FAILED(rv)) {
88 return rv;
91 nsresult rv =
92 mAttestationObjectParsed->GetAuthenticatorData(aAuthenticatorData);
93 if (NS_FAILED(rv)) {
94 return rv;
96 return NS_OK;
99 void AuthenticatorAttestationResponse::GetAuthenticatorData(
100 JSContext* aCx, JS::MutableHandle<JSObject*> aValue, ErrorResult& aRv) {
101 nsTArray<uint8_t> authenticatorData;
102 nsresult rv = GetAuthenticatorDataBytes(authenticatorData);
103 if (NS_FAILED(rv)) {
104 aRv.Throw(rv);
105 return;
108 JS::Heap<JSObject*> buffer(ArrayBuffer::Create(aCx, authenticatorData, aRv));
109 if (aRv.Failed()) {
110 return;
112 aValue.set(buffer);
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));
121 if (NS_FAILED(rv)) {
122 return rv;
125 nsresult rv = mAttestationObjectParsed->GetPublicKey(aPublicKeyBytes);
126 if (NS_FAILED(rv)) {
127 return rv;
129 return NS_OK;
132 void AuthenticatorAttestationResponse::GetPublicKey(
133 JSContext* aCx, JS::MutableHandle<JSObject*> aValue, ErrorResult& aRv) {
134 nsTArray<uint8_t> publicKey;
135 nsresult rv = GetPublicKeyBytes(publicKey);
136 if (NS_FAILED(rv)) {
137 if (rv == NS_ERROR_NOT_AVAILABLE) {
138 aValue.set(nullptr);
139 } else {
140 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
142 return;
145 JS::Heap<JSObject*> buffer(ArrayBuffer::Create(aCx, publicKey, aRv));
146 if (aRv.Failed()) {
147 return;
149 aValue.set(buffer);
152 COSEAlgorithmIdentifier AuthenticatorAttestationResponse::GetPublicKeyAlgorithm(
153 ErrorResult& aRv) {
154 if (!mAttestationObjectParsed) {
155 nsresult rv = authrs_webauthn_att_obj_constructor(
156 mAttestationObject, false, getter_AddRefs(mAttestationObjectParsed));
157 if (NS_FAILED(rv)) {
158 aRv.Throw(rv);
159 return 0;
163 COSEAlgorithmIdentifier alg;
164 mAttestationObjectParsed->GetPublicKeyAlgorithm(&alg);
165 return 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.
177 if (NS_FAILED(rv)) {
178 aError.ThrowDataError("clientDataJSON too long");
179 return;
181 aJSON.mClientDataJSON.Assign(NS_ConvertUTF8toUTF16(clientDataJSONBase64));
183 nsTArray<uint8_t> authenticatorData;
184 rv = GetAuthenticatorDataBytes(authenticatorData);
185 if (NS_FAILED(rv)) {
186 aError.ThrowUnknownError("could not get authenticatorData");
187 return;
189 nsAutoCString authenticatorDataBase64;
190 rv = Base64URLEncode(authenticatorData.Length(), authenticatorData.Elements(),
191 mozilla::Base64URLEncodePaddingPolicy::Omit,
192 authenticatorDataBase64);
193 if (NS_FAILED(rv)) {
194 aError.ThrowDataError("authenticatorData too long");
195 return;
197 aJSON.mAuthenticatorData.Assign(
198 NS_ConvertUTF8toUTF16(authenticatorDataBase64));
200 if (!aJSON.mTransports.Assign(mTransports, mozilla::fallible)) {
201 aError.Throw(NS_ERROR_OUT_OF_MEMORY);
202 return;
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);
212 if (NS_FAILED(rv)) {
213 aError.ThrowDataError("publicKey too long");
214 return;
216 aJSON.mPublicKey.Construct(NS_ConvertUTF8toUTF16(publicKeyBytesBase64));
217 } else if (rv != NS_ERROR_NOT_AVAILABLE) {
218 aError.ThrowUnknownError("could not get publicKey");
219 return;
222 COSEAlgorithmIdentifier publicKeyAlgorithm = GetPublicKeyAlgorithm(aError);
223 if (aError.Failed()) {
224 aError.ThrowUnknownError("could not get publicKeyAlgorithm");
225 return;
227 aJSON.mPublicKeyAlgorithm = publicKeyAlgorithm;
229 nsAutoCString attestationObjectBase64;
230 rv = Base64URLEncode(
231 mAttestationObject.Length(), mAttestationObject.Elements(),
232 mozilla::Base64URLEncodePaddingPolicy::Omit, attestationObjectBase64);
233 if (NS_FAILED(rv)) {
234 aError.ThrowDataError("attestationObject too long");
235 return;
237 aJSON.mAttestationObject.Assign(
238 NS_ConvertUTF8toUTF16(attestationObjectBase64));
241 } // namespace mozilla::dom