crypto.c revision 1.19.4.1 1 /* $NetBSD: crypto.c,v 1.19.4.1 2025/08/02 05:22:48 perseant Exp $ */
2
3 /*
4 * HMS: we need to test:
5 * - OpenSSL versions, if we are building with them
6 * - our versions
7 *
8 * We may need to test with(out) OPENSSL separately.
9 */
10
11 #include <config.h>
12 #include "crypto.h"
13 #include <ctype.h>
14 #include "isc/string.h"
15
16 struct key *key_ptr;
17 size_t key_cnt = 0;
18
19 typedef struct key Key_T;
20
21 static size_t
22 compute_mac(
23 u_char * digest,
24 size_t dig_sz,
25 char const * macname,
26 void const * pkt_data,
27 size_t pkt_len,
28 void const * key_data,
29 size_t key_size
30 )
31 {
32 u_int len = 0;
33 #if defined(OPENSSL) && defined(ENABLE_CMAC)
34 size_t slen = 0;
35 #endif
36 int key_type;
37
38 INIT_SSL();
39 key_type = keytype_from_text(macname, NULL);
40
41 #if defined(OPENSSL) && defined(ENABLE_CMAC)
42 /* Check if CMAC key type specific code required */
43 if (key_type == NID_cmac) {
44 CMAC_CTX * ctx = NULL;
45 u_char keybuf[AES_128_KEY_SIZE];
46
47 /* adjust key size (zero padded buffer) if necessary */
48 if (AES_128_KEY_SIZE > key_size) {
49 memcpy(keybuf, key_data, key_size);
50 memset((keybuf + key_size), 0,
51 (AES_128_KEY_SIZE - key_size));
52 key_data = keybuf;
53 }
54
55 if (!(ctx = CMAC_CTX_new())) {
56 msyslog(LOG_ERR, "make_mac: CMAC %s CTX new failed.", CMAC);
57 }
58 else if (!CMAC_Init(ctx, key_data, AES_128_KEY_SIZE,
59 EVP_aes_128_cbc(), NULL)) {
60 msyslog(LOG_ERR, "make_mac: CMAC %s Init failed.", CMAC);
61 }
62 else if (!CMAC_Update(ctx, pkt_data, pkt_len)) {
63 msyslog(LOG_ERR, "make_mac: CMAC %s Update failed.", CMAC);
64 }
65 else if (!CMAC_Final(ctx, digest, &slen)) {
66 msyslog(LOG_ERR, "make_mac: CMAC %s Final failed.", CMAC);
67 slen = 0;
68 }
69 len = (u_int)slen;
70
71 if (ctx)
72 CMAC_CTX_free(ctx);
73 /* Test our AES-128-CMAC implementation */
74
75 } else /* MD5 MAC handling */
76 #endif
77 {
78 EVP_MD_CTX * ctx;
79
80 if (!(ctx = EVP_MD_CTX_new())) {
81 msyslog(LOG_ERR, "make_mac: MAC %s Digest CTX new failed.",
82 macname);
83 goto mac_fail;
84 }
85 #ifdef OPENSSL /* OpenSSL 1 supports return codes 0 fail, 1 okay */
86 # ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
87 EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
88 # endif
89 /* [Bug 3457] DON'T use plain EVP_DigestInit! It would
90 * kill the flags! */
91 if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(key_type), NULL)) {
92 msyslog(LOG_ERR, "make_mac: MAC %s Digest Init failed.",
93 macname);
94 goto mac_fail;
95 }
96 if (!EVP_DigestUpdate(ctx, key_data, key_size)) {
97 msyslog(LOG_ERR, "make_mac: MAC %s Digest Update key failed.",
98 macname);
99 goto mac_fail;
100 }
101 if (!EVP_DigestUpdate(ctx, pkt_data, pkt_len)) {
102 msyslog(LOG_ERR, "make_mac: MAC %s Digest Update data failed.",
103 macname);
104 goto mac_fail;
105 }
106 if (!EVP_DigestFinal(ctx, digest, &len)) {
107 msyslog(LOG_ERR, "make_mac: MAC %s Digest Final failed.",
108 macname);
109 len = 0;
110 }
111 #else /* !OPENSSL */
112 (void)key_type; /* unused, so try to prevent compiler from croaks */
113 if (!EVP_DigestInit(ctx, EVP_get_digestbynid(key_type))) {
114 msyslog(LOG_ERR, "make_mac: MAC MD5 Digest Init failed.");
115 goto mac_fail;
116 }
117 EVP_DigestUpdate(ctx, key_data, key_size);
118 EVP_DigestUpdate(ctx, pkt_data, pkt_len);
119 EVP_DigestFinal(ctx, digest, &len);
120 #endif
121 mac_fail:
122 EVP_MD_CTX_free(ctx);
123 }
124
125 return len;
126 }
127
128
129 size_t
130 make_mac(
131 const void * pkt_data,
132 size_t pkt_len,
133 Key_T const * cmp_key,
134 void * digest,
135 size_t dig_sz
136 )
137 {
138 u_int len;
139 u_char dbuf[EVP_MAX_MD_SIZE];
140
141 if (cmp_key->key_len > 64 || pkt_len % 4 != 0) {
142 return 0;
143 }
144 len = compute_mac(dbuf, sizeof(dbuf), cmp_key->typen, pkt_data,
145 pkt_len, cmp_key->key_seq, cmp_key->key_len);
146 INSIST(len <= dig_sz);
147 memcpy(digest, dbuf, len);
148
149 return len;
150 }
151
152
153 /* Generates a md5 digest of the key specified in keyid concatenated with the
154 * ntp packet (exluding the MAC) and compares this digest to the digest in
155 * the packet's MAC. If they're equal this function returns 1 (packet is
156 * authentic) or else 0 (not authentic).
157 */
158 int
159 auth_md5(
160 void const * pkt_data,
161 size_t pkt_len,
162 size_t mac_len,
163 Key_T const * cmp_key
164 )
165 {
166 u_int len = 0;
167 u_char const * pkt_ptr = pkt_data;
168 u_char dbuf[EVP_MAX_MD_SIZE];
169
170 if (0 == mac_len || mac_len > sizeof(dbuf)) {
171 return FALSE;
172 }
173 len = compute_mac(dbuf, sizeof(dbuf), cmp_key->typen,
174 pkt_ptr, pkt_len, cmp_key->key_seq,
175 cmp_key->key_len);
176
177 pkt_ptr += pkt_len + sizeof(keyid_t);
178
179 /* isc_tsmemcmp will be better when its easy to link with. sntp
180 * is a 1-shot program, so snooping for timing attacks is
181 * Harder.
182 */
183 return mac_len == len && !memcmp(dbuf, pkt_ptr, mac_len);
184 }
185
186 static int
187 hex_val(
188 unsigned char x
189 )
190 {
191 int val;
192
193 if ('0' <= x && x <= '9')
194 val = x - '0';
195 else if ('a' <= x && x <= 'f')
196 val = x - 'a' + 0xa;
197 else if ('A' <= x && x <= 'F')
198 val = x - 'A' + 0xA;
199 else
200 val = -1;
201
202 return val;
203 }
204
205 /* Load keys from the specified keyfile into the key structures.
206 * Returns -1 if the reading failed, otherwise it returns the
207 * number of keys it read
208 */
209 int
210 auth_init(
211 const char *keyfile,
212 struct key **keys
213 )
214 {
215 FILE *keyf = fopen(keyfile, "r");
216 struct key *prev = NULL;
217 int scan_cnt, line_cnt = 1;
218 char kbuf[200];
219 char keystring[129];
220
221 /* HMS: Is it OK to do this later, after we know we have a key file? */
222 INIT_SSL();
223
224 if (keyf == NULL) {
225 if (debug)
226 printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile);
227 return -1;
228 }
229 if (feof(keyf)) {
230 if (debug)
231 printf("sntp auth_init: Key file %s is empty!\n", keyfile);
232 fclose(keyf);
233 return -1;
234 }
235 key_cnt = 0;
236 while (!feof(keyf)) {
237 char * octothorpe;
238 struct key *act;
239 int goodline = 0;
240
241 if (NULL == fgets(kbuf, sizeof(kbuf), keyf))
242 continue;
243
244 kbuf[sizeof(kbuf) - 1] = '\0';
245 octothorpe = strchr(kbuf, '#');
246 if (octothorpe)
247 *octothorpe = '\0';
248 act = emalloc(sizeof(*act));
249 /* keep width 15 = sizeof struct key.typen - 1 synced */
250 scan_cnt = sscanf(kbuf, "%d %15s %128s",
251 &act->key_id, act->typen, keystring);
252 if (scan_cnt == 3) {
253 int len = strlen(keystring);
254 goodline = 1; /* assume best for now */
255 if (len <= 20) {
256 act->key_len = len;
257 memcpy(act->key_seq, keystring, len + 1);
258 } else if ((len & 1) != 0) {
259 goodline = 0; /* it's bad */
260 } else {
261 int j;
262 act->key_len = len >> 1;
263 for (j = 0; j < len; j+=2) {
264 int val;
265 val = (hex_val(keystring[j]) << 4) |
266 hex_val(keystring[j+1]);
267 if (val < 0) {
268 goodline = 0; /* it's bad */
269 break;
270 }
271 act->key_seq[j>>1] = (char)val;
272 }
273 }
274 act->typei = keytype_from_text(act->typen, NULL);
275 if (0 == act->typei) {
276 printf("%s: line %d: key %d, %s not supported - ignoring\n",
277 keyfile, line_cnt,
278 act->key_id, act->typen);
279 goodline = 0; /* it's bad */
280 }
281 }
282 if (goodline) {
283 act->next = NULL;
284 if (NULL == prev)
285 *keys = act;
286 else
287 prev->next = act;
288 prev = act;
289 key_cnt++;
290 } else {
291 if (debug) {
292 printf("auth_init: scanf %d items, skipping line %d.",
293 scan_cnt, line_cnt);
294 }
295 free(act);
296 }
297 line_cnt++;
298 }
299 fclose(keyf);
300
301 key_ptr = *keys;
302 return key_cnt;
303 }
304
305 /* Looks for the key with keyid key_id and sets the d_key pointer to the
306 * address of the key. If no matching key is found the pointer is not touched.
307 */
308 void
309 get_key(
310 keyid_t key_id,
311 struct key ** d_key
312 )
313 {
314 struct key *itr_key;
315
316 if (key_cnt == 0) {
317 return;
318 }
319 for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) {
320 if (itr_key->key_id == key_id) {
321 *d_key = itr_key;
322 break;
323 }
324 }
325 return;
326 }
327