From 309ea5b90e2bfad84317ff707546e82ae2623726 Mon Sep 17 00:00:00 2001 From: Lazar Bulic Date: Thu, 10 Oct 2024 12:01:00 +0200 Subject: [PATCH] Quick Patch for CVE-2024-3596 to include Message-Authenticator in all responses --- .../org/tinyradius/packet/RadiusPacket.java | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/src/main/java/org/tinyradius/packet/RadiusPacket.java b/src/main/java/org/tinyradius/packet/RadiusPacket.java index e8f34af1..5536107b 100644 --- a/src/main/java/org/tinyradius/packet/RadiusPacket.java +++ b/src/main/java/org/tinyradius/packet/RadiusPacket.java @@ -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; @@ -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. @@ -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.add(new RadiusAttribute(MESSAGE_AUTHENTICATOR, new byte[16])); + } } byte[] attributes = getAttributeBytes(); @@ -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()); } @@ -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. @@ -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. * @@ -1153,6 +1213,11 @@ protected byte[] getAttributeBytes() throws IOException { */ private MessageDigest md5Digest = null; + /** + * hmacMd5 mac. + */ + private Mac hmacMd5 = null; + /** * Authenticator for this Radius packet. */ @@ -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; + }