1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/identity/IdentityCryptoService.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,576 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.8 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "nsIIdentityCryptoService.h" 1.11 +#include "mozilla/ModuleUtils.h" 1.12 +#include "nsServiceManagerUtils.h" 1.13 +#include "nsNSSShutDown.h" 1.14 +#include "nsIThread.h" 1.15 +#include "nsThreadUtils.h" 1.16 +#include "nsCOMPtr.h" 1.17 +#include "nsProxyRelease.h" 1.18 +#include "nsString.h" 1.19 +#include "mozilla/ArrayUtils.h" // ArrayLength 1.20 +#include "mozilla/Base64.h" 1.21 +#include "ScopedNSSTypes.h" 1.22 + 1.23 +#include "nss.h" 1.24 +#include "pk11pub.h" 1.25 +#include "secmod.h" 1.26 +#include "secerr.h" 1.27 +#include "keyhi.h" 1.28 +#include "cryptohi.h" 1.29 + 1.30 +#include <limits.h> 1.31 + 1.32 +using namespace mozilla; 1.33 + 1.34 +namespace { 1.35 + 1.36 +void 1.37 +HexEncode(const SECItem * it, nsACString & result) 1.38 +{ 1.39 + const char * digits = "0123456789ABCDEF"; 1.40 + result.SetCapacity((it->len * 2) + 1); 1.41 + result.SetLength(it->len * 2); 1.42 + char * p = result.BeginWriting(); 1.43 + for (unsigned int i = 0; i < it->len; ++i) { 1.44 + *p++ = digits[it->data[i] >> 4]; 1.45 + *p++ = digits[it->data[i] & 0x0f]; 1.46 + } 1.47 +} 1.48 + 1.49 +nsresult 1.50 +Base64UrlEncodeImpl(const nsACString & utf8Input, nsACString & result) 1.51 +{ 1.52 + nsresult rv = Base64Encode(utf8Input, result); 1.53 + 1.54 + NS_ENSURE_SUCCESS(rv, rv); 1.55 + 1.56 + nsACString::char_type * out = result.BeginWriting(); 1.57 + nsACString::size_type length = result.Length(); 1.58 + // base64url encoding is defined in RFC 4648. It replaces the last two 1.59 + // alphabet characters of base64 encoding with '-' and '_' respectively. 1.60 + for (unsigned int i = 0; i < length; ++i) { 1.61 + if (out[i] == '+') { 1.62 + out[i] = '-'; 1.63 + } else if (out[i] == '/') { 1.64 + out[i] = '_'; 1.65 + } 1.66 + } 1.67 + 1.68 + return NS_OK; 1.69 +} 1.70 + 1.71 +#define DSA_KEY_TYPE_STRING (NS_LITERAL_CSTRING("DS160")) 1.72 +#define RSA_KEY_TYPE_STRING (NS_LITERAL_CSTRING("RS256")) 1.73 + 1.74 +class KeyPair : public nsIIdentityKeyPair, public nsNSSShutDownObject 1.75 +{ 1.76 +public: 1.77 + NS_DECL_THREADSAFE_ISUPPORTS 1.78 + NS_DECL_NSIIDENTITYKEYPAIR 1.79 + 1.80 + KeyPair(SECKEYPrivateKey* aPrivateKey, SECKEYPublicKey* aPublicKey); 1.81 + 1.82 +private: 1.83 + ~KeyPair() 1.84 + { 1.85 + nsNSSShutDownPreventionLock locker; 1.86 + if (isAlreadyShutDown()) { 1.87 + return; 1.88 + } 1.89 + destructorSafeDestroyNSSReference(); 1.90 + shutdown(calledFromObject); 1.91 + } 1.92 + 1.93 + void virtualDestroyNSSReference() MOZ_OVERRIDE 1.94 + { 1.95 + destructorSafeDestroyNSSReference(); 1.96 + } 1.97 + 1.98 + void destructorSafeDestroyNSSReference() 1.99 + { 1.100 + SECKEY_DestroyPrivateKey(mPrivateKey); 1.101 + mPrivateKey = nullptr; 1.102 + SECKEY_DestroyPublicKey(mPublicKey); 1.103 + mPublicKey = nullptr; 1.104 + } 1.105 + 1.106 + SECKEYPrivateKey * mPrivateKey; 1.107 + SECKEYPublicKey * mPublicKey; 1.108 + 1.109 + KeyPair(const KeyPair &) MOZ_DELETE; 1.110 + void operator=(const KeyPair &) MOZ_DELETE; 1.111 +}; 1.112 + 1.113 +NS_IMPL_ISUPPORTS(KeyPair, nsIIdentityKeyPair) 1.114 + 1.115 +class KeyGenRunnable : public nsRunnable, public nsNSSShutDownObject 1.116 +{ 1.117 +public: 1.118 + NS_DECL_NSIRUNNABLE 1.119 + 1.120 + KeyGenRunnable(KeyType keyType, nsIIdentityKeyGenCallback * aCallback); 1.121 + 1.122 +private: 1.123 + ~KeyGenRunnable() 1.124 + { 1.125 + nsNSSShutDownPreventionLock locker; 1.126 + if (isAlreadyShutDown()) { 1.127 + return; 1.128 + } 1.129 + destructorSafeDestroyNSSReference(); 1.130 + shutdown(calledFromObject); 1.131 + } 1.132 + 1.133 + virtual void virtualDestroyNSSReference() MOZ_OVERRIDE 1.134 + { 1.135 + destructorSafeDestroyNSSReference(); 1.136 + } 1.137 + 1.138 + void destructorSafeDestroyNSSReference() 1.139 + { 1.140 + } 1.141 + 1.142 + const KeyType mKeyType; // in 1.143 + nsMainThreadPtrHandle<nsIIdentityKeyGenCallback> mCallback; // in 1.144 + nsresult mRv; // out 1.145 + nsCOMPtr<nsIIdentityKeyPair> mKeyPair; // out 1.146 + 1.147 + KeyGenRunnable(const KeyGenRunnable &) MOZ_DELETE; 1.148 + void operator=(const KeyGenRunnable &) MOZ_DELETE; 1.149 +}; 1.150 + 1.151 +class SignRunnable : public nsRunnable, public nsNSSShutDownObject 1.152 +{ 1.153 +public: 1.154 + NS_DECL_NSIRUNNABLE 1.155 + 1.156 + SignRunnable(const nsACString & textToSign, SECKEYPrivateKey * privateKey, 1.157 + nsIIdentitySignCallback * aCallback); 1.158 + 1.159 +private: 1.160 + ~SignRunnable() 1.161 + { 1.162 + nsNSSShutDownPreventionLock locker; 1.163 + if (isAlreadyShutDown()) { 1.164 + return; 1.165 + } 1.166 + destructorSafeDestroyNSSReference(); 1.167 + shutdown(calledFromObject); 1.168 + } 1.169 + 1.170 + void virtualDestroyNSSReference() MOZ_OVERRIDE 1.171 + { 1.172 + destructorSafeDestroyNSSReference(); 1.173 + } 1.174 + 1.175 + void destructorSafeDestroyNSSReference() 1.176 + { 1.177 + SECKEY_DestroyPrivateKey(mPrivateKey); 1.178 + mPrivateKey = nullptr; 1.179 + } 1.180 + 1.181 + const nsCString mTextToSign; // in 1.182 + SECKEYPrivateKey* mPrivateKey; // in 1.183 + nsMainThreadPtrHandle<nsIIdentitySignCallback> mCallback; // in 1.184 + nsresult mRv; // out 1.185 + nsCString mSignature; // out 1.186 + 1.187 +private: 1.188 + SignRunnable(const SignRunnable &) MOZ_DELETE; 1.189 + void operator=(const SignRunnable &) MOZ_DELETE; 1.190 +}; 1.191 + 1.192 +class IdentityCryptoService MOZ_FINAL : public nsIIdentityCryptoService 1.193 +{ 1.194 +public: 1.195 + NS_DECL_THREADSAFE_ISUPPORTS 1.196 + NS_DECL_NSIIDENTITYCRYPTOSERVICE 1.197 + 1.198 + IdentityCryptoService() { } 1.199 + nsresult Init() 1.200 + { 1.201 + nsresult rv; 1.202 + nsCOMPtr<nsISupports> dummyUsedToEnsureNSSIsInitialized 1.203 + = do_GetService("@mozilla.org/psm;1", &rv); 1.204 + NS_ENSURE_SUCCESS(rv, rv); 1.205 + 1.206 + return NS_OK; 1.207 + } 1.208 + 1.209 +private: 1.210 + IdentityCryptoService(const KeyPair &) MOZ_DELETE; 1.211 + void operator=(const IdentityCryptoService &) MOZ_DELETE; 1.212 +}; 1.213 + 1.214 +NS_IMPL_ISUPPORTS(IdentityCryptoService, nsIIdentityCryptoService) 1.215 + 1.216 +NS_IMETHODIMP 1.217 +IdentityCryptoService::GenerateKeyPair( 1.218 + const nsACString & keyTypeString, nsIIdentityKeyGenCallback * callback) 1.219 +{ 1.220 + KeyType keyType; 1.221 + if (keyTypeString.Equals(RSA_KEY_TYPE_STRING)) { 1.222 + keyType = rsaKey; 1.223 + } else if (keyTypeString.Equals(DSA_KEY_TYPE_STRING)) { 1.224 + keyType = dsaKey; 1.225 + } else { 1.226 + return NS_ERROR_UNEXPECTED; 1.227 + } 1.228 + 1.229 + nsCOMPtr<nsIRunnable> r = new KeyGenRunnable(keyType, callback); 1.230 + nsCOMPtr<nsIThread> thread; 1.231 + nsresult rv = NS_NewThread(getter_AddRefs(thread), r); 1.232 + NS_ENSURE_SUCCESS(rv, rv); 1.233 + 1.234 + return NS_OK; 1.235 +} 1.236 + 1.237 +NS_IMETHODIMP 1.238 +IdentityCryptoService::Base64UrlEncode(const nsACString & utf8Input, 1.239 + nsACString & result) 1.240 +{ 1.241 + return Base64UrlEncodeImpl(utf8Input, result); 1.242 +} 1.243 + 1.244 +KeyPair::KeyPair(SECKEYPrivateKey * privateKey, SECKEYPublicKey * publicKey) 1.245 + : mPrivateKey(privateKey) 1.246 + , mPublicKey(publicKey) 1.247 +{ 1.248 + MOZ_ASSERT(!NS_IsMainThread()); 1.249 +} 1.250 + 1.251 +NS_IMETHODIMP 1.252 +KeyPair::GetHexRSAPublicKeyExponent(nsACString & result) 1.253 +{ 1.254 + MOZ_ASSERT(NS_IsMainThread()); 1.255 + NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); 1.256 + NS_ENSURE_TRUE(mPublicKey->keyType == rsaKey, NS_ERROR_NOT_AVAILABLE); 1.257 + HexEncode(&mPublicKey->u.rsa.publicExponent, result); 1.258 + return NS_OK; 1.259 +} 1.260 + 1.261 +NS_IMETHODIMP 1.262 +KeyPair::GetHexRSAPublicKeyModulus(nsACString & result) 1.263 +{ 1.264 + MOZ_ASSERT(NS_IsMainThread()); 1.265 + NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); 1.266 + NS_ENSURE_TRUE(mPublicKey->keyType == rsaKey, NS_ERROR_NOT_AVAILABLE); 1.267 + HexEncode(&mPublicKey->u.rsa.modulus, result); 1.268 + return NS_OK; 1.269 +} 1.270 + 1.271 +NS_IMETHODIMP 1.272 +KeyPair::GetHexDSAPrime(nsACString & result) 1.273 +{ 1.274 + MOZ_ASSERT(NS_IsMainThread()); 1.275 + NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); 1.276 + NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE); 1.277 + HexEncode(&mPublicKey->u.dsa.params.prime, result); 1.278 + return NS_OK; 1.279 +} 1.280 + 1.281 +NS_IMETHODIMP 1.282 +KeyPair::GetHexDSASubPrime(nsACString & result) 1.283 +{ 1.284 + MOZ_ASSERT(NS_IsMainThread()); 1.285 + NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); 1.286 + NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE); 1.287 + HexEncode(&mPublicKey->u.dsa.params.subPrime, result); 1.288 + return NS_OK; 1.289 +} 1.290 + 1.291 +NS_IMETHODIMP 1.292 +KeyPair::GetHexDSAGenerator(nsACString & result) 1.293 +{ 1.294 + MOZ_ASSERT(NS_IsMainThread()); 1.295 + NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); 1.296 + NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE); 1.297 + HexEncode(&mPublicKey->u.dsa.params.base, result); 1.298 + return NS_OK; 1.299 +} 1.300 + 1.301 +NS_IMETHODIMP 1.302 +KeyPair::GetHexDSAPublicValue(nsACString & result) 1.303 +{ 1.304 + MOZ_ASSERT(NS_IsMainThread()); 1.305 + NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); 1.306 + NS_ENSURE_TRUE(mPublicKey->keyType == dsaKey, NS_ERROR_NOT_AVAILABLE); 1.307 + HexEncode(&mPublicKey->u.dsa.publicValue, result); 1.308 + return NS_OK; 1.309 +} 1.310 + 1.311 +NS_IMETHODIMP 1.312 +KeyPair::GetKeyType(nsACString & result) 1.313 +{ 1.314 + MOZ_ASSERT(NS_IsMainThread()); 1.315 + NS_ENSURE_TRUE(mPublicKey, NS_ERROR_NOT_AVAILABLE); 1.316 + 1.317 + switch (mPublicKey->keyType) { 1.318 + case rsaKey: result = RSA_KEY_TYPE_STRING; return NS_OK; 1.319 + case dsaKey: result = DSA_KEY_TYPE_STRING; return NS_OK; 1.320 + default: return NS_ERROR_UNEXPECTED; 1.321 + } 1.322 +} 1.323 + 1.324 +NS_IMETHODIMP 1.325 +KeyPair::Sign(const nsACString & textToSign, 1.326 + nsIIdentitySignCallback* callback) 1.327 +{ 1.328 + MOZ_ASSERT(NS_IsMainThread()); 1.329 + nsCOMPtr<nsIRunnable> r = new SignRunnable(textToSign, mPrivateKey, 1.330 + callback); 1.331 + 1.332 + nsCOMPtr<nsIThread> thread; 1.333 + nsresult rv = NS_NewThread(getter_AddRefs(thread), r); 1.334 + return rv; 1.335 +} 1.336 + 1.337 +KeyGenRunnable::KeyGenRunnable(KeyType keyType, 1.338 + nsIIdentityKeyGenCallback * callback) 1.339 + : mKeyType(keyType) 1.340 + , mCallback(new nsMainThreadPtrHolder<nsIIdentityKeyGenCallback>(callback)) 1.341 + , mRv(NS_ERROR_NOT_INITIALIZED) 1.342 +{ 1.343 +} 1.344 + 1.345 +MOZ_WARN_UNUSED_RESULT nsresult 1.346 +GenerateKeyPair(PK11SlotInfo * slot, 1.347 + SECKEYPrivateKey ** privateKey, 1.348 + SECKEYPublicKey ** publicKey, 1.349 + CK_MECHANISM_TYPE mechanism, 1.350 + void * params) 1.351 +{ 1.352 + *publicKey = nullptr; 1.353 + *privateKey = PK11_GenerateKeyPair(slot, mechanism, params, publicKey, 1.354 + PR_FALSE /*isPerm*/, 1.355 + PR_TRUE /*isSensitive*/, 1.356 + nullptr /*&pwdata*/); 1.357 + if (!*privateKey) { 1.358 + MOZ_ASSERT(!*publicKey); 1.359 + return PRErrorCode_to_nsresult(PR_GetError()); 1.360 + } 1.361 + if (!*publicKey) { 1.362 + SECKEY_DestroyPrivateKey(*privateKey); 1.363 + *privateKey = nullptr; 1.364 + MOZ_CRASH("PK11_GnerateKeyPair returned private key without public key"); 1.365 + } 1.366 + 1.367 + return NS_OK; 1.368 +} 1.369 + 1.370 + 1.371 +MOZ_WARN_UNUSED_RESULT nsresult 1.372 +GenerateRSAKeyPair(PK11SlotInfo * slot, 1.373 + SECKEYPrivateKey ** privateKey, 1.374 + SECKEYPublicKey ** publicKey) 1.375 +{ 1.376 + MOZ_ASSERT(!NS_IsMainThread()); 1.377 + 1.378 + PK11RSAGenParams rsaParams; 1.379 + rsaParams.keySizeInBits = 2048; 1.380 + rsaParams.pe = 0x10001; 1.381 + return GenerateKeyPair(slot, privateKey, publicKey, CKM_RSA_PKCS_KEY_PAIR_GEN, 1.382 + &rsaParams); 1.383 +} 1.384 + 1.385 +MOZ_WARN_UNUSED_RESULT nsresult 1.386 +GenerateDSAKeyPair(PK11SlotInfo * slot, 1.387 + SECKEYPrivateKey ** privateKey, 1.388 + SECKEYPublicKey ** publicKey) 1.389 +{ 1.390 + MOZ_ASSERT(!NS_IsMainThread()); 1.391 + 1.392 + // XXX: These could probably be static const arrays, but this way we avoid 1.393 + // compiler warnings and also we avoid having to worry much about whether the 1.394 + // functions that take these inputs will (unexpectedly) modify them. 1.395 + 1.396 + // Using NIST parameters. Some other BrowserID components require that these 1.397 + // exact parameters are used. 1.398 + uint8_t P[] = { 1.399 + 0xFF,0x60,0x04,0x83,0xDB,0x6A,0xBF,0xC5,0xB4,0x5E,0xAB,0x78, 1.400 + 0x59,0x4B,0x35,0x33,0xD5,0x50,0xD9,0xF1,0xBF,0x2A,0x99,0x2A, 1.401 + 0x7A,0x8D,0xAA,0x6D,0xC3,0x4F,0x80,0x45,0xAD,0x4E,0x6E,0x0C, 1.402 + 0x42,0x9D,0x33,0x4E,0xEE,0xAA,0xEF,0xD7,0xE2,0x3D,0x48,0x10, 1.403 + 0xBE,0x00,0xE4,0xCC,0x14,0x92,0xCB,0xA3,0x25,0xBA,0x81,0xFF, 1.404 + 0x2D,0x5A,0x5B,0x30,0x5A,0x8D,0x17,0xEB,0x3B,0xF4,0xA0,0x6A, 1.405 + 0x34,0x9D,0x39,0x2E,0x00,0xD3,0x29,0x74,0x4A,0x51,0x79,0x38, 1.406 + 0x03,0x44,0xE8,0x2A,0x18,0xC4,0x79,0x33,0x43,0x8F,0x89,0x1E, 1.407 + 0x22,0xAE,0xEF,0x81,0x2D,0x69,0xC8,0xF7,0x5E,0x32,0x6C,0xB7, 1.408 + 0x0E,0xA0,0x00,0xC3,0xF7,0x76,0xDF,0xDB,0xD6,0x04,0x63,0x8C, 1.409 + 0x2E,0xF7,0x17,0xFC,0x26,0xD0,0x2E,0x17 1.410 + }; 1.411 + 1.412 + uint8_t Q[] = { 1.413 + 0xE2,0x1E,0x04,0xF9,0x11,0xD1,0xED,0x79,0x91,0x00,0x8E,0xCA, 1.414 + 0xAB,0x3B,0xF7,0x75,0x98,0x43,0x09,0xC3 1.415 + }; 1.416 + 1.417 + uint8_t G[] = { 1.418 + 0xC5,0x2A,0x4A,0x0F,0xF3,0xB7,0xE6,0x1F,0xDF,0x18,0x67,0xCE, 1.419 + 0x84,0x13,0x83,0x69,0xA6,0x15,0x4F,0x4A,0xFA,0x92,0x96,0x6E, 1.420 + 0x3C,0x82,0x7E,0x25,0xCF,0xA6,0xCF,0x50,0x8B,0x90,0xE5,0xDE, 1.421 + 0x41,0x9E,0x13,0x37,0xE0,0x7A,0x2E,0x9E,0x2A,0x3C,0xD5,0xDE, 1.422 + 0xA7,0x04,0xD1,0x75,0xF8,0xEB,0xF6,0xAF,0x39,0x7D,0x69,0xE1, 1.423 + 0x10,0xB9,0x6A,0xFB,0x17,0xC7,0xA0,0x32,0x59,0x32,0x9E,0x48, 1.424 + 0x29,0xB0,0xD0,0x3B,0xBC,0x78,0x96,0xB1,0x5B,0x4A,0xDE,0x53, 1.425 + 0xE1,0x30,0x85,0x8C,0xC3,0x4D,0x96,0x26,0x9A,0xA8,0x90,0x41, 1.426 + 0xF4,0x09,0x13,0x6C,0x72,0x42,0xA3,0x88,0x95,0xC9,0xD5,0xBC, 1.427 + 0xCA,0xD4,0xF3,0x89,0xAF,0x1D,0x7A,0x4B,0xD1,0x39,0x8B,0xD0, 1.428 + 0x72,0xDF,0xFA,0x89,0x62,0x33,0x39,0x7A 1.429 + }; 1.430 + 1.431 + static_assert(MOZ_ARRAY_LENGTH(P) == 1024 / CHAR_BIT, "bad DSA P"); 1.432 + static_assert(MOZ_ARRAY_LENGTH(Q) == 160 / CHAR_BIT, "bad DSA Q"); 1.433 + static_assert(MOZ_ARRAY_LENGTH(G) == 1024 / CHAR_BIT, "bad DSA G"); 1.434 + 1.435 + PQGParams pqgParams = { 1.436 + nullptr /*arena*/, 1.437 + { siBuffer, P, static_cast<unsigned int>(mozilla::ArrayLength(P)) }, 1.438 + { siBuffer, Q, static_cast<unsigned int>(mozilla::ArrayLength(Q)) }, 1.439 + { siBuffer, G, static_cast<unsigned int>(mozilla::ArrayLength(G)) } 1.440 + }; 1.441 + 1.442 + return GenerateKeyPair(slot, privateKey, publicKey, CKM_DSA_KEY_PAIR_GEN, 1.443 + &pqgParams); 1.444 +} 1.445 + 1.446 +NS_IMETHODIMP 1.447 +KeyGenRunnable::Run() 1.448 +{ 1.449 + if (!NS_IsMainThread()) { 1.450 + nsNSSShutDownPreventionLock locker; 1.451 + if (isAlreadyShutDown()) { 1.452 + mRv = NS_ERROR_NOT_AVAILABLE; 1.453 + } else { 1.454 + // We always want to use the internal slot for BrowserID; in particular, 1.455 + // we want to avoid smartcard slots. 1.456 + PK11SlotInfo *slot = PK11_GetInternalSlot(); 1.457 + if (!slot) { 1.458 + mRv = NS_ERROR_UNEXPECTED; 1.459 + } else { 1.460 + SECKEYPrivateKey *privk = nullptr; 1.461 + SECKEYPublicKey *pubk = nullptr; 1.462 + 1.463 + switch (mKeyType) { 1.464 + case rsaKey: 1.465 + mRv = GenerateRSAKeyPair(slot, &privk, &pubk); 1.466 + break; 1.467 + case dsaKey: 1.468 + mRv = GenerateDSAKeyPair(slot, &privk, &pubk); 1.469 + break; 1.470 + default: 1.471 + MOZ_CRASH("unknown key type"); 1.472 + } 1.473 + 1.474 + PK11_FreeSlot(slot); 1.475 + 1.476 + if (NS_SUCCEEDED(mRv)) { 1.477 + MOZ_ASSERT(privk); 1.478 + MOZ_ASSERT(pubk); 1.479 + // mKeyPair will take over ownership of privk and pubk 1.480 + mKeyPair = new KeyPair(privk, pubk); 1.481 + } 1.482 + } 1.483 + } 1.484 + 1.485 + NS_DispatchToMainThread(this); 1.486 + } else { 1.487 + // Back on Main Thread 1.488 + (void) mCallback->GenerateKeyPairFinished(mRv, mKeyPair); 1.489 + } 1.490 + return NS_OK; 1.491 +} 1.492 + 1.493 +SignRunnable::SignRunnable(const nsACString & aText, 1.494 + SECKEYPrivateKey * privateKey, 1.495 + nsIIdentitySignCallback * aCallback) 1.496 + : mTextToSign(aText) 1.497 + , mPrivateKey(SECKEY_CopyPrivateKey(privateKey)) 1.498 + , mCallback(new nsMainThreadPtrHolder<nsIIdentitySignCallback>(aCallback)) 1.499 + , mRv(NS_ERROR_NOT_INITIALIZED) 1.500 +{ 1.501 +} 1.502 + 1.503 +NS_IMETHODIMP 1.504 +SignRunnable::Run() 1.505 +{ 1.506 + if (!NS_IsMainThread()) { 1.507 + nsNSSShutDownPreventionLock locker; 1.508 + if (isAlreadyShutDown()) { 1.509 + mRv = NS_ERROR_NOT_AVAILABLE; 1.510 + } else { 1.511 + // We need the output in PKCS#11 format, not DER encoding, so we must use 1.512 + // PK11_HashBuf and PK11_Sign instead of SEC_SignData. 1.513 + 1.514 + SECItem sig = { siBuffer, nullptr, 0 }; 1.515 + int sigLength = PK11_SignatureLen(mPrivateKey); 1.516 + if (sigLength <= 0) { 1.517 + mRv = PRErrorCode_to_nsresult(PR_GetError()); 1.518 + } else if (!SECITEM_AllocItem(nullptr, &sig, sigLength)) { 1.519 + mRv = PRErrorCode_to_nsresult(PR_GetError()); 1.520 + } else { 1.521 + uint8_t hash[32]; // big enough for SHA-1 or SHA-256 1.522 + SECOidTag hashAlg = mPrivateKey->keyType == dsaKey ? SEC_OID_SHA1 1.523 + : SEC_OID_SHA256; 1.524 + SECItem hashItem = { siBuffer, hash, 1.525 + hashAlg == SEC_OID_SHA1 ? 20u : 32u }; 1.526 + 1.527 + mRv = MapSECStatus(PK11_HashBuf(hashAlg, hash, 1.528 + const_cast<uint8_t*>(reinterpret_cast<const uint8_t *>( 1.529 + mTextToSign.get())), 1.530 + mTextToSign.Length())); 1.531 + if (NS_SUCCEEDED(mRv)) { 1.532 + mRv = MapSECStatus(PK11_Sign(mPrivateKey, &sig, &hashItem)); 1.533 + } 1.534 + if (NS_SUCCEEDED(mRv)) { 1.535 + nsDependentCSubstring sigString( 1.536 + reinterpret_cast<const char*>(sig.data), sig.len); 1.537 + mRv = Base64UrlEncodeImpl(sigString, mSignature); 1.538 + } 1.539 + SECITEM_FreeItem(&sig, false); 1.540 + } 1.541 + } 1.542 + 1.543 + NS_DispatchToMainThread(this); 1.544 + } else { 1.545 + // Back on Main Thread 1.546 + (void) mCallback->SignFinished(mRv, mSignature); 1.547 + } 1.548 + 1.549 + return NS_OK; 1.550 +} 1.551 + 1.552 +// XPCOM module registration 1.553 + 1.554 +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(IdentityCryptoService, Init) 1.555 + 1.556 +#define NS_IDENTITYCRYPTOSERVICE_CID \ 1.557 + {0xbea13a3a, 0x44e8, 0x4d7f, {0xa0, 0xa2, 0x2c, 0x67, 0xf8, 0x4e, 0x3a, 0x97}} 1.558 + 1.559 +NS_DEFINE_NAMED_CID(NS_IDENTITYCRYPTOSERVICE_CID); 1.560 + 1.561 +const mozilla::Module::CIDEntry kCIDs[] = { 1.562 + { &kNS_IDENTITYCRYPTOSERVICE_CID, false, nullptr, IdentityCryptoServiceConstructor }, 1.563 + { nullptr } 1.564 +}; 1.565 + 1.566 +const mozilla::Module::ContractIDEntry kContracts[] = { 1.567 + { "@mozilla.org/identity/crypto-service;1", &kNS_IDENTITYCRYPTOSERVICE_CID }, 1.568 + { nullptr } 1.569 +}; 1.570 + 1.571 +const mozilla::Module kModule = { 1.572 + mozilla::Module::kVersion, 1.573 + kCIDs, 1.574 + kContracts 1.575 +}; 1.576 + 1.577 +} // unnamed namespace 1.578 + 1.579 +NSMODULE_DEFN(identity) = &kModule;