Home | History | Annotate | Download | only in cups
      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