| 1 | /*************************************************************************** |
| 2 | * _ _ ____ _ |
| 3 | * Project ___| | | | _ \| | |
| 4 | * / __| | | | |_) | | |
| 5 | * | (__| |_| | _ <| |___ |
| 6 | * \___|\___/|_| \_\_____| |
| 7 | * |
| 8 | * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. |
| 9 | * |
| 10 | * This software is licensed as described in the file COPYING, which |
| 11 | * you should have received as part of this distribution. The terms |
| 12 | * are also available at https://curl.se/docs/copyright.html. |
| 13 | * |
| 14 | * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
| 15 | * copies of the Software, and permit persons to whom the Software is |
| 16 | * furnished to do so, under the terms of the COPYING file. |
| 17 | * |
| 18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
| 19 | * KIND, either express or implied. |
| 20 | * |
| 21 | * SPDX-License-Identifier: curl |
| 22 | * |
| 23 | * RFC2104 Keyed-Hashing for Message Authentication |
| 24 | * |
| 25 | ***************************************************************************/ |
| 26 | |
| 27 | #include "curl_setup.h" |
| 28 | |
| 29 | #if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \ |
| 30 | || !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) |
| 31 | |
| 32 | #include <curl/curl.h> |
| 33 | |
| 34 | #include "curl_hmac.h" |
| 35 | #include "curl_memory.h" |
| 36 | #include "warnless.h" |
| 37 | |
| 38 | /* The last #include file should be: */ |
| 39 | #include "memdebug.h" |
| 40 | |
| 41 | /* |
| 42 | * Generic HMAC algorithm. |
| 43 | * |
| 44 | * This module computes HMAC digests based on any hash function. Parameters |
| 45 | * and computing procedures are set-up dynamically at HMAC computation context |
| 46 | * initialization. |
| 47 | */ |
| 48 | |
| 49 | static const unsigned char hmac_ipad = 0x36; |
| 50 | static const unsigned char hmac_opad = 0x5C; |
| 51 | |
| 52 | |
| 53 | |
| 54 | struct HMAC_context * |
| 55 | Curl_HMAC_init(const struct HMAC_params *hashparams, |
| 56 | const unsigned char *key, |
| 57 | unsigned int keylen) |
| 58 | { |
| 59 | size_t i; |
| 60 | struct HMAC_context *ctxt; |
| 61 | unsigned char *hkey; |
| 62 | unsigned char b; |
| 63 | |
| 64 | /* Create HMAC context. */ |
| 65 | i = sizeof(*ctxt) + 2 * hashparams->hmac_ctxtsize + |
| 66 | hashparams->hmac_resultlen; |
| 67 | ctxt = malloc(i); |
| 68 | |
| 69 | if(!ctxt) |
| 70 | return ctxt; |
| 71 | |
| 72 | ctxt->hmac_hash = hashparams; |
| 73 | ctxt->hmac_hashctxt1 = (void *) (ctxt + 1); |
| 74 | ctxt->hmac_hashctxt2 = (void *) ((char *) ctxt->hmac_hashctxt1 + |
| 75 | hashparams->hmac_ctxtsize); |
| 76 | |
| 77 | /* If the key is too long, replace it by its hash digest. */ |
| 78 | if(keylen > hashparams->hmac_maxkeylen) { |
| 79 | (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1); |
| 80 | (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, key, keylen); |
| 81 | hkey = (unsigned char *) ctxt->hmac_hashctxt2 + hashparams->hmac_ctxtsize; |
| 82 | (*hashparams->hmac_hfinal)(hkey, ctxt->hmac_hashctxt1); |
| 83 | key = hkey; |
| 84 | keylen = hashparams->hmac_resultlen; |
| 85 | } |
| 86 | |
| 87 | /* Prime the two hash contexts with the modified key. */ |
| 88 | (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1); |
| 89 | (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt2); |
| 90 | |
| 91 | for(i = 0; i < keylen; i++) { |
| 92 | b = (unsigned char)(*key ^ hmac_ipad); |
| 93 | (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &b, 1); |
| 94 | b = (unsigned char)(*key++ ^ hmac_opad); |
| 95 | (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &b, 1); |
| 96 | } |
| 97 | |
| 98 | for(; i < hashparams->hmac_maxkeylen; i++) { |
| 99 | (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &hmac_ipad, 1); |
| 100 | (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &hmac_opad, 1); |
| 101 | } |
| 102 | |
| 103 | /* Done, return pointer to HMAC context. */ |
| 104 | return ctxt; |
| 105 | } |
| 106 | |
| 107 | int Curl_HMAC_update(struct HMAC_context *ctxt, |
| 108 | const unsigned char *data, |
| 109 | unsigned int len) |
| 110 | { |
| 111 | /* Update first hash calculation. */ |
| 112 | (*ctxt->hmac_hash->hmac_hupdate)(ctxt->hmac_hashctxt1, data, len); |
| 113 | return 0; |
| 114 | } |
| 115 | |
| 116 | |
| 117 | int Curl_HMAC_final(struct HMAC_context *ctxt, unsigned char *result) |
| 118 | { |
| 119 | const struct HMAC_params *hashparams = ctxt->hmac_hash; |
| 120 | |
| 121 | /* Do not get result if called with a null parameter: only release |
| 122 | storage. */ |
| 123 | |
| 124 | if(!result) |
| 125 | result = (unsigned char *) ctxt->hmac_hashctxt2 + |
| 126 | ctxt->hmac_hash->hmac_ctxtsize; |
| 127 | |
| 128 | (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt1); |
| 129 | (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, |
| 130 | result, hashparams->hmac_resultlen); |
| 131 | (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt2); |
| 132 | free((char *) ctxt); |
| 133 | return 0; |
| 134 | } |
| 135 | |
| 136 | /* |
| 137 | * Curl_hmacit() |
| 138 | * |
| 139 | * This is used to generate a HMAC hash, for the specified input data, given |
| 140 | * the specified hash function and key. |
| 141 | * |
| 142 | * Parameters: |
| 143 | * |
| 144 | * hashparams [in] - The hash function (Curl_HMAC_MD5). |
| 145 | * key [in] - The key to use. |
| 146 | * keylen [in] - The length of the key. |
| 147 | * data [in] - The data to encrypt. |
| 148 | * datalen [in] - The length of the data. |
| 149 | * output [in/out] - The output buffer. |
| 150 | * |
| 151 | * Returns CURLE_OK on success. |
| 152 | */ |
| 153 | CURLcode Curl_hmacit(const struct HMAC_params *hashparams, |
| 154 | const unsigned char *key, const size_t keylen, |
| 155 | const unsigned char *data, const size_t datalen, |
| 156 | unsigned char *output) |
| 157 | { |
| 158 | struct HMAC_context *ctxt = |
| 159 | Curl_HMAC_init(hashparams, key, keylen: curlx_uztoui(uznum: keylen)); |
| 160 | |
| 161 | if(!ctxt) |
| 162 | return CURLE_OUT_OF_MEMORY; |
| 163 | |
| 164 | /* Update the digest with the given challenge */ |
| 165 | Curl_HMAC_update(ctxt, data, len: curlx_uztoui(uznum: datalen)); |
| 166 | |
| 167 | /* Finalise the digest */ |
| 168 | Curl_HMAC_final(ctxt, result: output); |
| 169 | |
| 170 | return CURLE_OK; |
| 171 | } |
| 172 | |
| 173 | #endif /* Using NTLM (without SSPI) or AWS */ |
| 174 | |