~ubuntu-branches/ubuntu/natty/freeradius/natty-updates

« back to all changes in this revision

Viewing changes to src/modules/rlm_otp/otp_radstate.c

  • Committer: Bazaar Package Importer
  • Author(s): Paul Hampson
  • Date: 2006-01-15 13:34:13 UTC
  • mto: (3.1.3 dapper) (4.1.3 sid) (1.1.14 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060115133413-zo1dslttvdoalqym
Tags: upstream-1.1.0
ImportĀ upstreamĀ versionĀ 1.1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * otp_radstate.c
 
3
 * $Id: otp_radstate.c,v 1.4.2.1 2005/12/08 01:30:51 fcusack Exp $
 
4
 *
 
5
 *   This program is free software; you can redistribute it and/or modify
 
6
 *   it under the terms of the GNU General Public License as published by
 
7
 *   the Free Software Foundation; either version 2 of the License, or
 
8
 *   (at your option) any later version.
 
9
 *
 
10
 *   This program is distributed in the hope that it will be useful,
 
11
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *   GNU General Public License for more details.
 
14
 *
 
15
 *   You should have received a copy of the GNU General Public License
 
16
 *   along with this program; if not, write to the Free Software
 
17
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
18
 *
 
19
 * Copyright 2001,2002  Google, Inc.
 
20
 * Copyright 2005 TRI-D Systems, Inc.
 
21
 */
 
22
 
 
23
#ifdef FREERADIUS
 
24
#define _LRAD_MD4_H
 
25
#define _LRAD_SHA1_H
 
26
#endif
 
27
#include "otp.h"
 
28
 
 
29
#include <string.h>
 
30
#include <openssl/des.h> /* des_cblock */
 
31
#include <openssl/md5.h>
 
32
#include <openssl/hmac.h>
 
33
 
 
34
 
 
35
static const char rcsid[] = "$Id: otp_radstate.c,v 1.4.2.1 2005/12/08 01:30:51 fcusack Exp $";
 
36
 
 
37
 
 
38
/*
 
39
 * Generate the State attribute, suitable for passing to pairmake().
 
40
 * challenge must be a null terminated string, and be sized at least
 
41
 * as large as indicated in the function definition.
 
42
 *
 
43
 * Returns 0 on success, non-zero otherwise.  For successful returns,
 
44
 * ascii_state (suitable for passing to pairmake()) and raw_state, if
 
45
 * non-NULL, will be pointing to allocated storage.  The caller is
 
46
 * responsible for freeing the storage.  raw_state will not be
 
47
 * null-terminated, the caller should know the expected size (any
 
48
 * variance in size is solely due to the length of the challenge arg).
 
49
 *
 
50
 * In the simplest implementation, we would just use the challenge as state.
 
51
 * Unfortunately, the RADIUS secret protects only the User-Password
 
52
 * attribute; an attacker that can remove packets from the wire and insert
 
53
 * new ones can simply insert a replayed state without having to know
 
54
 * the secret.  If not for an attacker that can remove packets from the
 
55
 * network, I believe trivial state to be secure.
 
56
 *
 
57
 * So, we have to make up for that deficiency by signing our state with
 
58
 * data unique to this specific request.  A NAS would use the Request
 
59
 * Authenticator, but we don't know what that will be when the State is
 
60
 * returned to us, so we'll use the time.  So our replay prevention
 
61
 * is limited to a time interval (inst->chal_delay).  We could keep
 
62
 * track of all challenges issued over that time interval for
 
63
 * better protection.
 
64
 *
 
65
 * Our state, then, is
 
66
 *   (challenge + flags + time + hmac(challenge + resync + time, key)),
 
67
 * where '+' denotes concatentation, 'challenge' is ...
 
68
 * the challenge, 'flags' is a 32-bit value that can be used to record
 
69
 * additional info, 'time' is the 32-bit time (LSB if time_t is 64 bits)
 
70
 * in network byte order, and 'key' is a random key, generated in
 
71
 * otp_instantiate().  This means that only the server which generates a
 
72
 * challenge can verify it; this should be OK if your NAS's load balance
 
73
 * across RADIUS servers using a "first available" algorithm.  If your
 
74
 * NAS's round-robin (ugh), you could use the RADIUS secret instead, but
 
75
 * read RFC 2104 first, and make very sure you really want to do this.
 
76
 *
 
77
 * Note that putting the time in network byte order is pointless, since
 
78
 * only "this" server will be able to verify the hmac, due to the unique
 
79
 * key.  But I've left it in there for future consideration of sync'd
 
80
 * keys across servers (eg, using the RADIUS secret, which is probably
 
81
 * not a good idea; or reading from a file, which might be OK.)
 
82
 */
 
83
int
 
84
otp_gen_state(char **ascii_state, unsigned char **raw_state,
 
85
              const unsigned char challenge[OTP_MAX_CHALLENGE_LEN],
 
86
              size_t clen,
 
87
              int32_t flags, int32_t when, const unsigned char key[16])
 
88
{
 
89
  HMAC_CTX hmac_ctx;
 
90
  unsigned char hmac[MD5_DIGEST_LENGTH];
 
91
  char *p;
 
92
 
 
93
  /*
 
94
   * Generate the hmac.  We already have a dependency on openssl for
 
95
   * DES, so we'll use it's hmac functionality also -- saves us from
 
96
   * having to collect the data to be signed into one contiguous piece.
 
97
   */
 
98
  HMAC_Init(&hmac_ctx, key, sizeof(key), EVP_md5());
 
99
  HMAC_Update(&hmac_ctx, challenge, clen);
 
100
  HMAC_Update(&hmac_ctx, (unsigned char *) &flags, 4);
 
101
  HMAC_Update(&hmac_ctx, (unsigned char *) &when, 4);
 
102
  HMAC_Final(&hmac_ctx, hmac, NULL);
 
103
  HMAC_cleanup(&hmac_ctx);
 
104
 
 
105
  /* Fill in raw_state if requested. */
 
106
  if (raw_state) {
 
107
    *raw_state = rad_malloc(clen + 8 + sizeof(hmac));
 
108
    p = *raw_state;
 
109
    (void) memcpy(p, challenge, clen);
 
110
    p += clen;
 
111
    (void) memcpy(p, &flags, 4);
 
112
    p += 4;
 
113
    (void) memcpy(p, &when, 4);
 
114
    p += 4;
 
115
    (void) memcpy(p, hmac, sizeof(hmac));
 
116
  }
 
117
 
 
118
  /*
 
119
   * Fill in ascii_state if requested.  (pairmake() forces us to to this.)
 
120
   * "0x" is required for pairmake().  Note that each octet expands into
 
121
   * 2 hex digits in ASCII (0xAA -> 0x4141).
 
122
   */
 
123
  if (ascii_state) {
 
124
    *ascii_state = rad_malloc(2 +                       /* "0x"      */
 
125
                              clen * 2 +                /* challenge */
 
126
                              8 +                       /* flags     */
 
127
                              8 +                       /* time      */
 
128
                              sizeof(hmac) * 2 +        /* hmac      */
 
129
                              1);                       /* '\0'      */
 
130
    (void) sprintf(*ascii_state, "0x");
 
131
    p = *ascii_state + 2;
 
132
 
 
133
    /* Add the challenge. */
 
134
    (void) otp_keyblock2keystring(p, challenge, clen, otp_hex_conversion);
 
135
    p += clen * 2;
 
136
 
 
137
    /* Add the flags and time. */
 
138
    (void) otp_keyblock2keystring(p, (unsigned char *) &flags, 4,
 
139
                                  otp_hex_conversion);
 
140
    p += 8;
 
141
    (void) otp_keyblock2keystring(p, (unsigned char *) &when, 4,
 
142
                                  otp_hex_conversion);
 
143
    p += 8;
 
144
 
 
145
    /* Add the hmac. */
 
146
    (void) otp_keyblock2keystring(p, hmac, 16, otp_hex_conversion);
 
147
  }
 
148
 
 
149
  return 0;
 
150
}