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