static ssize_t test_encode(void const *instance, REQUEST *request, uint8_t *buffer, size_t buffer_len) { FR_MD5_CTX context; fr_listen_test_t const *pc = instance; MPRINT1("\t\tENCODE >>> request %"PRIu64"- data %p %p room %zd\n", request->number, pc, buffer, buffer_len); buffer[0] = FR_CODE_ACCESS_ACCEPT; buffer[1] = tpc.id; buffer[2] = 0; buffer[3] = 20; memcpy(buffer + 4, tpc.vector, 16); fr_md5_init(&context); fr_md5_update(&context, buffer, 20); fr_md5_update(&context, (uint8_t const *) secret, strlen(secret)); fr_md5_final(buffer + 4, &context); return 20; }
/** 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_md5_init(&ctx); fr_md5_update(&ctx, p, inlen); fr_md5_final(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); }
/* * Attach the module. */ static int mod_instantiate(CONF_SECTION *cs, void **instance) { rlm_eap_fast_t *inst; *instance = inst = talloc_zero(cs, rlm_eap_fast_t); if (!inst) return -1; /* * Parse the configuration attributes. */ if (cf_section_parse(cs, inst, module_config) < 0) { return -1; } if (!cf_section_sub_find_name2(main_config.config, "server", inst->virtual_server)) { ERROR("rlm_eap_fast.virtual_server: Unknown virtual server '%s'", inst->virtual_server); return -1; } inst->default_method = eap_name2type(inst->default_method_name); if (!inst->default_method) { ERROR("rlm_eap_fast.default_provisioning_eap_type: " "Unknown EAP type %s", inst->default_method_name); return -1; } /* * Read tls configuration, either from group given by 'tls' * option, or from the eap-tls configuration. */ inst->tls_conf = eaptls_conf_parse(cs, "tls"); if (!inst->tls_conf) { ERROR("rlm_eap_fast.tls: Failed initializing SSL context"); return -1; } if (talloc_array_length(inst->pac_opaque_key) - 1 != 32) { ERROR("rlm_eap_fast.pac_opaque_key: Must be 32 bytes long"); return -1; } // FIXME TLSv1.2 uses a different PRF and SSL_export_keying_material("key expansion") is forbidden if (!inst->tls_conf->disable_tlsv1_2) { ERROR("rlm_eap_fast.disable_tlsv1_2: require disable_tlsv1_2=yes"); return -1; } if (!inst->pac_lifetime) { ERROR("rlm_eap_fast.pac_lifetime: must be non-zero"); return -1; } rad_assert(PAC_A_ID_LENGTH == MD5_DIGEST_LENGTH); FR_MD5_CTX ctx; fr_md5_init(&ctx); fr_md5_update(&ctx, inst->authority_identity, talloc_array_length(inst->authority_identity) - 1); fr_md5_final(inst->a_id, &ctx); return 0; }
static int respond_eap_md5(RADIUS_PACKET *req, RADIUS_PACKET *rep) { VALUE_PAIR *vp, *id, *state; size_t valuesize; uint8_t identifier; uint8_t const *value; FR_MD5_CTX context; uint8_t response[16]; cleanresp(rep); if ((state = paircopy2(NULL, req->vps, PW_STATE, 0, TAG_ANY)) == NULL) { fprintf(stderr, "radeapclient: no state attribute found\n"); return 0; } if ((id = paircopy2(NULL, req->vps, ATTRIBUTE_EAP_ID, 0, TAG_ANY)) == NULL) { fprintf(stderr, "radeapclient: no EAP-ID attribute found\n"); return 0; } identifier = id->vp_integer; if ((vp = pairfind(req->vps, ATTRIBUTE_EAP_BASE+PW_EAP_MD5, 0, TAG_ANY)) == NULL) { fprintf(stderr, "radeapclient: no EAP-MD5 attribute found\n"); return 0; } /* got the details of the MD5 challenge */ valuesize = vp->vp_octets[0]; value = &vp->vp_octets[1]; /* sanitize items */ if(valuesize > vp->length) { fprintf(stderr, "radeapclient: md5 valuesize if too big (%u > %u)\n", (unsigned int) valuesize, (unsigned int) vp->length); return 0; } /* now do the CHAP operation ourself, rather than build the * buffer. We could also call rad_chap_encode, but it wants * a CHAP-Challenge, which we don't want to bother with. */ fr_md5_init(&context); fr_md5_update(&context, &identifier, 1); fr_md5_update(&context, (uint8_t *) password, strlen(password)); fr_md5_update(&context, value, valuesize); fr_md5_final(response, &context); { uint8_t *p; uint8_t lg_response; vp = paircreate(rep, ATTRIBUTE_EAP_BASE+PW_EAP_MD5, 0); vp->length = 17; p = talloc_zero_array(vp, uint8_t, 17); lg_response = 16; memcpy(p, &lg_response, 1); memcpy(p + 1, response, 16); pairmemsteal(vp, p); } pairreplace(&(rep->vps), vp); pairreplace(&(rep->vps), id); /* copy the state object in */ pairreplace(&(rep->vps), state); return 1; }
/** Calculate HMAC using internal MD5 implementation * * @param digest Caller digest to be filled in. * @param in Pointer to data stream. * @param inlen length of data stream. * @param key Pointer to authentication key. * @param key_len Length of authentication key. * */ void fr_hmac_md5(uint8_t digest[MD5_DIGEST_LENGTH], uint8_t const *in, size_t inlen, uint8_t const *key, size_t key_len) { fr_md5_ctx_t *ctx; uint8_t k_ipad[65]; /* inner padding - key XORd with ipad */ uint8_t k_opad[65]; /* outer padding - key XORd with opad */ uint8_t tk[16]; int i; ctx = fr_md5_ctx_alloc(true); /* if key is longer than 64 bytes reset it to key=MD5(key) */ if (key_len > 64) { fr_md5_update(ctx, key, key_len); fr_md5_final(tk, ctx); fr_md5_ctx_reset(ctx); key = tk; key_len = 16; } /* * the HMAC_MD5 transform looks like: * * MD5(K XOR opad, MD5(K XOR ipad, in)) * * where K is an n byte key * ipad is the byte 0x36 repeated 64 times * opad is the byte 0x5c repeated 64 times * and in is the data being protected */ /* start out by storing key in pads */ memset(k_ipad, 0, sizeof(k_ipad)); memset(k_opad, 0, sizeof(k_opad)); memcpy(k_ipad, key, key_len); memcpy(k_opad, key, key_len); /* XOR key with ipad and opad values */ for (i = 0; i < 64; i++) { k_ipad[i] ^= 0x36; k_opad[i] ^= 0x5c; } /* * perform inner MD5 */ fr_md5_update(ctx, k_ipad, 64); /* start with inner pad */ fr_md5_update(ctx, in, inlen); /* then in of datagram */ fr_md5_final(digest, ctx); /* finish up 1st pass */ /* * perform outer MD5 */ fr_md5_ctx_reset(ctx); fr_md5_update(ctx, k_opad, 64); /* start with outer pad */ fr_md5_update(ctx, digest, 16); /* then results of 1st hash */ fr_md5_final(digest, ctx); /* finish up 2nd pass */ fr_md5_ctx_free(&ctx); }