/** Generate the HMAC-SHA1 of a string or attribute * * Example: "%{hmacsha1:foo bar}" == "Zm9v" */ static ssize_t hmac_sha1_xlat(UNUSED void *instance, UNUSED REQUEST *request, char const *fmt, char *out, size_t outlen) { uint8_t const *data, *key; char const *p; ssize_t data_len, key_len; uint8_t digest[SHA1_DIGEST_LENGTH]; char data_ref[256]; if (outlen <= (sizeof(digest) * 2)) { REDEBUG("Insufficient space to write digest, needed %zu bytes, have %zu bytes", (sizeof(digest) * 2) + 1, outlen); return -1; } p = strchr(fmt, ' '); if (!p) { REDEBUG("HMAC requires exactly two arguments (&data &key)"); return -1; } if ((size_t)(p - fmt) >= sizeof(data_ref)) { REDEBUG("Insufficient space to store HMAC input data, needed %zu bytes, have %zu bytes", (p - fmt) + 1, sizeof(data_ref)); return -1; } strlcpy(data_ref, fmt, (p - fmt) + 1); data_len = xlat_fmt_to_ref(&data, request, data_ref); if (data_len < 0) return -1; while (isspace(*p) && p++); key_len = xlat_fmt_to_ref(&key, request, p); if (key_len < 0) return -1; fr_hmac_sha1(digest, data, data_len, key, key_len); return fr_bin2hex(out, digest, sizeof(digest)); }
static ssize_t evp_md_xlat(UNUSED void *instance, UNUSED REQUEST *request, char const *fmt, char *out, size_t outlen, EVP_MD const *md) { uint8_t digest[EVP_MAX_MD_SIZE]; unsigned int digestlen, i, len; ssize_t inlen; uint8_t const *p; EVP_MD_CTX *ctx; /* * We need room for at least one octet of output. */ if (outlen < 3) { *out = '\0'; return 0; } inlen = xlat_fmt_to_ref(&p, request, fmt); if (inlen < 0) { return -1; } ctx = EVP_MD_CTX_create(); EVP_DigestInit_ex(ctx, md, NULL); EVP_DigestUpdate(ctx, p, inlen); EVP_DigestFinal_ex(ctx, digest, &digestlen); EVP_MD_CTX_destroy(ctx); /* * Each digest octet takes two hex digits, plus one for * the terminating NUL. */ len = (outlen / 2) - 1; if (len > digestlen) len = digestlen; for (i = 0; i < len; i++) { snprintf(out + i * 2, 3, "%02x", digest[i]); } return strlen(out); }
/** Calculate the SHA1 hash of a string or attribute. * * Example: "%{sha1:foo}" == "0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33" */ static ssize_t sha1_xlat(UNUSED void *instance, UNUSED REQUEST *request, char const *fmt, char *out, size_t outlen) { uint8_t digest[20]; ssize_t i, len, inlen; uint8_t const *p; fr_SHA1_CTX ctx; /* * We need room for at least one octet of output. */ if (outlen < 3) { *out = '\0'; return 0; } inlen = xlat_fmt_to_ref(&p, request, fmt); if (inlen < 0) { return -1; } fr_sha1_init(&ctx); fr_sha1_update(&ctx, p, inlen); fr_sha1_final(digest, &ctx); /* * Each digest octet takes two hex digits, plus one for * the terminating NUL. SHA1 is 160 bits (20 bytes) */ len = (outlen / 2) - 1; if (len > 20) len = 20; for (i = 0; i < len; i++) { snprintf(out + i * 2, 3, "%02x", digest[i]); } return strlen(out); }
/** Calculate the MD5 hash of a string or attribute. * * Example: "%{md5:foo}" == "acbd18db4cc2f85cedef654fccc4a4d8" */ static ssize_t md5_xlat(UNUSED void *instance, UNUSED REQUEST *request, char const *fmt, char *out, size_t outlen) { uint8_t digest[16]; ssize_t i, len, inlen; uint8_t const *p; FR_MD5_CTX ctx; /* * We need room for at least one octet of output. */ if (outlen < 3) { *out = '\0'; return 0; } inlen = xlat_fmt_to_ref(&p, request, fmt); if (inlen < 0) { return -1; } fr_MD5Init(&ctx); fr_MD5Update(&ctx, p, inlen); fr_MD5Final(digest, &ctx); /* * Each digest octet takes two hex digits, plus one for * the terminating NUL. */ len = (outlen / 2) - 1; if (len > 16) len = 16; for (i = 0; i < len; i++) { snprintf(out + i * 2, 3, "%02x", digest[i]); } return strlen(out); }
/** Encode string or attribute as base64 * * Example: "%{base64:foo}" == "Zm9v" */ static ssize_t base64_xlat(UNUSED void *instance, UNUSED REQUEST *request, char const *fmt, char *out, size_t outlen) { ssize_t inlen; uint8_t const *p; inlen = xlat_fmt_to_ref(&p, request, fmt); if (inlen < 0) { return -1; } /* * We can accurately calculate the length of the output string * if it's larger than outlen, the output would be useless so abort. */ if ((inlen < 0) || ((FR_BASE64_ENC_LENGTH(inlen) + 1) > (ssize_t) outlen)) { REDEBUG("xlat failed"); *out = '\0'; return -1; } return fr_base64_encode(out, outlen, p, inlen); }