127bfbee1SPeter Avalos /*
227bfbee1SPeter Avalos * Redistribution and use in source and binary forms, with or without
327bfbee1SPeter Avalos * modification, are permitted provided that: (1) source code
427bfbee1SPeter Avalos * distributions retain the above copyright notice and this paragraph
527bfbee1SPeter Avalos * in its entirety, and (2) distributions including binary code include
627bfbee1SPeter Avalos * the above copyright notice and this paragraph in its entirety in
727bfbee1SPeter Avalos * the documentation or other materials provided with the distribution.
827bfbee1SPeter Avalos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
927bfbee1SPeter Avalos * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
1027bfbee1SPeter Avalos * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
1127bfbee1SPeter Avalos * FOR A PARTICULAR PURPOSE.
1227bfbee1SPeter Avalos *
1327bfbee1SPeter Avalos * Functions for signature and digest verification.
1427bfbee1SPeter Avalos *
15411677aeSAaron LI * Original code by Hannes Gredler (hannes@gredler.at)
1627bfbee1SPeter Avalos */
1727bfbee1SPeter Avalos
1827bfbee1SPeter Avalos #ifdef HAVE_CONFIG_H
19*ed775ee7SAntonio Huete Jimenez #include <config.h>
2027bfbee1SPeter Avalos #endif
2127bfbee1SPeter Avalos
22*ed775ee7SAntonio Huete Jimenez #include "netdissect-stdinc.h"
2327bfbee1SPeter Avalos
2427bfbee1SPeter Avalos #include <string.h>
25411677aeSAaron LI #include <stdlib.h>
2627bfbee1SPeter Avalos
27411677aeSAaron LI #include "netdissect.h"
2827bfbee1SPeter Avalos #include "signature.h"
2927bfbee1SPeter Avalos
3027bfbee1SPeter Avalos #ifdef HAVE_LIBCRYPTO
3127bfbee1SPeter Avalos #include <openssl/md5.h>
3227bfbee1SPeter Avalos #endif
3327bfbee1SPeter Avalos
3427bfbee1SPeter Avalos const struct tok signature_check_values[] = {
3527bfbee1SPeter Avalos { SIGNATURE_VALID, "valid"},
3627bfbee1SPeter Avalos { SIGNATURE_INVALID, "invalid"},
37411677aeSAaron LI { CANT_ALLOCATE_COPY, "can't allocate memory"},
3827bfbee1SPeter Avalos { CANT_CHECK_SIGNATURE, "unchecked"},
3927bfbee1SPeter Avalos { 0, NULL }
4027bfbee1SPeter Avalos };
4127bfbee1SPeter Avalos
4227bfbee1SPeter Avalos
4327bfbee1SPeter Avalos #ifdef HAVE_LIBCRYPTO
4427bfbee1SPeter Avalos /*
4527bfbee1SPeter Avalos * Compute a HMAC MD5 sum.
4627bfbee1SPeter Avalos * Taken from rfc2104, Appendix.
4727bfbee1SPeter Avalos */
48411677aeSAaron LI USES_APPLE_DEPRECATED_API
4927bfbee1SPeter Avalos static void
signature_compute_hmac_md5(const uint8_t * text,int text_len,unsigned char * key,unsigned int key_len,uint8_t * digest)50411677aeSAaron LI signature_compute_hmac_md5(const uint8_t *text, int text_len, unsigned char *key,
51411677aeSAaron LI unsigned int key_len, uint8_t *digest)
5227bfbee1SPeter Avalos {
5327bfbee1SPeter Avalos MD5_CTX context;
5427bfbee1SPeter Avalos unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */
5527bfbee1SPeter Avalos unsigned char k_opad[65]; /* outer padding - key XORd with opad */
5627bfbee1SPeter Avalos unsigned char tk[16];
5727bfbee1SPeter Avalos int i;
5827bfbee1SPeter Avalos
5927bfbee1SPeter Avalos /* if key is longer than 64 bytes reset it to key=MD5(key) */
6027bfbee1SPeter Avalos if (key_len > 64) {
6127bfbee1SPeter Avalos
6227bfbee1SPeter Avalos MD5_CTX tctx;
6327bfbee1SPeter Avalos
6427bfbee1SPeter Avalos MD5_Init(&tctx);
6527bfbee1SPeter Avalos MD5_Update(&tctx, key, key_len);
6627bfbee1SPeter Avalos MD5_Final(tk, &tctx);
6727bfbee1SPeter Avalos
6827bfbee1SPeter Avalos key = tk;
6927bfbee1SPeter Avalos key_len = 16;
7027bfbee1SPeter Avalos }
7127bfbee1SPeter Avalos
7227bfbee1SPeter Avalos /*
7327bfbee1SPeter Avalos * the HMAC_MD5 transform looks like:
7427bfbee1SPeter Avalos *
7527bfbee1SPeter Avalos * MD5(K XOR opad, MD5(K XOR ipad, text))
7627bfbee1SPeter Avalos *
7727bfbee1SPeter Avalos * where K is an n byte key
7827bfbee1SPeter Avalos * ipad is the byte 0x36 repeated 64 times
7927bfbee1SPeter Avalos * opad is the byte 0x5c repeated 64 times
8027bfbee1SPeter Avalos * and text is the data being protected
8127bfbee1SPeter Avalos */
8227bfbee1SPeter Avalos
8327bfbee1SPeter Avalos /* start out by storing key in pads */
84*ed775ee7SAntonio Huete Jimenez memset(k_ipad, 0, sizeof(k_ipad));
85*ed775ee7SAntonio Huete Jimenez memset(k_opad, 0, sizeof(k_opad));
8627bfbee1SPeter Avalos memcpy(k_ipad, key, key_len);
8727bfbee1SPeter Avalos memcpy(k_opad, key, key_len);
8827bfbee1SPeter Avalos
8927bfbee1SPeter Avalos /* XOR key with ipad and opad values */
9027bfbee1SPeter Avalos for (i=0; i<64; i++) {
9127bfbee1SPeter Avalos k_ipad[i] ^= 0x36;
9227bfbee1SPeter Avalos k_opad[i] ^= 0x5c;
9327bfbee1SPeter Avalos }
9427bfbee1SPeter Avalos
9527bfbee1SPeter Avalos /*
9627bfbee1SPeter Avalos * perform inner MD5
9727bfbee1SPeter Avalos */
9827bfbee1SPeter Avalos MD5_Init(&context); /* init context for 1st pass */
9927bfbee1SPeter Avalos MD5_Update(&context, k_ipad, 64); /* start with inner pad */
10027bfbee1SPeter Avalos MD5_Update(&context, text, text_len); /* then text of datagram */
10127bfbee1SPeter Avalos MD5_Final(digest, &context); /* finish up 1st pass */
10227bfbee1SPeter Avalos
10327bfbee1SPeter Avalos /*
10427bfbee1SPeter Avalos * perform outer MD5
10527bfbee1SPeter Avalos */
10627bfbee1SPeter Avalos MD5_Init(&context); /* init context for 2nd pass */
10727bfbee1SPeter Avalos MD5_Update(&context, k_opad, 64); /* start with outer pad */
10827bfbee1SPeter Avalos MD5_Update(&context, digest, 16); /* then results of 1st hash */
10927bfbee1SPeter Avalos MD5_Final(digest, &context); /* finish up 2nd pass */
11027bfbee1SPeter Avalos }
111411677aeSAaron LI USES_APPLE_RST
11227bfbee1SPeter Avalos
11327bfbee1SPeter Avalos /*
11427bfbee1SPeter Avalos * Verify a cryptographic signature of the packet.
11527bfbee1SPeter Avalos * Currently only MD5 is supported.
11627bfbee1SPeter Avalos */
11727bfbee1SPeter Avalos 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)118411677aeSAaron LI signature_verify(netdissect_options *ndo, const u_char *pptr, u_int plen,
119411677aeSAaron LI const u_char *sig_ptr, void (*clear_rtn)(void *),
120411677aeSAaron LI const void *clear_arg)
12127bfbee1SPeter Avalos {
122411677aeSAaron LI uint8_t *packet_copy, *sig_copy;
123411677aeSAaron LI uint8_t sig[16];
12427bfbee1SPeter Avalos unsigned int i;
12527bfbee1SPeter Avalos
126411677aeSAaron LI if (!ndo->ndo_sigsecret) {
12727bfbee1SPeter Avalos return (CANT_CHECK_SIGNATURE);
12827bfbee1SPeter Avalos }
12927bfbee1SPeter Avalos
130411677aeSAaron LI /*
131411677aeSAaron LI * Do we have all the packet data to be checked?
132411677aeSAaron LI */
133*ed775ee7SAntonio Huete Jimenez if (!ND_TTEST_LEN(pptr, plen)) {
134411677aeSAaron LI /* No. */
135411677aeSAaron LI return (CANT_CHECK_SIGNATURE);
136411677aeSAaron LI }
13727bfbee1SPeter Avalos
138411677aeSAaron LI /*
139411677aeSAaron LI * Do we have the entire signature to check?
140411677aeSAaron LI */
141*ed775ee7SAntonio Huete Jimenez if (!ND_TTEST_LEN(sig_ptr, sizeof(sig))) {
142411677aeSAaron LI /* No. */
143411677aeSAaron LI return (CANT_CHECK_SIGNATURE);
144411677aeSAaron LI }
145411677aeSAaron LI if (sig_ptr + sizeof(sig) > pptr + plen) {
146411677aeSAaron LI /* No. */
147411677aeSAaron LI return (CANT_CHECK_SIGNATURE);
148411677aeSAaron LI }
149411677aeSAaron LI
150411677aeSAaron LI /*
151411677aeSAaron LI * Make a copy of the packet, so we don't overwrite the original.
152411677aeSAaron LI */
153411677aeSAaron LI packet_copy = malloc(plen);
154411677aeSAaron LI if (packet_copy == NULL) {
155411677aeSAaron LI return (CANT_ALLOCATE_COPY);
156411677aeSAaron LI }
157411677aeSAaron LI
158411677aeSAaron LI memcpy(packet_copy, pptr, plen);
159411677aeSAaron LI
160411677aeSAaron LI /*
161411677aeSAaron LI * Clear the signature in the copy.
162411677aeSAaron LI */
163411677aeSAaron LI sig_copy = packet_copy + (sig_ptr - pptr);
164411677aeSAaron LI memset(sig_copy, 0, sizeof(sig));
165411677aeSAaron LI
166411677aeSAaron LI /*
167411677aeSAaron LI * Clear anything else that needs to be cleared in the copy.
168411677aeSAaron LI * Our caller is assumed to have vetted the clear_arg pointer.
169411677aeSAaron LI */
170411677aeSAaron LI (*clear_rtn)((void *)(packet_copy + ((const uint8_t *)clear_arg - pptr)));
171411677aeSAaron LI
172411677aeSAaron LI /*
173411677aeSAaron LI * Compute the signature.
174411677aeSAaron LI */
175411677aeSAaron LI signature_compute_hmac_md5(packet_copy, plen,
176411677aeSAaron LI (unsigned char *)ndo->ndo_sigsecret,
177411677aeSAaron LI strlen(ndo->ndo_sigsecret), sig);
178411677aeSAaron LI
179411677aeSAaron LI /*
180411677aeSAaron LI * Free the copy.
181411677aeSAaron LI */
182411677aeSAaron LI free(packet_copy);
183411677aeSAaron LI
184411677aeSAaron LI /*
185411677aeSAaron LI * Does the computed signature match the signature in the packet?
186411677aeSAaron LI */
187411677aeSAaron LI if (memcmp(sig_ptr, sig, sizeof(sig)) == 0) {
188411677aeSAaron LI /* Yes. */
18927bfbee1SPeter Avalos return (SIGNATURE_VALID);
19027bfbee1SPeter Avalos } else {
191411677aeSAaron LI /* No - print the computed signature. */
19227bfbee1SPeter Avalos for (i = 0; i < sizeof(sig); ++i) {
193*ed775ee7SAntonio Huete Jimenez ND_PRINT("%02x", sig[i]);
19427bfbee1SPeter Avalos }
19527bfbee1SPeter Avalos
19627bfbee1SPeter Avalos return (SIGNATURE_INVALID);
19727bfbee1SPeter Avalos }
19827bfbee1SPeter Avalos }
199411677aeSAaron LI #else
200411677aeSAaron LI 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_)201411677aeSAaron LI signature_verify(netdissect_options *ndo _U_, const u_char *pptr _U_,
202411677aeSAaron LI u_int plen _U_, const u_char *sig_ptr _U_,
203411677aeSAaron LI void (*clear_rtn)(void *) _U_, const void *clear_arg _U_)
204411677aeSAaron LI {
205411677aeSAaron LI return (CANT_CHECK_SIGNATURE);
206411677aeSAaron LI }
20727bfbee1SPeter Avalos #endif
208