我使用
之类的东西启动了HTTPS连接httpsCert.connect();
其中httpsCert为HttpsURLConnection httpsCert
。
现在我执行类似Certificate[] certs = httpsCert.getServerCertificates();
的操作来检索服务器x.509证书。
我想检索哪个根CA或中间CA签署了上面收到的证书。
我的方法是查看上面收到的证书中的issuer字段,但这是一个很好的方法。我的意思是有更好的方法吗?
其次,从developer.android.com/HttpsUrlConnection开始,getServerCertificates()似乎会返回标识对等方的证书列表,其中包含对等方的身份证书,后跟CA. 在此上下文中如果是某些证书,例如Google应用程序提取的证书,则证书的一部分会显示授权信息访问权限: CA Issuers - URI:http://pki.google.com/GIAG2.crt 但是其他应用程序获取其他权限签署的证书的情况并非如此。
第二个问题是Android如何验证由中间CA签名的证书的证书路径?
答案 0 :(得分:3)
我想检索哪个根CA或中间CA签署了上面收到的证书。
如果您正在谈论缺少证书,那么您就无法做到。这是PKI中一个众所周知的问题,称为"哪个目录"问题。问题是你不知道在哪里找到丢失的证书。服务器发送构建链以执行验证所需的所有证书,解决了该问题。
你仍然必须在某处信任;否则坏人会发给你他想要你信任的连锁店,你就不会更聪明了。这就是浏览器和cURL等用户代理带有cacert.pem等列表的原因。
事实上,一些配置不当的服务器将不发送所需的中间证书。在这种情况下,浏览器会携带一系列中间体来填补缺失的部分。
另见Peter Gutmann的Engineering Security。
我的方法是查看上面收到的证书中的issuer字段,但这是一个很好的方法。我的意思是有更好的方法吗?
大致如何建立链条。当您使用颁发者的名称时,您使用的是可分辨名称("目录中的颁发者DN")。还有一个主题DN。发行人是权力机构,主体是其发行的实体。
验证链时,其名为"路径构建"。这会引导您RFC 4158, Internet X.509 Public Key Infrastructure: Certification Path Building。
单凭DN通常是不够的,因为一个坏人可以重复使用相同的名称而你也不会更聪明。因此,您经常使用授权密钥标识符("目录中的AKI"),这是发行者公钥的指纹或摘要。这个坏人不能通过伪造AKI来做有用的事情,因为他没有私钥可以随身携带。
用于使元组唯一的其他内容是序列号。当CA使用相同的DN和相同的公钥重新颁发证书时,这很重要 - 只有序列号不同。当哈希值从SHA-1更改为SHA-256时,您会看到这种情况发生。
过去仅重新发布和更改哈希。由于表面上的一切看起来都很好,因此其中一个更难以追踪的路径验证失败。您需要一段时间才能意识到 DN 和 AKI 都可以,但 SN 不匹配。
第二个问题是Android如何验证由中间CA签名的证书的证书路径?
Android是Java,Java遵循RFC。以下是您需要咨询的三个RFC。这不是一个小题目,你可以写一本提供全面处理的书:
"互联网X.509公钥基础设施"也被称为PKIX。它是互联网的PKI简介。其他组织的PKI可以并且有时会有所不同。这只是意味着其他组织可能有不同于PKIX使用的规则和RFC中的文档。
请注意:a" CA root"将是自签名的。主题DN将与发行者DN相同,主题的密钥标识符("目录中的SKI")将是发行者的权限密钥标识符(&#34中的AKI) ;目录说")等。此外,基本约束将CA=true
,它可能会被标记为关键。
中间CA证书将针对(或链接到)不同的证书颁发,因此主题DN将不与颁发者DN相同。但是,与自签名根一样,基本约束将具有CA=true
,并且可能会被标记为关键。
作为依赖方,您完全可以接受信任中间人而不是根,即使中间人是由根证明的。这是你的特权。
答案 1 :(得分:0)
授权信息访问:CA颁发者存储在CA Extensions中。 此代码打印来自Authority Information Access Extension的URL列表。这就是你需要的东西。
import sun.security.util.ObjectIdentifier;
import sun.security.x509.X509CertImpl;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class readCert{
public boolean isExtAuthorityInfoAccess(Extension ext){
Pattern re = Pattern.compile("\\bcaIssuers\\b",Pattern.CASE_INSENSITIVE);
Matcher m = re.matcher(ext.toString());
if (m.find()) {
return true;
} else {
return false;
}
};
public static List<String> getAuthorityInfoAccesssUrls(String text)
{
List<String> containedUrls = new ArrayList<String>();
Pattern pattern = Pattern.compile(
"(?:^|[\\W])((ht|f)tp(s?):\\/\\/|www\\.)"
+ "(([\\w\\-]+\\.){1,}?([\\w\\-.~]+\\/?)*"
+ "[\\p{Alnum}.,%_=?&#\\-+()\\[\\]\\*$~@!:/{};']*)",
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
Matcher urlMatcher = pattern.matcher(text);
while (urlMatcher.find())
{
containedUrls.add(text.substring(urlMatcher.start(0),
urlMatcher.end(0)));
}
return containedUrls;
};
public static void main(String[] args) {
readCert rc = new readCert();
try {
File file = new File("yourcert.crt");
byte[] encCert = new byte[(int) file.length()];
FileInputStream fis = new FileInputStream(file);
fis.read(encCert);
fis.close();
InputStream in = new ByteArrayInputStream(encCert);
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate)certFactory.generateCertificate(in);
X509CertImpl impl = (X509CertImpl)cert;
int extnum = 0;
if (cert.getNonCriticalExtensionOIDs() != null) {
for (String extOID : cert.getNonCriticalExtensionOIDs()) {
Extension ext = impl.getExtension(new ObjectIdentifier(extOID));
if (ext != null) {
if (rc.isExtAuthorityInfoAccess(ext)) {
System.out.println(rc.getAuthorityInfoAccesssUrls(ext.toString()));
// System.out.println("#"+(++extnum)+": "+ ext.toString());
// CA ISSUERS ARE HERE
}
}
}
}
} catch ( Exception e) {
e.printStackTrace();
};
}
}