Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/manager/ssl/nsPK11TokenDB.cpp
Line
Count
Source (jump to first uncovered line)
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
#include "nsPK11TokenDB.h"
7
8
#include <string.h>
9
10
#include "ScopedNSSTypes.h"
11
#include "mozilla/Casting.h"
12
#include "mozilla/Unused.h"
13
#include "nsISupports.h"
14
#include "nsNSSComponent.h"
15
#include "nsPromiseFlatString.h"
16
#include "nsReadableUtils.h"
17
#include "nsServiceManagerUtils.h"
18
#include "prerror.h"
19
#include "secerr.h"
20
21
extern mozilla::LazyLogModule gPIPNSSLog;
22
23
NS_IMPL_ISUPPORTS(nsPK11Token, nsIPK11Token)
24
25
nsPK11Token::nsPK11Token(PK11SlotInfo* slot)
26
  : mUIContext(new PipUIContext())
27
0
{
28
0
  MOZ_ASSERT(slot);
29
0
  mSlot.reset(PK11_ReferenceSlot(slot));
30
0
  mIsInternalCryptoToken = PK11_IsInternal(mSlot.get()) &&
31
0
                           !PK11_IsInternalKeySlot(mSlot.get());
32
0
  mIsInternalKeyToken = PK11_IsInternalKeySlot(mSlot.get());
33
0
  mSeries = PK11_GetSlotSeries(slot);
34
0
  Unused << refreshTokenInfo();
35
0
}
36
37
nsresult
38
nsPK11Token::refreshTokenInfo()
39
0
{
40
0
  if (mIsInternalCryptoToken) {
41
0
    nsresult rv;
42
0
    if (PK11_IsFIPS()) {
43
0
      rv = GetPIPNSSBundleString("Fips140TokenDescription", mTokenName);
44
0
    } else {
45
0
      rv = GetPIPNSSBundleString("TokenDescription", mTokenName);
46
0
    }
47
0
    if (NS_FAILED(rv)) {
48
0
      return rv;
49
0
    }
50
0
  } else if (mIsInternalKeyToken) {
51
0
    nsresult rv = GetPIPNSSBundleString("PrivateTokenDescription", mTokenName);
52
0
    if (NS_FAILED(rv)) {
53
0
      return rv;
54
0
    }
55
0
  } else {
56
0
    mTokenName.Assign(PK11_GetTokenName(mSlot.get()));
57
0
  }
58
0
59
0
  CK_TOKEN_INFO tokInfo;
60
0
  nsresult rv = MapSECStatus(PK11_GetTokenInfo(mSlot.get(), &tokInfo));
61
0
  if (NS_FAILED(rv)) {
62
0
    return rv;
63
0
  }
64
0
65
0
  // Set the Manufacturer field
66
0
  if (mIsInternalCryptoToken || mIsInternalKeyToken) {
67
0
    rv = GetPIPNSSBundleString("ManufacturerID", mTokenManufacturerID);
68
0
    if (NS_FAILED(rv)) {
69
0
      return rv;
70
0
    }
71
0
  } else {
72
0
    const char* ccManID =
73
0
      mozilla::BitwiseCast<char*, CK_UTF8CHAR*>(tokInfo.manufacturerID);
74
0
    mTokenManufacturerID.Assign(
75
0
      ccManID,
76
0
      strnlen(ccManID, sizeof(tokInfo.manufacturerID)));
77
0
    mTokenManufacturerID.Trim(" ", false, true);
78
0
  }
79
0
80
0
  // Set the Hardware Version field
81
0
  mTokenHWVersion.Truncate();
82
0
  mTokenHWVersion.AppendInt(tokInfo.hardwareVersion.major);
83
0
  mTokenHWVersion.Append('.');
84
0
  mTokenHWVersion.AppendInt(tokInfo.hardwareVersion.minor);
85
0
86
0
  // Set the Firmware Version field
87
0
  mTokenFWVersion.Truncate();
88
0
  mTokenFWVersion.AppendInt(tokInfo.firmwareVersion.major);
89
0
  mTokenFWVersion.Append('.');
90
0
  mTokenFWVersion.AppendInt(tokInfo.firmwareVersion.minor);
91
0
92
0
  // Set the Serial Number field
93
0
  const char* ccSerial =
94
0
    mozilla::BitwiseCast<char*, CK_CHAR*>(tokInfo.serialNumber);
95
0
  mTokenSerialNum.Assign(ccSerial,
96
0
                         strnlen(ccSerial, sizeof(tokInfo.serialNumber)));
97
0
  mTokenSerialNum.Trim(" ", false, true);
98
0
99
0
  return NS_OK;
100
0
}
101
102
nsresult
103
nsPK11Token::GetAttributeHelper(const nsACString& attribute,
104
                        /*out*/ nsACString& xpcomOutParam)
