1 /* $NetBSD: a_md5encrypt.c,v 1.7 2016/11/22 03:09:30 christos Exp $ */ 2 3 /* 4 * digest support for NTP, MD5 and with OpenSSL more 5 */ 6 #ifdef HAVE_CONFIG_H 7 #include <config.h> 8 #endif 9 10 #include "ntp_fp.h" 11 #include "ntp_string.h" 12 #include "ntp_stdlib.h" 13 #include "ntp.h" 14 #include "ntp_md5.h" /* provides OpenSSL digest API */ 15 #include "isc/string.h" 16 #include "libssl_compat.h" 17 /* 18 * MD5authencrypt - generate message digest 19 * 20 * Returns length of MAC including key ID and digest. 21 */ 22 size_t 23 MD5authencrypt( 24 int type, /* hash algorithm */ 25 const u_char * key, /* key pointer */ 26 u_int32 * pkt, /* packet pointer */ 27 size_t length /* packet length */ 28 ) 29 { 30 u_char digest[EVP_MAX_MD_SIZE]; 31 u_int len; 32 EVP_MD_CTX *ctx; 33 34 /* 35 * Compute digest of key concatenated with packet. Note: the 36 * key type and digest type have been verified when the key 37 * was creaded. 38 */ 39 INIT_SSL(); 40 ctx = EVP_MD_CTX_new(); 41 if (!(ctx && EVP_DigestInit(ctx, EVP_get_digestbynid(type)))) { 42 msyslog(LOG_ERR, 43 "MAC encrypt: digest init failed"); 44 EVP_MD_CTX_free(ctx); 45 return (0); 46 } 47 EVP_DigestUpdate(ctx, key, cache_secretsize); 48 EVP_DigestUpdate(ctx, (u_char *)pkt, length); 49 EVP_DigestFinal(ctx, digest, &len); 50 EVP_MD_CTX_free(ctx); 51 /* If the MAC is longer than the MAX then truncate it. */ 52 if (len > MAX_MAC_LEN - 4) 53 len = MAX_MAC_LEN - 4; 54 memmove((u_char *)pkt + length + 4, digest, len); 55 return (len + 4); 56 } 57 58 59 /* 60 * MD5authdecrypt - verify MD5 message authenticator 61 * 62 * Returns one if digest valid, zero if invalid. 63 */ 64 int 65 MD5authdecrypt( 66 int type, /* hash algorithm */ 67 const u_char * key, /* key pointer */ 68 u_int32 * pkt, /* packet pointer */ 69 size_t length, /* packet length */ 70 size_t size /* MAC size */ 71 ) 72 { 73 u_char digest[EVP_MAX_MD_SIZE]; 74 u_int len; 75 EVP_MD_CTX *ctx; 76 77 /* 78 * Compute digest of key concatenated with packet. Note: the 79 * key type and digest type have been verified when the key 80 * was created. 81 */ 82 INIT_SSL(); 83 ctx = EVP_MD_CTX_new(); 84 if (!(ctx && EVP_DigestInit(ctx, EVP_get_digestbynid(type)))) { 85 msyslog(LOG_ERR, 86 "MAC decrypt: digest init failed"); 87 EVP_MD_CTX_free(ctx); 88 return (0); 89 } 90 EVP_DigestUpdate(ctx, key, cache_secretsize); 91 EVP_DigestUpdate(ctx, (u_char *)pkt, length); 92 EVP_DigestFinal(ctx, digest, &len); 93 EVP_MD_CTX_free(ctx); 94 /* If the MAC is longer than the MAX then truncate it. */ 95 if (len > MAX_MAC_LEN - 4) 96 len = MAX_MAC_LEN - 4; 97 if (size != (size_t)len + 4) { 98 msyslog(LOG_ERR, 99 "MAC decrypt: MAC length error"); 100 return (0); 101 } 102 return !isc_tsmemcmp(digest, (u_char *)pkt + length + 4, len); 103 } 104 105 /* 106 * Calculate the reference id from the address. If it is an IPv4 107 * address, use it as is. If it is an IPv6 address, do a md5 on 108 * it and use the bottom 4 bytes. 109 * The result is in network byte order. 110 */ 111 u_int32 112 addr2refid(sockaddr_u *addr) 113 { 114 u_char digest[20]; 115 u_int32 addr_refid; 116 EVP_MD_CTX *ctx; 117 u_int len; 118 119 if (IS_IPV4(addr)) 120 return (NSRCADR(addr)); 121 122 INIT_SSL(); 123 124 ctx = EVP_MD_CTX_new(); 125 EVP_MD_CTX_init(ctx); 126 #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW 127 /* MD5 is not used as a crypto hash here. */ 128 EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); 129 #endif 130 if (!EVP_DigestInit_ex(ctx, EVP_md5(), NULL)) { 131 msyslog(LOG_ERR, 132 "MD5 init failed"); 133 EVP_MD_CTX_free(ctx); /* pedantic... but safe */ 134 exit(1); 135 } 136 137 EVP_DigestUpdate(ctx, (u_char *)PSOCK_ADDR6(addr), 138 sizeof(struct in6_addr)); 139 EVP_DigestFinal(ctx, digest, &len); 140 EVP_MD_CTX_free(ctx); 141 memcpy(&addr_refid, digest, sizeof(addr_refid)); 142 return (addr_refid); 143 } 144