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)
67 if (strcasecmp(reporting, "None") == 0)
68 options->fticks_reporting = RSP_FTICKS_REPORTING_NONE;
69 else if (strcasecmp(reporting, "Basic") == 0)
70 options->fticks_reporting = RSP_FTICKS_REPORTING_BASIC;
71 else if (strcasecmp(reporting, "Full") == 0)
72 options->fticks_reporting = RSP_FTICKS_REPORTING_FULL;
74 debugx(1, DBG_ERR, "config error: invalid FTicksReporting value: %s",
82 if (strcasecmp(mac, "Static") == 0)
83 options->fticks_mac = RSP_FTICKS_MAC_STATIC;
84 else if (strcasecmp(mac, "Original") == 0)
85 options->fticks_mac = RSP_FTICKS_MAC_ORIGINAL;
86 else if (strcasecmp(mac, "VendorHashed") == 0)
87 options->fticks_mac = RSP_FTICKS_MAC_VENDOR_HASHED;
88 else if (strcasecmp(mac, "VendorKeyHashed") == 0)
89 options->fticks_mac = RSP_FTICKS_MAC_VENDOR_KEY_HASHED;
90 else if (strcasecmp(mac, "FullyHashed") == 0)
91 options->fticks_mac = RSP_FTICKS_MAC_FULLY_HASHED;
92 else if (strcasecmp(mac, "FullyKeyHashed") == 0)
93 options->fticks_mac = RSP_FTICKS_MAC_FULLY_KEY_HASHED;
95 debugx(1, DBG_ERR, "config error: invalid FTicksMAC value: %s", mac);
101 && (options->fticks_mac == RSP_FTICKS_MAC_VENDOR_KEY_HASHED
102 || options->fticks_mac == RSP_FTICKS_MAC_FULLY_KEY_HASHED)) {
104 "config error: FTicksMAC %s requires an FTicksKey", mac);
105 options->fticks_mac = RSP_FTICKS_MAC_STATIC;
111 options->fticks_key = *keyp;
114 if (*reportingp != NULL) {
125 /** Hash the Ethernet MAC address in \a IN, keying a HMAC with \a KEY
126 unless \a KEY is NULL. If \a KEY is null \a IN is hashed with an
127 ordinary cryptographic hash function such as SHA-2.
129 \a IN and \a KEY are NULL terminated strings.
131 \a IN is supposed to be an Ethernet MAC address and is sanitised
132 by lowercasing it, removing all but [0-9a-f] and truncating it at
133 the first ';' found. The truncation is done because RADIUS
134 supposedly has a praxis of tacking on SSID to the MAC address in
137 \return 0 on success, -ENOMEM on out of memory.
140 fticks_hashmac(const uint8_t *in,
145 uint8_t *in_copy = NULL;
149 in_copy = calloc(1, strlen((const char *) in) + 1);
153 /* Sanitise and lowercase 'in' into 'in_copy'. */
154 for (i = 0, p = in_copy; in[i] != '\0'; i++) {
159 if (in[i] >= '0' && in[i] <= '9') {
162 else if (tolower(in[i]) >= 'a' && tolower(in[i]) <= 'f') {
163 *p++ = tolower(in[i]);
167 _hash(in_copy, key, out_len, out);
173 fticks_log(const struct options *options,
174 const struct client *client,
175 const struct radmsg *msg,
176 const struct rqout *rqout)
178 uint8_t *username = NULL;
179 uint8_t *realm = NULL;
180 uint8_t visinst[8+40+1+1]; /* Room for 40 octets of VISINST. */
181 uint8_t *macin = NULL;
182 uint8_t macout[2*32+1]; /* Room for ASCII representation of SHA256. */
184 username = radattr2ascii(radmsg_gettype(rqout->rq->msg,
185 RAD_Attr_User_Name));
186 if (username != NULL) {
187 realm = (uint8_t *) strrchr((char *) username, '@');
192 realm = (uint8_t *) "";
194 memset(visinst, 0, sizeof(visinst));
195 if (options->fticks_reporting == RSP_FTICKS_REPORTING_FULL) {
196 snprintf((char *) visinst, sizeof(visinst), "VISINST=%s#",
200 memset(macout, 0, sizeof(macout));
201 if (options->fticks_mac == RSP_FTICKS_MAC_STATIC) {
202 strncpy((char *) macout, "undisclosed", sizeof(macout) - 1);
205 macin = radattr2ascii(radmsg_gettype(rqout->rq->msg,
206 RAD_Attr_Calling_Station_Id));
208 switch (options->fticks_mac)
210 case RSP_FTICKS_MAC_ORIGINAL:
211 memcpy(macout, macin, sizeof(macout));
213 case RSP_FTICKS_MAC_VENDOR_HASHED:
214 memcpy(macout, macin, 9);
215 fticks_hashmac(macin, NULL, sizeof(macout) - 9, macout + 9);
217 case RSP_FTICKS_MAC_VENDOR_KEY_HASHED:
218 memcpy(macout, macin, 9);
219 /* We are hashing the first nine octets too for easier
220 * correlation between vendor-key-hashed and
221 * fully-key-hashed log records. This opens up for a
222 * known plaintext attack on the key but the
223 * consequences of that is considered outweighed by
224 * the convenience gained. */
225 fticks_hashmac(macin, options->fticks_key,
226 sizeof(macout) - 9, macout + 9);
228 case RSP_FTICKS_MAC_FULLY_HASHED:
229 fticks_hashmac(macin, NULL, sizeof(macout), macout);
231 case RSP_FTICKS_MAC_FULLY_KEY_HASHED:
232 fticks_hashmac(macin, options->fticks_key, sizeof(macout),
236 debugx(2, DBG_ERR, "invalid fticks mac configuration: %d",
237 options->fticks_mac);
242 "F-TICKS/eduroam/1.0#REALM=%s#VISCOUNTRY=%s#%sCSI=%s#RESULT=%s#",
244 client->conf->fticks_viscountry,
247 msg->code == RAD_Access_Accept ? "OK" : "FAIL");
250 if (username != NULL)
254 /* Local Variables: */
255 /* c-file-style: "stroustrup" */