udid签名跟超级签名到底哪个更稳定以及原理

2019-05-29 10:13

iOS的签名机制很复杂,各种证书,Provision Profile,entitlements,CertificateSigningRequest,p12,AppID,这篇文章我从概念出发,一步一步推出为什么会有这么对概念,希望能有助于理解iOS的App签名的原理,以及udid签名超级签名到底那个稳定
在iOS出来之前,在主流操作系统(Mac,Windows,Linux)上开发和运行软件是不需要签名的,软件随便从哪里下载都能运行,导致平台对第三方软件很难控制,盗版盛行。苹果希望解决这样的问题,希望iOS平台对第三方App有绝对控制权,一定要保证每一个安装到iOS上的App都是经过苹果官方允许的,怎么保证呢?就是通过签名机制。
要实现这个需求很简单,最直接的方式,苹果官方生成一对公私钥,私钥由苹果后台保管,公钥内置到iOS设备里,在我们将App上传到App Store上时,苹果后台使用私钥对App进行签名,iOS设备下载这个应用后,用公钥验证这个签名,若签名正确,则说明这个App是经过苹果后台认证的,并且没有被修改过,这样也就达到了苹果的目的:保证iOS设备安装的每一个APP都是经过苹果官方允许的。

1-1Z5210ZF2542.png

如果我们的iOS设备安装App只通过App Store这一种方式的话,那么问题到这里就已经解决了,但是实际上除了从App Store上下载应用,还可以以一下三种方式安装一个APP:


1.作为开发者,开发App时直接进行真机调试。


2.In-House 企业内部分发,可以直接安装企业证书签名后的App。


3.AD-Hoc 相当于是企业分发的限制版,限制安装设备数量。


苹果要对这三种方式安装的APP进行孔子,就无法像上面这样简单了。

我们先来看第一个,开发时安装APP,它有两个需求:


1.安装包不需要传到苹果服务器,可以直接安装到手机上。


2.苹果必须对这个安装过程有控制权,包括:


a.经过苹果允许才可以这样安装


b.不能被滥用导致非开发App也能被安装。


为了满足这个需求,iOS签名的复杂度也就开始增加了。


苹果给出的方案是使用双层签名,有一点绕,流程大概是下图这样:

1-1Z5210ZZ0c7.png


1.在我们开发使用的Mac上生成一对公钥和私钥,称为公钥,私钥L。L:Local。


2.苹果有固定的一对公钥和私钥,私钥在自己后台保存,公钥内置到了iOS设备里,称为公钥,私钥A。A:Apple。


3.把公钥L上传到苹果后台,用苹果后台的私钥A去签名公钥L。得到了一份数据包括公钥L及其签名,这份数据称为证书。


4.在开发时,编译完一个APP后,用第一步生成的私钥L去签名这个App,同时把第三步得到的证书一起打包进App里,安装到手机上。


5.在安装时,iOS系统取得证书,通过系统内置的公钥A,去验证证书的数字签名是否正确。



6.验证证书后确保了公钥L是苹果认证的,再用公钥L去验证App的签名,这样就间接验证了这个App安装行为是否经过苹果允许。

上述流程只解决了上面的第一个需求,也就是需要经过苹果的允许才可以安装,还未解决第二个避免被滥用的问题。怎么解决呢?苹果加了两个限制,一个是限制在苹果后天注册过的设备才可以安装,二是限制签名只能针对某个具体的App。


在上述的第三步中,苹果用私钥A去签名我们本地公钥L时,实际上除了签名公钥L,还可以加上很多数据,这些数据都可以保证是经过苹果官方认证的,不会有被篡改的可能,那么我们就可以把AppID和设备ID添加进去:

1-1Z52109104B26.png

把允许安装的设备ID和APP对应的AppID等数据,都在第三步这里和公钥L一起,被私钥A签名,一起组成证书。在第五步验证时就可以拿到设备ID列表,判断当前设备是否符合要求。

