document rlm_otp fd leak fix
[freeradius.git] / src / modules / rlm_otp / otp_radstate.c
1 /*
2  * $Id$
3  *
4  *   This program is free software; you can redistribute it and/or modify
5  *   it under the terms of the GNU General Public License as published by
6  *   the Free Software Foundation; either version 2 of the License, or
7  *   (at your option) any later version.
8  *
9  *   This program is distributed in the hope that it will be useful,
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *   GNU General Public License for more details.
13  *
14  *   You should have received a copy of the GNU General Public License
15  *   along with this program; if not, write to the Free Software
16  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  *
18  * Copyright 2001,2002  Google, Inc.
19  * Copyright 2005,2006 TRI-D Systems, Inc.
20  */
21
22 #include "ident.h"
23 RCSID("$Id$")
24
25 /* avoid inclusion of these FR headers which conflict w/ OpenSSL */
26 #define _LRAD_MD4_H
27 #define _LRAD_SHA1_H
28
29 #include "extern.h"
30
31 #include <string.h>
32 #include <openssl/des.h> /* des_cblock */
33 #include <openssl/md5.h>
34 #include <openssl/hmac.h>
35
36 /*
37  * Generate the State attribute, suitable for passing to pairmake().
38  * 'challenge' must be a null terminated string, and be sized at least
39  * as large as indicated in the function definition.
40  *
41  * Returns 0 on success, non-zero otherwise.  For successful returns,
42  * 'rad_state' (suitable for passing to pairmake()) and 'raw_state',
43  * if non-NULL, will be filled in.
44  *
45  * In the simplest implementation, we would just use the challenge as state.
46  * Unfortunately, the RADIUS secret protects only the User-Password
47  * attribute; an attacker that can remove packets from the wire and insert
48  * new ones can simply insert a replayed state without having to know
49  * the secret.  If not for an attacker that can remove packets from the
50  * network, I believe trivial state to be secure.
51  *
52  * So, we have to make up for that deficiency by signing our state with
53  * data unique to this specific request.  A NAS would use the Request
54  * Authenticator, but we don't know what that will be when the State is
55  * returned to us, so we'll use the time.  So our replay prevention
56  * is limited to a time interval (inst->challenge_delay).  We could keep
57  * track of all challenges issued over that time interval for
58  * better protection.
59  *
60  * Our state, then, is
61  *   (challenge + flags + time + hmac(challenge + resync + time, key)),
62  * where '+' denotes concatentation, 'challenge' is ... the challenge,
63  * 'flags' is a 32-bit value that can be used to record additional info,
64  * 'time' is the 32-bit time (LSB if time_t is 64 bits), and 'key' is a
65  * random key, generated in otp_instantiate().  'flags' and 'time' are
66  * in network byte order.
67  *
68  * As the signing key is unique to each server, only the server which
69  * generates a challenge can verify it; this should be OK if your NAS's
70  * load balance across RADIUS servers using a "first available" algorithm.
71  * If your NAS's round-robin and don't "stick" to the same server if they
72  * see a State attribute (ugh), you could use the RADIUS secret instead,
73  * but read RFC 2104 first, and make very sure you really want to do this.
74  *
75  * Since only the "same server" can verify State, 'flags' and 'time' doesn't
76  * really need to be in network byte order, but we do it anyway.
77  *
78  * The State attribute is an octet string, however some versions of Cisco
79  * IOS and Catalyst OS (at least IOS 12.1(26)E4 and CatOS 7.6.12) treat it
80  * as an ASCII string (they only return data up to the first NUL byte).
81  * So we must handle state as an ASCII string (0x00 -> 0x3030).
82  */
83 int
84 otp_gen_state(char rad_state[OTP_MAX_RADSTATE_LEN],
85               unsigned char raw_state[OTP_MAX_RADSTATE_LEN],
86               const unsigned char challenge[OTP_MAX_CHALLENGE_LEN],
87               size_t clen,
88               int32_t flags, int32_t when, const unsigned char key[16])
89 {
90   HMAC_CTX hmac_ctx;
91   unsigned char hmac[MD5_DIGEST_LENGTH];
92   char *p;
93   char state[OTP_MAX_RADSTATE_LEN];
94
95   /*
96    * Generate the hmac.  We already have a dependency on openssl for
97    * DES, so we'll use it's hmac functionality also -- saves us from
98    * having to collect the data to be signed into one contiguous piece.
99    */
100   HMAC_Init(&hmac_ctx, key, sizeof(key), EVP_md5());
101   HMAC_Update(&hmac_ctx, challenge, clen);
102   HMAC_Update(&hmac_ctx, (unsigned char *) &flags, 4);
103   HMAC_Update(&hmac_ctx, (unsigned char *) &when, 4);
104   HMAC_Final(&hmac_ctx, hmac, NULL);
105   HMAC_cleanup(&hmac_ctx);
106
107   /*
108    * Generate the state.  Note that it is in ASCII.  The challenge
109    * value doesn't have to be ASCII encoded, as it is already
110    * ASCII, but we do it anyway, for consistency.
111    */
112 #if 0
113   /*
114    * We used to malloc() state (here and in callers).  We leave this
115    * here to show how OTP_MAX_RADSTATE_LEN is composed.  Note that
116    * it has to be double all the values below to account for an
117    * extra ASCII expansion (see Cisco notes, below).
118    */
119   state = rad_malloc(clen * 2 +                 /* challenge */
120                      8 +                        /* flags     */
121                      8 +                        /* time      */
122                      sizeof(hmac) * 2 +         /* hmac      */
123                      1);                        /* '\0'      */
124 #endif
125   p = state;
126   /* Add the challenge. */
127   otp_x2a(challenge, clen, p);
128   p += clen * 2;
129   /* Add the flags and time. */
130   otp_x2a((unsigned char *) &flags, 4, p);
131   p += 8;
132   otp_x2a((unsigned char *) &when, 4, p);
133   p += 8;
134   /* Add the hmac. */
135   otp_x2a(hmac, 16, p);
136
137   /*
138    * Expand state (already ASCII) into ASCII again (0x31 -> 0x3331).
139    * pairmake() forces us to do this (it will reduce it back to binary),
140    * and to include a leading "0x".
141    */
142   if (rad_state) {
143     (void) sprintf(rad_state, "0x");
144     p = rad_state + 2;
145     otp_x2a(state, strlen(state), p);
146   }
147
148   if (raw_state)
149     (void) memcpy(raw_state, state, sizeof(state));
150
151   return 0;
152 }