xref: /netbsd-src/external/bsd/ntp/dist/sntp/crypto.c (revision 2e2322c9c07009df921d11b1268f8506affbb8ba)
1 /*	$NetBSD: crypto.c,v 1.12 2016/11/22 03:09:31 christos Exp $	*/
2 
3 #include <config.h>
4 #include "crypto.h"
5 #include <ctype.h>
6 #include "isc/string.h"
7 #include "libssl_compat.h"
8 
9 struct key *key_ptr;
10 size_t key_cnt = 0;
11 
12 int
13 make_mac(
14 	const void *pkt_data,
15 	int pkt_size,
16 	int mac_size,
17 	const struct key *cmp_key,
18 	void * digest
19 	)
20 {
21 	u_int		len = mac_size;
22 	int		key_type;
23 	EVP_MD_CTX *	ctx;
24 
25 	if (cmp_key->key_len > 64)
26 		return 0;
27 	if (pkt_size % 4 != 0)
28 		return 0;
29 
30 	INIT_SSL();
31 	key_type = keytype_from_text(cmp_key->type, NULL);
32 
33 	ctx = EVP_MD_CTX_new();
34 	EVP_DigestInit(ctx, EVP_get_digestbynid(key_type));
35 	EVP_DigestUpdate(ctx, (const u_char *)cmp_key->key_seq, (u_int)cmp_key->key_len);
36 	EVP_DigestUpdate(ctx, pkt_data, (u_int)pkt_size);
37 	EVP_DigestFinal(ctx, digest, &len);
38 	EVP_MD_CTX_free(ctx);
39 
40 	return (int)len;
41 }
42 
43 
44 /* Generates a md5 digest of the key specified in keyid concatenated with the
45  * ntp packet (exluding the MAC) and compares this digest to the digest in
46  * the packet's MAC. If they're equal this function returns 1 (packet is
47  * authentic) or else 0 (not authentic).
48  */
49 int
50 auth_md5(
51 	const void *pkt_data,
52 	int pkt_size,
53 	int mac_size,
54 	const struct key *cmp_key
55 	)
56 {
57 	int  hash_len;
58 	int  authentic;
59 	char digest[20];
60 	const u_char *pkt_ptr;
61 	if (mac_size > (int)sizeof(digest))
62 		return 0;
63 	pkt_ptr = pkt_data;
64 	hash_len = make_mac(pkt_ptr, pkt_size, sizeof(digest), cmp_key,
65 			    digest);
66 	if (!hash_len) {
67 		authentic = FALSE;
68 	} else {
69 		/* isc_tsmemcmp will be better when its easy to link
70 		 * with.  sntp is a 1-shot program, so snooping for
71 		 * timing attacks is Harder.
72 		 */
73 		authentic = !memcmp(digest, (const char*)pkt_data + pkt_size + 4,
74 				    hash_len);
75 	}
76 	return authentic;
77 }
78 
79 static int
80 hex_val(
81 	unsigned char x
82 	)
83 {
84 	int val;
85 
86 	if ('0' <= x && x <= '9')
87 		val = x - '0';
88 	else if ('a' <= x && x <= 'f')
89 		val = x - 'a' + 0xa;
90 	else if ('A' <= x && x <= 'F')
91 		val = x - 'A' + 0xA;
92 	else
93 		val = -1;
94 
95 	return val;
96 }
97 
98 /* Load keys from the specified keyfile into the key structures.
99  * Returns -1 if the reading failed, otherwise it returns the
100  * number of keys it read
101  */
102 int
103 auth_init(
104 	const char *keyfile,
105 	struct key **keys
106 	)
107 {
108 	FILE *keyf = fopen(keyfile, "r");
109 	struct key *prev = NULL;
110 	int scan_cnt, line_cnt = 0;
111 	char kbuf[200];
112 	char keystring[129];
113 
114 	if (keyf == NULL) {
115 		if (debug)
116 			printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile);
117 		return -1;
118 	}
119 	if (feof(keyf)) {
120 		if (debug)
121 			printf("sntp auth_init: Key file %s is empty!\n", keyfile);
122 		fclose(keyf);
123 		return -1;
124 	}
125 	key_cnt = 0;
126 	while (!feof(keyf)) {
127 		char * octothorpe;
128 		struct key *act;
129 		int goodline = 0;
130 
131 		if (NULL == fgets(kbuf, sizeof(kbuf), keyf))
132 			continue;
133 
134 		kbuf[sizeof(kbuf) - 1] = '\0';
135 		octothorpe = strchr(kbuf, '#');
136 		if (octothorpe)
137 			*octothorpe = '\0';
138 		act = emalloc(sizeof(*act));
139 		scan_cnt = sscanf(kbuf, "%d %9s %128s", &act->key_id, act->type, keystring);
140 		if (scan_cnt == 3) {
141 			int len = strlen(keystring);
142 			if (len <= 20) {
143 				act->key_len = len;
144 				memcpy(act->key_seq, keystring, len + 1);
145 				goodline = 1;
146 			} else if ((len & 1) != 0) {
147 				goodline = 0; /* it's bad */
148 			} else {
149 				int j;
150 				goodline = 1;
151 				act->key_len = len >> 1;
152 				for (j = 0; j < len; j+=2) {
153 					int val;
154 					val = (hex_val(keystring[j]) << 4) |
155 					       hex_val(keystring[j+1]);
156 					if (val < 0) {
157 						goodline = 0; /* it's bad */
158 						break;
159 					}
160 					act->key_seq[j>>1] = (char)val;
161 				}
162 			}
163 		}
164 		if (goodline) {
165 			act->next = NULL;
166 			if (NULL == prev)
167 				*keys = act;
168 			else
169 				prev->next = act;
170 			prev = act;
171 			key_cnt++;
172 		} else {
173 			msyslog(LOG_DEBUG, "auth_init: scanf %d items, skipping line %d.",
174 				scan_cnt, line_cnt);
175 			free(act);
176 		}
177 		line_cnt++;
178 	}
179 	fclose(keyf);
180 
181 	key_ptr = *keys;
182 	return key_cnt;
183 }
184 
185 /* Looks for the key with keyid key_id and sets the d_key pointer to the
186  * address of the key. If no matching key is found the pointer is not touched.
187  */
188 void
189 get_key(
190 	int key_id,
191 	struct key **d_key
192 	)
193 {
194 	struct key *itr_key;
195 
196 	if (key_cnt == 0)
197 		return;
198 	for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) {
199 		if (itr_key->key_id == key_id) {
200 			*d_key = itr_key;
201 			break;
202 		}
203 	}
204 	return;
205 }
206