|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "nsCertPicker.h" |
|
7 #include "pkix/pkixtypes.h" |
|
8 #include "nsMemory.h" |
|
9 #include "nsCOMPtr.h" |
|
10 #include "nsXPIDLString.h" |
|
11 #include "nsIServiceManager.h" |
|
12 #include "nsNSSComponent.h" |
|
13 #include "nsNSSCertificate.h" |
|
14 #include "nsReadableUtils.h" |
|
15 #include "nsICertPickDialogs.h" |
|
16 #include "nsNSSShutDown.h" |
|
17 #include "nsNSSCertHelper.h" |
|
18 #include "ScopedNSSTypes.h" |
|
19 |
|
20 #include "cert.h" |
|
21 |
|
22 using namespace mozilla; |
|
23 |
|
24 NS_IMPL_ISUPPORTS(nsCertPicker, nsIUserCertPicker) |
|
25 |
|
26 nsCertPicker::nsCertPicker() |
|
27 { |
|
28 } |
|
29 |
|
30 nsCertPicker::~nsCertPicker() |
|
31 { |
|
32 } |
|
33 |
|
34 NS_IMETHODIMP nsCertPicker::PickByUsage(nsIInterfaceRequestor *ctx, |
|
35 const char16_t *selectedNickname, |
|
36 int32_t certUsage, |
|
37 bool allowInvalid, |
|
38 bool allowDuplicateNicknames, |
|
39 bool *canceled, |
|
40 nsIX509Cert **_retval) |
|
41 { |
|
42 nsNSSShutDownPreventionLock locker; |
|
43 int32_t selectedIndex = -1; |
|
44 bool selectionFound = false; |
|
45 char16_t **certNicknameList = nullptr; |
|
46 char16_t **certDetailsList = nullptr; |
|
47 CERTCertListNode* node = nullptr; |
|
48 nsresult rv = NS_OK; |
|
49 |
|
50 { |
|
51 // Iterate over all certs. This assures that user is logged in to all hardware tokens. |
|
52 nsCOMPtr<nsIInterfaceRequestor> ctx = new PipUIContext(); |
|
53 mozilla::pkix::ScopedCERTCertList allcerts( |
|
54 PK11_ListCerts(PK11CertListUnique, ctx)); |
|
55 } |
|
56 |
|
57 /* find all user certs that are valid and for SSL */ |
|
58 /* note that we are allowing expired certs in this list */ |
|
59 |
|
60 mozilla::pkix::ScopedCERTCertList certList( |
|
61 CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), |
|
62 (SECCertUsage)certUsage, |
|
63 !allowDuplicateNicknames, |
|
64 !allowInvalid, |
|
65 ctx)); |
|
66 if (!certList) { |
|
67 return NS_ERROR_NOT_AVAILABLE; |
|
68 } |
|
69 |
|
70 ScopedCERTCertNicknames nicknames(getNSSCertNicknamesFromCertList(certList.get())); |
|
71 if (!nicknames) { |
|
72 return NS_ERROR_NOT_AVAILABLE; |
|
73 } |
|
74 |
|
75 certNicknameList = (char16_t **)nsMemory::Alloc(sizeof(char16_t *) * nicknames->numnicknames); |
|
76 certDetailsList = (char16_t **)nsMemory::Alloc(sizeof(char16_t *) * nicknames->numnicknames); |
|
77 |
|
78 if (!certNicknameList || !certDetailsList) { |
|
79 nsMemory::Free(certNicknameList); |
|
80 nsMemory::Free(certDetailsList); |
|
81 return NS_ERROR_OUT_OF_MEMORY; |
|
82 } |
|
83 |
|
84 int32_t CertsToUse; |
|
85 |
|
86 for (CertsToUse = 0, node = CERT_LIST_HEAD(certList.get()); |
|
87 !CERT_LIST_END(node, certList.get()) && |
|
88 CertsToUse < nicknames->numnicknames; |
|
89 node = CERT_LIST_NEXT(node) |
|
90 ) |
|
91 { |
|
92 nsNSSCertificate *tempCert = nsNSSCertificate::Create(node->cert); |
|
93 |
|
94 if (tempCert) { |
|
95 |
|
96 // XXX we really should be using an nsCOMPtr instead of manually add-refing, |
|
97 // but nsNSSCertificate does not have a default constructor. |
|
98 |
|
99 NS_ADDREF(tempCert); |
|
100 |
|
101 nsAutoString i_nickname(NS_ConvertUTF8toUTF16(nicknames->nicknames[CertsToUse])); |
|
102 nsAutoString nickWithSerial; |
|
103 nsAutoString details; |
|
104 |
|
105 if (!selectionFound) { |
|
106 if (i_nickname == nsDependentString(selectedNickname)) { |
|
107 selectedIndex = CertsToUse; |
|
108 selectionFound = true; |
|
109 } |
|
110 } |
|
111 |
|
112 if (NS_SUCCEEDED(tempCert->FormatUIStrings(i_nickname, nickWithSerial, details))) { |
|
113 certNicknameList[CertsToUse] = ToNewUnicode(nickWithSerial); |
|
114 certDetailsList[CertsToUse] = ToNewUnicode(details); |
|
115 } |
|
116 else { |
|
117 certNicknameList[CertsToUse] = nullptr; |
|
118 certDetailsList[CertsToUse] = nullptr; |
|
119 } |
|
120 |
|
121 NS_RELEASE(tempCert); |
|
122 |
|
123 ++CertsToUse; |
|
124 } |
|
125 } |
|
126 |
|
127 if (CertsToUse) { |
|
128 nsICertPickDialogs *dialogs = nullptr; |
|
129 rv = getNSSDialogs((void**)&dialogs, |
|
130 NS_GET_IID(nsICertPickDialogs), |
|
131 NS_CERTPICKDIALOGS_CONTRACTID); |
|
132 |
|
133 if (NS_SUCCEEDED(rv)) { |
|
134 nsPSMUITracker tracker; |
|
135 if (tracker.isUIForbidden()) { |
|
136 rv = NS_ERROR_NOT_AVAILABLE; |
|
137 } |
|
138 else { |
|
139 /* Throw up the cert picker dialog and get back the index of the selected cert */ |
|
140 rv = dialogs->PickCertificate(ctx, |
|
141 (const char16_t**)certNicknameList, (const char16_t**)certDetailsList, |
|
142 CertsToUse, &selectedIndex, canceled); |
|
143 } |
|
144 |
|
145 NS_RELEASE(dialogs); |
|
146 } |
|
147 } |
|
148 |
|
149 int32_t i; |
|
150 for (i = 0; i < CertsToUse; ++i) { |
|
151 nsMemory::Free(certNicknameList[i]); |
|
152 nsMemory::Free(certDetailsList[i]); |
|
153 } |
|
154 nsMemory::Free(certNicknameList); |
|
155 nsMemory::Free(certDetailsList); |
|
156 |
|
157 if (!CertsToUse) { |
|
158 return NS_ERROR_NOT_AVAILABLE; |
|
159 } |
|
160 |
|
161 if (NS_SUCCEEDED(rv) && !*canceled) { |
|
162 for (i = 0, node = CERT_LIST_HEAD(certList); |
|
163 !CERT_LIST_END(node, certList); |
|
164 ++i, node = CERT_LIST_NEXT(node)) { |
|
165 |
|
166 if (i == selectedIndex) { |
|
167 nsNSSCertificate *cert = nsNSSCertificate::Create(node->cert); |
|
168 if (!cert) { |
|
169 rv = NS_ERROR_OUT_OF_MEMORY; |
|
170 break; |
|
171 } |
|
172 |
|
173 nsIX509Cert *x509 = 0; |
|
174 nsresult rv = cert->QueryInterface(NS_GET_IID(nsIX509Cert), (void**)&x509); |
|
175 if (NS_FAILED(rv)) { |
|
176 break; |
|
177 } |
|
178 |
|
179 NS_ADDREF(x509); |
|
180 *_retval = x509; |
|
181 NS_RELEASE(cert); |
|
182 break; |
|
183 } |
|
184 } |
|
185 } |
|
186 |
|
187 return rv; |
|
188 } |