Coverage Report

Created: 2025-08-28 07:06

/src/cups/cups/hash.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Hashing function for CUPS.
3
 *
4
 * Copyright © 2015-2019 by Apple Inc.
5
 *
6
 * These coded instructions, statements, and computer programs are the
7
 * property of Apple Inc. and are protected by Federal copyright
8
 * law.  Distribution and use rights are outlined in the file "LICENSE.txt"
9
 * which should have been included with this file.  If this file is
10
 * missing or damaged, see the license at "http://www.cups.org/".
11
 *
12
 * This file is subject to the Apple OS-Developed Software exception.
13
 */
14
15
/*
16
 * Include necessary headers...
17
 */
18
19
#include "cups-private.h"
20
#ifdef __APPLE__
21
#  include <CommonCrypto/CommonDigest.h>
22
#elif defined(HAVE_GNUTLS)
23
#  include <gnutls/crypto.h>
24
#else
25
#  include "md5-private.h"
26
#endif /* __APPLE__ */
27
28
29
/*
30
 * 'cupsHashData()' - Perform a hash function on the given data.
31
 *
32
 * The "algorithm" argument can be any of the registered, non-deprecated IPP
33
 * hash algorithms for the "job-password-encryption" attribute, including
34
 * "sha" for SHA-1, "sha-256" for SHA2-256, etc.
35
 *
36
 * The "hash" argument points to a buffer of "hashsize" bytes and should be at
37
 * least 64 bytes in length for all of the supported algorithms.
38
 *
39
 * The returned hash is binary data.
40
 *
41
 * @since CUPS 2.2/macOS 10.12@
42
 */
43
44
ssize_t         /* O - Size of hash or -1 on error */
45
cupsHashData(const char    *algorithm,  /* I - Algorithm name */
46
             const void    *data, /* I - Data to hash */
47
             size_t        datalen, /* I - Length of data to hash */
48
             unsigned char *hash, /* I - Hash buffer */
49
             size_t        hashsize)  /* I - Size of hash buffer */
