参考链接:
安卓证书相关验证机制:
https://duanqz.github.io/2017-09-01-Android-Digital-Signature
(部分内容不准确)
关于META-INF文件含义:
https://blog.csdn.net/diaoxuesong/article/details/78668659
关于V1 V2 V3签名机制:
https://zhuanlan.zhihu.com/p/108034286
数字证书原理:
https://network.51cto.com/article/628890.html
数字证书的结构:https://www.cnblogs.com/hyddd/archive/2009/01/07/1371292.html
关于CERT.RSA全部内容解析:
https://blog.csdn.net/diaoxuesong/article/details/78668659
安卓apk证书原理及实验验证
1. 数字签名
-
对待发送的数据明文进行Hash,通常可采用MD5或SHA算法,然后采用私钥对Hash值进行加密,得到签名。将数据明文和签名一同发送出去。
(为什么要先对原始数据进行Hash后再用私钥加密呢?因为原数据可能比较大,直接使用私钥加密将会非常耗时。) -
接收数据以后,会经过签名验证,其实就是比较两个Hash值:采用同样的Hash算法对数据明文进行哈希,得到一个Hash值;采用公钥对签名进行解密后,得到另一个Hash值。如果两个Hash值相同,则说明数据没有被篡改而且来源可信
2. keytool
keytool是JDK的一个工具,用于密钥和证书的管理。
keytool的主要操作对象是keystore文件,该文件一般以.keystore或.jks(Java KeyStore)为后缀名。
keystore可以存储多个密钥对(Key Pair),每一个密钥对包含私钥(Private Key)和多个证书(Certificate):
3. 证书(Certificate)
证书就是对公钥再次私钥签名产生的结果。证书中保存着被签名的公钥和签名。
3.1 证书认证机构CA(Certificate Authority)和证书链(Certificate Chain)
上述证书的生成过程会导致一个无限的链条:要得到证书,就需要对公钥A进行私钥B签名,并发布公钥B。这样就有两个公钥了:证书本身的公钥(即证书中的Public Key,用公钥A表示)和私钥B所对应的公钥(用公钥B表示)。
要保证公钥B的合法性,我们可以对公钥B再进行私钥C签名,这就又需要发布一个新的公钥C,…,公钥合法性的保证就像链条一样。要打破这个无限的链条,就需要有一个权威机构,来统一颁发证书,这个机构就是CA(Certificate Authority)。
CA的公钥被保存在OS中,被认为是可信的。
光靠一个CA是忙不过来的,CA得授权一些代理,这些代理也可以颁发证书,代理颁发的证书也被认为是合法可信的,这就形成了证书链。
keystore文件的结构:一个私钥(Private Key)与多个证书(Certificates)组成密钥对(Key Pair),其实多个证书的结构就是证书链。
4. keystore
如果将keystore看做密钥和证书管理的数据库,那么keytool就是这个数据库增、删、改、查的接口。
5. Android V1签名方案
-
应用层面:Android对APK的签名要求
Android拒绝安装没有签名的APK
Android并不校验证书的合法性(这与https网站证书不一样,https网站证书是要校验签发者的合法性的)
当签名不匹配时,APK升级会失败 -
系统层面:Android基于数字签名的一些机制
编译Android系统时,会根据不同应用的类型进行签名
Android基于数字签名来判定是否给应用授权
Android基于数字签名来标记APK的SELinux Lable
6. META-INF目录
给定一个Apk文件,解压,可以看到一个META-INF文件夹,在该文件夹下有三个文件:分别为MANIFEST.MF、CERT.SF和CERT.RSA。
其中MANIFEST.MF名称基本固定,CERT.SF和CERT.RSA可能被换成其他名称(例如微信app中是COM_TENC.SF和COM_TENC.RSA)。
(实测一些APK中用的不是SHA-1,而是SHA-256)
也就是说,CERT.RSA中包含一个证书和一个签名,CERT.RSA并不是一个单纯的证书。
6.1 MANIFEST.MF文件
MANIFEST.MF:记录了APK中每一个文件的摘要
Manifest-Version: 1.0
Built-By: Generated-by-ADT
Created-By: Android Gradle 3.4.2
Name: AndroidManifest.xml
SHA-256-Digest: 4Gyn/1pQJm4vo9BPrcOhNA9dqX0xN+Ilux6qDn1f24I=
Name: META-INF/androidx.activity_activity.version
SHA-256-Digest: WYVJhIUxBN9cNT4vaBoV/HkkdC+aLkaMKa8kjc5FzgM=
Name: META-INF/androidx.annotation_annotation-experimental.version
SHA-256-Digest: WYVJhIUxBN9cNT4vaBoV/HkkdC+aLkaMKa8kjc5FzgM=
Name: META-INF/androidx.appcompat_appcompat-resources.version
SHA-256-Digest: HltRzeUVOWqfp2KQnPjKZYTMxWSzJdLuvup2F1/pXE0=
Name: META-INF/androidx.appcompat_appcompat.version
SHA-256-Digest: HltRzeUVOWqfp2KQnPjKZYTMxWSzJdLuvup2F1/pXE0=
Name: META-INF/androidx.arch.core_core-runtime.version
SHA-256-Digest: wo/MpTY3vIjhJK8XJd8Ty5jGne3v1i+zzb4c22t2BiQ=
…………
6.2 CERT.SF文件
CERT.SF:对MANIFEST.MF计算摘要,结果存放在SHA-256-Digest-Manifest;同时对MANIFEST.MF中每一项计算摘要,结果存放在CERT.SF各项中。
Signature-Version: 1.0
Created-By: 1.0 (Android)
SHA-256-Digest-Manifest: ifpWUlrHBqAXmGWiygrMlMr4BL+9Z+J1xzN6IAKIi7U=
X-Android-APK-Signed: 2
Name: AndroidManifest.xml
SHA-256-Digest: FM8SO8spjSfyYXZCcMfhl93XRKbKItHolj1eOAaLnx4=
Name: META-INF/androidx.activity_activity.version
SHA-256-Digest: Yu1eiqd7wti3kPabgLC0lsO+1ns/UAhiPGUExHOxH/w=
Name: META-INF/androidx.annotation_annotation-experimental.version
SHA-256-Digest: Lxz3EbTZKQ+6YHD56UXKdC4eR6Vt/RCS/mhbehwNKY0=
Name: META-INF/androidx.appcompat_appcompat-resources.version
SHA-256-Digest: d8qnGN0xpQnZXwhik1KeeAcyufb6b2l+Ods8bsHKkVE=
Name: META-INF/androidx.appcompat_appcompat.version
SHA-256-Digest: YwDR0Rxo15s+KFBZKd2nWg6Xm4mF+YmpBoHOItYOSoU=
Name: META-INF/androidx.arch.core_core-runtime.version
SHA-256-Digest: PjygIQMN5T6nIKT/hi5PFaxVcEB+W20fr4f0g2n7jrg=
…………
可以看出其中多出一项SHA-256-Digest-Manifest(值为ifpWUlrHBqAXmGWiygrMlMr4BL+9Z+J1xzN6IAKIi7U=
)。这个是对MANIFEST.MF文件的SHA256值经Base64编码得到的。
验证过程如下:
利用在线工具(该工具可离线保存),计算MANIFEST.MF文件的SHA256值:89fa56525ac706a0179865a2ca0acc94caf804bfbd67e275c7337a2002888bb5
利用在线工具,求出SHA256值(16进制形式)的Base64编码结果:ifpWUlrHBqAXmGWiygrMlMr4BL+9Z+J1xzN6IAKIi7U=
该值与CERT.SF中的SHA-256-Digest-Manifest相同。
6.3 CERT.RSA文件
CERT.RSA:主要内容是对CERT.SF的私钥A签名(对CERT.SF的摘要的私钥A加密) 和 证书(用于保存公钥A) 。RSA后缀表示签名是基于RSA算法生成的。
证书的本质作用是保存公钥A。同时,证书具备可验证性(在某些额外信息被获取的情况下,用户可以判定证书是否是合法的)。
注意,CERT.RSA是三者中唯一用到私钥的。
6.3.1 证书部分分析
证书保存了:{公钥A+相关信息},{公钥A+相关信息}的私钥B签名结果(和签名算法)。公钥A和私钥A是一对,公钥B和私钥B是一对。当需要验证证书的合法性时,用户从某些途径获取到公钥B(通常是通过上一级证书),而后对 {公钥A+相关信息}的私钥B签名结果 进行解密,得到摘要1;对 {公钥A+相关信息} 计算摘要,得到摘要2;比较摘要1和摘要2是否相同。若相同,则说明证书是可信的。
使用Openssl可以提取其中证书部分内容:
openssl pkcs7 -inform DER -in CERT.RSA -noout -print_certs -text > CERT.RSA-cert.txt
内容如下:
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 33548542 (0x1ffe8fe)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=CN
Validity
Not Before: Dec 20 04:41:56 2018 GMT
Not After : Dec 14 04:41:56 2043 GMT
Subject: C=CN
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:dd:3f:31:51:7f:b3:2f:dd:07:9c:6f:66:3d:eb:
17:84:6d:7a:19:1f:bd:63:07:e3:be:30:41:09:a3:
84:e7:ab:7f:4b:88:0c:b6:27:3d:38:e6:28:3b:60:
ac:19:a9:98:cd:0f:3c:24:67:47:5f:f8:11:b1:e6:
00:eb:b0:a4:97:ff:db:db:1f:f8:e8:f7:74:66:51:
e2:46:7a:8b:ea:99:28:72:6e:83:f2:d3:50:0c:7e:
aa:e5:8a:58:03:98:e9:04:cd:1f:55:39:64:88:b8:
92:99:7c:ec:3f:a3:b8:68:44:df:f0:70:b1:2c:50:
d6:e8:be:82:3b:20:b6:04:cd:37:e1:1a:43:9b:7e:
b5:64:86:8e:ab:8f:8a:c1:86:7d:d8:cb:c7:a3:0c:
38:75:01:f4:ec:ad:ec:f5:5c:22:33:80:d6:d9:40:
69:dc:f2:d0:7d:19:69:8b:69:f8:48:b3:6f:b0:3c:
83:95:17:6d:5b:21:34:64:61:4a:f8:f3:80:fe:e7:
f3:2e:7b:86:4a:c8:f7:e2:e0:cd:ff:4f:e3:ad:d9:
18:58:fb:cc:7e:29:ff:a1:b8:20:37:25:31:cb:c1:
08:84:a2:07:08:35:4f:c9:52:28:c4:56:6a:59:92:
bd:ea:3d:47:41:80:1b:a5:0d:f1:f9:52:27:54:63:
d4:2f
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
07:8C:E8:A0:26:83:A6:E8:5D:C1:84:E7:C2:D4:45:8E:A4:D8:62:5A
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
3c:0c:03:7f:5c:20:92:0d:f1:a7:9a:35:77:23:b9:f2:d4:bc:
76:81:f6:2a:4b:6e:ac:7b:e7:e1:b4:c2:5b:e2:56:b5:cb:33:
c4:d6:5e:12:64:df:5a:a6:0c:3d:e6:74:e8:2b:62:3f:7f:0a:
16:51:51:ce:9c:f2:c1:88:6c:71:2b:73:53:0a:09:1c:60:86:
5d:6f:94:9e:60:0d:dd:a8:f6:e6:51:bf:13:d7:d9:38:81:ea:
4b:88:87:20:b0:bf:23:93:3c:9b:85:43:f8:81:f8:e2:ee:0d:
24:6b:48:c9:0b:e7:3c:eb:2d:a9:68:04:aa:44:6c:b0:59:80:
2b:3c:7e:ba:70:35:b5:22:32:d7:bf:3f:5b:7b:fb:bb:bf:ae:
b0:78:8e:4e:5a:87:2c:1a:b9:8f:1b:f9:1b:01:15:b5:fb:9a:
51:53:f6:a2:8b:93:84:37:f5:93:b9:f3:06:4d:37:10:21:f8:
e0:c8:83:1e:a4:f1:75:64:41:59:1b:68:c2:26:e3:9b:c0:8c:
d1:61:6c:62:bb:5b:fc:8f:d4:ee:e5:c2:97:6d:7a:e0:01:b9:
7c:08:7e:10:59:f6:4b:d7:7a:9f:c1:d6:99:c7:dd:89:ff:a2:
1c:13:53:b2:5f:09:5a:82:1d:b4:bf:59:63:bb:66:a6:88:0a:
4b:a2:f4:47
其中:
Signature Value(
3C 0C 03 7F …… 47
)是 {公钥A+相关信息}的私钥B签名结果,用于验证证书的可信性,这里暂时不涉及。使用JEB也可以查看Signature Value:
Modulus(模数)和Exponent(指数)共同构成公钥。
Modulus 为:
DD3F31517FB32FDD079C6F663DEB17846D7A191FBD6307E3BE304109A384E7AB7F4B880CB6273D38E6283B60AC19A998CD0F3C2467475FF811B1E600EBB0A497FFDBDB1FF8E8F7746651E2467A8BEA9928726E83F2D3500C7EAAE58A580398E904CD1F55396488B892997CEC3FA3B86844DFF070B12C50D6E8BE823B20B604CD37E11A439B7EB564868EAB8F8AC1867DD8CBC7A30C387501F4ECADECF55C223380D6D94069DCF2D07D19698B69F848B36FB03C8395176D5B213464614AF8F380FEE7F32E7B864AC8F7E2E0CDFF4FE3ADD91858FBCC7E29FFA1B820372531CBC10884A20708354FC95228C4566A5992BDEA3D4741801BA50DF1F952275463D42F
Exponent 为:65537 (0x10001)
通过在线工具生成PEM格式的RSA公钥:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3T8xUX+zL90HnG9mPesX
hG16GR+9YwfjvjBBCaOE56t/S4gMtic9OOYoO2CsGamYzQ88JGdHX/gRseYA67Ck
l//b2x/46Pd0ZlHiRnqL6pkocm6D8tNQDH6q5YpYA5jpBM0fVTlkiLiSmXzsP6O4
aETf8HCxLFDW6L6COyC2BM034RpDm361ZIaOq4+KwYZ92MvHoww4dQH07K3s9Vwi
M4DW2UBp3PLQfRlpi2n4SLNvsDyDlRdtWyE0ZGFK+POA/ufzLnuGSsj34uDN/0/j
rdkYWPvMfin/obggNyUxy8EIhKIHCDVPyVIoxFZqWZK96j1HQYAbpQ3x+VInVGPU
LwIDAQAB
-----END PUBLIC KEY-----
6.3.2 对CERT.SF的私钥A签名部分分析
使用Openssl查看CERT.RSA中全部内容:
openssl asn1parse -inform DER -in CERT.RSA -dump > CERT.RSA.txt
0:d=0 hl=4 l=1081 cons: SEQUENCE
4:d=1 hl=2 l= 9 prim: OBJECT :pkcs7-signedData
15:d=1 hl=4 l=1066 cons: cont [ 0 ]
19:d=2 hl=4 l=1062 cons: SEQUENCE
23:d=3 hl=2 l= 1 prim: INTEGER :01
26:d=3 hl=2 l= 15 cons: SET
28:d=4 hl=2 l= 13 cons: SEQUENCE
30:d=5 hl=2 l= 9 prim: OBJECT :sha256
41:d=5 hl=2 l= 0 prim: NULL
43:d=3 hl=2 l= 11 cons: SEQUENCE
45:d=4 hl=2 l= 9 prim: OBJECT :pkcs7-data
56:d=3 hl=4 l= 701 cons: cont [ 0 ]
60:d=4 hl=4 l= 697 cons: SEQUENCE
64:d=5 hl=4 l= 417 cons: SEQUENCE
68:d=6 hl=2 l= 3 cons: cont [ 0 ]
70:d=7 hl=2 l= 1 prim: INTEGER :02
73:d=6 hl=2 l= 4 prim: INTEGER :01FFE8FE
79:d=6 hl=2 l= 13 cons: SEQUENCE
81:d=7 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption
92:d=7 hl=2 l= 0 prim: NULL
94:d=6 hl=2 l= 13 cons: SEQUENCE
96:d=7 hl=2 l= 11 cons: SET
98:d=8 hl=2 l= 9 cons: SEQUENCE
100:d=9 hl=2 l= 3 prim: OBJECT :countryName
105:d=9 hl=2 l= 2 prim: PRINTABLESTRING :CN
109:d=6 hl=2 l= 30 cons: SEQUENCE
111:d=7 hl=2 l= 13 prim: UTCTIME :181220044156Z
126:d=7 hl=2 l= 13 prim: UTCTIME :431214044156Z
141:d=6 hl=2 l= 13 cons: SEQUENCE
143:d=7 hl=2 l= 11 cons: SET
145:d=8 hl=2 l= 9 cons: SEQUENCE
147:d=9 hl=2 l= 3 prim: OBJECT :countryName
152:d=9 hl=2 l= 2 prim: PRINTABLESTRING :CN
156:d=6 hl=4 l= 290 cons: SEQUENCE
160:d=7 hl=2 l= 13 cons: SEQUENCE
162:d=8 hl=2 l= 9 prim: OBJECT :rsaEncryption
173:d=8 hl=2 l= 0 prim: NULL
175:d=7 hl=4 l= 271 prim: BIT STRING
0000 - 00 30 82 01 0a 02 82 01-01 00 dd 3f 31 51 7f b3 .0.........?1Q..
0010 - 2f dd 07 9c 6f 66 3d eb-17 84 6d 7a 19 1f bd 63 /...of=...mz...c
0020 - 07 e3 be 30 41 09 a3 84-e7 ab 7f 4b 88 0c b6 27 ...0A......K...'
0030 - 3d 38 e6 28 3b 60 ac 19-a9 98 cd 0f 3c 24 67 47 =8.(;`......<$gG
0040 - 5f f8 11 b1 e6 00 eb b0-a4 97 ff db db 1f f8 e8 _...............
0050 - f7 74 66 51 e2 46 7a 8b-ea 99 28 72 6e 83 f2 d3 .tfQ.Fz...(rn...
0060 - 50 0c 7e aa e5 8a 58 03-98 e9 04 cd 1f 55 39 64 P.~...X......U9d
0070 - 88 b8 92 99 7c ec 3f a3-b8 68 44 df f0 70 b1 2c ....|.?..hD..p.,
0080 - 50 d6 e8 be 82 3b 20 b6-04 cd 37 e1 1a 43 9b 7e P....; ...7..C.~
0090 - b5 64 86 8e ab 8f 8a c1-86 7d d8 cb c7 a3 0c 38 .d.......}.....8
00a0 - 75 01 f4 ec ad ec f5 5c-22 33 80 d6 d9 40 69 dc u......\"3...@i.
00b0 - f2 d0 7d 19 69 8b 69 f8-48 b3 6f b0 3c 83 95 17 ..}.i.i.H.o.<...
00c0 - 6d 5b 21 34 64 61 4a f8-f3 80 fe e7 f3 2e 7b 86 m[!4daJ.......{.
00d0 - 4a c8 f7 e2 e0 cd ff 4f-e3 ad d9 18 58 fb cc 7e J......O....X..~
00e0 - 29 ff a1 b8 20 37 25 31-cb c1 08 84 a2 07 08 35 )... 7%1.......5
00f0 - 4f c9 52 28 c4 56 6a 59-92 bd ea 3d 47 41 80 1b O.R(.VjY...=GA..
0100 - a5 0d f1 f9 52 27 54 63-d4 2f 02 03 01 00 01 ....R'Tc./.....
450:d=6 hl=2 l= 33 cons: cont [ 3 ]
452:d=7 hl=2 l= 31 cons: SEQUENCE
454:d=8 hl=2 l= 29 cons: SEQUENCE
456:d=9 hl=2 l= 3 prim: OBJECT :X509v3 Subject Key Identifier
461:d=9 hl=2 l= 22 prim: OCTET STRING
0000 - 04 14 07 8c e8 a0 26 83-a6 e8 5d c1 84 e7 c2 d4 ......&...].....
0010 - 45 8e a4 d8 62 5a E...bZ
485:d=5 hl=2 l= 13 cons: SEQUENCE
487:d=6 hl=2 l= 9 prim: OBJECT :sha256WithRSAEncryption
498:d=6 hl=2 l= 0 prim: NULL
500:d=5 hl=4 l= 257 prim: BIT STRING
0000 - 00 3c 0c 03 7f 5c 20 92-0d f1 a7 9a 35 77 23 b9 .<...\ .....5w#.
0010 - f2 d4 bc 76 81 f6 2a 4b-6e ac 7b e7 e1 b4 c2 5b ...v..*Kn.{....[
0020 - e2 56 b5 cb 33 c4 d6 5e-12 64 df 5a a6 0c 3d e6 .V..3..^.d.Z..=.
0030 - 74 e8 2b 62 3f 7f 0a 16-51 51 ce 9c f2 c1 88 6c t.+b?...QQ.....l
0040 - 71 2b 73 53 0a 09 1c 60-86 5d 6f 94 9e 60 0d dd q+sS...`.]o..`..
0050 - a8 f6 e6 51 bf 13 d7 d9-38 81 ea 4b 88 87 20 b0 ...Q....8..K.. .
0060 - bf 23 93 3c 9b 85 43 f8-81 f8 e2 ee 0d 24 6b 48 .#.<..C......$kH
0070 - c9 0b e7 3c eb 2d a9 68-04 aa 44 6c b0 59 80 2b ...<.-.h..Dl.Y.+
0080 - 3c 7e ba 70 35 b5 22 32-d7 bf 3f 5b 7b fb bb bf <~.p5."2..?[{...
0090 - ae b0 78 8e 4e 5a 87 2c-1a b9 8f 1b f9 1b 01 15 ..x.NZ.,........
00a0 - b5 fb 9a 51 53 f6 a2 8b-93 84 37 f5 93 b9 f3 06 ...QS.....7.....
00b0 - 4d 37 10 21 f8 e0 c8 83-1e a4 f1 75 64 41 59 1b M7.!.......udAY.
00c0 - 68 c2 26 e3 9b c0 8c d1-61 6c 62 bb 5b fc 8f d4 h.&.....alb.[...
00d0 - ee e5 c2 97 6d 7a e0 01-b9 7c 08 7e 10 59 f6 4b ....mz...|.~.Y.K
00e0 - d7 7a 9f c1 d6 99 c7 dd-89 ff a2 1c 13 53 b2 5f .z...........S._
00f0 - 09 5a 82 1d b4 bf 59 63-bb 66 a6 88 0a 4b a2 f4 .Z....Yc.f...K..
0100 - 47 G
761:d=3 hl=4 l= 320 cons: SET
765:d=4 hl=4 l= 316 cons: SEQUENCE
769:d=5 hl=2 l= 1 prim: INTEGER :01
772:d=5 hl=2 l= 21 cons: SEQUENCE
774:d=6 hl=2 l= 13 cons: SEQUENCE
776:d=7 hl=2 l= 11 cons: SET
778:d=8 hl=2 l= 9 cons: SEQUENCE
780:d=9 hl=2 l= 3 prim: OBJECT :countryName
785:d=9 hl=2 l= 2 prim: PRINTABLESTRING :CN
789:d=6 hl=2 l= 4 prim: INTEGER :01FFE8FE
795:d=5 hl=2 l= 13 cons: SEQUENCE
797:d=6 hl=2 l= 9 prim: OBJECT :sha256
808:d=6 hl=2 l= 0 prim: NULL
810:d=5 hl=2 l= 13 cons: SEQUENCE
812:d=6 hl=2 l= 9 prim: OBJECT :rsaEncryption
823:d=6 hl=2 l= 0 prim: NULL
825:d=5 hl=4 l= 256 prim: OCTET STRING
0000 - 13 6e 93 d0 23 ce b7 33-d5 ed fa e7 cd 10 cf 56 .n..#..3.......V
0010 - 77 c5 e5 f6 03 07 49 31-70 d3 ad 1f 01 69 e0 e7 w.....I1p....i..
0020 - 31 0b 9b 26 57 7a e0 b1-66 79 79 8e af 57 ac 44 1..&Wz..fyy..W.D
0030 - c5 88 d5 50 cd ba 5e f9-0e e9 77 17 30 50 29 28 ...P..^...w.0P)(
0040 - 08 aa 98 20 3b 56 2f f6-10 2e e4 d8 2b 29 e4 6e ... ;V/.....+).n
0050 - 9d 4e 96 e2 03 0c df af-9a b4 bb fd a8 9c f7 39 .N.............9
0060 - 29 45 23 3f 01 13 0e 3d-b7 02 a2 d8 53 6a eb aa )E#?...=....Sj..
0070 - 21 71 9a af 0f 35 5b ec-26 51 d0 22 96 df 8d 14 !q...5[.&Q."....
0080 - 88 98 d4 d4 de 29 9d 77-17 96 e2 e3 bd cc b7 f0 .....).w........
0090 - 61 17 48 a8 33 f5 2e 40-77 b2 42 e1 cf db ef ac [email protected].....
00a0 - 65 a2 1e 10 2e a2 47 8f-b6 9b 7b 3b 84 43 bd 92 e.....G...{;.C..
00b0 - 57 72 ca e5 f8 d9 72 7d-3c 11 d7 4b b9 b0 1f ca Wr....r}<..K....
00c0 - 23 e3 07 bb d0 60 4d 4c-0c 28 11 bd 79 8a 2e b8 #....`ML.(..y...
00d0 - ce 75 6c bb 53 15 36 79-25 39 6c 55 66 97 87 5a .ul.S.6y%9lUf..Z
00e0 - be 8e ad 29 cc 99 f9 fa-c0 c7 fe 9d 7b f9 47 22 ...)........{.G"
00f0 - da ad 6d 90 66 61 52 45-95 cf 15 18 3c f3 51 58 ..m.faRE....<.QX
其中
00 3c 0c ... 47
是对证书加密的结果,用于验证证书的可信性,这里不涉及。
末尾的16进制数13 6e ... 58
是对CERT.SF的私钥A签名,也就是:
136E93D023CEB733D5EDFAE7CD10CF5677C5E5F60307493170D3AD1F0169E0E7310B9B26577AE0B16679798EAF57AC44C588D550CDBA5EF90EE977173050292808AA98203B562FF6102EE4D82B29E46E9D4E96E2030CDFAF9AB4BBFDA89CF7392945233F01130E3DB702A2D8536AEBAA21719AAF0F355BEC2651D02296DF8D148898D4D4DE299D771796E2E3BDCCB7F0611748A833F52E4077B242E1CFDBEFAC65A21E102EA2478FB69B7B3B8443BD925772CAE5F8D9727D3C11D74BB9B01FCA23E307BBD0604D4C0C2811BD798A2EB8CE756CBB5315367925396C556697875ABE8EAD29CC99F9FAC0C7FE9D7BF94722DAAD6D906661524595CF15183CF35158
使用在线工具对该值进行解密。
其中,公钥是PEM格式的,由前文提到的Modulus和Exponent生成,如下:
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3T8xUX+zL90HnG9mPesX
hG16GR+9YwfjvjBBCaOE56t/S4gMtic9OOYoO2CsGamYzQ88JGdHX/gRseYA67Ck
l//b2x/46Pd0ZlHiRnqL6pkocm6D8tNQDH6q5YpYA5jpBM0fVTlkiLiSmXzsP6O4
aETf8HCxLFDW6L6COyC2BM034RpDm361ZIaOq4+KwYZ92MvHoww4dQH07K3s9Vwi
M4DW2UBp3PLQfRlpi2n4SLNvsDyDlRdtWyE0ZGFK+POA/ufzLnuGSsj34uDN/0/j
rdkYWPvMfin/obggNyUxy8EIhKIHCDVPyVIoxFZqWZK96j1HQYAbpQ3x+VInVGPU
LwIDAQAB
-----END PUBLIC KEY-----
解密结果:
解密得到的数据为:
30 31 30 0D 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 A2 B4 DB 1A 50 BE BC 75 40 5B AB E5 C1 3B 96 CF DF 92 E6 50 65 4E DB 6F 56 46 E0 2B 41 B2 C1 E9
其中的A2 B4 DB 1A 50 BE BC 75 40 5B AB E5 C1 3B 96 CF DF 92 E6 50 65 4E DB 6F 56 46 E0 2B 41 B2 C1 E9
就是CERT.SF的SHA256摘要
验证如下:
6.3.3 从CERT.RSA中提取证书指纹(Fingerprint)
证书指纹是对证书的哈希值。
使用keytool也可以查看CERT.RSA中的证书指纹:
keytool --printcert -file CERT.RSA
所有者: C=CN
发布者: C=CN
序列号: 1ffe8fe
生效时间: Thu Dec 20 12:41:56 CST 2018, 失效时间: Mon Dec 14 12:41:56 CST 2043
证书指纹:
SHA1: 8B:4F:1A:B3:95:AB:B7:49:1F:44:49:E5:51:00:06:8A:FA:53:39:8B
SHA256: 8A:73:D3:A5:73:B4:30:18:81:ED:60:2A:57:6A:2C:BF:50:07:8C:4C:C8:0B:CE:52:FF:F7:19:33:98:6B:7A:66
签名算法名称: SHA256withRSA
主体公共密钥算法: 2048 位 RSA 密钥
版本: 3
扩展:
#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 07 8C E8 A0 26 83 A6 E8 5D C1 84 E7 C2 D4 45 8E ....&...].....E.
0010: A4 D8 62 5A ..bZ
]
]
使用JEB也可以查看相关信息:
该Fingerprint常用于各种第三方SDK平台的客户端身份验证(要求将该值上报到SDK平台,SDK中调接口获取)。
6.3.4 APP如何获得证书指纹(Fingerprint)
app通常需要获取证书指纹,以验证当前的app客户端是否被tampered了。
app中相关的java代码如下:
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P)
{
packageInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_SIGNING_CERTIFICATES);
SigningInfo signingInfo = packageInfo.signingInfo;
signatures = signingInfo.getApkContentsSigners();
} else {
packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
signatures = packageInfo.signatures;
}
String signBase64 = Base64Util.encodeToString(signatures [0].toByteArray());
nowSignMD5 = MD5Utils.MD5(signBase64);
7. 相关校验
7.1 App层面
7.1.1 Android拒绝安装没有证书的APK
通过命令行adb install安装一个没有签名的APK时,会提示INSTALL_PARSE_FAILED_NO_CERTIFICATES
错误。
7.1.2 Android不校验证书的合法性
只要证书中公钥解密CERT.SF签名得到的CERT.SF摘要,和计算出的CERT.SF摘要相同,不管证书是不是合法的,Android都允许安装。
7.1.3 两个版本证书不一致时,APK升级失败
如果一个APK的前后两个版本证书不一致时,Android拒绝升级APK。
7.2 操作系统层面
7.2.1 Android中的系统签名
Android设计了四种不同类型的签名:platform, share, media和testkey,默认置于在源码的build/target/product/security目录下,分别用于给不同类型的系统应用进行签名。从Android Lollipop开始,Android还对boot.img和system.img进行签名以防被篡改,所以在原来四组签名的基础上又增加了verity。
build/target/product/security
├── (media.pk8, media.x509.pem) #用于给MediaProvider, Gallery等签名
├── (platform.pk8, platform.x509.pem) #用于给Settings, Phone等签名
├── (shared.pk8, shared.x509.pem) #用于给Launcher, Dailer等签名
├── (testkey.pk8, testkey.x509.pem) #用于给一般应用签名
└── (verity.pk8, verity.x509.pem) #用于给boot.img和system.img签名
.pk8为私钥, .509.pem为证书(包含公钥)。
7.2.2 根据签名界定权限
应用可以定义属于自己的permission,并为其设定protectionLevel,通过Android的权限授予机制,来防止API被滥用。
譬如在packages/apps/Launcer3/AndroidManifest.xml中,就定义了如下权限:
<permission
android:name="com.android.launcher3.permission.WRITE_SETTINGS"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
android:protectionLevel="signatureOrSystem"
android:label="@string/permlab_write_settings"
android:description="@string/permdesc_write_settings"/>
注意android:protectionLevel="signatureOrSystem"
这就表明一个app要想获取com.android.launcher3.permission.WRITE_SETTINGS这个权限,app要么与Launcher3具有相同的签名(公私钥对),要么是一个系统应用。
有了数字签名,就相当于多了一种受信机制。两个不同的APK,签名相同,意味着来源相同,彼此是受信的。
7.2.3 SELinux根据签名给APK打标签
详细内容参考《Android数字签名机制和应用场景》
在SELinux环境下,所有的文件和进程都有标签(文件通过ls -Z
命令,进程通过ps -Z
命令可以查看),这个标签称为SELinux Context。
- 部分标签是事先定义好的,譬如system/sepolicy/file_contexts文件中定义了一些系统文件和目录的标签;
- 部分标签是根据规则生成的,譬如在fork子进程时,会根据TE(Type Enforcement)文件中定义的规则,为子进程打上标签。
- Android基于签名为APK打标签。
system/sepolicy/mac_permissions.xml
中记录签名到SELinux标签的映射。 - 当APK的应用进程启动时,根据seapp_contexts中定义的seinfo=>SELinux Context映射,设置进程的SELinux标签。
不同的标签对应着不同的可操作文件类型(例如system_app_data_file
等)。