Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions src/main/java/org/tinyradius/packet/RadiusPacket.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
Expand All @@ -28,6 +29,9 @@
import org.tinyradius.util.RadiusException;
import org.tinyradius.util.RadiusUtil;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

/**
* This class represents a Radius packet. Subclasses provide convenience methods
* for special packet types.
Expand Down Expand Up @@ -848,6 +852,21 @@ protected void encodePacket(OutputStream out, String sharedSecret, RadiusPacket
// (User-Password attribute needs the authenticator)
authenticator = createRequestAuthenticator(sharedSecret);
encodeRequestAttributes(sharedSecret);
} else {
//To mitigate CVE-2024-3596 we MUST add Message-Authenticator attribute to all responses
boolean exists = false;
for (Iterator i = this.attributes.iterator(); i.hasNext(); ) {
RadiusAttribute a = (RadiusAttribute) i.next();
//If already present in the packet we need to set it to sixteen octets of zero
if (a.getVendorId() == -1 && a.getAttributeType() == MESSAGE_AUTHENTICATOR) {
a.setAttributeData(new byte[16]);
exists = true;
break;
}
}
if (!exists) {
this.attributes.addFirst(new RadiusAttribute(MESSAGE_AUTHENTICATOR, new byte[16]));
}
}

byte[] attributes = getAttributeBytes();
Expand All @@ -857,6 +876,18 @@ protected void encodePacket(OutputStream out, String sharedSecret, RadiusPacket

// response packet authenticator
if (request != null) {
try {
//calculate Message-Authenticator according to RFC2869
byte[] messageAuthenticator = createResponseMessageAuthenticator(sharedSecret, packetLength, attributes, request.getAuthenticator());
for (Iterator i = this.attributes.iterator(); i.hasNext();) {
RadiusAttribute a = (RadiusAttribute) i.next();
if (a.getVendorId() == -1 && a.getAttributeType() == MESSAGE_AUTHENTICATOR) {
a.setAttributeData(messageAuthenticator);
}
}
} catch (InvalidKeyException ex) {
new RuntimeException("failed to create message authenticator", ex);
}
// after encoding attributes, create authenticator
authenticator = createResponseAuthenticator(sharedSecret, packetLength, attributes, request.getAuthenticator());
}
Expand Down Expand Up @@ -948,6 +979,19 @@ protected byte[] createResponseAuthenticator(String sharedSecret, int packetLeng
return md5.digest();
}

protected byte[] createResponseMessageAuthenticator(String sharedSecret, int packetLength, byte[] attributes, byte[] requestAuthenticator) throws InvalidKeyException {
Mac hmacMd5 = getHmacMd5();
hmacMd5.reset();
hmacMd5.init(new SecretKeySpec(sharedSecret.getBytes(), hmacMd5.getAlgorithm()));
hmacMd5.update((byte) getPacketType());
hmacMd5.update((byte) getPacketIdentifier());
hmacMd5.update((byte) (packetLength >> 8));
hmacMd5.update((byte) (packetLength & 0x0ff));
hmacMd5.update(requestAuthenticator, 0, requestAuthenticator.length);
hmacMd5.update(attributes, 0, attributes.length);
return hmacMd5.doFinal();
}

/**
* Reads a Radius packet from the given input stream and
* creates an appropiate RadiusPacket descendant object.
Expand Down Expand Up @@ -1116,6 +1160,22 @@ protected MessageDigest getMd5Digest() {
return md5Digest;
}

/**
* Returns a MD5 digest.
*
* @return MessageDigest object
*/
protected Mac getHmacMd5() {
if (hmacMd5 == null)
try {
hmacMd5 = Mac.getInstance("HmacMD5");
}
catch (NoSuchAlgorithmException nsae) {
throw new RuntimeException("Hmac is not available", nsae);
}
return hmacMd5;
}

/**
* Encodes the attributes of this Radius packet to a byte array.
*
Expand Down Expand Up @@ -1153,6 +1213,11 @@ protected byte[] getAttributeBytes() throws IOException {
*/
private MessageDigest md5Digest = null;

/**
* hmacMd5 mac.
*/
private Mac hmacMd5 = null;

/**
* Authenticator for this Radius packet.
*/
Expand All @@ -1173,4 +1238,13 @@ protected byte[] getAttributeBytes() throws IOException {
*/
private static SecureRandom random = new SecureRandom();

/**
* Radius attribute type for MS-CHAP-Challenge attribute.
*/

/**
* Radius attribute type for Message-Authenticator attribute.
*/
private static final int MESSAGE_AUTHENTICATOR = 80;

}
Loading