aboutsummaryrefslogtreecommitdiff
path: root/contrib/ntp/sntp/crypto.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ntp/sntp/crypto.c')
-rw-r--r--contrib/ntp/sntp/crypto.c242
1 files changed, 187 insertions, 55 deletions
diff --git a/contrib/ntp/sntp/crypto.c b/contrib/ntp/sntp/crypto.c
index e45b21360aa9..ce5d136fcbf1 100644
--- a/contrib/ntp/sntp/crypto.c
+++ b/contrib/ntp/sntp/crypto.c
@@ -1,77 +1,196 @@
+/*
+ * HMS: we need to test:
+ * - OpenSSL versions, if we are building with them
+ * - our versions
+ *
+ * We may need to test with(out) OPENSSL separately.
+ */
+
#include <config.h>
#include "crypto.h"
#include <ctype.h>
#include "isc/string.h"
#include "ntp_md5.h"
+/* HMS: We may not have OpenSSL, but we have our own AES-128-CMAC */
+#define CMAC "AES128CMAC"
+#ifdef OPENSSL
+# include "openssl/cmac.h"
+# define AES_128_KEY_SIZE 16
+#endif /* OPENSSL */
+
+#ifndef EVP_MAX_MD_SIZE
+# define EVP_MAX_MD_SIZE 32
+#endif
+
struct key *key_ptr;
size_t key_cnt = 0;
+typedef struct key Key_T;
+
+static u_int
+compute_mac(
+ u_char digest[EVP_MAX_MD_SIZE],
+ char const * macname,
+ void const * pkt_data,
+ u_int pkt_size,
+ void const * key_data,
+ u_int key_size
+ )
+{
+ u_int len = 0;
+ size_t slen = 0;
+ int key_type;
+
+ INIT_SSL();
+ key_type = keytype_from_text(macname, NULL);
+
+#ifdef OPENSSL
+ /* Check if CMAC key type specific code required */
+ if (key_type == NID_cmac) {
+ CMAC_CTX * ctx = NULL;
+ u_char keybuf[AES_128_KEY_SIZE];
+
+ /* adjust key size (zero padded buffer) if necessary */
+ if (AES_128_KEY_SIZE > key_size) {
+ memcpy(keybuf, key_data, key_size);
+ memset((keybuf + key_size), 0,
+ (AES_128_KEY_SIZE - key_size));
+ key_data = keybuf;
+ }
+
+ if (!(ctx = CMAC_CTX_new())) {
+ msyslog(LOG_ERR, "make_mac: CMAC %s CTX new failed.", CMAC);
+ }
+ else if (!CMAC_Init(ctx, key_data, AES_128_KEY_SIZE,
+ EVP_aes_128_cbc(), NULL)) {
+ msyslog(LOG_ERR, "make_mac: CMAC %s Init failed.", CMAC);
+ }
+ else if (!CMAC_Update(ctx, pkt_data, (size_t)pkt_size)) {
+ msyslog(LOG_ERR, "make_mac: CMAC %s Update failed.", CMAC);
+ }
+ else if (!CMAC_Final(ctx, digest, &slen)) {
+ msyslog(LOG_ERR, "make_mac: CMAC %s Final failed.", CMAC);
+ slen = 0;
+ }
+ len = (u_int)slen;
+
+ CMAC_CTX_cleanup(ctx);
+ /* Test our AES-128-CMAC implementation */
+
+ } else /* MD5 MAC handling */
+#endif
+ {
+ EVP_MD_CTX * ctx;
+
+ if (!(ctx = EVP_MD_CTX_new())) {
+ msyslog(LOG_ERR, "make_mac: MAC %s Digest CTX new failed.",
+ macname);
+ goto mac_fail;
+ }
+#ifdef OPENSSL /* OpenSSL 1 supports return codes 0 fail, 1 okay */
+# ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
+ EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW);
+# endif
+ /* [Bug 3457] DON'T use plain EVP_DigestInit! It would
+ * kill the flags! */
+ if (!EVP_DigestInit_ex(ctx, EVP_get_digestbynid(key_type), NULL)) {
+ msyslog(LOG_ERR, "make_mac: MAC %s Digest Init failed.",
+ macname);
+ goto mac_fail;
+ }
+ if (!EVP_DigestUpdate(ctx, key_data, key_size)) {
+ msyslog(LOG_ERR, "make_mac: MAC %s Digest Update key failed.",
+ macname);
+ goto mac_fail;
+ }
+ if (!EVP_DigestUpdate(ctx, pkt_data, pkt_size)) {
+ msyslog(LOG_ERR, "make_mac: MAC %s Digest Update data failed.",
+ macname);
+ goto mac_fail;
+ }
+ if (!EVP_DigestFinal(ctx, digest, &len)) {
+ msyslog(LOG_ERR, "make_mac: MAC %s Digest Final failed.",
+ macname);
+ len = 0;
+ }
+#else /* !OPENSSL */
+ EVP_DigestInit(ctx, EVP_get_digestbynid(key_type));
+ EVP_DigestUpdate(ctx, key_data, key_size);
+ EVP_DigestUpdate(ctx, pkt_data, pkt_size);
+ EVP_DigestFinal(ctx, digest, &len);
+#endif
+ mac_fail:
+ EVP_MD_CTX_free(ctx);
+ }
+
+ return len;
+}
+
int
make_mac(
- const void *pkt_data,
- int pkt_size,
- int mac_size,
- const struct key *cmp_key,
- void * digest
+ const void * pkt_data,
+ int pkt_size,
+ int mac_size,
+ Key_T const * cmp_key,
+ void * digest
)
{
- u_int len = mac_size;
- int key_type;
- EVP_MD_CTX * ctx;
+ u_int len;
+ u_char dbuf[EVP_MAX_MD_SIZE];
- if (cmp_key->key_len > 64)
+ if (cmp_key->key_len > 64 || mac_size <= 0)
return 0;
if (pkt_size % 4 != 0)
return 0;
- INIT_SSL();
- key_type = keytype_from_text(cmp_key->type, NULL);
-
- ctx = EVP_MD_CTX_new();
- EVP_DigestInit(ctx, EVP_get_digestbynid(key_type));
- EVP_DigestUpdate(ctx, (const u_char *)cmp_key->key_seq, (u_int)cmp_key->key_len);
- EVP_DigestUpdate(ctx, pkt_data, (u_int)pkt_size);
- EVP_DigestFinal(ctx, digest, &len);
- EVP_MD_CTX_free(ctx);
-
+ len = compute_mac(dbuf, cmp_key->typen,
+ pkt_data, (u_int)pkt_size,
+ cmp_key->key_seq, (u_int)cmp_key->key_len);
+
+
+ if (len) {
+ if (len > (u_int)mac_size)
+ len = (u_int)mac_size;
+ memcpy(digest, dbuf, len);
+ }
return (int)len;
}
-/* Generates a md5 digest of the key specified in keyid concatenated with the
+/* Generates a md5 digest of the key specified in keyid concatenated with the
* ntp packet (exluding the MAC) and compares this digest to the digest in
- * the packet's MAC. If they're equal this function returns 1 (packet is
+ * the packet's MAC. If they're equal this function returns 1 (packet is
* authentic) or else 0 (not authentic).
*/
int
auth_md5(
- const void *pkt_data,
- int pkt_size,
- int mac_size,
- const struct key *cmp_key
+ void const * pkt_data,
+ int pkt_size,
+ int mac_size,
+ Key_T const * cmp_key
)
{
- int hash_len;
- int authentic;
- char digest[20];
- const u_char *pkt_ptr;
- if (mac_size > (int)sizeof(digest))
- return 0;
- pkt_ptr = pkt_data;
- hash_len = make_mac(pkt_ptr, pkt_size, sizeof(digest), cmp_key,
- digest);
- if (!hash_len) {
- authentic = FALSE;
- } else {
- /* isc_tsmemcmp will be better when its easy to link
- * with. sntp is a 1-shot program, so snooping for
- * timing attacks is Harder.
- */
- authentic = !memcmp(digest, (const char*)pkt_data + pkt_size + 4,
- hash_len);
- }
- return authentic;
+ u_int len = 0;
+ u_char const * pkt_ptr = pkt_data;
+ u_char dbuf[EVP_MAX_MD_SIZE];
+
+ if (mac_size <= 0 || (size_t)mac_size > sizeof(dbuf))
+ return FALSE;
+
+ len = compute_mac(dbuf, cmp_key->typen,
+ pkt_ptr, (u_int)pkt_size,
+ cmp_key->key_seq, (u_int)cmp_key->key_len);
+
+ pkt_ptr += pkt_size + 4;
+ if (len > (u_int)mac_size)
+ len = (u_int)mac_size;
+
+ /* isc_tsmemcmp will be better when its easy to link with. sntp
+ * is a 1-shot program, so snooping for timing attacks is
+ * Harder.
+ */
+ return ((u_int)mac_size == len) && !memcmp(dbuf, pkt_ptr, len);
}
static int
@@ -94,7 +213,7 @@ hex_val(
}
/* Load keys from the specified keyfile into the key structures.
- * Returns -1 if the reading failed, otherwise it returns the
+ * Returns -1 if the reading failed, otherwise it returns the
* number of keys it read
*/
int
@@ -103,12 +222,15 @@ auth_init(
struct key **keys
)
{
- FILE *keyf = fopen(keyfile, "r");
+ FILE *keyf = fopen(keyfile, "r");
struct key *prev = NULL;
- int scan_cnt, line_cnt = 0;
+ int scan_cnt, line_cnt = 1;
char kbuf[200];
char keystring[129];
+ /* HMS: Is it OK to do this later, after we know we have a key file? */
+ INIT_SSL();
+
if (keyf == NULL) {
if (debug)
printf("sntp auth_init: Couldn't open key file %s for reading!\n", keyfile);
@@ -134,18 +256,19 @@ auth_init(
if (octothorpe)
*octothorpe = '\0';
act = emalloc(sizeof(*act));
- scan_cnt = sscanf(kbuf, "%d %9s %128s", &act->key_id, act->type, keystring);
+ /* keep width 15 = sizeof struct key.typen - 1 synced */
+ scan_cnt = sscanf(kbuf, "%d %15s %128s",
+ &act->key_id, act->typen, keystring);
if (scan_cnt == 3) {
int len = strlen(keystring);
+ goodline = 1; /* assume best for now */
if (len <= 20) {
act->key_len = len;
memcpy(act->key_seq, keystring, len + 1);
- goodline = 1;
} else if ((len & 1) != 0) {
goodline = 0; /* it's bad */
} else {
int j;
- goodline = 1;
act->key_len = len >> 1;
for (j = 0; j < len; j+=2) {
int val;
@@ -158,6 +281,13 @@ auth_init(
act->key_seq[j>>1] = (char)val;
}
}
+ act->typei = keytype_from_text(act->typen, NULL);
+ if (0 == act->typei) {
+ printf("%s: line %d: key %d, %s not supported - ignoring\n",
+ keyfile, line_cnt,
+ act->key_id, act->typen);
+ goodline = 0; /* it's bad */
+ }
}
if (goodline) {
act->next = NULL;
@@ -168,19 +298,21 @@ auth_init(
prev = act;
key_cnt++;
} else {
- msyslog(LOG_DEBUG, "auth_init: scanf %d items, skipping line %d.",
- scan_cnt, line_cnt);
+ if (debug) {
+ printf("auth_init: scanf %d items, skipping line %d.",
+ scan_cnt, line_cnt);
+ }
free(act);
}
line_cnt++;
}
fclose(keyf);
-
+
key_ptr = *keys;
return key_cnt;
}
-/* Looks for the key with keyid key_id and sets the d_key pointer to the
+/* Looks for the key with keyid key_id and sets the d_key pointer to the
* address of the key. If no matching key is found the pointer is not touched.
*/
void