显示 Android 证书

Display Android Certificate

我有一个简短的问题:return 究竟是什么?

context.getPackageManager().getPackageInfo(context.getPackageName(), GET_SIGNATURES).signatures[0].toByteArray();

我知道它return是应用程序的第一个应用程序证书,它是 META-INF 文件夹中的 CERT.RSA,但是它 return 有什么特别之处?只是一个将整个证书表示为文件或其他字节数组的字节数组?我真的不太了解证书的结构及其包含的数据,所以我真的没有任何线索。

最好的答案是 openssl 的说明,我从上面的代码行得到 returned 值。

context.getPackageManager().getPackageInfo(context.getPackageName(), GET_SIGNATURES).signatures[0]

将return表示与应用程序包关联的签名证书。它将是文档中 here 定义的签名 class 的一个实例。 (名称 'Signature' 有点误导,甚至在文档本身中也提到过)。

context.getPackageManager().getPackageInfo(context.getPackageName(), GET_SIGNATURES).signatures[0].toByteArray();

会return其字节数组表示。即:证书文件的字节数组表示。

除此之外,证书与文本文件没什么不同,但数据被构造成通用格式并进行了编码。 X.509 是使用最广泛的格式之一。你可以找到它here. The RFC for a X.509 certificate is here。证书的结构使得它们可以很容易地检查是否被第 3 方更改。

没有直接return一个字节[]的openssl命令。我能想到的最接近的是 openssl 命令,您可以使用它来获取证书的文本表示形式。

$ openssl x509 -in <your-certificate> -noout -text

PackageInfo 的签名成员只是从包文件中读取的所有签名的数组。

public Signature[] signatures;

class android.content.pm.Signature 以

形式存储签名
private final byte[] mSignature;

这是 toByteArray() 的作用:

/**
 * @return the contents of this signature as a byte array.
 */
public byte[] toByteArray() {
    byte[] bytes = new byte[mSignature.length];
    System.arraycopy(mSignature, 0, bytes, 0, mSignature.length);
    return bytes;
}

基本上这段代码只是为您提供了用于对包进行签名的签名的字节数组。

假设CERT.RSA是apk的META-INF文件夹下的RSA文件,可以通过以下方式获取包的MD5、SHA1、SHA256签名:

keytool -printcert -file CERT.RSA

我终于在android模拟器上自己测试了,得到了最终答案。当我意识到 PKCS7 只是一种存储形式或者更确切地说是各种签名类型的容器时,其实就不难理解了。

在应用内

调用 returns CERT.RSA 文件中的第一个签名。这是一个嵌入 X.509 证书的 PKCS7 文件,根据我的阅读,它始终只是 android 应用程序的一个签名。

Signature sig = context.getPackageManager().getPackageInfo(context.getPackageName(), GET_SIGNATURES).signatures[0];

从上面获得的 Signature 可以直接用于生成像这样的工作 X.509 证书(取自 here):

 byte[] rawCert = sig.toByteArray();
 InputStream certStream = new ByteArrayInputStream(rawCert);

 CertificateFactory certFactory;
 X509Certificate x509Cert;
 try {
      certFactory = CertificateFactory.getInstance("X509");
      x509Cert = (X509Certificate) certFactory.generateCertificate(certStream);

      //do stuff with your certificate
 } catch(Exception ex) {
      //handle exception
 }

其他地方

如果您在自己的 android 应用程序之外拥有证书并且想要相同的字节流,即由上面的函数提供的,您可以使用简单的 Java-程序来完成同样的操作像这样:

 FileInputStream is = new FileInputStream("CERT.RSA");
 CertificateFactory cf = CertificateFactory.getInstance("X.509");
 X509Certificate c = (X509Certificate) cf.generateCertificates(is).toArray()[0];
 byte[] rawCert = c.getEncoded();

此代码首先读取文件,创建 CertificateFactory,然后是重要的步骤,用于隔离 PKCS7 容器中的第一个证书。然后 c.getEncoded() 最终为您提供与上述方法完全相同的表示。

openssl

最后但并非最不重要的是 openssl-命令(取自 here):

 openssl pkcs7 -inform DER -in CERT.RSA -print_certs -text

它将为您提供对所含信息的全面概述,最后是

 -----BEGIN CERTIFICATE-----
 ...
 -----END CERTIFICATE-----

块。它包含与上面相同的数据。如果您解析此块的内容并使用 base64 对其进行解码,它将为您提供与上面两个示例中完全相同的字节数组。