Commit 0cdafb7e authored by Robert Dubner's avatar Robert Dubner
Browse files

Moved AdjustServerPacketForSending() to rpacket.c

parent 85bec976
Pipeline #3569 passed with stage
in 44 minutes and 57 seconds
/* radius.c - RADIUS protocol implementation */
/* radius.c - RADIUS protocol implementation */
/* radius.c - RADIUS protocol implementation */
/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
......@@ -26,65 +27,6 @@
//#define TEST_NT_RESPONSE 1
static void
AdjustPacketForSending( RADIUS_PACKET *response,
RADIUS_PACKET *request,
const char *shared_secret)
{
// Our job is to fill in the data for the Message-Authenticator attribute, which comes first, followed
// by the response->ResponseAuthenticator, which has to come second because it includes
// the hash of the attributes.
size_t length = get_length(response);
if( length )
{
RADIUS_ATTRIBUTE *ra = fetch_attribute_from_packet( response,
RATV_Message_Authenticator);
if( ra )
{
//Debug( LDAP_DEBUG_TRACE,"We have found the response Message-Authenticator attribute\n" );
// Per RFC2869, section 5.14, the Message-Authenticator sixteen-byte payload is calculated
// this way:
//
// Message-Authenticator = HMAC-MD5 (Type, Identifier, Length, Request Authenticator, Attributes)
//
// For the purposes of the calculation, the sixteen bytes of the Message-Authenticator are set to zero,
// which they are at this point.
MD5_CTX context;
hmac_md5_init( &context, (uint8_t *)shared_secret, strlen(shared_secret) );
hmac_md5_update(&context, response->packet_data, 4); // Type, Identifier, Length
hmac_md5_update(&context, request-> packet_data + AUTHENTICATOR_OFFSET, AUTHENTICATOR_LENGTH);
hmac_md5_update(&context, response->packet_data + ATTRIBUTES_OFFSET, length - ATTRIBUTES_OFFSET);
// Finalize the HMAC-MD5 hash, putting the results into the Message-Authenticator attribute
hmac_md5_final( &context, ra->Data);
}
// With the Message-Authenticator attribute established, we can now calculate the response authenticator:
// Per RFC2865 section 3, the description of Response Authenticator
// ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret)
MD5_CTX context;
md5_init(&context);
// Hash the first four bytes, which are Code, Identifier, and Length
md5_update(&context, response->packet_data + CODE_OFFSET, 1 + 1 + LENGTH_OF_PACKET_LENGTH);
md5_update(&context, request-> packet_data + AUTHENTICATOR_OFFSET, AUTHENTICATOR_LENGTH);
md5_update(&context, response->packet_data + ATTRIBUTES_OFFSET, length - ATTRIBUTES_OFFSET);
md5_update(&context, (uint8_t *)shared_secret, strlen(shared_secret));
// Finalize the MD5 hash, putting the result into the Authenticator slot:
md5_final(response-> packet_data + AUTHENTICATOR_OFFSET, &context);
}
else
{
Debug(LDAP_DEBUG_ANY, "A zero-length RADIUS packet? Really? "
"You'd better be debugging in development, my friend.\n");
}
}
//extern FILE *ltiming;
//extern int64_t Nanoseconds(void);
......@@ -137,49 +79,28 @@ SendThePacket( RADIUS_PACKET *response,
return rc;
}
static int
CopyStateAttribute(RADIUS_PACKET *response, RADIUS_PACKET *request)
static void
get_or_create_state_string(char *state_string, RADIUS_PACKET *request)
{
// Find the RATV_State attribute in request, and copy it to response->packet_data
// return 0 if we didn't find one to copy.
int retval = 0;
// RADIUS packet attribute payloads can be no more than 254 bytes. We
// assume that the state_string pointer points to a buffer that is at
// least 255 bytes:
RADIUS_ATTRIBUTE *ra = fetch_attribute_from_packet(request, RATV_State);
if( ra )
{
//Debug( LDAP_DEBUG_TRACE,"Copying RATV_State attribute. DataLength is %d\n", ra->DataLength);
// We found the request's RATV_State attribute
// Update the list of attributes
add_attribute_to_radius_packet( response,
ra->Type,
ra->DataLength,
ra->Data);
retval = 1;
memcpy(state_string, ra->Data, ra->DataLength);
state_string[ra->DataLength] = '\0';
}
return retval;
}
static void
IncorporateStateAttribute(RADIUS_PACKET *response, RADIUS_PACKET *request)
{
if( !CopyStateAttribute(response, request) )
else
{
// We didn't find a State to copy, so we create one.
static unsigned int state_count = 123;
char achState[IDENTIFIER_SIZE];
static unsigned int state_count = 1;
// Use a mutex to safely use and update the state_count
ldap_pvt_thread_mutex_lock( &libradius_mutex );
sprintf(achState,"Symas%6.6dSymas",state_count++);
sprintf(state_string, "Symas%6.6dSymas", state_count++);
ldap_pvt_thread_mutex_unlock( &libradius_mutex );
// And use that string as the RATV_State:
add_attribute_to_radius_packet( response,
RATV_State,
(uint8_t)strlen(achState),
(uint8_t *)achState);
}
}
......@@ -189,6 +110,7 @@ IncorporateStateAttribute(RADIUS_PACKET *response, RADIUS_PACKET *request)
static void
build_response_postamble( RADIUS_PACKET *response,
RADIUS_PACKET *request,
const char *state_string,
const char *shared_secret,
int include_state_attribute )
{
......@@ -203,9 +125,12 @@ build_response_postamble( RADIUS_PACKET *response,
MD5_DIGEST_LENGTH,
message_authenticator);
if( include_state_attribute == INCLUDE_STATE )
if( state_string )
{
IncorporateStateAttribute(response, request);
add_attribute_to_radius_packet( response,
RATV_State,
(uint8_t)strlen(state_string),
(uint8_t *)state_string);
}
// We now know the length of the RADIUS packet:
......@@ -213,9 +138,34 @@ build_response_postamble( RADIUS_PACKET *response,
// With the entire packet built, we can now polish it off by creating the
// MD5 hash and HMAC fields:
AdjustPacketForSending( response, request, shared_secret);
if( response )
{
// Since we are responding to something, we must be a server:
AdjustServerPacketForSending( response, request, shared_secret);
}
else
{
AdjustClientPacketForSending( response, shared_secret);
}
}
static void
server_postamble( RADIUS_PACKET *response,
RADIUS_PACKET *request,
const char *shared_secret,
int include_state_attribute )
{
char state_string[255];
get_or_create_state_string(state_string, request);
build_response_postamble( response,
request,
state_string,
shared_secret,
include_state_attribute);
}
static void
build_md5_challenge(RADIUS_PACKET *response,
RADIUS_PACKET *request,
......@@ -224,7 +174,6 @@ build_md5_challenge(RADIUS_PACKET *response,
{
DENTER;
build_response_preamble(response, get_identifier(request));
// This brings us to the attributes portion of the RADIUS packet we are building.
// The first attribute we are going to build is an EAP-MD5 challenge.
......@@ -244,7 +193,7 @@ build_md5_challenge(RADIUS_PACKET *response,
EAP_CHALLENGE_ATTRIBUTE_LENGTH,
eap_message_data);
build_response_postamble(response, request, shared_secret, INCLUDE_STATE);
server_postamble(response, request, shared_secret, INCLUDE_STATE);
}
static void
......@@ -273,7 +222,7 @@ build_peap_challenge( RADIUS_PACKET *response,
EAP_CHALLENGE_ATTRIBUTE_LENGTH,
eap_message_data);
build_response_postamble(response, request, shared_secret, INCLUDE_STATE);
server_postamble(response, request, shared_secret, INCLUDE_STATE);
}
static void
......@@ -301,7 +250,7 @@ build_ttls_challenge( RADIUS_PACKET *response,
EAP_CHALLENGE_ATTRIBUTE_LENGTH,
eap_message_data);
build_response_postamble(response, request, shared_secret, INCLUDE_STATE);
server_postamble(response, request, shared_secret, INCLUDE_STATE);
}
static int
......@@ -467,6 +416,9 @@ recover_state(RADIUS_INFO *radius_info, RADIUS_PACKET *request)
if( ra )
{
// We found a State identifier. See if it is in our list
// The state identifier does not have a terminating NUL. But we are
// expecting a string, so we make sure we copy over the string from the
// ra in a way that ends it with a NUL:
memset(achIdentifier, 0, IDENTIFIER_SIZE);
memcpy(achIdentifier, ra->Data, ra->DataLength);
Debug( LDAP_DEBUG_ARGS,
......@@ -822,7 +774,7 @@ build_tls_response( RADIUS_PACKET *response,
}
// With the PEAP messages out of the way, finish up the RADIUS packet:
build_response_postamble(response, volatiles->request, volatiles->shared_secret, INCLUDE_STATE);
server_postamble(response, volatiles->request, volatiles->shared_secret, INCLUDE_STATE);
Debug( LDAP_DEBUG_ARGS,
DPREFIX "Built eap_tls response with %d EAP-message attributes\n",
......@@ -907,10 +859,10 @@ encrypt_and_send_response( STATE *state,
attribute_data);
// With the PEAP message out of the way, finish up the RADIUS packet:
build_response_postamble( response,
volatiles->request,
volatiles->shared_secret,
INCLUDE_STATE);
server_postamble( response,
volatiles->request,
volatiles->shared_secret,
INCLUDE_STATE);
rc = SendThePacket( response,
volatiles->radius_info->udp_socket,
......@@ -1659,10 +1611,10 @@ send_access_accept(STATE *state)
sizeof(framed_mtu),
framed_mtu);
build_response_postamble( response,
volatiles->request,
volatiles->shared_secret,
DONT_INCLUDE_STATE);
server_postamble( response,
volatiles->request,
volatiles->shared_secret,
DONT_INCLUDE_STATE);
return SendThePacket( response,
volatiles->radius_info->udp_socket,
......@@ -1702,10 +1654,10 @@ send_access_reject(STATE *state)
eap_message_length,
eap_message_data);
build_response_postamble( response,
volatiles->request,
volatiles->shared_secret,
DONT_INCLUDE_STATE);
server_postamble( response,
volatiles->request,
volatiles->shared_secret,
DONT_INCLUDE_STATE);
return SendThePacket( response,
volatiles->radius_info->udp_socket,
......
......@@ -14,6 +14,7 @@
* <http://www.OpenLDAP.org/license.html>.
*/
#include <openssl/rand.h>
#include "radiusov.h"
#include "lber-int.h"
#include "rpacket.h"
......@@ -610,3 +611,109 @@ build_response_preamble(RADIUS_PACKET *response, uint8_t packet_id)
// calculation is described in RFC2865 section 3; see below
response->build_loc += AUTHENTICATOR_LENGTH;
}
void
AdjustServerPacketForSending( RADIUS_PACKET *response,
RADIUS_PACKET *request,
const char *shared_secret)
{
// Our job is to fill in the data for the Message-Authenticator attribute, which comes first, followed
// by the response->ResponseAuthenticator, which has to come second because it includes
// the hash of the attributes.
// See RFC2865 for the basic radius packet Authenticator field
// See RFC2869 for the Message-Authenticator attribute.
size_t length = get_length(response);
if( length )
{
RADIUS_ATTRIBUTE *ra = fetch_attribute_from_packet( response,
RATV_Message_Authenticator);
if( ra )
{
//Debug( LDAP_DEBUG_TRACE,"We have found the response Message-Authenticator attribute\n" );
// Per RFC2869, section 5.14, the Message-Authenticator sixteen-byte payload is calculated
// this way:
//
// Message-Authenticator = HMAC-MD5 (Type, Identifier, Length, Request Authenticator, Attributes)
//
// For the purposes of the calculation, the sixteen bytes of the Message-Authenticator are set to zero,
// which they are at this point.
MD5_CTX context;
hmac_md5_init( &context, (uint8_t *)shared_secret, strlen(shared_secret) );
hmac_md5_update(&context, response->packet_data, 4); // Type, Identifier, Length
hmac_md5_update(&context, request-> packet_data + AUTHENTICATOR_OFFSET, AUTHENTICATOR_LENGTH);
hmac_md5_update(&context, response->packet_data + ATTRIBUTES_OFFSET, length - ATTRIBUTES_OFFSET);
// Finalize the HMAC-MD5 hash, putting the results into the Message-Authenticator attribute
hmac_md5_final( &context, ra->Data);
}
// With the Message-Authenticator attribute established, we can now calculate the response authenticator:
// Per RFC2865 section 3, the description of Response Authenticator
// ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret)
MD5_CTX context;
md5_init(&context);
// Hash the first four bytes, which are Code, Identifier, and Length
md5_update(&context, response->packet_data + CODE_OFFSET, 1 + 1 + LENGTH_OF_PACKET_LENGTH);
md5_update(&context, request-> packet_data + AUTHENTICATOR_OFFSET, AUTHENTICATOR_LENGTH);
md5_update(&context, response->packet_data + ATTRIBUTES_OFFSET, length - ATTRIBUTES_OFFSET);
md5_update(&context, (uint8_t *)shared_secret, strlen(shared_secret));
// Finalize the MD5 hash, putting the result into the Authenticator slot:
md5_final(response-> packet_data + AUTHENTICATOR_OFFSET, &context);
}
else
{
Debug(LDAP_DEBUG_ANY, "A zero-length RADIUS packet? Really? "
"You'd better be debugging in development, my friend.\n");
}
}
void
AdjustClientPacketForSending( RADIUS_PACKET *request,
const char *shared_secret)
{
// Nomenclature is a bit of a mess. In this routine, we are building
// a RADIUS request packet; when it's done, we'll be sending it to the
// server.
// As per RFC2865, we are going to set the sixteen packet RequestAuthenticator
// bits to a random sequence:
if( RAND_bytes(get_authenticator(request), AUTHENTICATOR_LENGTH) != 1 )
{
printf( "%s(): Something went wrong with RAND_bytes\n",
__func__);
abort();
}
RADIUS_ATTRIBUTE *ra = fetch_attribute_from_packet( request,
RATV_Message_Authenticator);
if( ra )
{
Debug( LDAP_DEBUG_ARGS,
DPREFIX "%s(): RADIUS client packet has a RATV_Message_Authenticator\n",
__func__);
// Per RFC2869, we perform an HMAC-MD5 on the whole packet, but with the
// signature bytes set to zero:
uint8_t save_the_signature[AUTHENTICATOR_LENGTH];
memcpy(save_the_signature, ra->Data, AUTHENTICATOR_LENGTH);
memset(ra->Data, 0, AUTHENTICATOR_LENGTH);
// Calculate the digest
uint8_t digest[MD5_DIGEST_LENGTH];
hmac_md5(digest,
request->packet_data,
get_length(request),
(uint8_t *)shared_secret,
strlen(shared_secret) );
// Restore the original packet:
memcpy(ra->Data, save_the_signature, AUTHENTICATOR_LENGTH);
}
}
......@@ -293,6 +293,7 @@ uint16_t get_length(RADIUS_PACKET *radius_packet);
void set_length(RADIUS_PACKET *radius_packet, int length);
uint8_t *get_authenticator(RADIUS_PACKET *radius_packet);
void debugging_display_of(RADIUS_PACKET *packet);
char * radius_attribute_to_text(RADIUS_ATTRIBUTE *ra, char *buffer, size_t buf_len);
void radius_packet_initialize( RADIUS_PACKET *radius_packet );
......@@ -303,7 +304,11 @@ int radiusov_get_packet_from_request( RADIUS_PACKET *radius_packet,
ssize_t recv_len);
RADIUS_ATTRIBUTE *fetch_attribute_from_packet(RADIUS_PACKET *radius_packet, uint8_t Type);
void add_attribute_to_radius_packet( RADIUS_PACKET *radius_packet, uint8_t Type, uint8_t DataLength, uint8_t *Data);
void debugging_display_of(RADIUS_PACKET *packet);
void AdjustServerPacketForSending( RADIUS_PACKET *response,
RADIUS_PACKET *request,
const char *shared_secret);
void AdjustClientPacketForSending( RADIUS_PACKET *response,
const char *shared_secret);
#endif
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment