All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
otp_radstate.c
Go to the documentation of this file.
1 /*
2  * $Id: a70393918fd393c990cf05fe1c8933e288b966c3 $
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 RCSID("$Id: a70393918fd393c990cf05fe1c8933e288b966c3 $")
23 USES_APPLE_DEPRECATED_API /* OpenSSL API has been deprecated by Apple */
24 
25 /* avoid inclusion of these FR headers which conflict w/ OpenSSL */
26 #define _FR_MD4_H
27 #define _FR_SHA1_H
28 
29 #include "extern.h"
30 
31 #include <string.h>
32 
33 #include <openssl/des.h> /* des_cblock */
34 #include <openssl/md5.h>
35 #include <openssl/hmac.h>
36 
37 /*
38  * Generate the State attribute, suitable for passing to fr_pair_make().
39  * 'challenge' must be a null terminated string, and be sized at least
40  * as large as indicated in the function definition.
41  *
42  * Returns 0 on success, non-zero otherwise. For successful returns,
43  * 'rad_state' (suitable for passing to fr_pair_make()) and 'raw_state',
44  * if non-NULL, will be filled in.
45  *
46  * In the simplest implementation, we would just use the challenge as state.
47  * Unfortunately, the RADIUS secret protects only the User-Password
48  * attribute; an attacker that can remove packets from the wire and insert
49  * new ones can simply insert a replayed state without having to know
50  * the secret. If not for an attacker that can remove packets from the
51  * network, I believe trivial state to be secure.
52  *
53  * So, we have to make up for that deficiency by signing our state with
54  * data unique to this specific request. A NAS would use the Request
55  * Authenticator, but we don't know what that will be when the State is
56  * returned to us, so we'll use the time. So our replay prevention
57  * is limited to a time interval (inst->challenge_delay). We could keep
58  * track of all challenges issued over that time interval for
59  * better protection.
60  *
61  * Our state, then, is
62  * (challenge + flags + time + hmac(challenge + resync + time, key)),
63  * where '+' denotes concatentation, 'challenge' is ... the challenge,
64  * 'flags' is a 32-bit value that can be used to record additional info,
65  * 'time' is the 32-bit time (LSB if time_t is 64 bits), and 'key' is a
66  * random key, generated in mod_instantiate(). 'flags' and 'time' are
67  * in network byte order.
68  *
69  * As the signing key is unique to each server, only the server which
70  * generates a challenge can verify it; this should be OK if your NAS's
71  * load balance across RADIUS servers using a "first available" algorithm.
72  * If your NAS's round-robin and don't "stick" to the same server if they
73  * see a State attribute (ugh), you could use the RADIUS secret instead,
74  * but read RFC 2104 first, and make very sure you really want to do this.
75  *
76  * Since only the "same server" can verify State, 'flags' and 'time' doesn't
77  * really need to be in network byte order, but we do it anyway.
78  *
79  * The State attribute is an octet string, however some versions of Cisco
80  * IOS and Catalyst OS (at least IOS 12.1(26)E4 and CatOS 7.6.12) treat it
81  * as an ASCII string (they only return data up to the first NUL byte).
82  * So we must handle state as an ASCII string (0x00 -> 0x3030).
83  */
84 
85 /*
86  * OTP_MAX_RADSTATE_LEN is composed of:
87  *
88  * clen * 2 + challenge
89  * 8 + flags
90  * 8 + time
91  * sizeof(hmac) * 2 + hmac
92  * 1 \0'
93  */
94 
95 /** Generate an OTP state value
96  *
97  * Generates an OTP state value (an string of ASCII hexits in an opaque binary
98  * string).
99  *
100  * @param[out] state buffer in which to write the generated state value.
101  * @param[in] challenge The challenge value.
102  * @param[in] clen The length of the challenge data.
103  * @param[in] flags to remember.
104  * @param[in] when the challenge was originally generated.
105  * @param[in] key HMAC key.
106  * @return the amount of data written into the state buffer.
107  */
109  char const challenge[OTP_MAX_CHALLENGE_LEN],
110  size_t clen,
111  int32_t flags, int32_t when, uint8_t const key[16])
112 {
113  HMAC_CTX hmac_ctx;
114  uint8_t hmac[MD5_DIGEST_LENGTH];
115  char *p;
116 
117  /*
118  * Generate the hmac. We already have a dependency on openssl for
119  * DES, so we'll use it's hmac functionality also -- saves us from
120  * having to collect the data to be signed into one
121  * contiguous piece.
122  */
123  HMAC_Init(&hmac_ctx, key, sizeof(key[0]) * 16, EVP_md5());
124  HMAC_Update(&hmac_ctx, (uint8_t const *) challenge, clen);
125  HMAC_Update(&hmac_ctx, (uint8_t *) &flags, 4);
126  HMAC_Update(&hmac_ctx, (uint8_t *) &when, 4);
127  HMAC_Final(&hmac_ctx, hmac, NULL);
128  HMAC_cleanup(&hmac_ctx);
129 
130  /*
131  * Generate the state.
132  */
133  p = state;
134 
135  /*
136  * Add the challenge (which is already ASCII encoded)
137  */
138  p += fr_bin2hex(p, (uint8_t const *) challenge, clen);
139 
140  /* Add the flags and time. */
141  p += fr_bin2hex(p, (uint8_t *) &flags, 4);
142  p += fr_bin2hex(p, (uint8_t *) &when, 4);
143 
144  /* Add the hmac. */
145  p += fr_bin2hex(p, hmac, 16);
146 
147  return p - state;
148 }
#define OTP_MAX_RADSTATE_LEN
Definition: extern.h:70
size_t otp_gen_state(char state[OTP_MAX_RADSTATE_LEN], char const challenge[OTP_MAX_CHALLENGE_LEN], size_t clen, int32_t flags, int32_t when, uint8_t const key[16])
Generate an OTP state value.
Definition: otp_radstate.c:108
unsigned int state
Definition: proto_bfd.c:200
#define OTP_MAX_CHALLENGE_LEN
Definition: otp.h:35
void void MD5_DIGEST_LENGTH
Definition: md5.h:65
#define RCSID(id)
Definition: build.h:135
size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen)
Convert binary data to a hex string.
Definition: misc.c:254
#define USES_APPLE_DEPRECATED_API
Definition: build.h:122