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