问题
According to the release notes of JRE 7u72:
Change in javax.smartcardio.Card.disconnect(boolean reset) method behavior
Prior to the JDK 8u20 and JDK 7u72 releases, the javax.smartcardio.Card.disconnect(boolean reset) method had inverted logic for the 'reset' boolean value passed to it. The card was reset upon a disconnect if false was passed to it and vice versa. Starting with JDK 7u72 and JDK 8u20, the correct behavior as per API documentation has been implemented.
In order to provide backwards compatibility to users who rely on the old behavior, a new system property has been introduced. The following command-line option can be used to enforce the old broken behavior:
-Dsun.security.smartcardio.invertCardReset=true
This property is set by default for 7u72 and later JDK 7 update releases. By default, no behavioral change will be noticed in this area for JDK 7 update releases.
Also the following command-line option can be used to enforce the new correct behavior:
-Dsun.security.smartcardio.invertCardReset=false
This is default for 8u20 and later JDK 8 update releases. In future Java releases, the property will be ignored/disabled and default disconnect method behavior will be as specified by API.
When calling javax.smartcardio.Card.disconnect(true)
the card won't reset even though I have JDK 7u79. When I pass false
or use the option -Dsun.security.smartcardio.invertCardReset=true
to the VM, everything works fine. How could this be? Is an older version of the JRE shipped with JDK 7u79?
回答1:
In my eyes, the JRE behaves as expected.
Having a Java 7 JRE with version > 7u72, you have to call disconnect(false) to reset (by default. This might be overwritten by the system property, you mentioned). Here the reason is, that the bug that you have to call disconnect(false) to actually disconnect is quite old and known, so quite some software adopts and calls disconnect(false) to reset. If Oracle had changed that behavior in some minor release / bug fix, they would have created a security breach for all software projects, who fixed this JRE / JDK bug in their code by calling disconnect(false). For this reason:
By default, no behavioral change will be noticed in this area for JDK 7 update releases.
(which is part of what you quoted from the documentation)
If you have some Java 8 JRE, you have to call disconnect(true) by default, maybe overwritten by the system property.
So, if you now want to create some code, making sure, that your card is going to be reset, which works for java 7 and 8 (and maybe even older and upcomming versions), you have to evaluate, what you have to submit, i.e.:
final static boolean TRUE;
static{
String ven = System.getProperty("java.vendor");
String ver = System.getProperty("java.runtime.version");
String r = System.getProperty("sun.security.smartcardio.invertCardReset");
TRUE=!invertReset(ven, ver, r);
}
static boolean invertReset(String vendor, String version, String reset){
if("Oracle Corporation".equals(vendor)){
String[] javaVersionElements = version.split("\\.|_|-b");
//String discard = javaVersionElements[0];
int major = Integer.parseInt(javaVersionElements[1]);
//String minor = javaVersionElements[2];
int update = Integer.parseInt(javaVersionElements[3]);
//String build = javaVersionElements[4];
// version to small for existing reset property:
if((major == 7 && update<72) || major < 7){
return true;
}
if(null != reset){
// version recent enough and we have property:
return "true".equals(reset);
}else{
// version recent enough, but no property:
return major<8;
}
}
return false;
}
now, you can call card.disconnect(TRUE); and TRUE should be false if required. Please test this carefully before using it. I did not.
Note that I took the version detection/splitting code from the SO article Getting Java version at runtime
来源:https://stackoverflow.com/questions/40460516/behavior-of-javax-smartcardio-card-disconnectboolean-reset-in-jdk-7u79