1 /* Copyright (C) 2011 NORDUnet A/S
2 * See LICENSE for information about licensing.
5 #include <stdio.h> /* For sprintf(). */
9 #include <nettle/sha.h>
10 #include <nettle/hmac.h>
15 #include "radsecproxy.h"
21 _format_hash(const uint8_t *hash, size_t out_len, uint8_t *out)
25 for (ir = 0, iw = 0; iw <= out_len - 3; ir++, iw += 2)
26 sprintf((char *) out + iw, "%02x", hash[ir % SHA256_DIGEST_SIZE]);
30 _hash(const uint8_t *in,
36 struct sha256_ctx ctx;
37 uint8_t hash[SHA256_DIGEST_SIZE];
40 sha256_update(&ctx, strlen((char *) in), in);
41 sha256_digest(&ctx, sizeof(hash), hash);
42 _format_hash(hash, out_len, out);
45 struct hmac_sha256_ctx ctx;
46 uint8_t hash[SHA256_DIGEST_SIZE];
48 hmac_sha256_set_key(&ctx, strlen((char *) key), key);
49 hmac_sha256_update(&ctx, strlen((char *) in), in);
50 hmac_sha256_digest(&ctx, sizeof(hash), hash);
51 _format_hash(hash, out_len, out);
56 fticks_configure(struct options *options,
62 const char *reporting = (const char *) *reportingp;
63 const char *mac = (const char *) *macp;
65 if (reporting == NULL)
68 if (strcasecmp(reporting, "None") == 0)
69 options->fticks_reporting = RSP_FTICKS_REPORTING_NONE;
70 else if (strcasecmp(reporting, "Basic") == 0)
71 options->fticks_reporting = RSP_FTICKS_REPORTING_BASIC;
72 else if (strcasecmp(reporting, "Full") == 0)
73 options->fticks_reporting = RSP_FTICKS_REPORTING_FULL;
75 debugx(1, DBG_ERR, "config error: invalid FTicksReporting value: %s",
81 if (strcasecmp(mac, "Static") == 0)
82 options->fticks_mac = RSP_FTICKS_MAC_STATIC;
83 else if (strcasecmp(mac, "Original") == 0)
84 options->fticks_mac = RSP_FTICKS_MAC_ORIGINAL;
85 else if (strcasecmp(mac, "VendorHashed") == 0)
86 options->fticks_mac = RSP_FTICKS_MAC_VENDOR_HASHED;
87 else if (strcasecmp(mac, "VendorKeyHashed") == 0)
88 options->fticks_mac = RSP_FTICKS_MAC_VENDOR_KEY_HASHED;
89 else if (strcasecmp(mac, "FullyHashed") == 0)
90 options->fticks_mac = RSP_FTICKS_MAC_FULLY_HASHED;
91 else if (strcasecmp(mac, "FullyKeyHashed") == 0)
92 options->fticks_mac = RSP_FTICKS_MAC_FULLY_KEY_HASHED;
94 debugx(1, DBG_ERR, "config error: invalid FTicksMAC value: %s", mac);
100 && (options->fticks_mac == RSP_FTICKS_MAC_VENDOR_KEY_HASHED
101 || options->fticks_mac == RSP_FTICKS_MAC_FULLY_KEY_HASHED)) {
103 "config error: FTicksMAC %s requires an FTicksKey", mac);
104 options->fticks_mac = RSP_FTICKS_MAC_STATIC;
110 options->fticks_key = *keyp;
113 if (*reportingp != NULL) {
124 /** Hash the Ethernet MAC address in \a IN, keying a HMAC with \a KEY
125 unless \a KEY is NULL. If \a KEY is null \a IN is hashed with an
126 ordinary cryptographic hash function such as SHA-2.
128 \a IN and \a KEY are NULL terminated strings.
130 \a IN is supposed to be an Ethernet MAC address and is sanitised
131 by lowercasing it, removing all but [0-9a-f] and truncating it at
132 the first ';' found. The truncation is done because RADIUS
133 supposedly has a praxis of tacking on SSID to the MAC address in
136 \return 0 on success, -ENOMEM on out of memory.
139 fticks_hashmac(const uint8_t *in,
144 uint8_t *in_copy = NULL;
148 in_copy = calloc(1, strlen((const char *) in) + 1);
152 /* Sanitise and lowercase 'in' into 'in_copy'. */
153 for (i = 0, p = in_copy; in[i] != '\0'; i++) {
158 if (in[i] >= '0' && in[i] <= '9') {
161 else if (tolower(in[i]) >= 'a' && tolower(in[i]) <= 'f') {
162 *p++ = tolower(in[i]);
166 _hash(in_copy, key, out_len, out);
172 fticks_log(const struct options *options,
173 const struct client *client,
174 const struct radmsg *msg,
175 const struct rqout *rqout)
177 uint8_t *username = NULL;
178 uint8_t *realm = NULL;
179 uint8_t visinst[8+40+1+1]; /* Room for 40 octets of VISINST. */
180 uint8_t *macin = NULL;
181 uint8_t macout[2*32+1]; /* Room for ASCII representation of SHA256. */
183 username = radattr2ascii(radmsg_gettype(rqout->rq->msg,
184 RAD_Attr_User_Name));
185 if (username != NULL) {
186 realm = (uint8_t *) strrchr((char *) username, '@');
191 realm = (uint8_t *) "";
193 memset(visinst, 0, sizeof(visinst));
194 if (options->fticks_reporting == RSP_FTICKS_REPORTING_FULL) {
195 snprintf((char *) visinst, sizeof(visinst), "VISINST=%s#",
199 memset(macout, 0, sizeof(macout));
200 if (options->fticks_mac == RSP_FTICKS_MAC_STATIC) {
201 strncpy((char *) macout, "undisclosed", sizeof(macout) - 1);
204 macin = radattr2ascii(radmsg_gettype(rqout->rq->msg,
205 RAD_Attr_Calling_Station_Id));
207 switch (options->fticks_mac)
209 case RSP_FTICKS_MAC_ORIGINAL:
210 memcpy(macout, macin, sizeof(macout));
212 case RSP_FTICKS_MAC_VENDOR_HASHED:
213 memcpy(macout, macin, 9);
214 fticks_hashmac(macin, NULL, sizeof(macout) - 9, macout + 9);
216 case RSP_FTICKS_MAC_VENDOR_KEY_HASHED:
217 memcpy(macout, macin, 9);
218 /* We are hashing the first nine octets too for easier
219 * correlation between vendor-key-hashed and
220 * fully-key-hashed log records. This opens up for a
221 * known plaintext attack on the key but the
222 * consequences of that is considered outweighed by
223 * the convenience gained. */
224 fticks_hashmac(macin, options->fticks_key,
225 sizeof(macout) - 9, macout + 9);
227 case RSP_FTICKS_MAC_FULLY_HASHED:
228 fticks_hashmac(macin, NULL, sizeof(macout), macout);
230 case RSP_FTICKS_MAC_FULLY_KEY_HASHED:
231 fticks_hashmac(macin, options->fticks_key, sizeof(macout),
235 debugx(2, DBG_ERR, "invalid fticks mac configuration: %d",
236 options->fticks_mac);
241 "F-TICKS/eduroam/1.0#REALM=%s#VISCOUNTRY=%s#%sCSI=%s#RESULT=%s#",
243 client->conf->fticks_viscountry,
246 msg->code == RAD_Access_Accept ? "OK" : "FAIL");
249 if (username != NULL)
253 /* Local Variables: */
254 /* c-file-style: "stroustrup" */