security/manager/ssl/src/nsClientAuthRemember.cpp

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:ab5df9883f4f
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 "nsClientAuthRemember.h"
8
9 #include "nsIX509Cert.h"
10 #include "mozilla/RefPtr.h"
11 #include "nsCRT.h"
12 #include "nsNetUtil.h"
13 #include "nsNSSCertHelper.h"
14 #include "nsIObserverService.h"
15 #include "nsNetUtil.h"
16 #include "nsISupportsPrimitives.h"
17 #include "nsPromiseFlatString.h"
18 #include "nsThreadUtils.h"
19 #include "nsStringBuffer.h"
20 #include "cert.h"
21 #include "nspr.h"
22 #include "pk11pub.h"
23 #include "certdb.h"
24 #include "sechash.h"
25 #include "SharedSSLState.h"
26
27 using namespace mozilla;
28 using namespace mozilla::psm;
29
30 NS_IMPL_ISUPPORTS(nsClientAuthRememberService,
31 nsIObserver,
32 nsISupportsWeakReference)
33
34 nsClientAuthRememberService::nsClientAuthRememberService()
35 : monitor("nsClientAuthRememberService.monitor")
36 {
37 }
38
39 nsClientAuthRememberService::~nsClientAuthRememberService()
40 {
41 RemoveAllFromMemory();
42 }
43
44 nsresult
45 nsClientAuthRememberService::Init()
46 {
47 if (!NS_IsMainThread()) {
48 NS_ERROR("nsClientAuthRememberService::Init called off the main thread");
49 return NS_ERROR_NOT_SAME_THREAD;
50 }
51
52 nsCOMPtr<nsIObserverService> observerService =
53 mozilla::services::GetObserverService();
54 if (observerService) {
55 observerService->AddObserver(this, "profile-before-change", true);
56 }
57
58 return NS_OK;
59 }
60
61 NS_IMETHODIMP
62 nsClientAuthRememberService::Observe(nsISupports *aSubject,
63 const char *aTopic,
64 const char16_t *aData)
65 {
66 // check the topic
67 if (!nsCRT::strcmp(aTopic, "profile-before-change")) {
68 // The profile is about to change,
69 // or is going away because the application is shutting down.
70
71 ReentrantMonitorAutoEnter lock(monitor);
72 RemoveAllFromMemory();
73 }
74
75 return NS_OK;
76 }
77
78 void nsClientAuthRememberService::ClearRememberedDecisions()
79 {
80 ReentrantMonitorAutoEnter lock(monitor);
81 RemoveAllFromMemory();
82 }
83
84 void nsClientAuthRememberService::ClearAllRememberedDecisions()
85 {
86 RefPtr<nsClientAuthRememberService> svc =
87 PublicSSLState()->GetClientAuthRememberService();
88 svc->ClearRememberedDecisions();
89
90 svc = PrivateSSLState()->GetClientAuthRememberService();
91 svc->ClearRememberedDecisions();
92 }
93
94 void
95 nsClientAuthRememberService::RemoveAllFromMemory()
96 {
97 mSettingsTable.Clear();
98 }
99
100 nsresult
101 nsClientAuthRememberService::RememberDecision(const nsACString & aHostName,
102 CERTCertificate *aServerCert, CERTCertificate *aClientCert)
103 {
104 // aClientCert == nullptr means: remember that user does not want to use a cert
105 NS_ENSURE_ARG_POINTER(aServerCert);
106 if (aHostName.IsEmpty())
107 return NS_ERROR_INVALID_ARG;
108
109 nsAutoCString fpStr;
110 nsresult rv = GetCertFingerprintByOidTag(aServerCert, SEC_OID_SHA256, fpStr);
111 if (NS_FAILED(rv))
112 return rv;
113
114 {
115 ReentrantMonitorAutoEnter lock(monitor);
116 if (aClientCert) {
117 nsNSSCertificate pipCert(aClientCert);
118 char *dbkey = nullptr;
119 rv = pipCert.GetDbKey(&dbkey);
120 if (NS_SUCCEEDED(rv) && dbkey) {
121 AddEntryToList(aHostName, fpStr,
122 nsDependentCString(dbkey));
123 }
124 if (dbkey) {
125 PORT_Free(dbkey);
126 }
127 }
128 else {
129 nsCString empty;
130 AddEntryToList(aHostName, fpStr, empty);
131 }
132 }
133
134 return NS_OK;
135 }
136
137 nsresult
138 nsClientAuthRememberService::HasRememberedDecision(const nsACString & aHostName,
139 CERTCertificate *aCert,
140 nsACString & aCertDBKey,
141 bool *_retval)
142 {
143 if (aHostName.IsEmpty())
144 return NS_ERROR_INVALID_ARG;
145
146 NS_ENSURE_ARG_POINTER(aCert);
147 NS_ENSURE_ARG_POINTER(_retval);
148 *_retval = false;
149
150 nsresult rv;
151 nsAutoCString fpStr;
152 rv = GetCertFingerprintByOidTag(aCert, SEC_OID_SHA256, fpStr);
153 if (NS_FAILED(rv))
154 return rv;
155
156 nsAutoCString hostCert;
157 GetHostWithCert(aHostName, fpStr, hostCert);
158 nsClientAuthRemember settings;
159
160 {
161 ReentrantMonitorAutoEnter lock(monitor);
162 nsClientAuthRememberEntry *entry = mSettingsTable.GetEntry(hostCert.get());
163 if (!entry)
164 return NS_OK;
165 settings = entry->mSettings; // copy
166 }
167
168 aCertDBKey = settings.mDBKey;
169 *_retval = true;
170 return NS_OK;
171 }
172
173 nsresult
174 nsClientAuthRememberService::AddEntryToList(const nsACString &aHostName,
175 const nsACString &fingerprint,
176 const nsACString &db_key)
177
178 {
179 nsAutoCString hostCert;
180 GetHostWithCert(aHostName, fingerprint, hostCert);
181
182 {
183 ReentrantMonitorAutoEnter lock(monitor);
184 nsClientAuthRememberEntry *entry = mSettingsTable.PutEntry(hostCert.get());
185
186 if (!entry) {
187 NS_ERROR("can't insert a null entry!");
188 return NS_ERROR_OUT_OF_MEMORY;
189 }
190
191 entry->mHostWithCert = hostCert;
192
193 nsClientAuthRemember &settings = entry->mSettings;
194 settings.mAsciiHost = aHostName;
195 settings.mFingerprint = fingerprint;
196 settings.mDBKey = db_key;
197 }
198
199 return NS_OK;
200 }
201
202 void
203 nsClientAuthRememberService::GetHostWithCert(const nsACString & aHostName,
204 const nsACString & fingerprint,
205 nsACString& _retval)
206 {
207 nsAutoCString hostCert(aHostName);
208 hostCert.AppendLiteral(":");
209 hostCert.Append(fingerprint);
210
211 _retval.Assign(hostCert);
212 }

mercurial