From: Alan T. DeKok Date: Mon, 1 May 2017 17:03:15 +0000 (-0400) Subject: add bare octets fr_radius_sign X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=37af04dcb994b936bec8907966f04cd6a1b7a2fc;p=thirdparty%2Ffreeradius-server.git add bare octets fr_radius_sign --- diff --git a/src/lib/util/radius.c b/src/lib/util/radius.c index 71de0d9b697..fbbba2dba7b 100644 --- a/src/lib/util/radius.c +++ b/src/lib/util/radius.c @@ -378,71 +378,61 @@ static ssize_t rad_recvfrom(int sockfd, RADIUS_PACKET *packet, int flags) &packet->if_index, &packet->timestamp); } + /** Sign a previously encoded packet * + * @param packet the raw RADIUS packet (request or response) + * @param packet_len the length of the raw RADIUS packet + * @param original the raw original request (if this is a response) + * @param secret the shared secret + * @param secret_len the length of the secret + * @return + * - <0 on error + * - 0 on success */ -int fr_radius_packet_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original, - char const *secret) +static int fr_radius_sign(uint8_t *packet, size_t packet_len, + uint8_t const *original, + uint8_t const *secret, size_t secret_len) { - radius_packet_t *hdr = (radius_packet_t *)packet->data; - - /* - * It wasn't assigned an Id, this is bad! - */ - if (packet->id < 0) { - fr_strerror_printf("ERROR: RADIUS packets must be assigned an Id"); - return -1; - } + int i; + bool done_authenticator = false; + uint32_t hash; + uint8_t *msg, *end; + FR_MD5_CTX context; - if (!packet->data || (packet->data_len < RADIUS_HDR_LEN) || - (packet->offset < 0)) { - fr_strerror_printf("ERROR: You must call fr_radius_encode() before fr_radius_packet_sign()"); + if (packet_len < RADIUS_HDR_LEN) { + fr_strerror_printf("Packet must be encoded before calling fr_radius_sign()"); return -1; } /* - * Set up the authentication vector with zero, or with - * the original vector, prior to signing. + * Find Message-Authenticator. Its value has to be + * calculated before we calculate the Request + * Authenticator or the Response Authenticator. */ - switch (packet->code) { - case PW_CODE_ACCOUNTING_REQUEST: - case PW_CODE_DISCONNECT_REQUEST: - case PW_CODE_COA_REQUEST: - memset(packet->vector, 0, AUTH_VECTOR_LEN); - break; + msg = packet + RADIUS_HDR_LEN; + end = packet + packet_len; - case PW_CODE_ACCESS_ACCEPT: - case PW_CODE_ACCESS_REJECT: - case PW_CODE_ACCESS_CHALLENGE: - case PW_CODE_ACCOUNTING_RESPONSE: - case PW_CODE_DISCONNECT_ACK: - case PW_CODE_DISCONNECT_NAK: - case PW_CODE_COA_ACK: - case PW_CODE_COA_NAK: - if (!original) { - fr_strerror_printf("ERROR: Cannot sign response packet without a request packet"); - return -1; + while (msg < end) { + if (msg[0] != PW_MESSAGE_AUTHENTICATOR) { + if ((msg + msg[1]) > end) { + fr_strerror_printf("Invalid attribute at offset %zd", msg - packet); + return -1; + } + msg += msg[1]; + continue; } - memcpy(packet->vector, original->vector, AUTH_VECTOR_LEN); - break; - - case PW_CODE_ACCESS_REQUEST: - case PW_CODE_STATUS_SERVER: - break; /* packet->vector is already random bytes */ - } - /* - * If there's a Message-Authenticator, update it - * now. - */ - if (packet->offset > 0) { - uint8_t calc_auth_vector[AUTH_VECTOR_LEN]; + if (msg[1] < 18) { + fr_strerror_printf("Message-Authenticator is too small"); + return -1; + } - switch (packet->code) { + switch (packet[0]) { case PW_CODE_ACCOUNTING_RESPONSE: - if (original && original->code == PW_CODE_STATUS_SERVER) { - goto do_ack; - } + if (!original) goto need_original; + if (original[0] == PW_CODE_STATUS_SERVER) goto do_ack; + goto do_response; case PW_CODE_ACCOUNTING_REQUEST: case PW_CODE_DISCONNECT_REQUEST: @@ -451,71 +441,118 @@ int fr_radius_packet_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original, case PW_CODE_COA_REQUEST: case PW_CODE_COA_ACK: case PW_CODE_COA_NAK: - memset(hdr->vector, 0, AUTH_VECTOR_LEN); + if (!original) goto need_original; + + do_response: + memset(packet + 4, 0, AUTH_VECTOR_LEN); break; - do_ack: case PW_CODE_ACCESS_ACCEPT: case PW_CODE_ACCESS_REJECT: case PW_CODE_ACCESS_CHALLENGE: - memcpy(hdr->vector, original->vector, AUTH_VECTOR_LEN); + do_ack: + memcpy(packet + 4, original + 4, AUTH_VECTOR_LEN); break; case PW_CODE_ACCESS_REQUEST: case PW_CODE_STATUS_SERVER: + for (i = 0; i < AUTH_VECTOR_LEN; i += sizeof(hash)) { + hash = fr_rand(); + memcpy(packet + 4 + i, &hash, sizeof(hash)); + } + done_authenticator = true; break; + + default: + goto bad_packet; } /* - * Calculate the HMAC, and put it - * into the Message-Authenticator - * attribute. + * Calculate the HMAC, and put it into the + * Message-Authenticator attribute. */ - fr_hmac_md5(calc_auth_vector, packet->data, packet->data_len, - (uint8_t const *) secret, talloc_array_length(secret) - 1); - memcpy(packet->data + packet->offset + 2, - calc_auth_vector, AUTH_VECTOR_LEN); + fr_hmac_md5(msg + 2, packet, packet_len, secret, secret_len); + break; } /* - * Copy the request authenticator over to the packet. + * Initialize the request authenticator. */ - memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN); + switch (packet[0]) { + case PW_CODE_ACCOUNTING_REQUEST: + case PW_CODE_DISCONNECT_REQUEST: + case PW_CODE_COA_REQUEST: + memset(packet + 4, 0, AUTH_VECTOR_LEN); + break; + + case PW_CODE_ACCESS_ACCEPT: + case PW_CODE_ACCESS_REJECT: + case PW_CODE_ACCESS_CHALLENGE: + case PW_CODE_ACCOUNTING_RESPONSE: + case PW_CODE_DISCONNECT_ACK: + case PW_CODE_DISCONNECT_NAK: + case PW_CODE_COA_ACK: + case PW_CODE_COA_NAK: + if (!original) { + need_original: + fr_strerror_printf("Cannot sign response packet without a request packet"); + return -1; + } + memcpy(packet + 4, original + 4, AUTH_VECTOR_LEN); + break; - /* - * Switch over the packet code, deciding how to - * sign the packet. - */ - switch (packet->code) { /* - * Request packets are not signed, but - * have a random authentication vector. + * The Request Authenticator is random numbers. + * We don't need to sign anything else, so + * return. */ case PW_CODE_ACCESS_REQUEST: case PW_CODE_STATUS_SERVER: - break; + if (!done_authenticator) { + for (i = 0; i < AUTH_VECTOR_LEN; i += sizeof(hash)) { + hash = fr_rand(); + memcpy(packet + 4 + i, &hash, sizeof(hash)); + } + } + return 0; - /* - * Reply packets are signed with the - * authentication vector of the request. - */ default: - { - uint8_t digest[16]; - - FR_MD5_CTX context; - fr_md5_init(&context); - fr_md5_update(&context, packet->data, packet->data_len); - fr_md5_update(&context, (uint8_t const *) secret, - talloc_array_length(secret) - 1); - fr_md5_final(digest, &context); - - memcpy(hdr->vector, digest, AUTH_VECTOR_LEN); - memcpy(packet->vector, digest, AUTH_VECTOR_LEN); - break; - } - }/* switch over packet codes */ + bad_packet: + fr_strerror_printf("Cannot sign unknown packet code %u", packet[0]); + return -1; + } + + /* + * Request / Response Authenticator = MD5(packet + secret) + */ + fr_md5_init(&context); + fr_md5_update(&context, packet, packet_len); + fr_md5_update(&context, secret, secret_len); + fr_md5_final(packet + 4, &context); + + return 0; +} + +/** Sign a previously encoded packet + * + */ +int fr_radius_packet_sign(RADIUS_PACKET *packet, RADIUS_PACKET const *original, + char const *secret) +{ + int rcode; + uint8_t const *original_data; + + if (original) { + original_data = original->data; + } else { + original_data = NULL; + } + + rcode = fr_radius_sign(packet->data, packet->data_len, original_data, + (uint8_t const *) secret, talloc_array_length(secret) - 1); + if (rcode < 0) return rcode; + memcpy(packet->vector, packet->data + 4, AUTH_VECTOR_LEN); return 0; }