1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  *
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "TransportSecurityInfo.h"
8 
9 #include "DateTimeFormat.h"
10 #include "PSMRunnable.h"
11 #include "ipc/IPCMessageUtils.h"
12 #include "mozilla/Casting.h"
13 #include "nsComponentManagerUtils.h"
14 #include "nsICertOverrideService.h"
15 #include "nsIObjectInputStream.h"
16 #include "nsIObjectOutputStream.h"
17 #include "nsIWebProgressListener.h"
18 #include "nsNSSCertHelper.h"
19 #include "nsNSSCertificate.h"
20 #include "nsNSSComponent.h"
21 #include "nsNSSHelper.h"
22 #include "nsReadableUtils.h"
23 #include "nsServiceManagerUtils.h"
24 #include "nsXULAppAPI.h"
25 #include "mozpkix/pkixtypes.h"
26 #include "secerr.h"
27 #include "ssl.h"
28 
29 //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal
30 // reports when doing SSL read/write
31 
32 //#define DUMP_BUFFER  //Enable this define along with
33 // DEBUG_SSL_VERBOSE to dump SSL
34 // read/write buffer to a log.
35 // Uses PR_LOG except on Mac where
36 // we always write out to our own
37 // file.
38 
39 namespace mozilla {
40 namespace psm {
41 
TransportSecurityInfo()42 TransportSecurityInfo::TransportSecurityInfo()
43     : mCipherSuite(0),
44       mProtocolVersion(0),
45       mCertificateTransparencyStatus(
46           nsITransportSecurityInfo::CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE),
47       mKeaGroup(),
48       mSignatureSchemeName(),
49       mIsAcceptedEch(false),
50       mIsDelegatedCredential(false),
51       mIsDomainMismatch(false),
52       mIsNotValidAtThisTime(false),
53       mIsUntrusted(false),
54       mIsEV(false),
55       mHasIsEVStatus(false),
56       mHaveCipherSuiteAndProtocol(false),
57       mHaveCertErrorBits(false),
58       mCanceled(false),
59       mMutex("TransportSecurityInfo::mMutex"),
60       mNPNCompleted(false),
61       mResumed(false),
62       mIsBuiltCertChainRootBuiltInRoot(false),
63       mSecurityState(nsIWebProgressListener::STATE_IS_INSECURE),
64       mErrorCode(0),
65       mPort(0) {}
66 
NS_IMPL_ISUPPORTS(TransportSecurityInfo,nsITransportSecurityInfo,nsIInterfaceRequestor,nsISerializable,nsIClassInfo)67 NS_IMPL_ISUPPORTS(TransportSecurityInfo, nsITransportSecurityInfo,
68                   nsIInterfaceRequestor, nsISerializable, nsIClassInfo)
69 
70 void TransportSecurityInfo::SetHostName(const char* host) {
71   MutexAutoLock lock(mMutex);
72 
73   mHostName.Assign(host);
74 }
75 
SetPort(int32_t aPort)76 void TransportSecurityInfo::SetPort(int32_t aPort) { mPort = aPort; }
77 
SetOriginAttributes(const OriginAttributes & aOriginAttributes)78 void TransportSecurityInfo::SetOriginAttributes(
79     const OriginAttributes& aOriginAttributes) {
80   MutexAutoLock lock(mMutex);
81 
82   mOriginAttributes = aOriginAttributes;
83 }
84 
85 // NB: GetErrorCode may be called before an error code is set (if ever). In that
86 // case, this returns (by pointer) 0, which is treated as a successful value.
87 NS_IMETHODIMP
GetErrorCode(int32_t * state)88 TransportSecurityInfo::GetErrorCode(int32_t* state) {
89   // We're in an inconsistent state if we think we've been canceled but no error
90   // code was set or we haven't been canceled but an error code was set.
91   MOZ_ASSERT(
92       !((mCanceled && mErrorCode == 0) || (!mCanceled && mErrorCode != 0)));
93   if ((mCanceled && mErrorCode == 0) || (!mCanceled && mErrorCode != 0)) {
94     mCanceled = true;
95     mErrorCode = SEC_ERROR_LIBRARY_FAILURE;
96   }
97 
98   *state = mErrorCode;
99   return NS_OK;
100 }
101 
SetCanceled(PRErrorCode errorCode)102 void TransportSecurityInfo::SetCanceled(PRErrorCode errorCode) {
103   MOZ_ASSERT(errorCode != 0);
104   if (errorCode == 0) {
105     errorCode = SEC_ERROR_LIBRARY_FAILURE;
106   }
107 
108   mErrorCode = errorCode;
109   mCanceled = true;
110 }
111 
IsCanceled()112 bool TransportSecurityInfo::IsCanceled() { return mCanceled; }
113 
114 NS_IMETHODIMP
GetSecurityState(uint32_t * state)115 TransportSecurityInfo::GetSecurityState(uint32_t* state) {
116   *state = mSecurityState;
117   return NS_OK;
118 }
119 
SetSecurityState(uint32_t aState)120 void TransportSecurityInfo::SetSecurityState(uint32_t aState) {
121   mSecurityState = aState;
122 }
123 
124 NS_IMETHODIMP
GetErrorCodeString(nsAString & aErrorString)125 TransportSecurityInfo::GetErrorCodeString(nsAString& aErrorString) {
126   const char* codeName = PR_ErrorToName(mErrorCode);
127   aErrorString.Truncate();
128   if (codeName) {
129     aErrorString = NS_ConvertASCIItoUTF16(codeName);
130   }
131 
132   return NS_OK;
133 }
134 
135 NS_IMETHODIMP
GetInterface(const nsIID & uuid,void ** result)136 TransportSecurityInfo::GetInterface(const nsIID& uuid, void** result) {
137   if (!NS_IsMainThread()) {
138     NS_ERROR("nsNSSSocketInfo::GetInterface called off the main thread");
139     return NS_ERROR_NOT_SAME_THREAD;
140   }
141   MutexAutoLock lock(mMutex);
142 
143   nsresult rv;
144   if (!mCallbacks) {
145     nsCOMPtr<nsIInterfaceRequestor> ir = new PipUIContext();
146     rv = ir->GetInterface(uuid, result);
147   } else {
148     rv = mCallbacks->GetInterface(uuid, result);
149   }
150   return rv;
151 }
152 
153 // This is a new magic value. However, it re-uses the first 4 bytes
154 // of the previous value. This is so when older versions attempt to
155 // read a newer serialized TransportSecurityInfo, they will actually
156 // fail and return NS_ERROR_FAILURE instead of silently failing.
157 #define TRANSPORTSECURITYINFOMAGIC                   \
158   {                                                  \
159     0xa9863a23, 0x1faa, 0x4169, {                    \
160       0xb0, 0xd2, 0x81, 0x29, 0xec, 0x7c, 0xb1, 0xde \
161     }                                                \
162   }
163 static NS_DEFINE_CID(kTransportSecurityInfoMagic, TRANSPORTSECURITYINFOMAGIC);
164 
165 // NB: Any updates (except disk-only fields) must be kept in sync with
166 //     |SerializeToIPC|.
167 NS_IMETHODIMP
Write(nsIObjectOutputStream * aStream)168 TransportSecurityInfo::Write(nsIObjectOutputStream* aStream) {
169   nsresult rv = aStream->WriteID(kTransportSecurityInfoMagic);
170   if (NS_FAILED(rv)) {
171     return rv;
172   }
173 
174   MutexAutoLock lock(mMutex);
175 
176   rv = aStream->Write32(mSecurityState);
177   if (NS_FAILED(rv)) {
178     return rv;
179   }
180   // mSubRequestsBrokenSecurity was removed in bug 748809
181   rv = aStream->Write32(0);
182   if (NS_FAILED(rv)) {
183     return rv;
184   }
185   // mSubRequestsNoSecurity was removed in bug 748809
186   rv = aStream->Write32(0);
187   if (NS_FAILED(rv)) {
188     return rv;
189   }
190   rv = aStream->Write32(static_cast<uint32_t>(mErrorCode));
191   if (NS_FAILED(rv)) {
192     return rv;
193   }
194 
195   // Re-purpose mErrorMessageCached to represent serialization version
196   // If string doesn't match exact version it will be treated as older
197   // serialization.
198   rv = aStream->WriteWStringZ(NS_ConvertUTF8toUTF16("6").get());
199   if (NS_FAILED(rv)) {
200     return rv;
201   }
202 
203   // moved from nsISSLStatus
204   rv = NS_WriteOptionalCompoundObject(aStream, mServerCert,
205                                       NS_GET_IID(nsIX509Cert), true);
206   NS_ENSURE_SUCCESS(rv, rv);
207 
208   rv = aStream->Write16(mCipherSuite);
209   NS_ENSURE_SUCCESS(rv, rv);
210 
211   rv = aStream->Write16(mProtocolVersion);
212   NS_ENSURE_SUCCESS(rv, rv);
213 
214   rv = aStream->WriteBoolean(mIsDomainMismatch);
215   NS_ENSURE_SUCCESS(rv, rv);
216   rv = aStream->WriteBoolean(mIsNotValidAtThisTime);
217   NS_ENSURE_SUCCESS(rv, rv);
218   rv = aStream->WriteBoolean(mIsUntrusted);
219   NS_ENSURE_SUCCESS(rv, rv);
220   rv = aStream->WriteBoolean(mIsEV);
221   NS_ENSURE_SUCCESS(rv, rv);
222 
223   rv = aStream->WriteBoolean(mHasIsEVStatus);
224   NS_ENSURE_SUCCESS(rv, rv);
225   rv = aStream->WriteBoolean(mHaveCipherSuiteAndProtocol);
226   NS_ENSURE_SUCCESS(rv, rv);
227   rv = aStream->WriteBoolean(mHaveCertErrorBits);
228   NS_ENSURE_SUCCESS(rv, rv);
229 
230   rv = aStream->Write16(mCertificateTransparencyStatus);
231   NS_ENSURE_SUCCESS(rv, rv);
232 
233   rv = aStream->WriteStringZ(mKeaGroup.get());
234   NS_ENSURE_SUCCESS(rv, rv);
235 
236   rv = aStream->WriteStringZ(mSignatureSchemeName.get());
237   NS_ENSURE_SUCCESS(rv, rv);
238 
239   rv = aStream->Write16(mSucceededCertChain.Length());
240   NS_ENSURE_SUCCESS(rv, rv);
241 
242   for (const auto& cert : mSucceededCertChain) {
243     rv = aStream->WriteCompoundObject(cert, NS_GET_IID(nsIX509Cert), true);
244     NS_ENSURE_SUCCESS(rv, rv);
245   }
246   // END moved from nsISSLStatus
247   rv = aStream->Write16(mFailedCertChain.Length());
248   NS_ENSURE_SUCCESS(rv, rv);
249   for (const auto& cert : mFailedCertChain) {
250     rv = aStream->WriteCompoundObject(cert, NS_GET_IID(nsIX509Cert), true);
251     NS_ENSURE_SUCCESS(rv, rv);
252   }
253 
254   rv = aStream->WriteBoolean(mIsDelegatedCredential);
255   if (NS_FAILED(rv)) {
256     return rv;
257   }
258 
259   rv = aStream->WriteBoolean(mNPNCompleted);
260   if (NS_FAILED(rv)) {
261     return rv;
262   }
263 
264   rv = aStream->WriteStringZ(mNegotiatedNPN.get());
265   if (NS_FAILED(rv)) {
266     return rv;
267   }
268 
269   rv = aStream->WriteBoolean(mResumed);
270   if (NS_FAILED(rv)) {
271     return rv;
272   }
273 
274   rv = aStream->WriteBoolean(mIsBuiltCertChainRootBuiltInRoot);
275   if (NS_FAILED(rv)) {
276     return rv;
277   }
278 
279   rv = aStream->WriteBoolean(mIsAcceptedEch);
280   if (NS_FAILED(rv)) {
281     return rv;
282   }
283 
284   return NS_OK;
285 }
286 
287 #define CHILD_DIAGNOSTIC_ASSERT(condition, message)       \
288   if (XRE_GetProcessType() == GeckoProcessType_Content) { \
289     MOZ_DIAGNOSTIC_ASSERT(condition, message);            \
290   }
291 
292 // This is for backward compatibility to be able to read nsISSLStatus
293 // serialized object.
ReadSSLStatus(nsIObjectInputStream * aStream,MutexAutoLock & aProofOfLock)294 nsresult TransportSecurityInfo::ReadSSLStatus(nsIObjectInputStream* aStream,
295                                               MutexAutoLock& aProofOfLock) {
296   bool nsISSLStatusPresent;
297   nsresult rv = aStream->ReadBoolean(&nsISSLStatusPresent);
298   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
299   NS_ENSURE_SUCCESS(rv, rv);
300   if (!nsISSLStatusPresent) {
301     return NS_OK;
302   }
303   // nsISSLStatus present.  Prepare to read elements.
304   // Throw away cid, validate iid
305   nsCID cid;
306   nsIID iid;
307   rv = aStream->ReadID(&cid);
308   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
309   NS_ENSURE_SUCCESS(rv, rv);
310   rv = aStream->ReadID(&iid);
311   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
312   NS_ENSURE_SUCCESS(rv, rv);
313 
314   static const nsIID nsSSLStatusIID = {
315       0xfa9ba95b,
316       0xca3b,
317       0x498a,
318       {0xb8, 0x89, 0x7c, 0x79, 0xcf, 0x28, 0xfe, 0xe8}};
319   if (!iid.Equals(nsSSLStatusIID)) {
320     CHILD_DIAGNOSTIC_ASSERT(false, "Deserialization should not fail");
321     return NS_ERROR_UNEXPECTED;
322   }
323 
324   nsCOMPtr<nsISupports> cert;
325   rv = aStream->ReadObject(true, getter_AddRefs(cert));
326   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
327   NS_ENSURE_SUCCESS(rv, rv);
328 
329   if (cert) {
330     mServerCert = do_QueryInterface(cert);
331     if (!mServerCert) {
332       CHILD_DIAGNOSTIC_ASSERT(false, "Deserialization should not fail");
333       return NS_NOINTERFACE;
334     }
335   }
336 
337   rv = aStream->Read16(&mCipherSuite);
338   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
339   NS_ENSURE_SUCCESS(rv, rv);
340 
341   // The code below is a workaround to allow serializing new fields
342   // while preserving binary compatibility with older streams. For more details
343   // on the binary compatibility requirement, refer to bug 1248628.
344   // Here, we take advantage of the fact that mProtocolVersion was originally
345   // stored as a 16 bits integer, but the highest 8 bits were never used.
346   // These bits are now used for stream versioning.
347   uint16_t protocolVersionAndStreamFormatVersion;
348   rv = aStream->Read16(&protocolVersionAndStreamFormatVersion);
349   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
350   NS_ENSURE_SUCCESS(rv, rv);
351   mProtocolVersion = protocolVersionAndStreamFormatVersion & 0xFF;
352   const uint8_t streamFormatVersion =
353       (protocolVersionAndStreamFormatVersion >> 8) & 0xFF;
354 
355   rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsDomainMismatch);
356   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
357   NS_ENSURE_SUCCESS(rv, rv);
358   rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsNotValidAtThisTime);
359   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
360   NS_ENSURE_SUCCESS(rv, rv);
361   rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsUntrusted);
362   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
363   NS_ENSURE_SUCCESS(rv, rv);
364   rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsEV);
365   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
366   NS_ENSURE_SUCCESS(rv, rv);
367 
368   rv = ReadBoolAndSetAtomicFieldHelper(aStream, mHasIsEVStatus);
369   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
370   NS_ENSURE_SUCCESS(rv, rv);
371   rv = ReadBoolAndSetAtomicFieldHelper(aStream, mHaveCipherSuiteAndProtocol);
372   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
373   NS_ENSURE_SUCCESS(rv, rv);
374   rv = ReadBoolAndSetAtomicFieldHelper(aStream, mHaveCertErrorBits);
375   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
376   NS_ENSURE_SUCCESS(rv, rv);
377 
378   // Added in version 1 (see bug 1305289).
379   if (streamFormatVersion >= 1) {
380     rv = aStream->Read16(&mCertificateTransparencyStatus);
381     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
382                             "Deserialization should not fail");
383     NS_ENSURE_SUCCESS(rv, rv);
384   }
385 
386   // Added in version 2 (see bug 1304923).
387   if (streamFormatVersion >= 2) {
388     rv = aStream->ReadCString(mKeaGroup);
389     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
390                             "Deserialization should not fail");
391     NS_ENSURE_SUCCESS(rv, rv);
392 
393     rv = aStream->ReadCString(mSignatureSchemeName);
394     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
395                             "Deserialization should not fail");
396     NS_ENSURE_SUCCESS(rv, rv);
397   }
398 
399   // Added in version 3 (see bug 1406856).
400   if (streamFormatVersion >= 3) {
401     rv = ReadCertList(aStream, mSucceededCertChain, aProofOfLock);
402     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
403                             "Deserialization should not fail");
404     if (NS_FAILED(rv)) {
405       return rv;
406     }
407 
408     // Read only to consume bytes from the stream.
409     nsTArray<RefPtr<nsIX509Cert>> failedCertChain;
410     rv = ReadCertList(aStream, failedCertChain, aProofOfLock);
411     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
412                             "Deserialization should not fail");
413     if (NS_FAILED(rv)) {
414       return rv;
415     }
416   }
417   return rv;
418 }
419 
420 // This is for backward compatability to be able to read nsIX509CertList
421 // serialized object.
ReadCertList(nsIObjectInputStream * aStream,nsTArray<RefPtr<nsIX509Cert>> & aCertList,MutexAutoLock & aProofOfLock)422 nsresult TransportSecurityInfo::ReadCertList(
423     nsIObjectInputStream* aStream, nsTArray<RefPtr<nsIX509Cert>>& aCertList,
424     MutexAutoLock& aProofOfLock) {
425   bool nsIX509CertListPresent;
426 
427   nsresult rv = aStream->ReadBoolean(&nsIX509CertListPresent);
428   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
429   NS_ENSURE_SUCCESS(rv, rv);
430   if (!nsIX509CertListPresent) {
431     return NS_OK;
432   }
433   // nsIX509CertList present.  Prepare to read elements.
434   // Throw away cid, validate iid
435   nsCID cid;
436   nsIID iid;
437   rv = aStream->ReadID(&cid);
438   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
439   NS_ENSURE_SUCCESS(rv, rv);
440   rv = aStream->ReadID(&iid);
441   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
442   NS_ENSURE_SUCCESS(rv, rv);
443 
444   static const nsIID nsIX509CertListIID = {
445       0xae74cda5,
446       0xcd2f,
447       0x473f,
448       {0x96, 0xf5, 0xf0, 0xb7, 0xff, 0xf6, 0x2c, 0x68}};
449 
450   if (!iid.Equals(nsIX509CertListIID)) {
451     CHILD_DIAGNOSTIC_ASSERT(false, "Deserialization should not fail");
452     return NS_ERROR_UNEXPECTED;
453   }
454 
455   uint32_t certListSize;
456   rv = aStream->Read32(&certListSize);
457   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
458   NS_ENSURE_SUCCESS(rv, rv);
459 
460   return ReadCertificatesFromStream(aStream, certListSize, aCertList,
461                                     aProofOfLock);
462 }
463 
ReadCertificatesFromStream(nsIObjectInputStream * aStream,uint32_t aSize,nsTArray<RefPtr<nsIX509Cert>> & aCertList,MutexAutoLock & aProofOfLock)464 nsresult TransportSecurityInfo::ReadCertificatesFromStream(
465     nsIObjectInputStream* aStream, uint32_t aSize,
466     nsTArray<RefPtr<nsIX509Cert>>& aCertList, MutexAutoLock& aProofOfLock) {
467   nsresult rv;
468   for (uint32_t i = 0; i < aSize; ++i) {
469     nsCOMPtr<nsISupports> support;
470     rv = aStream->ReadObject(true, getter_AddRefs(support));
471     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
472                             "Deserialization should not fail");
473     NS_ENSURE_SUCCESS(rv, rv);
474     nsCOMPtr<nsIX509Cert> cert = do_QueryInterface(support);
475     if (!cert) {
476       return NS_ERROR_UNEXPECTED;
477     }
478     RefPtr<nsIX509Cert> castedCert(cert.get());
479     aCertList.AppendElement(castedCert);
480   }
481   return NS_OK;
482 }
483 
484 // NB: Any updates (except disk-only fields) must be kept in sync with
485 //     |DeserializeFromIPC|.
486 NS_IMETHODIMP
Read(nsIObjectInputStream * aStream)487 TransportSecurityInfo::Read(nsIObjectInputStream* aStream) {
488   nsID id;
489   nsresult rv = aStream->ReadID(&id);
490   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
491   if (NS_FAILED(rv)) {
492     return rv;
493   }
494   if (!id.Equals(kTransportSecurityInfoMagic)) {
495     CHILD_DIAGNOSTIC_ASSERT(false, "Deserialization should not fail");
496     return NS_ERROR_UNEXPECTED;
497   }
498 
499   MutexAutoLock lock(mMutex);
500 
501   rv = ReadUint32AndSetAtomicFieldHelper(aStream, mSecurityState);
502   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
503   if (NS_FAILED(rv)) {
504     return rv;
505   }
506   // mSubRequestsBrokenSecurity was removed in bug 748809
507   uint32_t unusedSubRequestsBrokenSecurity;
508   rv = aStream->Read32(&unusedSubRequestsBrokenSecurity);
509   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
510   if (NS_FAILED(rv)) {
511     return rv;
512   }
513   // mSubRequestsNoSecurity was removed in bug 748809
514   uint32_t unusedSubRequestsNoSecurity;
515   rv = aStream->Read32(&unusedSubRequestsNoSecurity);
516   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
517   if (NS_FAILED(rv)) {
518     return rv;
519   }
520   uint32_t errorCode;
521   rv = aStream->Read32(&errorCode);
522   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
523   if (NS_FAILED(rv)) {
524     return rv;
525   }
526   // PRErrorCode will be a negative value
527   mErrorCode = static_cast<PRErrorCode>(errorCode);
528   // If mErrorCode is non-zero, SetCanceled was called on the
529   // TransportSecurityInfo that was serialized.
530   if (mErrorCode != 0) {
531     mCanceled = true;
532   }
533 
534   // Re-purpose mErrorMessageCached to represent serialization version
535   // If string doesn't match exact version it will be treated as older
536   // serialization.
537   nsAutoString serVersion;
538   rv = aStream->ReadString(serVersion);
539   CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv), "Deserialization should not fail");
540   if (NS_FAILED(rv)) {
541     return rv;
542   }
543 
544   int32_t serVersionParsedToInt = 0;
545 
546   if (!serVersion.IsEmpty()) {
547     char first = serVersion.First();
548     // Check whether the first character of serVersion is a number
549     // since ToInteger() skipps some non integer values.
550     if (first >= '0' && first <= '9') {
551       nsresult error = NS_OK;
552       serVersionParsedToInt = serVersion.ToInteger(&error);
553       if (NS_FAILED(error)) {
554         return error;
555       }
556     }
557   }
558 
559   // moved from nsISSLStatus
560   if (serVersionParsedToInt < 1) {
561     // nsISSLStatus may be present
562     rv = ReadSSLStatus(aStream, lock);
563     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
564                             "Deserialization should not fail");
565     NS_ENSURE_SUCCESS(rv, rv);
566   } else {
567     nsCOMPtr<nsISupports> cert;
568     rv = NS_ReadOptionalObject(aStream, true, getter_AddRefs(cert));
569     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
570                             "Deserialization should not fail");
571     NS_ENSURE_SUCCESS(rv, rv);
572 
573     if (cert != nullptr) {
574       mServerCert = do_QueryInterface(cert);
575       if (!mServerCert) {
576         CHILD_DIAGNOSTIC_ASSERT(false, "Deserialization should not fail");
577         return NS_NOINTERFACE;
578       }
579     }
580 
581     rv = aStream->Read16(&mCipherSuite);
582     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
583                             "Deserialization should not fail");
584     NS_ENSURE_SUCCESS(rv, rv);
585 
586     rv = aStream->Read16(&mProtocolVersion);
587     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
588                             "Deserialization should not fail");
589     NS_ENSURE_SUCCESS(rv, rv);
590 
591     rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsDomainMismatch);
592     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
593                             "Deserialization should not fail");
594     NS_ENSURE_SUCCESS(rv, rv);
595     rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsNotValidAtThisTime);
596     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
597                             "Deserialization should not fail");
598     NS_ENSURE_SUCCESS(rv, rv);
599     rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsUntrusted);
600     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
601                             "Deserialization should not fail");
602     NS_ENSURE_SUCCESS(rv, rv);
603     rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsEV);
604     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
605                             "Deserialization should not fail");
606     NS_ENSURE_SUCCESS(rv, rv);
607 
608     rv = ReadBoolAndSetAtomicFieldHelper(aStream, mHasIsEVStatus);
609     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
610                             "Deserialization should not fail");
611     NS_ENSURE_SUCCESS(rv, rv);
612     rv = ReadBoolAndSetAtomicFieldHelper(aStream, mHaveCipherSuiteAndProtocol);
613     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
614                             "Deserialization should not fail");
615     NS_ENSURE_SUCCESS(rv, rv);
616     rv = ReadBoolAndSetAtomicFieldHelper(aStream, mHaveCertErrorBits);
617     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
618                             "Deserialization should not fail");
619     NS_ENSURE_SUCCESS(rv, rv);
620 
621     rv = aStream->Read16(&mCertificateTransparencyStatus);
622     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
623                             "Deserialization should not fail");
624     NS_ENSURE_SUCCESS(rv, rv);
625 
626     rv = aStream->ReadCString(mKeaGroup);
627     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
628                             "Deserialization should not fail");
629     NS_ENSURE_SUCCESS(rv, rv);
630 
631     rv = aStream->ReadCString(mSignatureSchemeName);
632     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
633                             "Deserialization should not fail");
634     NS_ENSURE_SUCCESS(rv, rv);
635 
636     if (serVersionParsedToInt < 3) {
637       // The old data structure of certList(nsIX509CertList) presents
638       rv = ReadCertList(aStream, mSucceededCertChain, lock);
639       CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
640                               "Deserialization should not fail");
641       NS_ENSURE_SUCCESS(rv, rv);
642     } else {
643       uint16_t certCount;
644       rv = aStream->Read16(&certCount);
645       CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
646                               "Deserialization should not fail");
647       NS_ENSURE_SUCCESS(rv, rv);
648 
649       rv = ReadCertificatesFromStream(aStream, certCount, mSucceededCertChain,
650                                       lock);
651       NS_ENSURE_SUCCESS(rv, rv);
652     }
653   }
654   // END moved from nsISSLStatus
655   if (serVersionParsedToInt < 3) {
656     // The old data structure of certList(nsIX509CertList) presents
657     rv = ReadCertList(aStream, mFailedCertChain, lock);
658     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
659                             "Deserialization should not fail");
660     NS_ENSURE_SUCCESS(rv, rv);
661   } else {
662     uint16_t certCount;
663     rv = aStream->Read16(&certCount);
664     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
665                             "Deserialization should not fail");
666     NS_ENSURE_SUCCESS(rv, rv);
667 
668     rv = ReadCertificatesFromStream(aStream, certCount, mFailedCertChain, lock);
669     NS_ENSURE_SUCCESS(rv, rv);
670   }
671 
672   // mIsDelegatedCredential added in bug 1562773
673   if (serVersionParsedToInt >= 2) {
674     rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsDelegatedCredential);
675     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
676                             "Deserialization should not fail");
677     if (NS_FAILED(rv)) {
678       return rv;
679     }
680   }
681 
682   // mNPNCompleted, mNegotiatedNPN, mResumed added in bug 1584104
683   if (serVersionParsedToInt >= 4) {
684     rv = ReadBoolAndSetAtomicFieldHelper(aStream, mNPNCompleted);
685     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
686                             "Deserialization should not fail");
687     if (NS_FAILED(rv)) {
688       return rv;
689     }
690 
691     rv = aStream->ReadCString(mNegotiatedNPN);
692     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
693                             "Deserialization should not fail");
694     if (NS_FAILED(rv)) {
695       return rv;
696     }
697 
698     rv = ReadBoolAndSetAtomicFieldHelper(aStream, mResumed);
699     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
700                             "Deserialization should not fail");
701     if (NS_FAILED(rv)) {
702       return rv;
703     }
704   }
705 
706   // mIsBuiltCertChainRootBuiltInRoot added in bug 1485652
707   if (serVersionParsedToInt >= 5) {
708     rv = ReadBoolAndSetAtomicFieldHelper(aStream,
709                                          mIsBuiltCertChainRootBuiltInRoot);
710     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
711                             "Deserialization should not fail");
712     if (NS_FAILED(rv)) {
713       return rv;
714     }
715   }
716 
717   // mIsAcceptedEch added in bug 1678079
718   if (serVersionParsedToInt >= 6) {
719     rv = ReadBoolAndSetAtomicFieldHelper(aStream, mIsAcceptedEch);
720     CHILD_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv),
721                             "Deserialization should not fail");
722     if (NS_FAILED(rv)) {
723       return rv;
724     }
725   }
726 
727   return NS_OK;
728 }
729 
730 #undef CHILD_DIAGNOSTIC_ASSERT
731 
SerializeToIPC(IPC::Message * aMsg)732 void TransportSecurityInfo::SerializeToIPC(IPC::Message* aMsg) {
733   MutexAutoLock guard(mMutex);
734 
735   int32_t errorCode = static_cast<int32_t>(mErrorCode);
736 
737   WriteParam(aMsg, static_cast<uint32_t>(mSecurityState));
738   WriteParam(aMsg, errorCode);
739   WriteParam(aMsg, mServerCert);
740   WriteParam(aMsg, mCipherSuite);
741   WriteParam(aMsg, mProtocolVersion);
742   WriteParam(aMsg, static_cast<bool>(mIsDomainMismatch));
743   WriteParam(aMsg, static_cast<bool>(mIsNotValidAtThisTime));
744   WriteParam(aMsg, static_cast<bool>(mIsUntrusted));
745   WriteParam(aMsg, static_cast<bool>(mIsEV));
746   WriteParam(aMsg, static_cast<bool>(mHasIsEVStatus));
747   WriteParam(aMsg, static_cast<bool>(mHaveCipherSuiteAndProtocol));
748   WriteParam(aMsg, static_cast<bool>(mHaveCertErrorBits));
749   WriteParam(aMsg, mCertificateTransparencyStatus);
750   WriteParam(aMsg, mKeaGroup);
751   WriteParam(aMsg, mSignatureSchemeName);
752   WriteParam(aMsg, mSucceededCertChain);
753   WriteParam(aMsg, mFailedCertChain);
754   WriteParam(aMsg, static_cast<bool>(mIsDelegatedCredential));
755   WriteParam(aMsg, static_cast<bool>(mNPNCompleted));
756   WriteParam(aMsg, mNegotiatedNPN);
757   WriteParam(aMsg, static_cast<bool>(mResumed));
758   WriteParam(aMsg, static_cast<bool>(mIsBuiltCertChainRootBuiltInRoot));
759   WriteParam(aMsg, static_cast<bool>(mIsAcceptedEch));
760 }
761 
DeserializeFromIPC(const IPC::Message * aMsg,PickleIterator * aIter)762 bool TransportSecurityInfo::DeserializeFromIPC(const IPC::Message* aMsg,
763                                                PickleIterator* aIter) {
764   MutexAutoLock guard(mMutex);
765 
766   int32_t errorCode = 0;
767 
768   if (!ReadParamAtomicHelper(aMsg, aIter, mSecurityState) ||
769       !ReadParam(aMsg, aIter, &errorCode) ||
770       !ReadParam(aMsg, aIter, &mServerCert) ||
771       !ReadParam(aMsg, aIter, &mCipherSuite) ||
772       !ReadParam(aMsg, aIter, &mProtocolVersion) ||
773       !ReadParamAtomicHelper(aMsg, aIter, mIsDomainMismatch) ||
774       !ReadParamAtomicHelper(aMsg, aIter, mIsNotValidAtThisTime) ||
775       !ReadParamAtomicHelper(aMsg, aIter, mIsUntrusted) ||
776       !ReadParamAtomicHelper(aMsg, aIter, mIsEV) ||
777       !ReadParamAtomicHelper(aMsg, aIter, mHasIsEVStatus) ||
778       !ReadParamAtomicHelper(aMsg, aIter, mHaveCipherSuiteAndProtocol) ||
779       !ReadParamAtomicHelper(aMsg, aIter, mHaveCertErrorBits) ||
780       !ReadParam(aMsg, aIter, &mCertificateTransparencyStatus) ||
781       !ReadParam(aMsg, aIter, &mKeaGroup) ||
782       !ReadParam(aMsg, aIter, &mSignatureSchemeName) ||
783       !ReadParam(aMsg, aIter, &mSucceededCertChain) ||
784       !ReadParam(aMsg, aIter, &mFailedCertChain) ||
785       !ReadParamAtomicHelper(aMsg, aIter, mIsDelegatedCredential) ||
786       !ReadParamAtomicHelper(aMsg, aIter, mNPNCompleted) ||
787       !ReadParam(aMsg, aIter, &mNegotiatedNPN) ||
788       !ReadParamAtomicHelper(aMsg, aIter, mResumed) ||
789       !ReadParamAtomicHelper(aMsg, aIter, mIsBuiltCertChainRootBuiltInRoot) ||
790       !ReadParamAtomicHelper(aMsg, aIter, mIsAcceptedEch)) {
791     return false;
792   }
793 
794   mErrorCode = static_cast<PRErrorCode>(errorCode);
795   if (mErrorCode != 0) {
796     mCanceled = true;
797   }
798 
799   return true;
800 }
801 
802 NS_IMETHODIMP
GetInterfaces(nsTArray<nsIID> & array)803 TransportSecurityInfo::GetInterfaces(nsTArray<nsIID>& array) {
804   array.Clear();
805   return NS_OK;
806 }
807 
808 NS_IMETHODIMP
GetScriptableHelper(nsIXPCScriptable ** _retval)809 TransportSecurityInfo::GetScriptableHelper(nsIXPCScriptable** _retval) {
810   *_retval = nullptr;
811   return NS_OK;
812 }
813 
814 NS_IMETHODIMP
GetContractID(nsACString & aContractID)815 TransportSecurityInfo::GetContractID(nsACString& aContractID) {
816   aContractID.SetIsVoid(true);
817   return NS_OK;
818 }
819 
820 NS_IMETHODIMP
GetClassDescription(nsACString & aClassDescription)821 TransportSecurityInfo::GetClassDescription(nsACString& aClassDescription) {
822   aClassDescription.SetIsVoid(true);
823   return NS_OK;
824 }
825 
826 NS_IMETHODIMP
GetClassID(nsCID ** aClassID)827 TransportSecurityInfo::GetClassID(nsCID** aClassID) {
828   *aClassID = (nsCID*)moz_xmalloc(sizeof(nsCID));
829   return GetClassIDNoAlloc(*aClassID);
830 }
831 
832 NS_IMETHODIMP
GetFlags(uint32_t * aFlags)833 TransportSecurityInfo::GetFlags(uint32_t* aFlags) {
834   *aFlags = 0;
835   return NS_OK;
836 }
837 
838 static NS_DEFINE_CID(kNSSSocketInfoCID, TRANSPORTSECURITYINFO_CID);
839 
840 NS_IMETHODIMP
GetClassIDNoAlloc(nsCID * aClassIDNoAlloc)841 TransportSecurityInfo::GetClassIDNoAlloc(nsCID* aClassIDNoAlloc) {
842   *aClassIDNoAlloc = kNSSSocketInfoCID;
843   return NS_OK;
844 }
845 
846 // RememberCertErrorsTable
847 
848 /*static*/
849 RememberCertErrorsTable* RememberCertErrorsTable::sInstance = nullptr;
850 
RememberCertErrorsTable()851 RememberCertErrorsTable::RememberCertErrorsTable()
852     : mErrorHosts(), mMutex("RememberCertErrorsTable::mMutex") {}
853 
GetHostPortKey(TransportSecurityInfo * infoObject,nsCString & result)854 static nsresult GetHostPortKey(TransportSecurityInfo* infoObject,
855                                /*out*/ nsCString& result) {
856   MOZ_ASSERT(infoObject);
857   NS_ENSURE_ARG(infoObject);
858 
859   result.Truncate();
860 
861   result.Assign(infoObject->GetHostName());
862   result.Append(':');
863   result.AppendInt(infoObject->GetPort());
864 
865   return NS_OK;
866 }
867 
RememberCertHasError(TransportSecurityInfo * infoObject,SECStatus certVerificationResult)868 void RememberCertErrorsTable::RememberCertHasError(
869     TransportSecurityInfo* infoObject, SECStatus certVerificationResult) {
870   nsresult rv;
871 
872   nsAutoCString hostPortKey;
873   rv = GetHostPortKey(infoObject, hostPortKey);
874   if (NS_FAILED(rv)) {
875     return;
876   }
877 
878   if (certVerificationResult != SECSuccess) {
879     MOZ_ASSERT(infoObject->mHaveCertErrorBits,
880                "Must have error bits when remembering flags");
881     if (!infoObject->mHaveCertErrorBits) {
882       return;
883     }
884 
885     CertStateBits bits;
886     bits.mIsDomainMismatch = infoObject->mIsDomainMismatch;
887     bits.mIsNotValidAtThisTime = infoObject->mIsNotValidAtThisTime;
888     bits.mIsUntrusted = infoObject->mIsUntrusted;
889 
890     MutexAutoLock lock(mMutex);
891     mErrorHosts.InsertOrUpdate(hostPortKey, bits);
892   } else {
893     MutexAutoLock lock(mMutex);
894     mErrorHosts.Remove(hostPortKey);
895   }
896 }
897 
LookupCertErrorBits(TransportSecurityInfo * infoObject)898 void RememberCertErrorsTable::LookupCertErrorBits(
899     TransportSecurityInfo* infoObject) {
900   // Get remembered error bits from our cache, because of SSL session caching
901   // the NSS library potentially hasn't notified us for this socket.
902   if (infoObject->mHaveCertErrorBits) {
903     // Rather do not modify bits if already set earlier
904     return;
905   }
906 
907   nsresult rv;
908 
909   nsAutoCString hostPortKey;
910   rv = GetHostPortKey(infoObject, hostPortKey);
911   if (NS_FAILED(rv)) {
912     return;
913   }
914 
915   CertStateBits bits;
916   {
917     MutexAutoLock lock(mMutex);
918     if (!mErrorHosts.Get(hostPortKey, &bits)) {
919       // No record was found, this host had no cert errors
920       return;
921     }
922   }
923 
924   // This host had cert errors, update the bits correctly
925   infoObject->mHaveCertErrorBits = true;
926   infoObject->mIsDomainMismatch = bits.mIsDomainMismatch;
927   infoObject->mIsNotValidAtThisTime = bits.mIsNotValidAtThisTime;
928   infoObject->mIsUntrusted = bits.mIsUntrusted;
929 }
930 
SetStatusErrorBits(nsNSSCertificate * cert,uint32_t collected_errors)931 void TransportSecurityInfo::SetStatusErrorBits(nsNSSCertificate* cert,
932                                                uint32_t collected_errors) {
933   SetServerCert(cert, EVStatus::NotEV);
934 
935   mHaveCertErrorBits = true;
936   mIsDomainMismatch = collected_errors & nsICertOverrideService::ERROR_MISMATCH;
937   mIsNotValidAtThisTime = collected_errors & nsICertOverrideService::ERROR_TIME;
938   mIsUntrusted = collected_errors & nsICertOverrideService::ERROR_UNTRUSTED;
939 
940   RememberCertErrorsTable::GetInstance().RememberCertHasError(this, SECFailure);
941 }
942 
943 NS_IMETHODIMP
GetFailedCertChain(nsTArray<RefPtr<nsIX509Cert>> & aFailedCertChain)944 TransportSecurityInfo::GetFailedCertChain(
945     nsTArray<RefPtr<nsIX509Cert>>& aFailedCertChain) {
946   MOZ_ASSERT(aFailedCertChain.IsEmpty());
947   MutexAutoLock lock(mMutex);
948   if (!aFailedCertChain.IsEmpty()) {
949     return NS_ERROR_INVALID_ARG;
950   }
951   aFailedCertChain.AppendElements(mFailedCertChain);
952   return NS_OK;
953 }
954 
CreateCertChain(nsTArray<RefPtr<nsIX509Cert>> & aOutput,nsTArray<nsTArray<uint8_t>> && aCertList)955 static nsresult CreateCertChain(nsTArray<RefPtr<nsIX509Cert>>& aOutput,
956                                 nsTArray<nsTArray<uint8_t>>&& aCertList) {
957   nsTArray<nsTArray<uint8_t>> certList = std::move(aCertList);
958   aOutput.Clear();
959   for (auto& certBytes : certList) {
960     RefPtr<nsIX509Cert> cert = nsNSSCertificate::ConstructFromDER(
961         BitwiseCast<char*, uint8_t*>(certBytes.Elements()), certBytes.Length());
962     if (!cert) {
963       return NS_ERROR_FAILURE;
964     }
965     aOutput.AppendElement(cert);
966   }
967   return NS_OK;
968 }
969 
SetFailedCertChain(nsTArray<nsTArray<uint8_t>> && aCertList)970 nsresult TransportSecurityInfo::SetFailedCertChain(
971     nsTArray<nsTArray<uint8_t>>&& aCertList) {
972   MutexAutoLock lock(mMutex);
973 
974   return CreateCertChain(mFailedCertChain, std::move(aCertList));
975 }
976 
GetServerCert(nsIX509Cert ** aServerCert)977 NS_IMETHODIMP TransportSecurityInfo::GetServerCert(nsIX509Cert** aServerCert) {
978   NS_ENSURE_ARG_POINTER(aServerCert);
979   MutexAutoLock lock(mMutex);
980 
981   nsCOMPtr<nsIX509Cert> cert = mServerCert;
982   cert.forget(aServerCert);
983   return NS_OK;
984 }
985 
SetServerCert(nsNSSCertificate * aServerCert,EVStatus aEVStatus)986 void TransportSecurityInfo::SetServerCert(nsNSSCertificate* aServerCert,
987                                           EVStatus aEVStatus) {
988   MOZ_ASSERT(aServerCert);
989   MutexAutoLock lock(mMutex);
990 
991   mServerCert = aServerCert;
992   mIsEV = (aEVStatus == EVStatus::EV);
993   mHasIsEVStatus = true;
994 }
995 
996 NS_IMETHODIMP
GetSucceededCertChain(nsTArray<RefPtr<nsIX509Cert>> & aSucceededCertChain)997 TransportSecurityInfo::GetSucceededCertChain(
998     nsTArray<RefPtr<nsIX509Cert>>& aSucceededCertChain) {
999   MOZ_ASSERT(aSucceededCertChain.IsEmpty());
1000   MutexAutoLock lock(mMutex);
1001   if (!aSucceededCertChain.IsEmpty()) {
1002     return NS_ERROR_INVALID_ARG;
1003   }
1004   aSucceededCertChain.AppendElements(mSucceededCertChain);
1005   return NS_OK;
1006 }
1007 
SetSucceededCertChain(nsTArray<nsTArray<uint8_t>> && aCertList)1008 nsresult TransportSecurityInfo::SetSucceededCertChain(
1009     nsTArray<nsTArray<uint8_t>>&& aCertList) {
1010   MutexAutoLock lock(mMutex);
1011   return CreateCertChain(mSucceededCertChain, std::move(aCertList));
1012 }
1013 
SetIsBuiltCertChainRootBuiltInRoot(bool aIsBuiltInRoot)1014 NS_IMETHODIMP TransportSecurityInfo::SetIsBuiltCertChainRootBuiltInRoot(
1015     bool aIsBuiltInRoot) {
1016   mIsBuiltCertChainRootBuiltInRoot = aIsBuiltInRoot;
1017   return NS_OK;
1018 }
1019 
GetIsBuiltCertChainRootBuiltInRoot(bool * aIsBuiltInRoot)1020 NS_IMETHODIMP TransportSecurityInfo::GetIsBuiltCertChainRootBuiltInRoot(
1021     bool* aIsBuiltInRoot) {
1022   NS_ENSURE_ARG_POINTER(aIsBuiltInRoot);
1023   *aIsBuiltInRoot = mIsBuiltCertChainRootBuiltInRoot;
1024   return NS_OK;
1025 }
1026 
1027 NS_IMETHODIMP
GetCipherName(nsACString & aCipherName)1028 TransportSecurityInfo::GetCipherName(nsACString& aCipherName) {
1029   MutexAutoLock lock(mMutex);
1030 
1031   if (!mHaveCipherSuiteAndProtocol) {
1032     return NS_ERROR_NOT_AVAILABLE;
1033   }
1034 
1035   SSLCipherSuiteInfo cipherInfo;
1036   if (SSL_GetCipherSuiteInfo(mCipherSuite, &cipherInfo, sizeof(cipherInfo)) !=
1037       SECSuccess) {
1038     return NS_ERROR_FAILURE;
1039   }
1040 
1041   aCipherName.Assign(cipherInfo.cipherSuiteName);
1042   return NS_OK;
1043 }
1044 
1045 NS_IMETHODIMP
GetKeyLength(uint32_t * aKeyLength)1046 TransportSecurityInfo::GetKeyLength(uint32_t* aKeyLength) {
1047   NS_ENSURE_ARG_POINTER(aKeyLength);
1048   MutexAutoLock lock(mMutex);
1049   if (!mHaveCipherSuiteAndProtocol) {
1050     return NS_ERROR_NOT_AVAILABLE;
1051   }
1052 
1053   SSLCipherSuiteInfo cipherInfo;
1054   if (SSL_GetCipherSuiteInfo(mCipherSuite, &cipherInfo, sizeof(cipherInfo)) !=
1055       SECSuccess) {
1056     return NS_ERROR_FAILURE;
1057   }
1058 
1059   *aKeyLength = cipherInfo.symKeyBits;
1060   return NS_OK;
1061 }
1062 
1063 NS_IMETHODIMP
GetSecretKeyLength(uint32_t * aSecretKeyLength)1064 TransportSecurityInfo::GetSecretKeyLength(uint32_t* aSecretKeyLength) {
1065   NS_ENSURE_ARG_POINTER(aSecretKeyLength);
1066   MutexAutoLock lock(mMutex);
1067   if (!mHaveCipherSuiteAndProtocol) {
1068     return NS_ERROR_NOT_AVAILABLE;
1069   }
1070 
1071   SSLCipherSuiteInfo cipherInfo;
1072   if (SSL_GetCipherSuiteInfo(mCipherSuite, &cipherInfo, sizeof(cipherInfo)) !=
1073       SECSuccess) {
1074     return NS_ERROR_FAILURE;
1075   }
1076 
1077   *aSecretKeyLength = cipherInfo.effectiveKeyBits;
1078   return NS_OK;
1079 }
1080 
1081 NS_IMETHODIMP
GetKeaGroupName(nsACString & aKeaGroup)1082 TransportSecurityInfo::GetKeaGroupName(nsACString& aKeaGroup) {
1083   MutexAutoLock lock(mMutex);
1084 
1085   if (!mHaveCipherSuiteAndProtocol) {
1086     return NS_ERROR_NOT_AVAILABLE;
1087   }
1088 
1089   aKeaGroup.Assign(mKeaGroup);
1090   return NS_OK;
1091 }
1092 
1093 NS_IMETHODIMP
GetSignatureSchemeName(nsACString & aSignatureScheme)1094 TransportSecurityInfo::GetSignatureSchemeName(nsACString& aSignatureScheme) {
1095   MutexAutoLock lock(mMutex);
1096 
1097   if (!mHaveCipherSuiteAndProtocol) {
1098     return NS_ERROR_NOT_AVAILABLE;
1099   }
1100 
1101   aSignatureScheme.Assign(mSignatureSchemeName);
1102   return NS_OK;
1103 }
1104 
1105 NS_IMETHODIMP
GetProtocolVersion(uint16_t * aProtocolVersion)1106 TransportSecurityInfo::GetProtocolVersion(uint16_t* aProtocolVersion) {
1107   MutexAutoLock lock(mMutex);
1108 
1109   NS_ENSURE_ARG_POINTER(aProtocolVersion);
1110   if (!mHaveCipherSuiteAndProtocol) {
1111     return NS_ERROR_NOT_AVAILABLE;
1112   }
1113 
1114   *aProtocolVersion = mProtocolVersion;
1115   return NS_OK;
1116 }
1117 
1118 NS_IMETHODIMP
GetCertificateTransparencyStatus(uint16_t * aCertificateTransparencyStatus)1119 TransportSecurityInfo::GetCertificateTransparencyStatus(
1120     uint16_t* aCertificateTransparencyStatus) {
1121   NS_ENSURE_ARG_POINTER(aCertificateTransparencyStatus);
1122   MutexAutoLock lock(mMutex);
1123 
1124   *aCertificateTransparencyStatus = mCertificateTransparencyStatus;
1125   return NS_OK;
1126 }
1127 
1128 // static
ConvertCertificateTransparencyInfoToStatus(const mozilla::psm::CertificateTransparencyInfo & info)1129 uint16_t TransportSecurityInfo::ConvertCertificateTransparencyInfoToStatus(
1130     const mozilla::psm::CertificateTransparencyInfo& info) {
1131   using mozilla::ct::CTPolicyCompliance;
1132 
1133   if (!info.enabled) {
1134     // CT disabled.
1135     return nsITransportSecurityInfo::CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE;
1136   }
1137 
1138   switch (info.policyCompliance) {
1139     case CTPolicyCompliance::Compliant:
1140       return nsITransportSecurityInfo::
1141           CERTIFICATE_TRANSPARENCY_POLICY_COMPLIANT;
1142     case CTPolicyCompliance::NotEnoughScts:
1143       return nsITransportSecurityInfo ::
1144           CERTIFICATE_TRANSPARENCY_POLICY_NOT_ENOUGH_SCTS;
1145     case CTPolicyCompliance::NotDiverseScts:
1146       return nsITransportSecurityInfo ::
1147           CERTIFICATE_TRANSPARENCY_POLICY_NOT_DIVERSE_SCTS;
1148     case CTPolicyCompliance::Unknown:
1149     default:
1150       MOZ_ASSERT_UNREACHABLE("Unexpected CTPolicyCompliance type");
1151   }
1152 
1153   return nsITransportSecurityInfo::CERTIFICATE_TRANSPARENCY_NOT_APPLICABLE;
1154 }
1155 
1156 // static
CreateCertBytesArray(const UniqueCERTCertList & aCertChain)1157 nsTArray<nsTArray<uint8_t>> TransportSecurityInfo::CreateCertBytesArray(
1158     const UniqueCERTCertList& aCertChain) {
1159   nsTArray<nsTArray<uint8_t>> certsBytes;
1160   for (CERTCertListNode* n = CERT_LIST_HEAD(aCertChain);
1161        !CERT_LIST_END(n, aCertChain); n = CERT_LIST_NEXT(n)) {
1162     nsTArray<uint8_t> certBytes;
1163     certBytes.AppendElements(n->cert->derCert.data, n->cert->derCert.len);
1164     certsBytes.AppendElement(std::move(certBytes));
1165   }
1166   return certsBytes;
1167 }
1168 
1169 NS_IMETHODIMP
GetIsDomainMismatch(bool * aIsDomainMismatch)1170 TransportSecurityInfo::GetIsDomainMismatch(bool* aIsDomainMismatch) {
1171   NS_ENSURE_ARG_POINTER(aIsDomainMismatch);
1172   *aIsDomainMismatch = mHaveCertErrorBits && mIsDomainMismatch;
1173   return NS_OK;
1174 }
1175 
1176 NS_IMETHODIMP
GetIsNotValidAtThisTime(bool * aIsNotValidAtThisTime)1177 TransportSecurityInfo::GetIsNotValidAtThisTime(bool* aIsNotValidAtThisTime) {
1178   NS_ENSURE_ARG_POINTER(aIsNotValidAtThisTime);
1179   *aIsNotValidAtThisTime = mHaveCertErrorBits && mIsNotValidAtThisTime;
1180   return NS_OK;
1181 }
1182 
1183 NS_IMETHODIMP
GetIsUntrusted(bool * aIsUntrusted)1184 TransportSecurityInfo::GetIsUntrusted(bool* aIsUntrusted) {
1185   NS_ENSURE_ARG_POINTER(aIsUntrusted);
1186   *aIsUntrusted = mHaveCertErrorBits && mIsUntrusted;
1187   return NS_OK;
1188 }
1189 
1190 NS_IMETHODIMP
GetIsExtendedValidation(bool * aIsEV)1191 TransportSecurityInfo::GetIsExtendedValidation(bool* aIsEV) {
1192   NS_ENSURE_ARG_POINTER(aIsEV);
1193   *aIsEV = false;
1194   // Never allow bad certs for EV, regardless of overrides.
1195   if (mHaveCertErrorBits) {
1196     return NS_OK;
1197   }
1198 
1199   if (mHasIsEVStatus) {
1200     *aIsEV = mIsEV;
1201     return NS_OK;
1202   }
1203 
1204   return NS_ERROR_NOT_AVAILABLE;
1205 }
1206 
1207 NS_IMETHODIMP
GetIsAcceptedEch(bool * aIsAcceptedEch)1208 TransportSecurityInfo::GetIsAcceptedEch(bool* aIsAcceptedEch) {
1209   NS_ENSURE_ARG_POINTER(aIsAcceptedEch);
1210   if (!mHaveCipherSuiteAndProtocol) {
1211     return NS_ERROR_NOT_AVAILABLE;
1212   }
1213   *aIsAcceptedEch = mIsAcceptedEch;
1214   return NS_OK;
1215 }
1216 
1217 NS_IMETHODIMP
GetIsDelegatedCredential(bool * aIsDelegCred)1218 TransportSecurityInfo::GetIsDelegatedCredential(bool* aIsDelegCred) {
1219   NS_ENSURE_ARG_POINTER(aIsDelegCred);
1220   if (!mHaveCipherSuiteAndProtocol) {
1221     return NS_ERROR_NOT_AVAILABLE;
1222   }
1223   *aIsDelegCred = mIsDelegatedCredential;
1224   return NS_OK;
1225 }
1226 
1227 NS_IMETHODIMP
GetNegotiatedNPN(nsACString & aNegotiatedNPN)1228 TransportSecurityInfo::GetNegotiatedNPN(nsACString& aNegotiatedNPN) {
1229   MutexAutoLock lock(mMutex);
1230 
1231   if (!mNPNCompleted) {
1232     return NS_ERROR_NOT_CONNECTED;
1233   }
1234 
1235   aNegotiatedNPN = mNegotiatedNPN;
1236   return NS_OK;
1237 }
1238 
1239 NS_IMETHODIMP
GetResumed(bool * aResumed)1240 TransportSecurityInfo::GetResumed(bool* aResumed) {
1241   *aResumed = mResumed;
1242   return NS_OK;
1243 }
1244 
SetResumed(bool aResumed)1245 void TransportSecurityInfo::SetResumed(bool aResumed) { mResumed = aResumed; }
1246 
1247 }  // namespace psm
1248 }  // namespace mozilla
1249