1 /*
2 * Hashing function for CUPS.
3 *
4 * Copyright 2015-2016 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 #endif /* __APPLE__ */
25
26
27 /*
28 * 'cupsHashData()' - Perform a hash function on the given data.
29 *
30 * The "algorithm" argument can be any of the registered, non-deprecated IPP
31 * hash algorithms for the "job-password-encryption" attribute, including
32 * "sha" for SHA-1, "sha-256" for SHA2-256, etc.
33 *
34 * The "hash" argument points to a buffer of "hashsize" bytes and should be at
35 * least 64 bytes in length for all of the supported algorithms.
36 *
37 * The returned hash is binary data.
38 *
39 * @since CUPS 2.2/macOS 10.12@
40 */
41
42 ssize_t /* O - Size of hash or -1 on error */
cupsHashData(const char * algorithm,const void * data,size_t datalen,unsigned char * hash,size_t hashsize)43 cupsHashData(const char *algorithm, /* I - Algorithm name */
44 const void *data, /* I - Data to hash */
45 size_t datalen, /* I - Length of data to hash */
46 unsigned char *hash, /* I - Hash buffer */
47 size_t hashsize) /* I - Size of hash buffer */
48 {
49 if (!algorithm || !data || datalen == 0 || !hash || hashsize == 0)
50 {
51 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Bad arguments to function"), 1);
52 return (-1);
53 }
54
55 #ifdef __APPLE__
56 if (!strcmp(algorithm, "sha"))
57 {
58 /*
59 * SHA-1...
60 */
61
62 CC_SHA1_CTX ctx; /* SHA-1 context */
63
64 if (hashsize < CC_SHA1_DIGEST_LENGTH)
65 goto too_small;
66
67 CC_SHA1_Init(&ctx);
68 CC_SHA1_Update(&ctx, data, (CC_LONG)datalen);
69 CC_SHA1_Final(hash, &ctx);
70
71 return (CC_SHA1_DIGEST_LENGTH);
72 }
73 else if (!strcmp(algorithm, "sha2-224"))
74 {
75 CC_SHA256_CTX ctx; /* SHA-224 context */
76
77 if (hashsize < CC_SHA224_DIGEST_LENGTH)
78 goto too_small;
79
80 CC_SHA224_Init(&ctx);
81 CC_SHA224_Update(&ctx, data, (CC_LONG)datalen);
82 CC_SHA224_Final(hash, &ctx);
83
84 return (CC_SHA224_DIGEST_LENGTH);
85 }
86 else if (!strcmp(algorithm, "sha2-256"))
87 {
88 CC_SHA256_CTX ctx; /* SHA-256 context */
89
90 if (hashsize < CC_SHA256_DIGEST_LENGTH)
91 goto too_small;
92
93 CC_SHA256_Init(&ctx);
94 CC_SHA256_Update(&ctx, data, (CC_LONG)datalen);
95 CC_SHA256_Final(hash, &ctx);
96
97 return (CC_SHA256_DIGEST_LENGTH);
98 }
99 else if (!strcmp(algorithm, "sha2-384"))
100 {
101 CC_SHA512_CTX ctx; /* SHA-384 context */
102
103 if (hashsize < CC_SHA384_DIGEST_LENGTH)
104 goto too_small;
105
106 CC_SHA384_Init(&ctx);
107 CC_SHA384_Update(&ctx, data, (CC_LONG)datalen);
108 CC_SHA384_Final(hash, &ctx);
109
110 return (CC_SHA384_DIGEST_LENGTH);
111 }
112 else if (!strcmp(algorithm, "sha2-512"))
113 {
114 CC_SHA512_CTX ctx; /* SHA-512 context */
115
116 if (hashsize < CC_SHA512_DIGEST_LENGTH)
117 goto too_small;
118
119 CC_SHA512_Init(&ctx);
120 CC_SHA512_Update(&ctx, data, (CC_LONG)datalen);
121 CC_SHA512_Final(hash, &ctx);
122
123 return (CC_SHA512_DIGEST_LENGTH);
124 }
125 else if (!strcmp(algorithm, "sha2-512_224"))
126 {
127 CC_SHA512_CTX ctx; /* SHA-512 context */
128 unsigned char temp[CC_SHA512_DIGEST_LENGTH];
129 /* SHA-512 hash */
130
131 /*
132 * SHA2-512 truncated to 224 bits (28 bytes)...
133 */
134
135 if (hashsize < CC_SHA224_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(temp, &ctx);
141
142 memcpy(hash, temp, CC_SHA224_DIGEST_LENGTH);
143
144 return (CC_SHA224_DIGEST_LENGTH);
145 }
146 else if (!strcmp(algorithm, "sha2-512_256"))
147 {
148 CC_SHA512_CTX ctx; /* SHA-512 context */
149 unsigned char temp[CC_SHA512_DIGEST_LENGTH];
150 /* SHA-512 hash */
151
152 /*
153 * SHA2-512 truncated to 256 bits (32 bytes)...
154 */
155
156 if (hashsize < CC_SHA256_DIGEST_LENGTH)
157 goto too_small;
158
159 CC_SHA512_Init(&ctx);
160 CC_SHA512_Update(&ctx, data, (CC_LONG)datalen);
161 CC_SHA512_Final(temp, &ctx);
162
163 memcpy(hash, temp, CC_SHA256_DIGEST_LENGTH);
164
165 return (CC_SHA256_DIGEST_LENGTH);
166 }
167
168 #elif defined(HAVE_GNUTLS)
169 gnutls_digest_algorithm_t alg = GNUTLS_DIG_UNKNOWN;
170 /* Algorithm */
171 unsigned char temp[64]; /* Temporary hash buffer */
172 size_t tempsize = 0; /* Truncate to this size? */
173
174 if (!strcmp(algorithm, "sha"))
175 alg = GNUTLS_DIG_SHA1;
176 else if (!strcmp(algorithm, "sha2-224"))
177 alg = GNUTLS_DIG_SHA224;
178 else if (!strcmp(algorithm, "sha2-256"))
179 alg = GNUTLS_DIG_SHA256;
180 else if (!strcmp(algorithm, "sha2-384"))
181 alg = GNUTLS_DIG_SHA384;
182 else if (!strcmp(algorithm, "sha2-512"))
183 alg = GNUTLS_DIG_SHA512;
184 else if (!strcmp(algorithm, "sha2-512_224"))
185 {
186 alg = GNUTLS_DIG_SHA512;
187 tempsize = 28;
188 }
189 else if (!strcmp(algorithm, "sha2-512_256"))
190 {
191 alg = GNUTLS_DIG_SHA512;
192 tempsize = 32;
193 }
194
195 if (alg != GNUTLS_DIG_UNKNOWN)
196 {
197 if (tempsize > 0)
198 {
199 /*
200 * Truncate result to tempsize bytes...
201 */
202
203 if (hashsize < tempsize)
204 goto too_small;
205
206 gnutls_hash_fast(alg, data, datalen, temp);
207 memcpy(hash, temp, tempsize);
208
209 return ((ssize_t)tempsize);
210 }
211
212 if (hashsize < gnutls_hash_get_len(alg))
213 goto too_small;
214
215 gnutls_hash_fast(alg, data, datalen, hash);
216
217 return (gnutls_hash_get_len(alg));
218 }
219
220 #else
221 /*
222 * No hash support without CommonCrypto or GNU TLS...
223 */
224
225 if (hashsize < 64)
226 goto too_small;
227 #endif /* __APPLE__ */
228
229 /*
230 * Unknown hash algorithm...
231 */
232
233 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unknown hash algorithm."), 1);
234
235 return (-1);
236
237 /*
238 * We get here if the buffer is too small.
239 */
240
241 too_small:
242
243 _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Hash buffer too small."), 1);
244 return (-1);
245 }
246