由于三星设备非常糟糕,我转而使用 GenyMotion 作为 Android 模拟器。但是,在我拥有的三星 Note 上运行的代码在模拟器上因 NoClassDefFoundError 而崩溃。
06-10 09:02:15.630: E/AndroidRuntime(2231): FATAL EXCEPTION: main
06-10 09:02:15.630: E/AndroidRuntime(2231): java.lang.NoClassDefFoundError: org.bouncycastle.asn1.ASN1Primitive
06-10 09:02:15.630: E/AndroidRuntime(2231): at org.bouncycastle.pkcs.PKCS10CertificationRequest.parseBytes(Unknown Source)
06-10 09:02:15.630: E/AndroidRuntime(2231): at org.bouncycastle.pkcs.PKCS10CertificationRequest.<init>(Unknown Source)
06-10 09:02:15.630: E/AndroidRuntime(2231): at org.bouncycastle.openssl.PEMParser$PKCS10CertificationRequestParser.parseObject(Unknown Source)
06-10 09:02:15.630: E/AndroidRuntime(2231): at org.bouncycastle.openssl.PEMParser.readObject(Unknown Source)
06-10 09:02:15.630: E/AndroidRuntime(2231): at com.example.MyFragment.convertPemToPKCS10CertificationRequest(MyFragment.java:254)
06-10 09:02:15.630: E/AndroidRuntime(2231): at com.example.MyFragment.testReadCertificateSigningRequest(MyFragment.java:145)
06-10 09:02:15.630: E/AndroidRuntime(2231): at com.example.MyFragment.onClick(MyFragment.java:87)
06-10 09:02:15.630: E/AndroidRuntime(2231): at android.view.View.performClick(View.java:2485)
06-10 09:02:15.630: E/AndroidRuntime(2231): at android.view.View$PerformClick.run(View.java:9080)
06-10 09:02:15.630: E/AndroidRuntime(2231): at android.os.Handler.handleCallback(Handler.java:587)
06-10 09:02:15.630: E/AndroidRuntime(2231): at android.os.Handler.dispatchMessage(Handler.java:92)
06-10 09:02:15.630: E/AndroidRuntime(2231): at android.os.Looper.loop(Looper.java:130)
06-10 09:02:15.630: E/AndroidRuntime(2231): at android.app.ActivityThread.main(ActivityThread.java:3683)
06-10 09:02:15.630: E/AndroidRuntime(2231): at java.lang.reflect.Method.invokeNative(Native Method)
06-10 09:02:15.630: E/AndroidRuntime(2231): at java.lang.reflect.Method.invoke(Method.java:507)
06-10 09:02:15.630: E/AndroidRuntime(2231): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
06-10 09:02:15.630: E/AndroidRuntime(2231): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
06-10 09:02:15.630: E/AndroidRuntime(2231): at dalvik.system.NativeStart.main(Native Method)
我也尝试过不同的版本,它并没有真正帮助,事实上,PEMParser 显然在 1.47 中甚至不可用。代码如下:
private final String csrPEM = "-----BEGIN CERTIFICATE REQUEST-----\n"
+ "MIICwjCCAaoCAQAwfTELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0Zsb3JpZGExEzAR\n"
+ "BgNVBAcTCkJvY2EgUmF0b24xGzAZBgNVBAoTEkxvb25leSBUb29ucywgSW5jLjEU\n"
+ "MBIGA1UECxMLRGV2ZWxvcG1lbnQxFDASBgNVBAMTC2V4YW1wbGUuY29tMIIBIjAN\n"
+ "BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiJCj31d1Rp+aKz/GTkedaiS/VSCc\n"
+ "PRARYgXukobjgBHx46HjldAcfg/DoANn5lEQaFxaIZJLbZ/AdLUyw/hUbU0CjWXv\n"
+ "pN3Ep3o9XgRTPkIFoI22VOI/O2ZLjBq/E4DWyVmv+vG6BK0LRh7hykzPCw6KIRR9\n"
+ "NCmUMJMQX5d5P/r1lR5H399pnLcLsrHoWDwBSEDgkGWyxnvEB0+/bIz42T3qnlFt\n"
+ "7avarxlHG2p5DoRTf8GJ+6imY88ZeBW/Nk18aDINsAHWLv383JICIAsZ3VuMk8m/\n"
+ "Z/Z5b21zIuZECDJjZjvAAjr/shVLB+Pck5+HJy6tqj79MJOQu+jKIrK8VwIDAQAB\n"
+ "oAAwDQYJKoZIhvcNAQEFBQADggEBAGtuAAHG4OC9jSRjGWSqfMXTDMz9tgekDREA\n"
+ "SYv5QIrOXsMzwbgDw8LxRJZEskl4JJOnjwEvUXWUF1M6XmG2h358nOnrkOlsumHw\n"
+ "Tx5gGSr6S6aJO/HG46erctE8aWpnFZYMfuEkul4ApsIufL7Bxqs3NHZWcrWBlLIP\n"
+ "aVCKx1FPRMC36Tj3EslbuUB/iTRt90Nfq1IxHMIKiwCiSNJSqfRVLANhI8MUbOjB\n"
+ "CBly1wcH68WWNkyvHVvbcF/B9AfYG9AqWjZjygKpyf81VZWctXhDc8UtomqrblXN\n"
+ "mvz4RKpIhZQLuuxlBrdzJkPm2sOdtdZghebCRRVWdjsig4sylgQ=\n"
+ "-----END CERTIFICATE REQUEST-----";
public void testReadCertificateSigningRequest()
{
PKCS10CertificationRequest csr = convertPemToPKCS10CertificationRequest(csrPEM);
if (csr == null)
{
System.out.println("FAIL!");
}
else
{
X500Name x500Name = csr.getSubject();
System.out.println("x500Name is: " + x500Name + "\n");
// country is 2.5.4.6
System.out.println("COUNTRY: " + getX500Field(COUNTRY, x500Name));
// state is 2.5.4.8
System.out.println("STATE: " + getX500Field(STATE, x500Name));
// locale is 2.5.4.7
System.out.println("LOCALE: " + getX500Field(LOCALE, x500Name));
}
}
private String getX500Field(String asn1ObjectIdentifier, X500Name x500Name)
{
RDN[] rdnArray = x500Name.getRDNs(new ASN1ObjectIdentifier(asn1ObjectIdentifier));
String retVal = null;
for (RDN item : rdnArray)
{
retVal = item.getFirst().getValue().toString();
}
return retVal;
}
private PKCS10CertificationRequest convertPemToPKCS10CertificationRequest(String pem)
{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
PKCS10CertificationRequest csr = null;
ByteArrayInputStream pemStream = null;
try
{
pemStream = new ByteArrayInputStream(pem.getBytes("UTF-8"));
}
catch (UnsupportedEncodingException ex)
{
Log.e(getClass().getSimpleName(), "UnsupportedEncodingException, convertPemToPublicKey", ex);
}
Reader pemReader = new BufferedReader(new InputStreamReader(pemStream));
PEMParser pemParser = null;
try
{
pemParser = new PEMParser(pemReader);
Object parsedObj = pemParser.readObject();
System.out.println("PemParser returned: " + parsedObj);
if (parsedObj instanceof PKCS10CertificationRequest)
{
csr = (PKCS10CertificationRequest) parsedObj;
}
}
catch (IOException ex)
{
Log.e(getClass().getSimpleName(), "IOException, convertPemToPublicKey", ex);
}
finally
{
if (pemParser != null)
{
IOUtils.closeQuietly(pemParser);
}
}
return csr;
}
而且我也得到了VerifyError ...
06-10 09:09:18.920: E/AndroidRuntime(2295): FATAL EXCEPTION: main
06-10 09:09:18.920: E/AndroidRuntime(2295): java.lang.VerifyError: org.bouncycastle.cert.X509CertificateHolder
06-10 09:09:18.920: E/AndroidRuntime(2295): at org.bouncycastle.openssl.PEMParser$X509CertificateParser.parseObject(Unknown Source)
06-10 09:09:18.920: E/AndroidRuntime(2295): at org.bouncycastle.openssl.PEMParser.readObject(Unknown Source)
06-10 09:09:18.920: E/AndroidRuntime(2295): at com.example.MyFragment.convertPemToX509Certificate(MyFragment.java:214)
06-10 09:09:18.920: E/AndroidRuntime(2295): at com.example.MyFragment.testReadCertificateSigningRequest(MyFragment.java:146)
06-10 09:09:18.920: E/AndroidRuntime(2295): at com.example.MyFragment.onClick(MyFragment.java:87)
06-10 09:09:18.920: E/AndroidRuntime(2295): at android.view.View.performClick(View.java:2485)
06-10 09:09:18.920: E/AndroidRuntime(2295): at android.view.View$PerformClick.run(View.java:9080)
06-10 09:09:18.920: E/AndroidRuntime(2295): at android.os.Handler.handleCallback(Handler.java:587)
06-10 09:09:18.920: E/AndroidRuntime(2295): at android.os.Handler.dispatchMessage(Handler.java:92)
06-10 09:09:18.920: E/AndroidRuntime(2295): at android.os.Looper.loop(Looper.java:130)
06-10 09:09:18.920: E/AndroidRuntime(2295): at android.app.ActivityThread.main(ActivityThread.java:3683)
06-10 09:09:18.920: E/AndroidRuntime(2295): at java.lang.reflect.Method.invokeNative(Native Method)
06-10 09:09:18.920: E/AndroidRuntime(2295): at java.lang.reflect.Method.invoke(Method.java:507)
06-10 09:09:18.920: E/AndroidRuntime(2295): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
06-10 09:09:18.920: E/AndroidRuntime(2295): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
06-10 09:09:18.920: E/AndroidRuntime(2295): at dalvik.system.NativeStart.main(Native Method)
代码如下:
public void testReadCertificateSigningRequest()
{
X509CertificateHolder csr2 = convertPemToX509Certificate(testCSR);
if (csr2 == null)
{
System.out.println("TOTAL FAIL!");
}
else
{
X500Name name = csr2.getSubject();
System.out.println("x500Name is: " + name + "\n");
System.out.println("Common Name: " + getX500Field(COMMON_NAME, name));
// country is 2.5.4.6
System.out.println("COUNTRY: " + getX500Field(COUNTRY, name));
// state is 2.5.4.8
System.out.println("STATE: " + getX500Field(STATE, name));
// locale is 2.5.4.7
System.out.println("LOCALE: " + getX500Field(LOCALE, name));
}
}
private X509CertificateHolder convertPemToX509Certificate(String pem)
{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
X509CertificateHolder csr = null;
ByteArrayInputStream pemStream = null;
try
{
pemStream = new ByteArrayInputStream(pem.getBytes("UTF-8"));
}
catch (UnsupportedEncodingException ex)
{
Log.e(getClass().getSimpleName(), "UnsupportedEncodingException, convertPemToPublicKey", ex);
}
Reader pemReader = new BufferedReader(new InputStreamReader(pemStream));
PEMParser pemParser = null;
try
{
pemParser = new PEMParser(pemReader);
Object parsedObj = pemParser.readObject();
System.out.println("PemParser returned: " + parsedObj);
if (parsedObj instanceof X509CertificateHolder)
{
csr = (X509CertificateHolder) parsedObj;
}
}
catch (IOException ex)
{
Log.e(getClass().getSimpleName(), "IOException, convertPemToPublicKey", ex);
}
finally
{
if (pemParser != null)
{
IOUtils.closeQuietly(pemParser);
}
}
return csr;
}
所以我真的无法判断这是否是模拟的 Google Nexus One、GenyMotion 或我的代码出现的错误。NoClassDefFound 和 VerifyError 都令人痛苦,我不知道如何追踪它.. :/