Imported Upstream version 2.2.1
[platform/upstream/cups.git] / cups / hash.c
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  * file is 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 */
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 }