/* * digest support for NTP, MD5 and with OpenSSL more */ #ifdef HAVE_CONFIG_H #include #endif #include "ntp_fp.h" #include "ntp_string.h" #include "ntp_stdlib.h" #include "ntp.h" #include "ntp_md5.h" /* provides OpenSSL digest API */ #include "isc/string.h" /* * MD5authencrypt - generate message digest * * Returns length of MAC including key ID and digest. */ size_t MD5authencrypt( int type, /* hash algorithm */ const u_char * key, /* key pointer */ u_int32 * pkt, /* packet pointer */ size_t length /* packet length */ ) { u_char digest[EVP_MAX_MD_SIZE]; u_int len; EVP_MD_CTX *ctx; /* * Compute digest of key concatenated with packet. Note: the * key type and digest type have been verified when the key * was creaded. */ INIT_SSL(); ctx = EVP_MD_CTX_new(); if (!(ctx && EVP_DigestInit(ctx, EVP_get_digestbynid(type)))) { msyslog(LOG_ERR, "MAC encrypt: digest init failed"); EVP_MD_CTX_free(ctx); return (0); } EVP_DigestUpdate(ctx, key, cache_secretsize); EVP_DigestUpdate(ctx, (u_char *)pkt, length); EVP_DigestFinal(ctx, digest, &len); EVP_MD_CTX_free(ctx); /* If the MAC is longer than the MAX then truncate it. */ if (len > MAX_MAC_LEN - 4) len = MAX_MAC_LEN - 4; memmove((u_char *)pkt + length + 4, digest, len); return (len + 4); } /* * MD5authdecrypt - verify MD5 message authenticator * * Returns one if digest valid, zero if invalid. */ int MD5authdecrypt( int type, /* hash algorithm */ const u_char * key, /* key pointer */ u_int32 * pkt, /* packet pointer */ size_t length, /* packet length */ size_t size /* MAC size */ ) { u_char digest[EVP_MAX_MD_SIZE]; u_int len; EVP_MD_CTX *ctx; /* * Compute digest of key concatenated with packet. Note: the * key type and digest type have been verified when the key * was created. */ INIT_SSL(); ctx = EVP_MD_CTX_new(); if (!(ctx && EVP_DigestInit(ctx, EVP_get_digestbynid(type)))) { msyslog(LOG_ERR, "MAC decrypt: digest init failed"); EVP_MD_CTX_free(ctx); return (0); } EVP_DigestUpdate(ctx, key, cache_secretsize); EVP_DigestUpdate(ctx, (u_char *)pkt, length); EVP_DigestFinal(ctx, digest, &len); EVP_MD_CTX_free(ctx); /* If the MAC is longer than the MAX then truncate it. */ if (len > MAX_MAC_LEN - 4) len = MAX_MAC_LEN - 4; if (size != (size_t)len + 4) { msyslog(LOG_ERR, "MAC decrypt: MAC length error"); return (0); } return !isc_tsmemcmp(digest, (u_char *)pkt + length + 4, len); } /* * 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. */ u_int32 addr2refid(sockaddr_u *addr) { u_char digest[20]; u_int32 addr_refid; EVP_MD_CTX *ctx; u_int len; if (IS_IPV4(addr)) return (NSRCADR(addr)); INIT_SSL(); ctx = EVP_MD_CTX_new(); EVP_MD_CTX_init(ctx); #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 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); }