F-5797: bound DER field lengths in WolfCryptDHPrivateKey PKCS#8 parsing
parent
e314b928b5
commit
f1a011956e
|
|
@ -198,6 +198,10 @@ public class WolfCryptDHPrivateKey implements DHPrivateKey, Destroyable {
|
|||
}
|
||||
pLen = WolfCryptASN1Util.getDERLength(derData, idx);
|
||||
idx += WolfCryptASN1Util.getDERLengthSize(derData, idx);
|
||||
if (pLen < 0 || pLen > derData.length - idx) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid PKCS#8: p length exceeds buffer");
|
||||
}
|
||||
pBytes = new byte[pLen];
|
||||
System.arraycopy(derData, idx, pBytes, 0, pLen);
|
||||
p = new BigInteger(1, pBytes);
|
||||
|
|
@ -210,6 +214,10 @@ public class WolfCryptDHPrivateKey implements DHPrivateKey, Destroyable {
|
|||
}
|
||||
gLen = WolfCryptASN1Util.getDERLength(derData, idx);
|
||||
idx += WolfCryptASN1Util.getDERLengthSize(derData, idx);
|
||||
if (gLen < 0 || gLen > derData.length - idx) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid PKCS#8: g length exceeds buffer");
|
||||
}
|
||||
gBytes = new byte[gLen];
|
||||
System.arraycopy(derData, idx, gBytes, 0, gLen);
|
||||
g = new BigInteger(1, gBytes);
|
||||
|
|
@ -230,6 +238,10 @@ public class WolfCryptDHPrivateKey implements DHPrivateKey, Destroyable {
|
|||
}
|
||||
privLen = WolfCryptASN1Util.getDERLength(derData, idx);
|
||||
idx += WolfCryptASN1Util.getDERLengthSize(derData, idx);
|
||||
if (privLen < 0 || privLen > derData.length - idx) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid PKCS#8: private value length exceeds buffer");
|
||||
}
|
||||
privBytes = new byte[privLen];
|
||||
System.arraycopy(derData, idx, privBytes, 0, privLen);
|
||||
privateVal = new BigInteger(1, privBytes);
|
||||
|
|
@ -382,6 +394,10 @@ public class WolfCryptDHPrivateKey implements DHPrivateKey, Destroyable {
|
|||
}
|
||||
pLen = WolfCryptASN1Util.getDERLength(this.encoded, idx);
|
||||
idx += WolfCryptASN1Util.getDERLengthSize(this.encoded, idx);
|
||||
if (pLen < 0 || pLen > this.encoded.length - idx) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid PKCS#8: p length exceeds buffer");
|
||||
}
|
||||
pBytes = new byte[pLen];
|
||||
System.arraycopy(this.encoded, idx, pBytes, 0, pLen);
|
||||
p = new BigInteger(1, pBytes);
|
||||
|
|
@ -394,6 +410,10 @@ public class WolfCryptDHPrivateKey implements DHPrivateKey, Destroyable {
|
|||
}
|
||||
gLen = WolfCryptASN1Util.getDERLength(this.encoded, idx);
|
||||
idx += WolfCryptASN1Util.getDERLengthSize(this.encoded, idx);
|
||||
if (gLen < 0 || gLen > this.encoded.length - idx) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid PKCS#8: g length exceeds buffer");
|
||||
}
|
||||
gBytes = new byte[gLen];
|
||||
System.arraycopy(this.encoded, idx, gBytes, 0, gLen);
|
||||
g = new BigInteger(1, gBytes);
|
||||
|
|
@ -486,6 +506,10 @@ public class WolfCryptDHPrivateKey implements DHPrivateKey, Destroyable {
|
|||
}
|
||||
privLen = WolfCryptASN1Util.getDERLength(this.encoded, idx);
|
||||
idx += WolfCryptASN1Util.getDERLengthSize(this.encoded, idx);
|
||||
if (privLen < 0 || privLen > this.encoded.length - idx) {
|
||||
throw new IllegalStateException(
|
||||
"Invalid PKCS#8: private value length exceeds buffer");
|
||||
}
|
||||
privBytes = new byte[privLen];
|
||||
System.arraycopy(this.encoded, idx, privBytes, 0, privLen);
|
||||
privateVal = new BigInteger(1, privBytes);
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ import org.junit.Assume;
|
|||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import com.wolfssl.provider.jce.WolfCryptProvider;
|
||||
import com.wolfssl.provider.jce.WolfCryptDHPublicKey;
|
||||
import com.wolfssl.wolfcrypt.FeatureDetect;
|
||||
|
|
@ -490,6 +491,44 @@ public class WolfCryptDHKeyFactoryTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPKCS8RejectsOversizedDERFieldLength() throws Exception {
|
||||
|
||||
Assume.assumeTrue(FeatureDetect.DhEnabled());
|
||||
|
||||
KeyFactory kf = KeyFactory.getInstance("DH", "wolfJCE");
|
||||
|
||||
/* PKCS#8 that parses up to the p INTEGER, whose length is a 4-byte
|
||||
* long-form 0x7FFFFFFF. Guard must reject it as a clean
|
||||
* InvalidKeySpecException instead. */
|
||||
byte[] malicious = new byte[] {
|
||||
(byte)0x30, (byte)0x30,
|
||||
(byte)0x02, (byte)0x01, (byte)0x00,
|
||||
(byte)0x30, (byte)0x03,
|
||||
(byte)0x06, (byte)0x01, (byte)0x2A,
|
||||
(byte)0x30, (byte)0x09,
|
||||
(byte)0x02,
|
||||
(byte)0x84, (byte)0x7F, (byte)0xFF, (byte)0xFF, (byte)0xFF
|
||||
};
|
||||
|
||||
try {
|
||||
kf.generatePrivate(new PKCS8EncodedKeySpec(malicious));
|
||||
fail("Should reject PKCS#8 with oversized DER field length");
|
||||
|
||||
} catch (InvalidKeySpecException e) {
|
||||
/* Expected */
|
||||
}
|
||||
|
||||
/* Positive test: a well-formed key still parses */
|
||||
if (enabledKeySizes.contains(2048)) {
|
||||
KeyPairGenerator kpg =
|
||||
KeyPairGenerator.getInstance("DH", "wolfJCE");
|
||||
kpg.initialize(2048);
|
||||
byte[] valid = kpg.generateKeyPair().getPrivate().getEncoded();
|
||||
assertNotNull(kf.generatePrivate(new PKCS8EncodedKeySpec(valid)));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDHPublicKeySpecRangeValidation() throws Exception {
|
||||
|
||||
|
|
@ -994,5 +1033,56 @@ public class WolfCryptDHKeyFactoryTest {
|
|||
assertEquals("Public key p should match",
|
||||
originalPub.getParams().getP(), roundTripPubDH.getParams().getP());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the cached DER of a key and clear its lazily-extracted fields,
|
||||
* so the next getter re-parses the supplied bytes. Mirrors the state a
|
||||
* key is left in after deserialization, where transient caches are null
|
||||
* but the encoded form is populated.
|
||||
*/
|
||||
private static void resetEncoded(Object key, byte[] der,
|
||||
String... cacheFields) throws Exception {
|
||||
|
||||
Field enc = key.getClass().getDeclaredField("encoded");
|
||||
enc.setAccessible(true);
|
||||
enc.set(key, der);
|
||||
|
||||
for (String name : cacheFields) {
|
||||
Field f = key.getClass().getDeclaredField(name);
|
||||
f.setAccessible(true);
|
||||
f.set(key, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrivateKeyLazyExtractRejectsOversizedLength()
|
||||
throws Exception {
|
||||
|
||||
Assume.assumeTrue(FeatureDetect.DhEnabled());
|
||||
Assume.assumeTrue(enabledKeySizes.contains(2048));
|
||||
|
||||
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DH", "wolfJCE");
|
||||
kpg.initialize(2048);
|
||||
DHPrivateKey priv = (DHPrivateKey)kpg.generateKeyPair().getPrivate();
|
||||
|
||||
/* PKCS#8 variant, adds the version INTEGER ahead of the params */
|
||||
byte[] oversizedPkcs8 = new byte[] {
|
||||
(byte)0x30, (byte)0x30,
|
||||
(byte)0x02, (byte)0x01, (byte)0x00,
|
||||
(byte)0x30, (byte)0x03,
|
||||
(byte)0x06, (byte)0x01, (byte)0x2A,
|
||||
(byte)0x30, (byte)0x09,
|
||||
(byte)0x02,
|
||||
(byte)0x84, (byte)0x7F, (byte)0xFF, (byte)0xFF, (byte)0xFF
|
||||
};
|
||||
|
||||
resetEncoded(priv, oversizedPkcs8, "paramSpec", "privateValue");
|
||||
|
||||
try {
|
||||
priv.getParams();
|
||||
fail("getParams() should reject an oversized DER length");
|
||||
} catch (IllegalStateException e) {
|
||||
/* expected */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue