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

检索java中X.509证书的主题替代名称,java,x509certificate,asn.1,Java,X509certificate,Asn.1,我已尝试使用本文提供的解决方案 当我尝试读取X.509证书的主题替代名称时,我遇到以下错误 java.lang.NoSuchMethodError:org.bouncycastle.asn1.ASN1InputStream.readObject()Lorg/bouncycastle/asn1/DERObject 在代码的下面一行 ASN1InputStream解码器=新的ASN1InputStream((字节[])项。toArray() DeRecodable encoded=decoder.r

我已尝试使用本文提供的解决方案

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

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

在代码的下面一行

ASN1InputStream解码器=新的ASN1InputStream((字节[])项。toArray()

DeRecodable encoded=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;
}
公共静态列表getSubjectAlternativeNames(X509证书){
列表标识=新的ArrayList();
试一试{

集合我尝试了你的代码,它正在运行,我使用从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;
    }
我得到的输出是[www.google.com,google.com]


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

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

  • 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()]);
}
公共静态字符串[]解析主机名(X509证书证书证书){
List hostNameList=new ArrayList();
试一试{

收集感谢您的解决方案。是的,它正在为.cer文件工作,我从IE中获取。我也需要它为.der文件工作。问题只是我的证书。
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()]);
}