105
0
{
106
0
  // Handle removals/insertions.
107
0
  if (PK11_GetSlotSeries(mSlot.get()) != mSeries) {
108
0
    nsresult rv = refreshTokenInfo();
109
0
    if (NS_FAILED(rv)) {
110
0
      return rv;
111
0
    }
112
0
  }
113
0
114
0
  xpcomOutParam = attribute;
115
0
  return NS_OK;
116
0
}
117
118
NS_IMETHODIMP
119
nsPK11Token::GetTokenName(/*out*/ nsACString& tokenName)
120
0
{
121
0
  return GetAttributeHelper(mTokenName, tokenName);
122
0
}
123
124
NS_IMETHODIMP
125
nsPK11Token::GetIsInternalKeyToken(/*out*/ bool* _retval)
126
0
{
127
0
  NS_ENSURE_ARG_POINTER(_retval);
128
0
  *_retval = mIsInternalKeyToken;
129
0
  return NS_OK;
130
0
}
131
132
NS_IMETHODIMP
133
nsPK11Token::GetTokenManID(/*out*/ nsACString& tokenManufacturerID)
134
0
{
135
0
  return GetAttributeHelper(mTokenManufacturerID, tokenManufacturerID);
136
0
}
137
138
NS_IMETHODIMP
139
nsPK11Token::GetTokenHWVersion(/*out*/ nsACString& tokenHWVersion)
140
0
{
141
0
  return GetAttributeHelper(mTokenHWVersion, tokenHWVersion);
142
0
}
143
144
NS_IMETHODIMP
145
nsPK11Token::GetTokenFWVersion(/*out*/ nsACString& tokenFWVersion)
146
0
{
147
0
  return GetAttributeHelper(mTokenFWVersion, tokenFWVersion);
148
0
}
149
150
NS_IMETHODIMP
151
nsPK11Token::GetTokenSerialNumber(/*out*/ nsACString& tokenSerialNum)
152
0
{
153
0
  return GetAttributeHelper(mTokenSerialNum, tokenSerialNum);
154
0
}
155
156
NS_IMETHODIMP
157
nsPK11Token::IsLoggedIn(bool* _retval)
158
0
{
159
0
  NS_ENSURE_ARG_POINTER(_retval);
160
0
  *_retval = PK11_IsLoggedIn(mSlot.get(), 0);
161
0
  return NS_OK;
162
0
}
163
164
NS_IMETHODIMP
165
nsPK11Token::Login(bool force)
166
0
{
167
0
  nsresult rv;
168
0
  bool test;
169
0
  rv = this->NeedsLogin(&test);
170
0
  if (NS_FAILED(rv)) return rv;
171
0
  if (test && force) {
172
0
    rv = this->LogoutSimple();
173
0
    if (NS_FAILED(rv)) return rv;
174
0
  }
175
0
  rv = setPassword(mSlot.get(), mUIContext);
176
0
  if (NS_FAILED(rv)) return rv;
177
0
178
0
  return MapSECStatus(PK11_Authenticate(mSlot.get(), true, mUIContext));
179
0
}
180
181
NS_IMETHODIMP
182
nsPK11Token::LogoutSimple()
183
0
{
184
0
  // PK11_Logout() can fail if the user wasn't logged in beforehand. We want
185
0
  // this method to succeed even in this case, so we ignore the return value.
186
0
  Unused << PK11_Logout(mSlot.get());
187
0
  return NS_OK;
188
0
}
189
190
NS_IMETHODIMP
191
nsPK11Token::LogoutAndDropAuthenticatedResources()
192
0
{
193
0
  static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID);
194
0
195
0
  nsresult rv = LogoutSimple();
196
0
197
0
  if (NS_FAILED(rv))
198
0
    return rv;
199
0
200
0
  nsCOMPtr<nsINSSComponent> nssComponent(do_GetService(kNSSComponentCID, &rv));
201
0
  if (NS_FAILED(rv))
202
0
    return rv;
203
0
204
0
  return nssComponent->LogoutAuthenticatedPK11();
