在java中检索X.509证书的主题替代名称

问题描述 投票:0回答:3

我已尝试使用此链接中提供的解决方案。

当我尝试读取 X.509 证书的主题替代名称时,出现以下错误

java.lang.NoSuchMethodError: org.bouncycastle.asn1.ASN1InputStream.readObject()Lorg/bouncycastle/asn1/DERObject;

在下面的代码行

ASN1InputStream 解码器 = new ASN1InputStream((byte[]) item.toArray());

DEREncodable 编码=解码器.readObject();

.der 文件用于创建证书,如下。

X509Certificate cert=null;
fis = new FileInputStream(file.getAbsoluteFile());     //.der file
bis = new BufferedInputStream(fis);

CertificateFactory cf = CertificateFactory.getInstance("X.509");
while (bis.available() > 0) {
                    try{
                    cert = cf.generateCertificate(bis);
                    }
                     catch (CertificateException e) {
                      e.printStackTrace();
                  }
 List list=getSubjectAlternativeNames((X509Certificate) cert);

下面是我从上面提到的链接得到的解决方案。

   public static List<String> getSubjectAlternativeNames(X509Certificate certificate) {
    List<String> identities = new ArrayList<String>();
    try {
        Collection<List<?>> altNames = certificate.getSubjectAlternativeNames();
        // Check that the certificate includes the SubjectAltName extension
        if (altNames == null)
            return Collections.emptyList();
        // Use the type OtherName to search for the certified server name
        for (List item : altNames) {
            Integer type = (Integer) item.get(0);
            if (type == 0)
                // Type OtherName found so return the associated value
                try {
                    // Value is encoded using ASN.1 so decode it to get the server's identity
                    ASN1InputStream decoder = new ASN1InputStream((byte[]) item.toArray()[1]);
                    DEREncodable encoded = decoder.readObject();
                    encoded = ((DERSequence) encoded).getObjectAt(1);
                    encoded = ((DERTaggedObject) encoded).getObject();
                    encoded = ((DERTaggedObject) encoded).getObject();
                    String identity = ((DERUTF8String) encoded).getString();
                    // Add the decoded server name to the list of identities
                    identities.add(identity);
                }
            catch (UnsupportedEncodingException e) {
                e.printStackTrace();
               // log.error("Error decoding subjectAltName" + e.getLocalizedMessage(),e);
            }
            catch (Exception e) {
               // log.error("Error decoding subjectAltName" + e.getLocalizedMessage(),e);
                e.printStackTrace();
            }
            // Other types are not good for XMPP so ignore them
            //log.warn("SubjectAltName of invalid type found: " + certificate);
        }
    }
    catch (CertificateParsingException e) {
        e.printStackTrace();
       // log.error("Error parsing SubjectAltName in certificate: " + certificate + "\r\nerror:" + e.getLocalizedMessage(),e);
    }
    return identities;
}

是不是我没有使用正确的.jar文件?

我使用的.jar是--> bcprov-jdk16-1.45.jar

建议我哪里出错了。

java x509certificate asn.1
3个回答
6
投票
我尝试使用你的代码,它工作正常,我使用从 Internet Explorer 导出的证书进行测试

Internet Explorer -> Tools -> Internet Options -> Content -> Certificates -> Untrusted Publishers -> www.google.com

我将其导出为“.cer”,我对您的代码做了一些更改

public static List<String> getSubjectAlternativeNames(X509Certificate certificate) { List<String> identities = new ArrayList<String>(); try { Collection<List<?>> altNames = certificate.getSubjectAlternativeNames(); if (altNames == null) return Collections.emptyList(); for (List item : altNames) { Integer type = (Integer) item.get(0); if (type == 0 || type == 2){ try { ASN1InputStream decoder=null; if(item.toArray()[1] instanceof byte[]) decoder = new ASN1InputStream((byte[]) item.toArray()[1]); else if(item.toArray()[1] instanceof String) identities.add( (String) item.toArray()[1] ); if(decoder==null) continue; DEREncodable encoded = decoder.readObject(); encoded = ((DERSequence) encoded).getObjectAt(1); encoded = ((DERTaggedObject) encoded).getObject(); encoded = ((DERTaggedObject) encoded).getObject(); String identity = ((DERUTF8String) encoded).getString(); identities.add(identity); } catch (UnsupportedEncodingException e) { log.error("Error decoding subjectAltName" + e.getLocalizedMessage(),e); } catch (Exception e) { log.error("Error decoding subjectAltName" + e.getLocalizedMessage(),e); } }else{ log.warn("SubjectAltName of invalid type found: " + certificate); } } } catch (CertificateParsingException e) { log.error("Error parsing SubjectAltName in certificate: " + certificate + "\r\nerror:" + e.getLocalizedMessage(),e); } return identities; }

我将文件保存到c:a1.cer

X509Certificate cert=null; FileInputStream fis = new FileInputStream("c:\\aa1.cer"); BufferedInputStream bis = new BufferedInputStream(fis); CertificateFactory cf = CertificateFactory.getInstance("X.509"); if (bis.available() > 0) try{ cert = (X509Certificate)cf.generateCertificate(bis); } catch (CertificateException e) { e.printStackTrace(); } System.out.println(CertificateInfo.getSubjectAlternativeNames(cert));

我得到的输出为 [www.google.com, google.com]

请检查您的证书,我认为问题出在您的证书上


1
投票
许多示例使用硬编码整数。为了可读性,我更喜欢使用:

  • GeneralName.dNSName
    =
    2
    
    
  • GeneralName.iPAddress
    =
    7
    
    
  • ...等等
代码:

public static String[] parseHostNames(X509Certificate cert) { List<String> hostNameList = new ArrayList<>(); try { Collection<List<?>> altNames = cert.getSubjectAlternativeNames(); if (altNames != null) { for(List<?> altName : altNames) { if(altName.size()< 2) continue; switch((Integer)altName.get(0)) { case GeneralName.dNSName: case GeneralName.iPAddress: Object data = altName.get(1); if (data instanceof String) { hostNameList.add(((String)data)); } break; default: } } } System.out.println("Parsed hostNames: " + String.join(", ", hostNameList)); } catch(CertificateParsingException | IOException e) { System.err.println("Can't parse hostNames from this cert."); e.printStackTrace(); } return hostNameList.toArray(new String[hostNameList.size()]); }

注意: 接受的答案会检查 byte[]

,但不会在我的系统上编译。我通过调用 
byte[]
 找到了一些其他使用 
new ASN1InputStream((byte[])data).readObject();
 的示例,但我没有证书来测试它,所以我已将其从我的示例中删除。


0
投票
对于我来说,这个方法效果很好。 我发现运行良好的库版本是这个:

bcprov-jdk15-1.46.jar

private String getOtherNameValue(X509Certificate certificate) { final String method = "[getOtherNameValue] - "; System.out.println(method + "START"); Collection<List<?>> altNames = null; try { altNames = certificate.getSubjectAlternativeNames(); } catch (CertificateParsingException e) { e.printStackTrace(); } if (altNames == null) return ""; for (List item : altNames) { Integer type = (Integer) item.get(0); if (type == 0) { try { ASN1InputStream decoder = null; if (item.toArray()[1] instanceof byte[]) decoder = new ASN1InputStream((byte[]) item.toArray()[1]); if (decoder == null) continue; DEREncodable encoded = decoder.readObject(); encoded = ((DERSequence) encoded).getObjectAt(1); encoded = ((DERTaggedObject) encoded).getObject(); encoded = ((DERTaggedObject) encoded).getObject(); String principalName = ((DERUTF8String) encoded).getString(); System.out.println(method + "END with principalName: " + principalName); return principalName; } catch (Exception e) { System.out.println(method + "Exception decoding subjectAltName" + e.getLocalizedMessage()); e.printStackTrace(); } } } System.out.println(method + "END"); return ""; }
    
© www.soinside.com 2019 - 2024. All rights reserved.