-
Bug
-
Resolution: Fixed
-
P4
-
8, 11, 17, 18, 19
-
b06
-
generic
-
generic
-
Not verified
A DESCRIPTION OF THE PROBLEM :
sun.security.x509.X509CertImpl.delete("x509.info.validity") nulls out info field instead of calling info.delete("validity").
Look at the lines 744-748, https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/sun/security/x509/X509CertImpl.java#L744
if (attr.getSuffix() != null) {
info = null;
} else {
info.delete(attr.getSuffix());
}
It seems like the if condition should be negated (or "if" branches swapped) in order to do the right thing.
I understand the client is not normally expected to call this code, because X509CertImpl instance is supposed to remain read-only once initialized from the certificate content.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Initialize X509CertImpl by calling:
X509CertImpl x509CertImpl = (X509CertImpl) CertificateFactory.getInstance("X.509").generateCertificate(<certficate-input-stream>);
disable readOnly flag with:
Field readOnlyField = X509CertImpl.class.getDeclaredField("readOnly");
readOnlyField.setAccessible(true);
readOnlyField.set(x509CertImpl, false);
then execute:
x509CertImpl.delete(X509CertImpl.NAME + "." + X509CertImpl.INFO + "." + X509CertInfo.VALIDITY);
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expect that "validity" field gets "deleted", i.e. null-ed out.
ACTUAL -
Instead null-ing happens to the "info" field, one level higher in the hierarchy of the qualified name given.
---------- BEGIN SOURCE ----------
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateFactory;
public class X509CertImplTest {
public static void main(String[] args) throws Exception {
final String cert = "-----BEGIN CERTIFICATE-----\n" +
"MIIBLjCB1qADAgECAgEBMAoGCCqGSM49BAMCMBIxEDAOBgNVBAMMB2xvY2FsQ0Ew\n" +
"HhcNMjIwMzEwMjMyMjU2WhcNMjIwMzExMjMyMjU2WjAUMRIwEAYDVQQDDAlsb2Nh\n" +
"bGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATSJzFRm9VrWVhcvrb6k/ql\n" +
"PvlhDQdNnUkx9v/LmvoLmM8Wqpw7+805V9ke51P/UbB3UreprwY0SEV18URYY/fM\n" +
"oxswGTAXBgNVHREBAf8EDTALgglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDRwAwRAIg\n" +
"aKRZuRQR+JJCLwqyr5Xbww6fHSBJuxk/63nNxx/yJzECICJZEuDo4a0gL6BprdEK\n" +
"06U7+ookw2vCAy99Qc9p34T4\n" +
"-----END CERTIFICATE-----\n";
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
ByteArrayInputStream inStream = new ByteArrayInputStream(cert.getBytes(StandardCharsets.US_ASCII));
X509CertImpl x509CertImpl = (X509CertImpl) certificateFactory.generateCertificate(inStream);
//disable readOnly flag
Field readOnlyField = X509CertImpl.class.getDeclaredField("readOnly");
readOnlyField.setAccessible(true);
readOnlyField.set(x509CertImpl, false);
//act
x509CertImpl.delete(X509CertImpl.NAME + "." + X509CertImpl.INFO + "." + X509CertInfo.VALIDITY);
X509CertInfo info = (X509CertInfo) x509CertImpl.get(X509CertImpl.NAME + "." + X509CertImpl.INFO);
assert info != null; // assertion fails if assertions are enabled
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
None.
FREQUENCY : always
sun.security.x509.X509CertImpl.delete("x509.info.validity") nulls out info field instead of calling info.delete("validity").
Look at the lines 744-748, https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/sun/security/x509/X509CertImpl.java#L744
if (attr.getSuffix() != null) {
info = null;
} else {
info.delete(attr.getSuffix());
}
It seems like the if condition should be negated (or "if" branches swapped) in order to do the right thing.
I understand the client is not normally expected to call this code, because X509CertImpl instance is supposed to remain read-only once initialized from the certificate content.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Initialize X509CertImpl by calling:
X509CertImpl x509CertImpl = (X509CertImpl) CertificateFactory.getInstance("X.509").generateCertificate(<certficate-input-stream>);
disable readOnly flag with:
Field readOnlyField = X509CertImpl.class.getDeclaredField("readOnly");
readOnlyField.setAccessible(true);
readOnlyField.set(x509CertImpl, false);
then execute:
x509CertImpl.delete(X509CertImpl.NAME + "." + X509CertImpl.INFO + "." + X509CertInfo.VALIDITY);
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expect that "validity" field gets "deleted", i.e. null-ed out.
ACTUAL -
Instead null-ing happens to the "info" field, one level higher in the hierarchy of the qualified name given.
---------- BEGIN SOURCE ----------
import sun.security.x509.X509CertImpl;
import sun.security.x509.X509CertInfo;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateFactory;
public class X509CertImplTest {
public static void main(String[] args) throws Exception {
final String cert = "-----BEGIN CERTIFICATE-----\n" +
"MIIBLjCB1qADAgECAgEBMAoGCCqGSM49BAMCMBIxEDAOBgNVBAMMB2xvY2FsQ0Ew\n" +
"HhcNMjIwMzEwMjMyMjU2WhcNMjIwMzExMjMyMjU2WjAUMRIwEAYDVQQDDAlsb2Nh\n" +
"bGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATSJzFRm9VrWVhcvrb6k/ql\n" +
"PvlhDQdNnUkx9v/LmvoLmM8Wqpw7+805V9ke51P/UbB3UreprwY0SEV18URYY/fM\n" +
"oxswGTAXBgNVHREBAf8EDTALgglsb2NhbGhvc3QwCgYIKoZIzj0EAwIDRwAwRAIg\n" +
"aKRZuRQR+JJCLwqyr5Xbww6fHSBJuxk/63nNxx/yJzECICJZEuDo4a0gL6BprdEK\n" +
"06U7+ookw2vCAy99Qc9p34T4\n" +
"-----END CERTIFICATE-----\n";
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
ByteArrayInputStream inStream = new ByteArrayInputStream(cert.getBytes(StandardCharsets.US_ASCII));
X509CertImpl x509CertImpl = (X509CertImpl) certificateFactory.generateCertificate(inStream);
//disable readOnly flag
Field readOnlyField = X509CertImpl.class.getDeclaredField("readOnly");
readOnlyField.setAccessible(true);
readOnlyField.set(x509CertImpl, false);
//act
x509CertImpl.delete(X509CertImpl.NAME + "." + X509CertImpl.INFO + "." + X509CertInfo.VALIDITY);
X509CertInfo info = (X509CertInfo) x509CertImpl.get(X509CertImpl.NAME + "." + X509CertImpl.INFO);
assert info != null; // assertion fails if assertions are enabled
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
None.
FREQUENCY : always