有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

ios苹果推送从Java 6升级到Java 7/8后不工作

我正在将一个应用程序从Java6升级到Java8,该应用程序通过APN向苹果设备发送推送通知

当使用相同的PKCS12证书文件在Java 8上运行在Java 6下工作的同一个JAR时,如果我尝试发送推送,我将返回状态代码8(无效令牌)

这可能是什么原因造成的


共 (1) 个答案

  1. # 1 楼答案

    这个问题是由PKCS12文件的内容和Java将PKCS12文件读入Java 6和Java 7之间的KeyStore对象的方式的变化共同造成的

    在相关pkcs12文件上运行openssl pkcs12 -in filename会产生以下结果:

    Enter Import Password:
    MAC verified OK
    Bag Attributes
        friendlyName: Apple Development IOS Push Services: app.id.1
        localKeyID: .... snip ....
    subject=/UID=app.id.1/CN=Apple Development IOS Push Services: app.id.1/OU=PRXXXXXXXX/C=US
    issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
      -BEGIN CERTIFICATE  -
    ... snip ...
      -END CERTIFICATE  -
    Bag Attributes
        friendlyName: Apple Development IOS Push Services: app.id.2
        localKeyID: .... snip ....
    subject=/UID=app.id.2/CN=Apple Development IOS Push Services: app.id.2/OU=PRXXXXXXXX/C=US
    issuer=/C=US/O=Apple Inc./OU=Apple Worldwide Developer Relations/CN=Apple Worldwide Developer Relations Certification Authority
      -BEGIN CERTIFICATE  -
    ... snip ...
      -END CERTIFICATE  -
    Bag Attributes
        friendlyName: User Name
        localKeyID: ... snip ...
    Key Attributes: <No Attributes>
    Enter PEM pass phrase:
    Verifying - Enter PEM pass phrase:
      -BEGIN ENCRYPTED PRIVATE KEY  -
    ... snip ...
      -END ENCRYPTED PRIVATE KEY  -
    Bag Attributes
        friendlyName: User Name
        localKeyID: ... snip ...
    Key Attributes: <No Attributes>
    Enter PEM pass phrase:
    Verifying - Enter PEM pass phrase:
      -BEGIN ENCRYPTED PRIVATE KEY  -
    ... snip ...
      -END ENCRYPTED PRIVATE KEY  -
    

    您可以在这里看到,PKCS12文件包含2个证书和2个私钥(实际上是相同密钥的2个副本),每个证书和私钥用于不同的应用程序ID。列出的第一个证书和私钥用于预期的应用程序ID,而第二个证书和私钥用于我们使用的不同应用程序

    该文件被读入KeyStore中,随后被传递到SSLSocket以连接到Apple。具体做法如下:

        String password = "my_password";
        KeyStore.ProtectionParameter pwParam = new KeyStore.PasswordProtection(password.toCharArray());
        KeyStore keystore = KeyStore.getInstance("PKCS12");
        System.out.println("keystore classname: " + keystore.getClass().getName());
        FileInputStream fileStream = new FileInputStream("certificate_file.p12");
        keystore.load(fileStream, password.toCharArray());
        for (Enumeration<String> e = keystore.aliases(); e.hasMoreElements(); ) {
                String alias = e.nextElement();
                System.out.println("*** entry name: " + alias);
                KeyStore.Entry entry = keystore.getEntry(alias, pwParam);
                System.out.println("entry as string: " + entry.toString());
                for (Certificate cert: keystore.getCertificateChain(alias)) {
                        System.out.println("*** cert: " + cert);
                }
        }
    

    在Java 6下,运行上述命令可以提供以下信息:

    keystore classname: java.security.KeyStore
    *** entry name: User Name
    entry as string: Private key entry and certificate chain with 1 elements:
    [
    [
      Version: V3
      Subject: C=US, OU=PRXXXXXXXX, CN=Apple Development IOS Push Services: app.id.1, UID=app.id.1
    
    ....
    

    在Java 7或Java 8中,我们得到以下结果:

    keystore classname: java.security.KeyStore
    *** entry name: User Name
    entry as string: Private key entry and certificate chain with 1 elements:
    [
    [
      Version: V3
      Subject: C=US, OU=PRXXXXXXXX, CN=Apple Development IOS Push Services: app.id.2, UID=app.id.2
    

    因此,由于两个证书引用相同的私钥,一个证书覆盖另一个证书,因此KeyStore只包含两个证书中的一个。在Java6下,保留第一个证书,而Java7和Java8保留第二个证书。因此,当连接到Apple时,它发送了错误的证书,并且发送的任何推送都被视为无效,因为发送的推送令牌的应用ID与用于连接的证书的应用ID不匹配

    要解决此问题,应仅使用预期的应用程序ID生成PKCS12文件。这可确保读取正确的证书并随后用于连接到Apple