From 15607271455f0ba459487643ee9c0e6b1b6a1e87 Mon Sep 17 00:00:00 2001 From: george-mcintyre Date: Wed, 15 Apr 2026 13:25:47 +0200 Subject: [PATCH] Fix double-layered DER encoding in certificate extension decoding --- .../org/epics/pva/common/SecureSockets.java | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/core/pva/src/main/java/org/epics/pva/common/SecureSockets.java b/core/pva/src/main/java/org/epics/pva/common/SecureSockets.java index d15d54957b..b7583b2ff9 100644 --- a/core/pva/src/main/java/org/epics/pva/common/SecureSockets.java +++ b/core/pva/src/main/java/org/epics/pva/common/SecureSockets.java @@ -274,8 +274,13 @@ public static String decodeDERString(final byte[] der_value) throws Exception { if (der_value == null) return ""; - // https://en.wikipedia.org/wiki/X.690#DER_encoding: - // Type 4, length 0..127, characters + // X509Certificate.getExtensionValue() returns a DER OCTET STRING + // that wraps the actual extension content. + // The extension content itself is a DER-encoded string + // (OCTET STRING 0x04 or UTF8String 0x0C), so we must unwrap two layers: + // Outer: 0x04 + // Inner: 0x04|0x0C + // https://en.wikipedia.org/wiki/X.690#DER_encoding if (der_value.length < 2) throw new Exception("Need DER type and size, only received " + der_value.length + " bytes"); if (der_value[0] != 0x04) @@ -284,7 +289,20 @@ public static String decodeDERString(final byte[] der_value) throws Exception throw new Exception("Can only handle strings of length 0-127, got " + der_value[1]); if (der_value[1] != der_value.length-2) throw new Exception("DER string length " + der_value[1] + " but " + (der_value.length-2) + " data items"); - return new String(der_value, 2, der_value[1]); + + // Unwrap outer OCTET STRING to get the inner DER-encoded string + final int inner_offset = 2; + final int inner_len = der_value.length - 2; + if (inner_len < 2) + throw new Exception("Inner DER too short: " + inner_len + " bytes"); + final byte inner_tag = der_value[inner_offset]; + // Accept OCTET STRING (0x04), UTF8String (0x0C), or IA5String (0x16) as inner type + if (inner_tag != 0x04 && inner_tag != 0x0C && inner_tag != 0x16) + throw new Exception(String.format("Expected inner DER string type 0x04, 0x0C, or 0x16, got 0x%02X", inner_tag)); + final int str_len = der_value[inner_offset + 1] & 0xFF; + if (str_len != inner_len - 2) + throw new Exception("Inner DER string length " + str_len + " but " + (inner_len-2) + " data bytes"); + return new String(der_value, inner_offset + 2, str_len); } /** Get CN from principal