1 /* 2 * digest support for NTP, MD5 and with OpenSSL more 3 */ 4 #ifdef HAVE_CONFIG_H 5 #include <config.h> 6 #endif 7 8 #include "ntp_fp.h" 9 #include "ntp_string.h" 10 #include "ntp_stdlib.h" 11 #include "ntp.h" 12 #include "isc/string.h" 13 14 typedef struct { 15 const void * buf; 16 size_t len; 17 } robuffT; 18 19 typedef struct { 20 void * buf; 21 size_t len; 22 } rwbuffT; 23 24 #if defined(OPENSSL) && defined(ENABLE_CMAC) 25 static size_t 26 cmac_ctx_size( 27 CMAC_CTX * ctx 28 ) 29 { 30 size_t mlen = 0; 31 32 if (ctx) { 33 EVP_CIPHER_CTX * cctx; 34 if (NULL != (cctx = CMAC_CTX_get0_cipher_ctx (ctx))) 35 mlen = EVP_CIPHER_CTX_block_size(cctx); 36 } 37 return mlen; 38 } 39 #endif /* OPENSSL && ENABLE_CMAC */ 40 41 42 /* 43 * Allocate and initialize a digest context. As a speed optimization, 44 * take an idea from ntpsec and cache the context to avoid malloc/free 45 * overhead in time-critical paths. ntpsec also caches the algorithms 46 * with each key. 47 * This is not thread-safe, but that is 48 * not a problem at present. 49 */ 50 static EVP_MD_CTX * 51 get_md_ctx( 52 int nid 53 ) 54 { 55 #ifndef OPENSSL 56 static MD5_CTX md5_ctx; 57 58 DEBUG_INSIST(NID_md5 == nid); 59 MD5Init(&md5_ctx); 60 61 return &md5_ctx; 62 #else 63 if (!EVP_DigestInit(digest_ctx, EVP_get_digestbynid(nid))) { 64 msyslog(LOG_ERR, "%s init failed", OBJ_nid2sn(nid)); 65 return NULL; 66 } 67 68 return digest_ctx; 69 #endif /* OPENSSL */ 70 } 71 72 73 static size_t 74 make_mac( 75 const rwbuffT * digest, 76 int ktype, 77 const robuffT * key, 78 const robuffT * msg 79 ) 80 { 81 /* 82 * Compute digest of key concatenated with packet. Note: the 83 * key type and digest type have been verified when the key 84 * was created. 85 */ 86 size_t retlen = 0; 87 88 #ifdef OPENSSL 89 90 INIT_SSL(); 91 92 /* Check if CMAC key type specific code required */ 93 # ifdef ENABLE_CMAC 94 if (ktype == NID_cmac) { 95 CMAC_CTX * ctx = NULL; 96 void const * keyptr = key->buf; 97 u_char keybuf[AES_128_KEY_SIZE]; 98 99 /* adjust key size (zero padded buffer) if necessary */ 100 if (AES_128_KEY_SIZE > key->len) { 101 memcpy(keybuf, keyptr, key->len); 102 zero_mem((keybuf + key->len), 103 (AES_128_KEY_SIZE - key->len)); 104 keyptr = keybuf; 105 } 106 107 if (NULL == (ctx = CMAC_CTX_new())) { 108 msyslog(LOG_ERR, "MAC encrypt: CMAC %s CTX new failed.", CMAC); 109 goto cmac_fail; 110 } 111 if (!CMAC_Init(ctx, keyptr, AES_128_KEY_SIZE, EVP_aes_128_cbc(), NULL)) { 112 msyslog(LOG_ERR, "MAC encrypt: CMAC %s Init failed.", CMAC); 113 goto cmac_fail; 114 } 115 if (cmac_ctx_size(ctx) > digest->len) { 116 msyslog(LOG_ERR, "MAC encrypt: CMAC %s buf too small.", CMAC); 117 goto cmac_fail; 118 } 119 if (!CMAC_Update(ctx, msg->buf, msg->len)) { 120 msyslog(LOG_ERR, "MAC encrypt: CMAC %s Update failed.", CMAC); 121 goto cmac_fail; 122 } 123 if (!CMAC_Final(ctx, digest->buf, &retlen)) { 124 msyslog(LOG_ERR, "MAC encrypt: CMAC %s Final failed.", CMAC); 125 retlen = 0; 126 } 127 cmac_fail: 128 if (ctx) 129 CMAC_CTX_free(ctx); 130 } 131 else 132 # endif /* ENABLE_CMAC */ 133 { /* generic MAC handling */ 134 EVP_MD_CTX * ctx; 135 u_int uilen = 0; 136 137 ctx = get_md_ctx(ktype); 138 if (NULL == ctx) { 139 goto mac_fail; 140 } 141 if ((size_t)EVP_MD_CTX_size(ctx) > digest->len) { 142 msyslog(LOG_ERR, "MAC encrypt: MAC %s buf too small.", 143 OBJ_nid2sn(ktype)); 144 goto mac_fail; 145 } 146 if (!EVP_DigestUpdate(ctx, key->buf, (u_int)key->len)) { 147 msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update key failed.", 148 OBJ_nid2sn(ktype)); 149 goto mac_fail; 150 } 151 if (!EVP_DigestUpdate(ctx, msg->buf, (u_int)msg->len)) { 152 msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Update data failed.", 153 OBJ_nid2sn(ktype)); 154 goto mac_fail; 155 } 156 if (!EVP_DigestFinal(ctx, digest->buf, &uilen)) { 157 msyslog(LOG_ERR, "MAC encrypt: MAC %s Digest Final failed.", 158 OBJ_nid2sn(ktype)); 159 uilen = 0; 160 } 161 mac_fail: 162 retlen = (size_t)uilen; 163 } 164 165 #else /* !OPENSSL follows */ 166 167 if (NID_md5 == ktype) { 168 EVP_MD_CTX * ctx; 169 170 ctx = get_md_ctx(ktype); 171 if (digest->len < MD5_LENGTH) { 172 msyslog(LOG_ERR, "%s", "MAC encrypt: MAC md5 buf too small."); 173 } else { 174 MD5Init(ctx); 175 MD5Update(ctx, (const void *)key->buf, key->len); 176 MD5Update(ctx, (const void *)msg->buf, msg->len); 177 MD5Final(digest->buf, ctx); 178 retlen = MD5_LENGTH; 179 } 180 } else { 181 msyslog(LOG_ERR, "MAC encrypt: invalid key type %d", ktype); 182 } 183 184 #endif /* !OPENSSL */ 185 186 return retlen; 187 } 188 189 190 /* 191 * MD5authencrypt - generate message digest 192 * 193 * Returns 0 on failure or length of MAC including key ID. 194 */ 195 size_t 196 MD5authencrypt( 197 int type, /* hash algorithm */ 198 const u_char * key, /* key pointer */ 199 size_t klen, /* key length */ 200 u_int32 * pkt, /* packet pointer */ 201 size_t length /* packet length */ 202 ) 203 { 204 u_char digest[EVP_MAX_MD_SIZE]; 205 rwbuffT digb = { digest, sizeof(digest) }; 206 robuffT keyb = { key, klen }; 207 robuffT msgb = { pkt, length }; 208 size_t dlen; 209 210 dlen = make_mac(&digb, type, &keyb, &msgb); 211 if (0 == dlen) { 212 return 0; 213 } 214 memcpy((u_char *)pkt + length + KEY_MAC_LEN, digest, 215 min(dlen, MAX_MDG_LEN)); 216 return (dlen + KEY_MAC_LEN); 217 } 218 219 220 /* 221 * MD5authdecrypt - verify MD5 message authenticator 222 * 223 * Returns one if digest valid, zero if invalid. 224 */ 225 int 226 MD5authdecrypt( 227 int type, /* hash algorithm */ 228 const u_char * key, /* key pointer */ 229 size_t klen, /* key length */ 230 u_int32 * pkt, /* packet pointer */ 231 size_t length, /* packet length */ 232 size_t size, /* MAC size */ 233 keyid_t keyno /* key id (for err log) */ 234 ) 235 { 236 u_char digest[EVP_MAX_MD_SIZE]; 237 rwbuffT digb = { digest, sizeof(digest) }; 238 robuffT keyb = { key, klen }; 239 robuffT msgb = { pkt, length }; 240 size_t dlen = 0; 241 242 dlen = make_mac(&digb, type, &keyb, &msgb); 243 if (0 == dlen || size != dlen + KEY_MAC_LEN) { 244 msyslog(LOG_ERR, 245 "MAC decrypt: MAC length error: %u not %u for key %u", 246 (u_int)size, (u_int)(dlen + KEY_MAC_LEN), keyno); 247 return FALSE; 248 } 249 return !isc_tsmemcmp(digest, 250 (u_char *)pkt + length + KEY_MAC_LEN, dlen); 251 } 252 253 /* 254 * Calculate the reference id from the address. If it is an IPv4 255 * address, use it as is. If it is an IPv6 address, do a md5 on 256 * it and use the bottom 4 bytes. 257 * The result is in network byte order for IPv4 addreseses. For 258 * IPv6, ntpd long differed in the hash calculated on big-endian 259 * vs. little-endian because the first four bytes of the MD5 hash 260 * were used as a u_int32 without any byte swapping. This broke 261 * the refid-based loop detection between mixed-endian systems. 262 * In order to preserve behavior on the more-common little-endian 263 * systems, the hash is now byte-swapped on big-endian systems to 264 * match the little-endian hash. This is ugly but it seems better 265 * than changing the IPv6 refid calculation on the more-common 266 * systems. 267 * This is not thread safe, not a problem so far. 268 */ 269 u_int32 270 addr2refid(sockaddr_u *addr) 271 { 272 static MD5_CTX md5_ctx; 273 union u_tag { 274 u_char digest[MD5_DIGEST_LENGTH]; 275 u_int32 addr_refid; 276 } u; 277 278 if (IS_IPV4(addr)) { 279 return (NSRCADR(addr)); 280 } 281 /* MD5 is not used for authentication here. */ 282 MD5Init(&md5_ctx); 283 MD5Update(&md5_ctx, (void *)&SOCK_ADDR6(addr), sizeof(SOCK_ADDR6(addr))); 284 MD5Final(u.digest, &md5_ctx); 285 #ifdef WORDS_BIGENDIAN 286 u.addr_refid = BYTESWAP32(u.addr_refid); 287 #endif 288 return u.addr_refid; 289 } 290