OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "bin/secure_socket.h" | 5 #include "bin/secure_socket.h" |
6 | 6 |
7 #include <errno.h> | 7 #include <errno.h> |
8 #include <fcntl.h> | 8 #include <fcntl.h> |
9 #include <sys/stat.h> | 9 #include <sys/stat.h> |
10 #include <stdio.h> | 10 #include <stdio.h> |
11 #include <string.h> | 11 #include <string.h> |
12 | 12 |
13 #include <certdb.h> | |
14 #include <key.h> | 13 #include <key.h> |
15 #include <keyt.h> | 14 #include <keyt.h> |
16 #include <nss.h> | 15 #include <nss.h> |
17 #include <p12.h> | |
18 #include <p12plcy.h> | |
19 #include <pk11pub.h> | 16 #include <pk11pub.h> |
20 #include <prerror.h> | 17 #include <prerror.h> |
21 #include <prinit.h> | 18 #include <prinit.h> |
22 #include <prnetdb.h> | 19 #include <prnetdb.h> |
23 #include <secmod.h> | 20 #include <secmod.h> |
24 #include <ssl.h> | 21 #include <ssl.h> |
25 #include <sslproto.h> | 22 #include <sslproto.h> |
26 | 23 |
27 #include "bin/builtin.h" | 24 #include "bin/builtin.h" |
28 #include "bin/dartutils.h" | 25 #include "bin/dartutils.h" |
29 #include "bin/net/nss_memio.h" | 26 #include "bin/net/nss_memio.h" |
30 #include "bin/socket.h" | 27 #include "bin/socket.h" |
31 #include "bin/thread.h" | 28 #include "bin/thread.h" |
32 #include "bin/utils.h" | 29 #include "bin/utils.h" |
33 #include "platform/utils.h" | 30 #include "platform/utils.h" |
34 | 31 |
35 #include "include/dart_api.h" | 32 #include "include/dart_api.h" |
36 | 33 |
37 | 34 |
38 namespace dart { | 35 namespace dart { |
39 namespace bin { | 36 namespace bin { |
40 | 37 |
41 bool SSLFilter::library_initialized_ = false; | 38 bool SSLFilter::library_initialized_ = false; |
42 // To protect library initialization. | 39 // To protect library initialization. |
43 dart::Mutex* SSLFilter::mutex = new dart::Mutex(); | 40 dart::Mutex* SSLFilter::mutex_ = new dart::Mutex(); |
44 // The password is needed when creating secure server sockets. It can | 41 // The password is needed when creating secure server sockets. It can |
45 // be null if only secure client sockets are used. | 42 // be null if only secure client sockets are used. |
46 char* SSLFilter::password_ = NULL; | 43 const char* SSLFilter::password_ = NULL; |
47 | 44 |
48 // Forward declaration. | 45 // Forward declaration. |
49 static void ProcessFilter(Dart_Port dest_port_id, | 46 static void ProcessFilter(Dart_Port dest_port_id, |
50 Dart_Port reply_port_id, | 47 Dart_Port reply_port_id, |
51 Dart_CObject* message); | 48 Dart_CObject* message); |
52 | 49 |
53 NativeService SSLFilter::filter_service_("FilterService", ProcessFilter, 16); | 50 NativeService SSLFilter::filter_service_("FilterService", ProcessFilter, 16); |
54 | 51 |
55 static const int kSSLFilterNativeFieldIndex = 0; | 52 static const int kSSLFilterNativeFieldIndex = 0; |
56 | 53 |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 (Dart_NativeArguments args) { | 222 (Dart_NativeArguments args) { |
226 Dart_Handle certificate_database_object = | 223 Dart_Handle certificate_database_object = |
227 ThrowIfError(Dart_GetNativeArgument(args, 0)); | 224 ThrowIfError(Dart_GetNativeArgument(args, 0)); |
228 // Check that the type is string, and get the UTF-8 C string value from it. | 225 // Check that the type is string, and get the UTF-8 C string value from it. |
229 const char* certificate_database = NULL; | 226 const char* certificate_database = NULL; |
230 if (Dart_IsString(certificate_database_object)) { | 227 if (Dart_IsString(certificate_database_object)) { |
231 ThrowIfError(Dart_StringToCString(certificate_database_object, | 228 ThrowIfError(Dart_StringToCString(certificate_database_object, |
232 &certificate_database)); | 229 &certificate_database)); |
233 } else if (!Dart_IsNull(certificate_database_object)) { | 230 } else if (!Dart_IsNull(certificate_database_object)) { |
234 Dart_ThrowException(DartUtils::NewDartArgumentError( | 231 Dart_ThrowException(DartUtils::NewDartArgumentError( |
235 "SecureSocket.initialize: database argument is not a String or null")); | 232 "Non-String certificate directory argument to SetCertificateDatabase")); |
236 } | 233 } |
237 // Leave certificate_database as NULL if no value was provided. | 234 // Leave certificate_database as NULL if no value was provided. |
238 | 235 |
239 Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); | 236 Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); |
240 // Check that the type is string or null, | 237 // Check that the type is string or null, |
241 // and get the UTF-8 C string value from it. | 238 // and get the UTF-8 C string value from it. |
242 const char* password = NULL; | 239 const char* password = NULL; |
243 if (Dart_IsString(password_object)) { | 240 if (Dart_IsString(password_object)) { |
244 ThrowIfError(Dart_StringToCString(password_object, &password)); | 241 ThrowIfError(Dart_StringToCString(password_object, &password)); |
245 } else if (Dart_IsNull(password_object)) { | 242 } else if (Dart_IsNull(password_object)) { |
246 // Pass the empty string as the password. | 243 // Pass the empty string as the password. |
247 password = ""; | 244 password = ""; |
248 } else { | 245 } else { |
249 Dart_ThrowException(DartUtils::NewDartArgumentError( | 246 Dart_ThrowException(DartUtils::NewDartArgumentError( |
250 "SecureSocket.initialize: password argument is not a String or null")); | 247 "Password argument to SetCertificateDatabase is not a String or null")); |
251 } | 248 } |
252 | 249 |
253 Dart_Handle builtin_roots_object = | 250 Dart_Handle builtin_roots_object = |
254 ThrowIfError(Dart_GetNativeArgument(args, 2)); | 251 ThrowIfError(Dart_GetNativeArgument(args, 2)); |
255 // Check that the type is boolean, and get the boolean value from it. | 252 // Check that the type is boolean, and get the boolean value from it. |
256 bool builtin_roots = true; | 253 bool builtin_roots = true; |
257 if (Dart_IsBoolean(builtin_roots_object)) { | 254 if (Dart_IsBoolean(builtin_roots_object)) { |
258 ThrowIfError(Dart_BooleanValue(builtin_roots_object, &builtin_roots)); | 255 ThrowIfError(Dart_BooleanValue(builtin_roots_object, &builtin_roots)); |
259 } else { | 256 } else { |
260 Dart_ThrowException(DartUtils::NewDartArgumentError( | 257 Dart_ThrowException(DartUtils::NewDartArgumentError( |
261 "SecureSocket.initialize: useBuiltinRoots argument is not a bool")); | 258 "UseBuiltinRoots argument to SetCertificateDatabase is not a bool")); |
262 } | 259 } |
263 | 260 |
264 Dart_Handle read_only_object = | 261 SSLFilter::InitializeLibrary(certificate_database, password, builtin_roots); |
265 ThrowIfError(Dart_GetNativeArgument(args, 3)); | |
266 // Check that the type is boolean, and get the boolean value from it. | |
267 bool read_only = true; | |
268 if (Dart_IsBoolean(read_only_object)) { | |
269 ThrowIfError(Dart_BooleanValue(read_only_object, &read_only)); | |
270 } else { | |
271 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
272 "SecureSocket.initialize: readOnly argument is not a bool")); | |
273 } | |
274 | |
275 SSLFilter::InitializeLibrary( | |
276 certificate_database, password, builtin_roots, read_only); | |
277 } | 262 } |
278 | 263 |
279 | 264 |
280 static Dart_Handle X509FromCertificate(CERTCertificate* certificate) { | |
281 PRTime start_validity; | |
282 PRTime end_validity; | |
283 SECStatus status = | |
284 CERT_GetCertTimes(certificate, &start_validity, &end_validity); | |
285 if (status != SECSuccess) { | |
286 ThrowPRException("CertificateException", | |
287 "Cannot get validity times from certificate"); | |
288 } | |
289 int64_t start_epoch_ms = start_validity / PR_USEC_PER_MSEC; | |
290 int64_t end_epoch_ms = end_validity / PR_USEC_PER_MSEC; | |
291 Dart_Handle subject_name_object = | |
292 DartUtils::NewString(certificate->subjectName); | |
293 Dart_Handle issuer_name_object = | |
294 DartUtils::NewString(certificate->issuerName); | |
295 Dart_Handle start_epoch_ms_int = Dart_NewInteger(start_epoch_ms); | |
296 Dart_Handle end_epoch_ms_int = Dart_NewInteger(end_epoch_ms); | |
297 | |
298 Dart_Handle date_type = | |
299 DartUtils::GetDartType(DartUtils::kCoreLibURL, "DateTime"); | |
300 Dart_Handle from_milliseconds = | |
301 DartUtils::NewString("fromMillisecondsSinceEpoch"); | |
302 | |
303 Dart_Handle start_validity_date = | |
304 Dart_New(date_type, from_milliseconds, 1, &start_epoch_ms_int); | |
305 Dart_Handle end_validity_date = | |
306 Dart_New(date_type, from_milliseconds, 1, &end_epoch_ms_int); | |
307 | |
308 Dart_Handle x509_type = | |
309 DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate"); | |
310 Dart_Handle arguments[] = { subject_name_object, | |
311 issuer_name_object, | |
312 start_validity_date, | |
313 end_validity_date }; | |
314 return Dart_New(x509_type, Dart_Null(), 4, arguments); | |
315 } | |
316 | |
317 | |
318 char* PasswordCallback(PK11SlotInfo* slot, PRBool retry, void* arg) { | |
319 if (!retry) { | |
320 return PL_strdup(static_cast<char*>(arg)); // Freed by NSS internals. | |
321 } | |
322 return NULL; | |
323 } | |
324 | |
325 | |
326 void FUNCTION_NAME(SecureSocket_AddCertificate) | |
327 (Dart_NativeArguments args) { | |
328 Dart_Handle certificate_object = | |
329 ThrowIfError(Dart_GetNativeArgument(args, 0)); | |
330 Dart_Handle trust_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); | |
331 | |
332 if (!Dart_IsList(certificate_object) || !Dart_IsString(trust_object)) { | |
333 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
334 "Bad argument to SecureSocket.addCertificate")); | |
335 } | |
336 | |
337 intptr_t length; | |
338 ThrowIfError(Dart_ListLength(certificate_object, &length)); | |
339 uint8_t* certificate = reinterpret_cast<uint8_t*>(malloc(length + 1)); | |
340 if (certificate == NULL) { | |
341 FATAL("Out of memory in SecureSocket.addCertificate"); | |
342 } | |
343 ThrowIfError(Dart_ListGetAsBytes( | |
344 certificate_object, 0, certificate, length)); | |
345 | |
346 const char* trust_string; | |
347 ThrowIfError(Dart_StringToCString(trust_object, | |
348 &trust_string)); | |
349 | |
350 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); | |
351 SECStatus status = PK11_Authenticate(slot, PR_TRUE, SSLFilter::GetPassword()); | |
352 PK11_FreeSlot(slot); | |
353 if (status == SECFailure) { | |
354 ThrowPRException("CertificateException", | |
355 "Could not authenticate to certificate database"); | |
356 } | |
357 | |
358 CERTCertificate* cert = CERT_DecodeCertFromPackage( | |
359 reinterpret_cast<char*>(certificate), length); | |
360 if (cert == NULL) { | |
361 ThrowPRException("CertificateException", "Certificate cannot be decoded"); | |
362 } | |
363 CERTCertTrust trust; | |
364 status = CERT_DecodeTrustString(&trust, trust_string); | |
365 if (status != SECSuccess) { | |
366 ThrowPRException("CertificateException", "Trust string cannot be decoded"); | |
367 } | |
368 { | |
369 MutexLocker locker(SSLFilter::mutex); | |
370 status = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, &trust); | |
371 } | |
372 if (status != SECSuccess) { | |
373 ThrowPRException("CertificateException", "Cannot set trust attributes"); | |
374 } | |
375 | |
376 Dart_SetReturnValue(args, X509FromCertificate(cert)); | |
377 return; | |
378 } | |
379 | |
380 | |
381 /* | |
382 * Called by the PKCS#12 decoder if a certificate's nickname collides with | |
383 * the nickname of a different existing certificate in the database. | |
384 */ | |
385 SECItem* nickname_callback(SECItem *old_nickname, | |
386 PRBool *cancel, | |
387 void *arg) { | |
388 *cancel = PR_TRUE; | |
389 return NULL; | |
390 } | |
391 | |
392 | |
393 void FUNCTION_NAME(SecureSocket_ImportCertificatesWithPrivateKeys) | |
394 (Dart_NativeArguments args) { | |
395 Dart_Handle pk12_object = ThrowIfError(Dart_GetNativeArgument(args, 0)); | |
396 if (!Dart_IsList(pk12_object)) { | |
397 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
398 "SecureSocket.importPrivateCertificates: certificates is not a List")); | |
399 } | |
400 | |
401 Dart_Handle password_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); | |
402 if (!Dart_IsString(password_object)) { | |
403 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
404 "SecureSocket.importPrivateCertificates: password is not a String")); | |
405 } | |
406 | |
407 intptr_t length; | |
408 ThrowIfError(Dart_ListLength(pk12_object, &length)); | |
409 uint8_t* pk12 = Dart_ScopeAllocate(length); | |
410 if (pk12 == NULL) { | |
411 FATAL("Out of memory in SecureSocket.importPrivateCertificates"); | |
412 } | |
413 ThrowIfError(Dart_ListGetAsBytes(pk12_object, 0, pk12, length)); | |
414 | |
415 // A big-endian Unicode (UTF16) password. | |
416 intptr_t password_length; | |
417 ThrowIfError(Dart_StringLength(password_object, &password_length)); | |
418 password_length++; | |
419 uint16_t* password = reinterpret_cast<uint16_t*>( | |
420 Dart_ScopeAllocate(sizeof(uint16_t) * password_length)); | |
421 if (password == NULL) { | |
422 FATAL("Out of memory in SecureSocket.importPrivateCertificates"); | |
423 } | |
424 intptr_t returned_length = password_length; | |
425 ThrowIfError(Dart_StringToUTF16(password_object, password, &returned_length)); | |
426 ASSERT(password_length == returned_length + 1); | |
427 password[password_length - 1] = 0; | |
428 for (int i = 0; i < password_length; ++i) { | |
429 password[i] = Utils::HostToBigEndian16(password[i]); | |
430 } | |
431 SECItem p12_password; | |
432 p12_password.type = siBuffer; | |
433 p12_password.data = reinterpret_cast<unsigned char*>(password); | |
434 p12_password.len = sizeof(uint16_t) * password_length; | |
435 | |
436 Dart_SetReturnValue(args, Dart_Null()); | |
437 // Set the password callback for the certificate database we are importing to. | |
438 // The password for a slot is gotten from a callback, and it is freed by the | |
439 // caller of the callback. The argument to the callback comes from the wincx | |
440 // argument to a PK11 function. | |
441 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); | |
442 SECStatus status = PK11_Authenticate(slot, PR_TRUE, SSLFilter::GetPassword()); | |
443 if (status == SECFailure) { | |
444 PK11_FreeSlot(slot); | |
445 ThrowPRException("CertificateException", | |
446 "Could not authenticate to certificate database"); | |
447 } | |
448 | |
449 SEC_PKCS12DecoderContext* context = SEC_PKCS12DecoderStart( | |
450 &p12_password, | |
451 slot, | |
452 SSLFilter::GetPassword(), | |
453 NULL, | |
454 NULL, | |
455 NULL, | |
456 NULL, | |
457 NULL); | |
458 PK11_FreeSlot(slot); | |
459 if (!context) { | |
460 FATAL("Unexpected error: SecureSocket.addPrivateCertificates DecoderStart"); | |
461 } | |
462 bool success; | |
463 { | |
464 MutexLocker locker(SSLFilter::mutex); | |
465 success = | |
466 SECSuccess == SEC_PKCS12DecoderUpdate(context, pk12, length) && | |
467 SECSuccess == SEC_PKCS12DecoderVerify(context) && | |
468 SECSuccess == SEC_PKCS12DecoderValidateBags(context, | |
469 nickname_callback) && | |
470 SECSuccess == SEC_PKCS12DecoderImportBags(context); | |
471 } | |
472 SEC_PKCS12DecoderFinish(context); | |
473 if (!success) { | |
474 ThrowPRException("CertificateException", "Could not import PKCS#12 file"); | |
475 } | |
476 } | |
477 | |
478 | |
479 void FUNCTION_NAME(SecureSocket_ChangeTrust)(Dart_NativeArguments args) { | |
480 Dart_Handle nickname_object = ThrowIfError(Dart_GetNativeArgument(args, 0)); | |
481 if (!Dart_IsString(nickname_object)) { | |
482 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
483 "SecureSocket.changeTrust: nickname argument is not a String")); | |
484 } | |
485 const char* nickname; | |
486 ThrowIfError(Dart_StringToCString(nickname_object, &nickname)); | |
487 | |
488 Dart_Handle trust_object = ThrowIfError(Dart_GetNativeArgument(args, 1)); | |
489 if (!Dart_IsString(trust_object)) { | |
490 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
491 "SecureSocket.changeTrust: trust argument is not a String")); | |
492 } | |
493 const char* trust_string; | |
494 ThrowIfError(Dart_StringToCString(trust_object, &trust_string)); | |
495 | |
496 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); | |
497 SECStatus status = PK11_Authenticate(slot, PR_TRUE, SSLFilter::GetPassword()); | |
498 if (status == SECFailure) { | |
499 ThrowPRException("CertificateException", | |
500 "Could not authenticate to certificate database"); | |
501 } | |
502 PK11_FreeSlot(slot); | |
503 | |
504 CERTCertificate* certificate = | |
505 PK11_FindCertFromNickname(nickname, SSLFilter::GetPassword()); | |
506 if (certificate == NULL) { | |
507 ThrowCertificateException("Cannot find certificate with nickname %s", | |
508 nickname); | |
509 } | |
510 CERTCertTrust trust; | |
511 if (SECSuccess != CERT_DecodeTrustString(&trust, trust_string)) { | |
512 CERT_DestroyCertificate(certificate); | |
513 ThrowPRException("CertificateException", "Trust string cannot be decoded"); | |
514 } | |
515 { | |
516 MutexLocker locker(SSLFilter::mutex); | |
517 status = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), certificate, &trust); | |
518 } | |
519 if (status != SECSuccess) { | |
520 CERT_DestroyCertificate(certificate); | |
521 ThrowCertificateException("Cannot set trust on certificate %s", nickname); | |
522 } | |
523 Dart_SetReturnValue(args, X509FromCertificate(certificate)); | |
524 CERT_DestroyCertificate(certificate); | |
525 } | |
526 | |
527 | |
528 void FUNCTION_NAME(SecureSocket_GetCertificate)(Dart_NativeArguments args) { | |
529 Dart_Handle nickname_object = ThrowIfError(Dart_GetNativeArgument(args, 0)); | |
530 if (!Dart_IsString(nickname_object)) { | |
531 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
532 "SecureSocket.getCertificate: nickname argument is not a String")); | |
533 } | |
534 const char* nickname; | |
535 ThrowIfError(Dart_StringToCString(nickname_object, &nickname)); | |
536 | |
537 CERTCertificate* certificate = PK11_FindCertFromNickname( | |
538 nickname, SSLFilter::GetPassword()); | |
539 if (certificate != NULL) { | |
540 Dart_SetReturnValue(args, X509FromCertificate(certificate)); | |
541 CERT_DestroyCertificate(certificate); | |
542 } | |
543 } | |
544 | |
545 | |
546 void FUNCTION_NAME(SecureSocket_RemoveCertificate)(Dart_NativeArguments args) { | |
547 Dart_Handle nickname_object = | |
548 ThrowIfError(Dart_GetNativeArgument(args, 0)); | |
549 if (!Dart_IsString(nickname_object)) { | |
550 Dart_ThrowException(DartUtils::NewDartArgumentError( | |
551 "SecureSocket.removeCertificate: nickname is not a String")); | |
552 } | |
553 const char* nickname; | |
554 ThrowIfError(Dart_StringToCString(nickname_object, &nickname)); | |
555 | |
556 CERTCertificate* certificate = | |
557 PK11_FindCertFromNickname(nickname, SSLFilter::GetPassword()); | |
558 if (certificate == NULL) { | |
559 ThrowCertificateException("Cannot find certificate with nickname %s", | |
560 nickname); | |
561 } | |
562 SECKEYPrivateKey* key = | |
563 PK11_FindKeyByAnyCert(certificate, SSLFilter::GetPassword()); | |
564 // Free the copy returned from FindKeyByAnyCert. | |
565 SECKEY_DestroyPrivateKey(key); | |
566 SECStatus status; | |
567 { | |
568 MutexLocker locker(SSLFilter::mutex); | |
569 status = (key == NULL) ? | |
570 SEC_DeletePermCertificate(certificate) : | |
571 PK11_DeleteTokenCertAndKey(certificate, SSLFilter::GetPassword()); | |
572 } | |
573 CERT_DestroyCertificate(certificate); | |
574 if (status != SECSuccess) { | |
575 ThrowCertificateException("Cannot remove certificate %s", nickname); | |
576 } | |
577 } | |
578 | |
579 | |
580 void FUNCTION_NAME(SecureSocket_PeerCertificate) | 265 void FUNCTION_NAME(SecureSocket_PeerCertificate) |
581 (Dart_NativeArguments args) { | 266 (Dart_NativeArguments args) { |
582 Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate()); | 267 Dart_SetReturnValue(args, GetFilter(args)->PeerCertificate()); |
583 } | 268 } |
584 | 269 |
585 | 270 |
586 void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) { | 271 void FUNCTION_NAME(SecureSocket_FilterPointer)(Dart_NativeArguments args) { |
587 intptr_t filter_pointer = reinterpret_cast<intptr_t>(GetFilter(args)); | 272 intptr_t filter_pointer = reinterpret_cast<intptr_t>(GetFilter(args)); |
588 Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer)); | 273 Dart_SetReturnValue(args, Dart_NewInteger(filter_pointer)); |
589 } | 274 } |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
716 starts[i] = start; | 401 starts[i] = start; |
717 break; | 402 break; |
718 default: | 403 default: |
719 UNREACHABLE(); | 404 UNREACHABLE(); |
720 } | 405 } |
721 } | 406 } |
722 return true; | 407 return true; |
723 } | 408 } |
724 | 409 |
725 | 410 |
| 411 static Dart_Handle X509FromCertificate(CERTCertificate* certificate) { |
| 412 PRTime start_validity; |
| 413 PRTime end_validity; |
| 414 SECStatus status = |
| 415 CERT_GetCertTimes(certificate, &start_validity, &end_validity); |
| 416 if (status != SECSuccess) { |
| 417 ThrowPRException("CertificateException", |
| 418 "Cannot get validity times from certificate"); |
| 419 } |
| 420 int64_t start_epoch_ms = start_validity / PR_USEC_PER_MSEC; |
| 421 int64_t end_epoch_ms = end_validity / PR_USEC_PER_MSEC; |
| 422 Dart_Handle subject_name_object = |
| 423 DartUtils::NewString(certificate->subjectName); |
| 424 Dart_Handle issuer_name_object = |
| 425 DartUtils::NewString(certificate->issuerName); |
| 426 Dart_Handle start_epoch_ms_int = Dart_NewInteger(start_epoch_ms); |
| 427 Dart_Handle end_epoch_ms_int = Dart_NewInteger(end_epoch_ms); |
| 428 |
| 429 Dart_Handle date_type = |
| 430 DartUtils::GetDartType(DartUtils::kCoreLibURL, "DateTime"); |
| 431 Dart_Handle from_milliseconds = |
| 432 DartUtils::NewString("fromMillisecondsSinceEpoch"); |
| 433 |
| 434 Dart_Handle start_validity_date = |
| 435 Dart_New(date_type, from_milliseconds, 1, &start_epoch_ms_int); |
| 436 Dart_Handle end_validity_date = |
| 437 Dart_New(date_type, from_milliseconds, 1, &end_epoch_ms_int); |
| 438 |
| 439 Dart_Handle x509_type = |
| 440 DartUtils::GetDartType(DartUtils::kIOLibURL, "X509Certificate"); |
| 441 Dart_Handle arguments[] = { subject_name_object, |
| 442 issuer_name_object, |
| 443 start_validity_date, |
| 444 end_validity_date }; |
| 445 return Dart_New(x509_type, Dart_Null(), 4, arguments); |
| 446 } |
| 447 |
| 448 |
726 void SSLFilter::Init(Dart_Handle dart_this) { | 449 void SSLFilter::Init(Dart_Handle dart_this) { |
727 if (!library_initialized_) { | 450 if (!library_initialized_) { |
728 InitializeLibrary(NULL, "", true, true, false); | 451 InitializeLibrary(NULL, "", true, false); |
729 } | 452 } |
730 ASSERT(string_start_ == NULL); | 453 ASSERT(string_start_ == NULL); |
731 string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start")); | 454 string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start")); |
732 ASSERT(string_start_ != NULL); | 455 ASSERT(string_start_ != NULL); |
733 ASSERT(string_length_ == NULL); | 456 ASSERT(string_length_ == NULL); |
734 string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length")); | 457 string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length")); |
735 ASSERT(string_length_ != NULL); | 458 ASSERT(string_length_ != NULL); |
736 ASSERT(bad_certificate_callback_ == NULL); | 459 ASSERT(bad_certificate_callback_ == NULL); |
737 bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null()); | 460 bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null()); |
738 ASSERT(bad_certificate_callback_ != NULL); | 461 ASSERT(bad_certificate_callback_ != NULL); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
791 | 514 |
792 | 515 |
793 void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) { | 516 void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) { |
794 ASSERT(bad_certificate_callback_ != NULL); | 517 ASSERT(bad_certificate_callback_ != NULL); |
795 Dart_DeletePersistentHandle(bad_certificate_callback_); | 518 Dart_DeletePersistentHandle(bad_certificate_callback_); |
796 bad_certificate_callback_ = Dart_NewPersistentHandle(callback); | 519 bad_certificate_callback_ = Dart_NewPersistentHandle(callback); |
797 ASSERT(bad_certificate_callback_ != NULL); | 520 ASSERT(bad_certificate_callback_ != NULL); |
798 } | 521 } |
799 | 522 |
800 | 523 |
| 524 char* PasswordCallback(PK11SlotInfo* slot, PRBool retry, void* arg) { |
| 525 if (!retry) { |
| 526 return PL_strdup(static_cast<char*>(arg)); // Freed by NSS internals. |
| 527 } |
| 528 return NULL; |
| 529 } |
| 530 |
| 531 |
801 static const char* builtin_roots_module = | 532 static const char* builtin_roots_module = |
802 #if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) | 533 #if defined(TARGET_OS_LINUX) || defined(TARGET_OS_ANDROID) |
803 "name=\"Root Certs\" library=\"libnssckbi.so\""; | 534 "name=\"Root Certs\" library=\"libnssckbi.so\""; |
804 #elif defined(TARGET_OS_MACOS) | 535 #elif defined(TARGET_OS_MACOS) |
805 "name=\"Root Certs\" library=\"libnssckbi.dylib\""; | 536 "name=\"Root Certs\" library=\"libnssckbi.dylib\""; |
806 #elif defined(TARGET_OS_WINDOWS) | 537 #elif defined(TARGET_OS_WINDOWS) |
807 "name=\"Root Certs\" library=\"nssckbi.dll\""; | 538 "name=\"Root Certs\" library=\"nssckbi.dll\""; |
808 #else | 539 #else |
809 #error Automatic target os detection failed. | 540 #error Automatic target os detection failed. |
810 #endif | 541 #endif |
811 | 542 |
812 | 543 |
813 | 544 |
814 void SSLFilter::InitializeLibrary(const char* certificate_database, | 545 void SSLFilter::InitializeLibrary(const char* certificate_database, |
815 const char* password, | 546 const char* password, |
816 bool use_builtin_root_certificates, | 547 bool use_builtin_root_certificates, |
817 bool read_only, | |
818 bool report_duplicate_initialization) { | 548 bool report_duplicate_initialization) { |
819 MutexLocker locker(mutex); | 549 MutexLocker locker(mutex_); |
820 SECStatus status; | 550 SECStatus status; |
821 if (!library_initialized_) { | 551 if (!library_initialized_) { |
822 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); | 552 PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); |
823 // TODO(whesse): Verify there are no UTF-8 issues here. | 553 // TODO(whesse): Verify there are no UTF-8 issues here. |
824 if (certificate_database == NULL || certificate_database[0] == '\0') { | 554 if (certificate_database == NULL || certificate_database[0] == '\0') { |
825 status = NSS_NoDB_Init(NULL); | 555 status = NSS_NoDB_Init(NULL); |
826 if (status != SECSuccess) { | 556 if (status != SECSuccess) { |
827 mutex->Unlock(); // MutexLocker destructor not called when throwing. | 557 mutex_->Unlock(); // MutexLocker destructor not called when throwing. |
828 ThrowPRException("TlsException", | 558 ThrowPRException("TlsException", |
829 "Failed NSS_NoDB_Init call."); | 559 "Failed NSS_NoDB_Init call."); |
830 } | 560 } |
831 if (use_builtin_root_certificates) { | 561 if (use_builtin_root_certificates) { |
832 SECMODModule* module = SECMOD_LoadUserModule( | 562 SECMODModule* module = SECMOD_LoadUserModule( |
833 const_cast<char*>(builtin_roots_module), NULL, PR_FALSE); | 563 const_cast<char*>(builtin_roots_module), NULL, PR_FALSE); |
834 if (!module) { | 564 if (!module) { |
835 mutex->Unlock(); // MutexLocker destructor not called when throwing. | 565 mutex_->Unlock(); // MutexLocker destructor not called when throwing. |
836 ThrowPRException("TlsException", | 566 ThrowPRException("TlsException", |
837 "Failed to load builtin root certificates."); | 567 "Failed to load builtin root certificates."); |
838 } | 568 } |
839 } | 569 } |
840 } else { | 570 } else { |
841 PRUint32 init_flags = read_only ? NSS_INIT_READONLY : 0; | 571 PRUint32 init_flags = NSS_INIT_READONLY; |
842 if (!use_builtin_root_certificates) { | 572 if (!use_builtin_root_certificates) { |
843 init_flags |= NSS_INIT_NOMODDB; | 573 init_flags |= NSS_INIT_NOMODDB; |
844 } | 574 } |
845 status = NSS_Initialize(certificate_database, | 575 status = NSS_Initialize(certificate_database, |
846 "", | 576 "", |
847 "", | 577 "", |
848 SECMOD_DB, | 578 SECMOD_DB, |
849 init_flags); | 579 init_flags); |
850 if (status != SECSuccess) { | 580 if (status != SECSuccess) { |
851 mutex->Unlock(); // MutexLocker destructor not called when throwing. | 581 mutex_->Unlock(); // MutexLocker destructor not called when throwing. |
852 ThrowPRException("TlsException", | 582 ThrowPRException("TlsException", |
853 "Failed NSS_Init call."); | 583 "Failed NSS_Init call."); |
854 } | 584 } |
855 password_ = strdup(password); // This one copy persists until Dart exits. | 585 password_ = strdup(password); // This one copy persists until Dart exits. |
856 PK11_SetPasswordFunc(PasswordCallback); | 586 PK11_SetPasswordFunc(PasswordCallback); |
857 } | 587 } |
858 library_initialized_ = true; | 588 library_initialized_ = true; |
859 | 589 |
860 // Allow encoding and decoding of private keys in PKCS#12 files. | |
861 SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1); | |
862 SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1); | |
863 SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1); | |
864 | |
865 status = NSS_SetDomesticPolicy(); | 590 status = NSS_SetDomesticPolicy(); |
866 if (status != SECSuccess) { | 591 if (status != SECSuccess) { |
867 mutex->Unlock(); // MutexLocker destructor not called when throwing. | 592 mutex_->Unlock(); // MutexLocker destructor not called when throwing. |
868 ThrowPRException("TlsException", | 593 ThrowPRException("TlsException", |
869 "Failed NSS_SetDomesticPolicy call."); | 594 "Failed NSS_SetDomesticPolicy call."); |
870 } | 595 } |
871 | |
872 // Enable TLS, as well as SSL3 and SSL2. | 596 // Enable TLS, as well as SSL3 and SSL2. |
873 status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE); | 597 status = SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE); |
874 if (status != SECSuccess) { | 598 if (status != SECSuccess) { |
875 mutex->Unlock(); // MutexLocker destructor not called when throwing. | 599 mutex_->Unlock(); // MutexLocker destructor not called when throwing. |
876 ThrowPRException("TlsException", | 600 ThrowPRException("TlsException", |
877 "Failed SSL_OptionSetDefault enable TLS call."); | 601 "Failed SSL_OptionSetDefault enable TLS call."); |
878 } | 602 } |
879 status = SSL_ConfigServerSessionIDCache(0, 0, 0, NULL); | 603 status = SSL_ConfigServerSessionIDCache(0, 0, 0, NULL); |
880 if (status != SECSuccess) { | 604 if (status != SECSuccess) { |
881 mutex->Unlock(); // MutexLocker destructor not called when throwing. | 605 mutex_->Unlock(); // MutexLocker destructor not called when throwing. |
882 ThrowPRException("TlsException", | 606 ThrowPRException("TlsException", |
883 "Failed SSL_ConfigServerSessionIDCache call."); | 607 "Failed SSL_ConfigServerSessionIDCache call."); |
884 } | 608 } |
885 | 609 |
886 } else if (report_duplicate_initialization) { | 610 } else if (report_duplicate_initialization) { |
887 mutex->Unlock(); // MutexLocker destructor not called when throwing. | 611 mutex_->Unlock(); // MutexLocker destructor not called when throwing. |
888 // Like ThrowPRException, without adding an OSError. | 612 // Like ThrowPRException, without adding an OSError. |
889 Dart_ThrowException(DartUtils::NewDartIOException("TlsException", | 613 Dart_ThrowException(DartUtils::NewDartIOException("TlsException", |
890 "Called SecureSocket.initialize more than once", | 614 "Called SecureSocket.initialize more than once", |
891 Dart_Null())); | 615 Dart_Null())); |
892 } | 616 } |
893 } | 617 } |
894 | 618 |
895 | 619 |
896 SECStatus BadCertificateCallback(void* filter, PRFileDesc* fd) { | 620 SECStatus BadCertificateCallback(void* filter, PRFileDesc* fd) { |
897 SSLFilter* ssl_filter = static_cast<SSLFilter*>(filter); | 621 SSLFilter* ssl_filter = static_cast<SSLFilter*>(filter); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
952 // Look up certificate using the distinguished name (DN) certificate_name. | 676 // Look up certificate using the distinguished name (DN) certificate_name. |
953 CERTCertDBHandle* certificate_database = CERT_GetDefaultCertDB(); | 677 CERTCertDBHandle* certificate_database = CERT_GetDefaultCertDB(); |
954 if (certificate_database == NULL) { | 678 if (certificate_database == NULL) { |
955 ThrowPRException("CertificateException", | 679 ThrowPRException("CertificateException", |
956 "Certificate database cannot be loaded"); | 680 "Certificate database cannot be loaded"); |
957 } | 681 } |
958 certificate = CERT_FindCertByNameString(certificate_database, | 682 certificate = CERT_FindCertByNameString(certificate_database, |
959 const_cast<char*>(certificate_name)); | 683 const_cast<char*>(certificate_name)); |
960 if (certificate == NULL) { | 684 if (certificate == NULL) { |
961 ThrowCertificateException( | 685 ThrowCertificateException( |
962 "Cannot find server certificate with distinguished name %s", | 686 "Cannot find server certificate by distinguished name: %s", |
963 certificate_name); | 687 certificate_name); |
964 } | 688 } |
965 } else { | 689 } else { |
966 // Look up certificate using the nickname certificate_name. | 690 // Look up certificate using the nickname certificate_name. |
967 certificate = PK11_FindCertFromNickname( | 691 certificate = PK11_FindCertFromNickname( |
968 const_cast<char*>(certificate_name), GetPassword()); | 692 const_cast<char*>(certificate_name), |
| 693 static_cast<void*>(const_cast<char*>(password_))); |
969 if (certificate == NULL) { | 694 if (certificate == NULL) { |
970 ThrowCertificateException( | 695 ThrowCertificateException( |
971 "Cannot find server certificate with nickname %s", | 696 "Cannot find server certificate by nickname: %s", |
972 certificate_name); | 697 certificate_name); |
973 } | 698 } |
974 } | 699 } |
975 SECKEYPrivateKey* key = PK11_FindKeyByAnyCert(certificate, GetPassword()); | 700 SECKEYPrivateKey* key = PK11_FindKeyByAnyCert( |
| 701 certificate, |
| 702 static_cast<void*>(const_cast<char*>(password_))); |
976 if (key == NULL) { | 703 if (key == NULL) { |
977 CERT_DestroyCertificate(certificate); | 704 CERT_DestroyCertificate(certificate); |
978 if (PR_GetError() == -8177) { | 705 if (PR_GetError() == -8177) { |
979 ThrowPRException("CertificateException", | 706 ThrowPRException("CertificateException", |
980 "Certificate database password incorrect"); | 707 "Certificate database password incorrect"); |
981 } else { | 708 } else { |
982 ThrowCertificateException( | 709 ThrowCertificateException( |
983 "Cannot find private key for certificate %s", | 710 "Cannot find private key for certificate %s", |
984 certificate_name); | 711 certificate_name); |
985 } | 712 } |
(...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1249 if (service_port != ILLEGAL_PORT) { | 976 if (service_port != ILLEGAL_PORT) { |
1250 // Return a send port for the service port. | 977 // Return a send port for the service port. |
1251 Dart_Handle send_port = Dart_NewSendPort(service_port); | 978 Dart_Handle send_port = Dart_NewSendPort(service_port); |
1252 Dart_SetReturnValue(args, send_port); | 979 Dart_SetReturnValue(args, send_port); |
1253 } | 980 } |
1254 } | 981 } |
1255 | 982 |
1256 | 983 |
1257 } // namespace bin | 984 } // namespace bin |
1258 } // namespace dart | 985 } // namespace dart |
OLD | NEW |