security/manager/ssl/src/nsNSSCallbacks.cpp

branch
TOR_BUG_9701
changeset 3
141e0f1194b1
equal deleted inserted replaced
-1:000000000000 0:e9b7a16d3123
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 *
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 "nsNSSCallbacks.h"
8 #include "pkix/pkixtypes.h"
9 #include "mozilla/Telemetry.h"
10 #include "mozilla/TimeStamp.h"
11 #include "nsNSSComponent.h"
12 #include "nsNSSIOLayer.h"
13 #include "nsIWebProgressListener.h"
14 #include "nsProtectedAuthThread.h"
15 #include "nsITokenDialogs.h"
16 #include "nsIUploadChannel.h"
17 #include "nsIPrompt.h"
18 #include "nsProxyRelease.h"
19 #include "PSMRunnable.h"
20 #include "nsContentUtils.h"
21 #include "nsIHttpChannelInternal.h"
22 #include "nsISupportsPriority.h"
23 #include "nsNetUtil.h"
24 #include "SharedSSLState.h"
25 #include "ssl.h"
26 #include "sslproto.h"
27
28 using namespace mozilla;
29 using namespace mozilla::psm;
30
31 #ifdef PR_LOGGING
32 extern PRLogModuleInfo* gPIPNSSLog;
33 #endif
34
35 static void AccumulateCipherSuite(Telemetry::ID probe,
36 const SSLChannelInfo& channelInfo);
37
38 namespace {
39
40 // Bits in bit mask for SSL_REASONS_FOR_NOT_FALSE_STARTING telemetry probe
41 // These bits are numbered so that the least subtle issues have higher values.
42 // This should make it easier for us to interpret the results.
43 const uint32_t NPN_NOT_NEGOTIATED = 64;
44 const uint32_t KEA_NOT_FORWARD_SECRET = 32;
45 const uint32_t KEA_NOT_SAME_AS_EXPECTED = 16;
46 const uint32_t KEA_NOT_ALLOWED = 8;
47 const uint32_t POSSIBLE_VERSION_DOWNGRADE = 4;
48 const uint32_t POSSIBLE_CIPHER_SUITE_DOWNGRADE = 2;
49 const uint32_t KEA_NOT_SUPPORTED = 1;
50
51 }
52
53 class nsHTTPDownloadEvent : public nsRunnable {
54 public:
55 nsHTTPDownloadEvent();
56 ~nsHTTPDownloadEvent();
57
58 NS_IMETHOD Run();
59
60 nsNSSHttpRequestSession *mRequestSession;
61
62 nsRefPtr<nsHTTPListener> mListener;
63 bool mResponsibleForDoneSignal;
64 TimeStamp mStartTime;
65 };
66
67 nsHTTPDownloadEvent::nsHTTPDownloadEvent()
68 :mResponsibleForDoneSignal(true)
69 {
70 }
71
72 nsHTTPDownloadEvent::~nsHTTPDownloadEvent()
73 {
74 if (mResponsibleForDoneSignal && mListener)
75 mListener->send_done_signal();
76
77 mRequestSession->Release();
78 }
79
80 NS_IMETHODIMP
81 nsHTTPDownloadEvent::Run()
82 {
83 if (!mListener)
84 return NS_OK;
85
86 nsresult rv;
87
88 nsCOMPtr<nsIIOService> ios = do_GetIOService();
89 NS_ENSURE_STATE(ios);
90
91 nsCOMPtr<nsIChannel> chan;
92 ios->NewChannel(mRequestSession->mURL, nullptr, nullptr, getter_AddRefs(chan));
93 NS_ENSURE_STATE(chan);
94
95 // Security operations scheduled through normal HTTP channels are given
96 // high priority to accommodate real time OCSP transactions. Background CRL
97 // fetches happen through a different path (CRLDownloadEvent).
98 nsCOMPtr<nsISupportsPriority> priorityChannel = do_QueryInterface(chan);
99 if (priorityChannel)
100 priorityChannel->AdjustPriority(nsISupportsPriority::PRIORITY_HIGHEST);
101
102 chan->SetLoadFlags(nsIRequest::LOAD_ANONYMOUS);
103
104 // Create a loadgroup for this new channel. This way if the channel
105 // is redirected, we'll have a way to cancel the resulting channel.
106 nsCOMPtr<nsILoadGroup> lg = do_CreateInstance(NS_LOADGROUP_CONTRACTID);
107 chan->SetLoadGroup(lg);
108
109 if (mRequestSession->mHasPostData)
110 {
111 nsCOMPtr<nsIInputStream> uploadStream;
112 rv = NS_NewPostDataStream(getter_AddRefs(uploadStream),
113 false,
114 mRequestSession->mPostData);
115 NS_ENSURE_SUCCESS(rv, rv);
116
117 nsCOMPtr<nsIUploadChannel> uploadChannel(do_QueryInterface(chan));
118 NS_ENSURE_STATE(uploadChannel);
119
120 rv = uploadChannel->SetUploadStream(uploadStream,
121 mRequestSession->mPostContentType,
122 -1);
123 NS_ENSURE_SUCCESS(rv, rv);
124 }
125
126 // Do not use SPDY for internal security operations. It could result
127 // in the silent upgrade to ssl, which in turn could require an SSL
128 // operation to fufill something like a CRL fetch, which is an
129 // endless loop.
130 nsCOMPtr<nsIHttpChannelInternal> internalChannel = do_QueryInterface(chan);
131 if (internalChannel) {
132 rv = internalChannel->SetAllowSpdy(false);
133 NS_ENSURE_SUCCESS(rv, rv);
134 }
135
136 nsCOMPtr<nsIHttpChannel> hchan = do_QueryInterface(chan);
137 NS_ENSURE_STATE(hchan);
138
139 rv = hchan->SetRequestMethod(mRequestSession->mRequestMethod);
140 NS_ENSURE_SUCCESS(rv, rv);
141
142 mResponsibleForDoneSignal = false;
143 mListener->mResponsibleForDoneSignal = true;
144
145 mListener->mLoadGroup = lg.get();
146 NS_ADDREF(mListener->mLoadGroup);
147 mListener->mLoadGroupOwnerThread = PR_GetCurrentThread();
148
149 rv = NS_NewStreamLoader(getter_AddRefs(mListener->mLoader),
150 mListener);
151
152 if (NS_SUCCEEDED(rv)) {
153 mStartTime = TimeStamp::Now();
154 rv = hchan->AsyncOpen(mListener->mLoader, nullptr);
155 }
156
157 if (NS_FAILED(rv)) {
158 mListener->mResponsibleForDoneSignal = false;
159 mResponsibleForDoneSignal = true;
160
161 NS_RELEASE(mListener->mLoadGroup);
162 mListener->mLoadGroup = nullptr;
163 mListener->mLoadGroupOwnerThread = nullptr;
164 }
165
166 return NS_OK;
167 }
168
169 struct nsCancelHTTPDownloadEvent : nsRunnable {
170 nsRefPtr<nsHTTPListener> mListener;
171
172 NS_IMETHOD Run() {
173 mListener->FreeLoadGroup(true);
174 mListener = nullptr;
175 return NS_OK;
176 }
177 };
178
179 SECStatus nsNSSHttpServerSession::createSessionFcn(const char *host,
180 uint16_t portnum,
181 SEC_HTTP_SERVER_SESSION *pSession)
182 {
183 if (!host || !pSession)
184 return SECFailure;
185
186 nsNSSHttpServerSession *hss = new nsNSSHttpServerSession;
187 if (!hss)
188 return SECFailure;
189
190 hss->mHost = host;
191 hss->mPort = portnum;
192
193 *pSession = hss;
194 return SECSuccess;
195 }
196
197 SECStatus nsNSSHttpRequestSession::createFcn(SEC_HTTP_SERVER_SESSION session,
198 const char *http_protocol_variant,
199 const char *path_and_query_string,
200 const char *http_request_method,
201 const PRIntervalTime timeout,
202 SEC_HTTP_REQUEST_SESSION *pRequest)
203 {
204 if (!session || !http_protocol_variant || !path_and_query_string ||
205 !http_request_method || !pRequest)
206 return SECFailure;
207
208 nsNSSHttpServerSession* hss = static_cast<nsNSSHttpServerSession*>(session);
209 if (!hss)
210 return SECFailure;
211
212 nsNSSHttpRequestSession *rs = new nsNSSHttpRequestSession;
213 if (!rs)
214 return SECFailure;
215
216 rs->mTimeoutInterval = timeout;
217
218 // Use a maximum timeout value of 10 seconds because of bug 404059.
219 // FIXME: Use a better approach once 406120 is ready.
220 uint32_t maxBug404059Timeout = PR_TicksPerSecond() * 10;
221 if (timeout > maxBug404059Timeout) {
222 rs->mTimeoutInterval = maxBug404059Timeout;
223 }
224
225 rs->mURL.Assign(http_protocol_variant);
226 rs->mURL.AppendLiteral("://");
227 rs->mURL.Append(hss->mHost);
228 rs->mURL.AppendLiteral(":");
229 rs->mURL.AppendInt(hss->mPort);
230 rs->mURL.Append(path_and_query_string);
231
232 rs->mRequestMethod = http_request_method;
233
234 *pRequest = (void*)rs;
235 return SECSuccess;
236 }
237
238 SECStatus nsNSSHttpRequestSession::setPostDataFcn(const char *http_data,
239 const uint32_t http_data_len,
240 const char *http_content_type)
241 {
242 mHasPostData = true;
243 mPostData.Assign(http_data, http_data_len);
244 mPostContentType.Assign(http_content_type);
245
246 return SECSuccess;
247 }
248
249 SECStatus nsNSSHttpRequestSession::addHeaderFcn(const char *http_header_name,
250 const char *http_header_value)
251 {
252 return SECFailure; // not yet implemented
253
254 // All http code needs to be postponed to the UI thread.
255 // Once this gets implemented, we need to add a string list member to
256 // nsNSSHttpRequestSession and queue up the headers,
257 // so they can be added in HandleHTTPDownloadPLEvent.
258 //
259 // The header will need to be set using
260 // mHttpChannel->SetRequestHeader(nsDependentCString(http_header_name),
261 // nsDependentCString(http_header_value),
262 // false)));
263 }
264
265 SECStatus nsNSSHttpRequestSession::trySendAndReceiveFcn(PRPollDesc **pPollDesc,
266 uint16_t *http_response_code,
267 const char **http_response_content_type,
268 const char **http_response_headers,
269 const char **http_response_data,
270 uint32_t *http_response_data_len)
271 {
272 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
273 ("nsNSSHttpRequestSession::trySendAndReceiveFcn to %s\n", mURL.get()));
274
275 bool onSTSThread;
276 nsresult nrv;
277 nsCOMPtr<nsIEventTarget> sts
278 = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &nrv);
279 if (NS_FAILED(nrv)) {
280 NS_ERROR("Could not get STS service");
281 PR_SetError(PR_INVALID_STATE_ERROR, 0);
282 return SECFailure;
283 }
284
285 nrv = sts->IsOnCurrentThread(&onSTSThread);
286 if (NS_FAILED(nrv)) {
287 NS_ERROR("IsOnCurrentThread failed");
288 PR_SetError(PR_INVALID_STATE_ERROR, 0);
289 return SECFailure;
290 }
291
292 if (onSTSThread) {
293 NS_ERROR("nsNSSHttpRequestSession::trySendAndReceiveFcn called on socket "
294 "thread; this will not work.");
295 PR_SetError(PR_INVALID_STATE_ERROR, 0);
296 return SECFailure;
297 }
298
299 const int max_retries = 2;
300 int retry_count = 0;
301 bool retryable_error = false;
302 SECStatus result_sec_status = SECFailure;
303
304 do
305 {
306 if (retry_count > 0)
307 {
308 if (retryable_error)
309 {
310 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
311 ("nsNSSHttpRequestSession::trySendAndReceiveFcn - sleeping and retrying: %d of %d\n",
312 retry_count, max_retries));
313 }
314
315 PR_Sleep( PR_MillisecondsToInterval(300) * retry_count );
316 }
317
318 ++retry_count;
319 retryable_error = false;
320
321 result_sec_status =
322 internal_send_receive_attempt(retryable_error, pPollDesc, http_response_code,
323 http_response_content_type, http_response_headers,
324 http_response_data, http_response_data_len);
325 }
326 while (retryable_error &&
327 retry_count < max_retries);
328
329 #ifdef PR_LOGGING
330 if (retry_count > 1)
331 {
332 if (retryable_error)
333 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
334 ("nsNSSHttpRequestSession::trySendAndReceiveFcn - still failing, giving up...\n"));
335 else
336 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
337 ("nsNSSHttpRequestSession::trySendAndReceiveFcn - success at attempt %d\n",
338 retry_count));
339 }
340 #endif
341
342 return result_sec_status;
343 }
344
345 void
346 nsNSSHttpRequestSession::AddRef()
347 {
348 ++mRefCount;
349 }
350
351 void
352 nsNSSHttpRequestSession::Release()
353 {
354 int32_t newRefCount = --mRefCount;
355 if (!newRefCount) {
356 delete this;
357 }
358 }
359
360 SECStatus
361 nsNSSHttpRequestSession::internal_send_receive_attempt(bool &retryable_error,
362 PRPollDesc **pPollDesc,
363 uint16_t *http_response_code,
364 const char **http_response_content_type,
365 const char **http_response_headers,
366 const char **http_response_data,
367 uint32_t *http_response_data_len)
368 {
369 if (pPollDesc) *pPollDesc = nullptr;
370 if (http_response_code) *http_response_code = 0;
371 if (http_response_content_type) *http_response_content_type = 0;
372 if (http_response_headers) *http_response_headers = 0;
373 if (http_response_data) *http_response_data = 0;
374
375 uint32_t acceptableResultSize = 0;
376
377 if (http_response_data_len)
378 {
379 acceptableResultSize = *http_response_data_len;
380 *http_response_data_len = 0;
381 }
382
383 if (!mListener)
384 return SECFailure;
385
386 Mutex& waitLock = mListener->mLock;
387 CondVar& waitCondition = mListener->mCondition;
388 volatile bool &waitFlag = mListener->mWaitFlag;
389 waitFlag = true;
390
391 RefPtr<nsHTTPDownloadEvent> event(new nsHTTPDownloadEvent);
392 if (!event)
393 return SECFailure;
394
395 event->mListener = mListener;
396 this->AddRef();
397 event->mRequestSession = this;
398
399 nsresult rv = NS_DispatchToMainThread(event);
400 if (NS_FAILED(rv))
401 {
402 event->mResponsibleForDoneSignal = false;
403 return SECFailure;
404 }
405
406 bool request_canceled = false;
407
408 {
409 MutexAutoLock locker(waitLock);
410
411 const PRIntervalTime start_time = PR_IntervalNow();
412 PRIntervalTime wait_interval;
413
414 bool running_on_main_thread = NS_IsMainThread();
415 if (running_on_main_thread)
416 {
417 // The result of running this on the main thread
418 // is a series of small timeouts mixed with spinning the
419 // event loop - this is always dangerous as there is so much main
420 // thread code that does not expect to be called re-entrantly. Your
421 // app really shouldn't do that.
422 NS_WARNING("Security network blocking I/O on Main Thread");
423
424 // let's process events quickly
425 wait_interval = PR_MicrosecondsToInterval(50);
426 }
427 else
428 {
429 // On a secondary thread, it's fine to wait some more for
430 // for the condition variable.
431 wait_interval = PR_MillisecondsToInterval(250);
432 }
433
434 while (waitFlag)
435 {
436 if (running_on_main_thread)
437 {
438 // Networking runs on the main thread, which we happen to block here.
439 // Processing events will allow the OCSP networking to run while we
440 // are waiting. Thanks a lot to Darin Fisher for rewriting the
441 // thread manager. Thanks a lot to Christian Biesinger who
442 // made me aware of this possibility. (kaie)
443
444 MutexAutoUnlock unlock(waitLock);
445 NS_ProcessNextEvent(nullptr);
446 }
447
448 waitCondition.Wait(wait_interval);
449
450 if (!waitFlag)
451 break;
452
453 if (!request_canceled)
454 {
455 bool timeout =
456 (PRIntervalTime)(PR_IntervalNow() - start_time) > mTimeoutInterval;
457
458 if (timeout)
459 {
460 request_canceled = true;
461
462 RefPtr<nsCancelHTTPDownloadEvent> cancelevent(
463 new nsCancelHTTPDownloadEvent);
464 cancelevent->mListener = mListener;
465 rv = NS_DispatchToMainThread(cancelevent);
466 if (NS_FAILED(rv)) {
467 NS_WARNING("cannot post cancel event");
468 }
469 break;
470 }
471 }
472 }
473 }
474
475 if (!event->mStartTime.IsNull()) {
476 if (request_canceled) {
477 Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 0);
478 Telemetry::AccumulateTimeDelta(
479 Telemetry::CERT_VALIDATION_HTTP_REQUEST_CANCELED_TIME,
480 event->mStartTime, TimeStamp::Now());
481 }
482 else if (NS_SUCCEEDED(mListener->mResultCode) &&
483 mListener->mHttpResponseCode == 200) {
484 Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 1);
485 Telemetry::AccumulateTimeDelta(
486 Telemetry::CERT_VALIDATION_HTTP_REQUEST_SUCCEEDED_TIME,
487 event->mStartTime, TimeStamp::Now());
488 }
489 else {
490 Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 2);
491 Telemetry::AccumulateTimeDelta(
492 Telemetry::CERT_VALIDATION_HTTP_REQUEST_FAILED_TIME,
493 event->mStartTime, TimeStamp::Now());
494 }
495 }
496 else {
497 Telemetry::Accumulate(Telemetry::CERT_VALIDATION_HTTP_REQUEST_RESULT, 3);
498 }
499
500 if (request_canceled)
501 return SECFailure;
502
503 if (NS_FAILED(mListener->mResultCode))
504 {
505 if (mListener->mResultCode == NS_ERROR_CONNECTION_REFUSED
506 ||
507 mListener->mResultCode == NS_ERROR_NET_RESET)
508 {
509 retryable_error = true;
510 }
511 return SECFailure;
512 }
513
514 if (http_response_code)
515 *http_response_code = mListener->mHttpResponseCode;
516
517 if (mListener->mHttpRequestSucceeded && http_response_data && http_response_data_len) {
518
519 *http_response_data_len = mListener->mResultLen;
520
521 // acceptableResultSize == 0 means: any size is acceptable
522 if (acceptableResultSize != 0
523 &&
524 acceptableResultSize < mListener->mResultLen)
525 {
526 return SECFailure;
527 }
528
529 // return data by reference, result data will be valid
530 // until "this" gets destroyed by NSS
531 *http_response_data = (const char*)mListener->mResultData;
532 }
533
534 if (mListener->mHttpRequestSucceeded && http_response_content_type) {
535 if (mListener->mHttpResponseContentType.Length()) {
536 *http_response_content_type = mListener->mHttpResponseContentType.get();
537 }
538 }
539
540 return SECSuccess;
541 }
542
543 SECStatus nsNSSHttpRequestSession::cancelFcn()
544 {
545 // As of today, only the blocking variant of the http interface
546 // has been implemented. Implementing cancelFcn will be necessary
547 // as soon as we implement the nonblocking variant.
548 return SECSuccess;
549 }
550
551 SECStatus nsNSSHttpRequestSession::freeFcn()
552 {
553 Release();
554 return SECSuccess;
555 }
556
557 nsNSSHttpRequestSession::nsNSSHttpRequestSession()
558 : mRefCount(1),
559 mHasPostData(false),
560 mTimeoutInterval(0),
561 mListener(new nsHTTPListener)
562 {
563 }
564
565 nsNSSHttpRequestSession::~nsNSSHttpRequestSession()
566 {
567 }
568
569 SEC_HttpClientFcn nsNSSHttpInterface::sNSSInterfaceTable;
570
571 void nsNSSHttpInterface::initTable()
572 {
573 sNSSInterfaceTable.version = 1;
574 SEC_HttpClientFcnV1 &v1 = sNSSInterfaceTable.fcnTable.ftable1;
575 v1.createSessionFcn = createSessionFcn;
576 v1.keepAliveSessionFcn = keepAliveFcn;
577 v1.freeSessionFcn = freeSessionFcn;
578 v1.createFcn = createFcn;
579 v1.setPostDataFcn = setPostDataFcn;
580 v1.addHeaderFcn = addHeaderFcn;
581 v1.trySendAndReceiveFcn = trySendAndReceiveFcn;
582 v1.cancelFcn = cancelFcn;
583 v1.freeFcn = freeFcn;
584 }
585
586 void nsNSSHttpInterface::registerHttpClient()
587 {
588 SEC_RegisterDefaultHttpClient(&sNSSInterfaceTable);
589 }
590
591 void nsNSSHttpInterface::unregisterHttpClient()
592 {
593 SEC_RegisterDefaultHttpClient(nullptr);
594 }
595
596 nsHTTPListener::nsHTTPListener()
597 : mResultData(nullptr),
598 mResultLen(0),
599 mLock("nsHTTPListener.mLock"),
600 mCondition(mLock, "nsHTTPListener.mCondition"),
601 mWaitFlag(true),
602 mResponsibleForDoneSignal(false),
603 mLoadGroup(nullptr),
604 mLoadGroupOwnerThread(nullptr)
605 {
606 }
607
608 nsHTTPListener::~nsHTTPListener()
609 {
610 if (mResponsibleForDoneSignal)
611 send_done_signal();
612
613 if (mResultData) {
614 NS_Free(const_cast<uint8_t *>(mResultData));
615 }
616
617 if (mLoader) {
618 nsCOMPtr<nsIThread> mainThread(do_GetMainThread());
619 NS_ProxyRelease(mainThread, mLoader);
620 }
621 }
622
623 NS_IMPL_ISUPPORTS(nsHTTPListener, nsIStreamLoaderObserver)
624
625 void
626 nsHTTPListener::FreeLoadGroup(bool aCancelLoad)
627 {
628 nsILoadGroup *lg = nullptr;
629
630 MutexAutoLock locker(mLock);
631
632 if (mLoadGroup) {
633 if (mLoadGroupOwnerThread != PR_GetCurrentThread()) {
634 NS_ASSERTION(false,
635 "attempt to access nsHTTPDownloadEvent::mLoadGroup on multiple threads, leaking it!");
636 }
637 else {
638 lg = mLoadGroup;
639 mLoadGroup = nullptr;
640 }
641 }
642
643 if (lg) {
644 if (aCancelLoad) {
645 lg->Cancel(NS_ERROR_ABORT);
646 }
647 NS_RELEASE(lg);
648 }
649 }
650
651 NS_IMETHODIMP
652 nsHTTPListener::OnStreamComplete(nsIStreamLoader* aLoader,
653 nsISupports* aContext,
654 nsresult aStatus,
655 uint32_t stringLen,
656 const uint8_t* string)
657 {
658 mResultCode = aStatus;
659
660 FreeLoadGroup(false);
661
662 nsCOMPtr<nsIRequest> req;
663 nsCOMPtr<nsIHttpChannel> hchan;
664
665 nsresult rv = aLoader->GetRequest(getter_AddRefs(req));
666
667 #ifdef PR_LOGGING
668 if (NS_FAILED(aStatus))
669 {
670 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
671 ("nsHTTPListener::OnStreamComplete status failed %d", aStatus));
672 }
673 #endif
674
675 if (NS_SUCCEEDED(rv))
676 hchan = do_QueryInterface(req, &rv);
677
678 if (NS_SUCCEEDED(rv))
679 {
680 rv = hchan->GetRequestSucceeded(&mHttpRequestSucceeded);
681 if (NS_FAILED(rv))
682 mHttpRequestSucceeded = false;
683
684 mResultLen = stringLen;
685 mResultData = string; // take ownership of allocation
686 aStatus = NS_SUCCESS_ADOPTED_DATA;
687
688 unsigned int rcode;
689 rv = hchan->GetResponseStatus(&rcode);
690 if (NS_FAILED(rv))
691 mHttpResponseCode = 500;
692 else
693 mHttpResponseCode = rcode;
694
695 hchan->GetResponseHeader(NS_LITERAL_CSTRING("Content-Type"),
696 mHttpResponseContentType);
697 }
698
699 if (mResponsibleForDoneSignal)
700 send_done_signal();
701
702 return aStatus;
703 }
704
705 void nsHTTPListener::send_done_signal()
706 {
707 mResponsibleForDoneSignal = false;
708
709 {
710 MutexAutoLock locker(mLock);
711 mWaitFlag = false;
712 mCondition.NotifyAll();
713 }
714 }
715
716 static char*
717 ShowProtectedAuthPrompt(PK11SlotInfo* slot, nsIInterfaceRequestor *ir)
718 {
719 if (!NS_IsMainThread()) {
720 NS_ERROR("ShowProtectedAuthPrompt called off the main thread");
721 return nullptr;
722 }
723
724 char* protAuthRetVal = nullptr;
725
726 // Get protected auth dialogs
727 nsITokenDialogs* dialogs = 0;
728 nsresult nsrv = getNSSDialogs((void**)&dialogs,
729 NS_GET_IID(nsITokenDialogs),
730 NS_TOKENDIALOGS_CONTRACTID);
731 if (NS_SUCCEEDED(nsrv))
732 {
733 nsProtectedAuthThread* protectedAuthRunnable = new nsProtectedAuthThread();
734 if (protectedAuthRunnable)
735 {
736 NS_ADDREF(protectedAuthRunnable);
737
738 protectedAuthRunnable->SetParams(slot);
739
740 nsCOMPtr<nsIProtectedAuthThread> runnable = do_QueryInterface(protectedAuthRunnable);
741 if (runnable)
742 {
743 nsrv = dialogs->DisplayProtectedAuth(ir, runnable);
744
745 // We call join on the thread,
746 // so we can be sure that no simultaneous access will happen.
747 protectedAuthRunnable->Join();
748
749 if (NS_SUCCEEDED(nsrv))
750 {
751 SECStatus rv = protectedAuthRunnable->GetResult();
752 switch (rv)
753 {
754 case SECSuccess:
755 protAuthRetVal = ToNewCString(nsDependentCString(PK11_PW_AUTHENTICATED));
756 break;
757 case SECWouldBlock:
758 protAuthRetVal = ToNewCString(nsDependentCString(PK11_PW_RETRY));
759 break;
760 default:
761 protAuthRetVal = nullptr;
762 break;
763
764 }
765 }
766 }
767
768 NS_RELEASE(protectedAuthRunnable);
769 }
770
771 NS_RELEASE(dialogs);
772 }
773
774 return protAuthRetVal;
775 }
776
777 class PK11PasswordPromptRunnable : public SyncRunnableBase
778 {
779 public:
780 PK11PasswordPromptRunnable(PK11SlotInfo* slot,
781 nsIInterfaceRequestor* ir)
782 : mResult(nullptr),
783 mSlot(slot),
784 mIR(ir)
785 {
786 }
787 char * mResult; // out
788 virtual void RunOnTargetThread();
789 private:
790 PK11SlotInfo* const mSlot; // in
791 nsIInterfaceRequestor* const mIR; // in
792 };
793
794 void PK11PasswordPromptRunnable::RunOnTargetThread()
795 {
796 static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
797
798 nsNSSShutDownPreventionLock locker;
799 nsresult rv = NS_OK;
800 char16_t *password = nullptr;
801 bool value = false;
802 nsCOMPtr<nsIPrompt> prompt;
803
804 /* TODO: Retry should generate a different dialog message */
805 /*
806 if (retry)
807 return nullptr;
808 */
809
810 if (!mIR)
811 {
812 nsNSSComponent::GetNewPrompter(getter_AddRefs(prompt));
813 }
814 else
815 {
816 prompt = do_GetInterface(mIR);
817 NS_ASSERTION(prompt, "callbacks does not implement nsIPrompt");
818 }
819
820 if (!prompt)
821 return;
822
823 if (PK11_ProtectedAuthenticationPath(mSlot)) {
824 mResult = ShowProtectedAuthPrompt(mSlot, mIR);
825 return;
826 }
827
828 nsAutoString promptString;
829 nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
830
831 if (NS_FAILED(rv))
832 return;
833
834 const char16_t* formatStrings[1] = {
835 ToNewUnicode(NS_ConvertUTF8toUTF16(PK11_GetTokenName(mSlot)))
836 };
837 rv = nssComponent->PIPBundleFormatStringFromName("CertPassPrompt",
838 formatStrings, 1,
839 promptString);
840 nsMemory::Free(const_cast<char16_t*>(formatStrings[0]));
841
842 if (NS_FAILED(rv))
843 return;
844
845 {
846 nsPSMUITracker tracker;
847 if (tracker.isUIForbidden()) {
848 rv = NS_ERROR_NOT_AVAILABLE;
849 }
850 else {
851 // Although the exact value is ignored, we must not pass invalid
852 // bool values through XPConnect.
853 bool checkState = false;
854 rv = prompt->PromptPassword(nullptr, promptString.get(),
855 &password, nullptr, &checkState, &value);
856 }
857 }
858
859 if (NS_SUCCEEDED(rv) && value) {
860 mResult = ToNewUTF8String(nsDependentString(password));
861 NS_Free(password);
862 }
863 }
864
865 char*
866 PK11PasswordPrompt(PK11SlotInfo* slot, PRBool retry, void* arg)
867 {
868 RefPtr<PK11PasswordPromptRunnable> runnable(
869 new PK11PasswordPromptRunnable(slot,
870 static_cast<nsIInterfaceRequestor*>(arg)));
871 runnable->DispatchToMainThreadAndWait();
872 return runnable->mResult;
873 }
874
875 // call with shutdown prevention lock held
876 static void
877 PreliminaryHandshakeDone(PRFileDesc* fd)
878 {
879 nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
880 if (!infoObject)
881 return;
882
883 if (infoObject->IsPreliminaryHandshakeDone())
884 return;
885
886 infoObject->SetPreliminaryHandshakeDone();
887
888 SSLChannelInfo channelInfo;
889 if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) == SECSuccess) {
890 infoObject->SetSSLVersionUsed(channelInfo.protocolVersion);
891 }
892
893 // Get the NPN value.
894 SSLNextProtoState state;
895 unsigned char npnbuf[256];
896 unsigned int npnlen;
897
898 if (SSL_GetNextProto(fd, &state, npnbuf, &npnlen, 256) == SECSuccess) {
899 if (state == SSL_NEXT_PROTO_NEGOTIATED ||
900 state == SSL_NEXT_PROTO_SELECTED) {
901 infoObject->SetNegotiatedNPN(reinterpret_cast<char *>(npnbuf), npnlen);
902 }
903 else {
904 infoObject->SetNegotiatedNPN(nullptr, 0);
905 }
906 mozilla::Telemetry::Accumulate(Telemetry::SSL_NPN_TYPE, state);
907 }
908 else {
909 infoObject->SetNegotiatedNPN(nullptr, 0);
910 }
911 }
912
913 SECStatus
914 CanFalseStartCallback(PRFileDesc* fd, void* client_data, PRBool *canFalseStart)
915 {
916 *canFalseStart = false;
917
918 nsNSSShutDownPreventionLock locker;
919
920 nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
921 if (!infoObject) {
922 PR_SetError(PR_INVALID_STATE_ERROR, 0);
923 return SECFailure;
924 }
925
926 infoObject->SetFalseStartCallbackCalled();
927
928 if (infoObject->isAlreadyShutDown()) {
929 MOZ_CRASH("SSL socket used after NSS shut down");
930 PR_SetError(PR_INVALID_STATE_ERROR, 0);
931 return SECFailure;
932 }
933
934 PreliminaryHandshakeDone(fd);
935
936 uint32_t reasonsForNotFalseStarting = 0;
937
938 SSLChannelInfo channelInfo;
939 if (SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo)) != SECSuccess) {
940 return SECSuccess;
941 }
942
943 SSLCipherSuiteInfo cipherInfo;
944 if (SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
945 sizeof (cipherInfo)) != SECSuccess) {
946 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
947 " KEA %d\n", fd,
948 static_cast<int32_t>(cipherInfo.keaType)));
949 return SECSuccess;
950 }
951
952 nsSSLIOLayerHelpers& helpers = infoObject->SharedState().IOLayerHelpers();
953
954 // Prevent version downgrade attacks from TLS 1.x to SSL 3.0.
955 // TODO(bug 861310): If we negotiate less than our highest-supported version,
956 // then check that a previously-completed handshake negotiated that version;
957 // eventually, require that the highest-supported version of TLS is used.
958 if (channelInfo.protocolVersion < SSL_LIBRARY_VERSION_TLS_1_0) {
959 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
960 "SSL Version must be >= TLS1 %x\n", fd,
961 static_cast<int32_t>(channelInfo.protocolVersion)));
962 reasonsForNotFalseStarting |= POSSIBLE_VERSION_DOWNGRADE;
963 }
964
965 // never do false start without one of these key exchange algorithms
966 if (cipherInfo.keaType != ssl_kea_rsa &&
967 cipherInfo.keaType != ssl_kea_dh &&
968 cipherInfo.keaType != ssl_kea_ecdh) {
969 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
970 "unsupported KEA %d\n", fd,
971 static_cast<int32_t>(cipherInfo.keaType)));
972 reasonsForNotFalseStarting |= KEA_NOT_SUPPORTED;
973 }
974
975 // XXX: This assumes that all TLS_DH_* and TLS_ECDH_* cipher suites
976 // are disabled.
977 if (cipherInfo.keaType != ssl_kea_ecdh &&
978 cipherInfo.keaType != ssl_kea_dh) {
979 if (helpers.mFalseStartRequireForwardSecrecy) {
980 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
981 ("CanFalseStartCallback [%p] failed - KEA used is %d, but "
982 "require-forward-secrecy configured.\n", fd,
983 static_cast<int32_t>(cipherInfo.keaType)));
984 reasonsForNotFalseStarting |= KEA_NOT_FORWARD_SECRET;
985 } else if (cipherInfo.keaType == ssl_kea_rsa) {
986 // Make sure we've seen the same kea from this host in the past, to limit
987 // the potential for downgrade attacks.
988 int16_t expected = infoObject->GetKEAExpected();
989 if (cipherInfo.keaType != expected) {
990 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
991 ("CanFalseStartCallback [%p] failed - "
992 "KEA used is %d, expected %d\n", fd,
993 static_cast<int32_t>(cipherInfo.keaType),
994 static_cast<int32_t>(expected)));
995 reasonsForNotFalseStarting |= KEA_NOT_SAME_AS_EXPECTED;
996 }
997 } else {
998 reasonsForNotFalseStarting |= KEA_NOT_ALLOWED;
999 }
1000 }
1001
1002 // Prevent downgrade attacks on the symmetric cipher. We accept downgrades
1003 // from 256-bit keys to 128-bit keys and we treat AES and Camellia as being
1004 // equally secure. We consider every message authentication mechanism that we
1005 // support *for these ciphers* to be equally-secure. We assume that for CBC
1006 // mode, that the server has implemented all the same mitigations for
1007 // published attacks that we have, or that those attacks are not relevant in
1008 // the decision to false start.
1009 if (cipherInfo.symCipher != ssl_calg_aes_gcm &&
1010 cipherInfo.symCipher != ssl_calg_aes &&
1011 cipherInfo.symCipher != ssl_calg_camellia) {
1012 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1013 ("CanFalseStartCallback [%p] failed - Symmetric cipher used, %d, "
1014 "is not supported with False Start.\n", fd,
1015 static_cast<int32_t>(cipherInfo.symCipher)));
1016 reasonsForNotFalseStarting |= POSSIBLE_CIPHER_SUITE_DOWNGRADE;
1017 }
1018
1019 // XXX: An attacker can choose which protocols are advertised in the
1020 // NPN extension. TODO(Bug 861311): We should restrict the ability
1021 // of an attacker leverage this capability by restricting false start
1022 // to the same protocol we previously saw for the server, after the
1023 // first successful connection to the server.
1024
1025 // Enforce NPN to do false start if policy requires it. Do this as an
1026 // indicator if server compatibility.
1027 if (helpers.mFalseStartRequireNPN) {
1028 nsAutoCString negotiatedNPN;
1029 if (NS_FAILED(infoObject->GetNegotiatedNPN(negotiatedNPN)) ||
1030 !negotiatedNPN.Length()) {
1031 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] failed - "
1032 "NPN cannot be verified\n", fd));
1033 reasonsForNotFalseStarting |= NPN_NOT_NEGOTIATED;
1034 }
1035 }
1036
1037 Telemetry::Accumulate(Telemetry::SSL_REASONS_FOR_NOT_FALSE_STARTING,
1038 reasonsForNotFalseStarting);
1039
1040 if (reasonsForNotFalseStarting == 0) {
1041 *canFalseStart = PR_TRUE;
1042 infoObject->SetFalseStarted();
1043 infoObject->NoteTimeUntilReady();
1044 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("CanFalseStartCallback [%p] ok\n", fd));
1045 }
1046
1047 return SECSuccess;
1048 }
1049
1050 static void
1051 AccumulateNonECCKeySize(Telemetry::ID probe, uint32_t bits)
1052 {
1053 unsigned int value = bits < 512 ? 1 : bits == 512 ? 2
1054 : bits < 768 ? 3 : bits == 768 ? 4
1055 : bits < 1024 ? 5 : bits == 1024 ? 6
1056 : bits < 1280 ? 7 : bits == 1280 ? 8
1057 : bits < 1536 ? 9 : bits == 1536 ? 10
1058 : bits < 2048 ? 11 : bits == 2048 ? 12
1059 : bits < 3072 ? 13 : bits == 3072 ? 14
1060 : bits < 4096 ? 15 : bits == 4096 ? 16
1061 : bits < 8192 ? 17 : bits == 8192 ? 18
1062 : bits < 16384 ? 19 : bits == 16384 ? 20
1063 : 0;
1064 Telemetry::Accumulate(probe, value);
1065 }
1066
1067 // XXX: This attempts to map a bit count to an ECC named curve identifier. In
1068 // the vast majority of situations, we only have the Suite B curves available.
1069 // In that case, this mapping works fine. If we were to have more curves
1070 // available, the mapping would be ambiguous since there could be multiple
1071 // named curves for a given size (e.g. secp256k1 vs. secp256r1). We punt on
1072 // that for now. See also NSS bug 323674.
1073 static void
1074 AccumulateECCCurve(Telemetry::ID probe, uint32_t bits)
1075 {
1076 unsigned int value = bits == 256 ? 23 // P-256
1077 : bits == 384 ? 24 // P-384
1078 : bits == 521 ? 25 // P-521
1079 : 0; // Unknown
1080 Telemetry::Accumulate(probe, value);
1081 }
1082
1083 static void
1084 AccumulateCipherSuite(Telemetry::ID probe, const SSLChannelInfo& channelInfo)
1085 {
1086 uint32_t value;
1087 switch (channelInfo.cipherSuite) {
1088 // ECDHE key exchange
1089 case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: value = 1; break;
1090 case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: value = 2; break;
1091 case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: value = 3; break;
1092 case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: value = 4; break;
1093 case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: value = 5; break;
1094 case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: value = 6; break;
1095 case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: value = 7; break;
1096 case TLS_ECDHE_RSA_WITH_RC4_128_SHA: value = 8; break;
1097 case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: value = 9; break;
1098 case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: value = 10; break;
1099 // DHE key exchange
1100 case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: value = 21; break;
1101 case TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA: value = 22; break;
1102 case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: value = 23; break;
1103 case TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA: value = 24; break;
1104 case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: value = 25; break;
1105 case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: value = 26; break;
1106 case TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA: value = 27; break;
1107 case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: value = 28; break;
1108 case TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA: value = 29; break;
1109 case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: value = 30; break;
1110 // ECDH key exchange
1111 case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: value = 41; break;
1112 case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: value = 42; break;
1113 case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: value = 43; break;
1114 case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: value = 44; break;
1115 case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: value = 45; break;
1116 case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: value = 46; break;
1117 case TLS_ECDH_ECDSA_WITH_RC4_128_SHA: value = 47; break;
1118 case TLS_ECDH_RSA_WITH_RC4_128_SHA: value = 48; break;
1119 // RSA key exchange
1120 case TLS_RSA_WITH_AES_128_CBC_SHA: value = 61; break;
1121 case TLS_RSA_WITH_CAMELLIA_128_CBC_SHA: value = 62; break;
1122 case TLS_RSA_WITH_AES_256_CBC_SHA: value = 63; break;
1123 case TLS_RSA_WITH_CAMELLIA_256_CBC_SHA: value = 64; break;
1124 case SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA: value = 65; break;
1125 case TLS_RSA_WITH_3DES_EDE_CBC_SHA: value = 66; break;
1126 case TLS_RSA_WITH_SEED_CBC_SHA: value = 67; break;
1127 case TLS_RSA_WITH_RC4_128_SHA: value = 68; break;
1128 case TLS_RSA_WITH_RC4_128_MD5: value = 69; break;
1129 // unknown
1130 default:
1131 value = 0;
1132 break;
1133 }
1134 MOZ_ASSERT(value != 0);
1135 Telemetry::Accumulate(probe, value);
1136 }
1137
1138 void HandshakeCallback(PRFileDesc* fd, void* client_data) {
1139 nsNSSShutDownPreventionLock locker;
1140 SECStatus rv;
1141
1142 nsNSSSocketInfo* infoObject = (nsNSSSocketInfo*) fd->higher->secret;
1143
1144 // Do the bookkeeping that needs to be done after the
1145 // server's ServerHello...ServerHelloDone have been processed, but that doesn't
1146 // need the handshake to be completed.
1147 PreliminaryHandshakeDone(fd);
1148
1149 nsSSLIOLayerHelpers& ioLayerHelpers
1150 = infoObject->SharedState().IOLayerHelpers();
1151
1152 SSLVersionRange versions(infoObject->GetTLSVersionRange());
1153
1154 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1155 ("[%p] HandshakeCallback: succeeded using TLS version range (0x%04x,0x%04x)\n",
1156 fd, static_cast<unsigned int>(versions.min),
1157 static_cast<unsigned int>(versions.max)));
1158
1159 // If the handshake completed, then we know the site is TLS tolerant
1160 ioLayerHelpers.rememberTolerantAtVersion(infoObject->GetHostName(),
1161 infoObject->GetPort(),
1162 versions.max);
1163
1164 PRBool siteSupportsSafeRenego;
1165 rv = SSL_HandshakeNegotiatedExtension(fd, ssl_renegotiation_info_xtn,
1166 &siteSupportsSafeRenego);
1167 MOZ_ASSERT(rv == SECSuccess);
1168 if (rv != SECSuccess) {
1169 siteSupportsSafeRenego = false;
1170 }
1171
1172 if (siteSupportsSafeRenego ||
1173 !ioLayerHelpers.treatUnsafeNegotiationAsBroken()) {
1174 infoObject->SetSecurityState(nsIWebProgressListener::STATE_IS_SECURE |
1175 nsIWebProgressListener::STATE_SECURE_HIGH);
1176 } else {
1177 infoObject->SetSecurityState(nsIWebProgressListener::STATE_IS_BROKEN);
1178 }
1179
1180 // XXX Bug 883674: We shouldn't be formatting messages here in PSM; instead,
1181 // we should set a flag on the channel that higher (UI) level code can check
1182 // to log the warning. In particular, these warnings should go to the web
1183 // console instead of to the error console. Also, the warning is not
1184 // localized.
1185 if (!siteSupportsSafeRenego &&
1186 ioLayerHelpers.getWarnLevelMissingRFC5746() > 0) {
1187 nsXPIDLCString hostName;
1188 infoObject->GetHostName(getter_Copies(hostName));
1189
1190 nsAutoString msg;
1191 msg.Append(NS_ConvertASCIItoUTF16(hostName));
1192 msg.Append(NS_LITERAL_STRING(" : server does not support RFC 5746, see CVE-2009-3555"));
1193
1194 nsContentUtils::LogSimpleConsoleError(msg, "SSL");
1195 }
1196
1197 mozilla::pkix::ScopedCERTCertificate serverCert(SSL_PeerCertificate(fd));
1198
1199 /* Set the SSL Status information */
1200 RefPtr<nsSSLStatus> status(infoObject->SSLStatus());
1201 if (!status) {
1202 status = new nsSSLStatus();
1203 infoObject->SetSSLStatus(status);
1204 }
1205
1206 RememberCertErrorsTable::GetInstance().LookupCertErrorBits(infoObject,
1207 status);
1208
1209 RefPtr<nsNSSCertificate> nssc(nsNSSCertificate::Create(serverCert.get()));
1210 nsCOMPtr<nsIX509Cert> prevcert;
1211 infoObject->GetPreviousCert(getter_AddRefs(prevcert));
1212
1213 bool equals_previous = false;
1214 if (prevcert && nssc) {
1215 nsresult rv = nssc->Equals(prevcert, &equals_previous);
1216 if (NS_FAILED(rv)) {
1217 equals_previous = false;
1218 }
1219 }
1220
1221 if (equals_previous) {
1222 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1223 ("HandshakeCallback using PREV cert %p\n", prevcert.get()));
1224 status->mServerCert = prevcert;
1225 }
1226 else {
1227 if (status->mServerCert) {
1228 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1229 ("HandshakeCallback KEEPING cert %p\n", status->mServerCert.get()));
1230 }
1231 else {
1232 PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
1233 ("HandshakeCallback using NEW cert %p\n", nssc.get()));
1234 status->mServerCert = nssc;
1235 }
1236 }
1237
1238 SSLChannelInfo channelInfo;
1239 rv = SSL_GetChannelInfo(fd, &channelInfo, sizeof(channelInfo));
1240 MOZ_ASSERT(rv == SECSuccess);
1241 if (rv == SECSuccess) {
1242 // Get the protocol version for telemetry
1243 // 0=ssl3, 1=tls1, 2=tls1.1, 3=tls1.2
1244 unsigned int versionEnum = channelInfo.protocolVersion & 0xFF;
1245 Telemetry::Accumulate(Telemetry::SSL_HANDSHAKE_VERSION, versionEnum);
1246 AccumulateCipherSuite(
1247 infoObject->IsFullHandshake() ? Telemetry::SSL_CIPHER_SUITE_FULL
1248 : Telemetry::SSL_CIPHER_SUITE_RESUMED,
1249 channelInfo);
1250
1251 SSLCipherSuiteInfo cipherInfo;
1252 rv = SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
1253 sizeof cipherInfo);
1254 MOZ_ASSERT(rv == SECSuccess);
1255 if (rv == SECSuccess) {
1256 status->mHaveKeyLengthAndCipher = true;
1257 status->mKeyLength = cipherInfo.symKeyBits;
1258 status->mSecretKeyLength = cipherInfo.effectiveKeyBits;
1259 status->mCipherName.Assign(cipherInfo.cipherSuiteName);
1260
1261 // keyExchange null=0, rsa=1, dh=2, fortezza=3, ecdh=4
1262 Telemetry::Accumulate(
1263 infoObject->IsFullHandshake()
1264 ? Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_FULL
1265 : Telemetry::SSL_KEY_EXCHANGE_ALGORITHM_RESUMED,
1266 cipherInfo.keaType);
1267 infoObject->SetKEAUsed(cipherInfo.keaType);
1268
1269 if (infoObject->IsFullHandshake()) {
1270 switch (cipherInfo.keaType) {
1271 case ssl_kea_rsa:
1272 AccumulateNonECCKeySize(Telemetry::SSL_KEA_RSA_KEY_SIZE_FULL,
1273 channelInfo.keaKeyBits);
1274 break;
1275 case ssl_kea_dh:
1276 AccumulateNonECCKeySize(Telemetry::SSL_KEA_DHE_KEY_SIZE_FULL,
1277 channelInfo.keaKeyBits);
1278 break;
1279 case ssl_kea_ecdh:
1280 AccumulateECCCurve(Telemetry::SSL_KEA_ECDHE_CURVE_FULL,
1281 channelInfo.keaKeyBits);
1282 break;
1283 default:
1284 MOZ_CRASH("impossible KEA");
1285 break;
1286 }
1287
1288 Telemetry::Accumulate(Telemetry::SSL_AUTH_ALGORITHM_FULL,
1289 cipherInfo.authAlgorithm);
1290
1291 // RSA key exchange doesn't use a signature for auth.
1292 if (cipherInfo.keaType != ssl_kea_rsa) {
1293 switch (cipherInfo.authAlgorithm) {
1294 case ssl_auth_rsa:
1295 AccumulateNonECCKeySize(Telemetry::SSL_AUTH_RSA_KEY_SIZE_FULL,
1296 channelInfo.authKeyBits);
1297 break;
1298 case ssl_auth_dsa:
1299 AccumulateNonECCKeySize(Telemetry::SSL_AUTH_DSA_KEY_SIZE_FULL,
1300 channelInfo.authKeyBits);
1301 break;
1302 case ssl_auth_ecdsa:
1303 AccumulateECCCurve(Telemetry::SSL_AUTH_ECDSA_CURVE_FULL,
1304 channelInfo.authKeyBits);
1305 break;
1306 default:
1307 MOZ_CRASH("impossible auth algorithm");
1308 break;
1309 }
1310 }
1311 }
1312
1313 Telemetry::Accumulate(
1314 infoObject->IsFullHandshake()
1315 ? Telemetry::SSL_SYMMETRIC_CIPHER_FULL
1316 : Telemetry::SSL_SYMMETRIC_CIPHER_RESUMED,
1317 cipherInfo.symCipher);
1318 }
1319 }
1320
1321 infoObject->NoteTimeUntilReady();
1322 infoObject->SetHandshakeCompleted();
1323 }

mercurial