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 */ 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