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