/src/mozilla-central/dom/prio/PrioEncoder.cpp
Line | Count | Source (jump to first uncovered line) |
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/ClearOnShutdown.h" |
8 | | #include "mozilla/Preferences.h" |
9 | | #include "mozilla/ScopeExit.h" |
10 | | #include "mozilla/Services.h" |
11 | | #include "mozilla/TextUtils.h" |
12 | | |
13 | | #include "mozilla/dom/ToJSValue.h" |
14 | | |
15 | | #include "PrioEncoder.h" |
16 | | |
17 | | namespace mozilla { |
18 | | namespace dom { |
19 | | |
20 | | /* static */ StaticRefPtr<PrioEncoder> PrioEncoder::sSingleton; |
21 | | |
22 | | /* static */ PublicKey PrioEncoder::sPublicKeyA = nullptr; |
23 | | /* static */ PublicKey PrioEncoder::sPublicKeyB = nullptr; |
24 | | |
25 | 0 | PrioEncoder::PrioEncoder() = default; |
26 | | PrioEncoder::~PrioEncoder() |
27 | 0 | { |
28 | 0 | if (sPublicKeyA) { |
29 | 0 | PublicKey_clear(sPublicKeyA); |
30 | 0 | sPublicKeyA = nullptr; |
31 | 0 | } |
32 | 0 |
|
33 | 0 | if (sPublicKeyB) { |
34 | 0 | PublicKey_clear(sPublicKeyB); |
35 | 0 | sPublicKeyB = nullptr; |
36 | 0 | } |
37 | 0 |
|
38 | 0 | Prio_clear(); |
39 | 0 | } |
40 | | |
41 | | /* static */ void |
42 | | PrioEncoder::Encode(GlobalObject& aGlobal, |
43 | | const nsCString& aBatchID, |
44 | | const PrioParams& aPrioParams, |
45 | | RootedDictionary<PrioEncodedData>& aData, |
46 | | ErrorResult& aRv) |
47 | 0 | { |
48 | 0 | nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); |
49 | 0 | if (!global) { |
50 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
51 | 0 | return; |
52 | 0 | } |
53 | 0 | |
54 | 0 | SECStatus prio_rv = SECSuccess; |
55 | 0 |
|
56 | 0 | if (!sSingleton) { |
57 | 0 | nsresult rv; |
58 | 0 |
|
59 | 0 | nsAutoCStringN<CURVE25519_KEY_LEN_HEX + 1> prioKeyA; |
60 | 0 | rv = Preferences::GetCString("prio.publicKeyA", prioKeyA); |
61 | 0 | if (NS_FAILED(rv)) { |
62 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
63 | 0 | return; |
64 | 0 | } |
65 | 0 | |
66 | 0 | nsAutoCStringN<CURVE25519_KEY_LEN_HEX + 1> prioKeyB; |
67 | 0 | rv = Preferences::GetCString("prio.publicKeyB", prioKeyB); |
68 | 0 | if (NS_FAILED(rv)) { |
69 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
70 | 0 | return; |
71 | 0 | } |
72 | 0 | |
73 | 0 | // Check that both public keys are of the right length |
74 | 0 | // and contain only hex digits 0-9a-fA-f |
75 | 0 | if (!PrioEncoder::IsValidHexPublicKey(prioKeyA) |
76 | 0 | || !PrioEncoder::IsValidHexPublicKey(prioKeyB)) { |
77 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
78 | 0 | return; |
79 | 0 | } |
80 | 0 | |
81 | 0 | prio_rv = Prio_init(); |
82 | 0 |
|
83 | 0 | if (prio_rv != SECSuccess) { |
84 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
85 | 0 | return; |
86 | 0 | } |
87 | 0 | |
88 | 0 | prio_rv = PublicKey_import_hex(&sPublicKeyA, |
89 | 0 | reinterpret_cast<const unsigned char*>(prioKeyA.BeginReading()), |
90 | 0 | CURVE25519_KEY_LEN_HEX); |
91 | 0 | if (prio_rv != SECSuccess) { |
92 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
93 | 0 | return; |
94 | 0 | } |
95 | 0 | |
96 | 0 | prio_rv = PublicKey_import_hex(&sPublicKeyB, |
97 | 0 | reinterpret_cast<const unsigned char*>(prioKeyB.BeginReading()), |
98 | 0 | CURVE25519_KEY_LEN_HEX); |
99 | 0 | if (prio_rv != SECSuccess) { |
100 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
101 | 0 | return; |
102 | 0 | } |
103 | 0 | |
104 | 0 | sSingleton = new PrioEncoder(); |
105 | 0 | ClearOnShutdown(&sSingleton); |
106 | 0 | } |
107 | 0 |
|
108 | 0 | bool dataItems[] = { |
109 | 0 | aPrioParams.mBrowserIsUserDefault, |
110 | 0 | aPrioParams.mNewTabPageEnabled, |
111 | 0 | aPrioParams.mPdfViewerUsed, |
112 | 0 | }; |
113 | 0 |
|
114 | 0 | PrioConfig prioConfig = PrioConfig_new(mozilla::ArrayLength(dataItems), |
115 | 0 | sPublicKeyA, |
116 | 0 | sPublicKeyB, |
117 | 0 | reinterpret_cast<const unsigned char*>(aBatchID.BeginReading()), |
118 | 0 | aBatchID.Length()); |
119 | 0 |
|
120 | 0 | if (!prioConfig) { |
121 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
122 | 0 | return; |
123 | 0 | } |
124 | 0 | |
125 | 0 | auto configGuard = MakeScopeExit([&] { |
126 | 0 | PrioConfig_clear(prioConfig); |
127 | 0 | }); |
128 | 0 |
|
129 | 0 | unsigned char* forServerA = nullptr; |
130 | 0 | unsigned int lenA = 0; |
131 | 0 | unsigned char* forServerB = nullptr; |
132 | 0 | unsigned int lenB = 0; |
133 | 0 |
|
134 | 0 | prio_rv = PrioClient_encode(prioConfig, |
135 | 0 | dataItems, |
136 | 0 | &forServerA, |
137 | 0 | &lenA, |
138 | 0 | &forServerB, |
139 | 0 | &lenB); |
140 | 0 |
|
141 | 0 | nsTArray<uint8_t> arrayForServerA; |
142 | 0 | nsTArray<uint8_t> arrayForServerB; |
143 | 0 |
|
144 | 0 | if (!arrayForServerA.AppendElements(reinterpret_cast<uint8_t*>(forServerA), |
145 | 0 | lenA, |
146 | 0 | fallible)) { |
147 | 0 | aRv.Throw(NS_ERROR_OUT_OF_MEMORY); |
148 | 0 | return; |
149 | 0 | } |
150 | 0 | |
151 | 0 | free(forServerA); |
152 | 0 |
|
153 | 0 | if (!arrayForServerB.AppendElements(reinterpret_cast<uint8_t*>(forServerB), |
154 | 0 | lenB, |
155 | 0 | fallible)) { |
156 | 0 | aRv.Throw(NS_ERROR_OUT_OF_MEMORY); |
157 | 0 | return ; |
158 | 0 | } |
159 | 0 | |
160 | 0 | free(forServerB); |
161 | 0 |
|
162 | 0 | if (prio_rv != SECSuccess) { |
163 | 0 | aRv.Throw(NS_ERROR_FAILURE); |
164 | 0 | return; |
165 | 0 | } |
166 | 0 | |
167 | 0 | JS::Rooted<JS::Value> valueA(aGlobal.Context()); |
168 | 0 | if (!ToJSValue(aGlobal.Context(), TypedArrayCreator<Uint8Array>(arrayForServerA), &valueA)) { |
169 | 0 | aRv.Throw(NS_ERROR_OUT_OF_MEMORY); |
170 | 0 | return; |
171 | 0 | } |
172 | 0 | |
173 | 0 | aData.mA.Construct().Init(&valueA.toObject()); |
174 | 0 |
|
175 | 0 | JS::Rooted<JS::Value> valueB(aGlobal.Context()); |
176 | 0 | if (!ToJSValue(aGlobal.Context(), TypedArrayCreator<Uint8Array>(arrayForServerB), &valueB)) { |
177 | 0 | aRv.Throw(NS_ERROR_OUT_OF_MEMORY); |
178 | 0 | return; |
179 | 0 | } |
180 | 0 | |
181 | 0 | aData.mB.Construct().Init(&valueB.toObject()); |
182 | 0 | } |
183 | | |
184 | | bool |
185 | | PrioEncoder::IsValidHexPublicKey(mozilla::Span<const char> aStr) |
186 | 0 | { |
187 | 0 | if (aStr.Length() != CURVE25519_KEY_LEN_HEX) { |
188 | 0 | return false; |
189 | 0 | } |
190 | 0 | |
191 | 0 | for (auto c : aStr) { |
192 | 0 | if (!IsAsciiHexDigit(c)) { |
193 | 0 | return false; |
194 | 0 | } |
195 | 0 | } |
196 | 0 |
|
197 | 0 | return true; |
198 | 0 | } |
199 | | |
200 | | } // dom namespace |
201 | | } // mozilla namespace |