Utilizar Bouncy Castle para extraer información de certificados de android

Estoy intentando utilizar el castillo bouncy para leer el contenido de CERT.RSA en un archivo apk de Android.

Mediante el uso de: openssl pkcs7 -inform DER -in CERT.RSA -noout -print_certs -text

Yo soy conseguir lo siguiente, que parece correcto:

 Certificate: Data: Version: 3 (0x2) Serial Number: 93:6e:ac:be:07:f2:01:df Signature Algorithm: sha1WithRSAEncryption Issuer: C=US, ST=California, L=Mountain View, O=Android, OU=Android, CN=Android/emailAddress=android@android.com Validity Not Before: Feb 29 01:33:46 2008 GMT Not After : Jul 17 01:33:46 2035 GMT Subject: C=US, ST=California, L=Mountain View, O=Android, OU=Android, CN=Android/emailAddress=android@android.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:d6:93:19:04:de:c6:0b:24:b1:ed:c7:62:e0:d9: d8:25:3e:3e:cd:6c:eb:1d:e2:ff:06:8c:a8:e8:bc: a8:cd:6b:d3:78:6e:a7:0a:a7:6c:e6:0e:bb:0f:99: 35:59:ff:d9:3e:77:a9:43:e7:e8:3d:4b:64:b8:e4: fe:a2:d3:e6:56:f1:e2:67:a8:1b:bf:b2:30:b5:78: c2:04:43:be:4c:72:18:b8:46:f5:21:15:86:f0:38: a1:4e:89:c2:be:38:7f:8e:be:cf:8f:ca:c3:da:1e: e3:30:c9:ea:93:d0:a7:c3:dc:4a:f3:50:22:0d:50: 08:07:32:e0:80:97:17:ee:6a:05:33:59:e6:a6:94: ec:2c:b3:f2:84:a0:a4:66:c8:7a:94:d8:3b:31:09: 3a:67:37:2e:2f:64:12:c0:6e:6d:42:f1:58:18:df: fe:03:81:cc:0c:d4:44:da:6c:dd:c3:b8:24:58:19: 48:01:b3:25:64:13:4f:bf:de:98:c9:28:77:48:db: f5:67:6a:54:0d:81:54:c8:bb:ca:07:b9:e2:47:55: 33:11:c4:6b:9a:f7:6f:de:ec:cc:8e:69:e7:c8:a2: d0:8e:78:26:20:94:3f:99:72:7d:3c:04:fe:72:99: 1d:99:df:9b:ae:38:a0:b2:17:7f:a3:1d:5b:6a:fe: e9:1f Exponent: 3 (0x3) X509v3 extensions: X509v3 Subject Key Identifier: 48:59:00:56:3D:27:2C:46:AE:11:86:05:A4:74:19:AC:09:CA:8C:11 X509v3 Authority Key Identifier: keyid:48:59:00:56:3D:27:2C:46:AE:11:86:05:A4:74:19:AC:09:CA:8C:11 DirName:/C=US/ST=California/L=Mountain View/O=Android/OU=Android/CN=Android/emailAddress=android@android.com serial:93:6E:AC:BE:07:F2:01:DF X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha1WithRSAEncryption 7a:af:96:8c:eb:50:c4:41:05:51:18:d0:da:ab:af:01:5b:8a: 76:5a:27:a7:15:a2:c2:b4:4f:22:14:15:ff:da:ce:03:09:5a: bf:a4:2d:f7:07:08:72:6c:20:69:e5:c3:6e:dd:ae:04:00:be: 29:45:2c:08:4b:c2:7e:b6:a1:7e:ac:9d:be:18:2c:20:4e:b1: 53:11:f4:55:d8:24:b6:56:db:e4:dc:22:40:91:2d:75:86:fe: 88:95:1d:01:a8:fe:b5:ae:5a:42:60:53:5d:f8:34:31:05:24: 22:46:8c:36:e2:2c:2a:5e:f9:94:d6:1d:d7:30:6a:e4:c9:f6: 95:1b:a3:c1:2f:1d:19:14:dd:c6:1f:1a:62:da:2d:f8:27:f6: 03:fe:a5:60:3b:2c:54:0d:bd:7c:01:9c:36:ba:b2:9a:42:71: c1:17:df:52:3c:db:c5:f3:81:7a:49:e0:ef:a6:0c:bd:7f:74: 17:7e:7a:4f:19:3d:43:f4:22:07:72:66:6e:4c:4d:83:e1:bd: 5a:86:08:7c:f3:4f:2d:ec:21:e2:45:ca:6c:2b:b0:16:e6:83: 63:80:50:d2:c4:30:ee:a7:c2:6a:1c:49:d3:76:0a:58:ab:7f: 1a:82:cc:93:8b:48:31:38:43:24:bd:04:01:fa:12:16:3a:50: 57:0e:68:4d 

