aboutsummaryrefslogtreecommitdiff
path: root/libntp/a_md5encrypt.c
diff options
context:
space:
mode:
Diffstat (limited to 'libntp/a_md5encrypt.c')
-rw-r--r--libntp/a_md5encrypt.c169
1 files changed, 83 insertions, 86 deletions
diff --git a/libntp/a_md5encrypt.c b/libntp/a_md5encrypt.c
index 7a372969123f..a571405a5d87 100644
--- a/libntp/a_md5encrypt.c
+++ b/libntp/a_md5encrypt.c
@@ -21,7 +21,6 @@ typedef struct {
size_t len;
} rwbuffT;
-
#if defined(OPENSSL) && defined(ENABLE_CMAC)
static size_t
cmac_ctx_size(
@@ -40,6 +39,37 @@ cmac_ctx_size(
#endif /* OPENSSL && ENABLE_CMAC */
+/*
+ * Allocate and initialize a digest context. As a speed optimization,
+ * take an idea from ntpsec and cache the context to avoid malloc/free
+ * overhead in time-critical paths. ntpsec also caches the algorithms
+ * with each key.
+ * This is not thread-safe, but that is
+ * not a problem at present.
+ */
+static EVP_MD_CTX *
+get_md_ctx(
+ int nid
+ )
+{
+#ifndef OPENSSL
+ static MD5_CTX md5_ctx;
+
+ DEBUG_INSIST(NID_md5 == nid);
+ MD5Init(&md5_ctx);
+
+ return &md5_ctx;
+#else
+ if (!EVP_DigestInit(digest_ctx, EVP_get_digestbynid(nid))) {
+ msyslog(LOG_ERR, "%s init failed", OBJ_nid2sn(nid));
+ return NULL;
+ }
+
+ return digest_ctx;
+#endif /* OPENSSL */
+}
+
+
static size_t
make_mac(
const rwbuffT * digest,
@@ -99,26 +129,13 @@ make_mac(
CMAC_CTX_free(ctx);
}
else
-# endif /*ENABLE_CMAC*/
+# endif /* ENABLE_CMAC */
{ /* generic MAC handling */
- EVP_MD_CTX * ctx = EVP_MD_CTX_new();
+ EVP_MD_CTX * ctx;
u_int uilen = 0;
- if ( ! ctx) {
- msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest CTX new failed.",
- OBJ_nid2sn(ktype));
- goto mac_fail;
- }
-
- #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
- /* make sure MD5 is allowd */
- 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(ktype), NULL)) {
- msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Init failed.",
- OBJ_nid2sn(ktype));
+ ctx = get_md_ctx(ktype);
+ if (NULL == ctx) {
goto mac_fail;
}
if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) {
@@ -143,39 +160,25 @@ make_mac(
}
mac_fail:
retlen = (size_t)uilen;
-
- if (ctx)
- EVP_MD_CTX_free(ctx);
}
#else /* !OPENSSL follows */
- if (ktype == NID_md5)
- {
- EVP_MD_CTX * ctx = EVP_MD_CTX_new();
- u_int uilen = 0;
+ if (NID_md5 == ktype) {
+ EVP_MD_CTX * ctx;
- if (digest->len < 16) {
+ ctx = get_md_ctx(ktype);
+ if (digest->len < MD5_LENGTH) {
msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small.");
+ } else {
+ MD5Init(ctx);
+ MD5Update(ctx, (const void *)key->buf, key->len);
+ MD5Update(ctx, (const void *)msg->buf, msg->len);
+ MD5Final(digest->buf, ctx);
+ retlen = MD5_LENGTH;
}
- else if ( ! ctx) {
- msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 Digest CTX new failed.");
- }
- else if (!EVP_DigestInit(ctx, EVP_get_digestbynid(ktype))) {
- msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 Digest INIT failed.");
- }
- else {
- EVP_DigestUpdate(ctx, key->buf, key->len);
- EVP_DigestUpdate(ctx, msg->buf, msg->len);
- EVP_DigestFinal(ctx, digest->buf, &uilen);
- }
- if (ctx)
- EVP_MD_CTX_free(ctx);
- retlen = (size_t)uilen;
- }
- else
- {
- msyslog(LOG_ERR, "MAC encrypt: invalid key type %d" , ktype);
+ } else {
+ msyslog(LOG_ERR, "MAC encrypt: invalid key type %d", ktype);
}
#endif /* !OPENSSL */
@@ -187,7 +190,7 @@ make_mac(
/*
* MD5authencrypt - generate message digest
*
- * Returns length of MAC including key ID and digest.
+ * Returns 0 on failure or length of MAC including key ID.
*/
size_t
MD5authencrypt(
@@ -202,13 +205,14 @@ MD5authencrypt(
rwbuffT digb = { digest, sizeof(digest) };
robuffT keyb = { key, klen };
robuffT msgb = { pkt, length };
- size_t dlen = 0;
+ size_t dlen;
dlen = make_mac(&digb, type, &keyb, &msgb);
- /* If the MAC is longer than the MAX then truncate it. */
- if (dlen > MAX_MDG_LEN)
- dlen = MAX_MDG_LEN;
- memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest, dlen);
+ if (0 == dlen) {
+ return 0;
+ }
+ memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest,
+ min(dlen, MAX_MDG_LEN));
return (dlen + KEY_MAC_LEN);
}
@@ -236,15 +240,11 @@ MD5authdecrypt(
size_t dlen = 0;
dlen = make_mac(&digb, type, &keyb, &msgb);
-
- /* If the MAC is longer than the MAX then truncate it. */
- if (dlen > MAX_MDG_LEN)
- dlen = MAX_MDG_LEN;
- if (size != (size_t)dlen + KEY_MAC_LEN) {
+ if (0 == dlen || size != dlen + KEY_MAC_LEN) {
msyslog(LOG_ERR,
- "MAC decrypt: MAC length error: len=%u key=%d",
- (u_int)size, keyno);
- return (0);
+ "MAC decrypt: MAC length error: %u not %u for key %u",
+ (u_int)size, (u_int)(dlen + KEY_MAC_LEN), keyno);
+ return FALSE;
}
return !isc_tsmemcmp(digest,
(u_char *)pkt + length + KEY_MAC_LEN, dlen);
@@ -254,39 +254,36 @@ MD5authdecrypt(
* Calculate the reference id from the address. If it is an IPv4
* address, use it as is. If it is an IPv6 address, do a md5 on
* it and use the bottom 4 bytes.
- * The result is in network byte order.
+ * The result is in network byte order for IPv4 addreseses. For
+ * IPv6, ntpd long differed in the hash calculated on big-endian
+ * vs. little-endian because the first four bytes of the MD5 hash
+ * were used as a u_int32 without any byte swapping. This broke
+ * the refid-based loop detection between mixed-endian systems.
+ * In order to preserve behavior on the more-common little-endian
+ * systems, the hash is now byte-swapped on big-endian systems to
+ * match the little-endian hash. This is ugly but it seems better
+ * than changing the IPv6 refid calculation on the more-common
+ * systems.
+ * This is not thread safe, not a problem so far.
*/
u_int32
addr2refid(sockaddr_u *addr)
{
- u_char digest[EVP_MAX_MD_SIZE];
- u_int32 addr_refid;
- EVP_MD_CTX *ctx;
- u_int len;
+ static MD5_CTX md5_ctx;
+ union u_tag {
+ u_char digest[MD5_DIGEST_LENGTH];
+ u_int32 addr_refid;
+ } u;
- if (IS_IPV4(addr))
+ if (IS_IPV4(addr)) {
return (NSRCADR(addr));
-
- INIT_SSL();
-
- ctx = EVP_MD_CTX_new();
-# ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW
- /* MD5 is not used as a crypto hash here. */
- 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_md5(), NULL)) {
- msyslog(LOG_ERR,
- "MD5 init failed");
- EVP_MD_CTX_free(ctx); /* pedantic... but safe */
- exit(1);
}
-
- EVP_DigestUpdate(ctx, (u_char *)PSOCK_ADDR6(addr),
- sizeof(struct in6_addr));
- EVP_DigestFinal(ctx, digest, &len);
- EVP_MD_CTX_free(ctx);
- memcpy(&addr_refid, digest, sizeof(addr_refid));
- return (addr_refid);
+ /* MD5 is not used for authentication here. */
+ MD5Init(&md5_ctx);
+ MD5Update(&md5_ctx, (void *)&SOCK_ADDR6(addr), sizeof(SOCK_ADDR6(addr)));
+ MD5Final(u.digest, &md5_ctx);
+#ifdef WORDS_BIGENDIAN
+ u.addr_refid = BYTESWAP32(u.addr_refid);
+#endif
+ return u.addr_refid;
}