1 /*
2   chronyd/chronyc - Programs for keeping computer clocks accurate.
3 
4  **********************************************************************
5  * Copyright (C) Miroslav Lichvar  2021
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of version 2 of the GNU General Public License as
9  * published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  *
20  **********************************************************************
21 
22   =======================================================================
23 
24   Crypto hashing using the GnuTLS library
25   */
26 
27 #include "config.h"
28 
29 #include "sysincl.h"
30 
31 #include <gnutls/crypto.h>
32 
33 #include "hash.h"
34 #include "logging.h"
35 
36 struct hash {
37   const HSH_Algorithm algorithm;
38   const gnutls_digest_algorithm_t type;
39   gnutls_hash_hd_t handle;
40 };
41 
42 static struct hash hashes[] = {
43   { HSH_MD5_NONCRYPTO, GNUTLS_DIG_MD5, NULL },
44   { HSH_MD5, GNUTLS_DIG_MD5, NULL },
45   { HSH_SHA1, GNUTLS_DIG_SHA1, NULL },
46   { HSH_SHA256, GNUTLS_DIG_SHA256, NULL },
47   { HSH_SHA384, GNUTLS_DIG_SHA384, NULL },
48   { HSH_SHA512, GNUTLS_DIG_SHA512, NULL },
49   { HSH_SHA3_224, GNUTLS_DIG_SHA3_224, NULL },
50   { HSH_SHA3_256, GNUTLS_DIG_SHA3_256, NULL },
51   { HSH_SHA3_384, GNUTLS_DIG_SHA3_384, NULL },
52   { HSH_SHA3_512, GNUTLS_DIG_SHA3_512, NULL },
53   { 0, 0, NULL }
54 };
55 
56 static int gnutls_initialised = 0;
57 
58 int
HSH_GetHashId(HSH_Algorithm algorithm)59 HSH_GetHashId(HSH_Algorithm algorithm)
60 {
61   int id, r;
62 
63   if (!gnutls_initialised) {
64     r = gnutls_global_init();
65     if (r < 0)
66       LOG_FATAL("Could not initialise %s : %s", "gnutls", gnutls_strerror(r));
67     gnutls_initialised = 1;
68   }
69 
70   for (id = 0; hashes[id].algorithm != 0; id++) {
71     if (hashes[id].algorithm == algorithm)
72       break;
73   }
74 
75   if (hashes[id].algorithm == 0)
76     return -1;
77 
78   if (hashes[id].handle)
79     return id;
80 
81   if (algorithm == HSH_MD5_NONCRYPTO)
82     GNUTLS_FIPS140_SET_LAX_MODE();
83 
84   r = gnutls_hash_init(&hashes[id].handle, hashes[id].type);
85 
86   if (algorithm == HSH_MD5_NONCRYPTO)
87     GNUTLS_FIPS140_SET_STRICT_MODE();
88 
89   if (r < 0) {
90     DEBUG_LOG("Could not initialise %s : %s", "hash", gnutls_strerror(r));
91     hashes[id].handle = NULL;
92     return -1;
93   }
94 
95   return id;
96 }
97 
98 int
HSH_Hash(int id,const void * in1,int in1_len,const void * in2,int in2_len,unsigned char * out,int out_len)99 HSH_Hash(int id, const void *in1, int in1_len, const void *in2, int in2_len,
100          unsigned char *out, int out_len)
101 {
102   unsigned char buf[MAX_HASH_LENGTH];
103   gnutls_hash_hd_t handle;
104   int hash_len;
105 
106   if (in1_len < 0 || in2_len < 0 || out_len < 0)
107     return 0;
108 
109   handle = hashes[id].handle;
110   hash_len = gnutls_hash_get_len(hashes[id].type);
111 
112   if (out_len > hash_len)
113     out_len = hash_len;
114 
115   if (hash_len > sizeof (buf))
116     return 0;
117 
118   if (gnutls_hash(handle, in1, in1_len) < 0 ||
119       (in2 && gnutls_hash(handle, in2, in2_len) < 0)) {
120     /* Reset the state */
121     gnutls_hash_output(handle, buf);
122     return 0;
123   }
124 
125   gnutls_hash_output(handle, buf);
126   memcpy(out, buf, out_len);
127 
128   return out_len;
129 }
130 
131 void
HSH_Finalise(void)132 HSH_Finalise(void)
133 {
134   int i;
135 
136   if (!gnutls_initialised)
137     return;
138 
139   for (i = 0; hashes[i].algorithm != 0; i++) {
140     if (hashes[i].handle)
141       gnutls_hash_deinit(hashes[i].handle, NULL);
142   }
143 
144   gnutls_global_deinit();
145 }
146