crypto.c revision 338531
1139969Simp/*
21556Srgrimes * HMS: we need to test:
31556Srgrimes * - OpenSSL versions, if we are building with them
41556Srgrimes * - our versions
51556Srgrimes *
61556Srgrimes * We may need to test with(out) OPENSSL separately.
71556Srgrimes */
81556Srgrimes
91556Srgrimes#include <config.h>
101556Srgrimes#include "crypto.h"
111556Srgrimes#include <ctype.h>
121556Srgrimes#include "isc/string.h"
131556Srgrimes#include "ntp_md5.h"
141556Srgrimes
151556Srgrimes#ifndef EVP_MAX_MD_SIZE
161556Srgrimes# define EVP_MAX_MD_SIZE 32
171556Srgrimes#endif
181556Srgrimes
191556Srgrimesstruct key *key_ptr;
201556Srgrimessize_t key_cnt = 0;
211556Srgrimes
221556Srgrimestypedef struct key Key_T;
231556Srgrimes
241556Srgrimesstatic u_int
251556Srgrimescompute_mac(
261556Srgrimes	u_char		digest[EVP_MAX_MD_SIZE],
271556Srgrimes	char const *	macname,
281556Srgrimes	void const *	pkt_data,
291556Srgrimes	u_int		pkt_size,
301556Srgrimes	void const *	key_data,
311556Srgrimes	u_int		key_size
321556Srgrimes	)
331556Srgrimes{
3450471Speter	u_int		len  = 0;
351556Srgrimes	size_t		slen = 0;
36211965Sbrian	int		key_type;
371556Srgrimes
3879526Sru	INIT_SSL();
391556Srgrimes	key_type = keytype_from_text(macname, NULL);
401556Srgrimes
411556Srgrimes#if defined(OPENSSL) && defined(ENABLE_CMAC)
421556Srgrimes	/* Check if CMAC key type specific code required */
4368935Sru	if (key_type == NID_cmac) {
4476286Skris		CMAC_CTX *	ctx    = NULL;
451556Srgrimes		u_char		keybuf[AES_128_KEY_SIZE];
461556Srgrimes
471556Srgrimes		/* adjust key size (zero padded buffer) if necessary */
481556Srgrimes		if (AES_128_KEY_SIZE > key_size) {
491556Srgrimes			memcpy(keybuf, key_data, key_size);
5070150Sru			memset((keybuf + key_size), 0,
511556Srgrimes			       (AES_128_KEY_SIZE - key_size));
521556Srgrimes			key_data = keybuf;
531556Srgrimes		}
5470150Sru
551556Srgrimes		if (!(ctx = CMAC_CTX_new())) {
561556Srgrimes			msyslog(LOG_ERR, "make_mac: CMAC %s CTX new failed.",   CMAC);
571556Srgrimes		}
5870150Sru		else if (!CMAC_Init(ctx, key_data, AES_128_KEY_SIZE,
591556Srgrimes				    EVP_aes_128_cbc(), NULL)) {
601556Srgrimes			msyslog(LOG_ERR, "make_mac: CMAC %s Init failed.",      CMAC);
611556Srgrimes		}
621556Srgrimes		else if (!CMAC_Update(ctx, pkt_data, (size_t)pkt_size)) {
631556Srgrimes			msyslog(LOG_ERR, "make_mac: CMAC %s Update failed.",    CMAC);
641556Srgrimes		}
651556Srgrimes		else if (!CMAC_Final(ctx, digest, &slen)) {
6670150Sru			msyslog(LOG_ERR, "make_mac: CMAC %s Final failed.",     CMAC);
671556Srgrimes			slen = 0;
6870150Sru		}
6968935Sru		len = (u_int)slen;
701556Srgrimes
7176286Skris		CMAC_CTX_cleanup(ctx);
721556Srgrimes		/* Test our AES-128-CMAC implementation */
731556Srgrimes
741556Srgrimes	} else	/* MD5 MAC handling */
751556Srgrimes#endif
761556Srgrimes	{
7770150Sru		EVP_MD_CTX *	ctx;
781556Srgrimes
791556Srgrimes		if (!(ctx = EVP_MD_CTX_new())) {
801556Srgrimes			msyslog(LOG_ERR, "make_mac: MAC %s Digest CTX new failed.",
8170150Sru				macname);
821556Srgrimes			goto mac_fail;
831556Srgrimes		}
841556Srgrimes#ifdef OPENSSL	/* OpenSSL 1 supports return codes 0 fail, 1 okay */
8570150Sru#	    ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
861556Srgrimes		EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
871556Srgrimes#	    endif
881556Srgrimes		/* [Bug 3457] DON'T use plain EVP_DigestInit! It would
891556Srgrimes		 *  kill the flags! */
9070150Sru		if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(key_type), NULL)) {
911556Srgrimes			msyslog(LOG_ERR, "make_mac: MAC %s Digest Init failed.",
921556Srgrimes				macname);
931556Srgrimes			goto mac_fail;
9470150Sru		}
951556Srgrimes		if (!EVP_DigestUpdate(ctx, key_data, key_size)) {
961556Srgrimes			msyslog(LOG_ERR, "make_mac: MAC %s Digest Update key failed.",
971556Srgrimes				macname);
981556Srgrimes			goto mac_fail;
991556Srgrimes		}
1001556Srgrimes		if (!EVP_DigestUpdate(ctx, pkt_data, pkt_size)) {
1011556Srgrimes			msyslog(LOG_ERR, "make_mac: MAC %s Digest Update data failed.",
10270150Sru				macname);
1031556Srgrimes			goto mac_fail;
10470150Sru		}
10568935Sru		if (!EVP_DigestFinal(ctx, digest, &len)) {
1061556Srgrimes			msyslog(LOG_ERR, "make_mac: MAC %s Digest Final failed.",
10776286Skris				macname);
1081556Srgrimes			len = 0;
1091556Srgrimes		}
1101556Srgrimes#else /* !OPENSSL */
1111556Srgrimes		EVP_DigestInit(ctx, EVP_get_digestbynid(key_type));
1121556Srgrimes		EVP_DigestUpdate(ctx, key_data, key_size);
1131556Srgrimes		EVP_DigestUpdate(ctx, pkt_data, pkt_size);
1141556Srgrimes		EVP_DigestFinal(ctx, digest, &len);
1151556Srgrimes#endif
1161556Srgrimes	  mac_fail:
1171556Srgrimes		EVP_MD_CTX_free(ctx);
1181556Srgrimes	}
1191556Srgrimes
12070150Sru	return len;
1211556Srgrimes}
1221556Srgrimes
1231556Srgrimesint
12470150Srumake_mac(
1251556Srgrimes	const void *	pkt_data,
1261556Srgrimes	int		pkt_size,
1271556Srgrimes	int		mac_size,
12870150Sru	Key_T const *	cmp_key,
1291556Srgrimes	void * 		digest
1301556Srgrimes	)
1311556Srgrimes{
13270150Sru	u_int		len;
1331556Srgrimes	u_char		dbuf[EVP_MAX_MD_SIZE];
1341556Srgrimes
1351556Srgrimes	if (cmp_key->key_len > 64 || mac_size <= 0)
1361556Srgrimes		return 0;
1371556Srgrimes	if (pkt_size % 4 != 0)
1381556Srgrimes		return 0;
1391556Srgrimes
1401556Srgrimes	len = compute_mac(dbuf, cmp_key->typen,
1411556Srgrimes			  pkt_data, (u_int)pkt_size,
1421556Srgrimes			  cmp_key->key_seq, (u_int)cmp_key->key_len);
1431556Srgrimes
14470150Sru
1451556Srgrimes	if (len) {
14672432Sru		if (len > (u_int)mac_size)
14768935Sru			len = (u_int)mac_size;
1481556Srgrimes		memcpy(digest, dbuf, len);
1491556Srgrimes	}
1501556Srgrimes	return (int)len;
1511556Srgrimes}
1521556Srgrimes
15370150Sru
1541556Srgrimes/* Generates a md5 digest of the key specified in keyid concatenated with the
1551556Srgrimes * ntp packet (exluding the MAC) and compares this digest to the digest in
1561556Srgrimes * the packet's MAC. If they're equal this function returns 1 (packet is
15770150Sru * authentic) or else 0 (not authentic).
1581556Srgrimes */
1591556Srgrimesint
1601556Srgrimesauth_md5(
16170150Sru	void const *	pkt_data,
1621556Srgrimes	int 		pkt_size,
1631556Srgrimes	int		mac_size,
1641556Srgrimes	Key_T const *	cmp_key
16570150Sru	)
1661556Srgrimes{
1671556Srgrimes	u_int		len       = 0;
1681556Srgrimes	u_char const *	pkt_ptr   = pkt_data;
1691556Srgrimes	u_char		dbuf[EVP_MAX_MD_SIZE];
1701556Srgrimes
1711556Srgrimes	if (mac_size <= 0 || (size_t)mac_size > sizeof(dbuf))
1721556Srgrimes		return FALSE;
1731556Srgrimes
17470150Sru	len = compute_mac(dbuf, cmp_key->typen,
1751556Srgrimes			  pkt_ptr, (u_int)pkt_size,
17672432Sru			  cmp_key->key_seq, (u_int)cmp_key->key_len);
1771556Srgrimes
1781556Srgrimes	pkt_ptr += pkt_size + 4;
17995204Scharnier	if (len > (u_int)mac_size)
18095204Scharnier		len = (u_int)mac_size;
18195204Scharnier
1821556Srgrimes	/* isc_tsmemcmp will be better when its easy to link with.  sntp
18395204Scharnier	 * is a 1-shot program, so snooping for timing attacks is
18495204Scharnier	 * Harder.
1851556Srgrimes	 */
1861556Srgrimes	return ((u_int)mac_size == len) && !memcmp(dbuf, pkt_ptr, len);
1871556Srgrimes}
1881556Srgrimes
1891556Srgrimesstatic int
1901556Srgrimeshex_val(
1911556Srgrimes	unsigned char x
1921556Srgrimes	)
1931556Srgrimes{
19436049Scharnier	int val;
1951556Srgrimes
1961556Srgrimes	if ('0' <= x && x <= '9')
1971556Srgrimes		val = x - '0';
19871895Sru	else if ('a' <= x && x <= 'f')
1991556Srgrimes		val = x - 'a' + 0xa;
2001556Srgrimes	else if ('A' <= x && x <= 'F')
2011556Srgrimes		val = x - 'A' + 0xA;
20295204Scharnier	else
2031556Srgrimes		val = -1;
2041556Srgrimes
2051556Srgrimes	return val;
2061556Srgrimes}
20771895Sru
2081556Srgrimes/* Load keys from the specified keyfile into the key structures.
2091556Srgrimes * Returns -1 if the reading failed, otherwise it returns the
2101556Srgrimes * number of keys it read
2111556Srgrimes */
21295204Scharnierint
2131556Srgrimesauth_init(
21479754Sdd	const char *keyfile,
21571895Sru	struct key **keys
2161556Srgrimes	)
2171556Srgrimes{
2181556Srgrimes	FILE *keyf = fopen(keyfile, "r");
2191556Srgrimes	struct key *prev = NULL;
2201556Srgrimes	int scan_cnt, line_cnt = 1;
2211556Srgrimes	char kbuf[200];
2221556Srgrimes	char keystring[129];
2231556Srgrimes
2241556Srgrimes	/* HMS: Is it OK to do this later, after we know we have a key file? */
2251556Srgrimes	INIT_SSL();
22695204Scharnier
2271556Srgrimes	if (keyf == NULL) {
2281556Srgrimes		if (debug)
2291556Srgrimes			printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile);
2301556Srgrimes		return -1;
23179754Sdd	}
2321556Srgrimes	if (feof(keyf)) {
23379754Sdd		if (debug)
2341556Srgrimes			printf("sntp auth_init: Key file %s is empty!\n", keyfile);
23579754Sdd		fclose(keyf);
2361556Srgrimes		return -1;
2371556Srgrimes	}
2381556Srgrimes	key_cnt = 0;
2391556Srgrimes	while (!feof(keyf)) {
2401556Srgrimes		char * octothorpe;
24195204Scharnier		struct key *act;
2421556Srgrimes		int goodline = 0;
2431556Srgrimes
2441556Srgrimes		if (NULL == fgets(kbuf, sizeof(kbuf), keyf))
24579754Sdd			continue;
2461556Srgrimes
2471556Srgrimes		kbuf[sizeof(kbuf) - 1] = '\0';
2481556Srgrimes		octothorpe = strchr(kbuf, '#');
2491556Srgrimes		if (octothorpe)
2501556Srgrimes			*octothorpe = '\0';
2511556Srgrimes		act = emalloc(sizeof(*act));
2521556Srgrimes		/* keep width 15 = sizeof struct key.typen - 1 synced */
2531556Srgrimes		scan_cnt = sscanf(kbuf, "%d %15s %128s",
2541556Srgrimes					&act->key_id, act->typen, keystring);
2551556Srgrimes		if (scan_cnt == 3) {
2561556Srgrimes			int len = strlen(keystring);
2571556Srgrimes			goodline = 1;	/* assume best for now */
2581556Srgrimes			if (len <= 20) {
2591556Srgrimes				act->key_len = len;
2601556Srgrimes				memcpy(act->key_seq, keystring, len + 1);
2611556Srgrimes			} else if ((len & 1) != 0) {
2621556Srgrimes				goodline = 0; /* it's bad */
2631556Srgrimes			} else {
2641556Srgrimes				int j;
2651556Srgrimes				act->key_len = len >> 1;
2661556Srgrimes				for (j = 0; j < len; j+=2) {
2671556Srgrimes					int val;
2681556Srgrimes					val = (hex_val(keystring[j]) << 4) |
2691556Srgrimes					       hex_val(keystring[j+1]);
2701556Srgrimes					if (val < 0) {
2711556Srgrimes						goodline = 0; /* it's bad */
2721556Srgrimes						break;
2731556Srgrimes					}
2741556Srgrimes					act->key_seq[j>>1] = (char)val;
2751556Srgrimes				}
2761556Srgrimes			}
2771556Srgrimes			act->typei = keytype_from_text(act->typen, NULL);
2781556Srgrimes			if (0 == act->typei) {
2791556Srgrimes				printf("%s: line %d: key %d, %s not supported - ignoring\n",
28036049Scharnier					keyfile, line_cnt,
2811556Srgrimes					act->key_id, act->typen);
2821556Srgrimes				goodline = 0; /* it's bad */
2831556Srgrimes			}
2841556Srgrimes		}
2851556Srgrimes		if (goodline) {
2861556Srgrimes			act->next = NULL;
2871556Srgrimes			if (NULL == prev)
2881556Srgrimes				*keys = act;
2891556Srgrimes			else
2901556Srgrimes				prev->next = act;
2911556Srgrimes			prev = act;
2921556Srgrimes			key_cnt++;
29336049Scharnier		} else {
2941556Srgrimes			if (debug) {
2951556Srgrimes				printf("auth_init: scanf %d items, skipping line %d.",
2961556Srgrimes					scan_cnt, line_cnt);
2971556Srgrimes			}
2981556Srgrimes			free(act);
2991556Srgrimes		}
3001556Srgrimes		line_cnt++;
3011556Srgrimes	}
30279754Sdd	fclose(keyf);
3031556Srgrimes
3041556Srgrimes	key_ptr = *keys;
30579754Sdd	return key_cnt;
3061556Srgrimes}
3071556Srgrimes
3081556Srgrimes/* Looks for the key with keyid key_id and sets the d_key pointer to the
3091556Srgrimes * address of the key. If no matching key is found the pointer is not touched.
3101556Srgrimes */
3111556Srgrimesvoid
31236049Scharnierget_key(
3131556Srgrimes	int key_id,
3141556Srgrimes	struct key **d_key
3151556Srgrimes	)
3161556Srgrimes{
3171556Srgrimes	struct key *itr_key;
3181556Srgrimes
3191556Srgrimes	if (key_cnt == 0)
3201556Srgrimes		return;
3211556Srgrimes	for (itr_key = key_ptr; itr_key; itr_key = itr_key->next) {
3221556Srgrimes		if (itr_key->key_id == key_id) {
3231556Srgrimes			*d_key = itr_key;
3241556Srgrimes			break;
32536049Scharnier		}
3261556Srgrimes	}
3271556Srgrimes	return;
3281556Srgrimes}
3291556Srgrimes