到这里这个证书已经变得很复杂了,有很多额外的信息,udid签名跟超级签名到底哪个更稳定实际上www.ken74.com就是不错的选择实际上除了设备ID,AppID,还有其他信息也需要用苹果签名,像App里面的iCloud,后天运行等苹果都想控制,苹果把这些权限开关统称为entitlements,它也需要通过签名去授权。


但是一个证书本来就有规范的格式,我们把这些杂七杂八的额外信息赛入证书是不合适的,因此苹果另外搞了一个东西叫Provisioning Profile,一个Provisioning Profile里面就包含了证书以及上述提到的所有额外信息,以及所有信息的签名。


1.在你的Mac上生成一对公钥和私钥,称为公钥L和私钥L。


2.苹果自己有一对固定的公钥和私钥,私钥在苹果后台,公钥内置在iOS设备中,分别称为私钥A和公钥A。


3.把公钥L传到苹果后天,用苹果后天的私钥A去签名公钥L,得到一份数据包括公钥L和签名,这份数据称为证书。


4.在苹果后台申请好AppID,配置好设备ID列表,App权限开关,再加上第三步的证书,组成的数据用苹果后天的私钥A签名,把数据和签名一起组成一个Provisioning Profile文件,下载到本地Mac。


5.在开发时,编译完一个App后,用本地的私钥L对这个App进行签名,同时把第四步生成的Provisionning Profile一起打包进App里,文件名为embeded.mobileprovision,把App安装到手机。


6.在安装时,就可以使用iOS设备里内置的公钥A来验证Provisioning Profile的数字签名是否正确。


7.如果数字签名没有问题,那么就能确保设备ID,AppID,entitlements,和App都是经过苹果认证的,可以安装到iOS设备上。



1.第一步对应的是从keychain里“从这证书颁发机构请求证书”,这样就在本地生成了一对公私钥,保存的额CertificateSigningRequest就是公钥,公钥保存在本地电脑里。


2.第二步苹果处理,不用管。


3.第三步把CertificateSigningRequest上传到苹果后天,生成证书,并下载到本地。


4.第四步是在苹果网站操作的,配置AppID,设备ID,权限等,生成Provisioning Profile文件,并下载Provisioning Profile文件到本地。


5.xcode通过第三步下载下来的证书,去找对应的本地私钥,用本地私钥去签名App,并把Provisioning Profile文件一起打包进去,安装进iOS设备。


总结一些概念:


1.证书:内容是公钥或者私钥,由其它机构对其签名组成的数据包。


2.entitlements:包含了App权限开关列表,AppID,设备ID等。


3.CertificateSigningRequest:本地公钥。


4.p12:本地私钥。


5.Provisioning Profile:包含证书,entitlements等数据,并由苹果后台私钥签名的数据包。


按照上面的流程,那么对于开发人员来说,应该是我们每次新建一个项目也就是有一个新的AppID时,都应该去申请一对本地公私钥,上传公钥到苹果后台,然后下载证书,但是实际上我们并没有这么做,好像很少需要去keychain请求本地公私钥,这是为什么呢?


这里的原因就是iOS Team Provisioning Profile。


iOS Team Provisioning Profile是第一次使用xcode添加设备时,xcode自动生成的,它包含了xcode生成的一个Wildcard AppID(匹配所有应用程序,账户里面的所有device,所有Development Certificates),因此team中的所有成员都可以使用这个iOS Team Provisioning Profile在team的所有设备上调试所有的应用程序,并且当有新设别添加进来时,xcode会更新这个文件。

如此一来,只要我们有一对本地公私钥,并且通过这个本地的公钥上传给苹果获取了证书,那么以后我们运行任何App,在任何iOS设备上运行,都可以使用这个本地私钥和证书,而没有必要每次去创建新的公私钥和获取证书。

通过这个iOS Team Provisioning Profile的结构我们就能明白,iOS Team Provisioning Profile中保存着很多分证书,很多AppID,很多设备ID,entitlements。当我们需要在一个指定的iOS设备上运行一个指定的App时,iOS Team Provisioning Profile就会得到这个AppID和这个设备ID以及它对应entitlements,组成这个特定的Provisioning Profile,打包进APP里面。这样就不需要我们每次去申请证书,生成Provisioning Profile文件了,非常方便。