LCOV - code coverage report
Current view: top level - cryptolink - crypto_hmac.cc (source / functions) Hit Total Coverage
Test: report.info Lines: 82 98 83.7 %
Date: 2012-05-15 Functions: 17 17 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 57 130 43.8 %

           Branch data     Line data    Source code
       1                 :            : // Copyright (C) 2011  Internet Systems Consortium, Inc. ("ISC")
       2                 :            : //
       3                 :            : // Permission to use, copy, modify, and/or distribute this software for any
       4                 :            : // purpose with or without fee is hereby granted, provided that the above
       5                 :            : // copyright notice and this permission notice appear in all copies.
       6                 :            : //
       7                 :            : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
       8                 :            : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
       9                 :            : // AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
      10                 :            : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
      11                 :            : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
      12                 :            : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
      13                 :            : // PERFORMANCE OF THIS SOFTWARE.
      14                 :            : 
      15                 :            : #include <cryptolink.h>
      16                 :            : #include <cryptolink/crypto_hmac.h>
      17                 :            : 
      18                 :            : #include <boost/scoped_ptr.hpp>
      19                 :            : 
      20                 :            : #include <botan/version.h>
      21                 :            : #include <botan/botan.h>
      22                 :            : #include <botan/hmac.h>
      23                 :            : #include <botan/hash.h>
      24                 :            : #include <botan/types.h>
      25                 :            : 
      26                 :            : #include <cstring>
      27                 :            : 
      28                 :            : namespace {
      29                 :            : const char*
      30                 :            : getBotanHashAlgorithmName(isc::cryptolink::HashAlgorithm algorithm) {
      31   [ +  +  +  +  :        785 :     switch (algorithm) {
             +  +  -  + ]
      32                 :            :     case isc::cryptolink::MD5:
      33                 :            :         return ("MD5");
      34                 :            :         break;
      35                 :            :     case isc::cryptolink::SHA1:
      36                 :            :         return ("SHA-1");
      37                 :            :         break;
      38                 :            :     case isc::cryptolink::SHA256:
      39                 :            :         return ("SHA-256");
      40                 :            :         break;
      41                 :            :     case isc::cryptolink::SHA224:
      42                 :            :         return ("SHA-224");
      43                 :            :         break;
      44                 :            :     case isc::cryptolink::SHA384:
      45                 :            :         return ("SHA-384");
      46                 :            :         break;
      47                 :            :     case isc::cryptolink::SHA512:
      48                 :            :         return ("SHA-512");
      49                 :            :         break;
      50                 :            :     case isc::cryptolink::UNKNOWN_HASH:
      51                 :            :         return ("Unknown");
      52                 :            :         break;
      53                 :            :     }
      54                 :            :     // compiler should have prevented us to reach this, since we have
      55                 :            :     // no default. But we need a return value anyway
      56                 :            :     return ("Unknown");
      57                 :            : }
      58                 :            : 
      59                 :            : } // local namespace
      60                 :            : 
      61                 :            : 
      62                 :            : namespace isc {
      63                 :            : namespace cryptolink {
      64                 :            : 
      65                 :            : class HMACImpl {
      66                 :            : public:
      67                 :        785 :     explicit HMACImpl(const void* secret, size_t secret_len,
      68                 :        793 :                       const HashAlgorithm hash_algorithm) {
      69                 :            :         Botan::HashFunction* hash;
      70                 :            :         try {
      71                 :            :             hash = Botan::get_hash(
      72 [ +  - ][ +  + ]:        785 :                 getBotanHashAlgorithmName(hash_algorithm));
      73                 :          6 :         } catch (const Botan::Algorithm_Not_Found&) {
      74 [ -  + ][ -  + ]:          6 :             isc_throw(isc::cryptolink::UnsupportedAlgorithm,
                 [ -  + ]
      75                 :            :                       "Unknown hash algorithm: " <<
      76                 :            :                       static_cast<int>(hash_algorithm));
      77      [ -  +  - ]:          3 :         } catch (const Botan::Exception& exc) {
      78 [ #  # ][ #  # ]:          0 :             isc_throw(isc::cryptolink::LibraryError, exc.what());
      79                 :            :         }
      80                 :            : 
      81 [ +  - ][ +  - ]:        782 :         hmac_.reset(new Botan::HMAC(hash));
      82                 :            : 
      83                 :            :         // If the key length is larger than the block size, we hash the
      84                 :            :         // key itself first.
      85                 :            :         try {
      86                 :            :             // use a temp var so we don't have blocks spanning
      87                 :            :             // preprocessor directives
      88                 :            : #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,0)
      89                 :            :             size_t block_length = hash->hash_block_size();
      90                 :            : #elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,8,0)
      91                 :        782 :             size_t block_length = hash->HASH_BLOCK_SIZE;
      92                 :            : #else
      93                 :            : #error "Unsupported Botan version (need 1.8 or higher)"
      94                 :            :             // added to suppress irrelevant compiler errors
      95                 :            :             size_t block_length = 0;
      96                 :            : #endif
      97         [ +  + ]:        782 :             if (secret_len > block_length) {
      98                 :            :                 Botan::SecureVector<Botan::byte> hashed_key =
      99                 :            :                     hash->process(static_cast<const Botan::byte*>(secret),
     100                 :        112 :                                   secret_len);
     101         [ +  - ]:        112 :                 hmac_->set_key(hashed_key.begin(), hashed_key.size());
     102                 :            :             } else {
     103                 :            :                 // Botan 1.8 considers len 0 a bad key. 1.9 does not,
     104                 :            :                 // but we won't accept it anyway, and fail early
     105         [ +  + ]:        670 :                 if (secret_len == 0) {
     106 [ +  - ][ +  - ]:         10 :                     isc_throw(BadKey, "Bad HMAC secret length: 0");
     107                 :            :                 }
     108                 :        665 :                 hmac_->set_key(static_cast<const Botan::byte*>(secret),
     109         [ +  - ]:        665 :                                secret_len);
     110                 :            :             }
     111                 :          0 :         } catch (const Botan::Invalid_Key_Length& ikl) {
     112 [ #  # ][ #  # ]:          0 :             isc_throw(BadKey, ikl.what());
     113      [ +  -  - ]:          5 :         } catch (const Botan::Exception& exc) {
     114 [ #  # ][ #  # ]:          0 :             isc_throw(isc::cryptolink::LibraryError, exc.what());
     115                 :            :         }
     116                 :        777 :     }
     117                 :            : 
     118                 :        777 :     ~HMACImpl() { }
     119                 :            : 
     120                 :            :     size_t getOutputLength() const {
     121                 :            : #if BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,9,0)
     122                 :            :         return (hmac_->output_length());
     123                 :            : #elif BOTAN_VERSION_CODE >= BOTAN_VERSION_CODE_FOR(1,8,0)
     124                 :       1011 :         return (hmac_->OUTPUT_LENGTH);
     125                 :            : #else
     126                 :            : #error "Unsupported Botan version (need 1.8 or higher)"
     127                 :            :         // added to suppress irrelevant compiler errors
     128                 :            :         return 0;
     129                 :            : #endif
     130                 :            :     }
     131                 :            : 
     132                 :       1061 :     void update(const void* data, const size_t len) {
     133                 :            :         try {
     134                 :       1061 :             hmac_->update(static_cast<const Botan::byte*>(data), len);
     135         [ #  # ]:          0 :         } catch (const Botan::Exception& exc) {
     136 [ #  # ][ #  # ]:          0 :             isc_throw(isc::cryptolink::LibraryError, exc.what());
     137                 :            :         }
     138                 :       1061 :     }
     139                 :            : 
     140                 :         97 :     void sign(isc::util::OutputBuffer& result, size_t len) {
     141                 :            :         try {
     142         [ +  - ]:         97 :             Botan::SecureVector<Botan::byte> b_result(hmac_->final());
     143                 :            : 
     144 [ +  + ][ +  + ]:         97 :             if (len == 0 || len > b_result.size()) {
                 [ +  + ]
     145                 :         15 :                 len = b_result.size();
     146                 :            :             }
     147                 :         97 :             result.writeData(b_result.begin(), len);
     148         [ #  # ]:          0 :         } catch (const Botan::Exception& exc) {
     149 [ #  # ][ #  # ]:          0 :             isc_throw(isc::cryptolink::LibraryError, exc.what());
     150                 :            :         }
     151                 :         97 :     }
     152                 :            : 
     153                 :         36 :     void sign(void* result, size_t len) {
     154                 :            :         try {
     155         [ +  - ]:         36 :             Botan::SecureVector<Botan::byte> b_result(hmac_->final());
     156                 :         36 :             size_t output_size = getOutputLength();
     157         [ -  + ]:         36 :             if (output_size > len) {
     158                 :          0 :                 output_size = len;
     159                 :            :             }
     160                 :         36 :             std::memcpy(result, b_result.begin(), output_size);
     161         [ #  # ]:          0 :         } catch (const Botan::Exception& exc) {
     162 [ #  # ][ #  # ]:          0 :             isc_throw(isc::cryptolink::LibraryError, exc.what());
     163                 :            :         }
     164                 :         36 :     }
     165                 :            : 
     166                 :        235 :     std::vector<uint8_t> sign(size_t len) {
     167                 :            :         try {
     168         [ +  - ]:        235 :             Botan::SecureVector<Botan::byte> b_result(hmac_->final());
     169 [ +  + ][ +  + ]:        235 :             if (len == 0 || len > b_result.size()) {
                 [ +  + ]
     170         [ +  - ]:        197 :                 return (std::vector<uint8_t>(b_result.begin(), b_result.end()));
     171                 :            :             } else {
     172         [ +  - ]:         38 :                 return (std::vector<uint8_t>(b_result.begin(), &b_result[len]));
     173                 :            :             }
     174         [ #  # ]:          0 :         } catch (const Botan::Exception& exc) {
     175 [ #  # ][ #  # ]:          0 :             isc_throw(isc::cryptolink::LibraryError, exc.what());
     176                 :            :         }
     177                 :            :     }
     178                 :            : 
     179                 :            : 
     180                 :        346 :     bool verify(const void* sig, size_t len) {
     181                 :            :         // Botan's verify_mac checks if len matches the output_length,
     182                 :            :         // which causes it to fail for truncated signatures, so we do
     183                 :            :         // the check ourselves
     184                 :            :         // SEE BELOW FOR TEMPORARY CHANGE
     185                 :            :         try {
     186         [ +  - ]:        346 :             Botan::SecureVector<Botan::byte> our_mac = hmac_->final();
     187         [ +  + ]:        346 :             if (len < getOutputLength()) {
     188                 :            :                 // Currently we don't support truncated signature in TSIG (see
     189                 :            :                 // #920).  To avoid validating too short signature accidently,
     190                 :            :                 // we enforce the standard signature size for the moment.
     191                 :            :                 // Once we support truncation correctly, this if-clause should
     192                 :            :                 // (and the capitalized comment above) be removed.
     193                 :            :                 return (false);
     194                 :            :             }
     195   [ +  -  +  - ]:        688 :             if (len == 0 || len > getOutputLength()) {
                 [ -  + ]
     196                 :          0 :                 len = getOutputLength();
     197                 :            :             }
     198                 :        344 :             return (Botan::same_mem(&our_mac[0],
     199                 :            :                                     static_cast<const unsigned char*>(sig),
     200                 :        344 :                                     len));
     201         [ #  # ]:          0 :         } catch (const Botan::Exception& exc) {
     202 [ #  # ][ #  # ]:          0 :             isc_throw(isc::cryptolink::LibraryError, exc.what());
     203                 :            :         }
     204                 :            :     }
     205                 :            : 
     206                 :            : private:
     207                 :            :     boost::scoped_ptr<Botan::HMAC> hmac_;
     208                 :            : };
     209                 :            : 
     210                 :        785 : HMAC::HMAC(const void* secret, size_t secret_length,
     211                 :            :            const HashAlgorithm hash_algorithm)
     212                 :            : {
     213         [ +  + ]:        785 :     impl_ = new HMACImpl(secret, secret_length, hash_algorithm);
     214                 :        777 : }
     215                 :            : 
     216                 :        777 : HMAC::~HMAC() {
     217         [ +  - ]:       1554 :     delete impl_;
     218                 :        777 : }
     219                 :            : 
     220                 :            : size_t
     221                 :        285 : HMAC::getOutputLength() const {
     222                 :        285 :     return (impl_->getOutputLength());
     223                 :            : }
     224                 :            : 
     225                 :            : void
     226                 :       1061 : HMAC::update(const void* data, const size_t len) {
     227                 :       1061 :     impl_->update(data, len);
     228                 :       1061 : }
     229                 :            : 
     230                 :            : void
     231                 :         97 : HMAC::sign(isc::util::OutputBuffer& result, size_t len) {
     232                 :         97 :     impl_->sign(result, len);
     233                 :         97 : }
     234                 :            : 
     235                 :            : void
     236                 :         36 : HMAC::sign(void* result, size_t len) {
     237                 :         36 :     impl_->sign(result, len);
     238                 :         36 : }
     239                 :            : 
     240                 :            : std::vector<uint8_t>
     241                 :        235 : HMAC::sign(size_t len) {
     242                 :        235 :     return impl_->sign(len);
     243                 :            : }
     244                 :            : 
     245                 :            : bool
     246                 :        346 : HMAC::verify(const void* sig, const size_t len) {
     247                 :        346 :     return (impl_->verify(sig, len));
     248                 :            : }
     249                 :            : 
     250                 :            : void
     251                 :         38 : signHMAC(const void* data, const size_t data_len, const void* secret,
     252                 :            :          size_t secret_len, const HashAlgorithm hash_algorithm,
     253                 :            :          isc::util::OutputBuffer& result, size_t len)
     254                 :            : {
     255                 :            :     boost::scoped_ptr<HMAC> hmac(
     256                 :         38 :         CryptoLink::getCryptoLink().createHMAC(secret,
     257                 :            :                                                secret_len,
     258                 :         74 :                                                hash_algorithm));
     259         [ +  - ]:         36 :     hmac->update(data, data_len);
     260         [ +  - ]:         36 :     hmac->sign(result, len);
     261                 :         36 : }
     262                 :            : 
     263                 :            : 
     264                 :            : bool
     265                 :         74 : verifyHMAC(const void* data, const size_t data_len, const void* secret,
     266                 :            :            size_t secret_len, const HashAlgorithm hash_algorithm,
     267                 :            :            const void* sig, const size_t sig_len)
     268                 :            : {
     269                 :            :     boost::scoped_ptr<HMAC> hmac(
     270                 :         74 :         CryptoLink::getCryptoLink().createHMAC(secret,
     271                 :            :                                                secret_len,
     272                 :        146 :                                                hash_algorithm));
     273         [ +  - ]:         72 :     hmac->update(data, data_len);
     274         [ +  - ]:        144 :     return (hmac->verify(sig, sig_len));
     275                 :            : }
     276                 :            : 
     277                 :            : void
     278                 :        669 : deleteHMAC(HMAC* hmac) {
     279         [ +  - ]:        669 :     delete hmac;
     280                 :        669 : }
     281                 :            : 
     282                 :            : } // namespace cryptolink
     283                 :       4375 : } // namespace isc

Generated by: LCOV version 1.9