All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
decrypt.c
Go to the documentation of this file.
1 /**
2  * $Id: ed50c0fc5d0ca2d928b0d6262a68be5da4a02d2f $
3  * @file decrypt.c
4  * @brief Authentication for yubikey OTP tokens using the yubikey library.
5  *
6  * @author Arran Cudbard-Bell <a.cudbardb@networkradius.com>
7  * @copyright 2013 The FreeRADIUS server project
8  * @copyright 2013 Network RADIUS <info@networkradius.com>
9  */
10 #include "rlm_yubikey.h"
11 
12 #ifdef HAVE_YUBIKEY
13 /** Decrypt a Yubikey OTP AES block
14  *
15  * @param inst Module configuration.
16  * @param request The current request.
17  * @param passcode string to decrypt.
18  * @return one of the RLM_RCODE_* constants.
19  */
20 rlm_rcode_t rlm_yubikey_decrypt(rlm_yubikey_t *inst, REQUEST *request, char const *passcode)
21 {
22  uint32_t counter, timestamp;
23  yubikey_token_st token;
24 
25  fr_dict_attr_t const *da;
26 
27  char private_id[(YUBIKEY_UID_SIZE * 2) + 1];
28  VALUE_PAIR *key, *vp;
29 
30  da = fr_dict_attr_by_name(NULL, "Yubikey-Key");
31  if (!da) {
32  REDEBUG("Dictionary missing entry for 'Yubikey-Key'");
33  return RLM_MODULE_FAIL;
34  }
35 
36  key = fr_pair_find_by_da(request->config, da, TAG_ANY);
37  if (!key) {
38  REDEBUG("Yubikey-Key attribute not found in control list, can't decrypt OTP data");
39  return RLM_MODULE_INVALID;
40  }
41 
42  if (key->vp_length != YUBIKEY_KEY_SIZE) {
43  REDEBUG("Yubikey-Key length incorrect, expected %u got %zu", YUBIKEY_KEY_SIZE, key->vp_length);
44  return RLM_MODULE_INVALID;
45  }
46 
47  yubikey_parse((uint8_t const *) passcode + inst->id_len, key->vp_octets, &token);
48 
49  /*
50  * Apparently this just uses byte offsets...
51  */
52  if (!yubikey_crc_ok_p((uint8_t *) &token)) {
53  REDEBUG("Decrypting OTP token data failed, rejecting");
54  return RLM_MODULE_REJECT;
55  }
56 
57  RDEBUG("Token data decrypted successfully");
58 
59  counter = (yubikey_counter(token.ctr) << 8) | token.use;
60  timestamp = (token.tstph << 16) | token.tstpl;
61 
62  if (RDEBUG_ENABLED2) {
63  (void) fr_bin2hex((char *) &private_id, (uint8_t*) &token.uid, YUBIKEY_UID_SIZE);
64  RDEBUG2("Private ID : 0x%s", private_id);
65  RDEBUG2("Session counter : %u", counter);
66 
67  RDEBUG2("Token timestamp : %u", timestamp);
68 
69  RDEBUG2("Random data : %u", token.rnd);
70  RDEBUG2("CRC data : 0x%x", token.crc);
71  }
72 
73  /*
74  * Private ID used for validation purposes
75  */
76  vp = fr_pair_make(request, &request->packet->vps, "Yubikey-Private-ID", NULL, T_OP_SET);
77  if (!vp) {
78  REDEBUG("Failed creating Yubikey-Private-ID");
79 
80  return RLM_MODULE_FAIL;
81  }
82  fr_pair_value_memcpy(vp, token.uid, YUBIKEY_UID_SIZE);
83 
84  /*
85  * Token timestamp
86  */
87  vp = fr_pair_make(request, &request->packet->vps, "Yubikey-Timestamp", NULL, T_OP_SET);
88  if (!vp) {
89  REDEBUG("Failed creating Yubikey-Timestamp");
90 
91  return RLM_MODULE_FAIL;
92  }
93  vp->vp_integer = timestamp;
94  vp->vp_length = 4;
95 
96  /*
97  * Token random
98  */
99  vp = fr_pair_make(request, &request->packet->vps, "Yubikey-Random", NULL, T_OP_SET);
100  if (!vp) {
101  REDEBUG("Failed creating Yubikey-Random");
102 
103  return RLM_MODULE_FAIL;
104  }
105  vp->vp_integer = token.rnd;
106  vp->vp_length = 4;
107 
108  /*
109  * Combine the two counter fields together so we can do
110  * replay attack checks.
111  */
112  vp = fr_pair_make(request, &request->packet->vps, "Yubikey-Counter", NULL, T_OP_SET);
113  if (!vp) {
114  REDEBUG("Failed creating Yubikey-Counter");
115 
116  return RLM_MODULE_FAIL;
117  }
118  vp->vp_integer = counter;
119  vp->vp_length = 4;
120 
121  /*
122  * Now we check for replay attacks
123  */
124  vp = fr_pair_find_by_da(request->config, da, TAG_ANY);
125  if (!vp) {
126  RWDEBUG("Yubikey-Counter not found in control list, skipping replay attack checks");
127  return RLM_MODULE_OK;
128  }
129 
130  if (counter <= vp->vp_integer) {
131  REDEBUG("Replay attack detected! Counter value %u, is lt or eq to last known counter value %u",
132  counter, vp->vp_integer);
133  return RLM_MODULE_REJECT;
134  }
135 
136  return RLM_MODULE_OK;
137 }
138 #endif
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
Definition: radiusd.h:227
The module is OK, continue.
Definition: radiusd.h:91
Dictionary attribute.
Definition: dict.h:77
#define RDEBUG_ENABLED2
True if request debug level 1-2 messages are enabled.
Definition: log.h:238
#define vp_integer
Definition: pair.h:166
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
#define inst
The module considers the request invalid.
Definition: radiusd.h:93
Immediately reject the request.
Definition: radiusd.h:89
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
Definition: token.h:45
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
rlm_rcode_t rlm_yubikey_decrypt(rlm_yubikey_t *inst, REQUEST *request, char const *passcode)
VALUE_PAIR * fr_pair_find_by_da(VALUE_PAIR *head, fr_dict_attr_t const *da, int8_t tag)
Find the pair with the matching DAs.
Definition: pair.c:624
#define RDEBUG2(fmt,...)
Definition: log.h:244
Module failed, don't reply.
Definition: radiusd.h:90
#define TAG_ANY
Definition: pair.h:191
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
uint8_t token[4]
Definition: eap_pwd.h:625
#define REDEBUG(fmt,...)
Definition: log.h:254
unsigned int id_len
The length of the Public ID portion of the OTP string.
Definition: rlm_yubikey.h:27
#define RWDEBUG(fmt,...)
Definition: log.h:251
VALUE_PAIR * fr_pair_make(TALLOC_CTX *ctx, VALUE_PAIR **vps, char const *attribute, char const *value, FR_TOKEN op)
Create a VALUE_PAIR from ASCII strings.
Definition: pair.c:338
#define RDEBUG(fmt,...)
Definition: log.h:243
size_t fr_bin2hex(char *hex, uint8_t const *bin, size_t inlen)
Convert binary data to a hex string.
Definition: misc.c:254
void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t len)
Copy data into an "octets" data type.
Definition: pair.c:1905
fr_dict_attr_t const * fr_dict_attr_by_name(fr_dict_t *dict, char const *attr)
Locate a fr_dict_attr_t by its name.
Definition: dict.c:3493