1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : *
3 : * ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is mozilla.org code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Brian Ryner <bryner@brianryner.com>
25 : * Javier Delgadillo <javi@netscape.com>
26 : * Kai Engert <kengert@redhat.com>
27 : *
28 : * Alternatively, the contents of this file may be used under the terms of
29 : * either the GNU General Public License Version 2 or later (the "GPL"), or
30 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 : * in which case the provisions of the GPL or the LGPL are applicable instead
32 : * of those above. If you wish to allow use of your version of this file only
33 : * under the terms of either the GPL or the LGPL, and not to allow others to
34 : * use your version of this file under the terms of the MPL, indicate your
35 : * decision by deleting the provisions above and replace them with the notice
36 : * and other provisions required by the GPL or the LGPL. If you do not delete
37 : * the provisions above, a recipient may use your version of this file under
38 : * the terms of any one of the MPL, the GPL or the LGPL.
39 : *
40 : * ***** END LICENSE BLOCK ***** */
41 :
42 : #include "nsNSSComponent.h"
43 : #include "nsNSSIOLayer.h"
44 : #include "nsNSSCallbacks.h"
45 :
46 : #include "prlog.h"
47 : #include "prnetdb.h"
48 : #include "nsIPrefService.h"
49 : #include "nsIPrefBranch.h"
50 : #include "nsIServiceManager.h"
51 : #include "nsIWebProgressListener.h"
52 : #include "nsIChannel.h"
53 : #include "nsNSSCertificate.h"
54 : #include "nsIX509CertValidity.h"
55 : #include "nsIDateTimeFormat.h"
56 : #include "nsDateTimeFormatCID.h"
57 : #include "nsIClientAuthDialogs.h"
58 : #include "nsClientAuthRemember.h"
59 : #include "nsICertOverrideService.h"
60 : #include "nsISSLErrorListener.h"
61 : #include "nsIObjectInputStream.h"
62 : #include "nsIObjectOutputStream.h"
63 :
64 : #include "nsXPIDLString.h"
65 : #include "nsReadableUtils.h"
66 : #include "nsCRT.h"
67 : #include "nsAutoPtr.h"
68 : #include "nsPrintfCString.h"
69 : #include "SSLServerCertVerification.h"
70 : #include "nsNSSShutDown.h"
71 : #include "nsSSLStatus.h"
72 : #include "nsNSSCertHelper.h"
73 : #include "nsNSSCleaner.h"
74 : #include "nsIDocShell.h"
75 : #include "nsIDocShellTreeItem.h"
76 : #include "nsISecureBrowserUI.h"
77 : #include "nsIClassInfoImpl.h"
78 : #include "nsIProgrammingLanguage.h"
79 : #include "nsIArray.h"
80 : #include "nsCharSeparatedTokenizer.h"
81 : #include "PSMRunnable.h"
82 :
83 : #include "ssl.h"
84 : #include "secerr.h"
85 : #include "sslerr.h"
86 : #include "secder.h"
87 : #include "secasn1.h"
88 : #include "certdb.h"
89 : #include "cert.h"
90 : #include "keyhi.h"
91 :
92 : #include "mozilla/Util.h"
93 :
94 : using namespace mozilla;
95 : using namespace mozilla::psm;
96 :
97 : //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal
98 : //reports when doing SSL read/write
99 :
100 : //#define DUMP_BUFFER //Enable this define along with
101 : //DEBUG_SSL_VERBOSE to dump SSL
102 : //read/write buffer to a log.
103 : //Uses PR_LOG except on Mac where
104 : //we always write out to our own
105 : //file.
106 :
107 :
108 0 : NSSCleanupAutoPtrClass(CERTCertificate, CERT_DestroyCertificate)
109 0 : NSSCleanupAutoPtrClass(void, PR_FREEIF)
110 :
111 : static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
112 :
113 : /* SSM_UserCertChoice: enum for cert choice info */
114 : typedef enum {ASK, AUTO} SSM_UserCertChoice;
115 :
116 : #ifdef PR_LOGGING
117 : extern PRLogModuleInfo* gPIPNSSLog;
118 : #endif
119 :
120 : #if defined(DEBUG_SSL_VERBOSE) && defined (XP_MAC)
121 :
122 : #ifdef PR_LOG
123 : #undef PR_LOG
124 : #endif
125 :
126 : static PRFileDesc *gMyLogFile = nsnull;
127 : #define MAC_LOG_FILE "MAC PIPNSS Log File"
128 :
129 : void MyLogFunction(const char *fmt, ...)
130 : {
131 :
132 : va_list ap;
133 : va_start(ap,fmt);
134 : if (gMyLogFile == nsnull)
135 : gMyLogFile = PR_Open(MAC_LOG_FILE, PR_WRONLY | PR_CREATE_FILE | PR_APPEND,
136 : 0600);
137 : if (!gMyLogFile)
138 : return;
139 : PR_vfprintf(gMyLogFile, fmt, ap);
140 : va_end(ap);
141 : }
142 :
143 : #define PR_LOG(module,level,args) MyLogFunction args
144 : #endif
145 :
146 4 : nsNSSSocketInfo::nsNSSSocketInfo()
147 : : mMutex("nsNSSSocketInfo::nsNSSSocketInfo"),
148 : mFd(nsnull),
149 : mCertVerificationState(before_cert_verification),
150 : mCertVerificationStarted(0),
151 : mCertVerificationEnded(0),
152 : mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE),
153 : mSubRequestsHighSecurity(0),
154 : mSubRequestsLowSecurity(0),
155 : mSubRequestsBrokenSecurity(0),
156 : mSubRequestsNoSecurity(0),
157 : mErrorCode(0),
158 : mErrorMessageType(PlainErrorMessage),
159 : mForSTARTTLS(false),
160 : mSSL3Enabled(false),
161 : mTLSEnabled(false),
162 : mHandshakePending(true),
163 : mHasCleartextPhase(false),
164 : mHandshakeInProgress(false),
165 : mAllowTLSIntoleranceTimeout(true),
166 : mRememberClientAuthCertificate(false),
167 : mHandshakeStartTime(0),
168 : mPort(0),
169 : mIsCertIssuerBlacklisted(false),
170 : mNPNCompleted(false),
171 : mHandshakeCompleted(false),
172 : mJoined(false),
173 4 : mSentClientCert(false)
174 : {
175 4 : }
176 :
177 12 : nsNSSSocketInfo::~nsNSSSocketInfo()
178 : {
179 8 : nsNSSShutDownPreventionLock locker;
180 4 : if (isAlreadyShutDown())
181 : return;
182 :
183 4 : shutdown(calledFromObject);
184 16 : }
185 :
186 4 : void nsNSSSocketInfo::virtualDestroyNSSReference()
187 : {
188 4 : }
189 :
190 280 : NS_IMPL_THREADSAFE_ISUPPORTS8(nsNSSSocketInfo,
191 : nsITransportSecurityInfo,
192 : nsISSLSocketControl,
193 : nsIInterfaceRequestor,
194 : nsISSLStatusProvider,
195 : nsIAssociatedContentSecurity,
196 : nsISerializable,
197 : nsIClassInfo,
198 : nsIClientAuthUserDecision)
199 :
200 : nsresult
201 32 : nsNSSSocketInfo::GetHandshakePending(bool *aHandshakePending)
202 : {
203 32 : *aHandshakePending = mHandshakePending;
204 32 : return NS_OK;
205 : }
206 :
207 : nsresult
208 4 : nsNSSSocketInfo::SetHandshakePending(bool aHandshakePending)
209 : {
210 4 : mHandshakePending = aHandshakePending;
211 4 : return NS_OK;
212 : }
213 :
214 : nsresult
215 4 : nsNSSSocketInfo::SetHostName(const char* host)
216 : {
217 4 : mHostName.Adopt(host ? NS_strdup(host) : 0);
218 4 : return NS_OK;
219 : }
220 :
221 : nsresult
222 12 : nsNSSSocketInfo::GetHostName(char **host)
223 : {
224 12 : *host = (mHostName) ? NS_strdup(mHostName) : nsnull;
225 12 : return NS_OK;
226 : }
227 :
228 : nsresult
229 4 : nsNSSSocketInfo::SetPort(PRInt32 aPort)
230 : {
231 4 : mPort = aPort;
232 4 : return NS_OK;
233 : }
234 :
235 : nsresult
236 12 : nsNSSSocketInfo::GetPort(PRInt32 *aPort)
237 : {
238 12 : *aPort = mPort;
239 12 : return NS_OK;
240 : }
241 :
242 : PRErrorCode
243 326 : nsNSSSocketInfo::GetErrorCode() const
244 : {
245 652 : MutexAutoLock lock(mMutex);
246 :
247 326 : return mErrorCode;
248 : }
249 :
250 : void
251 0 : nsNSSSocketInfo::SetCanceled(PRErrorCode errorCode,
252 : SSLErrorMessageType errorMessageType)
253 : {
254 0 : MutexAutoLock lock(mMutex);
255 :
256 0 : mErrorCode = errorCode;
257 0 : mErrorMessageType = errorMessageType;
258 0 : mErrorMessageCached.Truncate();
259 0 : }
260 :
261 0 : NS_IMETHODIMP nsNSSSocketInfo::GetRememberClientAuthCertificate(bool *aRememberClientAuthCertificate)
262 : {
263 0 : NS_ENSURE_ARG_POINTER(aRememberClientAuthCertificate);
264 0 : *aRememberClientAuthCertificate = mRememberClientAuthCertificate;
265 0 : return NS_OK;
266 : }
267 :
268 0 : NS_IMETHODIMP nsNSSSocketInfo::SetRememberClientAuthCertificate(bool aRememberClientAuthCertificate)
269 : {
270 0 : mRememberClientAuthCertificate = aRememberClientAuthCertificate;
271 0 : return NS_OK;
272 : }
273 :
274 0 : void nsNSSSocketInfo::SetHasCleartextPhase(bool aHasCleartextPhase)
275 : {
276 0 : mHasCleartextPhase = aHasCleartextPhase;
277 0 : }
278 :
279 0 : bool nsNSSSocketInfo::GetHasCleartextPhase()
280 : {
281 0 : return mHasCleartextPhase;
282 : }
283 :
284 : NS_IMETHODIMP
285 0 : nsNSSSocketInfo::GetNotificationCallbacks(nsIInterfaceRequestor** aCallbacks)
286 : {
287 0 : *aCallbacks = mCallbacks;
288 0 : NS_IF_ADDREF(*aCallbacks);
289 0 : return NS_OK;
290 : }
291 :
292 : NS_IMETHODIMP
293 16 : nsNSSSocketInfo::SetNotificationCallbacks(nsIInterfaceRequestor* aCallbacks)
294 : {
295 16 : if (!aCallbacks) {
296 8 : mCallbacks = nsnull;
297 8 : return NS_OK;
298 : }
299 :
300 8 : mCallbacks = aCallbacks;
301 :
302 8 : return NS_OK;
303 : }
304 :
305 : static void
306 4 : getSecureBrowserUI(nsIInterfaceRequestor * callbacks,
307 : nsISecureBrowserUI ** result)
308 : {
309 4 : NS_ASSERTION(result != nsnull, "result parameter to getSecureBrowserUI is null");
310 4 : *result = nsnull;
311 :
312 4 : NS_ASSERTION(NS_IsMainThread(),
313 : "getSecureBrowserUI called off the main thread");
314 :
315 4 : if (!callbacks)
316 0 : return;
317 :
318 8 : nsCOMPtr<nsISecureBrowserUI> secureUI = do_GetInterface(callbacks);
319 4 : if (secureUI) {
320 0 : secureUI.forget(result);
321 : return;
322 : }
323 :
324 8 : nsCOMPtr<nsIDocShellTreeItem> item = do_GetInterface(callbacks);
325 4 : if (item) {
326 0 : nsCOMPtr<nsIDocShellTreeItem> rootItem;
327 0 : (void) item->GetSameTypeRootTreeItem(getter_AddRefs(rootItem));
328 :
329 0 : nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(rootItem);
330 0 : if (docShell) {
331 0 : (void) docShell->GetSecurityUI(result);
332 : }
333 : }
334 : }
335 :
336 : NS_IMETHODIMP
337 0 : nsNSSSocketInfo::GetSecurityState(PRUint32* state)
338 : {
339 0 : *state = mSecurityState;
340 0 : return NS_OK;
341 : }
342 :
343 : nsresult
344 4 : nsNSSSocketInfo::SetSecurityState(PRUint32 aState)
345 : {
346 4 : mSecurityState = aState;
347 4 : return NS_OK;
348 : }
349 :
350 : /* attribute unsigned long countSubRequestsHighSecurity; */
351 0 : NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsHighSecurity(PRInt32 *aSubRequestsHighSecurity)
352 : {
353 0 : *aSubRequestsHighSecurity = mSubRequestsHighSecurity;
354 0 : return NS_OK;
355 : }
356 0 : NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsHighSecurity(PRInt32 aSubRequestsHighSecurity)
357 : {
358 0 : mSubRequestsHighSecurity = aSubRequestsHighSecurity;
359 0 : return NS_ERROR_NOT_IMPLEMENTED;
360 : }
361 :
362 : /* attribute unsigned long countSubRequestsLowSecurity; */
363 0 : NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsLowSecurity(PRInt32 *aSubRequestsLowSecurity)
364 : {
365 0 : *aSubRequestsLowSecurity = mSubRequestsLowSecurity;
366 0 : return NS_OK;
367 : }
368 0 : NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsLowSecurity(PRInt32 aSubRequestsLowSecurity)
369 : {
370 0 : mSubRequestsLowSecurity = aSubRequestsLowSecurity;
371 0 : return NS_OK;
372 : }
373 :
374 : /* attribute unsigned long countSubRequestsBrokenSecurity; */
375 0 : NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsBrokenSecurity(PRInt32 *aSubRequestsBrokenSecurity)
376 : {
377 0 : *aSubRequestsBrokenSecurity = mSubRequestsBrokenSecurity;
378 0 : return NS_OK;
379 : }
380 0 : NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsBrokenSecurity(PRInt32 aSubRequestsBrokenSecurity)
381 : {
382 0 : mSubRequestsBrokenSecurity = aSubRequestsBrokenSecurity;
383 0 : return NS_OK;
384 : }
385 :
386 : /* attribute unsigned long countSubRequestsNoSecurity; */
387 0 : NS_IMETHODIMP nsNSSSocketInfo::GetCountSubRequestsNoSecurity(PRInt32 *aSubRequestsNoSecurity)
388 : {
389 0 : *aSubRequestsNoSecurity = mSubRequestsNoSecurity;
390 0 : return NS_OK;
391 : }
392 0 : NS_IMETHODIMP nsNSSSocketInfo::SetCountSubRequestsNoSecurity(PRInt32 aSubRequestsNoSecurity)
393 : {
394 0 : mSubRequestsNoSecurity = aSubRequestsNoSecurity;
395 0 : return NS_OK;
396 : }
397 0 : NS_IMETHODIMP nsNSSSocketInfo::Flush()
398 : {
399 0 : return NS_OK;
400 : }
401 :
402 : NS_IMETHODIMP
403 0 : nsNSSSocketInfo::GetShortSecurityDescription(PRUnichar** aText) {
404 0 : if (mShortDesc.IsEmpty())
405 0 : *aText = nsnull;
406 : else {
407 0 : *aText = ToNewUnicode(mShortDesc);
408 0 : NS_ENSURE_TRUE(*aText, NS_ERROR_OUT_OF_MEMORY);
409 : }
410 0 : return NS_OK;
411 : }
412 :
413 : nsresult
414 4 : nsNSSSocketInfo::SetShortSecurityDescription(const PRUnichar* aText) {
415 4 : mShortDesc.Assign(aText);
416 4 : return NS_OK;
417 : }
418 :
419 : NS_IMETHODIMP
420 0 : nsNSSSocketInfo::GetErrorMessage(PRUnichar** aText)
421 : {
422 0 : NS_ENSURE_ARG_POINTER(aText);
423 0 : *aText = nsnull;
424 :
425 0 : if (!NS_IsMainThread()) {
426 0 : NS_ERROR("nsNSSSocketInfo::GetErrorMessage called off the main thread");
427 0 : return NS_ERROR_NOT_SAME_THREAD;
428 : }
429 :
430 0 : MutexAutoLock lock(mMutex);
431 :
432 0 : nsresult rv = formatErrorMessage(lock);
433 0 : NS_ENSURE_SUCCESS(rv, rv);
434 :
435 0 : *aText = ToNewUnicode(mErrorMessageCached);
436 0 : return *aText != nsnull ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
437 : }
438 :
439 : void
440 4 : nsNSSSocketInfo::SetNegotiatedNPN(const char *value, PRUint32 length)
441 : {
442 4 : if (!value)
443 4 : mNegotiatedNPN.Truncate();
444 : else
445 0 : mNegotiatedNPN.Assign(value, length);
446 4 : mNPNCompleted = true;
447 4 : }
448 :
449 : NS_IMETHODIMP
450 16 : nsNSSSocketInfo::GetNegotiatedNPN(nsACString &aNegotiatedNPN)
451 : {
452 16 : if (!mNPNCompleted)
453 12 : return NS_ERROR_NOT_CONNECTED;
454 :
455 4 : aNegotiatedNPN = mNegotiatedNPN;
456 4 : return NS_OK;
457 : }
458 :
459 : NS_IMETHODIMP
460 0 : nsNSSSocketInfo::JoinConnection(const nsACString & npnProtocol,
461 : const nsACString & hostname,
462 : PRInt32 port,
463 : bool *_retval NS_OUTPARAM)
464 : {
465 0 : *_retval = false;
466 :
467 : // Different ports may not be joined together
468 0 : if (port != mPort)
469 0 : return NS_OK;
470 :
471 : // Make sure NPN has been completed and matches requested npnProtocol
472 0 : if (!mNPNCompleted || !mNegotiatedNPN.Equals(npnProtocol))
473 0 : return NS_OK;
474 :
475 : // If this is the same hostname then the certicate status does not
476 : // need to be considered. They are joinable.
477 0 : if (mHostName && hostname.Equals(mHostName)) {
478 0 : *_retval = true;
479 0 : return NS_OK;
480 : }
481 :
482 : // Before checking the server certificate we need to make sure the
483 : // handshake has completed.
484 0 : if (!mHandshakeCompleted || !SSLStatus() || !SSLStatus()->mServerCert)
485 0 : return NS_OK;
486 :
487 : // If the cert has error bits (e.g. it is untrusted) then do not join.
488 : // The value of mHaveCertErrorBits is only reliable because we know that
489 : // the handshake completed.
490 0 : if (SSLStatus()->mHaveCertErrorBits)
491 0 : return NS_OK;
492 :
493 : // If the connection is using client certificates then do not join
494 : // because the user decides on whether to send client certs to hosts on a
495 : // per-domain basis.
496 0 : if (mSentClientCert)
497 0 : return NS_OK;
498 :
499 : // Ensure that the server certificate covers the hostname that would
500 : // like to join this connection
501 :
502 0 : CERTCertificate *nssCert = nsnull;
503 0 : CERTCertificateCleaner nsscertCleaner(nssCert);
504 :
505 0 : nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(SSLStatus()->mServerCert);
506 0 : if (cert2)
507 0 : nssCert = cert2->GetCert();
508 :
509 0 : if (!nssCert)
510 0 : return NS_OK;
511 :
512 0 : if (CERT_VerifyCertName(nssCert, PromiseFlatCString(hostname).get()) !=
513 : SECSuccess)
514 0 : return NS_OK;
515 :
516 : // All tests pass - this is joinable
517 0 : mJoined = true;
518 0 : *_retval = true;
519 0 : return NS_OK;
520 : }
521 :
522 : static nsresult
523 : formatPlainErrorMessage(nsXPIDLCString const & host, PRInt32 port,
524 : PRErrorCode err, nsString &returnedMessage);
525 :
526 : static nsresult
527 : formatOverridableCertErrorMessage(nsISSLStatus & sslStatus,
528 : PRErrorCode errorCodeToReport,
529 : const nsXPIDLCString & host, PRInt32 port,
530 : nsString & returnedMessage);
531 :
532 : // XXX: uses nsNSSComponent string bundles off the main thread when called by
533 : // nsNSSSocketInfo::Write(). When we remove the error message from the
534 : // serialization of nsNSSSocketInfo (bug 697781) we can inline
535 : // formatErrorMessage into GetErrorMessage().
536 : nsresult
537 4 : nsNSSSocketInfo::formatErrorMessage(MutexAutoLock const & proofOfLock)
538 : {
539 4 : if (mErrorCode == 0 || !mErrorMessageCached.IsEmpty()) {
540 4 : return NS_OK;
541 : }
542 :
543 : nsresult rv;
544 0 : NS_ConvertASCIItoUTF16 hostNameU(mHostName);
545 0 : NS_ASSERTION(mErrorMessageType != OverridableCertErrorMessage ||
546 : (mSSLStatus && mSSLStatus->mServerCert &&
547 : mSSLStatus->mHaveCertErrorBits),
548 : "GetErrorMessage called for cert error without cert");
549 0 : if (mErrorMessageType == OverridableCertErrorMessage &&
550 0 : mSSLStatus && mSSLStatus->mServerCert) {
551 0 : rv = formatOverridableCertErrorMessage(*mSSLStatus, mErrorCode,
552 : mHostName, mPort,
553 0 : mErrorMessageCached);
554 : } else {
555 : rv = formatPlainErrorMessage(mHostName, mPort, mErrorCode,
556 0 : mErrorMessageCached);
557 : }
558 :
559 0 : if (NS_FAILED(rv)) {
560 0 : mErrorMessageCached.Truncate();
561 : }
562 :
563 0 : return rv;
564 : }
565 :
566 : /* void getInterface (in nsIIDRef uuid, [iid_is (uuid), retval] out nsQIResult result); */
567 0 : NS_IMETHODIMP nsNSSSocketInfo::GetInterface(const nsIID & uuid, void * *result)
568 : {
569 0 : if (!NS_IsMainThread()) {
570 0 : NS_ERROR("nsNSSSocketInfo::GetInterface called off the main thread");
571 0 : return NS_ERROR_NOT_SAME_THREAD;
572 : }
573 :
574 : nsresult rv;
575 0 : if (!mCallbacks) {
576 0 : nsCOMPtr<nsIInterfaceRequestor> ir = new PipUIContext();
577 0 : if (!ir)
578 0 : return NS_ERROR_OUT_OF_MEMORY;
579 :
580 0 : rv = ir->GetInterface(uuid, result);
581 : } else {
582 0 : rv = mCallbacks->GetInterface(uuid, result);
583 : }
584 0 : return rv;
585 : }
586 :
587 : nsresult
588 0 : nsNSSSocketInfo::GetForSTARTTLS(bool* aForSTARTTLS)
589 : {
590 0 : *aForSTARTTLS = mForSTARTTLS;
591 0 : return NS_OK;
592 : }
593 :
594 : nsresult
595 4 : nsNSSSocketInfo::SetForSTARTTLS(bool aForSTARTTLS)
596 : {
597 4 : mForSTARTTLS = aForSTARTTLS;
598 4 : return NS_OK;
599 : }
600 :
601 : NS_IMETHODIMP
602 0 : nsNSSSocketInfo::ProxyStartSSL()
603 : {
604 0 : return ActivateSSL();
605 : }
606 :
607 : NS_IMETHODIMP
608 0 : nsNSSSocketInfo::StartTLS()
609 : {
610 0 : return ActivateSSL();
611 : }
612 :
613 : NS_IMETHODIMP
614 4 : nsNSSSocketInfo::SetNPNList(nsTArray<nsCString> &protocolArray)
615 : {
616 8 : nsNSSShutDownPreventionLock locker;
617 4 : if (isAlreadyShutDown())
618 0 : return NS_ERROR_NOT_AVAILABLE;
619 4 : if (!mFd)
620 0 : return NS_ERROR_FAILURE;
621 :
622 : // the npn list is a concatenated list of 8 bit byte strings.
623 8 : nsCString npnList;
624 :
625 12 : for (PRUint32 index = 0; index < protocolArray.Length(); ++index) {
626 16 : if (protocolArray[index].IsEmpty() ||
627 8 : protocolArray[index].Length() > 255)
628 0 : return NS_ERROR_ILLEGAL_VALUE;
629 :
630 8 : npnList.Append(protocolArray[index].Length());
631 8 : npnList.Append(protocolArray[index]);
632 : }
633 :
634 4 : if (SSL_SetNextProtoNego(
635 : mFd,
636 4 : reinterpret_cast<const unsigned char *>(npnList.get()),
637 8 : npnList.Length()) != SECSuccess)
638 0 : return NS_ERROR_FAILURE;
639 :
640 4 : return NS_OK;
641 : }
642 :
643 : static NS_DEFINE_CID(kNSSCertificateCID, NS_X509CERT_CID);
644 : #define NSSSOCKETINFOMAGIC { 0xa9863a23, 0x26b8, 0x4a9c, \
645 : { 0x83, 0xf1, 0xe9, 0xda, 0xdb, 0x36, 0xb8, 0x30 } }
646 : static NS_DEFINE_CID(kNSSSocketInfoMagic, NSSSOCKETINFOMAGIC);
647 :
648 : NS_IMETHODIMP
649 4 : nsNSSSocketInfo::Write(nsIObjectOutputStream* stream) {
650 4 : stream->WriteID(kNSSSocketInfoMagic);
651 :
652 8 : MutexAutoLock lock(mMutex);
653 :
654 8 : nsRefPtr<nsSSLStatus> status = mSSLStatus;
655 8 : nsCOMPtr<nsISerializable> certSerializable;
656 :
657 : // Write a redundant copy of the certificate for backward compatibility
658 : // with previous versions, which also unnecessarily wrote it.
659 : //
660 : // As we are reading the object our self, not using ReadObject, we have
661 : // to store it here 'manually' as well, mimicking our object stream
662 : // implementation.
663 :
664 4 : if (status) {
665 8 : nsCOMPtr<nsIX509Cert> cert = status->mServerCert;
666 4 : certSerializable = do_QueryInterface(cert);
667 :
668 4 : if (!certSerializable) {
669 0 : NS_ERROR("certificate is missing or isn't serializable");
670 0 : return NS_ERROR_UNEXPECTED;
671 : }
672 : } else {
673 0 : NS_WARNING("Serializing nsNSSSocketInfo without mSSLStatus");
674 : }
675 :
676 : // Store the flag if there is the certificate present
677 4 : stream->WriteBoolean(certSerializable);
678 4 : if (certSerializable) {
679 4 : stream->WriteID(kNSSCertificateCID);
680 4 : stream->WriteID(NS_GET_IID(nsISupports));
681 4 : certSerializable->Write(stream);
682 : }
683 :
684 : // Store the version number of the binary stream data format.
685 : // The 0xFFFF0000 mask is included to the version number
686 : // to distinguish version number from mSecurityState
687 : // field stored in times before versioning has been introduced.
688 : // This mask value has been chosen as mSecurityState could
689 : // never be assigned such value.
690 4 : PRUint32 version = 3;
691 4 : stream->Write32(version | 0xFFFF0000);
692 4 : stream->Write32(mSecurityState);
693 4 : stream->WriteWStringZ(mShortDesc.get());
694 :
695 : // XXX: uses nsNSSComponent string bundles off the main thread
696 4 : nsresult rv = formatErrorMessage(lock);
697 4 : NS_ENSURE_SUCCESS(rv, rv);
698 4 : stream->WriteWStringZ(mErrorMessageCached.get());
699 :
700 4 : stream->WriteCompoundObject(NS_ISUPPORTS_CAST(nsISSLStatus*, status),
701 8 : NS_GET_IID(nsISupports), true);
702 :
703 4 : stream->Write32((PRUint32)mSubRequestsHighSecurity);
704 4 : stream->Write32((PRUint32)mSubRequestsLowSecurity);
705 4 : stream->Write32((PRUint32)mSubRequestsBrokenSecurity);
706 4 : stream->Write32((PRUint32)mSubRequestsNoSecurity);
707 4 : return NS_OK;
708 : }
709 :
710 0 : static bool CheckUUIDEquals(PRUint32 m0,
711 : nsIObjectInputStream* stream,
712 : const nsCID& id)
713 : {
714 : nsID tempID;
715 0 : tempID.m0 = m0;
716 0 : stream->Read16(&tempID.m1);
717 0 : stream->Read16(&tempID.m2);
718 0 : for (int i = 0; i < 8; ++i)
719 0 : stream->Read8(&tempID.m3[i]);
720 0 : return tempID.Equals(id);
721 : }
722 :
723 : NS_IMETHODIMP
724 0 : nsNSSSocketInfo::Read(nsIObjectInputStream* stream) {
725 : nsresult rv;
726 :
727 : PRUint32 version;
728 : bool certificatePresent;
729 :
730 : // Check what we have here...
731 : PRUint32 UUID_0;
732 0 : stream->Read32(&UUID_0);
733 0 : if (UUID_0 == kNSSSocketInfoMagic.m0) {
734 : // It seems this stream begins with our magic ID, check it really is there
735 0 : if (!CheckUUIDEquals(UUID_0, stream, kNSSSocketInfoMagic))
736 0 : return NS_ERROR_FAILURE;
737 :
738 : // OK, this seems to be our stream, now continue to check there is
739 : // the certificate
740 0 : stream->ReadBoolean(&certificatePresent);
741 0 : stream->Read32(&UUID_0);
742 : }
743 : else {
744 : // There is no magic, assume there is a certificate present as in versions
745 : // prior to those with the magic didn't store that flag; we check the
746 : // certificate is present by cheking the CID then
747 0 : certificatePresent = true;
748 : }
749 :
750 0 : if (certificatePresent && UUID_0 == kNSSCertificateCID.m0) {
751 : // It seems there is the certificate CID present, check it now; we only
752 : // have this single certificate implementation at this time.
753 0 : if (!CheckUUIDEquals(UUID_0, stream, kNSSCertificateCID))
754 0 : return NS_ERROR_FAILURE;
755 :
756 : // OK, we have read the CID of the certificate, check the interface ID
757 : nsID tempID;
758 0 : stream->ReadID(&tempID);
759 0 : if (!tempID.Equals(NS_GET_IID(nsISupports)))
760 0 : return NS_ERROR_FAILURE;
761 :
762 : nsCOMPtr<nsISerializable> serializable =
763 0 : do_CreateInstance(kNSSCertificateCID, &rv);
764 0 : NS_ENSURE_SUCCESS(rv, rv);
765 :
766 : // This is the redundant copy of the certificate; just ignore it
767 0 : serializable->Read(stream);
768 :
769 : // We are done with reading the certificate, now read the version
770 : // as we did before.
771 0 : stream->Read32(&version);
772 : }
773 : else {
774 : // There seems not to be the certificate present in the stream.
775 0 : version = UUID_0;
776 : }
777 :
778 0 : MutexAutoLock lock(mMutex);
779 :
780 : // If the version field we have just read is not masked with 0xFFFF0000
781 : // then it is stored mSecurityState field and this is version 1 of
782 : // the binary data stream format.
783 0 : if ((version & 0xFFFF0000) == 0xFFFF0000) {
784 0 : version &= ~0xFFFF0000;
785 0 : stream->Read32(&mSecurityState);
786 : }
787 : else {
788 0 : mSecurityState = version;
789 0 : version = 1;
790 : }
791 0 : stream->ReadString(mShortDesc);
792 0 : stream->ReadString(mErrorMessageCached);
793 0 : mErrorCode = 0;
794 :
795 0 : nsCOMPtr<nsISupports> obj;
796 0 : stream->ReadObject(true, getter_AddRefs(obj));
797 :
798 0 : mSSLStatus = reinterpret_cast<nsSSLStatus*>(obj.get());
799 :
800 0 : if (!mSSLStatus) {
801 0 : NS_WARNING("deserializing nsNSSSocketInfo without mSSLStatus");
802 : }
803 :
804 0 : if (version >= 2) {
805 0 : stream->Read32((PRUint32*)&mSubRequestsHighSecurity);
806 0 : stream->Read32((PRUint32*)&mSubRequestsLowSecurity);
807 0 : stream->Read32((PRUint32*)&mSubRequestsBrokenSecurity);
808 0 : stream->Read32((PRUint32*)&mSubRequestsNoSecurity);
809 : }
810 : else {
811 0 : mSubRequestsHighSecurity = 0;
812 0 : mSubRequestsLowSecurity = 0;
813 0 : mSubRequestsBrokenSecurity = 0;
814 0 : mSubRequestsNoSecurity = 0;
815 : }
816 0 : return NS_OK;
817 : }
818 :
819 : NS_IMETHODIMP
820 0 : nsNSSSocketInfo::GetInterfaces(PRUint32 *count, nsIID * **array)
821 : {
822 0 : *count = 0;
823 0 : *array = nsnull;
824 0 : return NS_OK;
825 : }
826 :
827 : NS_IMETHODIMP
828 0 : nsNSSSocketInfo::GetHelperForLanguage(PRUint32 language, nsISupports **_retval)
829 : {
830 0 : *_retval = nsnull;
831 0 : return NS_OK;
832 : }
833 :
834 : NS_IMETHODIMP
835 0 : nsNSSSocketInfo::GetContractID(char * *aContractID)
836 : {
837 0 : *aContractID = nsnull;
838 0 : return NS_OK;
839 : }
840 :
841 : NS_IMETHODIMP
842 0 : nsNSSSocketInfo::GetClassDescription(char * *aClassDescription)
843 : {
844 0 : *aClassDescription = nsnull;
845 0 : return NS_OK;
846 : }
847 :
848 : NS_IMETHODIMP
849 0 : nsNSSSocketInfo::GetClassID(nsCID * *aClassID)
850 : {
851 0 : *aClassID = (nsCID*) nsMemory::Alloc(sizeof(nsCID));
852 0 : if (!*aClassID)
853 0 : return NS_ERROR_OUT_OF_MEMORY;
854 0 : return GetClassIDNoAlloc(*aClassID);
855 : }
856 :
857 : NS_IMETHODIMP
858 0 : nsNSSSocketInfo::GetImplementationLanguage(PRUint32 *aImplementationLanguage)
859 : {
860 0 : *aImplementationLanguage = nsIProgrammingLanguage::CPLUSPLUS;
861 0 : return NS_OK;
862 : }
863 :
864 : NS_IMETHODIMP
865 0 : nsNSSSocketInfo::GetFlags(PRUint32 *aFlags)
866 : {
867 0 : *aFlags = 0;
868 0 : return NS_OK;
869 : }
870 :
871 : static NS_DEFINE_CID(kNSSSocketInfoCID, NS_NSSSOCKETINFO_CID);
872 :
873 : NS_IMETHODIMP
874 4 : nsNSSSocketInfo::GetClassIDNoAlloc(nsCID *aClassIDNoAlloc)
875 : {
876 4 : *aClassIDNoAlloc = kNSSSocketInfoCID;
877 4 : return NS_OK;
878 : }
879 :
880 0 : nsresult nsNSSSocketInfo::ActivateSSL()
881 : {
882 0 : nsNSSShutDownPreventionLock locker;
883 0 : if (isAlreadyShutDown())
884 0 : return NS_ERROR_NOT_AVAILABLE;
885 :
886 0 : if (SECSuccess != SSL_OptionSet(mFd, SSL_SECURITY, true))
887 0 : return NS_ERROR_FAILURE;
888 0 : if (SECSuccess != SSL_ResetHandshake(mFd, false))
889 0 : return NS_ERROR_FAILURE;
890 :
891 0 : mHandshakePending = true;
892 :
893 0 : return NS_OK;
894 : }
895 :
896 0 : nsresult nsNSSSocketInfo::GetFileDescPtr(PRFileDesc** aFilePtr)
897 : {
898 0 : *aFilePtr = mFd;
899 0 : return NS_OK;
900 : }
901 :
902 4 : nsresult nsNSSSocketInfo::SetFileDescPtr(PRFileDesc* aFilePtr)
903 : {
904 4 : mFd = aFilePtr;
905 4 : return NS_OK;
906 : }
907 :
908 : class PreviousCertRunnable : public SyncRunnableBase
909 16 : {
910 : public:
911 4 : PreviousCertRunnable(nsIInterfaceRequestor * callbacks)
912 4 : : mCallbacks(callbacks)
913 : {
914 4 : }
915 :
916 4 : virtual void RunOnTargetThread()
917 : {
918 8 : nsCOMPtr<nsISecureBrowserUI> secureUI;
919 4 : getSecureBrowserUI(mCallbacks, getter_AddRefs(secureUI));
920 8 : nsCOMPtr<nsISSLStatusProvider> statusProvider = do_QueryInterface(secureUI);
921 4 : if (statusProvider) {
922 0 : nsCOMPtr<nsISSLStatus> status;
923 0 : (void) statusProvider->GetSSLStatus(getter_AddRefs(status));
924 0 : if (status) {
925 0 : (void) status->GetServerCert(getter_AddRefs(mPreviousCert));
926 : }
927 : }
928 4 : }
929 :
930 : nsCOMPtr<nsIX509Cert> mPreviousCert; // out
931 : private:
932 : nsCOMPtr<nsIInterfaceRequestor> mCallbacks; // in
933 : };
934 :
935 4 : void nsNSSSocketInfo::GetPreviousCert(nsIX509Cert** _result)
936 : {
937 4 : NS_ASSERTION(_result, "_result parameter to GetPreviousCert is null");
938 4 : *_result = nsnull;
939 :
940 12 : nsRefPtr<PreviousCertRunnable> runnable = new PreviousCertRunnable(mCallbacks);
941 4 : nsresult rv = runnable->DispatchToMainThreadAndWait();
942 4 : NS_ASSERTION(NS_SUCCEEDED(rv), "runnable->DispatchToMainThreadAndWait() failed");
943 4 : runnable->mPreviousCert.forget(_result);
944 4 : }
945 :
946 : void
947 4 : nsNSSSocketInfo::SetCertVerificationWaiting()
948 : {
949 : // mCertVerificationState may be before_cert_verification for the first
950 : // handshake on the connection, or after_cert_verification for subsequent
951 : // renegotiation handshakes.
952 4 : NS_ASSERTION(mCertVerificationState != waiting_for_cert_verification,
953 : "Invalid state transition to waiting_for_cert_verification");
954 4 : mCertVerificationState = waiting_for_cert_verification;
955 4 : mCertVerificationStarted = PR_IntervalNow();
956 4 : }
957 :
958 : // Be careful that SetCertVerificationResult does NOT get called while we are
959 : // processing a SSL callback function, because SSL_AuthCertificateComplete will
960 : // attempt to acquire locks that are already held by libssl when it calls
961 : // callbacks.
962 : void
963 4 : nsNSSSocketInfo::SetCertVerificationResult(PRErrorCode errorCode,
964 : SSLErrorMessageType errorMessageType)
965 : {
966 4 : NS_ASSERTION(mCertVerificationState == waiting_for_cert_verification,
967 : "Invalid state transition to cert_verification_finished");
968 :
969 4 : mCertVerificationEnded = PR_IntervalNow();
970 :
971 4 : if (mFd) {
972 4 : SECStatus rv = SSL_AuthCertificateComplete(mFd, errorCode);
973 : // Only replace errorCode if there was originally no error
974 4 : if (rv != SECSuccess && errorCode == 0) {
975 0 : errorCode = PR_GetError();
976 0 : errorMessageType = PlainErrorMessage;
977 0 : if (errorCode == 0) {
978 0 : NS_ERROR("SSL_AuthCertificateComplete didn't set error code");
979 0 : errorCode = PR_INVALID_STATE_ERROR;
980 : }
981 : }
982 : }
983 :
984 4 : if (errorCode) {
985 0 : SetCanceled(errorCode, errorMessageType);
986 : }
987 :
988 4 : mCertVerificationState = after_cert_verification;
989 4 : }
990 :
991 4 : nsresult nsNSSSocketInfo::GetSSLStatus(nsISSLStatus** _result)
992 : {
993 4 : NS_ENSURE_ARG_POINTER(_result);
994 :
995 4 : *_result = mSSLStatus;
996 4 : NS_IF_ADDREF(*_result);
997 :
998 4 : return NS_OK;
999 : }
1000 :
1001 4 : nsresult nsNSSSocketInfo::SetSSLStatus(nsSSLStatus *aSSLStatus)
1002 : {
1003 4 : mSSLStatus = aSSLStatus;
1004 :
1005 4 : return NS_OK;
1006 : }
1007 :
1008 12 : void nsNSSSocketInfo::SetHandshakeInProgress(bool aIsIn)
1009 : {
1010 12 : mHandshakeInProgress = aIsIn;
1011 :
1012 12 : if (mHandshakeInProgress && !mHandshakeStartTime)
1013 : {
1014 4 : mHandshakeStartTime = PR_IntervalNow();
1015 : }
1016 12 : }
1017 :
1018 0 : void nsNSSSocketInfo::SetAllowTLSIntoleranceTimeout(bool aAllow)
1019 : {
1020 0 : mAllowTLSIntoleranceTimeout = aAllow;
1021 0 : }
1022 :
1023 : #define HANDSHAKE_TIMEOUT_SECONDS 25
1024 :
1025 270 : bool nsNSSSocketInfo::HandshakeTimeout()
1026 : {
1027 270 : if (mCertVerificationState == waiting_for_cert_verification) {
1028 : // Do not do a TLS interlerance timeout during cert verification because:
1029 : //
1030 : // * If we would have timed out, but cert verification is still ongoing,
1031 : // then the handshake probably already completed, and it is probably the
1032 : // certificate validation (OCSP responder or similar) that is timing
1033 : // out.
1034 : // * If certificate validation AND the handshake is slow, then that is a
1035 : // good indication that the network is bad, and so the problem probably
1036 : // isn't the server being TLS intolerant.
1037 : // * When we timeout, we return non-zero flags from PR_Poll, which will
1038 : // cause the application to try to read from and/or write to the socket,
1039 : // possibly in a loop. But, it is likely that the socket is blocked on
1040 : // cert authentication, so those read and/or write calls would result in
1041 : // PR_WOULD_BLOCK_ERROR, causing the application to spin.
1042 4 : return false;
1043 : }
1044 :
1045 266 : if (!mHandshakeInProgress || !mAllowTLSIntoleranceTimeout)
1046 258 : return false;
1047 :
1048 8 : PRIntervalTime now = PR_IntervalNow();
1049 : PRIntervalTime certVerificationTime =
1050 8 : mCertVerificationEnded - mCertVerificationStarted;
1051 8 : PRIntervalTime totalTime = now - mHandshakeStartTime;
1052 : PRIntervalTime totalTimeExceptCertVerificationTime =
1053 8 : totalTime - certVerificationTime;
1054 :
1055 : return totalTimeExceptCertVerificationTime >
1056 8 : PR_SecondsToInterval(HANDSHAKE_TIMEOUT_SECONDS);
1057 : }
1058 :
1059 328 : void nsSSLIOLayerHelpers::Cleanup()
1060 : {
1061 328 : if (mTLSIntolerantSites) {
1062 328 : delete mTLSIntolerantSites;
1063 328 : mTLSIntolerantSites = nsnull;
1064 : }
1065 :
1066 328 : if (mTLSTolerantSites) {
1067 328 : delete mTLSTolerantSites;
1068 328 : mTLSTolerantSites = nsnull;
1069 : }
1070 :
1071 328 : if (mRenegoUnrestrictedSites) {
1072 328 : delete mRenegoUnrestrictedSites;
1073 328 : mRenegoUnrestrictedSites = nsnull;
1074 : }
1075 :
1076 328 : if (mutex) {
1077 328 : delete mutex;
1078 328 : mutex = nsnull;
1079 : }
1080 :
1081 328 : if (mHostsWithCertErrors) {
1082 328 : delete mHostsWithCertErrors;
1083 328 : mHostsWithCertErrors = nsnull;
1084 : }
1085 328 : }
1086 :
1087 : /* Formats an error message for non-certificate-related SSL errors
1088 : * and non-overridable certificate errors (both are of type
1089 : * PlainErrormMessage). Use formatOverridableCertErrorMessage
1090 : * for overridable cert errors.
1091 : */
1092 : static nsresult
1093 0 : formatPlainErrorMessage(const nsXPIDLCString &host, PRInt32 port,
1094 : PRErrorCode err, nsString &returnedMessage)
1095 : {
1096 : const PRUnichar *params[1];
1097 : nsresult rv;
1098 :
1099 0 : nsCOMPtr<nsINSSComponent> component = do_GetService(kNSSComponentCID, &rv);
1100 0 : NS_ENSURE_SUCCESS(rv, rv);
1101 :
1102 0 : if (host.Length())
1103 : {
1104 0 : nsString hostWithPort;
1105 :
1106 : // For now, hide port when it's 443 and we're reporting the error.
1107 : // In the future a better mechanism should be used
1108 : // to make a decision about showing the port number, possibly by requiring
1109 : // the context object to implement a specific interface.
1110 : // The motivation is that Mozilla browser would like to hide the port number
1111 : // in error pages in the common case.
1112 :
1113 0 : hostWithPort.AssignASCII(host);
1114 0 : if (port != 443) {
1115 0 : hostWithPort.AppendLiteral(":");
1116 0 : hostWithPort.AppendInt(port);
1117 : }
1118 0 : params[0] = hostWithPort.get();
1119 :
1120 0 : nsString formattedString;
1121 0 : rv = component->PIPBundleFormatStringFromName("SSLConnectionErrorPrefix",
1122 : params, 1,
1123 0 : formattedString);
1124 0 : if (NS_SUCCEEDED(rv))
1125 : {
1126 0 : returnedMessage.Append(formattedString);
1127 0 : returnedMessage.Append(NS_LITERAL_STRING("\n\n"));
1128 : }
1129 : }
1130 :
1131 0 : nsString explanation;
1132 0 : rv = nsNSSErrors::getErrorMessageFromCode(err, component, explanation);
1133 0 : if (NS_SUCCEEDED(rv))
1134 0 : returnedMessage.Append(explanation);
1135 :
1136 0 : return NS_OK;
1137 : }
1138 :
1139 : static void
1140 0 : AppendErrorTextUntrusted(PRErrorCode errTrust,
1141 : const nsString &host,
1142 : nsIX509Cert* ix509,
1143 : nsINSSComponent *component,
1144 : nsString &returnedMessage)
1145 : {
1146 0 : const char *errorID = nsnull;
1147 0 : nsCOMPtr<nsIX509Cert3> cert3 = do_QueryInterface(ix509);
1148 0 : if (cert3) {
1149 : bool isSelfSigned;
1150 0 : if (NS_SUCCEEDED(cert3->GetIsSelfSigned(&isSelfSigned))
1151 : && isSelfSigned) {
1152 0 : errorID = "certErrorTrust_SelfSigned";
1153 : }
1154 : }
1155 :
1156 0 : if (!errorID) {
1157 0 : switch (errTrust) {
1158 : case SEC_ERROR_UNKNOWN_ISSUER:
1159 : {
1160 0 : nsCOMPtr<nsIArray> chain;
1161 0 : ix509->GetChain(getter_AddRefs(chain));
1162 0 : PRUint32 length = 0;
1163 0 : if (chain && NS_FAILED(chain->GetLength(&length)))
1164 0 : length = 0;
1165 0 : if (length == 1)
1166 0 : errorID = "certErrorTrust_MissingChain";
1167 : else
1168 0 : errorID = "certErrorTrust_UnknownIssuer";
1169 : break;
1170 : }
1171 : case SEC_ERROR_INADEQUATE_KEY_USAGE:
1172 : // Should get an individual string in the future
1173 : // For now, use the same as CaInvalid
1174 : case SEC_ERROR_CA_CERT_INVALID:
1175 0 : errorID = "certErrorTrust_CaInvalid";
1176 0 : break;
1177 : case SEC_ERROR_UNTRUSTED_ISSUER:
1178 0 : errorID = "certErrorTrust_Issuer";
1179 0 : break;
1180 : case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
1181 0 : errorID = "certErrorTrust_ExpiredIssuer";
1182 0 : break;
1183 : case SEC_ERROR_UNTRUSTED_CERT:
1184 : default:
1185 0 : errorID = "certErrorTrust_Untrusted";
1186 0 : break;
1187 : }
1188 : }
1189 :
1190 0 : nsString formattedString;
1191 : nsresult rv = component->GetPIPNSSBundleString(errorID,
1192 0 : formattedString);
1193 0 : if (NS_SUCCEEDED(rv))
1194 : {
1195 0 : returnedMessage.Append(formattedString);
1196 0 : returnedMessage.Append(NS_LITERAL_STRING("\n"));
1197 : }
1198 0 : }
1199 :
1200 : // returns TRUE if SAN was used to produce names
1201 : // return FALSE if nothing was produced
1202 : // names => a single name or a list of names
1203 : // multipleNames => whether multiple names were delivered
1204 : static bool
1205 0 : GetSubjectAltNames(CERTCertificate *nssCert,
1206 : nsINSSComponent *component,
1207 : nsString &allNames,
1208 : PRUint32 &nameCount)
1209 : {
1210 0 : allNames.Truncate();
1211 0 : nameCount = 0;
1212 :
1213 0 : PRArenaPool *san_arena = nsnull;
1214 0 : SECItem altNameExtension = {siBuffer, NULL, 0 };
1215 0 : CERTGeneralName *sanNameList = nsnull;
1216 :
1217 : nsresult rv;
1218 : rv = CERT_FindCertExtension(nssCert, SEC_OID_X509_SUBJECT_ALT_NAME,
1219 0 : &altNameExtension);
1220 0 : if (rv != SECSuccess)
1221 0 : return false;
1222 :
1223 0 : san_arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
1224 0 : if (!san_arena)
1225 0 : return false;
1226 :
1227 0 : sanNameList = CERT_DecodeAltNameExtension(san_arena, &altNameExtension);
1228 0 : if (!sanNameList)
1229 0 : return false;
1230 :
1231 0 : SECITEM_FreeItem(&altNameExtension, false);
1232 :
1233 0 : CERTGeneralName *current = sanNameList;
1234 0 : do {
1235 0 : nsAutoString name;
1236 0 : switch (current->type) {
1237 : case certDNSName:
1238 0 : name.AssignASCII((char*)current->name.other.data, current->name.other.len);
1239 0 : if (!allNames.IsEmpty()) {
1240 0 : allNames.Append(NS_LITERAL_STRING(" , "));
1241 : }
1242 0 : ++nameCount;
1243 0 : allNames.Append(name);
1244 0 : break;
1245 :
1246 : case certIPAddress:
1247 : {
1248 : char buf[INET6_ADDRSTRLEN];
1249 : PRNetAddr addr;
1250 0 : if (current->name.other.len == 4) {
1251 0 : addr.inet.family = PR_AF_INET;
1252 0 : memcpy(&addr.inet.ip, current->name.other.data, current->name.other.len);
1253 0 : PR_NetAddrToString(&addr, buf, sizeof(buf));
1254 0 : name.AssignASCII(buf);
1255 0 : } else if (current->name.other.len == 16) {
1256 0 : addr.ipv6.family = PR_AF_INET6;
1257 0 : memcpy(&addr.ipv6.ip, current->name.other.data, current->name.other.len);
1258 0 : PR_NetAddrToString(&addr, buf, sizeof(buf));
1259 0 : name.AssignASCII(buf);
1260 : } else {
1261 : /* invalid IP address */
1262 : }
1263 0 : if (!name.IsEmpty()) {
1264 0 : if (!allNames.IsEmpty()) {
1265 0 : allNames.Append(NS_LITERAL_STRING(" , "));
1266 : }
1267 0 : ++nameCount;
1268 0 : allNames.Append(name);
1269 : }
1270 0 : break;
1271 : }
1272 :
1273 : default: // all other types of names are ignored
1274 0 : break;
1275 : }
1276 0 : current = CERT_GetNextGeneralName(current);
1277 : } while (current != sanNameList); // double linked
1278 :
1279 0 : PORT_FreeArena(san_arena, false);
1280 0 : return true;
1281 : }
1282 :
1283 : static void
1284 0 : AppendErrorTextMismatch(const nsString &host,
1285 : nsIX509Cert* ix509,
1286 : nsINSSComponent *component,
1287 : nsString &returnedMessage)
1288 : {
1289 : const PRUnichar *params[1];
1290 : nsresult rv;
1291 :
1292 0 : CERTCertificate *nssCert = NULL;
1293 0 : CERTCertificateCleaner nssCertCleaner(nssCert);
1294 :
1295 0 : nsCOMPtr<nsIX509Cert2> cert2 = do_QueryInterface(ix509, &rv);
1296 0 : if (cert2)
1297 0 : nssCert = cert2->GetCert();
1298 :
1299 0 : if (!nssCert) {
1300 : // We are unable to extract the valid names, say "not valid for name".
1301 0 : params[0] = host.get();
1302 0 : nsString formattedString;
1303 : rv = component->PIPBundleFormatStringFromName("certErrorMismatch",
1304 : params, 1,
1305 0 : formattedString);
1306 0 : if (NS_SUCCEEDED(rv)) {
1307 0 : returnedMessage.Append(formattedString);
1308 0 : returnedMessage.Append(NS_LITERAL_STRING("\n"));
1309 : }
1310 : return;
1311 : }
1312 :
1313 0 : nsString allNames;
1314 0 : PRUint32 nameCount = 0;
1315 0 : bool useSAN = false;
1316 :
1317 0 : if (nssCert)
1318 0 : useSAN = GetSubjectAltNames(nssCert, component, allNames, nameCount);
1319 :
1320 0 : if (!useSAN) {
1321 0 : char *certName = nsnull;
1322 : // currently CERT_FindNSStringExtension is not being exported by NSS.
1323 : // If it gets exported, enable the following line.
1324 : // certName = CERT_FindNSStringExtension(nssCert, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME);
1325 : // However, it has been discussed to treat the extension as obsolete and ignore it.
1326 0 : if (!certName)
1327 0 : certName = CERT_GetCommonName(&nssCert->subject);
1328 0 : if (certName) {
1329 0 : ++nameCount;
1330 0 : allNames.AssignASCII(certName);
1331 0 : PORT_Free(certName);
1332 : }
1333 : }
1334 :
1335 0 : if (nameCount > 1) {
1336 0 : nsString message;
1337 : rv = component->GetPIPNSSBundleString("certErrorMismatchMultiple",
1338 0 : message);
1339 0 : if (NS_SUCCEEDED(rv)) {
1340 0 : returnedMessage.Append(message);
1341 0 : returnedMessage.Append(NS_LITERAL_STRING("\n "));
1342 0 : returnedMessage.Append(allNames);
1343 0 : returnedMessage.Append(NS_LITERAL_STRING(" \n"));
1344 : }
1345 : }
1346 0 : else if (nameCount == 1) {
1347 : const PRUnichar *params[1];
1348 0 : params[0] = allNames.get();
1349 :
1350 0 : nsString formattedString;
1351 : rv = component->PIPBundleFormatStringFromName("certErrorMismatchSingle2",
1352 : params, 1,
1353 0 : formattedString);
1354 0 : if (NS_SUCCEEDED(rv)) {
1355 0 : returnedMessage.Append(formattedString);
1356 0 : returnedMessage.Append(NS_LITERAL_STRING("\n"));
1357 : }
1358 : }
1359 : else { // nameCount == 0
1360 0 : nsString message;
1361 : nsresult rv = component->GetPIPNSSBundleString("certErrorMismatchNoNames",
1362 0 : message);
1363 0 : if (NS_SUCCEEDED(rv)) {
1364 0 : returnedMessage.Append(message);
1365 0 : returnedMessage.Append(NS_LITERAL_STRING("\n"));
1366 : }
1367 : }
1368 : }
1369 :
1370 : static void
1371 0 : GetDateBoundary(nsIX509Cert* ix509,
1372 : nsString &formattedDate,
1373 : nsString &nowDate,
1374 : bool &trueExpired_falseNotYetValid)
1375 : {
1376 0 : trueExpired_falseNotYetValid = true;
1377 0 : formattedDate.Truncate();
1378 :
1379 : PRTime notAfter, notBefore, timeToUse;
1380 0 : nsCOMPtr<nsIX509CertValidity> validity;
1381 : nsresult rv;
1382 :
1383 0 : rv = ix509->GetValidity(getter_AddRefs(validity));
1384 0 : if (NS_FAILED(rv))
1385 : return;
1386 :
1387 0 : rv = validity->GetNotAfter(¬After);
1388 0 : if (NS_FAILED(rv))
1389 : return;
1390 :
1391 0 : rv = validity->GetNotBefore(¬Before);
1392 0 : if (NS_FAILED(rv))
1393 : return;
1394 :
1395 0 : PRTime now = PR_Now();
1396 0 : if (LL_CMP(now, >, notAfter)) {
1397 0 : timeToUse = notAfter;
1398 : } else {
1399 0 : timeToUse = notBefore;
1400 0 : trueExpired_falseNotYetValid = false;
1401 : }
1402 :
1403 0 : nsCOMPtr<nsIDateTimeFormat> dateTimeFormat(do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &rv));
1404 0 : if (NS_FAILED(rv))
1405 : return;
1406 :
1407 0 : dateTimeFormat->FormatPRTime(nsnull, kDateFormatShort,
1408 : kTimeFormatNoSeconds, timeToUse,
1409 0 : formattedDate);
1410 0 : dateTimeFormat->FormatPRTime(nsnull, kDateFormatShort,
1411 : kTimeFormatNoSeconds, now,
1412 0 : nowDate);
1413 : }
1414 :
1415 : static void
1416 0 : AppendErrorTextTime(nsIX509Cert* ix509,
1417 : nsINSSComponent *component,
1418 : nsString &returnedMessage)
1419 : {
1420 0 : nsAutoString formattedDate, nowDate;
1421 : bool trueExpired_falseNotYetValid;
1422 0 : GetDateBoundary(ix509, formattedDate, nowDate, trueExpired_falseNotYetValid);
1423 :
1424 : const PRUnichar *params[2];
1425 0 : params[0] = formattedDate.get(); // might be empty, if helper function had a problem
1426 0 : params[1] = nowDate.get();
1427 :
1428 : const char *key = trueExpired_falseNotYetValid ?
1429 0 : "certErrorExpiredNow" : "certErrorNotYetValidNow";
1430 : nsresult rv;
1431 0 : nsString formattedString;
1432 : rv = component->PIPBundleFormatStringFromName(
1433 : key,
1434 : params,
1435 : ArrayLength(params),
1436 0 : formattedString);
1437 0 : if (NS_SUCCEEDED(rv))
1438 : {
1439 0 : returnedMessage.Append(formattedString);
1440 0 : returnedMessage.Append(NS_LITERAL_STRING("\n"));
1441 : }
1442 0 : }
1443 :
1444 : static void
1445 0 : AppendErrorTextCode(PRErrorCode errorCodeToReport,
1446 : nsINSSComponent *component,
1447 : nsString &returnedMessage)
1448 : {
1449 0 : const char *codeName = nsNSSErrors::getDefaultErrorStringName(errorCodeToReport);
1450 0 : if (codeName)
1451 : {
1452 0 : nsCString error_id(codeName);
1453 0 : ToLowerCase(error_id);
1454 0 : NS_ConvertASCIItoUTF16 idU(error_id);
1455 :
1456 : const PRUnichar *params[1];
1457 0 : params[0] = idU.get();
1458 :
1459 0 : nsString formattedString;
1460 : nsresult rv;
1461 : rv = component->PIPBundleFormatStringFromName("certErrorCodePrefix",
1462 : params, 1,
1463 0 : formattedString);
1464 0 : if (NS_SUCCEEDED(rv)) {
1465 0 : returnedMessage.Append(NS_LITERAL_STRING("\n"));
1466 0 : returnedMessage.Append(formattedString);
1467 0 : returnedMessage.Append(NS_LITERAL_STRING("\n"));
1468 : }
1469 : else {
1470 0 : returnedMessage.Append(NS_LITERAL_STRING(" ("));
1471 0 : returnedMessage.Append(idU);
1472 0 : returnedMessage.Append(NS_LITERAL_STRING(")"));
1473 : }
1474 : }
1475 0 : }
1476 :
1477 : /* Formats an error message for overridable certificate errors (of type
1478 : * OverridableCertErrorMessage). Use formatPlainErrorMessage to format
1479 : * non-overridable cert errors and non-cert-related errors.
1480 : */
1481 : static nsresult
1482 0 : formatOverridableCertErrorMessage(nsISSLStatus & sslStatus,
1483 : PRErrorCode errorCodeToReport,
1484 : const nsXPIDLCString & host, PRInt32 port,
1485 : nsString & returnedMessage)
1486 : {
1487 : const PRUnichar *params[1];
1488 : nsresult rv;
1489 0 : nsAutoString hostWithPort;
1490 0 : nsAutoString hostWithoutPort;
1491 :
1492 : // For now, hide port when it's 443 and we're reporting the error.
1493 : // In the future a better mechanism should be used
1494 : // to make a decision about showing the port number, possibly by requiring
1495 : // the context object to implement a specific interface.
1496 : // The motivation is that Mozilla browser would like to hide the port number
1497 : // in error pages in the common case.
1498 :
1499 0 : hostWithoutPort.AppendASCII(host);
1500 0 : if (port == 443) {
1501 0 : params[0] = hostWithoutPort.get();
1502 : } else {
1503 0 : hostWithPort.AppendASCII(host);
1504 0 : hostWithPort.Append(':');
1505 0 : hostWithPort.AppendInt(port);
1506 0 : params[0] = hostWithPort.get();
1507 : }
1508 :
1509 0 : nsCOMPtr<nsINSSComponent> component = do_GetService(kNSSComponentCID, &rv);
1510 0 : NS_ENSURE_SUCCESS(rv, rv);
1511 :
1512 0 : returnedMessage.Truncate();
1513 0 : rv = component->PIPBundleFormatStringFromName("certErrorIntro", params, 1,
1514 0 : returnedMessage);
1515 0 : NS_ENSURE_SUCCESS(rv, rv);
1516 :
1517 0 : returnedMessage.Append(NS_LITERAL_STRING("\n\n"));
1518 :
1519 0 : nsRefPtr<nsIX509Cert> ix509;
1520 0 : rv = sslStatus.GetServerCert(getter_AddRefs(ix509));
1521 0 : NS_ENSURE_SUCCESS(rv, rv);
1522 :
1523 : bool isUntrusted;
1524 0 : rv = sslStatus.GetIsUntrusted(&isUntrusted);
1525 0 : NS_ENSURE_SUCCESS(rv, rv);
1526 0 : if (isUntrusted) {
1527 : AppendErrorTextUntrusted(errorCodeToReport, hostWithoutPort, ix509,
1528 0 : component, returnedMessage);
1529 : }
1530 :
1531 : bool isDomainMismatch;
1532 0 : rv = sslStatus.GetIsDomainMismatch(&isDomainMismatch);
1533 0 : NS_ENSURE_SUCCESS(rv, rv);
1534 0 : if (isDomainMismatch) {
1535 0 : AppendErrorTextMismatch(hostWithoutPort, ix509, component, returnedMessage);
1536 : }
1537 :
1538 : bool isNotValidAtThisTime;
1539 0 : rv = sslStatus.GetIsNotValidAtThisTime(&isNotValidAtThisTime);
1540 0 : NS_ENSURE_SUCCESS(rv, rv);
1541 0 : if (isNotValidAtThisTime) {
1542 0 : AppendErrorTextTime(ix509, component, returnedMessage);
1543 : }
1544 :
1545 0 : AppendErrorTextCode(errorCodeToReport, component, returnedMessage);
1546 :
1547 0 : return NS_OK;
1548 : }
1549 :
1550 : static void
1551 0 : nsHandleSSLError(nsNSSSocketInfo *socketInfo, PRErrorCode err)
1552 : {
1553 0 : if (!NS_IsMainThread()) {
1554 0 : NS_ERROR("nsHandleSSLError called off the main thread");
1555 0 : return;
1556 : }
1557 :
1558 : // SetCanceled is only called by the main thread or the socket transport
1559 : // thread. Whenever this function is called on the main thread, the SSL
1560 : // thread is blocked on it. So, no mutex is necessary for
1561 : // SetCanceled()/GetError*().
1562 0 : if (socketInfo->GetErrorCode()) {
1563 : // If the socket has been flagged as canceled,
1564 : // the code who did was responsible for setting the error code.
1565 0 : return;
1566 : }
1567 :
1568 : nsresult rv;
1569 0 : NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
1570 0 : nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
1571 0 : if (NS_FAILED(rv))
1572 : return;
1573 :
1574 0 : nsXPIDLCString hostName;
1575 0 : socketInfo->GetHostName(getter_Copies(hostName));
1576 :
1577 : PRInt32 port;
1578 0 : socketInfo->GetPort(&port);
1579 :
1580 : // Try to get a nsISSLErrorListener implementation from the socket consumer.
1581 0 : nsCOMPtr<nsIInterfaceRequestor> cb;
1582 0 : socketInfo->GetNotificationCallbacks(getter_AddRefs(cb));
1583 0 : if (cb) {
1584 0 : nsCOMPtr<nsISSLErrorListener> sel = do_GetInterface(cb);
1585 0 : if (sel) {
1586 0 : nsIInterfaceRequestor *csi = static_cast<nsIInterfaceRequestor*>(socketInfo);
1587 0 : nsCString hostWithPortString = hostName;
1588 0 : hostWithPortString.AppendLiteral(":");
1589 0 : hostWithPortString.AppendInt(port);
1590 :
1591 0 : bool suppressMessage = false; // obsolete, ignored
1592 0 : rv = sel->NotifySSLError(csi, err, hostWithPortString, &suppressMessage);
1593 : }
1594 : }
1595 :
1596 0 : socketInfo->SetCanceled(err, PlainErrorMessage);
1597 : }
1598 :
1599 : namespace {
1600 :
1601 : enum Operation { reading, writing, not_reading_or_writing };
1602 :
1603 : PRInt32 checkHandshake(PRInt32 bytesTransfered, bool wasReading,
1604 : PRFileDesc* ssl_layer_fd,
1605 : nsNSSSocketInfo *socketInfo);
1606 :
1607 : nsNSSSocketInfo *
1608 326 : getSocketInfoIfRunning(PRFileDesc * fd, Operation op,
1609 : const nsNSSShutDownPreventionLock & /*proofOfLock*/)
1610 : {
1611 326 : if (!fd || !fd->lower || !fd->secret ||
1612 : fd->identity != nsSSLIOLayerHelpers::nsSSLIOLayerIdentity) {
1613 0 : NS_ERROR("bad file descriptor passed to getSocketInfoIfRunning");
1614 0 : PR_SetError(PR_BAD_DESCRIPTOR_ERROR, 0);
1615 0 : return nsnull;
1616 : }
1617 :
1618 326 : nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
1619 :
1620 326 : if (socketInfo->isAlreadyShutDown() || socketInfo->isPK11LoggedOut()) {
1621 0 : PR_SetError(PR_SOCKET_SHUTDOWN_ERROR, 0);
1622 0 : return nsnull;
1623 : }
1624 :
1625 326 : if (socketInfo->GetErrorCode()) {
1626 0 : PRErrorCode err = socketInfo->GetErrorCode();
1627 0 : PR_SetError(err, 0);
1628 0 : if (op == reading || op == writing) {
1629 : // We must do TLS intolerance checks for reads and writes, for timeouts
1630 : // in particular.
1631 0 : (void) checkHandshake(-1, op == reading, fd, socketInfo);
1632 : }
1633 :
1634 : // If we get here, it is probably because cert verification failed and this
1635 : // is the first I/O attempt since that failure.
1636 0 : return nsnull;
1637 : }
1638 :
1639 326 : return socketInfo;
1640 : }
1641 :
1642 : } // unnnamed namespace
1643 :
1644 : static PRStatus PR_CALLBACK
1645 4 : nsSSLIOLayerConnect(PRFileDesc* fd, const PRNetAddr* addr,
1646 : PRIntervalTime timeout)
1647 : {
1648 4 : PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] connecting SSL socket\n", (void*)fd));
1649 8 : nsNSSShutDownPreventionLock locker;
1650 4 : if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
1651 0 : return PR_FAILURE;
1652 :
1653 4 : PRStatus status = fd->lower->methods->connect(fd->lower, addr, timeout);
1654 4 : if (status != PR_SUCCESS) {
1655 4 : PR_LOG(gPIPNSSLog, PR_LOG_ERROR, ("[%p] Lower layer connect error: %d\n",
1656 : (void*)fd, PR_GetError()));
1657 4 : return status;
1658 : }
1659 :
1660 0 : PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Connect\n", (void*)fd));
1661 0 : return status;
1662 : }
1663 :
1664 : // nsPSMRememberCertErrorsTable
1665 :
1666 328 : nsPSMRememberCertErrorsTable::nsPSMRememberCertErrorsTable()
1667 : {
1668 328 : mErrorHosts.Init(16);
1669 328 : }
1670 :
1671 : nsresult
1672 8 : nsPSMRememberCertErrorsTable::GetHostPortKey(nsNSSSocketInfo* infoObject,
1673 : nsCAutoString &result)
1674 : {
1675 : nsresult rv;
1676 :
1677 8 : result.Truncate();
1678 :
1679 16 : nsXPIDLCString hostName;
1680 8 : rv = infoObject->GetHostName(getter_Copies(hostName));
1681 8 : NS_ENSURE_SUCCESS(rv, rv);
1682 :
1683 : PRInt32 port;
1684 8 : rv = infoObject->GetPort(&port);
1685 8 : NS_ENSURE_SUCCESS(rv, rv);
1686 :
1687 8 : result.Assign(hostName);
1688 8 : result.Append(':');
1689 8 : result.AppendInt(port);
1690 :
1691 8 : return NS_OK;
1692 : }
1693 :
1694 : void
1695 4 : nsPSMRememberCertErrorsTable::RememberCertHasError(nsNSSSocketInfo* infoObject,
1696 : nsSSLStatus* status,
1697 : SECStatus certVerificationResult)
1698 : {
1699 : nsresult rv;
1700 :
1701 8 : nsCAutoString hostPortKey;
1702 4 : rv = GetHostPortKey(infoObject, hostPortKey);
1703 4 : if (NS_FAILED(rv))
1704 : return;
1705 :
1706 4 : if (certVerificationResult != SECSuccess) {
1707 0 : NS_ASSERTION(status,
1708 : "Must have nsSSLStatus object when remembering flags");
1709 :
1710 0 : if (!status)
1711 : return;
1712 :
1713 : CertStateBits bits;
1714 0 : bits.mIsDomainMismatch = status->mIsDomainMismatch;
1715 0 : bits.mIsNotValidAtThisTime = status->mIsNotValidAtThisTime;
1716 0 : bits.mIsUntrusted = status->mIsUntrusted;
1717 0 : mErrorHosts.Put(hostPortKey, bits);
1718 : }
1719 : else {
1720 4 : mErrorHosts.Remove(hostPortKey);
1721 : }
1722 : }
1723 :
1724 : void
1725 4 : nsPSMRememberCertErrorsTable::LookupCertErrorBits(nsNSSSocketInfo* infoObject,
1726 : nsSSLStatus* status)
1727 : {
1728 : // Get remembered error bits from our cache, because of SSL session caching
1729 : // the NSS library potentially hasn't notified us for this socket.
1730 4 : if (status->mHaveCertErrorBits)
1731 : // Rather do not modify bits if already set earlier
1732 0 : return;
1733 :
1734 : nsresult rv;
1735 :
1736 8 : nsCAutoString hostPortKey;
1737 4 : rv = GetHostPortKey(infoObject, hostPortKey);
1738 4 : if (NS_FAILED(rv))
1739 : return;
1740 :
1741 : CertStateBits bits;
1742 4 : if (!mErrorHosts.Get(hostPortKey, &bits))
1743 : // No record was found, this host had no cert errors
1744 : return;
1745 :
1746 : // This host had cert errors, update the bits correctly
1747 0 : status->mHaveCertErrorBits = true;
1748 0 : status->mIsDomainMismatch = bits.mIsDomainMismatch;
1749 0 : status->mIsNotValidAtThisTime = bits.mIsNotValidAtThisTime;
1750 0 : status->mIsUntrusted = bits.mIsUntrusted;
1751 : }
1752 :
1753 : void
1754 4 : nsSSLIOLayerHelpers::getSiteKey(nsNSSSocketInfo *socketInfo, nsCSubstring &key)
1755 : {
1756 : PRInt32 port;
1757 4 : socketInfo->GetPort(&port);
1758 :
1759 8 : nsXPIDLCString host;
1760 4 : socketInfo->GetHostName(getter_Copies(host));
1761 :
1762 4 : key = host + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
1763 4 : }
1764 :
1765 : // Call this function to report a site that is possibly TLS intolerant.
1766 : // This function will return true, if the given socket is currently using TLS.
1767 : bool
1768 0 : nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(nsNSSSocketInfo *socketInfo)
1769 : {
1770 0 : nsCAutoString key;
1771 0 : getSiteKey(socketInfo, key);
1772 :
1773 0 : if (!socketInfo->IsTLSEnabled()) {
1774 : // We did not offer TLS but failed with an intolerant error using
1775 : // a different protocol. To give TLS a try on next connection attempt again
1776 : // drop this site from the list of intolerant sites. TLS failure might be
1777 : // caused only by a traffic congestion while the server is TLS tolerant.
1778 0 : removeIntolerantSite(key);
1779 0 : return false;
1780 : }
1781 :
1782 0 : if (socketInfo->IsSSL3Enabled()) {
1783 : // Add this site to the list of TLS intolerant sites.
1784 0 : addIntolerantSite(key);
1785 : }
1786 :
1787 0 : return socketInfo->IsTLSEnabled();
1788 : }
1789 :
1790 : void
1791 4 : nsSSLIOLayerHelpers::rememberTolerantSite(nsNSSSocketInfo *socketInfo)
1792 : {
1793 4 : if (!socketInfo->IsTLSEnabled())
1794 0 : return;
1795 :
1796 8 : nsCAutoString key;
1797 4 : getSiteKey(socketInfo, key);
1798 :
1799 8 : MutexAutoLock lock(*mutex);
1800 4 : nsSSLIOLayerHelpers::mTLSTolerantSites->PutEntry(key);
1801 : }
1802 :
1803 : static PRStatus PR_CALLBACK
1804 4 : nsSSLIOLayerClose(PRFileDesc *fd)
1805 : {
1806 8 : nsNSSShutDownPreventionLock locker;
1807 4 : if (!fd)
1808 0 : return PR_FAILURE;
1809 :
1810 4 : PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Shutting down socket\n", (void*)fd));
1811 :
1812 4 : nsNSSSocketInfo *socketInfo = (nsNSSSocketInfo*)fd->secret;
1813 4 : NS_ASSERTION(socketInfo,"nsNSSSocketInfo was null for an fd");
1814 :
1815 4 : return socketInfo->CloseSocketAndDestroy(locker);
1816 : }
1817 :
1818 4 : PRStatus nsNSSSocketInfo::CloseSocketAndDestroy(
1819 : const nsNSSShutDownPreventionLock & /*proofOfLock*/)
1820 : {
1821 4 : nsNSSShutDownList::trackSSLSocketClose();
1822 :
1823 4 : PRFileDesc* popped = PR_PopIOLayer(mFd, PR_TOP_IO_LAYER);
1824 :
1825 4 : PRStatus status = mFd->methods->close(mFd);
1826 :
1827 : // the nsNSSSocketInfo instance can out-live the connection, so we need some
1828 : // indication that the connection has been closed. mFd == nsnull is that
1829 : // indication. This is needed, for example, when the connection is closed
1830 : // before we have finished validating the server's certificate.
1831 4 : mFd = nsnull;
1832 :
1833 4 : if (status != PR_SUCCESS) return status;
1834 :
1835 4 : popped->identity = PR_INVALID_IO_LAYER;
1836 4 : NS_RELEASE_THIS();
1837 4 : popped->dtor(popped);
1838 :
1839 4 : return PR_SUCCESS;
1840 : }
1841 :
1842 : #if defined(DEBUG_SSL_VERBOSE) && defined(DUMP_BUFFER)
1843 : /* Dumps a (potentially binary) buffer using SSM_DEBUG.
1844 : (We could have used the version in ssltrace.c, but that's
1845 : specifically tailored to SSLTRACE. Sigh. */
1846 : #define DUMPBUF_LINESIZE 24
1847 : static void
1848 : nsDumpBuffer(unsigned char *buf, PRIntn len)
1849 : {
1850 : char hexbuf[DUMPBUF_LINESIZE*3+1];
1851 : char chrbuf[DUMPBUF_LINESIZE+1];
1852 : static const char *hex = "0123456789abcdef";
1853 : PRIntn i = 0, l = 0;
1854 : char ch, *c, *h;
1855 : if (len == 0)
1856 : return;
1857 : hexbuf[DUMPBUF_LINESIZE*3] = '\0';
1858 : chrbuf[DUMPBUF_LINESIZE] = '\0';
1859 : (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
1860 : (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
1861 : h = hexbuf;
1862 : c = chrbuf;
1863 :
1864 : while (i < len)
1865 : {
1866 : ch = buf[i];
1867 :
1868 : if (l == DUMPBUF_LINESIZE)
1869 : {
1870 : PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("%s%s\n", hexbuf, chrbuf));
1871 : (void) memset(hexbuf, 0x20, DUMPBUF_LINESIZE*3);
1872 : (void) memset(chrbuf, 0x20, DUMPBUF_LINESIZE);
1873 : h = hexbuf;
1874 : c = chrbuf;
1875 : l = 0;
1876 : }
1877 :
1878 : /* Convert a character to hex. */
1879 : *h++ = hex[(ch >> 4) & 0xf];
1880 : *h++ = hex[ch & 0xf];
1881 : h++;
1882 :
1883 : /* Put the character (if it's printable) into the character buffer. */
1884 : if ((ch >= 0x20) && (ch <= 0x7e))
1885 : *c++ = ch;
1886 : else
1887 : *c++ = '.';
1888 : i++; l++;
1889 : }
1890 : PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("%s%s\n", hexbuf, chrbuf));
1891 : }
1892 :
1893 : #define DEBUG_DUMP_BUFFER(buf,len) nsDumpBuffer(buf,len)
1894 : #else
1895 : #define DEBUG_DUMP_BUFFER(buf,len)
1896 : #endif
1897 :
1898 : static bool
1899 0 : isNonSSLErrorThatWeAllowToRetry(PRInt32 err, bool withInitialCleartext)
1900 : {
1901 0 : switch (err)
1902 : {
1903 : case PR_CONNECT_RESET_ERROR:
1904 0 : if (!withInitialCleartext)
1905 0 : return true;
1906 0 : break;
1907 :
1908 : case PR_END_OF_FILE_ERROR:
1909 0 : return true;
1910 : }
1911 :
1912 0 : return false;
1913 : }
1914 :
1915 : static bool
1916 0 : isTLSIntoleranceError(PRInt32 err, bool withInitialCleartext)
1917 : {
1918 : // This function is supposed to decide, which error codes should
1919 : // be used to conclude server is TLS intolerant.
1920 : // Note this only happens during the initial SSL handshake.
1921 : //
1922 : // When not using a proxy we'll see a connection reset error.
1923 : // When using a proxy, we'll see an end of file error.
1924 : // In addition check for some error codes where it is reasonable
1925 : // to retry without TLS.
1926 :
1927 0 : if (isNonSSLErrorThatWeAllowToRetry(err, withInitialCleartext))
1928 0 : return true;
1929 :
1930 0 : switch (err)
1931 : {
1932 : case SSL_ERROR_BAD_MAC_ALERT:
1933 : case SSL_ERROR_BAD_MAC_READ:
1934 : case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
1935 : case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
1936 : case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE:
1937 : case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
1938 : case SSL_ERROR_NO_CYPHER_OVERLAP:
1939 : case SSL_ERROR_BAD_SERVER:
1940 : case SSL_ERROR_BAD_BLOCK_PADDING:
1941 : case SSL_ERROR_UNSUPPORTED_VERSION:
1942 : case SSL_ERROR_PROTOCOL_VERSION_ALERT:
1943 : case SSL_ERROR_RX_MALFORMED_FINISHED:
1944 : case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE:
1945 : case SSL_ERROR_DECODE_ERROR_ALERT:
1946 : case SSL_ERROR_RX_UNKNOWN_ALERT:
1947 0 : return true;
1948 : }
1949 :
1950 0 : return false;
1951 : }
1952 :
1953 : class SSLErrorRunnable : public SyncRunnableBase
1954 0 : {
1955 : public:
1956 0 : SSLErrorRunnable(nsNSSSocketInfo * infoObject, PRErrorCode errorCode)
1957 0 : : mInfoObject(infoObject), mErrorCode(errorCode)
1958 : {
1959 0 : }
1960 :
1961 0 : virtual void RunOnTargetThread()
1962 : {
1963 0 : nsHandleSSLError(mInfoObject, mErrorCode);
1964 0 : }
1965 :
1966 : nsRefPtr<nsNSSSocketInfo> mInfoObject;
1967 : const PRErrorCode mErrorCode;
1968 : };
1969 :
1970 : namespace {
1971 :
1972 32 : PRInt32 checkHandshake(PRInt32 bytesTransfered, bool wasReading,
1973 : PRFileDesc* ssl_layer_fd,
1974 : nsNSSSocketInfo *socketInfo)
1975 : {
1976 : // This is where we work around all of those SSL servers that don't
1977 : // conform to the SSL spec and shutdown a connection when we request
1978 : // SSL v3.1 (aka TLS). The spec says the client says what version
1979 : // of the protocol we're willing to perform, in our case SSL v3.1
1980 : // In its response, the server says which version it wants to perform.
1981 : // Many servers out there only know how to do v3.0. Next, we're supposed
1982 : // to send back the version of the protocol we requested (ie v3.1). At
1983 : // this point many servers's implementations are broken and they shut
1984 : // down the connection when they don't see the version they sent back.
1985 : // This is supposed to prevent a man in the middle from forcing one
1986 : // side to dumb down to a lower level of the protocol. Unfortunately,
1987 : // there are enough broken servers out there that such a gross work-around
1988 : // is necessary. :(
1989 :
1990 : // Additional comment added in August 2006:
1991 : // When we begun to use TLS hello extensions, we encountered a new class of
1992 : // broken server, which simply stall for a very long time.
1993 : // We would like to shorten the timeout, but limit this shorter timeout
1994 : // to the handshake phase.
1995 : // When we arrive here for the first time (for a given socket),
1996 : // we know the connection is established, and the application code
1997 : // tried the first read or write. This triggers the beginning of the
1998 : // SSL handshake phase at the SSL FD level.
1999 : // We'll make a note of the current time,
2000 : // and use this to measure the elapsed time since handshake begin.
2001 :
2002 : // Do NOT assume TLS intolerance on a closed connection after bad cert ui was shown.
2003 : // Simply retry.
2004 : // This depends on the fact that Cert UI will not be shown again,
2005 : // should the user override the bad cert.
2006 :
2007 : bool handleHandshakeResultNow;
2008 32 : socketInfo->GetHandshakePending(&handleHandshakeResultNow);
2009 :
2010 32 : bool wantRetry = false;
2011 :
2012 32 : if (0 > bytesTransfered) {
2013 16 : PRInt32 err = PR_GetError();
2014 :
2015 16 : if (handleHandshakeResultNow) {
2016 8 : if (PR_WOULD_BLOCK_ERROR == err) {
2017 8 : socketInfo->SetHandshakeInProgress(true);
2018 8 : return bytesTransfered;
2019 : }
2020 :
2021 0 : if (!wantRetry // no decision yet
2022 0 : && isTLSIntoleranceError(err, socketInfo->GetHasCleartextPhase()))
2023 : {
2024 0 : wantRetry = nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(socketInfo);
2025 : }
2026 : }
2027 :
2028 : // This is the common place where we trigger non-cert-errors on a SSL
2029 : // socket. This might be reached at any time of the connection.
2030 : //
2031 : // The socketInfo->GetErrorCode() check is here to ensure we don't try to
2032 : // do the synchronous dispatch to the main thread unnecessarily after we've
2033 : // already handled a certificate error. (SSLErrorRunnable calls
2034 : // nsHandleSSLError, which has logic to avoid replacing the error message,
2035 : // so without the !socketInfo->GetErrorCode(), it would just be an
2036 : // expensive no-op.)
2037 8 : if (!wantRetry && (IS_SSL_ERROR(err) || IS_SEC_ERROR(err)) &&
2038 0 : !socketInfo->GetErrorCode()) {
2039 : nsRefPtr<SyncRunnableBase> runnable = new SSLErrorRunnable(socketInfo,
2040 0 : err);
2041 0 : (void) runnable->DispatchToMainThreadAndWait();
2042 : }
2043 : }
2044 16 : else if (wasReading && 0 == bytesTransfered) // zero bytes on reading, socket closed
2045 : {
2046 0 : if (handleHandshakeResultNow)
2047 : {
2048 0 : if (!wantRetry // no decision yet
2049 0 : && !socketInfo->GetHasCleartextPhase()) // mirror PR_CONNECT_RESET_ERROR treament
2050 : {
2051 : wantRetry =
2052 0 : nsSSLIOLayerHelpers::rememberPossibleTLSProblemSite(socketInfo);
2053 : }
2054 : }
2055 : }
2056 :
2057 24 : if (wantRetry) {
2058 : // We want to cause the network layer to retry the connection.
2059 0 : PR_SetError(PR_CONNECT_RESET_ERROR, 0);
2060 0 : if (wasReading)
2061 0 : bytesTransfered = -1;
2062 : }
2063 :
2064 : // TLS intolerant servers only cause the first transfer to fail, so let's
2065 : // set the HandshakePending attribute to false so that we don't try the logic
2066 : // above again in a subsequent transfer.
2067 24 : if (handleHandshakeResultNow) {
2068 4 : socketInfo->SetHandshakePending(false);
2069 4 : socketInfo->SetHandshakeInProgress(false);
2070 : }
2071 :
2072 24 : return bytesTransfered;
2073 : }
2074 :
2075 : }
2076 :
2077 : static PRInt16 PR_CALLBACK
2078 270 : nsSSLIOLayerPoll(PRFileDesc * fd, PRInt16 in_flags, PRInt16 *out_flags)
2079 : {
2080 540 : nsNSSShutDownPreventionLock locker;
2081 :
2082 270 : if (!out_flags)
2083 : {
2084 0 : NS_WARNING("nsSSLIOLayerPoll called with null out_flags");
2085 0 : return 0;
2086 : }
2087 :
2088 270 : *out_flags = 0;
2089 :
2090 : nsNSSSocketInfo * socketInfo =
2091 270 : getSocketInfoIfRunning(fd, not_reading_or_writing, locker);
2092 :
2093 270 : if (!socketInfo) {
2094 : // If we get here, it is probably because certificate validation failed
2095 : // and this is the first I/O operation after the failure.
2096 0 : PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
2097 : ("[%p] polling SSL socket right after certificate verification failed "
2098 : "or NSS shutdown or SDR logout %d\n",
2099 : fd, (int) in_flags));
2100 :
2101 0 : NS_ASSERTION(in_flags & PR_POLL_EXCEPT,
2102 : "caller did not poll for EXCEPT (canceled)");
2103 : // Since this poll method cannot return errors, we want the caller to call
2104 : // PR_Send/PR_Recv right away to get the error, so we tell that we are
2105 : // ready for whatever I/O they are asking for. (See getSocketInfoIfRunning).
2106 0 : *out_flags = in_flags | PR_POLL_EXCEPT; // see also bug 480619
2107 0 : return in_flags;
2108 : }
2109 :
2110 270 : PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
2111 : (socketInfo->IsWaitingForCertVerification()
2112 : ? "[%p] polling SSL socket during certificate verification using lower %d\n"
2113 : : "[%p] poll SSL socket using lower %d\n",
2114 : fd, (int) in_flags));
2115 :
2116 : // See comments in HandshakeTimeout before moving and/or changing this block
2117 270 : if (socketInfo->HandshakeTimeout()) {
2118 0 : NS_WARNING("SSL handshake timed out");
2119 0 : PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] handshake timed out\n", fd));
2120 0 : NS_ASSERTION(in_flags & PR_POLL_EXCEPT,
2121 : "caller did not poll for EXCEPT (handshake timeout)");
2122 0 : *out_flags = in_flags | PR_POLL_EXCEPT;
2123 0 : socketInfo->SetCanceled(PR_CONNECT_RESET_ERROR, PlainErrorMessage);
2124 0 : return in_flags;
2125 : }
2126 :
2127 : // We want the handshake to continue during certificate validation, so we
2128 : // don't need to do anything special here. libssl automatically blocks when
2129 : // it reaches any point that would be unsafe to send/receive something before
2130 : // cert validation is complete.
2131 270 : PRInt16 result = fd->lower->methods->poll(fd->lower, in_flags, out_flags);
2132 270 : PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] poll SSL socket returned %d\n",
2133 : (void*)fd, (int) result));
2134 270 : return result;
2135 : }
2136 :
2137 : bool nsSSLIOLayerHelpers::nsSSLIOLayerInitialized = false;
2138 : PRDescIdentity nsSSLIOLayerHelpers::nsSSLIOLayerIdentity;
2139 : PRIOMethods nsSSLIOLayerHelpers::nsSSLIOLayerMethods;
2140 : Mutex *nsSSLIOLayerHelpers::mutex = nsnull;
2141 : nsTHashtable<nsCStringHashKey> *nsSSLIOLayerHelpers::mTLSIntolerantSites = nsnull;
2142 : nsTHashtable<nsCStringHashKey> *nsSSLIOLayerHelpers::mTLSTolerantSites = nsnull;
2143 : nsPSMRememberCertErrorsTable *nsSSLIOLayerHelpers::mHostsWithCertErrors = nsnull;
2144 : nsTHashtable<nsCStringHashKey> *nsSSLIOLayerHelpers::mRenegoUnrestrictedSites = nsnull;
2145 : bool nsSSLIOLayerHelpers::mTreatUnsafeNegotiationAsBroken = false;
2146 : PRInt32 nsSSLIOLayerHelpers::mWarnLevelMissingRFC5746 = 1;
2147 :
2148 0 : static PRIntn _PSM_InvalidInt(void)
2149 : {
2150 0 : PR_ASSERT(!"I/O method is invalid");
2151 0 : PR_SetError(PR_INVALID_METHOD_ERROR, 0);
2152 0 : return -1;
2153 : }
2154 :
2155 0 : static PRInt64 _PSM_InvalidInt64(void)
2156 : {
2157 0 : PR_ASSERT(!"I/O method is invalid");
2158 0 : PR_SetError(PR_INVALID_METHOD_ERROR, 0);
2159 0 : return -1;
2160 : }
2161 :
2162 0 : static PRStatus _PSM_InvalidStatus(void)
2163 : {
2164 0 : PR_ASSERT(!"I/O method is invalid");
2165 0 : PR_SetError(PR_INVALID_METHOD_ERROR, 0);
2166 0 : return PR_FAILURE;
2167 : }
2168 :
2169 0 : static PRFileDesc *_PSM_InvalidDesc(void)
2170 : {
2171 0 : PR_ASSERT(!"I/O method is invalid");
2172 0 : PR_SetError(PR_INVALID_METHOD_ERROR, 0);
2173 0 : return NULL;
2174 : }
2175 :
2176 8 : static PRStatus PR_CALLBACK PSMGetsockname(PRFileDesc *fd, PRNetAddr *addr)
2177 : {
2178 16 : nsNSSShutDownPreventionLock locker;
2179 8 : if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
2180 0 : return PR_FAILURE;
2181 :
2182 8 : return fd->lower->methods->getsockname(fd->lower, addr);
2183 : }
2184 :
2185 0 : static PRStatus PR_CALLBACK PSMGetpeername(PRFileDesc *fd, PRNetAddr *addr)
2186 : {
2187 0 : nsNSSShutDownPreventionLock locker;
2188 0 : if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
2189 0 : return PR_FAILURE;
2190 :
2191 0 : return fd->lower->methods->getpeername(fd->lower, addr);
2192 : }
2193 :
2194 0 : static PRStatus PR_CALLBACK PSMGetsocketoption(PRFileDesc *fd,
2195 : PRSocketOptionData *data)
2196 : {
2197 0 : nsNSSShutDownPreventionLock locker;
2198 0 : if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
2199 0 : return PR_FAILURE;
2200 :
2201 0 : return fd->lower->methods->getsocketoption(fd, data);
2202 : }
2203 :
2204 8 : static PRStatus PR_CALLBACK PSMSetsocketoption(PRFileDesc *fd,
2205 : const PRSocketOptionData *data)
2206 : {
2207 16 : nsNSSShutDownPreventionLock locker;
2208 8 : if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker))
2209 0 : return PR_FAILURE;
2210 :
2211 8 : return fd->lower->methods->setsocketoption(fd, data);
2212 : }
2213 :
2214 16 : static PRInt32 PR_CALLBACK PSMRecv(PRFileDesc *fd, void *buf, PRInt32 amount,
2215 : PRIntn flags, PRIntervalTime timeout)
2216 : {
2217 32 : nsNSSShutDownPreventionLock locker;
2218 16 : nsNSSSocketInfo *socketInfo = getSocketInfoIfRunning(fd, reading, locker);
2219 16 : if (!socketInfo)
2220 0 : return -1;
2221 :
2222 16 : if (flags != PR_MSG_PEEK && flags != 0) {
2223 0 : PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
2224 0 : return -1;
2225 : }
2226 :
2227 : PRInt32 bytesRead = fd->lower->methods->recv(fd->lower, buf, amount, flags,
2228 16 : timeout);
2229 :
2230 16 : PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] read %d bytes\n", (void*)fd, bytesRead));
2231 :
2232 : #ifdef DEBUG_SSL_VERBOSE
2233 : DEBUG_DUMP_BUFFER((unsigned char*)buf, bytesRead);
2234 : #endif
2235 :
2236 16 : return checkHandshake(bytesRead, true, fd, socketInfo);
2237 : }
2238 :
2239 16 : static PRInt32 PR_CALLBACK PSMSend(PRFileDesc *fd, const void *buf, PRInt32 amount,
2240 : PRIntn flags, PRIntervalTime timeout)
2241 : {
2242 32 : nsNSSShutDownPreventionLock locker;
2243 16 : nsNSSSocketInfo *socketInfo = getSocketInfoIfRunning(fd, writing, locker);
2244 16 : if (!socketInfo)
2245 0 : return -1;
2246 :
2247 16 : if (flags != 0) {
2248 0 : PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
2249 0 : return -1;
2250 : }
2251 :
2252 : #ifdef DEBUG_SSL_VERBOSE
2253 : DEBUG_DUMP_BUFFER((unsigned char*)buf, amount);
2254 : #endif
2255 :
2256 : PRInt32 bytesWritten = fd->lower->methods->send(fd->lower, buf, amount,
2257 16 : flags, timeout);
2258 :
2259 16 : PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] wrote %d bytes\n",
2260 : fd, bytesWritten));
2261 :
2262 16 : return checkHandshake(bytesWritten, false, fd, socketInfo);
2263 : }
2264 :
2265 : static PRInt32 PR_CALLBACK
2266 8 : nsSSLIOLayerRead(PRFileDesc* fd, void* buf, PRInt32 amount)
2267 : {
2268 8 : return PSMRecv(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
2269 : }
2270 :
2271 : static PRInt32 PR_CALLBACK
2272 16 : nsSSLIOLayerWrite(PRFileDesc* fd, const void* buf, PRInt32 amount)
2273 : {
2274 16 : return PSMSend(fd, buf, amount, 0, PR_INTERVAL_NO_TIMEOUT);
2275 : }
2276 :
2277 4 : static PRStatus PR_CALLBACK PSMConnectcontinue(PRFileDesc *fd, PRInt16 out_flags)
2278 : {
2279 8 : nsNSSShutDownPreventionLock locker;
2280 4 : if (!getSocketInfoIfRunning(fd, not_reading_or_writing, locker)) {
2281 0 : return PR_FAILURE;
2282 : }
2283 :
2284 4 : return fd->lower->methods->connectcontinue(fd, out_flags);
2285 : }
2286 :
2287 4 : static PRIntn PSMAvailable(void)
2288 : {
2289 : // This is called through PR_Available(), but is not implemented in PSM
2290 4 : PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2291 4 : return -1;
2292 : }
2293 :
2294 0 : static PRInt64 PSMAvailable64(void)
2295 : {
2296 : // This is called through PR_Available(), but is not implemented in PSM
2297 0 : PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
2298 0 : return -1;
2299 : }
2300 :
2301 328 : nsresult nsSSLIOLayerHelpers::Init()
2302 : {
2303 328 : if (!nsSSLIOLayerInitialized) {
2304 328 : nsSSLIOLayerInitialized = true;
2305 328 : nsSSLIOLayerIdentity = PR_GetUniqueIdentity("NSS layer");
2306 328 : nsSSLIOLayerMethods = *PR_GetDefaultIOMethods();
2307 :
2308 328 : nsSSLIOLayerMethods.available = (PRAvailableFN)PSMAvailable;
2309 328 : nsSSLIOLayerMethods.available64 = (PRAvailable64FN)PSMAvailable64;
2310 328 : nsSSLIOLayerMethods.fsync = (PRFsyncFN)_PSM_InvalidStatus;
2311 328 : nsSSLIOLayerMethods.seek = (PRSeekFN)_PSM_InvalidInt;
2312 328 : nsSSLIOLayerMethods.seek64 = (PRSeek64FN)_PSM_InvalidInt64;
2313 328 : nsSSLIOLayerMethods.fileInfo = (PRFileInfoFN)_PSM_InvalidStatus;
2314 328 : nsSSLIOLayerMethods.fileInfo64 = (PRFileInfo64FN)_PSM_InvalidStatus;
2315 328 : nsSSLIOLayerMethods.writev = (PRWritevFN)_PSM_InvalidInt;
2316 328 : nsSSLIOLayerMethods.accept = (PRAcceptFN)_PSM_InvalidDesc;
2317 328 : nsSSLIOLayerMethods.bind = (PRBindFN)_PSM_InvalidStatus;
2318 328 : nsSSLIOLayerMethods.listen = (PRListenFN)_PSM_InvalidStatus;
2319 328 : nsSSLIOLayerMethods.shutdown = (PRShutdownFN)_PSM_InvalidStatus;
2320 328 : nsSSLIOLayerMethods.recvfrom = (PRRecvfromFN)_PSM_InvalidInt;
2321 328 : nsSSLIOLayerMethods.sendto = (PRSendtoFN)_PSM_InvalidInt;
2322 328 : nsSSLIOLayerMethods.acceptread = (PRAcceptreadFN)_PSM_InvalidInt;
2323 328 : nsSSLIOLayerMethods.transmitfile = (PRTransmitfileFN)_PSM_InvalidInt;
2324 328 : nsSSLIOLayerMethods.sendfile = (PRSendfileFN)_PSM_InvalidInt;
2325 :
2326 328 : nsSSLIOLayerMethods.getsockname = PSMGetsockname;
2327 328 : nsSSLIOLayerMethods.getpeername = PSMGetpeername;
2328 328 : nsSSLIOLayerMethods.getsocketoption = PSMGetsocketoption;
2329 328 : nsSSLIOLayerMethods.setsocketoption = PSMSetsocketoption;
2330 328 : nsSSLIOLayerMethods.recv = PSMRecv;
2331 328 : nsSSLIOLayerMethods.send = PSMSend;
2332 328 : nsSSLIOLayerMethods.connectcontinue = PSMConnectcontinue;
2333 :
2334 328 : nsSSLIOLayerMethods.connect = nsSSLIOLayerConnect;
2335 328 : nsSSLIOLayerMethods.close = nsSSLIOLayerClose;
2336 328 : nsSSLIOLayerMethods.write = nsSSLIOLayerWrite;
2337 328 : nsSSLIOLayerMethods.read = nsSSLIOLayerRead;
2338 328 : nsSSLIOLayerMethods.poll = nsSSLIOLayerPoll;
2339 : }
2340 :
2341 328 : mutex = new Mutex("nsSSLIOLayerHelpers.mutex");
2342 :
2343 328 : mTLSIntolerantSites = new nsTHashtable<nsCStringHashKey>();
2344 328 : if (!mTLSIntolerantSites)
2345 0 : return NS_ERROR_OUT_OF_MEMORY;
2346 :
2347 328 : mTLSIntolerantSites->Init(1);
2348 :
2349 328 : mTLSTolerantSites = new nsTHashtable<nsCStringHashKey>();
2350 328 : if (!mTLSTolerantSites)
2351 0 : return NS_ERROR_OUT_OF_MEMORY;
2352 :
2353 : // Initialize the tolerant site hashtable to 16 items at the start seems
2354 : // reasonable as most servers are TLS tolerant. We just want to lower
2355 : // the rate of hashtable array reallocation.
2356 328 : mTLSTolerantSites->Init(16);
2357 :
2358 328 : mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>();
2359 328 : if (!mRenegoUnrestrictedSites)
2360 0 : return NS_ERROR_OUT_OF_MEMORY;
2361 :
2362 328 : mRenegoUnrestrictedSites->Init(1);
2363 :
2364 328 : mTreatUnsafeNegotiationAsBroken = false;
2365 :
2366 328 : mHostsWithCertErrors = new nsPSMRememberCertErrorsTable();
2367 328 : if (!mHostsWithCertErrors || !mHostsWithCertErrors->mErrorHosts.IsInitialized())
2368 0 : return NS_ERROR_OUT_OF_MEMORY;
2369 :
2370 328 : return NS_OK;
2371 : }
2372 :
2373 0 : void nsSSLIOLayerHelpers::addIntolerantSite(const nsCString &str)
2374 : {
2375 0 : MutexAutoLock lock(*mutex);
2376 : // Remember intolerant site only if it is not known as tolerant
2377 0 : if (!mTLSTolerantSites->Contains(str))
2378 0 : nsSSLIOLayerHelpers::mTLSIntolerantSites->PutEntry(str);
2379 0 : }
2380 :
2381 0 : void nsSSLIOLayerHelpers::removeIntolerantSite(const nsCString &str)
2382 : {
2383 0 : MutexAutoLock lock(*mutex);
2384 0 : nsSSLIOLayerHelpers::mTLSIntolerantSites->RemoveEntry(str);
2385 0 : }
2386 :
2387 4 : bool nsSSLIOLayerHelpers::isKnownAsIntolerantSite(const nsCString &str)
2388 : {
2389 8 : MutexAutoLock lock(*mutex);
2390 4 : return mTLSIntolerantSites->Contains(str);
2391 : }
2392 :
2393 328 : void nsSSLIOLayerHelpers::setRenegoUnrestrictedSites(const nsCString &str)
2394 : {
2395 656 : MutexAutoLock lock(*mutex);
2396 :
2397 328 : if (mRenegoUnrestrictedSites) {
2398 328 : delete mRenegoUnrestrictedSites;
2399 328 : mRenegoUnrestrictedSites = nsnull;
2400 : }
2401 :
2402 328 : mRenegoUnrestrictedSites = new nsTHashtable<nsCStringHashKey>();
2403 328 : if (!mRenegoUnrestrictedSites)
2404 : return;
2405 :
2406 328 : mRenegoUnrestrictedSites->Init(1);
2407 :
2408 328 : nsCCharSeparatedTokenizer toker(str, ',');
2409 :
2410 656 : while (toker.hasMoreTokens()) {
2411 0 : const nsCSubstring &host = toker.nextToken();
2412 0 : if (!host.IsEmpty()) {
2413 0 : mRenegoUnrestrictedSites->PutEntry(host);
2414 : }
2415 : }
2416 : }
2417 :
2418 4 : bool nsSSLIOLayerHelpers::isRenegoUnrestrictedSite(const nsCString &str)
2419 : {
2420 8 : MutexAutoLock lock(*mutex);
2421 4 : return mRenegoUnrestrictedSites->Contains(str);
2422 : }
2423 :
2424 328 : void nsSSLIOLayerHelpers::setTreatUnsafeNegotiationAsBroken(bool broken)
2425 : {
2426 656 : MutexAutoLock lock(*mutex);
2427 328 : mTreatUnsafeNegotiationAsBroken = broken;
2428 328 : }
2429 :
2430 0 : bool nsSSLIOLayerHelpers::treatUnsafeNegotiationAsBroken()
2431 : {
2432 0 : MutexAutoLock lock(*mutex);
2433 0 : return mTreatUnsafeNegotiationAsBroken;
2434 : }
2435 :
2436 328 : void nsSSLIOLayerHelpers::setWarnLevelMissingRFC5746(PRInt32 level)
2437 : {
2438 656 : MutexAutoLock lock(*mutex);
2439 328 : mWarnLevelMissingRFC5746 = level;
2440 328 : }
2441 :
2442 0 : PRInt32 nsSSLIOLayerHelpers::getWarnLevelMissingRFC5746()
2443 : {
2444 0 : MutexAutoLock lock(*mutex);
2445 0 : return mWarnLevelMissingRFC5746;
2446 : }
2447 :
2448 : nsresult
2449 4 : nsSSLIOLayerNewSocket(PRInt32 family,
2450 : const char *host,
2451 : PRInt32 port,
2452 : const char *proxyHost,
2453 : PRInt32 proxyPort,
2454 : PRFileDesc **fd,
2455 : nsISupports** info,
2456 : bool forSTARTTLS,
2457 : bool anonymousLoad)
2458 : {
2459 :
2460 4 : PRFileDesc* sock = PR_OpenTCPSocket(family);
2461 4 : if (!sock) return NS_ERROR_OUT_OF_MEMORY;
2462 :
2463 : nsresult rv = nsSSLIOLayerAddToSocket(family, host, port, proxyHost, proxyPort,
2464 4 : sock, info, forSTARTTLS, anonymousLoad);
2465 4 : if (NS_FAILED(rv)) {
2466 0 : PR_Close(sock);
2467 0 : return rv;
2468 : }
2469 :
2470 4 : *fd = sock;
2471 4 : return NS_OK;
2472 : }
2473 :
2474 : /*
2475 : * Function: SECStatus nsConvertCANamesToStrings()
2476 : * Purpose: creates CA names strings from (CERTDistNames* caNames)
2477 : *
2478 : * Arguments and return values
2479 : * - arena: arena to allocate strings on
2480 : * - caNameStrings: filled with CA names strings on return
2481 : * - caNames: CERTDistNames to extract strings from
2482 : * - return: SECSuccess if successful; error code otherwise
2483 : *
2484 : * Note: copied in its entirety from Nova code
2485 : */
2486 0 : SECStatus nsConvertCANamesToStrings(PRArenaPool* arena, char** caNameStrings,
2487 : CERTDistNames* caNames)
2488 : {
2489 : SECItem* dername;
2490 : SECStatus rv;
2491 : int headerlen;
2492 : PRUint32 contentlen;
2493 : SECItem newitem;
2494 : int n;
2495 : char* namestring;
2496 :
2497 0 : for (n = 0; n < caNames->nnames; n++) {
2498 0 : newitem.data = NULL;
2499 0 : dername = &caNames->names[n];
2500 :
2501 0 : rv = DER_Lengths(dername, &headerlen, &contentlen);
2502 :
2503 0 : if (rv != SECSuccess) {
2504 0 : goto loser;
2505 : }
2506 :
2507 0 : if (headerlen + contentlen != dername->len) {
2508 : /* This must be from an enterprise 2.x server, which sent
2509 : * incorrectly formatted der without the outer wrapper of
2510 : * type and length. Fix it up by adding the top level
2511 : * header.
2512 : */
2513 0 : if (dername->len <= 127) {
2514 0 : newitem.data = (unsigned char *) PR_Malloc(dername->len + 2);
2515 0 : if (newitem.data == NULL) {
2516 0 : goto loser;
2517 : }
2518 0 : newitem.data[0] = (unsigned char)0x30;
2519 0 : newitem.data[1] = (unsigned char)dername->len;
2520 0 : (void)memcpy(&newitem.data[2], dername->data, dername->len);
2521 : }
2522 0 : else if (dername->len <= 255) {
2523 0 : newitem.data = (unsigned char *) PR_Malloc(dername->len + 3);
2524 0 : if (newitem.data == NULL) {
2525 0 : goto loser;
2526 : }
2527 0 : newitem.data[0] = (unsigned char)0x30;
2528 0 : newitem.data[1] = (unsigned char)0x81;
2529 0 : newitem.data[2] = (unsigned char)dername->len;
2530 0 : (void)memcpy(&newitem.data[3], dername->data, dername->len);
2531 : }
2532 : else {
2533 : /* greater than 256, better be less than 64k */
2534 0 : newitem.data = (unsigned char *) PR_Malloc(dername->len + 4);
2535 0 : if (newitem.data == NULL) {
2536 0 : goto loser;
2537 : }
2538 0 : newitem.data[0] = (unsigned char)0x30;
2539 0 : newitem.data[1] = (unsigned char)0x82;
2540 0 : newitem.data[2] = (unsigned char)((dername->len >> 8) & 0xff);
2541 0 : newitem.data[3] = (unsigned char)(dername->len & 0xff);
2542 0 : memcpy(&newitem.data[4], dername->data, dername->len);
2543 : }
2544 0 : dername = &newitem;
2545 : }
2546 :
2547 0 : namestring = CERT_DerNameToAscii(dername);
2548 0 : if (namestring == NULL) {
2549 : /* XXX - keep going until we fail to convert the name */
2550 0 : caNameStrings[n] = const_cast<char*>("");
2551 : }
2552 : else {
2553 0 : caNameStrings[n] = PORT_ArenaStrdup(arena, namestring);
2554 0 : PR_Free(namestring);
2555 0 : if (caNameStrings[n] == NULL) {
2556 0 : goto loser;
2557 : }
2558 : }
2559 :
2560 0 : if (newitem.data != NULL) {
2561 0 : PR_Free(newitem.data);
2562 : }
2563 : }
2564 :
2565 0 : return SECSuccess;
2566 : loser:
2567 0 : if (newitem.data != NULL) {
2568 0 : PR_Free(newitem.data);
2569 : }
2570 0 : return SECFailure;
2571 : }
2572 :
2573 : /*
2574 : * structs and ASN1 templates for the limited scope-of-use extension
2575 : *
2576 : * CertificateScopeEntry ::= SEQUENCE {
2577 : * name GeneralName, -- pattern, as for NameConstraints
2578 : * portNumber INTEGER OPTIONAL }
2579 : *
2580 : * CertificateScopeOfUse ::= SEQUENCE OF CertificateScopeEntry
2581 : */
2582 : /*
2583 : * CERTCertificateScopeEntry: struct for scope entry that can be consumed by
2584 : * the code
2585 : * certCertificateScopeOfUse: struct that represents the decoded extension data
2586 : */
2587 : typedef struct {
2588 : SECItem derConstraint;
2589 : SECItem derPort;
2590 : CERTGeneralName* constraint; /* decoded constraint */
2591 : PRIntn port; /* decoded port number */
2592 : } CERTCertificateScopeEntry;
2593 :
2594 : typedef struct {
2595 : CERTCertificateScopeEntry** entries;
2596 : } certCertificateScopeOfUse;
2597 :
2598 : /* corresponding ASN1 templates */
2599 : static const SEC_ASN1Template cert_CertificateScopeEntryTemplate[] = {
2600 : { SEC_ASN1_SEQUENCE,
2601 : 0, NULL, sizeof(CERTCertificateScopeEntry) },
2602 : { SEC_ASN1_ANY,
2603 : offsetof(CERTCertificateScopeEntry, derConstraint) },
2604 : { SEC_ASN1_OPTIONAL | SEC_ASN1_INTEGER,
2605 : offsetof(CERTCertificateScopeEntry, derPort) },
2606 : { 0 }
2607 : };
2608 :
2609 : static const SEC_ASN1Template cert_CertificateScopeOfUseTemplate[] = {
2610 : { SEC_ASN1_SEQUENCE_OF, 0, cert_CertificateScopeEntryTemplate }
2611 : };
2612 :
2613 : #if 0
2614 : /*
2615 : * decodes the extension data and create CERTCertificateScopeEntry that can
2616 : * be consumed by the code
2617 : */
2618 : static
2619 : SECStatus cert_DecodeScopeOfUseEntries(PRArenaPool* arena, SECItem* extData,
2620 : CERTCertificateScopeEntry*** entries,
2621 : int* numEntries)
2622 : {
2623 : certCertificateScopeOfUse* scope = NULL;
2624 : SECStatus rv = SECSuccess;
2625 : int i;
2626 :
2627 : *entries = NULL; /* in case of failure */
2628 : *numEntries = 0; /* ditto */
2629 :
2630 : scope = (certCertificateScopeOfUse*)
2631 : PORT_ArenaZAlloc(arena, sizeof(certCertificateScopeOfUse));
2632 : if (scope == NULL) {
2633 : goto loser;
2634 : }
2635 :
2636 : rv = SEC_ASN1DecodeItem(arena, (void*)scope,
2637 : cert_CertificateScopeOfUseTemplate, extData);
2638 : if (rv != SECSuccess) {
2639 : goto loser;
2640 : }
2641 :
2642 : *entries = scope->entries;
2643 : PR_ASSERT(*entries != NULL);
2644 :
2645 : /* first, let's count 'em. */
2646 : for (i = 0; (*entries)[i] != NULL; i++) ;
2647 : *numEntries = i;
2648 :
2649 : /* convert certCertificateScopeEntry sequence into what we can readily
2650 : * use
2651 : */
2652 : for (i = 0; i < *numEntries; i++) {
2653 : (*entries)[i]->constraint =
2654 : CERT_DecodeGeneralName(arena, &((*entries)[i]->derConstraint),
2655 : NULL);
2656 : if ((*entries)[i]->derPort.data != NULL) {
2657 : (*entries)[i]->port =
2658 : (int)DER_GetInteger(&((*entries)[i]->derPort));
2659 : }
2660 : else {
2661 : (*entries)[i]->port = 0;
2662 : }
2663 : }
2664 :
2665 : goto done;
2666 : loser:
2667 : if (rv == SECSuccess) {
2668 : rv = SECFailure;
2669 : }
2670 : done:
2671 : return rv;
2672 : }
2673 :
2674 : static SECStatus cert_DecodeCertIPAddress(SECItem* genname,
2675 : PRUint32* constraint, PRUint32* mask)
2676 : {
2677 : /* in case of failure */
2678 : *constraint = 0;
2679 : *mask = 0;
2680 :
2681 : PR_ASSERT(genname->data != NULL);
2682 : if (genname->data == NULL) {
2683 : return SECFailure;
2684 : }
2685 : if (genname->len != 8) {
2686 : /* the length must be 4 byte IP address with 4 byte subnet mask */
2687 : return SECFailure;
2688 : }
2689 :
2690 : /* get them in the right order */
2691 : *constraint = PR_ntohl((PRUint32)(*genname->data));
2692 : *mask = PR_ntohl((PRUint32)(*(genname->data + 4)));
2693 :
2694 : return SECSuccess;
2695 : }
2696 :
2697 : static char* _str_to_lower(char* string)
2698 : {
2699 : #ifdef XP_WIN
2700 : return _strlwr(string);
2701 : #else
2702 : int i;
2703 : for (i = 0; string[i] != '\0'; i++) {
2704 : string[i] = tolower(string[i]);
2705 : }
2706 : return string;
2707 : #endif
2708 : }
2709 :
2710 : /*
2711 : * Sees if the client certificate has a restriction in presenting the cert
2712 : * to the host: returns true if there is no restriction or if the hostname
2713 : * (and the port) satisfies the restriction, or false if the hostname (and
2714 : * the port) does not satisfy the restriction
2715 : */
2716 : static bool CERT_MatchesScopeOfUse(CERTCertificate* cert, char* hostname,
2717 : char* hostIP, PRIntn port)
2718 : {
2719 : bool rv = true; /* whether the cert can be presented */
2720 : SECStatus srv;
2721 : SECItem extData;
2722 : PRArenaPool* arena = NULL;
2723 : CERTCertificateScopeEntry** entries = NULL;
2724 : /* arrays of decoded scope entries */
2725 : int numEntries = 0;
2726 : int i;
2727 : char* hostLower = NULL;
2728 : PRUint32 hostIPAddr = 0;
2729 :
2730 : PR_ASSERT((cert != NULL) && (hostname != NULL) && (hostIP != NULL));
2731 :
2732 : /* find cert extension */
2733 : srv = CERT_FindCertExtension(cert, SEC_OID_NS_CERT_EXT_SCOPE_OF_USE,
2734 : &extData);
2735 : if (srv != SECSuccess) {
2736 : /* most of the time, this means the extension was not found: also,
2737 : * since this is not a critical extension (as of now) we may simply
2738 : * return true
2739 : */
2740 : goto done;
2741 : }
2742 :
2743 : arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
2744 : if (arena == NULL) {
2745 : goto done;
2746 : }
2747 :
2748 : /* decode the scope of use entries into pairs of GeneralNames and
2749 : * an optional port numbers
2750 : */
2751 : srv = cert_DecodeScopeOfUseEntries(arena, &extData, &entries, &numEntries);
2752 : if (srv != SECSuccess) {
2753 : /* XXX What should we do when we failed to decode the extension? This
2754 : * may mean either the extension was malformed or some (unlikely)
2755 : * fatal error on our part: my argument is that if the extension
2756 : * was malformed the extension "disqualifies" as a valid
2757 : * constraint and we may present the cert
2758 : */
2759 : goto done;
2760 : }
2761 :
2762 : /* loop over these structures */
2763 : for (i = 0; i < numEntries; i++) {
2764 : /* determine whether the GeneralName is a DNS pattern, an IP address
2765 : * constraint, or else
2766 : */
2767 : CERTGeneralName* genname = entries[i]->constraint;
2768 :
2769 : /* if constraint is NULL, don't bother looking */
2770 : if (genname == NULL) {
2771 : /* this is not a failure: just continue */
2772 : continue;
2773 : }
2774 :
2775 : switch (genname->type) {
2776 : case certDNSName: {
2777 : /* we have a DNS name constraint; we should use only the host name
2778 : * information
2779 : */
2780 : char* pattern = NULL;
2781 : char* substring = NULL;
2782 :
2783 : /* null-terminate the string */
2784 : genname->name.other.data[genname->name.other.len] = '\0';
2785 : pattern = _str_to_lower((char*)genname->name.other.data);
2786 :
2787 : if (hostLower == NULL) {
2788 : /* so that it's done only if necessary and only once */
2789 : hostLower = _str_to_lower(PL_strdup(hostname));
2790 : }
2791 :
2792 : /* the hostname satisfies the constraint */
2793 : if (((substring = strstr(hostLower, pattern)) != NULL) &&
2794 : /* the hostname contains the pattern */
2795 : (strlen(substring) == strlen(pattern)) &&
2796 : /* the hostname ends with the pattern */
2797 : ((substring == hostLower) || (*(substring-1) == '.'))) {
2798 : /* the hostname either is identical to the pattern or
2799 : * belongs to a subdomain
2800 : */
2801 : rv = true;
2802 : }
2803 : else {
2804 : rv = false;
2805 : }
2806 : /* clean up strings if necessary */
2807 : break;
2808 : }
2809 : case certIPAddress: {
2810 : PRUint32 constraint;
2811 : PRUint32 mask;
2812 : PRNetAddr addr;
2813 :
2814 : if (hostIPAddr == 0) {
2815 : /* so that it's done only if necessary and only once */
2816 : PR_StringToNetAddr(hostIP, &addr);
2817 : hostIPAddr = addr.inet.ip;
2818 : }
2819 :
2820 : if (cert_DecodeCertIPAddress(&(genname->name.other), &constraint,
2821 : &mask) != SECSuccess) {
2822 : continue;
2823 : }
2824 : if ((hostIPAddr & mask) == (constraint & mask)) {
2825 : rv = true;
2826 : }
2827 : else {
2828 : rv = false;
2829 : }
2830 : break;
2831 : }
2832 : default:
2833 : /* ill-formed entry: abort */
2834 : continue; /* go to the next entry */
2835 : }
2836 :
2837 : if (!rv) {
2838 : /* we do not need to check the port: go to the next entry */
2839 : continue;
2840 : }
2841 :
2842 : /* finally, check the optional port number */
2843 : if ((entries[i]->port != 0) && (port != entries[i]->port)) {
2844 : /* port number does not match */
2845 : rv = false;
2846 : continue;
2847 : }
2848 :
2849 : /* we have a match */
2850 : PR_ASSERT(rv);
2851 : break;
2852 : }
2853 : done:
2854 : /* clean up entries */
2855 : if (arena != NULL) {
2856 : PORT_FreeArena(arena, false);
2857 : }
2858 : if (hostLower != NULL) {
2859 : PR_Free(hostLower);
2860 : }
2861 : return rv;
2862 : }
2863 : #endif
2864 :
2865 : /*
2866 : * Function: SSMStatus SSM_SetUserCertChoice()
2867 :
2868 : * Purpose: sets certChoice by reading the preference
2869 : *
2870 : * Arguments and return values
2871 : * - conn: SSMSSLDataConnection
2872 : * - returns: SSM_SUCCESS if successful; SSM_FAILURE otherwise
2873 : *
2874 : * Note: If done properly, this function will read the identifier strings
2875 : * for ASK and AUTO modes, read the selected strings from the
2876 : * preference, compare the strings, and determine in which mode it is
2877 : * in.
2878 : * We currently use ASK mode for UI apps and AUTO mode for UI-less
2879 : * apps without really asking for preferences.
2880 : */
2881 0 : nsresult nsGetUserCertChoice(SSM_UserCertChoice* certChoice)
2882 : {
2883 0 : char *mode=NULL;
2884 : nsresult ret;
2885 :
2886 0 : NS_ENSURE_ARG_POINTER(certChoice);
2887 :
2888 0 : nsCOMPtr<nsIPrefBranch> pref = do_GetService(NS_PREFSERVICE_CONTRACTID);
2889 :
2890 0 : ret = pref->GetCharPref("security.default_personal_cert", &mode);
2891 0 : if (NS_FAILED(ret)) {
2892 0 : goto loser;
2893 : }
2894 :
2895 0 : if (PL_strcmp(mode, "Select Automatically") == 0) {
2896 0 : *certChoice = AUTO;
2897 : }
2898 0 : else if (PL_strcmp(mode, "Ask Every Time") == 0) {
2899 0 : *certChoice = ASK;
2900 : }
2901 : else {
2902 : // Most likely we see a nickname from a migrated cert.
2903 : // We do not currently support that, ask the user which cert to use.
2904 0 : *certChoice = ASK;
2905 : }
2906 :
2907 : loser:
2908 0 : if (mode) {
2909 0 : nsMemory::Free(mode);
2910 : }
2911 0 : return ret;
2912 : }
2913 :
2914 0 : static bool hasExplicitKeyUsageNonRepudiation(CERTCertificate *cert)
2915 : {
2916 : /* There is no extension, v1 or v2 certificate */
2917 0 : if (!cert->extensions)
2918 0 : return false;
2919 :
2920 : SECStatus srv;
2921 : SECItem keyUsageItem;
2922 0 : keyUsageItem.data = NULL;
2923 :
2924 0 : srv = CERT_FindKeyUsageExtension(cert, &keyUsageItem);
2925 0 : if (srv == SECFailure)
2926 0 : return false;
2927 :
2928 0 : unsigned char keyUsage = keyUsageItem.data[0];
2929 0 : PORT_Free (keyUsageItem.data);
2930 :
2931 0 : return !!(keyUsage & KU_NON_REPUDIATION);
2932 : }
2933 :
2934 : class ClientAuthDataRunnable : public SyncRunnableBase
2935 0 : {
2936 : public:
2937 0 : ClientAuthDataRunnable(CERTDistNames* caNames,
2938 : CERTCertificate** pRetCert,
2939 : SECKEYPrivateKey** pRetKey,
2940 : nsNSSSocketInfo * info,
2941 : CERTCertificate * serverCert)
2942 : : mRV(SECFailure)
2943 : , mErrorCodeToReport(SEC_ERROR_NO_MEMORY)
2944 : , mPRetCert(pRetCert)
2945 : , mPRetKey(pRetKey)
2946 : , mCANames(caNames)
2947 : , mSocketInfo(info)
2948 0 : , mServerCert(serverCert)
2949 : {
2950 0 : }
2951 :
2952 : SECStatus mRV; // out
2953 : PRErrorCode mErrorCodeToReport; // out
2954 : CERTCertificate** const mPRetCert; // in/out
2955 : SECKEYPrivateKey** const mPRetKey; // in/out
2956 : protected:
2957 : virtual void RunOnTargetThread();
2958 : private:
2959 : CERTDistNames* const mCANames; // in
2960 : nsNSSSocketInfo * const mSocketInfo; // in
2961 : CERTCertificate * const mServerCert; // in
2962 : };
2963 :
2964 : /*
2965 : * Function: SECStatus SSM_SSLGetClientAuthData()
2966 : * Purpose: this callback function is used to pull client certificate
2967 : * information upon server request
2968 : *
2969 : * Arguments and return values
2970 : * - arg: SSL data connection
2971 : * - socket: SSL socket we're dealing with
2972 : * - caNames: list of CA names
2973 : * - pRetCert: returns a pointer to a pointer to a valid certificate if
2974 : * successful; otherwise NULL
2975 : * - pRetKey: returns a pointer to a pointer to the corresponding key if
2976 : * successful; otherwise NULL
2977 : * - returns: SECSuccess if successful; error code otherwise
2978 : */
2979 0 : SECStatus nsNSS_SSLGetClientAuthData(void* arg, PRFileDesc* socket,
2980 : CERTDistNames* caNames,
2981 : CERTCertificate** pRetCert,
2982 : SECKEYPrivateKey** pRetKey)
2983 : {
2984 0 : nsNSSShutDownPreventionLock locker;
2985 :
2986 0 : if (!socket || !caNames || !pRetCert || !pRetKey) {
2987 0 : PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0);
2988 0 : return SECFailure;
2989 : }
2990 :
2991 : nsRefPtr<nsNSSSocketInfo> info
2992 0 : = reinterpret_cast<nsNSSSocketInfo*>(socket->higher->secret);
2993 :
2994 0 : CERTCertificate* serverCert = SSL_PeerCertificate(socket);
2995 0 : if (!serverCert) {
2996 : NS_NOTREACHED("Missing server certificate should have been detected during "
2997 0 : "server cert authentication.");
2998 0 : PR_SetError(SSL_ERROR_NO_CERTIFICATE, 0);
2999 0 : return SECFailure;
3000 : }
3001 :
3002 0 : if (info->GetJoined()) {
3003 : // We refuse to send a client certificate when there are multiple hostnames
3004 : // joined on this connection, because we only show the user one hostname
3005 : // (mHostName) in the client certificate UI.
3006 :
3007 0 : PR_LOG(gPIPNSSLog, PR_LOG_DEBUG,
3008 : ("[%p] Not returning client cert due to previous join\n", socket));
3009 0 : *pRetCert = nsnull;
3010 0 : *pRetKey = nsnull;
3011 0 : return SECSuccess;
3012 : }
3013 :
3014 : // XXX: This should be done asynchronously; see bug 696976
3015 : nsRefPtr<ClientAuthDataRunnable> runnable =
3016 0 : new ClientAuthDataRunnable(caNames, pRetCert, pRetKey, info, serverCert);
3017 0 : nsresult rv = runnable->DispatchToMainThreadAndWait();
3018 0 : if (NS_FAILED(rv)) {
3019 0 : PR_SetError(SEC_ERROR_NO_MEMORY, 0);
3020 0 : return SECFailure;
3021 : }
3022 :
3023 0 : if (runnable->mRV != SECSuccess) {
3024 0 : PR_SetError(runnable->mErrorCodeToReport, 0);
3025 0 : } else if (*runnable->mPRetCert || *runnable->mPRetKey) {
3026 : // Make joinConnection prohibit joining after we've sent a client cert
3027 0 : info->SetSentClientCert();
3028 : }
3029 :
3030 0 : return runnable->mRV;
3031 : }
3032 :
3033 0 : void ClientAuthDataRunnable::RunOnTargetThread()
3034 : {
3035 0 : PRArenaPool* arena = NULL;
3036 : char** caNameStrings;
3037 0 : CERTCertificate* cert = NULL;
3038 0 : SECKEYPrivateKey* privKey = NULL;
3039 0 : CERTCertList* certList = NULL;
3040 : CERTCertListNode* node;
3041 0 : CERTCertNicknames* nicknames = NULL;
3042 0 : char* extracted = NULL;
3043 0 : PRIntn keyError = 0; /* used for private key retrieval error */
3044 : SSM_UserCertChoice certChoice;
3045 0 : PRInt32 NumberOfCerts = 0;
3046 0 : void * wincx = mSocketInfo;
3047 :
3048 : /* create caNameStrings */
3049 0 : arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
3050 0 : if (arena == NULL) {
3051 0 : goto loser;
3052 : }
3053 :
3054 : caNameStrings = (char**)PORT_ArenaAlloc(arena,
3055 0 : sizeof(char*)*(mCANames->nnames));
3056 0 : if (caNameStrings == NULL) {
3057 0 : goto loser;
3058 : }
3059 :
3060 0 : mRV = nsConvertCANamesToStrings(arena, caNameStrings, mCANames);
3061 0 : if (mRV != SECSuccess) {
3062 0 : goto loser;
3063 : }
3064 :
3065 : /* get the preference */
3066 0 : if (NS_FAILED(nsGetUserCertChoice(&certChoice))) {
3067 0 : goto loser;
3068 : }
3069 :
3070 : /* find valid user cert and key pair */
3071 0 : if (certChoice == AUTO) {
3072 : /* automatically find the right cert */
3073 :
3074 : /* find all user certs that are valid and for SSL */
3075 : certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(),
3076 : certUsageSSLClient, false,
3077 0 : true, wincx);
3078 0 : if (certList == NULL) {
3079 0 : goto noCert;
3080 : }
3081 :
3082 : /* filter the list to those issued by CAs supported by the server */
3083 : mRV = CERT_FilterCertListByCANames(certList, mCANames->nnames,
3084 0 : caNameStrings, certUsageSSLClient);
3085 0 : if (mRV != SECSuccess) {
3086 0 : goto noCert;
3087 : }
3088 :
3089 : /* make sure the list is not empty */
3090 0 : node = CERT_LIST_HEAD(certList);
3091 0 : if (CERT_LIST_END(node, certList)) {
3092 0 : goto noCert;
3093 : }
3094 :
3095 0 : CERTCertificate* low_prio_nonrep_cert = NULL;
3096 0 : CERTCertificateCleaner low_prio_cleaner(low_prio_nonrep_cert);
3097 :
3098 : /* loop through the list until we find a cert with a key */
3099 0 : while (!CERT_LIST_END(node, certList)) {
3100 : /* if the certificate has restriction and we do not satisfy it
3101 : * we do not use it
3102 : */
3103 : #if 0 /* XXX This must be re-enabled */
3104 : if (!CERT_MatchesScopeOfUse(node->cert, mSocketInfo->GetHostName,
3105 : info->GetHostIP, info->GetHostPort)) {
3106 : node = CERT_LIST_NEXT(node);
3107 : continue;
3108 : }
3109 : #endif
3110 :
3111 0 : privKey = PK11_FindKeyByAnyCert(node->cert, wincx);
3112 0 : if (privKey != NULL) {
3113 0 : if (hasExplicitKeyUsageNonRepudiation(node->cert)) {
3114 0 : SECKEY_DestroyPrivateKey(privKey);
3115 0 : privKey = NULL;
3116 : // Not a prefered cert
3117 0 : if (!low_prio_nonrep_cert) // did not yet find a low prio cert
3118 0 : low_prio_nonrep_cert = CERT_DupCertificate(node->cert);
3119 : }
3120 : else {
3121 : // this is a good cert to present
3122 0 : cert = CERT_DupCertificate(node->cert);
3123 0 : break;
3124 : }
3125 : }
3126 0 : keyError = PR_GetError();
3127 0 : if (keyError == SEC_ERROR_BAD_PASSWORD) {
3128 : /* problem with password: bail */
3129 : goto loser;
3130 : }
3131 :
3132 0 : node = CERT_LIST_NEXT(node);
3133 : }
3134 :
3135 0 : if (!cert && low_prio_nonrep_cert) {
3136 0 : cert = low_prio_nonrep_cert;
3137 0 : low_prio_nonrep_cert = NULL; // take it away from the cleaner
3138 0 : privKey = PK11_FindKeyByAnyCert(cert, wincx);
3139 : }
3140 :
3141 0 : if (cert == NULL) {
3142 : goto noCert;
3143 : }
3144 : }
3145 : else { // Not Auto => ask
3146 : /* Get the SSL Certificate */
3147 :
3148 0 : nsXPIDLCString hostname;
3149 0 : mSocketInfo->GetHostName(getter_Copies(hostname));
3150 :
3151 : nsresult rv;
3152 0 : NS_DEFINE_CID(nssComponentCID, NS_NSSCOMPONENT_CID);
3153 0 : nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(nssComponentCID, &rv));
3154 0 : nsRefPtr<nsClientAuthRememberService> cars;
3155 0 : if (nssComponent) {
3156 0 : nssComponent->GetClientAuthRememberService(getter_AddRefs(cars));
3157 : }
3158 :
3159 0 : bool hasRemembered = false;
3160 0 : nsCString rememberedDBKey;
3161 0 : if (cars) {
3162 : bool found;
3163 : nsresult rv = cars->HasRememberedDecision(hostname, mServerCert,
3164 0 : rememberedDBKey, &found);
3165 0 : if (NS_SUCCEEDED(rv) && found) {
3166 0 : hasRemembered = true;
3167 : }
3168 : }
3169 :
3170 0 : bool canceled = false;
3171 :
3172 0 : if (hasRemembered)
3173 : {
3174 0 : if (rememberedDBKey.IsEmpty())
3175 : {
3176 0 : canceled = true;
3177 : }
3178 : else
3179 : {
3180 0 : nsCOMPtr<nsIX509CertDB> certdb;
3181 0 : certdb = do_GetService(NS_X509CERTDB_CONTRACTID);
3182 0 : if (certdb)
3183 : {
3184 0 : nsCOMPtr<nsIX509Cert> found_cert;
3185 : nsresult find_rv =
3186 0 : certdb->FindCertByDBKey(rememberedDBKey.get(), nsnull,
3187 0 : getter_AddRefs(found_cert));
3188 0 : if (NS_SUCCEEDED(find_rv) && found_cert) {
3189 0 : nsNSSCertificate *obj_cert = reinterpret_cast<nsNSSCertificate *>(found_cert.get());
3190 0 : if (obj_cert) {
3191 0 : cert = obj_cert->GetCert();
3192 :
3193 : #ifdef DEBUG_kaie
3194 : nsAutoString nick, nickWithSerial, details;
3195 : if (NS_SUCCEEDED(obj_cert->FormatUIStrings(nick,
3196 : nickWithSerial,
3197 : details))) {
3198 : NS_LossyConvertUTF16toASCII asc(nickWithSerial);
3199 : fprintf(stderr, "====> remembered serial %s\n", asc.get());
3200 : }
3201 : #endif
3202 :
3203 : }
3204 : }
3205 :
3206 0 : if (!cert) {
3207 0 : hasRemembered = false;
3208 : }
3209 : }
3210 : }
3211 : }
3212 :
3213 0 : if (!hasRemembered)
3214 : {
3215 : /* user selects a cert to present */
3216 0 : nsIClientAuthDialogs *dialogs = NULL;
3217 0 : PRInt32 selectedIndex = -1;
3218 0 : PRUnichar **certNicknameList = NULL;
3219 0 : PRUnichar **certDetailsList = NULL;
3220 :
3221 : /* find all user certs that are for SSL */
3222 : /* note that we are allowing expired certs in this list */
3223 : certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(),
3224 : certUsageSSLClient, false,
3225 0 : false, wincx);
3226 0 : if (certList == NULL) {
3227 : goto noCert;
3228 : }
3229 :
3230 0 : if (mCANames->nnames != 0) {
3231 : /* filter the list to those issued by CAs supported by the
3232 : * server
3233 : */
3234 : mRV = CERT_FilterCertListByCANames(certList, mCANames->nnames,
3235 : caNameStrings,
3236 0 : certUsageSSLClient);
3237 0 : if (mRV != SECSuccess) {
3238 : goto loser;
3239 : }
3240 : }
3241 :
3242 0 : if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
3243 : /* list is empty - no matching certs */
3244 : goto noCert;
3245 : }
3246 :
3247 : /* filter it further for hostname restriction */
3248 0 : node = CERT_LIST_HEAD(certList);
3249 0 : while (!CERT_LIST_END(node, certList)) {
3250 0 : ++NumberOfCerts;
3251 : #if 0 /* XXX Fix this */
3252 : if (!CERT_MatchesScopeOfUse(node->cert, conn->hostName,
3253 : conn->hostIP, conn->port)) {
3254 : CERTCertListNode* removed = node;
3255 : node = CERT_LIST_NEXT(removed);
3256 : CERT_RemoveCertListNode(removed);
3257 : }
3258 : else {
3259 : node = CERT_LIST_NEXT(node);
3260 : }
3261 : #endif
3262 0 : node = CERT_LIST_NEXT(node);
3263 : }
3264 0 : if (CERT_LIST_END(CERT_LIST_HEAD(certList), certList)) {
3265 : goto noCert;
3266 : }
3267 :
3268 0 : nicknames = getNSSCertNicknamesFromCertList(certList);
3269 :
3270 0 : if (nicknames == NULL) {
3271 : goto loser;
3272 : }
3273 :
3274 0 : NS_ASSERTION(nicknames->numnicknames == NumberOfCerts, "nicknames->numnicknames != NumberOfCerts");
3275 :
3276 : /* Get CN and O of the subject and O of the issuer */
3277 0 : char *ccn = CERT_GetCommonName(&mServerCert->subject);
3278 0 : void *v = ccn;
3279 0 : voidCleaner ccnCleaner(v);
3280 0 : NS_ConvertUTF8toUTF16 cn(ccn);
3281 :
3282 : PRInt32 port;
3283 0 : mSocketInfo->GetPort(&port);
3284 :
3285 0 : nsString cn_host_port;
3286 0 : if (ccn && strcmp(ccn, hostname) == 0) {
3287 0 : cn_host_port.Append(cn);
3288 0 : cn_host_port.AppendLiteral(":");
3289 0 : cn_host_port.AppendInt(port);
3290 : }
3291 : else {
3292 0 : cn_host_port.Append(cn);
3293 0 : cn_host_port.AppendLiteral(" (");
3294 0 : cn_host_port.AppendLiteral(":");
3295 0 : cn_host_port.AppendInt(port);
3296 0 : cn_host_port.AppendLiteral(")");
3297 : }
3298 :
3299 0 : char *corg = CERT_GetOrgName(&mServerCert->subject);
3300 0 : NS_ConvertUTF8toUTF16 org(corg);
3301 0 : if (corg) PORT_Free(corg);
3302 :
3303 0 : char *cissuer = CERT_GetOrgName(&mServerCert->issuer);
3304 0 : NS_ConvertUTF8toUTF16 issuer(cissuer);
3305 0 : if (cissuer) PORT_Free(cissuer);
3306 :
3307 0 : certNicknameList = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nicknames->numnicknames);
3308 0 : if (!certNicknameList)
3309 : goto loser;
3310 0 : certDetailsList = (PRUnichar **)nsMemory::Alloc(sizeof(PRUnichar *) * nicknames->numnicknames);
3311 0 : if (!certDetailsList) {
3312 0 : nsMemory::Free(certNicknameList);
3313 : goto loser;
3314 : }
3315 :
3316 : PRInt32 CertsToUse;
3317 0 : for (CertsToUse = 0, node = CERT_LIST_HEAD(certList);
3318 0 : !CERT_LIST_END(node, certList) && CertsToUse < nicknames->numnicknames;
3319 : node = CERT_LIST_NEXT(node)
3320 : )
3321 : {
3322 0 : nsRefPtr<nsNSSCertificate> tempCert = nsNSSCertificate::Create(node->cert);
3323 :
3324 0 : if (!tempCert)
3325 0 : continue;
3326 :
3327 0 : NS_ConvertUTF8toUTF16 i_nickname(nicknames->nicknames[CertsToUse]);
3328 0 : nsAutoString nickWithSerial, details;
3329 :
3330 0 : if (NS_FAILED(tempCert->FormatUIStrings(i_nickname, nickWithSerial, details)))
3331 0 : continue;
3332 :
3333 0 : certNicknameList[CertsToUse] = ToNewUnicode(nickWithSerial);
3334 0 : if (!certNicknameList[CertsToUse])
3335 0 : continue;
3336 0 : certDetailsList[CertsToUse] = ToNewUnicode(details);
3337 0 : if (!certDetailsList[CertsToUse]) {
3338 0 : nsMemory::Free(certNicknameList[CertsToUse]);
3339 0 : continue;
3340 : }
3341 :
3342 0 : ++CertsToUse;
3343 : }
3344 :
3345 : /* Throw up the client auth dialog and get back the index of the selected cert */
3346 : rv = getNSSDialogs((void**)&dialogs,
3347 : NS_GET_IID(nsIClientAuthDialogs),
3348 0 : NS_CLIENTAUTHDIALOGS_CONTRACTID);
3349 :
3350 0 : if (NS_FAILED(rv)) {
3351 0 : NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
3352 0 : NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
3353 : goto loser;
3354 : }
3355 :
3356 : {
3357 0 : nsPSMUITracker tracker;
3358 0 : if (tracker.isUIForbidden()) {
3359 0 : rv = NS_ERROR_NOT_AVAILABLE;
3360 : }
3361 : else {
3362 : rv = dialogs->ChooseCertificate(mSocketInfo, cn_host_port.get(),
3363 : org.get(), issuer.get(),
3364 : (const PRUnichar**)certNicknameList,
3365 : (const PRUnichar**)certDetailsList,
3366 0 : CertsToUse, &selectedIndex, &canceled);
3367 : }
3368 : }
3369 :
3370 0 : NS_RELEASE(dialogs);
3371 0 : NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certNicknameList);
3372 0 : NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(CertsToUse, certDetailsList);
3373 :
3374 0 : if (NS_FAILED(rv)) goto loser;
3375 :
3376 : // even if the user has canceled, we want to remember that, to avoid repeating prompts
3377 0 : bool wantRemember = false;
3378 0 : mSocketInfo->GetRememberClientAuthCertificate(&wantRemember);
3379 :
3380 : int i;
3381 0 : if (!canceled)
3382 0 : for (i = 0, node = CERT_LIST_HEAD(certList);
3383 0 : !CERT_LIST_END(node, certList);
3384 : ++i, node = CERT_LIST_NEXT(node)) {
3385 :
3386 0 : if (i == selectedIndex) {
3387 0 : cert = CERT_DupCertificate(node->cert);
3388 0 : break;
3389 : }
3390 : }
3391 :
3392 0 : if (cars && wantRemember) {
3393 0 : cars->RememberDecision(hostname, mServerCert, canceled ? 0 : cert);
3394 : }
3395 : }
3396 :
3397 0 : if (canceled) { rv = NS_ERROR_NOT_AVAILABLE; goto loser; }
3398 :
3399 0 : if (cert == NULL) {
3400 : goto loser;
3401 : }
3402 :
3403 : /* go get the private key */
3404 0 : privKey = PK11_FindKeyByAnyCert(cert, wincx);
3405 0 : if (privKey == NULL) {
3406 0 : keyError = PR_GetError();
3407 0 : if (keyError == SEC_ERROR_BAD_PASSWORD) {
3408 : /* problem with password: bail */
3409 : goto loser;
3410 : }
3411 : else {
3412 : goto noCert;
3413 : }
3414 : }
3415 : }
3416 0 : goto done;
3417 :
3418 : noCert:
3419 : loser:
3420 0 : if (mRV == SECSuccess) {
3421 0 : mRV = SECFailure;
3422 : }
3423 0 : if (cert != NULL) {
3424 0 : CERT_DestroyCertificate(cert);
3425 0 : cert = NULL;
3426 : }
3427 : done:
3428 0 : int error = PR_GetError();
3429 :
3430 0 : if (extracted != NULL) {
3431 0 : PR_Free(extracted);
3432 : }
3433 0 : if (nicknames != NULL) {
3434 0 : CERT_FreeNicknames(nicknames);
3435 : }
3436 0 : if (certList != NULL) {
3437 0 : CERT_DestroyCertList(certList);
3438 : }
3439 0 : if (arena != NULL) {
3440 0 : PORT_FreeArena(arena, false);
3441 : }
3442 :
3443 0 : *mPRetCert = cert;
3444 0 : *mPRetKey = privKey;
3445 :
3446 0 : if (mRV == SECFailure) {
3447 0 : mErrorCodeToReport = error;
3448 : }
3449 0 : }
3450 :
3451 : void
3452 0 : nsNSSSocketInfo::SetStatusErrorBits(nsIX509Cert & cert,
3453 : PRUint32 collected_errors)
3454 : {
3455 0 : MutexAutoLock lock(mMutex);
3456 :
3457 0 : if (!mSSLStatus)
3458 0 : mSSLStatus = new nsSSLStatus();
3459 :
3460 0 : mSSLStatus->mServerCert = &cert;
3461 :
3462 0 : mSSLStatus->mHaveCertErrorBits = true;
3463 0 : mSSLStatus->mIsDomainMismatch =
3464 0 : collected_errors & nsICertOverrideService::ERROR_MISMATCH;
3465 0 : mSSLStatus->mIsNotValidAtThisTime =
3466 0 : collected_errors & nsICertOverrideService::ERROR_TIME;
3467 0 : mSSLStatus->mIsUntrusted =
3468 0 : collected_errors & nsICertOverrideService::ERROR_UNTRUSTED;
3469 :
3470 : nsSSLIOLayerHelpers::mHostsWithCertErrors->RememberCertHasError(
3471 0 : this, mSSLStatus, SECFailure);
3472 0 : }
3473 :
3474 : static PRFileDesc*
3475 4 : nsSSLIOLayerImportFD(PRFileDesc *fd,
3476 : nsNSSSocketInfo *infoObject,
3477 : const char *host,
3478 : bool anonymousLoad)
3479 : {
3480 8 : nsNSSShutDownPreventionLock locker;
3481 4 : PRFileDesc* sslSock = SSL_ImportFD(nsnull, fd);
3482 4 : if (!sslSock) {
3483 0 : NS_ASSERTION(false, "NSS: Error importing socket");
3484 0 : return nsnull;
3485 : }
3486 4 : SSL_SetPKCS11PinArg(sslSock, (nsIInterfaceRequestor*)infoObject);
3487 4 : SSL_HandshakeCallback(sslSock, HandshakeCallback, infoObject);
3488 :
3489 : // Disable this hook if we connect anonymously. See bug 466080.
3490 4 : if (anonymousLoad) {
3491 0 : SSL_GetClientAuthDataHook(sslSock, NULL, infoObject);
3492 : } else {
3493 : SSL_GetClientAuthDataHook(sslSock,
3494 : (SSLGetClientAuthData)nsNSS_SSLGetClientAuthData,
3495 4 : infoObject);
3496 : }
3497 4 : if (SECSuccess != SSL_AuthCertificateHook(sslSock, AuthCertificateHook,
3498 4 : infoObject)) {
3499 0 : NS_NOTREACHED("failed to configure AuthCertificateHook");
3500 0 : goto loser;
3501 : }
3502 :
3503 4 : if (SECSuccess != SSL_SetURL(sslSock, host)) {
3504 0 : NS_NOTREACHED("SSL_SetURL failed");
3505 0 : goto loser;
3506 : }
3507 4 : return sslSock;
3508 : loser:
3509 0 : if (sslSock) {
3510 0 : PR_Close(sslSock);
3511 : }
3512 0 : return nsnull;
3513 : }
3514 :
3515 : static nsresult
3516 4 : nsSSLIOLayerSetOptions(PRFileDesc *fd, bool forSTARTTLS,
3517 : const char *proxyHost, const char *host, PRInt32 port,
3518 : bool anonymousLoad, nsNSSSocketInfo *infoObject)
3519 : {
3520 8 : nsNSSShutDownPreventionLock locker;
3521 4 : if (forSTARTTLS || proxyHost) {
3522 0 : if (SECSuccess != SSL_OptionSet(fd, SSL_SECURITY, false)) {
3523 0 : return NS_ERROR_FAILURE;
3524 : }
3525 0 : infoObject->SetHasCleartextPhase(true);
3526 : }
3527 :
3528 : // Let's see if we're trying to connect to a site we know is
3529 : // TLS intolerant.
3530 8 : nsCAutoString key;
3531 4 : key = nsDependentCString(host) + NS_LITERAL_CSTRING(":") + nsPrintfCString("%d", port);
3532 :
3533 4 : if (nsSSLIOLayerHelpers::isKnownAsIntolerantSite(key)) {
3534 0 : if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_TLS, false))
3535 0 : return NS_ERROR_FAILURE;
3536 :
3537 0 : infoObject->SetAllowTLSIntoleranceTimeout(false);
3538 :
3539 : // We assume that protocols that use the STARTTLS mechanism should support
3540 : // modern hellos. For other protocols, if we suspect a site
3541 : // does not support TLS, let's also use V2 hellos.
3542 : // One advantage of this approach, if a site only supports the older
3543 : // hellos, it is more likely that we will get a reasonable error code
3544 : // on our single retry attempt.
3545 : }
3546 :
3547 : PRBool enabled;
3548 4 : if (SECSuccess != SSL_OptionGet(fd, SSL_ENABLE_SSL3, &enabled)) {
3549 0 : return NS_ERROR_FAILURE;
3550 : }
3551 4 : infoObject->SetSSL3Enabled(enabled);
3552 4 : if (SECSuccess != SSL_OptionGet(fd, SSL_ENABLE_TLS, &enabled)) {
3553 0 : return NS_ERROR_FAILURE;
3554 : }
3555 4 : infoObject->SetTLSEnabled(enabled);
3556 :
3557 4 : if (SECSuccess != SSL_OptionSet(fd, SSL_HANDSHAKE_AS_CLIENT, true)) {
3558 0 : return NS_ERROR_FAILURE;
3559 : }
3560 :
3561 4 : if (nsSSLIOLayerHelpers::isRenegoUnrestrictedSite(nsDependentCString(host))) {
3562 0 : if (SECSuccess != SSL_OptionSet(fd, SSL_REQUIRE_SAFE_NEGOTIATION, false)) {
3563 0 : return NS_ERROR_FAILURE;
3564 : }
3565 0 : if (SECSuccess != SSL_OptionSet(fd, SSL_ENABLE_RENEGOTIATION, SSL_RENEGOTIATE_UNRESTRICTED)) {
3566 0 : return NS_ERROR_FAILURE;
3567 : }
3568 : }
3569 :
3570 : // Set the Peer ID so that SSL proxy connections work properly.
3571 : char *peerId;
3572 4 : if (anonymousLoad) { // See bug #466080. Separate the caches.
3573 0 : peerId = PR_smprintf("anon:%s:%d", host, port);
3574 : } else {
3575 4 : peerId = PR_smprintf("%s:%d", host, port);
3576 : }
3577 :
3578 4 : if (SECSuccess != SSL_SetSockPeerID(fd, peerId)) {
3579 0 : PR_smprintf_free(peerId);
3580 0 : return NS_ERROR_FAILURE;
3581 : }
3582 :
3583 4 : PR_smprintf_free(peerId);
3584 4 : return NS_OK;
3585 : }
3586 :
3587 : nsresult
3588 4 : nsSSLIOLayerAddToSocket(PRInt32 family,
3589 : const char* host,
3590 : PRInt32 port,
3591 : const char* proxyHost,
3592 : PRInt32 proxyPort,
3593 : PRFileDesc* fd,
3594 : nsISupports** info,
3595 : bool forSTARTTLS,
3596 : bool anonymousLoad)
3597 : {
3598 8 : nsNSSShutDownPreventionLock locker;
3599 4 : PRFileDesc* layer = nsnull;
3600 : nsresult rv;
3601 :
3602 4 : nsNSSSocketInfo* infoObject = new nsNSSSocketInfo();
3603 4 : if (!infoObject) return NS_ERROR_FAILURE;
3604 :
3605 4 : NS_ADDREF(infoObject);
3606 4 : infoObject->SetForSTARTTLS(forSTARTTLS);
3607 4 : infoObject->SetHostName(host);
3608 4 : infoObject->SetPort(port);
3609 :
3610 4 : PRFileDesc *sslSock = nsSSLIOLayerImportFD(fd, infoObject, host, anonymousLoad);
3611 4 : if (!sslSock) {
3612 0 : NS_ASSERTION(false, "NSS: Error importing socket");
3613 0 : goto loser;
3614 : }
3615 :
3616 4 : infoObject->SetFileDescPtr(sslSock);
3617 :
3618 : rv = nsSSLIOLayerSetOptions(sslSock,
3619 : forSTARTTLS, proxyHost, host, port, anonymousLoad,
3620 4 : infoObject);
3621 :
3622 4 : if (NS_FAILED(rv))
3623 0 : goto loser;
3624 :
3625 : /* Now, layer ourselves on top of the SSL socket... */
3626 : layer = PR_CreateIOLayerStub(nsSSLIOLayerHelpers::nsSSLIOLayerIdentity,
3627 4 : &nsSSLIOLayerHelpers::nsSSLIOLayerMethods);
3628 4 : if (!layer)
3629 0 : goto loser;
3630 :
3631 4 : layer->secret = (PRFilePrivate*) infoObject;
3632 4 : rv = PR_PushIOLayer(sslSock, PR_GetLayersIdentity(sslSock), layer);
3633 :
3634 4 : if (NS_FAILED(rv)) {
3635 0 : goto loser;
3636 : }
3637 :
3638 4 : nsNSSShutDownList::trackSSLSocketCreate();
3639 :
3640 4 : PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("[%p] Socket set up\n", (void*)sslSock));
3641 4 : infoObject->QueryInterface(NS_GET_IID(nsISupports), (void**) (info));
3642 :
3643 : // We are going use a clear connection first //
3644 4 : if (forSTARTTLS || proxyHost) {
3645 0 : infoObject->SetHandshakePending(false);
3646 : }
3647 :
3648 4 : return NS_OK;
3649 : loser:
3650 0 : NS_IF_RELEASE(infoObject);
3651 0 : if (layer) {
3652 0 : layer->dtor(layer);
3653 : }
3654 0 : return NS_ERROR_FAILURE;
3655 : }
|