security/manager/ssl/src/nsCryptoHash.cpp

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

     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/. */
     7 #ifdef MOZ_LOGGING
     8 #define FORCE_PR_LOG 1
     9 #endif
    11 #include <algorithm>
    13 #include "nsCryptoHash.h"
    15 #include "nsIInputStream.h"
    16 #include "nsIKeyModule.h"
    18 #include "nsString.h"
    20 #include "sechash.h"
    21 #include "pk11pub.h"
    22 #include "base64.h"
    24 #define NS_CRYPTO_HASH_BUFFER_SIZE 4096
    26 //---------------------------------------------
    27 // Implementing nsICryptoHash
    28 //---------------------------------------------
    30 nsCryptoHash::nsCryptoHash()
    31   : mHashContext(nullptr)
    32   , mInitialized(false)
    33 {
    34 }
    36 nsCryptoHash::~nsCryptoHash()
    37 {
    38   nsNSSShutDownPreventionLock locker;
    39   if (isAlreadyShutDown()) {
    40     return;
    41   }
    42   destructorSafeDestroyNSSReference();
    43   shutdown(calledFromObject);
    44 }
    46 void nsCryptoHash::virtualDestroyNSSReference()
    47 {
    48   destructorSafeDestroyNSSReference();
    49 }
    51 void nsCryptoHash::destructorSafeDestroyNSSReference()
    52 {
    53   if (mHashContext)
    54     HASH_Destroy(mHashContext);
    55   mHashContext = nullptr;
    56 }
    58 NS_IMPL_ISUPPORTS(nsCryptoHash, nsICryptoHash)
    60 NS_IMETHODIMP 
    61 nsCryptoHash::Init(uint32_t algorithm)
    62 {
    63   nsNSSShutDownPreventionLock locker;
    65   HASH_HashType hashType = (HASH_HashType)algorithm;
    66   if (mHashContext)
    67   {
    68     if ((!mInitialized) && (HASH_GetType(mHashContext) == hashType))
    69     {
    70       mInitialized = true;
    71       HASH_Begin(mHashContext);
    72       return NS_OK;
    73     }
    75     // Destroy current hash context if the type was different
    76     // or Finish method wasn't called.
    77     HASH_Destroy(mHashContext);
    78     mInitialized = false;
    79   }
    81   mHashContext = HASH_Create(hashType);
    82   if (!mHashContext)
    83     return NS_ERROR_INVALID_ARG;
    85   HASH_Begin(mHashContext);
    86   mInitialized = true;
    87   return NS_OK; 
    88 }
    90 NS_IMETHODIMP
    91 nsCryptoHash::InitWithString(const nsACString & aAlgorithm)
    92 {
    93   if (aAlgorithm.LowerCaseEqualsLiteral("md2"))
    94     return Init(nsICryptoHash::MD2);
    96   if (aAlgorithm.LowerCaseEqualsLiteral("md5"))
    97     return Init(nsICryptoHash::MD5);
    99   if (aAlgorithm.LowerCaseEqualsLiteral("sha1"))
   100     return Init(nsICryptoHash::SHA1);
   102   if (aAlgorithm.LowerCaseEqualsLiteral("sha256"))
   103     return Init(nsICryptoHash::SHA256);
   105   if (aAlgorithm.LowerCaseEqualsLiteral("sha384"))
   106     return Init(nsICryptoHash::SHA384);
   108   if (aAlgorithm.LowerCaseEqualsLiteral("sha512"))
   109     return Init(nsICryptoHash::SHA512);
   111   return NS_ERROR_INVALID_ARG;
   112 }
   114 NS_IMETHODIMP
   115 nsCryptoHash::Update(const uint8_t *data, uint32_t len)
   116 {
   117   nsNSSShutDownPreventionLock locker;
   119   if (!mInitialized)
   120     return NS_ERROR_NOT_INITIALIZED;
   122   HASH_Update(mHashContext, data, len);
   123   return NS_OK; 
   124 }
   126 NS_IMETHODIMP
   127 nsCryptoHash::UpdateFromStream(nsIInputStream *data, uint32_t aLen)
   128 {
   129   if (!mInitialized)
   130     return NS_ERROR_NOT_INITIALIZED;
   132   if (!data)
   133     return NS_ERROR_INVALID_ARG;
   135   uint64_t n;
   136   nsresult rv = data->Available(&n);
   137   if (NS_FAILED(rv))
   138     return rv;
   140   // if the user has passed UINT32_MAX, then read
   141   // everything in the stream
   143   uint64_t len = aLen;
   144   if (aLen == UINT32_MAX)
   145     len = n;
   147   // So, if the stream has NO data available for the hash,
   148   // or if the data available is less then what the caller
   149   // requested, we can not fulfill the hash update.  In this
   150   // case, just return NS_ERROR_NOT_AVAILABLE indicating
   151   // that there is not enough data in the stream to satisify
   152   // the request.
   154   if (n == 0 || n < len)
   155     return NS_ERROR_NOT_AVAILABLE;
   157   char buffer[NS_CRYPTO_HASH_BUFFER_SIZE];
   158   uint32_t read, readLimit;
   160   while(NS_SUCCEEDED(rv) && len>0)
   161   {
   162     readLimit = (uint32_t)std::min<uint64_t>(NS_CRYPTO_HASH_BUFFER_SIZE, len);
   164     rv = data->Read(buffer, readLimit, &read);
   166     if (NS_SUCCEEDED(rv))
   167       rv = Update((const uint8_t*)buffer, read);
   169     len -= read;
   170   }
   172   return rv;
   173 }
   175 NS_IMETHODIMP
   176 nsCryptoHash::Finish(bool ascii, nsACString & _retval)
   177 {
   178   nsNSSShutDownPreventionLock locker;
   180   if (!mInitialized)
   181     return NS_ERROR_NOT_INITIALIZED;
   183   uint32_t hashLen = 0;
   184   unsigned char buffer[HASH_LENGTH_MAX];
   185   unsigned char* pbuffer = buffer;
   187   HASH_End(mHashContext, pbuffer, &hashLen, HASH_LENGTH_MAX);
   189   mInitialized = false;
   191   if (ascii)
   192   {
   193     char *asciiData = BTOA_DataToAscii(buffer, hashLen);
   194     NS_ENSURE_TRUE(asciiData, NS_ERROR_OUT_OF_MEMORY);
   196     _retval.Assign(asciiData);
   197     PORT_Free(asciiData);
   198   }
   199   else
   200   {
   201     _retval.Assign((const char*)buffer, hashLen);
   202   }
   204   return NS_OK;
   205 }
   207 //---------------------------------------------
   208 // Implementing nsICryptoHMAC
   209 //---------------------------------------------
   211 NS_IMPL_ISUPPORTS(nsCryptoHMAC, nsICryptoHMAC)
   213 nsCryptoHMAC::nsCryptoHMAC()
   214 {
   215   mHMACContext = nullptr;
   216 }
   218 nsCryptoHMAC::~nsCryptoHMAC()
   219 {
   220   nsNSSShutDownPreventionLock locker;
   221   if (isAlreadyShutDown()) {
   222     return;
   223   }
   224   destructorSafeDestroyNSSReference();
   225   shutdown(calledFromObject);
   226 }
   228 void nsCryptoHMAC::virtualDestroyNSSReference()
   229 {
   230   destructorSafeDestroyNSSReference();
   231 }
   233 void nsCryptoHMAC::destructorSafeDestroyNSSReference()
   234 {
   235   if (mHMACContext)
   236     PK11_DestroyContext(mHMACContext, true);
   237   mHMACContext = nullptr;
   238 }
   240 /* void init (in unsigned long aAlgorithm, in nsIKeyObject aKeyObject); */
   241 NS_IMETHODIMP nsCryptoHMAC::Init(uint32_t aAlgorithm, nsIKeyObject *aKeyObject)
   242 {
   243   nsNSSShutDownPreventionLock locker;
   245   if (mHMACContext)
   246   {
   247     PK11_DestroyContext(mHMACContext, true);
   248     mHMACContext = nullptr;
   249   }
   251   CK_MECHANISM_TYPE HMACMechType;
   252   switch (aAlgorithm)
   253   {
   254   case nsCryptoHMAC::MD2:
   255     HMACMechType = CKM_MD2_HMAC; break;
   256   case nsCryptoHMAC::MD5:
   257     HMACMechType = CKM_MD5_HMAC; break;
   258   case nsCryptoHMAC::SHA1:
   259     HMACMechType = CKM_SHA_1_HMAC; break;
   260   case nsCryptoHMAC::SHA256:
   261     HMACMechType = CKM_SHA256_HMAC; break;
   262   case nsCryptoHMAC::SHA384:
   263     HMACMechType = CKM_SHA384_HMAC; break;
   264   case nsCryptoHMAC::SHA512:
   265     HMACMechType = CKM_SHA512_HMAC; break;
   266   default:
   267     return NS_ERROR_INVALID_ARG;
   268   }
   270   NS_ENSURE_ARG_POINTER(aKeyObject);
   272   nsresult rv;
   274   int16_t keyType;
   275   rv = aKeyObject->GetType(&keyType);
   276   NS_ENSURE_SUCCESS(rv, rv);
   278   NS_ENSURE_TRUE(keyType == nsIKeyObject::SYM_KEY, NS_ERROR_INVALID_ARG);
   280   PK11SymKey* key;
   281   // GetKeyObj doesn't addref the key
   282   rv = aKeyObject->GetKeyObj((void**)&key);
   283   NS_ENSURE_SUCCESS(rv, rv);
   285   SECItem rawData;
   286   rawData.data = 0;
   287   rawData.len = 0;
   288   mHMACContext = PK11_CreateContextBySymKey(
   289       HMACMechType, CKA_SIGN, key, &rawData);
   290   NS_ENSURE_TRUE(mHMACContext, NS_ERROR_FAILURE);
   292   SECStatus ss = PK11_DigestBegin(mHMACContext);
   293   NS_ENSURE_TRUE(ss == SECSuccess, NS_ERROR_FAILURE);
   295   return NS_OK;
   296 }
   298 /* void update ([array, size_is (aLen), const] in octet aData, in unsigned long aLen); */
   299 NS_IMETHODIMP nsCryptoHMAC::Update(const uint8_t *aData, uint32_t aLen)
   300 {
   301   nsNSSShutDownPreventionLock locker;
   303   if (!mHMACContext)
   304     return NS_ERROR_NOT_INITIALIZED;
   306   if (!aData)
   307     return NS_ERROR_INVALID_ARG;
   309   SECStatus ss = PK11_DigestOp(mHMACContext, aData, aLen);
   310   NS_ENSURE_TRUE(ss == SECSuccess, NS_ERROR_FAILURE);
   312   return NS_OK;
   313 }
   315 /* void updateFromStream (in nsIInputStream aStream, in unsigned long aLen); */
   316 NS_IMETHODIMP nsCryptoHMAC::UpdateFromStream(nsIInputStream *aStream, uint32_t aLen)
   317 {
   318   if (!mHMACContext)
   319     return NS_ERROR_NOT_INITIALIZED;
   321   if (!aStream)
   322     return NS_ERROR_INVALID_ARG;
   324   uint64_t n;
   325   nsresult rv = aStream->Available(&n);
   326   if (NS_FAILED(rv))
   327     return rv;
   329   // if the user has passed UINT32_MAX, then read
   330   // everything in the stream
   332   uint64_t len = aLen;
   333   if (aLen == UINT32_MAX)
   334     len = n;
   336   // So, if the stream has NO data available for the hash,
   337   // or if the data available is less then what the caller
   338   // requested, we can not fulfill the HMAC update.  In this
   339   // case, just return NS_ERROR_NOT_AVAILABLE indicating
   340   // that there is not enough data in the stream to satisify
   341   // the request.
   343   if (n == 0 || n < len)
   344     return NS_ERROR_NOT_AVAILABLE;
   346   char buffer[NS_CRYPTO_HASH_BUFFER_SIZE];
   347   uint32_t read, readLimit;
   349   while(NS_SUCCEEDED(rv) && len > 0)
   350   {
   351     readLimit = (uint32_t)std::min<uint64_t>(NS_CRYPTO_HASH_BUFFER_SIZE, len);
   353     rv = aStream->Read(buffer, readLimit, &read);
   354     if (read == 0)
   355       return NS_BASE_STREAM_CLOSED;
   357     if (NS_SUCCEEDED(rv))
   358       rv = Update((const uint8_t*)buffer, read);
   360     len -= read;
   361   }
   363   return rv;
   364 }
   366 /* ACString finish (in bool aASCII); */
   367 NS_IMETHODIMP nsCryptoHMAC::Finish(bool aASCII, nsACString & _retval)
   368 {
   369   nsNSSShutDownPreventionLock locker;
   371   if (!mHMACContext)
   372     return NS_ERROR_NOT_INITIALIZED;
   374   uint32_t hashLen = 0;
   375   unsigned char buffer[HASH_LENGTH_MAX];
   376   unsigned char* pbuffer = buffer;
   378   PK11_DigestFinal(mHMACContext, pbuffer, &hashLen, HASH_LENGTH_MAX);
   379   if (aASCII)
   380   {
   381     char *asciiData = BTOA_DataToAscii(buffer, hashLen);
   382     NS_ENSURE_TRUE(asciiData, NS_ERROR_OUT_OF_MEMORY);
   384     _retval.Assign(asciiData);
   385     PORT_Free(asciiData);
   386   }
   387   else
   388   {
   389     _retval.Assign((const char*)buffer, hashLen);
   390   }
   392   return NS_OK;
   393 }
   395 /* void reset (); */
   396 NS_IMETHODIMP nsCryptoHMAC::Reset()
   397 {
   398   nsNSSShutDownPreventionLock locker;
   400   SECStatus ss = PK11_DigestBegin(mHMACContext);
   401   NS_ENSURE_TRUE(ss == SECSuccess, NS_ERROR_FAILURE);
   403   return NS_OK;
   404 }

mercurial