diff options
Diffstat (limited to 'signature.c')
-rw-r--r-- | signature.c | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/signature.c b/signature.c new file mode 100644 index 0000000..77d6e81 --- /dev/null +++ b/signature.c @@ -0,0 +1,208 @@ +/* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: (1) source code + * distributions retain the above copyright notice and this paragraph + * in its entirety, and (2) distributions including binary code include + * the above copyright notice and this paragraph in its entirety in + * the documentation or other materials provided with the distribution. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND + * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT + * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * Functions for signature and digest verification. + * + * Original code by Hannes Gredler (hannes@gredler.at) + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "netdissect-stdinc.h" + +#include <string.h> +#include <stdlib.h> + +#include "netdissect.h" +#include "signature.h" +#include "diag-control.h" + +#ifdef HAVE_LIBCRYPTO +#include <openssl/md5.h> +#endif + +const struct tok signature_check_values[] = { + { SIGNATURE_VALID, "valid"}, + { SIGNATURE_INVALID, "invalid"}, + { CANT_ALLOCATE_COPY, "can't allocate memory"}, + { CANT_CHECK_SIGNATURE, "unchecked"}, + { 0, NULL } +}; + + +#ifdef HAVE_LIBCRYPTO +/* + * Compute a HMAC MD5 sum. + * Taken from rfc2104, Appendix. + */ +DIAG_OFF_DEPRECATION +static void +signature_compute_hmac_md5(const uint8_t *text, int text_len, unsigned char *key, + unsigned int key_len, uint8_t *digest) +{ + MD5_CTX context; + unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[65]; /* outer padding - key XORd with opad */ + unsigned char tk[16]; + int i; + + /* if key is longer than 64 bytes reset it to key=MD5(key) */ + if (key_len > 64) { + + MD5_CTX tctx; + + MD5_Init(&tctx); + MD5_Update(&tctx, key, key_len); + MD5_Final(tk, &tctx); + + key = tk; + key_len = 16; + } + + /* + * the HMAC_MD5 transform looks like: + * + * MD5(K XOR opad, MD5(K XOR ipad, text)) + * + * where K is an n byte key + * ipad is the byte 0x36 repeated 64 times + * opad is the byte 0x5c repeated 64 times + * and text is the data being protected + */ + + /* start out by storing key in pads */ + memset(k_ipad, 0, sizeof(k_ipad)); + memset(k_opad, 0, sizeof(k_opad)); + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + + /* XOR key with ipad and opad values */ + for (i=0; i<64; i++) { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + /* + * perform inner MD5 + */ + MD5_Init(&context); /* init context for 1st pass */ + MD5_Update(&context, k_ipad, 64); /* start with inner pad */ + MD5_Update(&context, text, text_len); /* then text of datagram */ + MD5_Final(digest, &context); /* finish up 1st pass */ + + /* + * perform outer MD5 + */ + MD5_Init(&context); /* init context for 2nd pass */ + MD5_Update(&context, k_opad, 64); /* start with outer pad */ + MD5_Update(&context, digest, 16); /* then results of 1st hash */ + MD5_Final(digest, &context); /* finish up 2nd pass */ +} +DIAG_ON_DEPRECATION + +/* + * Verify a cryptographic signature of the packet. + * Currently only MD5 is supported. + */ +int +signature_verify(netdissect_options *ndo, const u_char *pptr, u_int plen, + const u_char *sig_ptr, void (*clear_rtn)(void *), + const void *clear_arg) +{ + uint8_t *packet_copy, *sig_copy; + uint8_t sig[16]; + unsigned int i; + + if (!ndo->ndo_sigsecret) { + return (CANT_CHECK_SIGNATURE); + } + + /* + * Do we have all the packet data to be checked? + */ + if (!ND_TTEST_LEN(pptr, plen)) { + /* No. */ + return (CANT_CHECK_SIGNATURE); + } + + /* + * Do we have the entire signature to check? + */ + if (!ND_TTEST_LEN(sig_ptr, sizeof(sig))) { + /* No. */ + return (CANT_CHECK_SIGNATURE); + } + if (sig_ptr + sizeof(sig) > pptr + plen) { + /* No. */ + return (CANT_CHECK_SIGNATURE); + } + + /* + * Make a copy of the packet, so we don't overwrite the original. + */ + packet_copy = malloc(plen); + if (packet_copy == NULL) { + return (CANT_ALLOCATE_COPY); + } + + memcpy(packet_copy, pptr, plen); + + /* + * Clear the signature in the copy. + */ + sig_copy = packet_copy + (sig_ptr - pptr); + memset(sig_copy, 0, sizeof(sig)); + + /* + * Clear anything else that needs to be cleared in the copy. + * Our caller is assumed to have vetted the clear_arg pointer. + */ + (*clear_rtn)((void *)(packet_copy + ((const uint8_t *)clear_arg - pptr))); + + /* + * Compute the signature. + */ + signature_compute_hmac_md5(packet_copy, plen, + (unsigned char *)ndo->ndo_sigsecret, + strlen(ndo->ndo_sigsecret), sig); + + /* + * Free the copy. + */ + free(packet_copy); + + /* + * Does the computed signature match the signature in the packet? + */ + if (memcmp(sig_ptr, sig, sizeof(sig)) == 0) { + /* Yes. */ + return (SIGNATURE_VALID); + } else { + /* No - print the computed signature. */ + for (i = 0; i < sizeof(sig); ++i) { + ND_PRINT("%02x", sig[i]); + } + + return (SIGNATURE_INVALID); + } +} +#else +int +signature_verify(netdissect_options *ndo _U_, const u_char *pptr _U_, + u_int plen _U_, const u_char *sig_ptr _U_, + void (*clear_rtn)(void *) _U_, const void *clear_arg _U_) +{ + return (CANT_CHECK_SIGNATURE); +} +#endif |