Wonderffee's Blog

A blogging framework for hackers.

自动化生成APNS PEM文件

缘由

由于工作需要,我需要大量生成iOS推送服务端所用到的PEM文件,一个个手动生成那真是要烦死。梳理了一下PEM文件的生成过程,发现涉及到证书导出、生成与验证,这样的话我还真的只能一个个手动生成。不过仔细研究,还是可以提高生成自动化水平的,比如PEM文件后期生成过程的把P12文件转换成PEM文件。

这个P12文件转换成PEM文件的自动化过程有一个难点,就是需要手动输入密码,换言之就是有交互的过程,如果写成脚本,如果让脚本自动交互呢?也就是把密码写死在脚本里,在脚本执行时自动输入密码。还真让我找到了解决这个问题的神器:expect和autoexpect。

看看Expect的介绍:我们通过Shell可以实现简单的控制流功能,如:循环、判断等。但是对于需要交互的场合则必须通过人工来干预,有时候我们可能会需要实现和交互程序如telnet服务器等进行交互的功能。而expect就使用来实现这种功能的工具。

那么autoexpect是什么呢?实际上写expect脚本仍然是挺烦的,autoexpect是用来录制生成expect脚本的,这样就更加自动化了。

实现

Mac本身带有expect工具,这可以通过expect -v看出来,但是却没有autoexpect。其实是因为Mac带的这个expect比较简单,用brew install expect就可以安装上带autoexpect的expect了。

本文中PEM文件的生成主要参考了《IOS Push 证书的重新生成》 一文,涉及到的自动化对应”把两个.p12文件转换成.pem文件”之后的过程.

在Terminal下执行autoexpect -p -f autoGeneratePEM.exp就可以开始脚本的录制了,录制成功后,生成的autoGeneratePEM.exp就是你需要的脚本了,稍做修改,就可以使用了。

下面是我录下来的脚本,由于是录制的,所以会有一些冗余代码。

如何使用:

1. 确保cert.p12和key.p12在当前目录  
2. 修改脚本中的custompassword为两个p12文件的导出密码(这里假设两个是一样的),以及修改customPemPassPhrase为你自己定义的字符串。   
3. 执行脚本时需要bundleid参数,示例:./autoGeneratePEM.exp com.test.123456,或者./autoGeneratePEM.exp 123456
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/usr/bin/expect -f
#
# This Expect script was generated by autoexpect on Tue Aug 25 14:39:57 2015
# Expect and autoexpect were both written by Don Libes, NIST.


set force_conservative 0  ;# set to 1 to force conservative mode even if
            ;# script wasn't run conservatively originally
if {$force_conservative} {
  set send_slow {1 .1}
  proc send {ignore arg} {
      sleep .1
      exp_send -s -- $arg
  }
}

set timeout -1
set bundleid [lindex $argv 0]
spawn $env(SHELL)
match_max 100000
expect -exact "\[?1034hbash-3.2\$ "
send -- "openssl pkcs12 -clcerts -nokeys -out cert.pem -in cert.p12"
expect -exact "openssl pkcs12 -clcerts -nokeys -out cert.pem -in cert.p12"
send -- "\r"
expect -exact "Enter Import Password:"
send -- "custompassword\r"
expect -exact "bash-3.2\$ "
send -- "openssl pkcs12 -nocerts -out key.pem -in key.p12"
expect -exact "openssl pkcs12 -nocerts -out key.pem -in key.p12"
send -- "\r"
expect -exact "Enter Import Password:"
send -- "custompassword\r"
expect -exact "Enter PEM pass phrase:"
send -- "customPemPassPhrase\r"
expect -exact "Verifying - Enter PEM pass phrase:"
send -- "customPemPassPhrase\r"
expect -exact "bash-3.2\$ "
send -- "openssl rsa -in key.pem -out key.unencrypted.pem"
expect -exact "openssl rsa -in key.pem -out key.unencrypted.pem"
send -- "\r"
expect -exact "Enter pass phrase for key.pem:"
send -- "customPemPassPhrase\r"
expect -exact "bash-3.2\$ "
send -- "cat cert.pem key.unencrypted.pem > $bundleid.pem"
expect -exact "cat cert.pem key.unencrypted.pem > $bundleid.pem"
send -- "\r"
expect -exact "bash-3.2\$ "
send -- "exit\r"
expect eof

参考: