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