xref: /dflybsd-src/contrib/tcpdump/signature.c (revision 59c07fbdf8168fa08c76c515186d561b5a92690c)
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