Validate when keystore.load() is canceled - java

I need to write an applet that reads info from smartcards, I based my script on the code example provided by #Jovo Krneta here.
My concern is about this specific piece of code:
keyStore.load(null, null); // opens the windows security window
Enumeration<String> enums = keyStore.aliases(); // looks for local certificates
while (enums.hasMoreElements()) {
this.jComboBox1.addItem((String) enums.nextElement());
}
I'm finding it hard to find a way to validate if the user clicked on Cancel once the window is opened.
My question is if exists something like
keyStore.load(null, null);
if(keyStore.canceled()){
// do nothing
}else{
Enumeration<String> enums = keyStore.aliases(); // looks for local certificates
while (enums.hasMoreElements()) {
this.jComboBox1.addItem((String) enums.nextElement());
}
}

Related

empty keyStore in crypto

I'm using wss4j in order to sign a message request.
But when signing the message with this code:
Document d = signer.build(unsignedDoc, crypto, header)
I always get the error
org.apache.ws.security.WSSecurityException: General security error (no certificates for user ... were found for signature)
Searching for the cause I found out, that en empty key store seems to be the reason for this.
This is how I create a crypto instance:
private void createCrypto(){
// reading preferences (keystone-filename, password, etc.) from properties file
Properties prop = new Properties();
FileInputStream fis = new FileInputStream("myprops.properties");
props.load(fis);
// create a crypto instance
Crypto crypto = CryptoFactory.getInstance(props);
// This line always prints "Size:0"
System.out.println("Size:" + crypto.getKeyStore.getSize())
...
But if I load the Keystore the following way, it shows size=1:
private void loadKeystore(){
KeyStore keystore;
try{
// reading and loading keystone file
InputStream is = new FileInputStream("myKeyStore.jks");
keystore.load(is, "password".toCharArray());
// Prints "Size:1"
System.out.println("Size:"+keystore.size());
...
So I wonder, what is wrong with the first example. Why is the keystore empty?
I already checked the properties: keystore and password are set correctly!
But if I remove the keystore-property from the properties-file, the error message is the same.
Can anyone help me with this?

"Windows-MY" Keystore won't list all available aliases

I have a problem listing all available certificates installed in my personal (windows) keystore.
I use following code to get a list of all certificate aliases:
public static void main(String[] args) {
try {
KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);
Enumeration<String> en = ks.aliases();
while (en.hasMoreElements()) {
String aliasKey = (String) en.nextElement();
System.out.println("---> alias '" + aliasKey + "'");
//TODO GET CERT ETC
}
} catch (Exception ioe) {
System.err.println(ioe.getMessage());
}
}
It works fine, listing 2 of my recently installed certificates.
HOWEVER.
After a computer restart, code lists only one certificate alias, though in system (using certmgr.msc) i still have two certificates active.
Whats more - installed certificates are from smartcards:
- ENCARD (with ENIGMA CAPI)
- UNIZETO CARD (dont know details)
Problem seems to occur, when i use ENCARD with API.
After restart, UNIZETO card still works fine.
Any ideas?

JRuby equivalent of Java Code

How could I express this java code in JRuby:
// Convert the store to a certificate chain
CertStore store = response.getCertStore();
Collection<? extends Certificate> certs = store
.getCertificates(null);
Certificate[] chain = new Certificate[certs.size()];
int i = 0;
for (Certificate certificate : certs) {
chain[i++] = certificate;
}
I have the "store" within JRuby and its recognised as a collection.
e.g.
puts store.type
#Collection
OK so the problem here is that I was passing in a regular expression and not a CertSelector object.
This code now works as expected.
store.get_certificates(nil)

Disable hostname verification in hsqldb

I have a tomcat-hibernate-hsqldb setup and I want to use SSL to secure data transfer between my application and hsqldb. However, I need to pre install a certificate which can be used at any deployment. I do not want to use a new certificate for each new deployment site. For this, if I just use a self-signed certificate issues to any random Common Name and then install the same certificate in the trust store of tomcat, then I get this exception
java.net.UnknownHostException: Certificate Common Name[random name] does not match host name[192.168.100.10]
I need to disable hostname verification in this setup, but all the info I found on web points to the mechanism of disabling it for HttpsURLConnection.
I believe hsqldb has a custom code to do it, in the file
org.hsqldb.serverHsqlSocketFactorySecure
Here is the method, which does this:
protected void verify(String host, SSLSession session) throws Exception {
X509Certificate[] chain;
X509Certificate certificate;
Principal principal;
PublicKey publicKey;
String DN;
String CN;
int start;
int end;
String emsg;
chain = session.getPeerCertificateChain();
certificate = chain[0];
principal = certificate.getSubjectDN();
DN = String.valueOf(principal);
start = DN.indexOf("CN=");
if (start < 0) {
throw new UnknownHostException(
Error.getMessage(ErrorCode.M_SERVER_SECURE_VERIFY_1));
}
start += 3;
end = DN.indexOf(',', start);
CN = DN.substring(start, (end > -1) ? end
: DN.length());
if (CN.length() < 1) {
throw new UnknownHostException(
Error.getMessage(ErrorCode.M_SERVER_SECURE_VERIFY_2));
}
if (!CN.equalsIgnoreCase(host)) {
// TLS_HOSTNAME_MISMATCH
throw new UnknownHostException(
Error.getMessage(
ErrorCode.M_SERVER_SECURE_VERIFY_3, 0,
new Object[] {
CN, host
}));
}
}
Is there a way to somehow bypass this mechanism and disable hostname validation?
Asked the same question on hsqldb forums and got to know that there is no workaround to this. The only thing you could do is to comment out the code which is calling the verify method and then rebuild the jar. I am still puzzled why hsqldb didn't use the HostnameVerifier (http://docs.oracle.com/javase/6/docs/api/javax/net/ssl/HostnameVerifier.html), which would have made it easier to write a custom Hostname Verifier.

Implement signature-level security on Android services with more than one allowed signature

I'm developing on an application at the moment which contains quite a lot of personal user information - things like Facebook contacts, etc ... Now, one of the things I want to be able to do (and have done, quite effectively) is open up parts of the application to "3rd Party" applications, using Android's build-in inter-process communication protocol (AIDL). So far so good.
Here's the catch: because we're involved in handling quite a lot of personal information, we have to be quite careful about who can and can't access it; specifically, only "Trusted" applications should be able to do so. So the natural way to do this is to use a custom permission within the AndroidManifest.xml file where we declare the services. My problem is this: I want to be able to enact signature-level protection (similar to the normal "signature" permission level), but with a bit of a catch:
I don't only want application signed with our internal signature to be able to access the services. I'd like to be able to build a list of "trusted signatures" & at runtime (or if there's a better way, then maybe some other time?) be able to check incoming requests against this list of trusted keys.
This would satisfy the security constraints in the same way as the normal "signature" permission level I think - only programs on the "trusted keys list" would be able to access the services, and keys are hard to spoof (if possible at all?) - but with the added bonus that we wouldn't have to sign every application making use of the APIs with our internal team's key.
Is this possible at the moment in Android? And if so, are there any special requirements?
Thanks
I've now found the answer to this question, but I'll leave it for the sake of anyone looking in the future.
I opened up a discussion on android-security-discuss where it was answered. Link: http://groups.google.com/group/android-security-discuss/browse_thread/thread/e01f63c2c024a767
Short answer:
private boolean checkAuthorised(){
PackageManager pm = getPackageManager();
try {
for (Signature sig :
pm.getPackageInfo(pm.getNameForUid(getCallingUid()),
PackageManager.GET_SIGNATURES).signatures){
LogUtils.logD("Signature: " + sig.toCharsString());
if (Security.trustedSignatures.get(sig.toCharsString()) != null) {
return true;
}
}
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
LogUtils.logD("Couldn't find signature in list of trusted keys! Possibilities:");
for(String sigString : Security.trustedSignatures.keySet()){
LogUtils.logD(sigString);
}
/* Crash the calling application if it doesn't catch */
throw new SecurityException();
}
Where Security.trustedSignatures is a Map of the form:
Map<String,String>().put("public key","some description eg. name");
Put this method inside any code that is being called by the external process (ie. within your interface). Note that this will not have the desired effect inside the onBind() method of your RemoteService.
Great info jelford, but I would suggest instead of storing the entire string of the signature, to store/compare the SHA-1 of the certificate as shown in this answer from matreshkin.
This is similar to how Google handles the Maps Android API, and this will match the output shown via keytool.
private boolean checkAuthorized() throws SecurityException {
PackageManager pm = getPackageManager();
try {
PackageInfo packageInfo = pm.getPackageInfo(pm.getNameForUid(getCallingUid()),
PackageManager.GET_SIGNATURES);
Signature[] signatures = packageInfo.signatures;
byte[] certBytes = signatures[0].toByteArray();
CertificateFactory cf = CertificateFactory.getInstance("X509");
X509Certificate cert = (X509Certificate)cf.generateCertificate(
new ByteArrayInputStream(certBytes));
MessageDigest md = MessageDigest.getInstance("SHA1");
byte[] encodedCert = md.digest(cert.getEncoded());
String hexString = byte2HexFormatted(encodedCert);
Log.d("public certificate SHA-1: " + hexString);
String trustedAppName = trustedCerts.get(hexString);
if (trustedAppName != null) {
Log.d("Found public certificate SHA-1 for " + trustedAppName);
return true;
}
} catch (Exception e) {
Log.e(e, "Unable to get certificate from client");
}
Log.w("Couldn't find signature in list of trusted certs!");
/* Crash the calling application if it doesn't catch */
throw new SecurityException();
}
public static String byte2HexFormatted(byte[] arr) {
StringBuilder str = new StringBuilder(arr.length * 2);
for (int i = 0; i < arr.length; i++) {
String h = Integer.toHexString(arr[i]);
int l = h.length();
if (l == 1) h = "0" + h;
if (l > 2) h = h.substring(l - 2, l);
str.append(h.toUpperCase());
if (i < (arr.length - 1)) str.append(':');
}
return str.toString();
}

Categories