【问题标题】:Retrieve Subject alternative names of X.509 certificate in java在 java 中检索 X.509 证书的主题替代名称
【发布时间】:2015-06-23 04:28:32
【问题描述】:

我已尝试使用link 中提供的解决方案。

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

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

在下面的代码行

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

DEREncodable 编码 = decoder.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


    【解决方案1】:

    我尝试使用您的代码,它正在工作,我使用从 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:\aa1.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]

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

    【讨论】:

    • 感谢您的解决方案。是的,它适用于我从 IE 获取的 .cer 文件。我也需要 .der 文件。
    • 问题仅出在我的证书上。
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 2011-09-21
      • 1970-01-01
      • 2021-03-16
      • 1970-01-01
      • 1970-01-01
      • 2018-03-03
      • 2020-10-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多