|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* vim: set sw=4 ts=8 et ft=cpp: */ |
|
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 <fcntl.h> |
|
8 #include <sys/stat.h> |
|
9 |
|
10 #undef CHROMIUM_LOG |
|
11 #if defined(MOZ_WIDGET_GONK) |
|
12 #include <android/log.h> |
|
13 #define CHROMIUM_LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk", args) |
|
14 #else |
|
15 #define CHROMIUM_LOG(args...) printf(args); |
|
16 #endif |
|
17 |
|
18 #include "KeyStore.h" |
|
19 #include "jsfriendapi.h" |
|
20 #include "MainThreadUtils.h" // For NS_IsMainThread. |
|
21 |
|
22 #include "plbase64.h" |
|
23 #include "certdb.h" |
|
24 #include "ScopedNSSTypes.h" |
|
25 |
|
26 using namespace mozilla::ipc; |
|
27 |
|
28 namespace mozilla { |
|
29 namespace ipc { |
|
30 |
|
31 static const char* KEYSTORE_SOCKET_NAME = "keystore"; |
|
32 static const char* KEYSTORE_SOCKET_PATH = "/dev/socket/keystore"; |
|
33 |
|
34 int |
|
35 KeyStoreConnector::Create() |
|
36 { |
|
37 MOZ_ASSERT(!NS_IsMainThread()); |
|
38 |
|
39 int fd; |
|
40 |
|
41 unlink(KEYSTORE_SOCKET_PATH); |
|
42 |
|
43 fd = socket(AF_LOCAL, SOCK_STREAM, 0); |
|
44 |
|
45 if (fd < 0) { |
|
46 NS_WARNING("Could not open keystore socket!"); |
|
47 return -1; |
|
48 } |
|
49 |
|
50 return fd; |
|
51 } |
|
52 |
|
53 bool |
|
54 KeyStoreConnector::CreateAddr(bool aIsServer, |
|
55 socklen_t& aAddrSize, |
|
56 sockaddr_any& aAddr, |
|
57 const char* aAddress) |
|
58 { |
|
59 // Keystore socket must be server |
|
60 MOZ_ASSERT(aIsServer); |
|
61 |
|
62 aAddr.un.sun_family = AF_LOCAL; |
|
63 if(strlen(KEYSTORE_SOCKET_PATH) > sizeof(aAddr.un.sun_path)) { |
|
64 NS_WARNING("Address too long for socket struct!"); |
|
65 return false; |
|
66 } |
|
67 strcpy((char*)&aAddr.un.sun_path, KEYSTORE_SOCKET_PATH); |
|
68 aAddrSize = strlen(KEYSTORE_SOCKET_PATH) + offsetof(struct sockaddr_un, sun_path) + 1; |
|
69 |
|
70 return true; |
|
71 } |
|
72 |
|
73 bool |
|
74 KeyStoreConnector::SetUp(int aFd) |
|
75 { |
|
76 return true; |
|
77 } |
|
78 |
|
79 bool |
|
80 KeyStoreConnector::SetUpListenSocket(int aFd) |
|
81 { |
|
82 // Allow access of wpa_supplicant(different user, differnt group) |
|
83 chmod(KEYSTORE_SOCKET_PATH, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH); |
|
84 |
|
85 return true; |
|
86 } |
|
87 |
|
88 void |
|
89 KeyStoreConnector::GetSocketAddr(const sockaddr_any& aAddr, |
|
90 nsAString& aAddrStr) |
|
91 { |
|
92 // Unused. |
|
93 MOZ_CRASH("This should never be called!"); |
|
94 } |
|
95 |
|
96 static char * |
|
97 get_cert_db_filename(void *arg, int vers) |
|
98 { |
|
99 static char keystoreDbPath[] = "/data/misc/wifi/keystore"; |
|
100 return keystoreDbPath; |
|
101 } |
|
102 |
|
103 KeyStore::KeyStore() |
|
104 { |
|
105 // Initial NSS |
|
106 certdb = CERT_GetDefaultCertDB(); |
|
107 |
|
108 Listen(); |
|
109 } |
|
110 |
|
111 void |
|
112 KeyStore::Shutdown() |
|
113 { |
|
114 mShutdown = true; |
|
115 CloseSocket(); |
|
116 } |
|
117 |
|
118 void |
|
119 KeyStore::Listen() |
|
120 { |
|
121 ListenSocket(new KeyStoreConnector()); |
|
122 |
|
123 ResetHandlerInfo(); |
|
124 } |
|
125 |
|
126 void |
|
127 KeyStore::ResetHandlerInfo() |
|
128 { |
|
129 mHandlerInfo.state = STATE_IDLE; |
|
130 mHandlerInfo.command = 0; |
|
131 mHandlerInfo.paramCount = 0; |
|
132 mHandlerInfo.commandPattern = nullptr; |
|
133 for (int i = 0; i < MAX_PARAM; i++) { |
|
134 mHandlerInfo.param[i].length = 0; |
|
135 memset(mHandlerInfo.param[i].data, 0, VALUE_SIZE); |
|
136 } |
|
137 } |
|
138 |
|
139 bool |
|
140 KeyStore::CheckSize(UnixSocketRawData *aMessage, size_t aExpectSize) |
|
141 { |
|
142 return (aMessage->mSize - aMessage->mCurrentWriteOffset >= aExpectSize) ? |
|
143 true : false; |
|
144 } |
|
145 |
|
146 bool |
|
147 KeyStore::ReadCommand(UnixSocketRawData *aMessage) |
|
148 { |
|
149 if (mHandlerInfo.state != STATE_IDLE) { |
|
150 NS_WARNING("Wrong state in ReadCommand()!"); |
|
151 return false; |
|
152 } |
|
153 |
|
154 if (!CheckSize(aMessage, 1)) { |
|
155 NS_WARNING("Data size error in ReadCommand()!"); |
|
156 return false; |
|
157 } |
|
158 |
|
159 mHandlerInfo.command = aMessage->mData[aMessage->mCurrentWriteOffset]; |
|
160 aMessage->mCurrentWriteOffset++; |
|
161 |
|
162 // Find corrsponding command pattern |
|
163 const struct ProtocolCommand *command = commands; |
|
164 while (command->command && command->command != mHandlerInfo.command) { |
|
165 command++; |
|
166 } |
|
167 |
|
168 if (!command->command) { |
|
169 NS_WARNING("Unsupported command!"); |
|
170 return false; |
|
171 } |
|
172 |
|
173 // Get command pattern. |
|
174 mHandlerInfo.commandPattern = command; |
|
175 if (command->paramNum) { |
|
176 // Read command parameter if needed. |
|
177 mHandlerInfo.state = STATE_READ_PARAM_LEN; |
|
178 } else { |
|
179 mHandlerInfo.state = STATE_PROCESSING; |
|
180 } |
|
181 |
|
182 return true; |
|
183 } |
|
184 |
|
185 bool |
|
186 KeyStore::ReadLength(UnixSocketRawData *aMessage) |
|
187 { |
|
188 if (mHandlerInfo.state != STATE_READ_PARAM_LEN) { |
|
189 NS_WARNING("Wrong state in ReadLength()!"); |
|
190 return false; |
|
191 } |
|
192 |
|
193 if (!CheckSize(aMessage, 2)) { |
|
194 NS_WARNING("Data size error in ReadLength()!"); |
|
195 return false; |
|
196 } |
|
197 |
|
198 // Read length of command parameter. |
|
199 unsigned short dataLength; |
|
200 memcpy(&dataLength, &aMessage->mData[aMessage->mCurrentWriteOffset], 2); |
|
201 aMessage->mCurrentWriteOffset += 2; |
|
202 mHandlerInfo.param[mHandlerInfo.paramCount].length = ntohs(dataLength); |
|
203 |
|
204 mHandlerInfo.state = STATE_READ_PARAM_DATA; |
|
205 |
|
206 return true; |
|
207 } |
|
208 |
|
209 bool |
|
210 KeyStore::ReadData(UnixSocketRawData *aMessage) |
|
211 { |
|
212 if (mHandlerInfo.state != STATE_READ_PARAM_DATA) { |
|
213 NS_WARNING("Wrong state in ReadData()!"); |
|
214 return false; |
|
215 } |
|
216 |
|
217 if (!CheckSize(aMessage, mHandlerInfo.param[mHandlerInfo.paramCount].length)) { |
|
218 NS_WARNING("Data size error in ReadData()!"); |
|
219 return false; |
|
220 } |
|
221 |
|
222 // Read command parameter. |
|
223 memcpy(mHandlerInfo.param[mHandlerInfo.paramCount].data, |
|
224 &aMessage->mData[aMessage->mCurrentWriteOffset], |
|
225 mHandlerInfo.param[mHandlerInfo.paramCount].length); |
|
226 aMessage->mCurrentWriteOffset += mHandlerInfo.param[mHandlerInfo.paramCount].length; |
|
227 mHandlerInfo.paramCount++; |
|
228 |
|
229 if (mHandlerInfo.paramCount == mHandlerInfo.commandPattern->paramNum) { |
|
230 mHandlerInfo.state = STATE_PROCESSING; |
|
231 } else { |
|
232 mHandlerInfo.state = STATE_READ_PARAM_LEN; |
|
233 } |
|
234 |
|
235 return true; |
|
236 } |
|
237 |
|
238 // Transform base64 certification data into DER format |
|
239 void |
|
240 KeyStore::FormatCaData(const uint8_t *aCaData, int aCaDataLength, |
|
241 const char *aName, const uint8_t **aFormatData, |
|
242 int &aFormatDataLength) |
|
243 { |
|
244 int bufSize = strlen(CA_BEGIN) + strlen(CA_END) + strlen(CA_TAILER) * 2 + |
|
245 strlen(aName) * 2 + aCaDataLength + aCaDataLength/CA_LINE_SIZE + 2; |
|
246 char *buf = (char *)malloc(bufSize); |
|
247 |
|
248 aFormatDataLength = bufSize; |
|
249 *aFormatData = (const uint8_t *)buf; |
|
250 |
|
251 char *ptr = buf; |
|
252 int len; |
|
253 |
|
254 // Create DER header. |
|
255 len = snprintf(ptr, bufSize, "%s%s%s", CA_BEGIN, aName, CA_TAILER); |
|
256 ptr += len; |
|
257 bufSize -= len; |
|
258 |
|
259 // Split base64 data in lines. |
|
260 int copySize; |
|
261 while (aCaDataLength > 0) { |
|
262 copySize = (aCaDataLength > CA_LINE_SIZE) ? CA_LINE_SIZE : aCaDataLength; |
|
263 |
|
264 memcpy(ptr, aCaData, copySize); |
|
265 ptr += copySize; |
|
266 aCaData += copySize; |
|
267 aCaDataLength -= copySize; |
|
268 bufSize -= copySize; |
|
269 |
|
270 *ptr = '\n'; |
|
271 ptr++; |
|
272 bufSize--; |
|
273 } |
|
274 |
|
275 // Create DEA tailer. |
|
276 snprintf(ptr, bufSize, "%s%s%s", CA_END, aName, CA_TAILER); |
|
277 } |
|
278 |
|
279 // Status response |
|
280 void |
|
281 KeyStore::SendResponse(ResponseCode aResponse) |
|
282 { |
|
283 if (aResponse == NO_RESPONSE) |
|
284 return; |
|
285 |
|
286 uint8_t response = (uint8_t)aResponse; |
|
287 UnixSocketRawData* data = new UnixSocketRawData((const void *)&response, 1); |
|
288 SendSocketData(data); |
|
289 } |
|
290 |
|
291 // Data response |
|
292 void |
|
293 KeyStore::SendData(const uint8_t *aData, int aLength) |
|
294 { |
|
295 unsigned short dataLength = htons(aLength); |
|
296 |
|
297 UnixSocketRawData* length = new UnixSocketRawData((const void *)&dataLength, 2); |
|
298 SendSocketData(length); |
|
299 |
|
300 UnixSocketRawData* data = new UnixSocketRawData((const void *)aData, aLength); |
|
301 SendSocketData(data); |
|
302 } |
|
303 |
|
304 void |
|
305 KeyStore::ReceiveSocketData(nsAutoPtr<UnixSocketRawData>& aMessage) |
|
306 { |
|
307 MOZ_ASSERT(NS_IsMainThread()); |
|
308 |
|
309 bool success = true; |
|
310 while (aMessage->mCurrentWriteOffset < aMessage->mSize || |
|
311 mHandlerInfo.state == STATE_PROCESSING) { |
|
312 switch (mHandlerInfo.state) { |
|
313 case STATE_IDLE: |
|
314 success = ReadCommand(aMessage); |
|
315 break; |
|
316 case STATE_READ_PARAM_LEN: |
|
317 success = ReadLength(aMessage); |
|
318 break; |
|
319 case STATE_READ_PARAM_DATA: |
|
320 success = ReadData(aMessage); |
|
321 break; |
|
322 case STATE_PROCESSING: |
|
323 success = false; |
|
324 if (mHandlerInfo.command == 'g') { |
|
325 // Get CA |
|
326 const uint8_t *certData; |
|
327 int certDataLength; |
|
328 const char *certName = (const char *)mHandlerInfo.param[0].data; |
|
329 |
|
330 // Get cert from NSS by name |
|
331 ScopedCERTCertificate cert(CERT_FindCertByNickname(certdb, certName)); |
|
332 if (!cert) { |
|
333 break; |
|
334 } |
|
335 |
|
336 char *certDER = PL_Base64Encode((const char *)cert->derCert.data, |
|
337 cert->derCert.len, nullptr); |
|
338 if (!certDER) { |
|
339 break; |
|
340 } |
|
341 |
|
342 FormatCaData((const uint8_t *)certDER, strlen(certDER), "CERTIFICATE", |
|
343 &certData, certDataLength); |
|
344 PL_strfree(certDER); |
|
345 |
|
346 SendResponse(SUCCESS); |
|
347 SendData(certData, certDataLength); |
|
348 success = true; |
|
349 |
|
350 free((void *)certData); |
|
351 } |
|
352 |
|
353 ResetHandlerInfo(); |
|
354 break; |
|
355 } |
|
356 |
|
357 if (!success) { |
|
358 SendResponse(PROTOCOL_ERROR); |
|
359 ResetHandlerInfo(); |
|
360 return; |
|
361 } |
|
362 } |
|
363 } |
|
364 |
|
365 void |
|
366 KeyStore::OnConnectSuccess() |
|
367 { |
|
368 mShutdown = false; |
|
369 } |
|
370 |
|
371 void |
|
372 KeyStore::OnConnectError() |
|
373 { |
|
374 if (!mShutdown) { |
|
375 Listen(); |
|
376 } |
|
377 } |
|
378 |
|
379 void |
|
380 KeyStore::OnDisconnect() |
|
381 { |
|
382 if (!mShutdown) { |
|
383 Listen(); |
|
384 } |
|
385 } |
|
386 |
|
387 } // namespace ipc |
|
388 } // namespace mozilla |