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