Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=2 et sw=2 tw=80: */
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 file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "nsIIdentityCryptoService.h"
8 : #include "mozilla/ModuleUtils.h"
9 : #include "nsServiceManagerUtils.h"
10 : #include "nsNSSShutDown.h"
11 : #include "nsIThread.h"
12 : #include "nsThreadUtils.h"
13 : #include "nsCOMPtr.h"
14 : #include "nsProxyRelease.h"
15 : #include "nsString.h"
16 : #include "mozilla/ArrayUtils.h" // ArrayLength
17 : #include "mozilla/Base64.h"
18 : #include "ScopedNSSTypes.h"
19 : #include "NSSErrorsService.h"
20 :
21 : #include "nss.h"
22 : #include "pk11pub.h"
23 : #include "secmod.h"
24 : #include "secerr.h"
25 : #include "keyhi.h"
26 : #include "cryptohi.h"
27 :
28 : #include <limits.h>
29 :
30 : using namespace mozilla;
31 :
32 : namespace {
33 :
34 : void
35 0 : HexEncode(const SECItem * it, nsACString & result)
36 : {
37 0 : const char * digits = "0123456789ABCDEF";
38 0 : result.SetCapacity((it->len * 2) + 1);
39 0 : result.SetLength(it->len * 2);
40 0 : char * p = result.BeginWriting();
41 0 : for (unsigned int i = 0; i < it->len; ++i) {
42 0 : *p++ = digits[it->data[i] >> 4];
43 0 : *p++ = digits[it->data[i] & 0x0f];
44 : }
45 0 : }
46 :
47 : #define DSA_KEY_TYPE_STRING (NS_LITERAL_CSTRING("DS160"))
48 : #define RSA_KEY_TYPE_STRING (NS_LITERAL_CSTRING("RS256"))
49 :
50 : class KeyPair : public nsIIdentityKeyPair, public nsNSSShutDownObject
51 : {
52 : public:
53 : NS_DECL_THREADSAFE_ISUPPORTS
54 : NS_DECL_NSIIDENTITYKEYPAIR
55 :
56 : KeyPair(SECKEYPrivateKey* aPrivateKey, SECKEYPublicKey* aPublicKey,
57 : nsIEventTarget* aOperationThread);
58 :
59 : private:
60 0 : ~KeyPair() override
61 0 : {
62 0 : nsNSSShutDownPreventionLock locker;
63 0 : if (isAlreadyShutDown()) {
64 0 : return;
65 : }
66 0 : destructorSafeDestroyNSSReference();
67 0 : shutdown(ShutdownCalledFrom::Object);
68 0 : }
69 :
70 0 : void virtualDestroyNSSReference() override
71 : {
72 0 : destructorSafeDestroyNSSReference();
73 0 : }
74 :
75 0 : void destructorSafeDestroyNSSReference()
76 : {
77 0 : SECKEY_DestroyPrivateKey(mPrivateKey);
78 0 : mPrivateKey = nullptr;
79 0 : SECKEY_DestroyPublicKey(mPublicKey);
80 0 : mPublicKey = nullptr;
81 0 : }
82 :
83 : SECKEYPrivateKey * mPrivateKey;
84 : SECKEYPublicKey * mPublicKey;
85 : nsCOMPtr<nsIEventTarget> mThread;
86 :
87 : KeyPair(const KeyPair &) = delete;
88 : void operator=(const KeyPair &) = delete;
89 : };
90 :
91 0 : NS_IMPL_ISUPPORTS(KeyPair, nsIIdentityKeyPair)
92 :
93 : class KeyGenRunnable : public Runnable, public nsNSSShutDownObject
94 : {
95 : public:
96 : NS_DECL_NSIRUNNABLE
97 :
98 : KeyGenRunnable(KeyType keyType, nsIIdentityKeyGenCallback * aCallback,
99 : nsIEventTarget* aOperationThread);
100 :
101 : private:
102 0 : ~KeyGenRunnable() override
103 0 : {
104 0 : nsNSSShutDownPreventionLock locker;
105 0 : if (isAlreadyShutDown()) {
106 0 : return;
107 : }
108 0 : destructorSafeDestroyNSSReference();
109 0 : shutdown(ShutdownCalledFrom::Object);
110 0 : }
111 :
112 0 : void virtualDestroyNSSReference() override
113 : {
114 0 : destructorSafeDestroyNSSReference();
115 0 : }
116 :
117 0 : void destructorSafeDestroyNSSReference()
118 : {
119 0 : }
120 :
121 : const KeyType mKeyType; // in
122 : nsMainThreadPtrHandle<nsIIdentityKeyGenCallback> mCallback; // in
123 : nsresult mRv; // out
124 : nsCOMPtr<nsIIdentityKeyPair> mKeyPair; // out
125 : nsCOMPtr<nsIEventTarget> mThread;
126 :
127 : KeyGenRunnable(const KeyGenRunnable &) = delete;
128 : void operator=(const KeyGenRunnable &) = delete;
129 : };
130 :
131 : class SignRunnable : public Runnable, public nsNSSShutDownObject
132 : {
133 : public:
134 : NS_DECL_NSIRUNNABLE
135 :
136 : SignRunnable(const nsACString & textToSign, SECKEYPrivateKey * privateKey,
137 : nsIIdentitySignCallback * aCallback);
138 :
139 : private:
140 0 : ~SignRunnable() override
141 0 : {
142 0 : nsNSSShutDownPreventionLock locker;
143 0 : if (isAlreadyShutDown()) {
144 0 : return;
145 : }
146 0 : destructorSafeDestroyNSSReference();
147 0 : shutdown(ShutdownCalledFrom::Object);
148 0 : }
149 :
150 0 : void virtualDestroyNSSReference() override
151 : {
152 0 : destructorSafeDestroyNSSReference();
153 0 : }
154 :
155 0 : void destructorSafeDestroyNSSReference()
156 : {
157 0 : SECKEY_DestroyPrivateKey(mPrivateKey);
158 0 : mPrivateKey = nullptr;
159 0 : }
160 :
161 : const nsCString mTextToSign; // in
162 : SECKEYPrivateKey* mPrivateKey; // in
163 : nsMainThreadPtrHandle<nsIIdentitySignCallback> mCallback; // in
164 : nsresult mRv; // out
165 : nsCString mSignature; // out
166 :
167 : private:
168 : SignRunnable(const SignRunnable &) = delete;
169 : void operator=(const SignRunnable &) = delete;
170 : };
171 :
172 : class IdentityCryptoService final : public nsIIdentityCryptoService
173 : {
174 : public:
175 : NS_DECL_THREADSAFE_ISUPPORTS
176 : NS_DECL_NSIIDENTITYCRYPTOSERVICE
177 :
178 0 : IdentityCryptoService() = default;
179 0 : nsresult Init()
180 : {
181 : nsresult rv;
182 : nsCOMPtr<nsISupports> dummyUsedToEnsureNSSIsInitialized
183 0 : = do_GetService("@mozilla.org/psm;1", &rv);
184 0 : NS_ENSURE_SUCCESS(rv, rv);
185 :
186 0 : nsCOMPtr<nsIThread> thread;
187 0 : rv = NS_NewNamedThread("IdentityCrypto", getter_AddRefs(thread));
188 0 : NS_ENSURE_SUCCESS(rv, rv);
189 :
190 0 : mThread = thread.forget();
191 :
192 0 : return NS_OK;
193 : }
194 :
195 : private:
196 0 : ~IdentityCryptoService() = default;
197 : IdentityCryptoService(const KeyPair &) = delete;
198 : void operator=(const IdentityCryptoService &) = delete;
199 :
200 : nsCOMPtr<nsIEventTarget> mThread;
201 : };
202 :
203 0 : NS_IMPL_ISUPPORTS(IdentityCryptoService, nsIIdentityCryptoService)
204 :
205 : NS_IMETHODIMP
206 0 : IdentityCryptoService::GenerateKeyPair(
207 : const nsACString & keyTypeString, nsIIdentityKeyGenCallback * callback)
208 : {
209 : KeyType keyType;
210 0 : if (keyTypeString.Equals(RSA_KEY_TYPE_STRING)) {
211 0 : keyType = rsaKey;
212 0 : } else if (keyTypeString.Equals(DSA_KEY_TYPE_STRING)) {
213 0 : keyType = dsaKey;
214 : } else {
215 0 : return NS_ERROR_UNEXPECTED;
216 : }
217 :
218 0 : nsCOMPtr<nsIRunnable> r = new KeyGenRunnable(keyType, callback, mThread);
219 0 : nsresult rv = mThread->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
220 0 : NS_ENSURE_SUCCESS(rv, rv);
221 :
222 0 : return NS_OK;
223 : }
224 :
225 : NS_IMETHODIMP
226 0 : IdentityCryptoService::Base64UrlEncode(const nsACString & utf8Input,
227 : nsACString & result)
228 : {
229 0 : return Base64URLEncode(utf8Input.Length(),
230 0 : reinterpret_cast<const uint8_t*>(utf8Input.BeginReading()),
231 0 : Base64URLEncodePaddingPolicy::Include, result);
232 : }
233 :
234 0 : KeyPair::KeyPair(SECKEYPrivateKey * privateKey, SECKEYPublicKey * publicKey,
235 0 : nsIEventTarget* operationThread)
236 : : mPrivateKey(privateKey)
237 : , mPublicKey(publicKey)
238 0 : , mThread(operationThread)
239 : {
240 0 : MOZ_ASSERT(!NS_IsMainThread());
241 0 : }
242 :
243 : NS_IMETHODIMP
244 0 : KeyPair::GetHexRSAPublicKeyExponent(nsACString & result)
245 : {
246 0 : MOZ_ASSERT(NS_IsMainThread());
247 0 : NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE);
248 0 : NS_ENSURE_TRUE(mPublicKey->keyType == rsaKey, NS_ERROR_NOT_AVAILABLE);
249 0 : HexEncode(&mPublicKey->u.rsa.publicExponent, result);
250 0 : return NS_OK;
251 : }
252 :
253 : NS_IMETHODIMP
254 0 : KeyPair::GetHexRSAPublicKeyModulus(nsACString & result)
255 : {
256 0 : MOZ_ASSERT(NS_IsMainThread());
257 0 : NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE);
258 0 : NS_ENSURE_TRUE(mPublicKey->keyType == rsaKey, NS_ERROR_NOT_AVAILABLE);
259 0 : HexEncode(&mPublicKey->u.rsa.modulus, result);
260 0 : return NS_OK;
261 : }
262 :
263 : NS_IMETHODIMP
264 0 : KeyPair::GetHexDSAPrime(nsACString & result)
265 : {
266 0 : MOZ_ASSERT(NS_IsMainThread());
267 0 : NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE);
268 0 : NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE);
269 0 : HexEncode(&mPublicKey->u.dsa.params.prime, result);
270 0 : return NS_OK;
271 : }
272 :
273 : NS_IMETHODIMP
274 0 : KeyPair::GetHexDSASubPrime(nsACString & result)
275 : {
276 0 : MOZ_ASSERT(NS_IsMainThread());
277 0 : NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE);
278 0 : NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE);
279 0 : HexEncode(&mPublicKey->u.dsa.params.subPrime, result);
280 0 : return NS_OK;
281 : }
282 :
283 : NS_IMETHODIMP
284 0 : KeyPair::GetHexDSAGenerator(nsACString & result)
285 : {
286 0 : MOZ_ASSERT(NS_IsMainThread());
287 0 : NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE);
288 0 : NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE);
289 0 : HexEncode(&mPublicKey->u.dsa.params.base, result);
290 0 : return NS_OK;
291 : }
292 :
293 : NS_IMETHODIMP
294 0 : KeyPair::GetHexDSAPublicValue(nsACString & result)
295 : {
296 0 : MOZ_ASSERT(NS_IsMainThread());
297 0 : NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE);
298 0 : NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE);
299 0 : HexEncode(&mPublicKey->u.dsa.publicValue, result);
300 0 : return NS_OK;
301 : }
302 :
303 : NS_IMETHODIMP
304 0 : KeyPair::GetKeyType(nsACString & result)
305 : {
306 0 : MOZ_ASSERT(NS_IsMainThread());
307 0 : NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE);
308 :
309 0 : switch (mPublicKey->keyType) {
310 0 : case rsaKey: result = RSA_KEY_TYPE_STRING; return NS_OK;
311 0 : case dsaKey: result = DSA_KEY_TYPE_STRING; return NS_OK;
312 0 : default: return NS_ERROR_UNEXPECTED;
313 : }
314 : }
315 :
316 : NS_IMETHODIMP
317 0 : KeyPair::Sign(const nsACString & textToSign,
318 : nsIIdentitySignCallback* callback)
319 : {
320 0 : MOZ_ASSERT(NS_IsMainThread());
321 : nsCOMPtr<nsIRunnable> r = new SignRunnable(textToSign, mPrivateKey,
322 0 : callback);
323 :
324 0 : return mThread->Dispatch(r, NS_DISPATCH_NORMAL);
325 : }
326 :
327 0 : KeyGenRunnable::KeyGenRunnable(KeyType keyType,
328 : nsIIdentityKeyGenCallback* callback,
329 0 : nsIEventTarget* operationThread)
330 : : mozilla::Runnable("KeyGenRunnable")
331 : , mKeyType(keyType)
332 : , mCallback(new nsMainThreadPtrHolder<nsIIdentityKeyGenCallback>(
333 0 : "KeyGenRunnable::mCallback", callback))
334 : , mRv(NS_ERROR_NOT_INITIALIZED)
335 0 : , mThread(operationThread)
336 : {
337 0 : }
338 :
339 : MOZ_MUST_USE nsresult
340 0 : GenerateKeyPair(PK11SlotInfo * slot,
341 : SECKEYPrivateKey ** privateKey,
342 : SECKEYPublicKey ** publicKey,
343 : CK_MECHANISM_TYPE mechanism,
344 : void * params)
345 : {
346 0 : *publicKey = nullptr;
347 0 : *privateKey = PK11_GenerateKeyPair(slot, mechanism, params, publicKey,
348 : PR_FALSE /*isPerm*/,
349 : PR_TRUE /*isSensitive*/,
350 : nullptr /*&pwdata*/);
351 0 : if (!*privateKey) {
352 0 : MOZ_ASSERT(!*publicKey);
353 0 : return mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
354 : }
355 0 : if (!*publicKey) {
356 0 : SECKEY_DestroyPrivateKey(*privateKey);
357 0 : *privateKey = nullptr;
358 0 : MOZ_CRASH("PK11_GnerateKeyPair returned private key without public key");
359 : }
360 :
361 0 : return NS_OK;
362 : }
363 :
364 :
365 : MOZ_MUST_USE nsresult
366 0 : GenerateRSAKeyPair(PK11SlotInfo * slot,
367 : SECKEYPrivateKey ** privateKey,
368 : SECKEYPublicKey ** publicKey)
369 : {
370 0 : MOZ_ASSERT(!NS_IsMainThread());
371 :
372 : PK11RSAGenParams rsaParams;
373 0 : rsaParams.keySizeInBits = 2048;
374 0 : rsaParams.pe = 0x10001;
375 : return GenerateKeyPair(slot, privateKey, publicKey, CKM_RSA_PKCS_KEY_PAIR_GEN,
376 0 : &rsaParams);
377 : }
378 :
379 : MOZ_MUST_USE nsresult
380 0 : GenerateDSAKeyPair(PK11SlotInfo * slot,
381 : SECKEYPrivateKey ** privateKey,
382 : SECKEYPublicKey ** publicKey)
383 : {
384 0 : MOZ_ASSERT(!NS_IsMainThread());
385 :
386 : // XXX: These could probably be static const arrays, but this way we avoid
387 : // compiler warnings and also we avoid having to worry much about whether the
388 : // functions that take these inputs will (unexpectedly) modify them.
389 :
390 : // Using NIST parameters. Some other BrowserID components require that these
391 : // exact parameters are used.
392 : uint8_t P[] = {
393 : 0xFF,0x60,0x04,0x83,0xDB,0x6A,0xBF,0xC5,0xB4,0x5E,0xAB,0x78,
394 : 0x59,0x4B,0x35,0x33,0xD5,0x50,0xD9,0xF1,0xBF,0x2A,0x99,0x2A,
395 : 0x7A,0x8D,0xAA,0x6D,0xC3,0x4F,0x80,0x45,0xAD,0x4E,0x6E,0x0C,
396 : 0x42,0x9D,0x33,0x4E,0xEE,0xAA,0xEF,0xD7,0xE2,0x3D,0x48,0x10,
397 : 0xBE,0x00,0xE4,0xCC,0x14,0x92,0xCB,0xA3,0x25,0xBA,0x81,0xFF,
398 : 0x2D,0x5A,0x5B,0x30,0x5A,0x8D,0x17,0xEB,0x3B,0xF4,0xA0,0x6A,
399 : 0x34,0x9D,0x39,0x2E,0x00,0xD3,0x29,0x74,0x4A,0x51,0x79,0x38,
400 : 0x03,0x44,0xE8,0x2A,0x18,0xC4,0x79,0x33,0x43,0x8F,0x89,0x1E,
401 : 0x22,0xAE,0xEF,0x81,0x2D,0x69,0xC8,0xF7,0x5E,0x32,0x6C,0xB7,
402 : 0x0E,0xA0,0x00,0xC3,0xF7,0x76,0xDF,0xDB,0xD6,0x04,0x63,0x8C,
403 : 0x2E,0xF7,0x17,0xFC,0x26,0xD0,0x2E,0x17
404 0 : };
405 :
406 : uint8_t Q[] = {
407 : 0xE2,0x1E,0x04,0xF9,0x11,0xD1,0xED,0x79,0x91,0x00,0x8E,0xCA,
408 : 0xAB,0x3B,0xF7,0x75,0x98,0x43,0x09,0xC3
409 0 : };
410 :
411 : uint8_t G[] = {
412 : 0xC5,0x2A,0x4A,0x0F,0xF3,0xB7,0xE6,0x1F,0xDF,0x18,0x67,0xCE,
413 : 0x84,0x13,0x83,0x69,0xA6,0x15,0x4F,0x4A,0xFA,0x92,0x96,0x6E,
414 : 0x3C,0x82,0x7E,0x25,0xCF,0xA6,0xCF,0x50,0x8B,0x90,0xE5,0xDE,
415 : 0x41,0x9E,0x13,0x37,0xE0,0x7A,0x2E,0x9E,0x2A,0x3C,0xD5,0xDE,
416 : 0xA7,0x04,0xD1,0x75,0xF8,0xEB,0xF6,0xAF,0x39,0x7D,0x69,0xE1,
417 : 0x10,0xB9,0x6A,0xFB,0x17,0xC7,0xA0,0x32,0x59,0x32,0x9E,0x48,
418 : 0x29,0xB0,0xD0,0x3B,0xBC,0x78,0x96,0xB1,0x5B,0x4A,0xDE,0x53,
419 : 0xE1,0x30,0x85,0x8C,0xC3,0x4D,0x96,0x26,0x9A,0xA8,0x90,0x41,
420 : 0xF4,0x09,0x13,0x6C,0x72,0x42,0xA3,0x88,0x95,0xC9,0xD5,0xBC,
421 : 0xCA,0xD4,0xF3,0x89,0xAF,0x1D,0x7A,0x4B,0xD1,0x39,0x8B,0xD0,
422 : 0x72,0xDF,0xFA,0x89,0x62,0x33,0x39,0x7A
423 0 : };
424 :
425 : static_assert(MOZ_ARRAY_LENGTH(P) == 1024 / CHAR_BIT, "bad DSA P");
426 : static_assert(MOZ_ARRAY_LENGTH(Q) == 160 / CHAR_BIT, "bad DSA Q");
427 : static_assert(MOZ_ARRAY_LENGTH(G) == 1024 / CHAR_BIT, "bad DSA G");
428 :
429 : PQGParams pqgParams = {
430 : nullptr /*arena*/,
431 : { siBuffer, P, static_cast<unsigned int>(mozilla::ArrayLength(P)) },
432 : { siBuffer, Q, static_cast<unsigned int>(mozilla::ArrayLength(Q)) },
433 : { siBuffer, G, static_cast<unsigned int>(mozilla::ArrayLength(G)) }
434 0 : };
435 :
436 : return GenerateKeyPair(slot, privateKey, publicKey, CKM_DSA_KEY_PAIR_GEN,
437 0 : &pqgParams);
438 : }
439 :
440 : NS_IMETHODIMP
441 0 : KeyGenRunnable::Run()
442 : {
443 0 : if (!NS_IsMainThread()) {
444 0 : nsNSSShutDownPreventionLock locker;
445 0 : if (isAlreadyShutDown()) {
446 0 : mRv = NS_ERROR_NOT_AVAILABLE;
447 : } else {
448 : // We always want to use the internal slot for BrowserID; in particular,
449 : // we want to avoid smartcard slots.
450 0 : PK11SlotInfo *slot = PK11_GetInternalSlot();
451 0 : if (!slot) {
452 0 : mRv = NS_ERROR_UNEXPECTED;
453 : } else {
454 0 : SECKEYPrivateKey *privk = nullptr;
455 0 : SECKEYPublicKey *pubk = nullptr;
456 :
457 0 : switch (mKeyType) {
458 : case rsaKey:
459 0 : mRv = GenerateRSAKeyPair(slot, &privk, &pubk);
460 0 : break;
461 : case dsaKey:
462 0 : mRv = GenerateDSAKeyPair(slot, &privk, &pubk);
463 0 : break;
464 : default:
465 0 : MOZ_CRASH("unknown key type");
466 : }
467 :
468 0 : PK11_FreeSlot(slot);
469 :
470 0 : if (NS_SUCCEEDED(mRv)) {
471 0 : MOZ_ASSERT(privk);
472 0 : MOZ_ASSERT(pubk);
473 : // mKeyPair will take over ownership of privk and pubk
474 0 : mKeyPair = new KeyPair(privk, pubk, mThread);
475 : }
476 : }
477 : }
478 :
479 0 : NS_DispatchToMainThread(this);
480 : } else {
481 : // Back on Main Thread
482 0 : (void) mCallback->GenerateKeyPairFinished(mRv, mKeyPair);
483 : }
484 0 : return NS_OK;
485 : }
486 :
487 0 : SignRunnable::SignRunnable(const nsACString& aText,
488 : SECKEYPrivateKey* privateKey,
489 0 : nsIIdentitySignCallback* aCallback)
490 : : mozilla::Runnable("SignRunnable")
491 : , mTextToSign(aText)
492 0 : , mPrivateKey(SECKEY_CopyPrivateKey(privateKey))
493 : , mCallback(new nsMainThreadPtrHolder<nsIIdentitySignCallback>(
494 0 : "SignRunnable::mCallback", aCallback))
495 0 : , mRv(NS_ERROR_NOT_INITIALIZED)
496 : {
497 0 : }
498 :
499 : NS_IMETHODIMP
500 0 : SignRunnable::Run()
501 : {
502 0 : if (!NS_IsMainThread()) {
503 0 : nsNSSShutDownPreventionLock locker;
504 0 : if (isAlreadyShutDown()) {
505 0 : mRv = NS_ERROR_NOT_AVAILABLE;
506 : } else {
507 : // We need the output in PKCS#11 format, not DER encoding, so we must use
508 : // PK11_HashBuf and PK11_Sign instead of SEC_SignData.
509 :
510 0 : SECItem sig = { siBuffer, nullptr, 0 };
511 0 : int sigLength = PK11_SignatureLen(mPrivateKey);
512 0 : if (sigLength <= 0) {
513 0 : mRv = mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
514 0 : } else if (!SECITEM_AllocItem(nullptr, &sig, sigLength)) {
515 0 : mRv = mozilla::psm::GetXPCOMFromNSSError(PR_GetError());
516 : } else {
517 : uint8_t hash[32]; // big enough for SHA-1 or SHA-256
518 0 : SECOidTag hashAlg = mPrivateKey->keyType == dsaKey ? SEC_OID_SHA1
519 0 : : SEC_OID_SHA256;
520 : SECItem hashItem = { siBuffer, hash,
521 0 : hashAlg == SEC_OID_SHA1 ? 20u : 32u };
522 :
523 0 : mRv = MapSECStatus(PK11_HashBuf(hashAlg, hash,
524 : const_cast<uint8_t*>(reinterpret_cast<const uint8_t *>(
525 0 : mTextToSign.get())),
526 0 : mTextToSign.Length()));
527 0 : if (NS_SUCCEEDED(mRv)) {
528 0 : mRv = MapSECStatus(PK11_Sign(mPrivateKey, &sig, &hashItem));
529 : }
530 0 : if (NS_SUCCEEDED(mRv)) {
531 0 : mRv = Base64URLEncode(sig.len, sig.data,
532 : Base64URLEncodePaddingPolicy::Include,
533 : mSignature);
534 : }
535 0 : SECITEM_FreeItem(&sig, false);
536 : }
537 : }
538 :
539 0 : NS_DispatchToMainThread(this);
540 : } else {
541 : // Back on Main Thread
542 0 : (void) mCallback->SignFinished(mRv, mSignature);
543 : }
544 :
545 0 : return NS_OK;
546 : }
547 :
548 : // XPCOM module registration
549 :
550 0 : NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(IdentityCryptoService, Init)
551 :
552 : #define NS_IDENTITYCRYPTOSERVICE_CID \
553 : {0xbea13a3a, 0x44e8, 0x4d7f, {0xa0, 0xa2, 0x2c, 0x67, 0xf8, 0x4e, 0x3a, 0x97}}
554 :
555 : NS_DEFINE_NAMED_CID(NS_IDENTITYCRYPTOSERVICE_CID);
556 :
557 : const mozilla::Module::CIDEntry kCIDs[] = {
558 : { &kNS_IDENTITYCRYPTOSERVICE_CID, false, nullptr, IdentityCryptoServiceConstructor },
559 : { nullptr }
560 : };
561 :
562 : const mozilla::Module::ContractIDEntry kContracts[] = {
563 : { "@mozilla.org/identity/crypto-service;1", &kNS_IDENTITYCRYPTOSERVICE_CID },
564 : { nullptr }
565 : };
566 :
567 : const mozilla::Module kModule = {
568 : mozilla::Module::kVersion,
569 : kCIDs,
570 : kContracts
571 : };
572 :
573 : } // unnamed namespace
574 :
575 : NSMODULE_DEFN(identity) = &kModule;
|