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