Coverage Report

Created: 2026-04-29 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmcurl/lib/sha256.c
Line
Count
Source
1
/***************************************************************************
2
 *                                  _   _ ____  _
3
 *  Project                     ___| | | |  _ \| |
4
 *                             / __| | | | |_) | |
5
 *                            | (__| |_| |  _ <| |___
6
 *                             \___|\___/|_| \_\_____|
7
 *
8
 * Copyright (C) Florin Petriuc, <petriuc.florin@gmail.com>
9
 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
10
 *
11
 * This software is licensed as described in the file COPYING, which
12
 * you should have received as part of this distribution. The terms
13
 * are also available at https://curl.se/docs/copyright.html.
14
 *
15
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
16
 * copies of the Software, and permit persons to whom the Software is
17
 * furnished to do so, under the terms of the COPYING file.
18
 *
19
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20
 * KIND, either express or implied.
21
 *
22
 * SPDX-License-Identifier: curl
23
 *
24
 ***************************************************************************/
25
#include "curl_setup.h"
26
27
#if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) || \
28
  defined(USE_LIBSSH2) || defined(USE_SSL)
29
30
#include "curl_sha256.h"
31
32
#ifdef USE_MBEDTLS
33
#include <mbedtls/version.h>
34
#if MBEDTLS_VERSION_NUMBER < 0x03020000
35
#error "mbedTLS 3.2.0 or later required"
36
#endif
37
#include <psa/crypto_config.h>
38
#endif
39
40
/* Please keep the SSL backend-specific #if branches in this order:
41
 *
42
 * 1. USE_OPENSSL
43
 * 2. USE_GNUTLS
44
 * 3. USE_MBEDTLS
45
 * 4. USE_COMMON_CRYPTO
46
 * 5. USE_WIN32_CRYPTO
47
 *
48
 * This ensures that the same SSL branch gets activated throughout this source
49
 * file even if multiple backends are enabled at the same time.
50
 */
51
52
#ifdef USE_OPENSSL
53
#include <openssl/evp.h>
54
55
struct ossl_sha256_ctx {
56
  EVP_MD_CTX *openssl_ctx;
57
};
58
typedef struct ossl_sha256_ctx my_sha256_ctx;
59
60
static CURLcode my_sha256_init(void *in)
61
{
62
  my_sha256_ctx *ctx = (my_sha256_ctx *)in;
63
  ctx->openssl_ctx = EVP_MD_CTX_create();
64
  if(!ctx->openssl_ctx)
65
    return CURLE_OUT_OF_MEMORY;
66
67
  if(!EVP_DigestInit_ex(ctx->openssl_ctx, EVP_sha256(), NULL)) {
68
    EVP_MD_CTX_destroy(ctx->openssl_ctx);
69
    return CURLE_FAILED_INIT;
70
  }
71
  return CURLE_OK;
72
}
73
74
static void my_sha256_update(void *in,
75
                             const unsigned char *data,
76
                             unsigned int length)
77
{
78
  my_sha256_ctx *ctx = (my_sha256_ctx *)in;
79
  EVP_DigestUpdate(ctx->openssl_ctx, data, length);
80
}
81
82
static void my_sha256_final(unsigned char *digest, void *in)
83
{
84
  my_sha256_ctx *ctx = (my_sha256_ctx *)in;
85
  EVP_DigestFinal_ex(ctx->openssl_ctx, digest, NULL);
86
  EVP_MD_CTX_destroy(ctx->openssl_ctx);
87
}
88
89
#elif defined(USE_GNUTLS)
90
#include <nettle/sha.h>
91
92
typedef struct sha256_ctx my_sha256_ctx;
93
94
static CURLcode my_sha256_init(void *ctx)
95
{
96
  sha256_init(ctx);
97
  return CURLE_OK;
98
}
99
100
static void my_sha256_update(void *ctx,
101
                             const unsigned char *data,
102
                             unsigned int length)
103
{
104
  sha256_update(ctx, length, data);
105
}
106
107
static void my_sha256_final(unsigned char *digest, void *ctx)
108
{
109
  sha256_digest(ctx, SHA256_DIGEST_SIZE, digest);
110
}
111
112
#elif defined(USE_MBEDTLS) && \
113
  defined(PSA_WANT_ALG_SHA_256) && PSA_WANT_ALG_SHA_256  /* mbedTLS 4+ */
114
#include <psa/crypto.h>
115
116
typedef psa_hash_operation_t my_sha256_ctx;
117
118
static CURLcode my_sha256_init(void *ctx)
119
{
120
  memset(ctx, 0, sizeof(my_sha256_ctx));
121
  if(psa_hash_setup(ctx, PSA_ALG_SHA_256) != PSA_SUCCESS)
122
    return CURLE_OUT_OF_MEMORY;
123
  return CURLE_OK;
124
}
125
126
static void my_sha256_update(void *ctx,
127
                             const unsigned char *data,
128
                             unsigned int length)
