127df3f5dSRui Paulo /* 227df3f5dSRui Paulo * Redistribution and use in source and binary forms, with or without 327df3f5dSRui Paulo * modification, are permitted provided that: (1) source code 427df3f5dSRui Paulo * distributions retain the above copyright notice and this paragraph 527df3f5dSRui Paulo * in its entirety, and (2) distributions including binary code include 627df3f5dSRui Paulo * the above copyright notice and this paragraph in its entirety in 727df3f5dSRui Paulo * the documentation or other materials provided with the distribution. 827df3f5dSRui Paulo * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 927df3f5dSRui Paulo * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 1027df3f5dSRui Paulo * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 1127df3f5dSRui Paulo * FOR A PARTICULAR PURPOSE. 1227df3f5dSRui Paulo * 1327df3f5dSRui Paulo * Functions for signature and digest verification. 1427df3f5dSRui Paulo * 1527df3f5dSRui Paulo * Original code by Hannes Gredler (hannes@juniper.net) 1627df3f5dSRui Paulo */ 1727df3f5dSRui Paulo 1827df3f5dSRui Paulo #ifdef HAVE_CONFIG_H 1927df3f5dSRui Paulo #include "config.h" 2027df3f5dSRui Paulo #endif 2127df3f5dSRui Paulo 22*3340d773SGleb Smirnoff #include <netdissect-stdinc.h> 2327df3f5dSRui Paulo 2427df3f5dSRui Paulo #include <string.h> 25*3340d773SGleb Smirnoff #include <stdlib.h> 2627df3f5dSRui Paulo 27*3340d773SGleb Smirnoff #include "netdissect.h" 2827df3f5dSRui Paulo #include "signature.h" 2927df3f5dSRui Paulo 3027df3f5dSRui Paulo #ifdef HAVE_LIBCRYPTO 3127df3f5dSRui Paulo #include <openssl/md5.h> 3227df3f5dSRui Paulo #endif 3327df3f5dSRui Paulo 3427df3f5dSRui Paulo const struct tok signature_check_values[] = { 3527df3f5dSRui Paulo { SIGNATURE_VALID, "valid"}, 3627df3f5dSRui Paulo { SIGNATURE_INVALID, "invalid"}, 37*3340d773SGleb Smirnoff { CANT_ALLOCATE_COPY, "can't allocate memory"}, 3827df3f5dSRui Paulo { CANT_CHECK_SIGNATURE, "unchecked"}, 3927df3f5dSRui Paulo { 0, NULL } 4027df3f5dSRui Paulo }; 4127df3f5dSRui Paulo 4227df3f5dSRui Paulo 4327df3f5dSRui Paulo #ifdef HAVE_LIBCRYPTO 4427df3f5dSRui Paulo /* 4527df3f5dSRui Paulo * Compute a HMAC MD5 sum. 4627df3f5dSRui Paulo * Taken from rfc2104, Appendix. 4727df3f5dSRui Paulo */ 483c602fabSXin LI USES_APPLE_DEPRECATED_API 4927df3f5dSRui Paulo static void 503c602fabSXin LI signature_compute_hmac_md5(const uint8_t *text, int text_len, unsigned char *key, 513c602fabSXin LI unsigned int key_len, uint8_t *digest) 5227df3f5dSRui Paulo { 5327df3f5dSRui Paulo MD5_CTX context; 5427df3f5dSRui Paulo unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */ 5527df3f5dSRui Paulo unsigned char k_opad[65]; /* outer padding - key XORd with opad */ 5627df3f5dSRui Paulo unsigned char tk[16]; 5727df3f5dSRui Paulo int i; 5827df3f5dSRui Paulo 5927df3f5dSRui Paulo /* if key is longer than 64 bytes reset it to key=MD5(key) */ 6027df3f5dSRui Paulo if (key_len > 64) { 6127df3f5dSRui Paulo 6227df3f5dSRui Paulo MD5_CTX tctx; 6327df3f5dSRui Paulo 6427df3f5dSRui Paulo MD5_Init(&tctx); 6527df3f5dSRui Paulo MD5_Update(&tctx, key, key_len); 6627df3f5dSRui Paulo MD5_Final(tk, &tctx); 6727df3f5dSRui Paulo 6827df3f5dSRui Paulo key = tk; 6927df3f5dSRui Paulo key_len = 16; 7027df3f5dSRui Paulo } 7127df3f5dSRui Paulo 7227df3f5dSRui Paulo /* 7327df3f5dSRui Paulo * the HMAC_MD5 transform looks like: 7427df3f5dSRui Paulo * 7527df3f5dSRui Paulo * MD5(K XOR opad, MD5(K XOR ipad, text)) 7627df3f5dSRui Paulo * 7727df3f5dSRui Paulo * where K is an n byte key 7827df3f5dSRui Paulo * ipad is the byte 0x36 repeated 64 times 7927df3f5dSRui Paulo * opad is the byte 0x5c repeated 64 times 8027df3f5dSRui Paulo * and text is the data being protected 8127df3f5dSRui Paulo */ 8227df3f5dSRui Paulo 8327df3f5dSRui Paulo /* start out by storing key in pads */ 8427df3f5dSRui Paulo memset(k_ipad, 0, sizeof k_ipad); 8527df3f5dSRui Paulo memset(k_opad, 0, sizeof k_opad); 8627df3f5dSRui Paulo memcpy(k_ipad, key, key_len); 8727df3f5dSRui Paulo memcpy(k_opad, key, key_len); 8827df3f5dSRui Paulo 8927df3f5dSRui Paulo /* XOR key with ipad and opad values */ 9027df3f5dSRui Paulo for (i=0; i<64; i++) { 9127df3f5dSRui Paulo k_ipad[i] ^= 0x36; 9227df3f5dSRui Paulo k_opad[i] ^= 0x5c; 9327df3f5dSRui Paulo } 9427df3f5dSRui Paulo 9527df3f5dSRui Paulo /* 9627df3f5dSRui Paulo * perform inner MD5 9727df3f5dSRui Paulo */ 9827df3f5dSRui Paulo MD5_Init(&context); /* init context for 1st pass */ 9927df3f5dSRui Paulo MD5_Update(&context, k_ipad, 64); /* start with inner pad */ 10027df3f5dSRui Paulo MD5_Update(&context, text, text_len); /* then text of datagram */ 10127df3f5dSRui Paulo MD5_Final(digest, &context); /* finish up 1st pass */ 10227df3f5dSRui Paulo 10327df3f5dSRui Paulo /* 10427df3f5dSRui Paulo * perform outer MD5 10527df3f5dSRui Paulo */ 10627df3f5dSRui Paulo MD5_Init(&context); /* init context for 2nd pass */ 10727df3f5dSRui Paulo MD5_Update(&context, k_opad, 64); /* start with outer pad */ 10827df3f5dSRui Paulo MD5_Update(&context, digest, 16); /* then results of 1st hash */ 10927df3f5dSRui Paulo MD5_Final(digest, &context); /* finish up 2nd pass */ 11027df3f5dSRui Paulo } 1113c602fabSXin LI USES_APPLE_RST 11227df3f5dSRui Paulo 11327df3f5dSRui Paulo /* 11427df3f5dSRui Paulo * Verify a cryptographic signature of the packet. 11527df3f5dSRui Paulo * Currently only MD5 is supported. 11627df3f5dSRui Paulo */ 11727df3f5dSRui Paulo int 118*3340d773SGleb Smirnoff signature_verify(netdissect_options *ndo, const u_char *pptr, u_int plen, 119*3340d773SGleb Smirnoff const u_char *sig_ptr, void (*clear_rtn)(void *), 120*3340d773SGleb Smirnoff const void *clear_arg) 12127df3f5dSRui Paulo { 122*3340d773SGleb Smirnoff uint8_t *packet_copy, *sig_copy; 1233c602fabSXin LI uint8_t sig[16]; 12427df3f5dSRui Paulo unsigned int i; 12527df3f5dSRui Paulo 1263c602fabSXin LI if (!ndo->ndo_sigsecret) { 12727df3f5dSRui Paulo return (CANT_CHECK_SIGNATURE); 12827df3f5dSRui Paulo } 12927df3f5dSRui Paulo 130*3340d773SGleb Smirnoff /* 131*3340d773SGleb Smirnoff * Do we have all the packet data to be checked? 132*3340d773SGleb Smirnoff */ 133*3340d773SGleb Smirnoff if (!ND_TTEST2(pptr, plen)) { 134*3340d773SGleb Smirnoff /* No. */ 135*3340d773SGleb Smirnoff return (CANT_CHECK_SIGNATURE); 136*3340d773SGleb Smirnoff } 137*3340d773SGleb Smirnoff 138*3340d773SGleb Smirnoff /* 139*3340d773SGleb Smirnoff * Do we have the entire signature to check? 140*3340d773SGleb Smirnoff */ 141*3340d773SGleb Smirnoff if (!ND_TTEST2(sig_ptr, sizeof(sig))) { 142*3340d773SGleb Smirnoff /* No. */ 143*3340d773SGleb Smirnoff return (CANT_CHECK_SIGNATURE); 144*3340d773SGleb Smirnoff } 145*3340d773SGleb Smirnoff if (sig_ptr + sizeof(sig) > pptr + plen) { 146*3340d773SGleb Smirnoff /* No. */ 147*3340d773SGleb Smirnoff return (CANT_CHECK_SIGNATURE); 148*3340d773SGleb Smirnoff } 149*3340d773SGleb Smirnoff 150*3340d773SGleb Smirnoff /* 151*3340d773SGleb Smirnoff * Make a copy of the packet, so we don't overwrite the original. 152*3340d773SGleb Smirnoff */ 153*3340d773SGleb Smirnoff packet_copy = malloc(plen); 154*3340d773SGleb Smirnoff if (packet_copy == NULL) { 155*3340d773SGleb Smirnoff return (CANT_ALLOCATE_COPY); 156*3340d773SGleb Smirnoff } 157*3340d773SGleb Smirnoff 158*3340d773SGleb Smirnoff memcpy(packet_copy, pptr, plen); 159*3340d773SGleb Smirnoff 160*3340d773SGleb Smirnoff /* 161*3340d773SGleb Smirnoff * Clear the signature in the copy. 162*3340d773SGleb Smirnoff */ 163*3340d773SGleb Smirnoff sig_copy = packet_copy + (sig_ptr - pptr); 164*3340d773SGleb Smirnoff memset(sig_copy, 0, sizeof(sig)); 165*3340d773SGleb Smirnoff 166*3340d773SGleb Smirnoff /* 167*3340d773SGleb Smirnoff * Clear anything else that needs to be cleared in the copy. 168*3340d773SGleb Smirnoff * Our caller is assumed to have vetted the clear_arg pointer. 169*3340d773SGleb Smirnoff */ 170*3340d773SGleb Smirnoff (*clear_rtn)((void *)(packet_copy + ((const uint8_t *)clear_arg - pptr))); 171*3340d773SGleb Smirnoff 172*3340d773SGleb Smirnoff /* 173*3340d773SGleb Smirnoff * Compute the signature. 174*3340d773SGleb Smirnoff */ 175*3340d773SGleb Smirnoff signature_compute_hmac_md5(packet_copy, plen, 176*3340d773SGleb Smirnoff (unsigned char *)ndo->ndo_sigsecret, 1773c602fabSXin LI strlen(ndo->ndo_sigsecret), sig); 17827df3f5dSRui Paulo 179*3340d773SGleb Smirnoff /* 180*3340d773SGleb Smirnoff * Free the copy. 181*3340d773SGleb Smirnoff */ 182*3340d773SGleb Smirnoff free(packet_copy); 183*3340d773SGleb Smirnoff 184*3340d773SGleb Smirnoff /* 185*3340d773SGleb Smirnoff * Does the computed signature match the signature in the packet? 186*3340d773SGleb Smirnoff */ 187*3340d773SGleb Smirnoff if (memcmp(sig_ptr, sig, sizeof(sig)) == 0) { 188*3340d773SGleb Smirnoff /* Yes. */ 18927df3f5dSRui Paulo return (SIGNATURE_VALID); 19027df3f5dSRui Paulo } else { 191*3340d773SGleb Smirnoff /* No - print the computed signature. */ 19227df3f5dSRui Paulo for (i = 0; i < sizeof(sig); ++i) { 1933c602fabSXin LI ND_PRINT((ndo, "%02x", sig[i])); 19427df3f5dSRui Paulo } 19527df3f5dSRui Paulo 19627df3f5dSRui Paulo return (SIGNATURE_INVALID); 19727df3f5dSRui Paulo } 19827df3f5dSRui Paulo } 199*3340d773SGleb Smirnoff #else 200*3340d773SGleb Smirnoff int 201*3340d773SGleb Smirnoff signature_verify(netdissect_options *ndo _U_, const u_char *pptr _U_, 202*3340d773SGleb Smirnoff u_int plen _U_, const u_char *sig_ptr _U_, 203*3340d773SGleb Smirnoff void (*clear_rtn)(void *) _U_, const void *clear_arg _U_) 204*3340d773SGleb Smirnoff { 205*3340d773SGleb Smirnoff return (CANT_CHECK_SIGNATURE); 206*3340d773SGleb Smirnoff } 20727df3f5dSRui Paulo #endif 20827df3f5dSRui Paulo 20927df3f5dSRui Paulo /* 21027df3f5dSRui Paulo * Local Variables: 21127df3f5dSRui Paulo * c-style: whitesmith 21227df3f5dSRui Paulo * c-basic-offset: 4 21327df3f5dSRui Paulo * End: 21427df3f5dSRui Paulo */ 215