50
0
{
51
0
  if (!algorithm || !data || datalen == 0 || !hash || hashsize == 0)
52
0
  {
53
0
    _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad arguments to function"), 1);
54
0
    return (-1);
55
0
  }
56
57
#ifdef __APPLE__
58
  if (!strcmp(algorithm, "md5"))
59
  {
60
   /*
61
    * MD5 (deprecated but widely used...)
62
    */
63
64
    CC_MD5_CTX  ctx;      /* MD5 context */
65
66
    if (hashsize < CC_MD5_DIGEST_LENGTH)
67
      goto too_small;
68
69
    CC_MD5_Init(&ctx);
70
    CC_MD5_Update(&ctx, data, (CC_LONG)datalen);
71
    CC_MD5_Final(hash, &ctx);
72
73
    return (CC_MD5_DIGEST_LENGTH);
74
  }
75
  else if (!strcmp(algorithm, "sha"))
76
  {
77
   /*
78
    * SHA-1...
79
    */
80
81
    CC_SHA1_CTX ctx;      /* SHA-1 context */
82
83
    if (hashsize < CC_SHA1_DIGEST_LENGTH)
84
      goto too_small;
85
86
    CC_SHA1_Init(&ctx);
87
    CC_SHA1_Update(&ctx, data, (CC_LONG)datalen);
88
    CC_SHA1_Final(hash, &ctx);
89
90
    return (CC_SHA1_DIGEST_LENGTH);
91
  }
92
  else if (!strcmp(algorithm, "sha2-224"))
93
  {
94
    CC_SHA256_CTX ctx;    /* SHA-224 context */
95
96
    if (hashsize < CC_SHA224_DIGEST_LENGTH)
97
      goto too_small;
98
99
    CC_SHA224_Init(&ctx);
100
    CC_SHA224_Update(&ctx, data, (CC_LONG)datalen);
101
    CC_SHA224_Final(hash, &ctx);
102
103
    return (CC_SHA224_DIGEST_LENGTH);
104
  }
105
  else if (!strcmp(algorithm, "sha2-256"))
106
  {
107
    CC_SHA256_CTX ctx;    /* SHA-256 context */
108
109
    if (hashsize < CC_SHA256_DIGEST_LENGTH)
110
      goto too_small;
111
112
    CC_SHA256_Init(&ctx);
113
    CC_SHA256_Update(&ctx, data, (CC_LONG)datalen);
114
    CC_SHA256_Final(hash, &ctx);
115
116
    return (CC_SHA256_DIGEST_LENGTH);
117
  }
118
  else if (!strcmp(algorithm, "sha2-384"))
119
  {
120
    CC_SHA512_CTX ctx;    /* SHA-384 context */
121
122
    if (hashsize < CC_SHA384_DIGEST_LENGTH)
123
      goto too_small;
124
125
    CC_SHA384_Init(&ctx);
126
    CC_SHA384_Update(&ctx, data, (CC_LONG)datalen);
127
    CC_SHA384_Final(hash, &ctx);
128
129
    return (CC_SHA384_DIGEST_LENGTH);
130
  }
131
  else if (!strcmp(algorithm, "sha2-512"))
132
  {
133
    CC_SHA512_CTX ctx;    /* SHA-512 context */
134
135
    if (hashsize < CC_SHA512_DIGEST_LENGTH)
136
      goto too_small;
137
138
    CC_SHA512_Init(&ctx);
139
    CC_SHA512_Update(&ctx, data, (CC_LONG)datalen);
140
    CC_SHA512_Final(hash, &ctx);
141
142
    return (CC_SHA512_DIGEST_LENGTH);
143
  }
144
  else if (!strcmp(algorithm, "sha2-512_224"))
145
  {
146
    CC_SHA512_CTX ctx;    /* SHA-512 context */
147
    unsigned char temp[CC_SHA512_DIGEST_LENGTH];
148
                                        /* SHA-512 hash */
149
150
   /*
151
    * SHA2-512 truncated to 224 bits (28 bytes)...
152
    */
153
154
    if (hashsize < CC_SHA224_DIGEST_LENGTH)
155
      goto too_small;
156
157
    CC_SHA512_Init(&ctx);
158
    CC_SHA512_Update(&ctx, data, (CC_LONG)datalen);
159
    CC_SHA512_Final(temp, &ctx);
160
161
    memcpy(hash, temp, CC_SHA224_DIGEST_LENGTH);
162
163
    return (CC_SHA224_DIGEST_LENGTH);
164
  }
165
  else if (!strcmp(algorithm, "sha2-512_256"))
166
  {
167
    CC_SHA512_CTX ctx;    /* SHA-512 context */
168
    unsigned char temp[CC_SHA512_DIGEST_LENGTH];
169
                                        /* SHA-512 hash */
170
171
   /*
172
    * SHA2-512 truncated to 256 bits (32 bytes)...
173
    */
174
175
    if (hashsize < CC_SHA256_DIGEST_LENGTH)
176
      goto too_small;
177
178
    CC_SHA512_Init(&ctx);
179
    CC_SHA512_Update(&ctx, data, (CC_LONG)datalen);
180
    CC_SHA512_Final(temp, &ctx);
181
182
    memcpy(hash, temp, CC_SHA256_DIGEST_LENGTH);
183
184
    return (CC_SHA256_DIGEST_LENGTH);
185
  }
186
187
#elif defined(HAVE_GNUTLS)
188
  gnutls_digest_algorithm_t alg = GNUTLS_DIG_UNKNOWN;
189
          /* Algorithm */
190
  unsigned char temp[64];   /* Temporary hash buffer */
191
  size_t  tempsize = 0;   /* Truncate to this size? */
192
193
194
#  ifdef HAVE_GNUTLS_FIPS140_SET_MODE
195
  unsigned oldmode = gnutls_fips140_mode_enabled();
196
197
  gnutls_fips140_set_mode(GNUTLS_FIPS140_LAX, GNUTLS_FIPS140_SET_MODE_THREAD);
198
#  endif /* HAVE_GNUTLS_FIPS140_SET_MODE */
199
200
  if (!strcmp(algorithm, "md5"))
201
    alg = GNUTLS_DIG_MD5;
202
  else if (!strcmp(algorithm, "sha"))
203
    alg = GNUTLS_DIG_SHA1;
204
  else if (!strcmp(algorithm, "sha2-224"))
205
    alg = GNUTLS_DIG_SHA224;
206
  else if (!strcmp(algorithm, "sha2-256"))
207
    alg = GNUTLS_DIG_SHA256;
208
  else if (!strcmp(algorithm, "sha2-384"))
209
    alg = GNUTLS_DIG_SHA384;
210
  else if (!strcmp(algorithm, "sha2-512"))
211
    alg = GNUTLS_DIG_SHA512;
212
  else if (!strcmp(algorithm, "sha2-512_224"))
213
  {
214
    alg      = GNUTLS_DIG_SHA512;
215
    tempsize = 28;
216
  }
217
  else if (!strcmp(algorithm, "sha2-512_256"))
218
  {
219
    alg      = GNUTLS_DIG_SHA512;
220
    tempsize = 32;
221
  }
222
223
  if (alg != GNUTLS_DIG_UNKNOWN)
224
  {
225
    if (tempsize > 0)
226
    {
227
     /*
228
      * Truncate result to tempsize bytes...
229
      */
230
231
      if (hashsize < tempsize)
232
        goto too_small;
233
234
      gnutls_hash_fast(alg, data, datalen, temp);
235
      memcpy(hash, temp, tempsize);
236
237
#  ifdef HAVE_GNUTLS_FIPS140_SET_MODE
238
      gnutls_fips140_set_mode(oldmode, GNUTLS_FIPS140_SET_MODE_THREAD);
239
#  endif /* HAVE_GNUTLS_FIPS140_SET_MODE */
240
241
      return ((ssize_t)tempsize);
242
    }
243
244
    if (hashsize < gnutls_hash_get_len(alg))
245
      goto too_small;
246
247
    gnutls_hash_fast(alg, data, datalen, hash);
248
249
#  ifdef HAVE_GNUTLS_FIPS140_SET_MODE
250
    gnutls_fips140_set_mode(oldmode, GNUTLS_FIPS140_SET_MODE_THREAD);
251
#  endif /* HAVE_GNUTLS_FIPS140_SET_MODE */
252
253
    return ((ssize_t)gnutls_hash_get_len(alg));
254
  }
255
256
#  ifdef HAVE_GNUTLS_FIPS140_SET_MODE
257
  gnutls_fips140_set_mode(oldmode, GNUTLS_FIPS140_SET_MODE_THREAD);
258
#  endif /* HAVE_GNUTLS_FIPS140_SET_MODE */
259
260
#else
261
 /*
262
  * No hash support beyond MD5 without CommonCrypto or GNU TLS...
263
  */
264
265
0
  if (!strcmp(algorithm, "md5"))
266
0
  {
267
0
    _cups_md5_state_t state;    /* MD5 state info */
268
269
0
    _cupsMD5Init(&state);
270
0
    _cupsMD5Append(&state, data, datalen);
271
0
    _cupsMD5Finish(&state, hash);
272
273
0
    return (16);
274
0
  }
275
0
  else if (hashsize < 64)
276
0
    goto too_small;
277
0
#endif /* __APPLE__ */
278
279
 /*
280
  * Unknown hash algorithm...
281
  */
282
283
0
  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown hash algorithm."), 1);
284
285
0
  return (-1);
286
287
 /*
288
  * We get here if the buffer is too small.
289
  */
290
291
0
  too_small:
292
293
#ifdef HAVE_GNUTLS_FIPS140_SET_MODE
294
  gnutls_fips140_set_mode(oldmode, GNUTLS_FIPS140_SET_MODE_THREAD);
295
#endif /* HAVE_GNUTLS_FIPS140_SET_MODE */
296
297
0
  _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Hash buffer too small."), 1);
298
0
  return (-1);
299
0
}
300
301
302
/*
303
 * 'cupsHashString()' - Format a hash value as a hexadecimal string.
304
 *
305
 * The passed buffer must be at least 2 * hashsize + 1 characters in length.
306
 *
307
 * @since CUPS 2.2.7@
308
 */
309
310
const char *        /* O - Formatted string */
311
cupsHashString(
312
    const unsigned char *hash,    /* I - Hash */
313
    size_t              hashsize, /* I - Size of hash */
314
    char                *buffer,  /* I - String buffer */
315
    size_t    bufsize)  /* I - Size of string buffer */
316
0
{
317
0
  char    *bufptr = buffer; /* Pointer into buffer */
318
0
  static const char *hex = "0123456789abcdef";
319
          /* Hex characters (lowercase!) */
320
321
322
 /*
323
  * Range check input...
324
  */
325
326
0
  if (!hash || hashsize < 1 || !buffer || bufsize < (2 * hashsize + 1))
327
0
  {
328
0
    if (buffer)
329
0
      *buffer = '\0';
330
0
    return (NULL);
331
0
  }
332
333
 /*
334
  * Loop until we've converted the whole hash...
335
  */
336
337
0
  while (hashsize > 0)
338
0
  {
339
0
    *bufptr++ = hex[*hash >> 4];
340
0
    *bufptr++ = hex[*hash & 15];
341
342
0
    hash ++;
343
0
    hashsize --;
344
0
  }
345
346
0
  *bufptr = '\0';
347
348
0
  return (buffer);
349
0
}