diff options
Diffstat (limited to 'libntp/a_md5encrypt.c')
-rw-r--r-- | libntp/a_md5encrypt.c | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/libntp/a_md5encrypt.c b/libntp/a_md5encrypt.c new file mode 100644 index 0000000..ffabc47 --- /dev/null +++ b/libntp/a_md5encrypt.c @@ -0,0 +1,137 @@ +/* + * digest support for NTP, MD5 and with OpenSSL more + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "ntp_fp.h" +#include "ntp_string.h" +#include "ntp_stdlib.h" +#include "ntp.h" +#include "ntp_md5.h" /* provides OpenSSL digest API */ + +/* + * MD5authencrypt - generate message digest + * + * Returns length of MAC including key ID and digest. + */ +int +MD5authencrypt( + int type, /* hash algorithm */ + u_char *key, /* key pointer */ + u_int32 *pkt, /* packet pointer */ + int 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(); +#if defined(OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x0090700fL + if (!EVP_DigestInit(&ctx, EVP_get_digestbynid(type))) { + msyslog(LOG_ERR, + "MAC encrypt: digest init failed"); + return (0); + } +#else + EVP_DigestInit(&ctx, EVP_get_digestbynid(type)); +#endif + EVP_DigestUpdate(&ctx, key, cache_secretsize); + EVP_DigestUpdate(&ctx, (u_char *)pkt, (u_int)length); + EVP_DigestFinal(&ctx, digest, &len); + 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 */ + u_char *key, /* key pointer */ + u_int32 *pkt, /* packet pointer */ + int length, /* packet length */ + int 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(); +#if defined(OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x0090700fL + if (!EVP_DigestInit(&ctx, EVP_get_digestbynid(type))) { + msyslog(LOG_ERR, + "MAC decrypt: digest init failed"); + return (0); + } +#else + EVP_DigestInit(&ctx, EVP_get_digestbynid(type)); +#endif + EVP_DigestUpdate(&ctx, key, cache_secretsize); + EVP_DigestUpdate(&ctx, (u_char *)pkt, (u_int)length); + EVP_DigestFinal(&ctx, digest, &len); + if ((u_int)size != len + 4) { + msyslog(LOG_ERR, + "MAC decrypt: MAC length error"); + return (0); + } + return !memcmp(digest, (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(); + +#if defined(OPENSSL) && OPENSSL_VERSION_NUMBER >= 0x0090700fL + 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"); + exit(1); + } +#else + EVP_DigestInit(&ctx, EVP_md5()); +#endif + + EVP_DigestUpdate(&ctx, (u_char *)PSOCK_ADDR6(addr), + sizeof(struct in6_addr)); + EVP_DigestFinal(&ctx, digest, &len); + memcpy(&addr_refid, digest, sizeof(addr_refid)); + return (addr_refid); +} |