CertificateException when generateCertificate()

2019-03-22 06:29发布

I am developing my android app. I am trying to generate the X509Certificate instance from my certificate file stream, but get CertificateException , here is my simple code:

import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
...
public class CertMgr {
   //my certification file 'mycert.p12' located in my app internal storage
   File certFile = GET_CERT();

   X509Certificate cert = null;
   try {

      FileInputStream fis = new FileInputStream(certFile);
      BufferedInputStream bis = new BufferedInputStream(fis);

      CertificateFactory cf = CertificateFactory.getInstance("X.509"); 

      if(bis.available() > 0){
           //I got CertificateException here, see the stack trace
          cert = (X509Certificate) cf.generateCertificate(bis); //line nr 150
      }
   }catch(...)
      {...}
 ...
}

stack trace:

javax.security.cert.CertificateException: org.apache.harmony.security.asn1.ASN1Exception: ASN.1 Sequence: mandatory value is missing at [4]
11-11 17:30:20.731: W/System.err(11529):    at javax.security.cert.X509Certificate.getInstance(X509Certificate.java:94)
11-11 17:30:20.731: W/System.err(11529):    at javax.security.cert.X509Certificate.getInstance(X509Certificate.java:213)
11-11 17:30:20.731: W/System.err(11529):    at com.my.app.CertMgr.getCert(CertMgr.java:150)

Could someone please explain to me why I get this exception?

P.S.: Here are the classes I am using from Android SDK X509Certificate , CertificateFactory

If you are curious about why I am doing this, the reason is that I want my app to be able to install the certificate(mycert.p12) by the following code (if above code is working properly):

Intent installIntent = KeyChain.createInstallIntent();

installIntent.putExtra(KeyChain.EXTRA_CERTIFICATE, cert.getEncoded());
installIntent.putExtra(KeyChain.EXTRA_NAME, MY_CERT);
startActivityForResult(installIntent, INSTALL_KEYCHAIN_CODE);

1条回答
爷的心禁止访问
2楼-- · 2019-03-22 06:52

You are trying to read a PKCS#12 data structure as it was a X509 certificate. The PKCS#12 standard specifies a data structure which can bundle multiple certificates and private keys, optionally protected by a password.

In order to read the PKCS#12 data you need to load it with a KeyStore. This code snippet show how list all entries of the PCKS#12 file:

KeyStore keyStore = KeyStore.getInstance("PKCS12");
File p12File = GET_CERT();
FileInputStream fis = new FileInputStream(p12File);
BufferedInputStream bis = new BufferedInputStream(fis);
keyStore.load(bis, password.toCharArray()); // password is the PKCS#12 password. If there is no password, just pass null
Enumeration<String> aliases = keyStore.aliases();
while (aliases.hasMoreElements()) {
    String alias = aliases.nextElement();
    /* Do something with the keystore entry */
}

KeyStore entries can be private key, with or without an associated certificate chain (i.e. a sequence of certificate from the root certificate to the certificate corresponding to the private key), or a trusted certificate. You can determine the entry type by the KeyStore.isKeyEntry and KeyStore.isCertificateEntry methods.

According to the KeyChain intent you gave, it seems you want to add a new trusted Root CA certificate in the key chain. Therefore I think you should list the certificate entries of the PKCS#12 file.

EDIT (12th nov 2013)

How to get a trusted certificate from the keystore:

String alias = aliases.nextElement();
if (keyStore.isCertificateEntry(alias)) { // keep only trusted cert entries
    Certificate caCert = keyStore.getCertificate(alias)
    byte[] extraCertificate = caCert.getEncoded();
    Intent installIntent = KeyChain.createInstallIntent();
    installIntent.putExtra(KeyChain.EXTRA_CERTIFICATE, extraCertificate);
    installIntent.putExtra(KeyChain.EXTRA_NAME, MY_CERT);
    startActivityForResult(installIntent, INSTALL_KEYCHAIN_CODE);
}
查看更多
登录 后发表回答