Pero no obtengo el módulo de clave pública y las otras cosas necesarias cuando estoy usando Bouncy Castle. El pubkey es sólo null. Supongo que cometí algún error en el código, pero es extraño que consiga todo lo que quiero, excepto la clave pública.

 X509CertParser certParser = new X509CertParser(); FileInputStream stream; X509CertificateObject cert= null; try { stream = new FileInputStream("CERT.RSA"); certParser.engineInit(stream); cert = (X509CertificateObject) certParser.engineRead(); stream.close(); if(cert.getPublicKey()==null)System.out.println("NULL"); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } 

Este código imprime NULL, mientras que la llamada openssl me dice el módulo, etc.

¿Qué debo hacer para obtener el pubkey en Java? (Tal vez es posible utilizar sdk android o algo más para obtener los datos en lugar de castillo hinchable)

Editar:

Olvidé mencionar que ya probé código de David Grants, que me da el mensaje de error, que el DerInputStream es demasiado grande:

 java.security.cert.CertificateException: Unable to initialize, java.io.IOException: DerInputStream.getLength(): lengthTag=127, too big. at sun.security.x509.X509CertImpl.<init>(X509CertImpl.java:199) at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:107) at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:322) 

No necesita BC para leer un certificado de un flujo DER, puede hacerlo bien en Java SE:

 InputStream in = new FileInputStream("CERT.RSA"); CertificateFactory factory = CertificateFactory.getInstance("X.509") X509Certificate cert = (X509Certificate) factory.generateCertificate(in); 

El APK es simplemente un archivo jar. Utilice el JarFile para analizarlo y luego enumere los JarEntry , llamando al método getCertifiates() para obtener certificados de firma. Por lo general, sólo uno. Puede emitir a X509Certifiate para obtener toda la información de certificado. Tenga en cuenta que no tiene que extraer el archivo CERT.RSA, simplemente pasar el archivo APK al constructor JarFile .

Si está preparado para utilizar BouncyCastle, puede intentar utilizar la clase PEMReader . (Claramente su certificado entonces necesitaría estar en formato PEM, no DER).

 FileReader fileReader = new FileReader("/path/to/cert.pem"); PEMReader pemReader = new PEMReader(fileReader); Object obj = pemReader.readObject(); pemReader.close(); // sloppy IO handling, be thorough in production code X509CertificateObject certObj = (X509CertificateObject) obj; System.out.println(certObj.getPublicKey()); 

Por alguna razón, el código que publicó no chupará la clave pública. No tengo ni idea de porqué.

Puede leer los archivos CERT.RSA utilizando el método PKCS7:

  PKCS7 p7 = new PKCS7(new FileInputStream("CERT.RSA")); p7.getCertificates(); 

Esto le devolverá un Array de X509Certificate .

