1 /*
2   Copyright 2021 Northern.tech AS
3 
4   This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5 
6   This program is free software; you can redistribute it and/or modify it
7   under the terms of the GNU General Public License as published by the
8   Free Software Foundation; version 3.
9 
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14 
15   You should have received a copy of the GNU General Public License
16   along with this program; if not, write to the Free Software
17   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
18 
19   To the extent this program is licensed as part of the Enterprise
20   versions of CFEngine, the applicable Commercial Open Source License
21   (COSL) may apply to this file if you as a licensee so wish it. See
22   included file COSL.txt.
23 */
24 
25 #ifndef CFENGINE_HASH_H
26 #define CFENGINE_HASH_H
27 
28 /**
29   @brief Hash implementations
30   */
31 
32 #include <openssl/rsa.h>
33 #include <openssl/evp.h>
34 
35 #include <stdbool.h>
36 #include <hash_method.h>                            /* HashMethod, HashSize */
37 
38 
39 typedef struct Hash Hash;
40 
41 /**
42   @brief Creates a new structure of type Hash.
43   @param data String to hash.
44   @param length Length of the string to hash.
45   @param method Hash method.
46   @return A structure of type Hash or NULL in case of error.
47   */
48 Hash *HashNew(const char *data, const unsigned int length, HashMethod method);
49 
50 /**
51   @brief Creates a new structure of type Hash.
52   @param descriptor Either file descriptor or socket descriptor.
53   @param method Hash method.
54   @return A structure of type Hash or NULL in case of error.
55   */
56 Hash *HashNewFromDescriptor(const int descriptor, HashMethod method);
57 
58 /**
59   @brief Creates a new structure of type Hash.
60   @param rsa RSA key to be hashed.
61   @param method Hash method.
62   @return A structure of type Hash or NULL in case of error.
63   */
64 Hash *HashNewFromKey(const RSA *rsa, HashMethod method);
65 
66 /**
67   @brief Destroys a structure of type Hash.
68   @param hash The structure to be destroyed.
69   */
70 void HashDestroy(Hash **hash);
71 
72 /**
73   @brief Copy a hash
74   @param origin Hash to be copied.
75   @param destination Hash to be copied to.
76   @return 0 if successful, -1 in any other case.
77   */
78 int HashCopy(Hash *origin, Hash **destination);
79 
80 /**
81   @brief Checks if two hashes are equal.
82   @param a 1st hash to be compared.
83   @param b 2nd hash to be compared.
84   @return True if both hashes are equal and false in any other case.
85   */
86 bool HashEqual(const Hash *a, const Hash *b);
87 
88 /**
89   @brief Pointer to the raw digest data.
90   @note Notice that this is a binary representation and not '\0' terminated.
91   @param hash Hash structure.
92   @param length Pointer to an unsigned int to hold the length of the data.
93   @return A pointer to the raw digest data.
94   */
95 const unsigned  char *HashData(const Hash *hash, unsigned int *length);
96 
97 /**
98   @brief Printable hash representation.
99   @param hash Hash structure.
100   @return A pointer to the printable digest representation.
101   */
102 const char *HashPrintable(const Hash *hash);
103 
104 /**
105   @brief Hash type.
106   @param hash Hash structure
107   @return The hash method used by this hash structure.
108   */
109 HashMethod HashType(const Hash *hash);
110 
111 /**
112   @brief Hash length in bytes.
113   @param hash Hash structure
114   @return The hash length in bytes.
115   */
116 HashSize HashLength(const Hash *hash);
117 
118 /**
119   @brief Returns the ID of the hash based on the name
120   @param hash_name Name of the hash.
121   @return Returns the ID of the hash from the name.
122   */
123 HashMethod HashIdFromName(const char *hash_name);
124 
125 /**
126   @brief Returns the name of the hash based on the ID.
127   @param hash_id Id of the hash.
128   @return Returns the name of the hash.
129   */
130 const char *HashNameFromId(HashMethod hash_id);
131 
132 
133 /**
134   @brief Returns pointer to an openssl digest struct
135 
136   Equivalent to EVP_get_digestbyname(HashNameFromId(type)),
137   but with added error checking.
138 
139   Returns NULL in case of error.
140   */
141 const EVP_MD *HashDigestFromId(HashMethod type);
142 
143 /**
144   @brief Size of the hash
145   @param method Hash method
146   @return Returns the size of the hash or 0 in case of error.
147   */
148 HashSize HashSizeFromId(HashMethod hash_id);
149 
150 /* Enough room for "SHA=asdfasdfasdf". */
151 #define CF_HOSTKEY_STRING_SIZE (4 + 2 * EVP_MAX_MD_SIZE + 1)
152 
153 
154 void HashFile(const char *filename, unsigned char digest[EVP_MAX_MD_SIZE + 1], HashMethod type, bool text_mode);
155 void HashString(const char *buffer, int len, unsigned char digest[EVP_MAX_MD_SIZE + 1], HashMethod type);
156 bool HashesMatch(
157     const unsigned char digest1[EVP_MAX_MD_SIZE + 1],
158     const unsigned char digest2[EVP_MAX_MD_SIZE + 1],
159     HashMethod type);
160 char *HashPrintSafe(char *dst, size_t dst_size, const unsigned char *digest,
161                     HashMethod type, bool use_prefix);
162 char *SkipHashType(char *hash);
163 void HashPubKey(const RSA *key, unsigned char digest[EVP_MAX_MD_SIZE + 1], HashMethod type);
164 
165 /**
166  * @brief Copy a string from src to dst, if src is too big, truncate and hash.
167  *
168  * If the src string (including NUL terminator) does not fit in dst
169  * (according to dst_size), the last part of dst is a hash of the full src
170  * string, before truncation.
171  *
172  * This function is primarily intended to limit the length of keys in a
173  * key-value store, like LMDB, while still keeping the strings readable AND
174  * unique.
175  *
176  * Examples:
177  * "short_string" -> "short_string"
178  * "string_which_is_too_long_for_size" -> "string_which_is#MD5="
179  *
180  * If this function returns dst_size, the string was truncated and hashed,
181  * the destination string is exactly dst_size - 1 bytes long in this case.
182  *
183  * @param src[in] String to copy from, must be '\0'-terminated
184  * @param dst[out] Destination to copy to, will always be '\0'-terminated
185  * @param dst_size[in] Size of destination buffer (including '\0'-terminator)
186  * @return dst_size if string was truncated, string length (src/dst) otherwise
187  * @note dst must always be of size dst_size or bigger, regardless of src
188  * @see StringCopy()
189  */
190 size_t StringCopyTruncateAndHashIfNecessary(
191     const char *src, char *dst, size_t dst_size);
192 
193 #endif // CFENGINE_HASH_H
194