1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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 #include "nsPK11TokenDB.h"
10 #include "ScopedNSSTypes.h"
11 #include "mozilla/Casting.h"
12 #include "mozilla/Unused.h"
13 #include "mozilla/Logging.h"
14 #include "nsISupports.h"
15 #include "nsNSSCertHelper.h"
16 #include "nsNSSComponent.h"
17 #include "nsPromiseFlatString.h"
18 #include "nsReadableUtils.h"
19 #include "nsServiceManagerUtils.h"
23 extern mozilla::LazyLogModule gPIPNSSLog
;
25 NS_IMPL_ISUPPORTS(nsPK11Token
, nsIPK11Token
)
27 nsPK11Token::nsPK11Token(PK11SlotInfo
* slot
) : mUIContext(new PipUIContext()) {
29 mSlot
.reset(PK11_ReferenceSlot(slot
));
30 mIsInternalCryptoToken
=
31 PK11_IsInternal(mSlot
.get()) && !PK11_IsInternalKeySlot(mSlot
.get());
32 mIsInternalKeyToken
= PK11_IsInternalKeySlot(mSlot
.get());
33 mSeries
= PK11_GetSlotSeries(slot
);
34 mozilla::Unused
<< refreshTokenInfo();
37 nsresult
nsPK11Token::refreshTokenInfo() {
38 if (mIsInternalCryptoToken
) {
41 rv
= GetPIPNSSBundleString("Fips140TokenDescription", mTokenName
);
43 rv
= GetPIPNSSBundleString("TokenDescription", mTokenName
);
48 } else if (mIsInternalKeyToken
) {
49 nsresult rv
= GetPIPNSSBundleString("PrivateTokenDescription", mTokenName
);
54 mTokenName
.Assign(PK11_GetTokenName(mSlot
.get()));
57 CK_TOKEN_INFO tokInfo
;
58 nsresult rv
= mozilla::MapSECStatus(PK11_GetTokenInfo(mSlot
.get(), &tokInfo
));
63 // Set the Manufacturer field
64 if (mIsInternalCryptoToken
|| mIsInternalKeyToken
) {
65 rv
= GetPIPNSSBundleString("ManufacturerID", mTokenManufacturerID
);
71 mozilla::BitwiseCast
<char*, CK_UTF8CHAR
*>(tokInfo
.manufacturerID
);
72 mTokenManufacturerID
.Assign(
73 ccManID
, strnlen(ccManID
, sizeof(tokInfo
.manufacturerID
)));
74 mTokenManufacturerID
.Trim(" ", false, true);
77 // Set the Hardware Version field
78 mTokenHWVersion
.Truncate();
79 mTokenHWVersion
.AppendInt(tokInfo
.hardwareVersion
.major
);
80 mTokenHWVersion
.Append('.');
81 mTokenHWVersion
.AppendInt(tokInfo
.hardwareVersion
.minor
);
83 // Set the Firmware Version field
84 mTokenFWVersion
.Truncate();
85 mTokenFWVersion
.AppendInt(tokInfo
.firmwareVersion
.major
);
86 mTokenFWVersion
.Append('.');
87 mTokenFWVersion
.AppendInt(tokInfo
.firmwareVersion
.minor
);
89 // Set the Serial Number field
90 const char* ccSerial
=
91 mozilla::BitwiseCast
<char*, CK_CHAR
*>(tokInfo
.serialNumber
);
92 mTokenSerialNum
.Assign(ccSerial
,
93 strnlen(ccSerial
, sizeof(tokInfo
.serialNumber
)));
94 mTokenSerialNum
.Trim(" ", false, true);
99 nsresult
nsPK11Token::GetAttributeHelper(const nsACString
& attribute
,
100 /*out*/ nsACString
& xpcomOutParam
) {
101 // Handle removals/insertions.
102 if (PK11_GetSlotSeries(mSlot
.get()) != mSeries
) {
103 nsresult rv
= refreshTokenInfo();
109 xpcomOutParam
= attribute
;
114 nsPK11Token::GetTokenName(/*out*/ nsACString
& tokenName
) {
115 return GetAttributeHelper(mTokenName
, tokenName
);
119 nsPK11Token::GetIsInternalKeyToken(/*out*/ bool* _retval
) {
120 NS_ENSURE_ARG_POINTER(_retval
);
121 *_retval
= mIsInternalKeyToken
;
126 nsPK11Token::GetTokenManID(/*out*/ nsACString
& tokenManufacturerID
) {
127 return GetAttributeHelper(mTokenManufacturerID
, tokenManufacturerID
);
131 nsPK11Token::GetTokenHWVersion(/*out*/ nsACString
& tokenHWVersion
) {
132 return GetAttributeHelper(mTokenHWVersion
, tokenHWVersion
);
136 nsPK11Token::GetTokenFWVersion(/*out*/ nsACString
& tokenFWVersion
) {
137 return GetAttributeHelper(mTokenFWVersion
, tokenFWVersion
);
141 nsPK11Token::GetTokenSerialNumber(/*out*/ nsACString
& tokenSerialNum
) {
142 return GetAttributeHelper(mTokenSerialNum
, tokenSerialNum
);
146 nsPK11Token::IsLoggedIn(bool* _retval
) {
147 NS_ENSURE_ARG_POINTER(_retval
);
148 *_retval
= PK11_IsLoggedIn(mSlot
.get(), 0);
153 nsPK11Token::Login(bool force
) {
156 rv
= this->NeedsLogin(&test
);
157 if (NS_FAILED(rv
)) return rv
;
159 rv
= this->LogoutSimple();
160 if (NS_FAILED(rv
)) return rv
;
162 rv
= setPassword(mSlot
.get(), mUIContext
);
163 if (NS_FAILED(rv
)) return rv
;
165 return mozilla::MapSECStatus(
166 PK11_Authenticate(mSlot
.get(), true, mUIContext
));
170 nsPK11Token::LogoutSimple() {
171 // PK11_Logout() can fail if the user wasn't logged in beforehand. We want
172 // this method to succeed even in this case, so we ignore the return value.
173 mozilla::Unused
<< PK11_Logout(mSlot
.get());
178 nsPK11Token::LogoutAndDropAuthenticatedResources() {
179 static NS_DEFINE_CID(kNSSComponentCID
, NS_NSSCOMPONENT_CID
);
181 nsresult rv
= LogoutSimple();
183 if (NS_FAILED(rv
)) return rv
;
185 nsCOMPtr
<nsINSSComponent
> nssComponent(do_GetService(kNSSComponentCID
, &rv
));
186 if (NS_FAILED(rv
)) return rv
;
188 return nssComponent
->LogoutAuthenticatedPK11();
192 nsPK11Token::Reset() {
193 return mozilla::MapSECStatus(PK11_ResetToken(mSlot
.get(), nullptr));
197 nsPK11Token::GetNeedsUserInit(bool* aNeedsUserInit
) {
198 NS_ENSURE_ARG_POINTER(aNeedsUserInit
);
199 *aNeedsUserInit
= PK11_NeedUserInit(mSlot
.get());
204 nsPK11Token::CheckPassword(const nsACString
& password
, bool* _retval
) {
205 NS_ENSURE_ARG_POINTER(_retval
);
207 PK11_CheckUserPassword(mSlot
.get(), PromiseFlatCString(password
).get());
208 if (srv
!= SECSuccess
) {
210 PRErrorCode error
= PR_GetError();
211 if (error
!= SEC_ERROR_BAD_PASSWORD
) {
212 /* something really bad happened - throw an exception */
213 return mozilla::psm::GetXPCOMFromNSSError(error
);
222 nsPK11Token::InitPassword(const nsACString
& initialPassword
) {
223 const nsCString
& passwordCStr
= PromiseFlatCString(initialPassword
);
224 // PSM initializes the sqlite-backed softoken with an empty password. The
225 // implementation considers this not to be a password (GetHasPassword returns
226 // false), but we can't actually call PK11_InitPin again. Instead, we call
227 // PK11_ChangePW with the empty password.
229 nsresult rv
= GetHasPassword(&hasPassword
);
233 if (!PK11_NeedUserInit(mSlot
.get()) && !hasPassword
) {
234 return mozilla::MapSECStatus(
235 PK11_ChangePW(mSlot
.get(), "", passwordCStr
.get()));
237 return mozilla::MapSECStatus(
238 PK11_InitPin(mSlot
.get(), "", passwordCStr
.get()));
242 nsPK11Token::ChangePassword(const nsACString
& oldPassword
,
243 const nsACString
& newPassword
) {
244 // PK11_ChangePW() has different semantics for the empty string and for
245 // nullptr. In order to support this difference, we need to check IsVoid() to
246 // find out if our caller supplied null/undefined args or just empty strings.
248 return mozilla::MapSECStatus(PK11_ChangePW(
250 oldPassword
.IsVoid() ? nullptr : PromiseFlatCString(oldPassword
).get(),
251 newPassword
.IsVoid() ? nullptr : PromiseFlatCString(newPassword
).get()));
255 nsPK11Token::GetHasPassword(bool* hasPassword
) {
256 NS_ENSURE_ARG_POINTER(hasPassword
);
257 // PK11_NeedLogin returns true if the token is currently configured to require
258 // the user to log in (whether or not the user is actually logged in makes no
260 *hasPassword
= PK11_NeedLogin(mSlot
.get()) && !PK11_NeedUserInit(mSlot
.get());
265 nsPK11Token::NeedsLogin(bool* _retval
) {
266 NS_ENSURE_ARG_POINTER(_retval
);
267 *_retval
= PK11_NeedLogin(mSlot
.get());
271 /*=========================================================*/
273 NS_IMPL_ISUPPORTS(nsPK11TokenDB
, nsIPK11TokenDB
)
276 nsPK11TokenDB::GetInternalKeyToken(nsIPK11Token
** _retval
) {
277 NS_ENSURE_ARG_POINTER(_retval
);
278 mozilla::UniquePK11SlotInfo
slot(PK11_GetInternalKeySlot());
280 return NS_ERROR_FAILURE
;
283 nsCOMPtr
<nsIPK11Token
> token
= new nsPK11Token(slot
.get());
284 token
.forget(_retval
);