|
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 "nsRecentBadCerts.h" |
|
8 |
|
9 #include "pkix/pkixtypes.h" |
|
10 #include "nsIX509Cert.h" |
|
11 #include "nsIObserverService.h" |
|
12 #include "mozilla/RefPtr.h" |
|
13 #include "mozilla/Services.h" |
|
14 #include "nsSSLStatus.h" |
|
15 #include "nsCOMPtr.h" |
|
16 #include "nsNSSCertificate.h" |
|
17 #include "nsCRT.h" |
|
18 #include "nsPromiseFlatString.h" |
|
19 #include "nsStringBuffer.h" |
|
20 #include "nspr.h" |
|
21 #include "pk11pub.h" |
|
22 #include "certdb.h" |
|
23 #include "sechash.h" |
|
24 |
|
25 using namespace mozilla; |
|
26 |
|
27 NS_IMPL_ISUPPORTS(nsRecentBadCerts, nsIRecentBadCerts) |
|
28 |
|
29 nsRecentBadCerts::nsRecentBadCerts() |
|
30 :monitor("nsRecentBadCerts.monitor") |
|
31 ,mNextStorePosition(0) |
|
32 { |
|
33 } |
|
34 |
|
35 nsRecentBadCerts::~nsRecentBadCerts() |
|
36 { |
|
37 } |
|
38 |
|
39 NS_IMETHODIMP |
|
40 nsRecentBadCerts::GetRecentBadCert(const nsAString & aHostNameWithPort, |
|
41 nsISSLStatus **aStatus) |
|
42 { |
|
43 NS_ENSURE_ARG_POINTER(aStatus); |
|
44 if (!aHostNameWithPort.Length()) |
|
45 return NS_ERROR_INVALID_ARG; |
|
46 |
|
47 *aStatus = nullptr; |
|
48 RefPtr<nsSSLStatus> status(new nsSSLStatus()); |
|
49 |
|
50 SECItem foundDER; |
|
51 foundDER.len = 0; |
|
52 foundDER.data = nullptr; |
|
53 |
|
54 bool isDomainMismatch = false; |
|
55 bool isNotValidAtThisTime = false; |
|
56 bool isUntrusted = false; |
|
57 |
|
58 { |
|
59 ReentrantMonitorAutoEnter lock(monitor); |
|
60 for (size_t i=0; i<const_recently_seen_list_size; ++i) { |
|
61 if (mCerts[i].mHostWithPort.Equals(aHostNameWithPort)) { |
|
62 SECStatus srv = SECITEM_CopyItem(nullptr, &foundDER, &mCerts[i].mDERCert); |
|
63 if (srv != SECSuccess) |
|
64 return NS_ERROR_OUT_OF_MEMORY; |
|
65 |
|
66 isDomainMismatch = mCerts[i].isDomainMismatch; |
|
67 isNotValidAtThisTime = mCerts[i].isNotValidAtThisTime; |
|
68 isUntrusted = mCerts[i].isUntrusted; |
|
69 } |
|
70 } |
|
71 } |
|
72 |
|
73 if (foundDER.len) { |
|
74 CERTCertDBHandle *certdb = CERT_GetDefaultCertDB(); |
|
75 mozilla::pkix::ScopedCERTCertificate nssCert( |
|
76 CERT_FindCertByDERCert(certdb, &foundDER)); |
|
77 if (!nssCert) |
|
78 nssCert = CERT_NewTempCertificate(certdb, &foundDER, |
|
79 nullptr, // no nickname |
|
80 false, // not perm |
|
81 true); // copy der |
|
82 |
|
83 SECITEM_FreeItem(&foundDER, false); |
|
84 |
|
85 if (!nssCert) |
|
86 return NS_ERROR_FAILURE; |
|
87 |
|
88 status->mServerCert = nsNSSCertificate::Create(nssCert.get()); |
|
89 status->mHaveCertErrorBits = true; |
|
90 status->mIsDomainMismatch = isDomainMismatch; |
|
91 status->mIsNotValidAtThisTime = isNotValidAtThisTime; |
|
92 status->mIsUntrusted = isUntrusted; |
|
93 |
|
94 *aStatus = status; |
|
95 NS_IF_ADDREF(*aStatus); |
|
96 } |
|
97 |
|
98 return NS_OK; |
|
99 } |
|
100 |
|
101 NS_IMETHODIMP |
|
102 nsRecentBadCerts::AddBadCert(const nsAString &hostWithPort, |
|
103 nsISSLStatus *aStatus) |
|
104 { |
|
105 NS_ENSURE_ARG(aStatus); |
|
106 |
|
107 nsCOMPtr<nsIX509Cert> cert; |
|
108 nsresult rv; |
|
109 rv = aStatus->GetServerCert(getter_AddRefs(cert)); |
|
110 NS_ENSURE_SUCCESS(rv, rv); |
|
111 |
|
112 bool isDomainMismatch; |
|
113 bool isNotValidAtThisTime; |
|
114 bool isUntrusted; |
|
115 |
|
116 rv = aStatus->GetIsDomainMismatch(&isDomainMismatch); |
|
117 NS_ENSURE_SUCCESS(rv, rv); |
|
118 |
|
119 rv = aStatus->GetIsNotValidAtThisTime(&isNotValidAtThisTime); |
|
120 NS_ENSURE_SUCCESS(rv, rv); |
|
121 |
|
122 rv = aStatus->GetIsUntrusted(&isUntrusted); |
|
123 NS_ENSURE_SUCCESS(rv, rv); |
|
124 |
|
125 SECItem tempItem; |
|
126 rv = cert->GetRawDER(&tempItem.len, (uint8_t **)&tempItem.data); |
|
127 NS_ENSURE_SUCCESS(rv, rv); |
|
128 |
|
129 { |
|
130 ReentrantMonitorAutoEnter lock(monitor); |
|
131 RecentBadCert &updatedEntry = mCerts[mNextStorePosition]; |
|
132 |
|
133 ++mNextStorePosition; |
|
134 if (mNextStorePosition == const_recently_seen_list_size) |
|
135 mNextStorePosition = 0; |
|
136 |
|
137 updatedEntry.Clear(); |
|
138 updatedEntry.mHostWithPort = hostWithPort; |
|
139 updatedEntry.mDERCert = tempItem; // consume |
|
140 updatedEntry.isDomainMismatch = isDomainMismatch; |
|
141 updatedEntry.isNotValidAtThisTime = isNotValidAtThisTime; |
|
142 updatedEntry.isUntrusted = isUntrusted; |
|
143 } |
|
144 |
|
145 return NS_OK; |
|
146 } |
|
147 |
|
148 NS_IMETHODIMP |
|
149 nsRecentBadCerts::ResetStoredCerts() |
|
150 { |
|
151 for (size_t i = 0; i < const_recently_seen_list_size; ++i) { |
|
152 RecentBadCert &entry = mCerts[i]; |
|
153 entry.Clear(); |
|
154 } |
|
155 return NS_OK; |
|
156 } |