205
0
}
206
207
NS_IMETHODIMP
208
nsPK11Token::Reset()
209
0
{
210
0
  return MapSECStatus(PK11_ResetToken(mSlot.get(), nullptr));
211
0
}
212
213
NS_IMETHODIMP
214
nsPK11Token::GetNeedsUserInit(bool* aNeedsUserInit)
215
0
{
216
0
  NS_ENSURE_ARG_POINTER(aNeedsUserInit);
217
0
  *aNeedsUserInit = PK11_NeedUserInit(mSlot.get());
218
0
  return NS_OK;
219
0
}
220
221
NS_IMETHODIMP
222
nsPK11Token::CheckPassword(const nsACString& password, bool* _retval)
223
0
{
224
0
  NS_ENSURE_ARG_POINTER(_retval);
225
0
  SECStatus srv =
226
0
    PK11_CheckUserPassword(mSlot.get(), PromiseFlatCString(password).get());
227
0
  if (srv != SECSuccess) {
228
0
    *_retval =  false;
229
0
    PRErrorCode error = PR_GetError();
230
0
    if (error != SEC_ERROR_BAD_PASSWORD) {
231
0
      /* something really bad happened - throw an exception */
232
0
      return mozilla::psm::GetXPCOMFromNSSError(error);
233
0
    }
234
0
  } else {
235
0
    *_retval =  true;
236
0
  }
237
0
  return NS_OK;
238
0
}
239
240
NS_IMETHODIMP
241
nsPK11Token::InitPassword(const nsACString& initialPassword)
242
0
{
243
0
  const nsCString& passwordCStr = PromiseFlatCString(initialPassword);
244
0
  // PSM initializes the sqlite-backed softoken with an empty password. The
245
0
  // implementation considers this not to be a password (GetHasPassword returns
246
0
  // false), but we can't actually call PK11_InitPin again. Instead, we call
247
0
  // PK11_ChangePW with the empty password.
248
0
  bool hasPassword;
249
0
  nsresult rv = GetHasPassword(&hasPassword);
250
0
  if (NS_FAILED(rv)) {
251
0
    return rv;
252
0
  }
253
0
  if (!PK11_NeedUserInit(mSlot.get()) && !hasPassword) {
254
0
    return MapSECStatus(PK11_ChangePW(mSlot.get(), "", passwordCStr.get()));
255
0
  }
256
0
  return MapSECStatus(PK11_InitPin(mSlot.get(), "", passwordCStr.get()));
257
0
}
258
259
NS_IMETHODIMP
260
nsPK11Token::ChangePassword(const nsACString& oldPassword,
261
                            const nsACString& newPassword)
262
0
{
263
0
  // PK11_ChangePW() has different semantics for the empty string and for
264
0
  // nullptr. In order to support this difference, we need to check IsVoid() to
265
0
  // find out if our caller supplied null/undefined args or just empty strings.
266
0
  // See Bug 447589.
267
0
  return MapSECStatus(PK11_ChangePW(
268
0
    mSlot.get(),
269
0
    oldPassword.IsVoid() ? nullptr : PromiseFlatCString(oldPassword).get(),
270
0
    newPassword.IsVoid() ? nullptr : PromiseFlatCString(newPassword).get()));
271
0
}
272
273
NS_IMETHODIMP
274
nsPK11Token::GetHasPassword(bool* hasPassword)
275
0
{
276
0
  NS_ENSURE_ARG_POINTER(hasPassword);
277
0
  // PK11_NeedLogin returns true if the token is currently configured to require
278
0
  // the user to log in (whether or not the user is actually logged in makes no
279
0
  // difference).
280
0
  *hasPassword = PK11_NeedLogin(mSlot.get()) && !PK11_NeedUserInit(mSlot.get());
281
0
  return NS_OK;
282
0
}
283
284
NS_IMETHODIMP
285
nsPK11Token::NeedsLogin(bool* _retval)
286
0
{
287
0
  NS_ENSURE_ARG_POINTER(_retval);
288
0
  *_retval = PK11_NeedLogin(mSlot.get());
289
0
  return NS_OK;
290
0
}
291
292
/*=========================================================*/
293
294
NS_IMPL_ISUPPORTS(nsPK11TokenDB, nsIPK11TokenDB)
295
296
NS_IMETHODIMP
297
nsPK11TokenDB::GetInternalKeyToken(nsIPK11Token** _retval)
298
0
{
299
0
  NS_ENSURE_ARG_POINTER(_retval);
300
0
  UniquePK11SlotInfo slot(PK11_GetInternalKeySlot());
301
0
  if (!slot) {
302
0
    return NS_ERROR_FAILURE;
303
0
  }
304
0
305
0
  nsCOMPtr<nsIPK11Token> token = new nsPK11Token(slot.get());
306
0
  token.forget(_retval);
307
0
308
0
  return NS_OK;
309
0
}