LCOV - code coverage report
Current view: top level - security/manager/ssl - nsCryptoHash.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 63 210 30.0 %
Date: 2017-07-14 16:53:18 Functions: 11 26 42.3 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
       7             : #include "nsCryptoHash.h"
       8             : 
       9             : #include <algorithm>
      10             : 
      11             : #include "mozilla/ArrayUtils.h"
      12             : #include "mozilla/Base64.h"
      13             : #include "mozilla/Casting.h"
      14             : #include "nsDependentString.h"
      15             : #include "nsIInputStream.h"
      16             : #include "nsIKeyModule.h"
      17             : #include "nsString.h"
      18             : #include "pk11pub.h"
      19             : #include "sechash.h"
      20             : 
      21             : using namespace mozilla;
      22             : 
      23             : namespace {
      24             : 
      25             : static const uint64_t STREAM_BUFFER_SIZE = 4096;
      26             : 
      27             : } // namespace
      28             : 
      29             : //---------------------------------------------
      30             : // Implementing nsICryptoHash
      31             : //---------------------------------------------
      32             : 
      33          15 : nsCryptoHash::nsCryptoHash()
      34             :   : mHashContext(nullptr)
      35          15 :   , mInitialized(false)
      36             : {
      37          15 : }
      38             : 
      39          39 : nsCryptoHash::~nsCryptoHash()
      40             : {
      41          26 :   nsNSSShutDownPreventionLock locker;
      42          13 :   if (isAlreadyShutDown()) {
      43           0 :     return;
      44             :   }
      45          13 :   destructorSafeDestroyNSSReference();
      46          13 :   shutdown(ShutdownCalledFrom::Object);
      47          39 : }
      48             : 
      49             : void
      50           0 : nsCryptoHash::virtualDestroyNSSReference()
      51             : {
      52           0 :   destructorSafeDestroyNSSReference();
      53           0 : }
      54             : 
      55             : void
      56          13 : nsCryptoHash::destructorSafeDestroyNSSReference()
      57             : {
      58          13 :   mHashContext = nullptr;
      59          13 : }
      60             : 
      61         123 : NS_IMPL_ISUPPORTS(nsCryptoHash, nsICryptoHash)
      62             : 
      63             : NS_IMETHODIMP
      64          21 : nsCryptoHash::Init(uint32_t algorithm)
      65             : {
      66          42 :   nsNSSShutDownPreventionLock locker;
      67          21 :   if (isAlreadyShutDown()) {
      68           0 :     return NS_ERROR_NOT_AVAILABLE;
      69             :   }
      70             : 
      71             :   HASH_HashType hashType;
      72          21 :   switch (algorithm) {
      73             :     case nsICryptoHash::MD2:
      74           0 :       hashType = HASH_AlgMD2; break;
      75             :     case nsICryptoHash::MD5:
      76          12 :       hashType = HASH_AlgMD5; break;
      77             :     case nsICryptoHash::SHA1:
      78           0 :       hashType = HASH_AlgSHA1; break;
      79             :     case nsICryptoHash::SHA256:
      80           9 :       hashType = HASH_AlgSHA256; break;
      81             :     case nsICryptoHash::SHA384:
      82           0 :       hashType = HASH_AlgSHA384; break;
      83             :     case nsICryptoHash::SHA512:
      84           0 :       hashType = HASH_AlgSHA512; break;
      85             :     default:
      86           0 :       return NS_ERROR_INVALID_ARG;
      87             :   }
      88             : 
      89          21 :   if (mHashContext) {
      90           7 :     if (!mInitialized && HASH_GetType(mHashContext.get()) == hashType) {
      91           7 :       mInitialized = true;
      92           7 :       HASH_Begin(mHashContext.get());
      93           7 :       return NS_OK;
      94             :     }
      95             : 
      96             :     // Destroy current hash context if the type was different
      97             :     // or Finish method wasn't called.
      98           0 :     mHashContext = nullptr;
      99           0 :     mInitialized = false;
     100             :   }
     101             : 
     102          14 :   mHashContext.reset(HASH_Create(hashType));
     103          14 :   if (!mHashContext) {
     104           0 :     return NS_ERROR_INVALID_ARG;
     105             :   }
     106             : 
     107          14 :   HASH_Begin(mHashContext.get());
     108          14 :   mInitialized = true;
     109          14 :   return NS_OK;
     110             : }
     111             : 
     112             : NS_IMETHODIMP
     113           0 : nsCryptoHash::InitWithString(const nsACString & aAlgorithm)
     114             : {
     115           0 :   if (aAlgorithm.LowerCaseEqualsLiteral("md2"))
     116           0 :     return Init(nsICryptoHash::MD2);
     117             : 
     118           0 :   if (aAlgorithm.LowerCaseEqualsLiteral("md5"))
     119           0 :     return Init(nsICryptoHash::MD5);
     120             : 
     121           0 :   if (aAlgorithm.LowerCaseEqualsLiteral("sha1"))
     122           0 :     return Init(nsICryptoHash::SHA1);
     123             : 
     124           0 :   if (aAlgorithm.LowerCaseEqualsLiteral("sha256"))
     125           0 :     return Init(nsICryptoHash::SHA256);
     126             : 
     127           0 :   if (aAlgorithm.LowerCaseEqualsLiteral("sha384"))
     128           0 :     return Init(nsICryptoHash::SHA384);
     129             : 
     130           0 :   if (aAlgorithm.LowerCaseEqualsLiteral("sha512"))
     131           0 :     return Init(nsICryptoHash::SHA512);
     132             : 
     133           0 :   return NS_ERROR_INVALID_ARG;
     134             : }
     135             : 
     136             : NS_IMETHODIMP
     137         213 : nsCryptoHash::Update(const uint8_t *data, uint32_t len)
     138             : {
     139         426 :   nsNSSShutDownPreventionLock locker;
     140         213 :   if (isAlreadyShutDown()) {
     141           0 :     return NS_ERROR_NOT_AVAILABLE;
     142             :   }
     143             : 
     144         213 :   if (!mInitialized) {
     145           0 :     return NS_ERROR_NOT_INITIALIZED;
     146             :   }
     147             : 
     148         213 :   HASH_Update(mHashContext.get(), data, len);
     149         213 :   return NS_OK;
     150             : }
     151             : 
     152             : NS_IMETHODIMP
     153           6 : nsCryptoHash::UpdateFromStream(nsIInputStream *data, uint32_t aLen)
     154             : {
     155          12 :   nsNSSShutDownPreventionLock locker;
     156           6 :   if (isAlreadyShutDown()) {
     157           0 :     return NS_ERROR_NOT_AVAILABLE;
     158             :   }
     159             : 
     160           6 :   if (!mInitialized)
     161           0 :     return NS_ERROR_NOT_INITIALIZED;
     162             : 
     163           6 :   if (!data)
     164           0 :     return NS_ERROR_INVALID_ARG;
     165             : 
     166             :   uint64_t n;
     167           6 :   nsresult rv = data->Available(&n);
     168           6 :   if (NS_FAILED(rv))
     169           0 :     return rv;
     170             : 
     171             :   // if the user has passed UINT32_MAX, then read
     172             :   // everything in the stream
     173             : 
     174           6 :   uint64_t len = aLen;
     175           6 :   if (aLen == UINT32_MAX)
     176           0 :     len = n;
     177             : 
     178             :   // So, if the stream has NO data available for the hash,
     179             :   // or if the data available is less then what the caller
     180             :   // requested, we can not fulfill the hash update.  In this
     181             :   // case, just return NS_ERROR_NOT_AVAILABLE indicating
     182             :   // that there is not enough data in the stream to satisify
     183             :   // the request.
     184             : 
     185           6 :   if (n == 0 || n < len) {
     186           0 :     return NS_ERROR_NOT_AVAILABLE;
     187             :   }
     188             : 
     189             :   char buffer[STREAM_BUFFER_SIZE];
     190          18 :   while (len > 0) {
     191           6 :     uint64_t readLimit = std::min<uint64_t>(STREAM_BUFFER_SIZE, len);
     192             :     uint32_t read;
     193           6 :     rv = data->Read(buffer, AssertedCast<uint32_t>(readLimit), &read);
     194           6 :     if (NS_FAILED(rv)) {
     195           0 :       return rv;
     196             :     }
     197             : 
     198           6 :     rv = Update(BitwiseCast<uint8_t*>(buffer), read);
     199           6 :     if (NS_FAILED(rv)) {
     200           0 :       return rv;
     201             :     }
     202             : 
     203           6 :     len -= read;
     204             :   }
     205             : 
     206           6 :   return NS_OK;
     207             : }
     208             : 
     209             : NS_IMETHODIMP
     210          21 : nsCryptoHash::Finish(bool ascii, nsACString & _retval)
     211             : {
     212          42 :   nsNSSShutDownPreventionLock locker;
     213          21 :   if (isAlreadyShutDown()) {
     214           0 :     return NS_ERROR_NOT_AVAILABLE;
     215             :   }
     216             : 
     217          21 :   if (!mInitialized) {
     218           0 :     return NS_ERROR_NOT_INITIALIZED;
     219             :   }
     220             : 
     221          21 :   uint32_t hashLen = 0;
     222             :   unsigned char buffer[HASH_LENGTH_MAX];
     223          21 :   HASH_End(mHashContext.get(), buffer, &hashLen, HASH_LENGTH_MAX);
     224             : 
     225          21 :   mInitialized = false;
     226             : 
     227          21 :   if (ascii) {
     228           0 :     nsDependentCSubstring dataStr(BitwiseCast<char*>(buffer), hashLen);
     229           0 :     return Base64Encode(dataStr, _retval);
     230             :   }
     231             : 
     232          21 :   _retval.Assign(BitwiseCast<char*>(buffer), hashLen);
     233          21 :   return NS_OK;
     234             : }
     235             : 
     236             : //---------------------------------------------
     237             : // Implementing nsICryptoHMAC
     238             : //---------------------------------------------
     239             : 
     240           0 : NS_IMPL_ISUPPORTS(nsCryptoHMAC, nsICryptoHMAC)
     241             : 
     242           0 : nsCryptoHMAC::nsCryptoHMAC()
     243           0 :   : mHMACContext(nullptr)
     244             : {
     245           0 : }
     246             : 
     247           0 : nsCryptoHMAC::~nsCryptoHMAC()
     248             : {
     249           0 :   nsNSSShutDownPreventionLock locker;
     250           0 :   if (isAlreadyShutDown()) {
     251           0 :     return;
     252             :   }
     253           0 :   destructorSafeDestroyNSSReference();
     254           0 :   shutdown(ShutdownCalledFrom::Object);
     255           0 : }
     256             : 
     257             : void
     258           0 : nsCryptoHMAC::virtualDestroyNSSReference()
     259             : {
     260           0 :   destructorSafeDestroyNSSReference();
     261           0 : }
     262             : 
     263             : void
     264           0 : nsCryptoHMAC::destructorSafeDestroyNSSReference()
     265             : {
     266           0 :   mHMACContext = nullptr;
     267           0 : }
     268             : 
     269             : NS_IMETHODIMP
     270           0 : nsCryptoHMAC::Init(uint32_t aAlgorithm, nsIKeyObject *aKeyObject)
     271             : {
     272           0 :   nsNSSShutDownPreventionLock locker;
     273           0 :   if (isAlreadyShutDown()) {
     274           0 :     return NS_ERROR_NOT_AVAILABLE;
     275             :   }
     276             : 
     277           0 :   if (mHMACContext) {
     278           0 :     mHMACContext = nullptr;
     279             :   }
     280             : 
     281             :   CK_MECHANISM_TYPE mechType;
     282           0 :   switch (aAlgorithm) {
     283             :     case nsICryptoHMAC::MD5:
     284           0 :       mechType = CKM_MD5_HMAC; break;
     285             :     case nsICryptoHMAC::SHA1:
     286           0 :       mechType = CKM_SHA_1_HMAC; break;
     287             :     case nsICryptoHMAC::SHA256:
     288           0 :       mechType = CKM_SHA256_HMAC; break;
     289             :     case nsICryptoHMAC::SHA384:
     290           0 :       mechType = CKM_SHA384_HMAC; break;
     291             :     case nsICryptoHMAC::SHA512:
     292           0 :       mechType = CKM_SHA512_HMAC; break;
     293             :     default:
     294           0 :       return NS_ERROR_INVALID_ARG;
     295             :   }
     296             : 
     297           0 :   NS_ENSURE_ARG_POINTER(aKeyObject);
     298             : 
     299             :   nsresult rv;
     300             : 
     301             :   int16_t keyType;
     302           0 :   rv = aKeyObject->GetType(&keyType);
     303           0 :   NS_ENSURE_SUCCESS(rv, rv);
     304             : 
     305           0 :   NS_ENSURE_TRUE(keyType == nsIKeyObject::SYM_KEY, NS_ERROR_INVALID_ARG);
     306             : 
     307             :   PK11SymKey* key;
     308             :   // GetKeyObj doesn't addref the key
     309           0 :   rv = aKeyObject->GetKeyObj(&key);
     310           0 :   NS_ENSURE_SUCCESS(rv, rv);
     311             : 
     312             :   SECItem rawData;
     313           0 :   rawData.data = 0;
     314           0 :   rawData.len = 0;
     315           0 :   mHMACContext.reset(PK11_CreateContextBySymKey(mechType, CKA_SIGN, key,
     316           0 :                                                 &rawData));
     317           0 :   NS_ENSURE_TRUE(mHMACContext, NS_ERROR_FAILURE);
     318             : 
     319           0 :   if (PK11_DigestBegin(mHMACContext.get()) != SECSuccess) {
     320           0 :     return NS_ERROR_FAILURE;
     321             :   }
     322             : 
     323           0 :   return NS_OK;
     324             : }
     325             : 
     326             : NS_IMETHODIMP
     327           0 : nsCryptoHMAC::Update(const uint8_t *aData, uint32_t aLen)
     328             : {
     329           0 :   nsNSSShutDownPreventionLock locker;
     330           0 :   if (isAlreadyShutDown()) {
     331           0 :     return NS_ERROR_NOT_AVAILABLE;
     332             :   }
     333             : 
     334           0 :   if (!mHMACContext)
     335           0 :     return NS_ERROR_NOT_INITIALIZED;
     336             : 
     337           0 :   if (!aData)
     338           0 :     return NS_ERROR_INVALID_ARG;
     339             : 
     340           0 :   if (PK11_DigestOp(mHMACContext.get(), aData, aLen) != SECSuccess) {
     341           0 :     return NS_ERROR_FAILURE;
     342             :   }
     343             : 
     344           0 :   return NS_OK;
     345             : }
     346             : 
     347             : NS_IMETHODIMP
     348           0 : nsCryptoHMAC::UpdateFromStream(nsIInputStream *aStream, uint32_t aLen)
     349             : {
     350           0 :   nsNSSShutDownPreventionLock locker;
     351           0 :   if (isAlreadyShutDown()) {
     352           0 :     return NS_ERROR_NOT_AVAILABLE;
     353             :   }
     354             : 
     355           0 :   if (!mHMACContext)
     356           0 :     return NS_ERROR_NOT_INITIALIZED;
     357             : 
     358           0 :   if (!aStream)
     359           0 :     return NS_ERROR_INVALID_ARG;
     360             : 
     361             :   uint64_t n;
     362           0 :   nsresult rv = aStream->Available(&n);
     363           0 :   if (NS_FAILED(rv))
     364           0 :     return rv;
     365             : 
     366             :   // if the user has passed UINT32_MAX, then read
     367             :   // everything in the stream
     368             : 
     369           0 :   uint64_t len = aLen;
     370           0 :   if (aLen == UINT32_MAX)
     371           0 :     len = n;
     372             : 
     373             :   // So, if the stream has NO data available for the hash,
     374             :   // or if the data available is less then what the caller
     375             :   // requested, we can not fulfill the HMAC update.  In this
     376             :   // case, just return NS_ERROR_NOT_AVAILABLE indicating
     377             :   // that there is not enough data in the stream to satisify
     378             :   // the request.
     379             : 
     380           0 :   if (n == 0 || n < len)
     381           0 :     return NS_ERROR_NOT_AVAILABLE;
     382             : 
     383             :   char buffer[STREAM_BUFFER_SIZE];
     384           0 :   while (len > 0) {
     385           0 :     uint64_t readLimit = std::min<uint64_t>(STREAM_BUFFER_SIZE, len);
     386             :     uint32_t read;
     387           0 :     rv = aStream->Read(buffer, AssertedCast<uint32_t>(readLimit), &read);
     388           0 :     if (NS_FAILED(rv)) {
     389           0 :       return rv;
     390             :     }
     391             : 
     392           0 :     if (read == 0) {
     393           0 :       return NS_BASE_STREAM_CLOSED;
     394             :     }
     395             : 
     396           0 :     rv = Update(BitwiseCast<uint8_t*>(buffer), read);
     397           0 :     if (NS_FAILED(rv)) {
     398           0 :       return rv;
     399             :     }
     400             : 
     401           0 :     len -= read;
     402             :   }
     403             : 
     404           0 :   return NS_OK;
     405             : }
     406             : 
     407             : NS_IMETHODIMP
     408           0 : nsCryptoHMAC::Finish(bool aASCII, nsACString & _retval)
     409             : {
     410           0 :   nsNSSShutDownPreventionLock locker;
     411           0 :   if (isAlreadyShutDown()) {
     412           0 :     return NS_ERROR_NOT_AVAILABLE;
     413             :   }
     414             : 
     415           0 :   if (!mHMACContext)
     416           0 :     return NS_ERROR_NOT_INITIALIZED;
     417             : 
     418           0 :   uint32_t hashLen = 0;
     419             :   unsigned char buffer[HASH_LENGTH_MAX];
     420           0 :   SECStatus srv = PK11_DigestFinal(mHMACContext.get(), buffer, &hashLen,
     421           0 :                                    HASH_LENGTH_MAX);
     422           0 :   if (srv != SECSuccess) {
     423           0 :     return NS_ERROR_FAILURE;
     424             :   }
     425             : 
     426           0 :   if (aASCII) {
     427           0 :     nsDependentCSubstring dataStr(BitwiseCast<char*>(buffer), hashLen);
     428           0 :     return Base64Encode(dataStr, _retval);
     429             :   }
     430             : 
     431           0 :   _retval.Assign(BitwiseCast<char*>(buffer), hashLen);
     432           0 :   return NS_OK;
     433             : }
     434             : 
     435             : NS_IMETHODIMP
     436           0 : nsCryptoHMAC::Reset()
     437             : {
     438           0 :   nsNSSShutDownPreventionLock locker;
     439           0 :   if (isAlreadyShutDown()) {
     440           0 :     return NS_ERROR_NOT_AVAILABLE;
     441             :   }
     442             : 
     443           0 :   if (PK11_DigestBegin(mHMACContext.get()) != SECSuccess) {
     444           0 :     return NS_ERROR_FAILURE;
     445             :   }
     446             : 
     447           0 :   return NS_OK;
     448             : }

Generated by: LCOV version 1.13