"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.11.23/lib/isc/hmacmd5.c" (7 Sep 2020, 10341 Bytes) of package /linux/misc/dns/bind9/9.11.23/bind-9.11.23.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "hmacmd5.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 /*! \file
   13  * This code implements the HMAC-MD5 keyed hash algorithm
   14  * described in RFC2104.
   15  */
   16 
   17 #include "config.h"
   18 
   19 #include <pk11/site.h>
   20 
   21 #ifndef PK11_MD5_DISABLE
   22 
   23 #include <stdbool.h>
   24 
   25 #include <isc/assertions.h>
   26 #include <isc/hmacmd5.h>
   27 #include <isc/md5.h>
   28 #include <isc/platform.h>
   29 #include <isc/safe.h>
   30 #include <isc/string.h>
   31 #include <isc/types.h>
   32 #include <isc/util.h>
   33 
   34 #if PKCS11CRYPTO
   35 #include <pk11/internal.h>
   36 #include <pk11/pk11.h>
   37 #endif
   38 
   39 #ifdef ISC_PLATFORM_OPENSSLHASH
   40 #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
   41 #define HMAC_CTX_new() &(ctx->_ctx), HMAC_CTX_init(&(ctx->_ctx))
   42 #define HMAC_CTX_free(ptr) HMAC_CTX_cleanup(ptr)
   43 #endif
   44 
   45 void
   46 isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
   47          unsigned int len)
   48 {
   49     ctx->ctx = HMAC_CTX_new();
   50     RUNTIME_CHECK(ctx->ctx != NULL);
   51     RUNTIME_CHECK(HMAC_Init_ex(ctx->ctx, (const void *) key,
   52                    (int) len, EVP_md5(), NULL) == 1);
   53 }
   54 
   55 void
   56 isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
   57     if (ctx->ctx == NULL)
   58         return;
   59     HMAC_CTX_free(ctx->ctx);
   60     ctx->ctx = NULL;
   61 }
   62 
   63 void
   64 isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
   65            unsigned int len)
   66 {
   67     RUNTIME_CHECK(HMAC_Update(ctx->ctx, buf, (int) len) == 1);
   68 }
   69 
   70 void
   71 isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
   72     RUNTIME_CHECK(HMAC_Final(ctx->ctx, digest, NULL) == 1);
   73     HMAC_CTX_free(ctx->ctx);
   74     ctx->ctx = NULL;
   75 }
   76 
   77 #elif PKCS11CRYPTO
   78 
   79 #ifndef PK11_MD5_HMAC_REPLACE
   80 
   81 static CK_BBOOL truevalue = TRUE;
   82 static CK_BBOOL falsevalue = FALSE;
   83 
   84 void
   85 isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
   86          unsigned int len)
   87 {
   88     CK_RV rv;
   89     CK_MECHANISM mech = { CKM_MD5_HMAC, NULL, 0 };
   90     CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY;
   91     CK_KEY_TYPE keyType = CKK_MD5_HMAC;
   92     CK_ATTRIBUTE keyTemplate[] =
   93     {
   94         { CKA_CLASS, &keyClass, (CK_ULONG) sizeof(keyClass) },
   95         { CKA_KEY_TYPE, &keyType, (CK_ULONG) sizeof(keyType) },
   96         { CKA_TOKEN, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
   97         { CKA_PRIVATE, &falsevalue, (CK_ULONG) sizeof(falsevalue) },
   98         { CKA_SIGN, &truevalue, (CK_ULONG) sizeof(truevalue) },
   99         { CKA_VALUE, NULL, (CK_ULONG) len }
  100     };
  101 #ifdef PK11_PAD_HMAC_KEYS
  102     CK_BYTE keypad[ISC_MD5_DIGESTLENGTH];
  103 
  104     if (len < ISC_MD5_DIGESTLENGTH) {
  105         memset(keypad, 0, ISC_MD5_DIGESTLENGTH);
  106         memmove(keypad, key, len);
  107         keyTemplate[5].pValue = keypad;
  108         keyTemplate[5].ulValueLen = ISC_MD5_DIGESTLENGTH;
  109     } else
  110         DE_CONST(key, keyTemplate[5].pValue);
  111 #else
  112     DE_CONST(key, keyTemplate[5].pValue);
  113 #endif
  114     RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
  115                        false, NULL, 0) == ISC_R_SUCCESS);
  116     ctx->object = CK_INVALID_HANDLE;
  117     PK11_FATALCHECK(pkcs_C_CreateObject,
  118             (ctx->session, keyTemplate,
  119              (CK_ULONG) 6, &ctx->object));
  120     INSIST(ctx->object != CK_INVALID_HANDLE);
  121     PK11_FATALCHECK(pkcs_C_SignInit, (ctx->session, &mech, ctx->object));
  122 }
  123 
  124 void
  125 isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
  126     CK_BYTE garbage[ISC_MD5_DIGESTLENGTH];
  127     CK_ULONG len = ISC_MD5_DIGESTLENGTH;
  128 
  129     if (ctx->handle == NULL)
  130         return;
  131     (void) pkcs_C_SignFinal(ctx->session, garbage, &len);
  132     isc_safe_memwipe(garbage, sizeof(garbage));
  133     if (ctx->object != CK_INVALID_HANDLE)
  134         (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
  135     ctx->object = CK_INVALID_HANDLE;
  136     pk11_return_session(ctx);
  137 }
  138 
  139 void
  140 isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
  141            unsigned int len)
  142 {
  143     CK_RV rv;
  144     CK_BYTE_PTR pPart;
  145 
  146     DE_CONST(buf, pPart);
  147     PK11_FATALCHECK(pkcs_C_SignUpdate,
  148             (ctx->session, pPart, (CK_ULONG) len));
  149 }
  150 
  151 void
  152 isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
  153     CK_RV rv;
  154     CK_ULONG len = ISC_MD5_DIGESTLENGTH;
  155 
  156     PK11_FATALCHECK(pkcs_C_SignFinal,
  157             (ctx->session, (CK_BYTE_PTR) digest, &len));
  158     if (ctx->object != CK_INVALID_HANDLE)
  159         (void) pkcs_C_DestroyObject(ctx->session, ctx->object);
  160     ctx->object = CK_INVALID_HANDLE;
  161     pk11_return_session(ctx);
  162 }
  163 #else
  164 /* Replace missing CKM_MD5_HMAC PKCS#11 mechanism */
  165 
  166 #define PADLEN 64
  167 #define IPAD 0x36
  168 #define OPAD 0x5C
  169 
  170 void
  171 isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
  172          unsigned int len)
  173 {
  174     CK_RV rv;
  175     CK_MECHANISM mech = { CKM_MD5, NULL, 0 };
  176     unsigned char ipad[PADLEN];
  177     unsigned int i;
  178 
  179     RUNTIME_CHECK(pk11_get_session(ctx, OP_DIGEST, true, false,
  180                        false, NULL, 0) == ISC_R_SUCCESS);
  181     RUNTIME_CHECK((ctx->key = pk11_mem_get(PADLEN)) != NULL);
  182     if (len > PADLEN) {
  183         CK_BYTE_PTR kPart;
  184         CK_ULONG kl;
  185 
  186         PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
  187         DE_CONST(key, kPart);
  188         PK11_FATALCHECK(pkcs_C_DigestUpdate,
  189                 (ctx->session, kPart, (CK_ULONG) len));
  190         kl = ISC_MD5_DIGESTLENGTH;
  191         PK11_FATALCHECK(pkcs_C_DigestFinal,
  192                 (ctx->session, (CK_BYTE_PTR) ctx->key, &kl));
  193     } else
  194         memmove(ctx->key, key, len);
  195     PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
  196     memset(ipad, IPAD, PADLEN);
  197     for (i = 0; i < PADLEN; i++)
  198         ipad[i] ^= ctx->key[i];
  199     PK11_FATALCHECK(pkcs_C_DigestUpdate,
  200             (ctx->session, ipad, (CK_ULONG) PADLEN));
  201 }
  202 
  203 void
  204 isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
  205     if (ctx->key != NULL)
  206         pk11_mem_put(ctx->key, PADLEN);
  207     ctx->key = NULL;
  208     isc_md5_invalidate(ctx);
  209 }
  210 
  211 void
  212 isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
  213            unsigned int len)
  214 {
  215     CK_RV rv;
  216     CK_BYTE_PTR pPart;
  217 
  218     DE_CONST(buf, pPart);
  219     PK11_FATALCHECK(pkcs_C_DigestUpdate,
  220             (ctx->session, pPart, (CK_ULONG) len));
  221 }
  222 
  223 void
  224 isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
  225     CK_RV rv;
  226     CK_MECHANISM mech = { CKM_MD5, NULL, 0 };
  227     CK_ULONG len = ISC_MD5_DIGESTLENGTH;
  228     CK_BYTE opad[PADLEN];
  229     unsigned int i;
  230 
  231     PK11_FATALCHECK(pkcs_C_DigestFinal,
  232             (ctx->session, (CK_BYTE_PTR) digest,
  233              (CK_ULONG_PTR) &len));
  234     memset(opad, OPAD, PADLEN);
  235     for (i = 0; i < PADLEN; i++)
  236         opad[i] ^= ctx->key[i];
  237     pk11_mem_put(ctx->key, PADLEN);
  238     ctx->key = NULL;
  239     PK11_FATALCHECK(pkcs_C_DigestInit, (ctx->session, &mech));
  240     PK11_FATALCHECK(pkcs_C_DigestUpdate,
  241             (ctx->session, opad, (CK_ULONG) PADLEN));
  242     PK11_FATALCHECK(pkcs_C_DigestUpdate,
  243             (ctx->session, (CK_BYTE_PTR) digest, len));
  244     PK11_FATALCHECK(pkcs_C_DigestFinal,
  245             (ctx->session,
  246              (CK_BYTE_PTR) digest,
  247              (CK_ULONG_PTR) &len));
  248     pk11_return_session(ctx);
  249 }
  250 #endif
  251 
  252 #else
  253 
  254 #define PADLEN 64
  255 #define IPAD 0x36
  256 #define OPAD 0x5C
  257 
  258 /*!
  259  * Start HMAC-MD5 process.  Initialize an md5 context and digest the key.
  260  */
  261 void
  262 isc_hmacmd5_init(isc_hmacmd5_t *ctx, const unsigned char *key,
  263          unsigned int len)
  264 {
  265     unsigned char ipad[PADLEN];
  266     int i;
  267 
  268     memset(ctx->key, 0, sizeof(ctx->key));
  269     if (len > sizeof(ctx->key)) {
  270         isc_md5_t md5ctx;
  271         isc_md5_init(&md5ctx);
  272         isc_md5_update(&md5ctx, key, len);
  273         isc_md5_final(&md5ctx, ctx->key);
  274     } else
  275         memmove(ctx->key, key, len);
  276 
  277     isc_md5_init(&ctx->md5ctx);
  278     memset(ipad, IPAD, sizeof(ipad));
  279     for (i = 0; i < PADLEN; i++)
  280         ipad[i] ^= ctx->key[i];
  281     isc_md5_update(&ctx->md5ctx, ipad, sizeof(ipad));
  282 }
  283 
  284 void
  285 isc_hmacmd5_invalidate(isc_hmacmd5_t *ctx) {
  286     isc_md5_invalidate(&ctx->md5ctx);
  287     isc_safe_memwipe(ctx->key, sizeof(ctx->key));
  288 }
  289 
  290 /*!
  291  * Update context to reflect the concatenation of another buffer full
  292  * of bytes.
  293  */
  294 void
  295 isc_hmacmd5_update(isc_hmacmd5_t *ctx, const unsigned char *buf,
  296            unsigned int len)
  297 {
  298     isc_md5_update(&ctx->md5ctx, buf, len);
  299 }
  300 
  301 /*!
  302  * Compute signature - finalize MD5 operation and reapply MD5.
  303  */
  304 void
  305 isc_hmacmd5_sign(isc_hmacmd5_t *ctx, unsigned char *digest) {
  306     unsigned char opad[PADLEN];
  307     int i;
  308 
  309     isc_md5_final(&ctx->md5ctx, digest);
  310 
  311     memset(opad, OPAD, sizeof(opad));
  312     for (i = 0; i < PADLEN; i++)
  313         opad[i] ^= ctx->key[i];
  314 
  315     isc_md5_init(&ctx->md5ctx);
  316     isc_md5_update(&ctx->md5ctx, opad, sizeof(opad));
  317     isc_md5_update(&ctx->md5ctx, digest, ISC_MD5_DIGESTLENGTH);
  318     isc_md5_final(&ctx->md5ctx, digest);
  319     isc_hmacmd5_invalidate(ctx);
  320 }
  321 
  322 #endif /* !ISC_PLATFORM_OPENSSLHASH */
  323 
  324 /*!
  325  * Verify signature - finalize MD5 operation and reapply MD5, then
  326  * compare to the supplied digest.
  327  */
  328 bool
  329 isc_hmacmd5_verify(isc_hmacmd5_t *ctx, unsigned char *digest) {
  330     return (isc_hmacmd5_verify2(ctx, digest, ISC_MD5_DIGESTLENGTH));
  331 }
  332 
  333 bool
  334 isc_hmacmd5_verify2(isc_hmacmd5_t *ctx, unsigned char *digest, size_t len) {
  335     unsigned char newdigest[ISC_MD5_DIGESTLENGTH];
  336 
  337     REQUIRE(len <= ISC_MD5_DIGESTLENGTH);
  338     isc_hmacmd5_sign(ctx, newdigest);
  339     return (isc_safe_memequal(digest, newdigest, len));
  340 }
  341 
  342 /*
  343  * Check for MD5 support; if it does not work, raise a fatal error.
  344  *
  345  * Use the first test vector from RFC 2104, with a second round using
  346  * a too-short key.
  347  *
  348  * Standard use is testing 0 and expecting result true.
  349  * Testing use is testing 1..4 and expecting result false.
  350  */
  351 bool
  352 isc_hmacmd5_check(int testing) {
  353     isc_hmacmd5_t ctx;
  354     unsigned char key[] = { /* 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b */
  355         0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
  356         0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
  357     };
  358     unsigned char input[] = { /* "Hi There" */
  359         0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65
  360     };
  361     unsigned char expected[] = {
  362         0x92, 0x94, 0x72, 0x7a, 0x36, 0x38, 0xbb, 0x1c,
  363         0x13, 0xf4, 0x8e, 0xf8, 0x15, 0x8b, 0xfc, 0x9d
  364     };
  365     unsigned char expected2[] = {
  366         0xad, 0xb8, 0x48, 0x05, 0xb8, 0x8d, 0x03, 0xe5,
  367         0x90, 0x1e, 0x4b, 0x05, 0x69, 0xce, 0x35, 0xea
  368     };
  369     bool result;
  370 
  371     /*
  372      * Introduce a fault for testing.
  373      */
  374     switch (testing) {
  375     case 0:
  376     default:
  377         break;
  378     case 1:
  379         key[0] ^= 0x01;
  380         break;
  381     case 2:
  382         input[0] ^= 0x01;
  383         break;
  384     case 3:
  385         expected[0] ^= 0x01;
  386         break;
  387     case 4:
  388         expected2[0] ^= 0x01;
  389         break;
  390     }
  391 
  392     /*
  393      * These functions do not return anything; any failure will be fatal.
  394      */
  395     isc_hmacmd5_init(&ctx, key, 16U);
  396     isc_hmacmd5_update(&ctx, input, 8U);
  397     result = isc_hmacmd5_verify2(&ctx, expected, sizeof(expected));
  398     if (!result) {
  399         return (result);
  400     }
  401 
  402     /* Second round using a byte key */
  403     isc_hmacmd5_init(&ctx, key, 1U);
  404     isc_hmacmd5_update(&ctx, input, 8U);
  405     return (isc_hmacmd5_verify2(&ctx, expected2, sizeof(expected2)));
  406 }
  407 
  408 #else /* !PK11_MD5_DISABLE */
  409 
  410 #include <isc/util.h>
  411 
  412 EMPTY_TRANSLATION_UNIT
  413 
  414 #endif /* PK11_MD5_DISABLE */