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