1 /* Copyright (C) 2011 NORDUnet A/S
2 * See LICENSE for information about licensing.
5 #include <stdio.h> /* For sprintf(). */
7 #include <nettle/sha.h>
8 #include <nettle/hmac.h>
13 #include "radsecproxy.h"
19 _format_hash(const uint8_t *hash, size_t out_len, uint8_t *out)
23 for (ir = 0, iw = 0; iw <= out_len - 3; ir++, iw += 2)
24 sprintf((char *) out + iw, "%02x", hash[ir % SHA256_DIGEST_SIZE]);
28 _hash(const uint8_t *in,
34 struct sha256_ctx ctx;
35 uint8_t hash[SHA256_DIGEST_SIZE];
38 sha256_update(&ctx, strlen((char *) in), in);
39 sha256_digest(&ctx, sizeof(hash), hash);
40 _format_hash(hash, out_len, out);
43 struct hmac_sha256_ctx ctx;
44 uint8_t hash[SHA256_DIGEST_SIZE];
46 hmac_sha256_set_key(&ctx, strlen((char *) key), key);
47 hmac_sha256_update(&ctx, strlen((char *) in), in);
48 hmac_sha256_digest(&ctx, sizeof(hash), hash);
49 _format_hash(hash, out_len, out);
54 fticks_configure(struct options *options,
60 const char *reporting = (const char *) *reportingp;
61 const char *mac = (const char *) *macp;
63 if (reporting == NULL)
66 if (strcasecmp(reporting, "None") == 0)
67 options->fticks_reporting = RSP_FTICKS_REPORTING_NONE;
68 else if (strcasecmp(reporting, "Basic") == 0)
69 options->fticks_reporting = RSP_FTICKS_REPORTING_BASIC;
70 else if (strcasecmp(reporting, "Full") == 0)
71 options->fticks_reporting = RSP_FTICKS_REPORTING_FULL;
73 debugx(1, DBG_ERR, "config error: invalid FTicksReporting value: %s",
79 if (strcasecmp(mac, "Static") == 0)
80 options->fticks_mac = RSP_FTICKS_MAC_STATIC;
81 else if (strcasecmp(mac, "Original") == 0)
82 options->fticks_mac = RSP_FTICKS_MAC_ORIGINAL;
83 else if (strcasecmp(mac, "VendorHashed") == 0)
84 options->fticks_mac = RSP_FTICKS_MAC_VENDOR_HASHED;
85 else if (strcasecmp(mac, "VendorKeyHashed") == 0)
86 options->fticks_mac = RSP_FTICKS_MAC_VENDOR_KEY_HASHED;
87 else if (strcasecmp(mac, "FullyHashed") == 0)
88 options->fticks_mac = RSP_FTICKS_MAC_FULLY_HASHED;
89 else if (strcasecmp(mac, "FullyKeyHashed") == 0)
90 options->fticks_mac = RSP_FTICKS_MAC_FULLY_KEY_HASHED;
92 debugx(1, DBG_ERR, "config error: invalid FTicksMAC value: %s", mac);
98 && (options->fticks_mac == RSP_FTICKS_MAC_VENDOR_KEY_HASHED
99 || options->fticks_mac == RSP_FTICKS_MAC_FULLY_KEY_HASHED)) {
101 "config error: FTicksMAC %s requires an FTicksKey", mac);
102 options->fticks_mac = RSP_FTICKS_MAC_STATIC;
108 options->fticks_key = *keyp;
111 if (*reportingp != NULL) {
122 /** Hash the Ethernet MAC address in \a IN, keying a HMAC with \a KEY
123 unless \a KEY is NULL. If \a KEY is null \a IN is hashed with an
124 ordinary cryptographic hash function such as SHA-2.
126 \a IN and \a KEY are NULL terminated strings.
128 \a IN is supposed to be an Ethernet MAC address and is sanitised
129 by lowercasing it, removing all but [0-9a-f] and truncating it at
130 the first ';' found. The truncation is done because RADIUS
131 supposedly has a praxis of tacking on SSID to the MAC address in
132 Calling-Station-Id. */
134 fticks_hashmac(const uint8_t *in,
139 /* TODO: lowercase */
140 /* TODO: s/[!0-9a-f]//1 */
141 /* TODO: truncate after first ';', if any */
143 _hash(in, key, out_len, out);
147 fticks_log(const struct options *options,
148 const struct client *client,
149 const struct radmsg *msg,
150 const struct rqout *rqout)
152 uint8_t *username = NULL;
153 uint8_t *realm = NULL;
154 uint8_t visinst[8+40+1+1]; /* Room for 40 octets of VISINST. */
155 uint8_t *macin = NULL;
156 uint8_t macout[2*32+1]; /* Room for ASCII representation of SHA256. */
158 username = radattr2ascii(radmsg_gettype(rqout->rq->msg,
159 RAD_Attr_User_Name));
160 if (username != NULL) {
161 realm = (uint8_t *) strrchr((char *) username, '@');
166 realm = (uint8_t *) "";
168 memset(visinst, 0, sizeof(visinst));
169 if (options->fticks_reporting == RSP_FTICKS_REPORTING_FULL) {
170 snprintf((char *) visinst, sizeof(visinst), "VISINST=%s#",
174 memset(macout, 0, sizeof(macout));
175 if (options->fticks_mac == RSP_FTICKS_MAC_STATIC) {
176 strncpy((char *) macout, "undisclosed", sizeof(macout) - 1);
179 macin = radattr2ascii(radmsg_gettype(rqout->rq->msg,
180 RAD_Attr_Calling_Station_Id));
182 switch (options->fticks_mac)
184 case RSP_FTICKS_MAC_ORIGINAL:
185 memcpy(macout, macin, sizeof(macout));
187 case RSP_FTICKS_MAC_VENDOR_HASHED:
188 memcpy(macout, macin, 9);
189 fticks_hashmac(macin, NULL, sizeof(macout) - 9, macout + 9);
191 case RSP_FTICKS_MAC_VENDOR_KEY_HASHED:
192 memcpy(macout, macin, 9);
193 /* We are hashing the first nine octets too for easier
194 * correlation between vendor-key-hashed and
195 * fully-key-hashed log records. This opens up for a
196 * known plaintext attack on the key but the
197 * consequences of that is considered outweighed by
198 * the convenience gained. */
199 fticks_hashmac(macin, options->fticks_key,
200 sizeof(macout) - 9, macout + 9);
202 case RSP_FTICKS_MAC_FULLY_HASHED:
203 fticks_hashmac(macin, NULL, sizeof(macout), macout);
205 case RSP_FTICKS_MAC_FULLY_KEY_HASHED:
206 fticks_hashmac(macin, options->fticks_key, sizeof(macout),
210 debugx(2, DBG_ERR, "invalid fticks mac configuration: %d",
211 options->fticks_mac);
216 "F-TICKS/eduroam/1.0#REALM=%s#VISCOUNTRY=%s#%sCSI=%s#RESULT=%s#",
218 client->conf->fticks_viscountry,
221 msg->code == RAD_Access_Accept ? "OK" : "FAIL");
224 if (username != NULL)
228 /* Local Variables: */
229 /* c-file-style: "stroustrup" */