129
{
130
  (void)psa_hash_update(ctx, data, length);
131
}
132
133
static void my_sha256_final(unsigned char *digest, void *ctx)
134
{
135
  size_t actual_length;
136
  (void)psa_hash_finish(ctx, digest, CURL_SHA256_DIGEST_LENGTH,
137
                        &actual_length);
138
}
139
140
#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
141
              (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
142
      (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
143
              (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
144
#include <CommonCrypto/CommonDigest.h>
145
146
typedef CC_SHA256_CTX my_sha256_ctx;
147
148
static CURLcode my_sha256_init(void *ctx)
149
{
150
  (void)CC_SHA256_Init(ctx);
151
  return CURLE_OK;
152
}
153
154
static void my_sha256_update(void *ctx,
155
                             const unsigned char *data,
156
                             unsigned int length)
157
{
158
  (void)CC_SHA256_Update(ctx, data, length);
159
}
160
161
static void my_sha256_final(unsigned char *digest, void *ctx)
162
{
163
  (void)CC_SHA256_Final(digest, ctx);
164
}
165
166
#elif defined(USE_WIN32_CRYPTO)
167
#include <wincrypt.h>
168
169
struct sha256_ctx {
170
  HCRYPTPROV hCryptProv;
171
  HCRYPTHASH hHash;
172
};
173
typedef struct sha256_ctx my_sha256_ctx;
174
175
static CURLcode my_sha256_init(void *in)
176
{
177
  my_sha256_ctx *ctx = (my_sha256_ctx *)in;
178
  if(!CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES,
179
                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
180
    return CURLE_OUT_OF_MEMORY;
181
182
  if(!CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash)) {
183
    CryptReleaseContext(ctx->hCryptProv, 0);
184
    ctx->hCryptProv = 0;
185
    return CURLE_FAILED_INIT;
186
  }
187
188
  return CURLE_OK;
189
}
190
191
static void my_sha256_update(void *in,
192
                             const unsigned char *data,
193
                             unsigned int length)
194
{
195
  my_sha256_ctx *ctx = (my_sha256_ctx *)in;
196
  CryptHashData(ctx->hHash, (const BYTE *)data, length, 0);
197
}
198
199
static void my_sha256_final(unsigned char *digest, void *in)
200
{
201
  my_sha256_ctx *ctx = (my_sha256_ctx *)in;
202
  unsigned long length = 0;
203
204
  CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
205
  if(length == CURL_SHA256_DIGEST_LENGTH)
206
    CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
207
208
  if(ctx->hHash)
209
    CryptDestroyHash(ctx->hHash);
210
211
  if(ctx->hCryptProv)
212
    CryptReleaseContext(ctx->hCryptProv, 0);
213
}
214
215
#else
216
217
/* When no other crypto library is available we use this code segment */
218
219
/* This is based on the SHA256 implementation in LibTomCrypt that was released
220
 * into public domain. */
221
222
#define WPA_GET_BE32(a)              \
223
0
  ((((unsigned long)(a)[0]) << 24) | \
224
0
   (((unsigned long)(a)[1]) << 16) | \
225
0
   (((unsigned long)(a)[2]) <<  8) | \
226
0
    ((unsigned long)(a)[3]))
227
#define WPA_PUT_BE32(a, val)                                         \
228
0
  do {                                                               \
229
0
    (a)[0] = (unsigned char)((((unsigned long)(val)) >> 24) & 0xff); \
230
0
    (a)[1] = (unsigned char)((((unsigned long)(val)) >> 16) & 0xff); \
231
0
    (a)[2] = (unsigned char)((((unsigned long)(val)) >>  8) & 0xff); \
232
0
    (a)[3] = (unsigned char) (((unsigned long)(val)) & 0xff);        \
233
0
  } while(0)
234
235
#define WPA_PUT_BE64(a, val)                            \
236
0
  do {                                                  \
237
0
    (a)[0] = (unsigned char)(((uint64_t)(val)) >> 56);  \
238
0
    (a)[1] = (unsigned char)(((uint64_t)(val)) >> 48);  \
239
0
    (a)[2] = (unsigned char)(((uint64_t)(val)) >> 40);  \
240
0
    (a)[3] = (unsigned char)(((uint64_t)(val)) >> 32);  \
241
0
    (a)[4] = (unsigned char)(((uint64_t)(val)) >> 24);  \
242
0
    (a)[5] = (unsigned char)(((uint64_t)(val)) >> 16);  \
243
0
    (a)[6] = (unsigned char)(((uint64_t)(val)) >>  8);  \
244
0
    (a)[7] = (unsigned char)(((uint64_t)(val)) & 0xff); \
245
0
  } while(0)
246
247
struct sha256_state {
248
  uint64_t length;
249
  unsigned long state[8], curlen;
250
  unsigned char buf[64];
251
};
252
typedef struct sha256_state my_sha256_ctx;
253
254
/* The K array */
255
static const unsigned long K[64] = {
256
  0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
257
  0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
258
  0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
259
  0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
260
  0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
261
  0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
262
  0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
263
  0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
264
  0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
265
  0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
266
  0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
267
  0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
268
  0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
269
};
270
271
/* Various logical functions */
272
#define RORc(x, y) \
273
0
  (((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long)((y) & 31)) | \
274
0
     ((unsigned long)(x) << (unsigned long)(32 - ((y) & 31)))) & 0xFFFFFFFFUL)
275
276
0
#define Sha256_Ch(x, y, z)  (z ^ (x & (y ^ z)))
277
0
#define Sha256_Maj(x, y, z) (((x | y) & z) | (x & y))
278
0
#define Sha256_S(x, n)      RORc(x, n)
279
0
#define Sha256_R(x, n)      (((x) & 0xFFFFFFFFUL) >> (n))
280
281
0
#define Sigma0(x)         (Sha256_S(x, 2) ^ Sha256_S(x, 13) ^ Sha256_S(x, 22))
282
0
#define Sigma1(x)         (Sha256_S(x, 6) ^ Sha256_S(x, 11) ^ Sha256_S(x, 25))
283
0
#define Gamma0(x)         (Sha256_S(x, 7) ^ Sha256_S(x, 18) ^ Sha256_R(x, 3))
284
0
#define Gamma1(x)         (Sha256_S(x, 17) ^ Sha256_S(x, 19) ^ Sha256_R(x, 10))
285
286
/* Compress 512 bits */
287
static int sha256_compress(struct sha256_state *md, const unsigned char *buf)
288
0
{
289
0
  unsigned long S[8], W[64];
290
0
  int i;
291
292
  /* Copy state into S */
293
0
  for(i = 0; i < 8; i++) {
294
0
    S[i] = md->state[i];
295
0
  }
296
  /* copy the state into 512 bits into W[0..15] */
297
0
  for(i = 0; i < 16; i++)
298
0
    W[i] = WPA_GET_BE32(buf + (4 * i));
299
  /* fill W[16..63] */
300
0
  for(i = 16; i < 64; i++) {
301
0
    W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
302
0
  }
303
304
  /* Compress */
305
0
#define RND(a, b, c, d, e, f, g, h, i)                                   \
306
0
  do {                                                                   \
307
0
    unsigned long t0 = h + Sigma1(e) + Sha256_Ch(e, f, g) + K[i] + W[i]; \
308
0
    unsigned long t1 = Sigma0(a) + Sha256_Maj(a, b, c);                  \
309
0
    d += t0;                                                             \
310
0
    h = t0 + t1;                                                         \
311
0
  } while(0)
312
313
0
  for(i = 0; i < 64; ++i) {
314
0
    unsigned long t;
315
0
    RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
316
0
    t = S[7];
317
0
    S[7] = S[6];
318
0
    S[6] = S[5];
319
0
    S[5] = S[4];
320
0
    S[4] = S[3];
321
0
    S[3] = S[2];
322
0
    S[2] = S[1];
323
0
    S[1] = S[0];
324
0
    S[0] = t;
325
0
  }
326
327
  /* Feedback */
328
0
  for(i = 0; i < 8; i++) {
329
0
    md->state[i] = md->state[i] + S[i];
330
0
  }
331
332
0
  return 0;
333
0
}
334
335
/* Initialize the hash state */
336
static CURLcode my_sha256_init(void *in)
337
0
{
338
0
  struct sha256_state *md = (struct sha256_state *)in;
339
0
  md->curlen = 0;
340
0
  md->length = 0;
341
0
  md->state[0] = 0x6A09E667UL;
342
0
  md->state[1] = 0xBB67AE85UL;
343
0
  md->state[2] = 0x3C6EF372UL;
344
0
  md->state[3] = 0xA54FF53AUL;
345
0
  md->state[4] = 0x510E527FUL;
346
0
  md->state[5] = 0x9B05688CUL;
347
0
  md->state[6] = 0x1F83D9ABUL;
348
0
  md->state[7] = 0x5BE0CD19UL;
349
350
0
  return CURLE_OK;
351
0
}
352
353
/*
354
   Process a block of memory though the hash
355
   @param md     The hash state
356
   @param in     The data to hash
357
   @param inlen  The length of the data (octets)
358
*/
359
static void my_sha256_update(void *ctx,
360
                             const unsigned char *in,
361
                             unsigned int len)
362
0
{
363
0
  unsigned long inlen = len;
364
0
  unsigned long n;
365
0
  struct sha256_state *md = (struct sha256_state *)ctx;
366
0
#define CURL_SHA256_BLOCK_SIZE 64
367
0
  if(md->curlen > sizeof(md->buf))
368
0
    return;
369
0
  while(inlen > 0) {
370
0
    if(md->curlen == 0 && inlen >= CURL_SHA256_BLOCK_SIZE) {
371
0
      if(sha256_compress(md, in) < 0)
372
0
        return;
373
0
      md->length += CURL_SHA256_BLOCK_SIZE * 8;
374
0
      in += CURL_SHA256_BLOCK_SIZE;
375
0
      inlen -= CURL_SHA256_BLOCK_SIZE;
376
0
    }
377
0
    else {
378
0
      n = CURLMIN(inlen, (CURL_SHA256_BLOCK_SIZE - md->curlen));
379
0
      memcpy(md->buf + md->curlen, in, n);
380
0
      md->curlen += n;
381
0
      in += n;
382
0
      inlen -= n;
383
0
      if(md->curlen == CURL_SHA256_BLOCK_SIZE) {
384
0
        if(sha256_compress(md, md->buf) < 0)
385
0
          return;
386
0
        md->length += 8 * CURL_SHA256_BLOCK_SIZE;
387
0
        md->curlen = 0;
388
0
      }
389
0
    }
390
0
  }
391
0
}
392
393
/*
394
   Terminate the hash to get the digest
395
   @param md  The hash state
396
   @param out [out] The destination of the hash (32 bytes)
397
   @return 0 if successful
398
*/
399
static void my_sha256_final(unsigned char *out, void *ctx)
400
0
{
401
0
  struct sha256_state *md = ctx;
402
0
  int i;
403
404
0
  if(md->curlen >= sizeof(md->buf))
405
0
    return;
406
407
  /* Increase the length of the message */
408
0
  md->length += md->curlen * 8;
409
410
  /* Append the '1' bit */
411
0
  md->buf[md->curlen++] = (unsigned char)0x80;
412
413
  /* If the length is currently above 56 bytes we append zeros
414
   * then compress. Then we can fall back to padding zeros and length
415
   * encoding like normal.
416
   */
417
0
  if(md->curlen > 56) {
418
0
    while(md->curlen < 64) {
419
0
      md->buf[md->curlen++] = 0;
420
0
    }
421
0
    sha256_compress(md, md->buf);
422
0
    md->curlen = 0;
423
0
  }
424
425
  /* Pad up to 56 bytes of zeroes */
426
0
  while(md->curlen < 56) {
427
0
    md->buf[md->curlen++] = 0;
428
0
  }
429
430
  /* Store length */
431
0
  WPA_PUT_BE64(md->buf + 56, md->length);
432
0
  sha256_compress(md, md->buf);
433
434
  /* Copy output */
435
0
  for(i = 0; i < 8; i++)
436
0
    WPA_PUT_BE32(out + (4 * i), md->state[i]);
437
0
}
438
439
#endif /* CRYPTO LIBS */
440
441
/*
442
 * Curl_sha256it()
443
 *
444
 * Generates a SHA256 hash for the given input data.
445
 *
446
 * Parameters:
447
 *
448
 * output [in/out] - The output buffer.
449
 * input  [in]     - The input data.
450
 * length [in]     - The input length.
451
 *
452
 * Returns CURLE_OK on success.
453
 */
454
CURLcode Curl_sha256it(unsigned char *output, const unsigned char *input,
455
                       const size_t len)
456
0
{
457
0
  CURLcode result;
458
0
  my_sha256_ctx ctx;
459
460
0
  result = my_sha256_init(&ctx);
461
0
  if(!result) {
462
0
    my_sha256_update(&ctx, input, curlx_uztoui(len));
463
0
    my_sha256_final(output, &ctx);
464
0
  }
465
0
  return result;
466
0
}
467
468
const struct HMAC_params Curl_HMAC_SHA256 = {
469
  my_sha256_init,        /* Hash initialization function. */
470
  my_sha256_update,      /* Hash update function. */
471
  my_sha256_final,       /* Hash computation end function. */
472
  sizeof(my_sha256_ctx), /* Size of hash context structure. */
473
  64,                    /* Maximum key length. */
474
  32                     /* Result size. */
475
};
476
477
#endif /* AWS, DIGEST, or libssh2 */