En Android, puede leer el contenido del certificado digital ( META-INF / CERT.RSA ) de un paquete con la clase abstracta X509Certificate .

 final String appPackage = "com.example" // TODO: Add here the package name!! try { final PackageManager pm = getPackageManager(); final ApplicationInfo ai = pm.getApplicationInfo(appPackage, PackageManager.GET_META_DATA); if ( ai != null ) { final PackageInfo pi = pm.getPackageInfo(this.packageName, PackageManager.GET_PERMISSIONS); if ( pi != null ) { final Signature[] signatures = pi.signatures; if ( (pi.signatures != null) && (pi.signatures.length > 0) ) { for ( final Signature signature : signatures ) { if ( signature != null ) { final InputStream certInputStream = new ByteArrayInputStream(signature.toByteArray()); final CertificateFactory certFactory; final X509Certificate x509Cert; try { certFactory = CertificateFactory.getInstance("X509"); if ( certFactory != null ) { x509Cert = (X509Certificate) certFactory.generateCertificate(certInputStream); if ( x509Cert != null ) { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Log.d(TAG, "Certificate Owner: " + x509Cert.getSubjectDN().toString()); Log.d(TAG, "Certificate Issuer: " + x509Cert.getIssuerDN().toString()); Log.d(TAG, "Certificate Serial Number: " + x509Cert.getSerialNumber().toString()); Log.d(TAG, "Certificate Algorithm: " + x509Cert.getSigAlgName()); Log.d(TAG, "Certificate Version: " + x509Cert.getVersion()); Log.d(TAG, "Certificate OID: " + x509Cert.getSigAlgOID()); Log.d(TAG, "Certificate Valid From: " + dateFormat.format( x509Cert.getNotBefore() )); Log.d(TAG, "Certificate Valid To: " + dateFormat.format( x509Cert.getNotAfter() )); try { final MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update( x509Cert.getEncoded() ); Log.d(TAG, "Certificate SHA-256: " + getHex(md.digest())); } catch ( NoSuchAlgorithmException e ) { //Debug: Log.e(TAG, "MessageDigest ERROR: " + e.getMessage() + "\n"); //e.printStackTrace(); } } } } catch ( final CertificateException e ) { //Debug: Log.e(TAG, "CertificateFactory ERROR: " + e.getMessage() + "\n"); //e.printStackTrace(); } } } } } } } catch ( final PackageManager.NameNotFoundException e ) { //Debug: Log.e(TAG, "ApplicationInfo ERROR: " + e.getMessage() + "\n"); //e.printStackTrace(); } 

Cuando el método getHex () utilizado para extraer el hash SHA-256 del certificado digital es el siguiente:

 /** * Get the hex value of a raw byte array. * * @param raw the raw byte array. * @return the hex value. */ public static String getHex( byte[] raw ) { final String HEXES = "0123456789abcdef"; if ( (raw == null) || (raw.length == 0) ) { return null; } final StringBuilder hex = new StringBuilder( 2 * raw.length ); for ( final byte b : raw ) { hex.append(HEXES.charAt((b & 0xF0) >> 4)).append(HEXES.charAt((b & 0x0F))); } return hex.toString(); } 

Además, puede extraer todas las entradas del propietario y los campos del emisor (recuperados utilizando el método getSubjectDN () el método getIssuerDN () del X509Certificate respectivamente), cuando no son nulos, por ejemplo, utilizando el código siguiente:

 for ( final String field : (x509Cert.getSubjectDN().toString()).split(", ") ) { if ( field.startsWith("CN=") ) { Log.d(TAG, "Common Name: " + field.substring(3)); } if ( field.startsWith("OU=") ) { Log.d(TAG, "Organization Unit: " + field.substring(3)); } if ( field.startsWith("O=") ) { Log.d(TAG, "Organization name: " + field.substring(2)); } if ( field.startsWith("L=") ) { Log.d(TAG, "Locality name: " + field.substring(2)); } if ( field.startsWith("ST=") ) { Log.d(TAG, "State or province Name: " + field.substring(3)); } if ( field.startsWith("C=") ) { Log.d(TAG, "Country: " + field.substring(2)); } if ( field.startsWith("DC=") ) { Log.d(TAG, "Domain Component: " + field.substring(3)); } } 
  • Convención de paquetes Java
  • Tramando 404 y 500 errores al usar tth DefaultHTTPClient
  • Ejecución del emulador de Android en un ordenador con procesador AMD
  • Supervisar la memoria ocupada por mi aplicación en Android
  • El servicio Android debe ejecutarse siempre (nunca detener o detener)
  • ActionBar con el icono y el texto en modo retrato
  • RxJava HashMap Transformación
  • Mostrar texto dinámico en una vista de Android
  • Android: DigitalClock eliminar segundos
  • ¿Por qué las firmas son nulas?
  • Registro personalizado para la aplicación de Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.