signature.c revision 356341
1/*
2 * Redistribution and use in source and binary forms, with or without
3 * modification, are permitted provided that: (1) source code
4 * distributions retain the above copyright notice and this paragraph
5 * in its entirety, and (2) distributions including binary code include
6 * the above copyright notice and this paragraph in its entirety in
7 * the documentation or other materials provided with the distribution.
8 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
9 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
10 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
11 * FOR A PARTICULAR PURPOSE.
12 *
13 * Functions for signature and digest verification.
14 *
15 * Original code by Hannes Gredler (hannes@gredler.at)
16 */
17
18#ifdef HAVE_CONFIG_H
19#include "config.h"
20#endif
21
22#include <netdissect-stdinc.h>
23
24#include <string.h>
25#include <stdlib.h>
26
27#include "netdissect.h"
28#include "signature.h"
29
30#ifdef HAVE_LIBCRYPTO
31#include <openssl/md5.h>
32#endif
33
34const struct tok signature_check_values[] = {
35    { SIGNATURE_VALID, "valid"},
36    { SIGNATURE_INVALID, "invalid"},
37    { CANT_ALLOCATE_COPY, "can't allocate memory"},
38    { CANT_CHECK_SIGNATURE, "unchecked"},
39    { 0, NULL }
40};
41
42
43#ifdef HAVE_LIBCRYPTO
44/*
45 * Compute a HMAC MD5 sum.
46 * Taken from rfc2104, Appendix.
47 */
48USES_APPLE_DEPRECATED_API
49static void
50signature_compute_hmac_md5(const uint8_t *text, int text_len, unsigned char *key,
51                           unsigned int key_len, uint8_t *digest)
52{
53    MD5_CTX context;
54    unsigned char k_ipad[65];    /* inner padding - key XORd with ipad */
55    unsigned char k_opad[65];    /* outer padding - key XORd with opad */
56    unsigned char tk[16];
57    int i;
58
59    /* if key is longer than 64 bytes reset it to key=MD5(key) */
60    if (key_len > 64) {
61
62        MD5_CTX tctx;
63
64        MD5_Init(&tctx);
65        MD5_Update(&tctx, key, key_len);
66        MD5_Final(tk, &tctx);
67
68        key = tk;
69        key_len = 16;
70    }
71
72    /*
73     * the HMAC_MD5 transform looks like:
74     *
75     * MD5(K XOR opad, MD5(K XOR ipad, text))
76     *
77     * where K is an n byte key
78     * ipad is the byte 0x36 repeated 64 times
79     * opad is the byte 0x5c repeated 64 times
80     * and text is the data being protected
81     */
82
83    /* start out by storing key in pads */
84    memset(k_ipad, 0, sizeof k_ipad);
85    memset(k_opad, 0, sizeof k_opad);
86    memcpy(k_ipad, key, key_len);
87    memcpy(k_opad, key, key_len);
88
89    /* XOR key with ipad and opad values */
90    for (i=0; i<64; i++) {
91        k_ipad[i] ^= 0x36;
92        k_opad[i] ^= 0x5c;
93    }
94
95    /*
96     * perform inner MD5
97     */
98    MD5_Init(&context);                   /* init context for 1st pass */
99    MD5_Update(&context, k_ipad, 64);     /* start with inner pad */
100    MD5_Update(&context, text, text_len); /* then text of datagram */
101    MD5_Final(digest, &context);          /* finish up 1st pass */
102
103    /*
104     * perform outer MD5
105     */
106    MD5_Init(&context);                   /* init context for 2nd pass */
107    MD5_Update(&context, k_opad, 64);     /* start with outer pad */
108    MD5_Update(&context, digest, 16);     /* then results of 1st hash */
109    MD5_Final(digest, &context);          /* finish up 2nd pass */
110}
111USES_APPLE_RST
112
113/*
114 * Verify a cryptographic signature of the packet.
115 * Currently only MD5 is supported.
116 */
117int
118signature_verify(netdissect_options *ndo, const u_char *pptr, u_int plen,
119                 const u_char *sig_ptr, void (*clear_rtn)(void *),
120                 const void *clear_arg)
121{
122    uint8_t *packet_copy, *sig_copy;
123    uint8_t sig[16];
124    unsigned int i;
125
126    if (!ndo->ndo_sigsecret) {
127        return (CANT_CHECK_SIGNATURE);
128    }
129
130    /*
131     * Do we have all the packet data to be checked?
132     */
133    if (!ND_TTEST2(*pptr, plen)) {
134        /* No. */
135        return (CANT_CHECK_SIGNATURE);
136    }
137
138    /*
139     * Do we have the entire signature to check?
140     */
141    if (!ND_TTEST2(*sig_ptr, sizeof(sig))) {
142        /* No. */
143        return (CANT_CHECK_SIGNATURE);
144    }
145    if (sig_ptr + sizeof(sig) > pptr + plen) {
146        /* No. */
147        return (CANT_CHECK_SIGNATURE);
148    }
149
150    /*
151     * Make a copy of the packet, so we don't overwrite the original.
152     */
153    packet_copy = malloc(plen);
154    if (packet_copy == NULL) {
155        return (CANT_ALLOCATE_COPY);
156    }
157
158    memcpy(packet_copy, pptr, plen);
159
160    /*
161     * Clear the signature in the copy.
162     */
163    sig_copy = packet_copy + (sig_ptr - pptr);
164    memset(sig_copy, 0, sizeof(sig));
165
166    /*
167     * Clear anything else that needs to be cleared in the copy.
168     * Our caller is assumed to have vetted the clear_arg pointer.
169     */
170    (*clear_rtn)((void *)(packet_copy + ((const uint8_t *)clear_arg - pptr)));
171
172    /*
173     * Compute the signature.
174     */
175    signature_compute_hmac_md5(packet_copy, plen,
176                               (unsigned char *)ndo->ndo_sigsecret,
177                               strlen(ndo->ndo_sigsecret), sig);
178
179    /*
180     * Free the copy.
181     */
182    free(packet_copy);
183
184    /*
185     * Does the computed signature match the signature in the packet?
186     */
187    if (memcmp(sig_ptr, sig, sizeof(sig)) == 0) {
188        /* Yes. */
189        return (SIGNATURE_VALID);
190    } else {
191        /* No - print the computed signature. */
192        for (i = 0; i < sizeof(sig); ++i) {
193            ND_PRINT((ndo, "%02x", sig[i]));
194        }
195
196        return (SIGNATURE_INVALID);
197    }
198}
199#else
200int
201signature_verify(netdissect_options *ndo _U_, const u_char *pptr _U_,
202                 u_int plen _U_, const u_char *sig_ptr _U_,
203                 void (*clear_rtn)(void *) _U_, const void *clear_arg _U_)
204{
205    return (CANT_CHECK_SIGNATURE);
206}
207#endif
208
209/*
210 * Local Variables:
211 * c-style: whitesmith
212 * c-basic-offset: 4
213 * End:
214 */
215