Java PKI Programmer‘s Guide

news2024/9/20 20:49:44

一、PKI程序员指南概述 PKI Programmer’s Guide Overview

  Java认证路径API由一系列类和接口组成,用于创建、构建和验证认证路径这些路径也被称作认证链。实现可以通过基于提供者的接口插入。

  这个API基于密码服务提供者架构,这在《Java密码架构参考指南 Cryptographic Service Providers》中有描述,并包括特定算法的类,用于根据PKIX标准构建和验证X.509认证路径。PKIX标准是由IETF PKIX工作组开发的。

  文档目标读者

  此文档面向两类经验丰富的开发人员:

  1. 想要设计能够构建或验证认证路径的安全应用程序的开发人员。
  2. 想要编写服务提供者实现以构建或验证认证路径的开发人员。

  此文档假定您已经阅读了《密码服务提供者Cryptographic Service Providers.》。

1.1 公钥证书介绍 Introduction to Public Key Certificates

  公钥应用和系统的用户必须确信,一个主体的公钥是真实的,即与主体相关的私钥由主体拥有。公钥证书用于建立这种信任。

  公钥(或身份)证书是将公钥绑定到身份的证书,该证书由另一个实体(通常称为认证机构CA)的私钥进行数字签名。在本节的其余部分中,术语CA用于指代签署证书的实体。

  如果用户没有签署主体公钥证书的CA的公钥的可信副本,则需要另一个公钥证书来证明签署CA的可信度。这种逻辑可以递归应用,直到从信任锚点或最受信任的CA到目标主体(通常称为终端实体)发现一系列证书(或认证路径)。最受信任的CA通常由颁发给CA的证书指定,该CA是用户直接信任的。通常,认证路径是一个有序的证书列表,通常由终端实体的公钥证书和零个或多个附加证书组成。认证路径通常有一种或多种编码,允许它安全地通过网络传输,并适应不同的操作系统架构。

  下图说明了从最受信任的CA的公钥(CA 1)到目标主体(Alice)的认证路径。认证路径通过名为CA2的中间CA建立对Alice公钥的信任。
在这里插入图片描述
   图9-1 从CA的公钥(CA 1)到目标主体的认证路径

   认证路径必须在依赖其建立对主体公钥的信任之前进行验证。验证可以包括对认证路径中包含的证书的各种检查,例如验证签名并检查每个证书是否已被撤销。PKIX标准定义了一种用于验证由X.509证书组成的认证路径的算法。

   用户可能经常没有从最受信任的CA到主体的认证路径。提供构建或发现认证路径的服务是启用公钥系统的重要特性。RFC 2587定义了一种LDAP(轻量级目录访问协议)模式定义,该定义促进了使用LDAP目录服务协议发现X.509认证路径。

   构建和验证认证路径是许多标准安全协议的重要组成部分,例如SSL/TLS/DTLS、S/MIME和IPsec。Java认证路径API为需要将此功能集成到其应用程序中的开发人员提供了一组类和接口。这个API使两类开发人员受益:那些需要编写特定认证路径构建或验证算法的服务提供者实现的开发人员;以及那些需要以独立于实现的方式访问用于创建、构建和验证认证路径的标准算法的开发人员

1.2 、X.509 证书和证书撤销列表 X.509 Certificates and Certificate Revocation Lists (CRLs)

  公钥证书是一个实体的数字签名声明,表明另一个实体的公钥及其它一些信息具有特定的值。

  关键术语定义表

  • 公钥: 与特定实体相关联的数字,旨在被所有需要与该实体进行可信交互的人所知晓。公钥用于验证签名。
  • 数字签名: 如果一些数据被数字签名,它就被存储了实体的“身份”和证明该实体知道这些数据的签名。数据通过使用实体的私钥签名而变得不可伪造。
  • 身份: 实体的已知地址方式。在某些系统中,身份是公钥,在其他系统中,它可以是从UNIX UID到电子邮件地址到X.509 可分辨名称的任何东西。
  • 签名: 使用实体(签名者)的私钥对一些数据计算出的签名。
  • 私钥: 这些数字,每一个只应被拥有该私钥的特定实体所知晓(即,应该保密)。在所有的公钥密码系统中,私钥和公钥成对存在(也被称为“公钥密码系统”)。在典型的公钥密码系统中,如DSA,一个私钥对应一个公钥。私钥用于计算签名。
  • 实体: 实体是个人、组织、程序、计算机、企业、银行或您在某种程度上信任的其它实体。

  X.509证书最广泛可见的应用是在支持TLS协议的网络浏览器中(例如Mozilla Firefox和Microsoft Internet Explorer)。TLS(传输层安全)是一个安全协议,为您的网络流量提供隐私和认证。这些浏览器只能与支持TLS的Web服务器一起使用TLS协议。
  依赖X.509证书的其他技术包括:

  • 各种代码签名方案,如签名的Java ARchives和Microsoft Authenticode。
  • 各种安全的电子邮件标准,如PEM和S/MIME。

1.2.1 如何获取证书?How do I Get a Certificate?

  获取证书的两种基本技术:

  1. 您可以自己创建一个(使用工具,如keytool)。
  2. 您可以请求认证机构为您颁发一个(直接或使用如keytool这样的工具生成请求)。

   证书创建过程的主要输入:

  • 匹配的公钥和私钥,使用特殊工具(如keytool)或浏览器生成。只有公钥会展示给其他人。私钥用于签名数据;如果有人知道您的私钥,他们可以伪装成您……也许伪造归因于您的法律文件!

  • 您需要提供被认证实体的信息(例如,您自己)。这通常包括您的姓名和组织地址等信息。如果您请求CA为您颁发证书,通常需要提供证明以显示信息的正确性。

      如果您请求CA为您颁发证书,您提供您的公钥和一些关于您的信息。您将使用工具(如支持证书签名请求生成的keytool或浏览器)。对这些信息进行数字签名,并将其发送给CA。然后CA将生成证书并返回给您。

      如果您自己生成证书,您将使用相同的信息,添加一些额外的内容(证书有效期内的日期,序列号),并仅使用一些工具(如keytool)创建证书。不是每个人都会接受自签名证书CA提供的价值之一是作为中立和可信的介绍服务,这部分基于他们的验证要求,这些要求在他们的证书服务实践(CSP)中公开发布。

1.2.2 X.509 证书包含什么?

  X.509标准定义了可以放入证书的信息,并描述了如何写下来(数据格式)。除了签名外,所有X.509证书都有以下数据:

  • 版本:这识别适用于该证书的X.509标准的版本,这影响可以在其中指定的信息。到目前为止,定义了三个版本。
  • 序列号:创建证书的实体负责为其分配一个序列号,以将其与其他证书区分开来。此信息在许多方面使用,例如当证书被撤销时,其序列号将放置在证书撤销列表(CRL)中。
  • 签名算法标识符:这识别CA用于签署证书的算法。
  • 发行者名称:签署证书的实体的X.500名称。这通常是一个CA。使用此证书意味着信任签署此证书的实体。(请注意,在某些情况下,例如根或顶级CA证书,发行者签署自己的证书。)
  • 有效期:每个证书仅在有限的时间内有效。这个时间段由开始日期和时间以及结束日期和时间描述,可以短至几秒钟,或几乎长达一个世纪。所选择的有效期取决于多个因素,例如用于签署证书的私钥的强度或一个人愿意为证书支付的金额。这是实体可以依赖公钥的预期期限,如果相关的私钥没有被泄露。
  • 主题Subject名称:证书识别的实体的名称。此名称使用X.500标准,因此它应该在互联网上是唯一的。这是实体的可分辨名称(DN),例如,
CN=Java Duke, OU=Java Software Division, O=Sun Microsystems Inc, C=US
(这些指的是主题的通用名称、组织单位、组织和国家。)
  • 主题Subject公钥信息:这是被命名实体的公钥,以及指定此密钥属于哪个公钥密码系统和任何相关密钥参数的算法标识符。

  所有证书中的数据都使用两个相关标准ASN.1/DER进行编码。抽象语法表示1描述数据。可分辨编码规则描述了一种存储和传输数据的方式。

1.2.3 哪些Java工具可以生成、显示、导入和导出X.509证书?

  有一个名为**keytool**的工具,可以用来创建公钥/私钥对和X.509 v3证书,以及管理密钥库。密钥和证书用于对Java应用程序和小应用程序进行数字签名(见jarsigner)。

  密钥库是一个受保护的数据库,保存密钥和证书。对密钥库的访问由密码保护(在创建密钥库时由创建密钥库的人定义,只有在提供当前密码时才能更改)。此外,密钥库中的每个私钥也可以由自己的密码保护。

  使用keytool,可以显示、导入和导出存储为文件的X.509 v1、v2和v3证书,并生成新的v3证书。有关示例,请参见Java开发工具包工具规范中的keytool。

二、核心类和接口 Core Classes and Interfaces

  Java认证路径API的核心类由接口和类组成,它们以算法和实现无关的方式支持认证路径功能。

  API基于并扩展了现有的java.security.cert包,用于处理证书。核心类可以分为4个类别:基础、验证、构建和存储。

  • 基础认证路径类
      CertPath CertificateFactoryCertPathParameters

  • 认证路径验证类
      CertPathValidatorCertPathValidatorResultCertPathChecker

  • 认证路径构建类
      CertPathBuilderCertPathBuilderResult

  • 证书/CRL存储类
      CertStoreCertStoreParametersCertSelectorCRLSelector

  Java认证路径API还包括一组特定算法的类,这些类为使用RFC 5280中定义的PKIX认证路径验证算法而建模:公钥基础设施证书和证书撤销列表(CRL)配置文件。PKIX类包括:

  • TrustAnchor
  • PKIXParameters
  • PKIXCertPathValidatorResult
  • PKIXBuilderParameters
  • PKIXCertPathBuilderResult
  • PKIXCertPathChecker
  • PKIXRevocationChecker
      相关认证路径API类的全部参考文档可以在java.security.cert中找到。

   CertPath API中的大多数类和接口都不是线程安全的。然而,有一些例外,这些将在本指南和API规范中注明。需要同时访问单个非线程安全对象的多个线程应该在它们之间进行同步并提供必要的锁定。每个操作不同对象的多个线程不需要同步。

2.1 、基础认证路径类 Basic Certification Path Classes

  基础认证路径类提供了对认证路径进行编码和表示的基本功能。Java认证路径API中的关键基础类是CertPath,它封装了所有类型认证路径共享的通用方面。应用程序使用CertificateFactory类的实例来创建CertPath对象。

2.1.1 The CertPath Class

  CertPath 类是认证路径的抽象类。它定义了所有认证路径对象共享的功能。可以通过继承CertPath类来实现各种认证路径类型,尽管它们可能有不同的内容和排序方案。

   所有CertPath对象都是可序列化的、不可变的和线程安全的,并具有以下特性:

  • 类型
    这对应于认证路径中的证书类型,例如:X.509。使用以下方法获取CertPath的类型:

    public String getType()
    

    有关标准证书类型的信息,请参见[CertificateFactory](https://docs.oracle.com/en/java/javase/22/docs/specs/security/standard-names.html#certificatefactory-types)类型。

  • 证书列表
    getCertificates方法返回认证路径中的证书列表:

    public abstract List<? extends Certificate> getCertificates()
    

    此方法返回一个包含零个或多个java.security.cert.Certificate对象的列表。返回的列表及其中包含的证书都是不可变的,以保护CertPath对象的内容。返回的证书顺序取决于类型。按照惯例,X.509类型的CertPath对象中的证书顺序从目标证书开始,以由信任锚点颁发的证书结束。也就是说,一个证书的发行者是下一个证书的主题。代表TrustAnchor的证书不应包含在认证路径中。未经验证的X.509 CertPaths可能不遵循此约定。PKIX CertPathValidators将检测到任何偏离这些约定导致认证路径无效的情况,并抛出CertPathValidatorException

  • 一种或多种编码
    每个CertPath对象支持一种或多种编码。这些是认证路径的外部编码形式,当需要在Java虚拟机外部以标准表示形式表示路径时使用(例如,将路径通过网络传输给另一方)。每个路径都可以使用默认格式进行编码,使用以下方法返回字节:

    public abstract byte[] getEncoded()
    

    或者,getEncoded(String)方法通过指定编码格式为字符串(例如:“PKCS7”)返回特定支持的编码。有关标准编码格式的信息,请参见CertPath编码。

    public abstract byte[] getEncoded(String encoding)
    

    另外,getEncodings方法返回支持的编码格式字符串的迭代器(首先返回默认编码格式):

    public abstract Iterator<String> getEncodings()
    

  所有CertPath对象也是可序列化的。在序列化期间,CertPath对象解析为一个替代的CertPath.CertPathRep对象。这允许CertPath对象序列化为一个等价的表示,无论其底层实现如何。

  CertPath对象是从编码的字节数组或证书列表使用CertificateFactory生成的。或者,可以使用CertPathBuilder尝试从最受信任的CA到特定主题查找CertPath。一旦创建了CertPath对象,可以通过将其传递给CertPathValidatorvalidate方法来验证。这些概念将在后续部分中更详细地解释。

2.1.2 证书工厂类 The CertificateFactory Class

  CertificateFactory类是一个引擎类,定义了证书工厂的功能。它用于生成Certificate, CRL, 和 CertPath

  不应将CertificateFactoryCertPathBuilder混淆。CertPathBuilder(稍后讨论)用于在不存在认证路径时发现或找到认证路径。相比之下,当已经发现认证路径,并且调用者需要根据其内容(以编码的字节数组或证书数组的形式存在)实例化CertPath对象时,使用CertificateFactory

2.1.2.1 创建CertificateFactory对象 Creating a CertificateFactory Object

  有关创建CertificateFactory对象的详细信息,请参阅Java加密架构参考指南中的CertificateFactory部分。

2.1.2.2 生成CertPath对象 Generating CertPath Objects

  CertificateFactory实例从证书列表或包含CertPath编码形式的InputStream生成CertPath对象。就像CertPath一样,每个CertificateFactory支持认证路径的默认编码格式(例如:PKCS#7)。要生成CertPath对象并用从输入流中读取的数据初始化(以默认编码格式),请使用generateCertPath方法:

public final CertPath generateCertPath(InputStream inStream)

  或者从特定编码格式:

public final CertPath generateCertPath(InputStream inStream, String encoding)

  要了解支持的编码格式,请使用getCertPathEncodings方法(首先返回默认编码):

public final Iterator<String> getCertPathEncodings()

  要从证书列表生成认证路径对象,请使用以下方法:

public final CertPath generateCertPath(List<? extends Certificate> certificates)

  CertificateFactory始终返回由与工厂相同类型的证书组成的CertPath对象。例如,X.509类型的CertificateFactory返回由java.security.cert.X509Certificate实例组成的证书的CertPath对象。

  以下代码示例说明了如何从文件中存储的PKCS#7编码的证书回复生成认证路径:

// 打开文件的输入流
FileInputStream fis = new FileInputStream(filename);
// 实例化X.509的CertificateFactory
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// 从PKCS7 SignedData结构中提取认证路径
CertPath cp = cf.generateCertPath(fis, "PKCS7");
// 打印路径中的每个证书
List<Certificate> certs = cp.getCertificates();
for (Certificate cert : certs) {
    System.out.println(cert);
}

  另一个代码示例说明了如何从KeyStore获取证书链并使用CertificateFactory转换为CertPath:

// 实例化类型为JKS的KeyStore
KeyStore ks = KeyStore.getInstance("JKS");
// 加载KeyStore的内容
ks.load(new FileInputStream("./keystore"), "password".toCharArray());
// 获取存储在别名"sean"中的证书链
Certificate[] certArray = ks.getCertificateChain("sean");
// 将链转换为列表
List<Certificate> certList = Arrays.asList(certArray);
// 实例化X.509的CertificateFactory
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// 从证书列表中提取认证路径
CertPath cp = cf.generateCertPath(certList);

  请注意,CertificateFactory中有一个名为generateCertificates的现有方法,用于解析证书序列。对于包含多个证书的编码,请使用generateCertificates解析可能无关的证书集合。否则,当您想要生成CertPath并随后使用CertPathValidator(稍后讨论)验证它时,请使用generateCertPath。

2.1.3 证书路径参数接口 The CertPathParameters Interface

  CertPathParameters接口是与特定认证路径构建器或验证算法一起使用的参数集的透明表示。

  其主要目的是对所有认证路径参数规范进行分组(并提供类型安全性)。CertPathParameters接口扩展了Cloneable接口,并定义了一个不抛出异常的clone()方法。所有此接口的具体实现应该实现并覆盖Object.clone()方法(如果需要)。这允许应用程序克隆任何CertPathParameters对象。

  实现CertPathParameters接口的对象作为参数传递给CertPathValidator和CertPathBuilder类的方法。通常,CertPathParameters接口的具体实现将保存一组特定于特定认证路径构建或验证算法的输入参数。例如,PKIXParameters类是CertPathParameters接口的实现,它保存了一组PKIX认证路径验证算法的输入参数。其中一个参数是调用者信任的最受信任的CA集合,用于锚定验证过程。这个参数和其他参数将在讨论PKIXParameters类的章节中更详细地讨论。

2.2 、认证路径验证类 Certification Path Validation Classes

  Java 证书路径 API 包括用于验证证书路径的类和接口。应用程序使用 CertPathValidator 类的实例来验证 CertPath 对象。如果验证成功,验证算法的结果将在实现 CertPathValidatorResult 接口的对象中返回。

2.2.1 验证证书路径的有效性 The CertPathValidator Class

  CertPathValidator 类是一个引擎类,用于验证证书路径。

2.2.1.1 获得 CertPathValidator 对象 Creating a CertPathValidator Object

  与所有引擎类一样,获取特定验证算法的 CertPathValidator 对象的方法是调用 CertPathValidator 类上的 getInstance 静态工厂方法之一:

public static CertPathValidator getInstance(String algorithm)
// 为指定算法获取一个 `CertPathValidator` 实例。

public static CertPathValidator getInstance(String algorithm, 
                                             String provider)
// 为指定算法和提供者名称获取一个 `CertPathValidator` 实例。

public static CertPathValidator getInstance(String algorithm, 
                                             Provider provider)
// 为指定算法和提供者获取一个 `CertPathValidator` 实例。

  algorithm 参数是证书路径验证算法的名称(例如 “PKIX”)。标准的 CertPathValidator 算法名称列在 Java 安全标准算法名称中。

2.2.1.2 验证证书路径

  一旦创建了 CertPathValidator 对象,就可以通过调用 validate 方法并传入待验证的证书路径和一组算法特定的参数来验证路径:

public final CertPathValidatorResult 
validate(CertPath certPath, CertPathParameters params)
throws CertPathValidatorException, 
       InvalidAlgorithmParameterException
// 验证证书路径并返回结果。

  如果验证算法成功,结果将在实现 CertPathValidatorResult 接口的对象中返回。否则,将抛出 CertPathValidatorExceptionCertPathValidatorException 包含返回证书路径的方法,并且如果相关,还包含导致算法失败的证书的索引以及失败的根本异常或原因。

  请注意,传递给 validate 方法的 CertPathCertPathParameters 必须是验证算法所支持的类型。否则,将抛出 InvalidAlgorithmParameterException。例如,实现 PKIX 算法的 CertPathValidator 实例将验证类型为 X.509 的 CertPath 对象和是 PKIXParameters 实例的 CertPathParameters

2.2.2 验证证书路径返回接口 The CertPathValidatorResult Interface

  CertPathValidatorResult 接口是认证路径验证算法成功结果或输出的透明表示(output of a certification path validation algorithm.)。

  这个接口的主要目的是将所有验证结果进行分组,并提供类型安全性。与 CertPathParameters 接口类似,CertPathValidatorResult 扩展了 Cloneable 并定义了一个不抛出异常的 clone() 方法。这允许应用程序克隆任何 CertPathValidatorResult 对象。

  实现 CertPathValidatorResult 接口的对象由 CertPathValidatorResult 接口的 validate 方法在成功时返回。如果不成功,则抛出一个带有失败描述的 CertPathValidatorException。通常,CertPathValidatorResult 接口的具体实现将持有一组特定于特定认证路径验证算法的输出参数。例如,PKIXCertPathValidatorResult 类是 CertPathValidatorResult 接口的一个实现,它包含获取 PKIX 认证路径验证算法输出参数的方法。其中一个参数是有效的策略树。这个参数以及其他参数将在讨论 PKIXCertPathValidatorResult 类的章节中更详细地讨论。

  以下代码示例展示了如何创建一个 CertPathValidator 并使用它来验证认证路径。示例假设传递给 validate 方法的 CertPath 和 CertPathParameters 对象之前已经创建;一个更完整的示例将在描述 PKIX 类的章节中展示。


    // create CertPathValidator that implements the "PKIX" algorithm
    CertPathValidator cpv = null;
    try {
        cpv = CertPathValidator.getInstance("PKIX");
    } catch (NoSuchAlgorithmException nsae) {
        System.err.println(nsae);
        System.exit(1);
    }
    // validate certification path ("cp") with specified parameters ("params")
    try {
        CertPathValidatorResult cpvResult = cpv.validate(cp, params);
    } catch (InvalidAlgorithmParameterException iape) {
        System.err.println("validation failed: " + iape);
        System.exit(1);
    } catch (CertPathValidatorException cpve) {
        System.err.println("validation failed: " + cpve);
        System.err.println("index of certificate that caused exception: "
                + cpve.getIndex());
        System.exit(1);
    }

2.3 、认证路径构建类 Certification Path Building Classes

  Java 认证路径 API 包括用于构建(或发现)认证路径的类。应用程序使用 CertPathBuilder 类的一个实例来构建一个 CertPath 对象。如果成功,构建的结果将返回在一个实现了 CertPathBuilderResult 接口的对象中。

2.3.1 认证路径生成类 The CertPathBuilder Class

  CertPathBuilder 类是一个引擎类,用于构建认证路径。

2.3.3 .1 创建一个证书路径生成类对象 Creating a CertPathBuilder Object

  与所有引擎类一样,获取特定构建算法的 CertPathBuilder 对象的方法是调用 CertPathBuilder 类上的一个 getInstance 静态工厂方法:

public static CertPathBuilder getInstance(String algorithm)
public static CertPathBuilder getInstance(String algorithm, String provider)
public static CertPathBuilder getInstance(String algorithm,  Provider provider)

  algorithm 参数是一个认证路径构建器算法的名称(例如,“PKIX”)。标准的 CertPathBuilder 算法名称列在 Java 安全标准算法名称中。

2.3.3.2 构造一个证书路径 Building a Certification Path

  一旦创建了 CertPathBuilder 对象,就可以通过调用 build 方法并传递特定算法的参数规范来构建路径:

public final CertPathBuilderResult build(CertPathParameters params)
        throws CertPathBuilderException, 
               InvalidAlgorithmParameterException

  如果构建算法成功,结果将返回在一个实现了 CertPathBuilderResult 接口的对象中。否则,将抛出一个包含有关失败信息的 CertPathBuilderException;例如,底层异常(如果有的话)和错误消息。

  请注意,传递给 build 方法的 CertPathParameters 必须是构建算法所支持的类型。否则,将抛出 InvalidAlgorithmParameterException。

2.3.2 证书路径返回接口 The CertPathBuilderResult Interface

  CertPathBuilderResult 接口是认证路径构建算法结果或输出的透明表示。

  这个接口包含一个方法,用于返回已成功构建的认证路径:

public CertPath getCertPath()

  CertPathBuilderResult 接口的目的是将所有构建结果进行分组(并提供类型安全性)。与 CertPathValidatorResult 接口一样,CertPathBuilderResult 扩展了 Cloneable 并定义了一个不抛出异常的 clone() 方法。这允许应用程序克隆任何 CertPathBuilderResult 对象。

  实现 CertPathBuilderResult 接口的对象由 CertPathBuilder 的 build 方法返回。

  以下代码示例展示了如何创建一个 CertPathBuilder 并使用它来构建认证路径。示例假设传递给 build 方法的 CertPathParameters 对象之前已经创建;一个更完整的示例将在描述 PKIX 类的章节中展示。


    // create CertPathBuilder that implements the "PKIX" algorithm
    CertPathBuilder cpb = null;
    try {
        cpb = CertPathBuilder.getInstance("PKIX");
    } catch (NoSuchAlgorithmException nsae) {
        System.err.println(nsae);
        System.exit(1);
    }
    // build certification path using specified parameters ("params")
    try {
        CertPathBuilderResult cpbResult = cpb.build(params);
        CertPath cp = cpbResult.getCertPath();
        System.out.println("build passed, path contents: " + cp);
    } catch (InvalidAlgorithmParameterException iape) {
        System.err.println("build failed: " + iape);
        System.exit(1);
    } catch (CertPathBuilderException cpbe) {
        System.err.println("build failed: " + cpbe);
        System.exit(1);
    }

2.4 、证书/CRL存储类 Certificate/CRL Storage Classes

   Java 认证路径 API 包括用于从存储库中检索证书和 CRL(证书撤销列表)的 CertStore 类。

   这个类允许调用者指定 CertPathValidator 或 CertPathBuilder 实现应该使用的存储库来查找证书和 CRL。请参阅 PKIXParameters 类的 addCertStores 方法。

   CertPathValidator 实现可能会使用调用者指定的 CertStore 对象作为一个回调机制,以获取用于执行撤销检查的 CRL。同样,CertPathBuilder 也可能使用 CertStore 作为一个回调机制来获取证书,如果执行撤销检查,则获取 CRL。

2.4.1 证书存储类 The CertStore Class

   CertStore 类是一个引擎类,用于提供证书和证书撤销列表(CRL)存储库的功能。

  这个类可以由 CertPathBuilder 和 CertPathValidator 实现用于查找证书和 CRL,或者作为一个通用的证书和 CRL 检索机制。

  与 java.security.KeyStore 类不同,后者提供对私钥和受信任证书的缓存访问,CertStore 设计用来提供对大量不受信任的证书和 CRL 的访问。例如,LDAP 实现的 CertStore 提供了使用 LDAP 协议访问存储在一个或多个目录中的证书和 CRL。

  CertStore 对象的所有公共方法都是线程安全的。也就是说,多个线程可以同时调用一个单独 CertStore 对象(或多个对象)上的这些方法,而不会产生不良影响。这允许例如 CertPathBuilder 在同时搜索更多证书的同时搜索 CRL。

2.4.1.1 创建 CertStore 对象 Creating a CertStore Object

  与所有引擎类一样,获取特定存储库类型的 CertStore 对象的方法是调用 CertStore 类上的 getInstance 静态工厂方法之一:

public static CertStore getInstance(String type, CertStoreParameters params)
public static CertStore getInstance(String type, CertStoreParameters params, String provider)
public static CertStore getInstance(String type, CertStoreParameters params, Provider provider)

  type 参数是证书存储库类型的名称(例如 “LDAP”)。标准的 CertStore 类型列在 Java 安全标准算法名称中。

  初始化参数(params)特定于存储库类型。例如,基于服务器的存储库的初始化参数可能包括服务器的主机名和端口号。如果参数对此 CertStore 类型无效,则抛出 InvalidAlgorithmParameterExceptiongetCertStoreParameters 方法返回用于初始化 CertStoreCertStoreParameters

public final CertStoreParameters getCertStoreParameters()
2.4.1.2 检索证书 Retrieving Certificates

  创建了 CertStore 对象之后,您可以使用 getCertificates 方法从存储库中检索证书。这个方法接受一个 CertSelector(稍后将更详细地讨论)对象作为参数,该对象指定了一组选择标准,用于确定应该返回哪些证书:

public final Collection<? extends Certificate> getCertificates(CertSelector selector) 
        throws CertStoreException

  这个方法返回一个满足选择标准的 java.security.cert.Certificate 对象的集合。如果没有匹配项,则返回一个空的集合。如果遇到意外的错误条件,如与远程存储库的通信失败,通常会抛出一个 CertStoreException。

  对于一些 CertStore 实现来说,可能无法对整个存储库进行搜索,以找到与指定选择标准匹配的证书或 CRL。在这些情况下,CertStore 实现可能会使用选择器中指定的信息来定位证书和 CRL。例如,LDAP CertStore 可能不会搜索目录中的所有条目。相反,它可能只搜索可能包含它正在寻找的证书的条目。如果提供的 CertSelector 没有提供足够的信息供 LDAP CertStore 确定它应该查看哪些条目,LDAP CertStore 可能会抛出一个 CertStoreException。

2.4.1.3 检索证书撤销列表 Retrieving CRLs

  您也可以使用 getCRLs 方法从存储库中检索证书撤销列表(CRL)。这个方法接受一个 CRLSelector(稍后将更详细地讨论)对象作为参数,该对象指定了一组选择标准,用于确定应该返回哪些 CRL:

public final Collection<? extends CRL> getCRLs(CRLSelector selector) 
        throws CertStoreException

  这个方法返回一个满足选择标准的 java.security.cert.CRL 对象的集合。如果没有匹配项,则返回一个空的集合。

2.4.2 The CertStoreParameters Interface

  CertStoreParameters 接口是与特定 CertStore 一起使用的参数集的透明表示。

  这个接口的主要目的是将所有证书存储参数规范进行分组,并提供类型安全性。CertStoreParameters 接口扩展了 Cloneable 接口,并定义了一个不抛出异常的 clone 方法。实现此接口的类应该实现并覆盖 Object.clone() 方法(如果需要)。这允许应用程序克隆任何 CertStoreParameters 对象。

  实现 CertStoreParameters 接口的对象作为参数传递给 CertStore 类的 getInstance 方法。此 API 定义了两个实现 CertStoreParameters 接口的类:LDAPCertStoreParameters 类和 CollectionCertStoreParameters 类。

The LDAPCertStoreParameters Class
  LDAPCertStoreParameters 类是 CertStoreParameters 接口的一个实现,它保存了一组最小初始化参数(目录服务器的主机和端口号),用于从 LDAP 类型的 CertStore 检索证书和 CRL。

The CollectionCertStoreParameters Class

  CollectionCertStoreParameters 类是 CertStoreParameters 接口的一个实现,它保存了一组初始化参数,用于从 Collection 类型的 CertStore 检索证书和 CRL。

2.4.3 证书筛选 The CertSelector and CRLSelector Interfaces

  CertSelector 和 CRLSelector 接口是用于从证书和 CRL 的集合或大组中选择证书和 CRL 的标准集。

  这些接口将所有选择器规范进行分组,并提供类型安全性。每个选择器接口都扩展了 Cloneable 并定义了一个不抛出异常的 clone() 方法。这允许应用程序克隆任何 CertSelector 或 CRLSelector 对象。

  CertSelector 和 CRLSelector 接口各自定义了一个名为 match 的方法。match 方法接受一个 Certificate 或 CRL 对象作为参数,如果对象满足选择标准,则返回 true;否则返回 false。CertSelector 接口的 match 方法定义如下:

public boolean match(Certificate cert)

  以及 CRLSelector 接口:

public boolean match(CRL crl)

  通常,实现这些接口的对象作为参数传递给 CertStore 类的 getCertificates 和 getCRLs 方法。这些方法返回 CertStore 存储库中与指定选择标准匹配的 Certificates 或 CRLs 的集合。CertSelectors 也可以用于指定认证路径中目标或终端实体证书的验证约束(例如,参见 PKIXParameters.setTargetCertConstraints 方法)。

2.4.3.1 The X509CertSelector Class

  X509CRLSelector 类是 CRLSelector 接口的一个实现,它定义了选择 X.509 CRL 的一套标准。

  一个 X509CRL 对象必须符合所有指定的标准才能被 match 方法选中。选择标准旨在对需要从存储库中检索 CRL 以检查 X.509 认证路径中证书的吊销状态的 CertPathValidator 或 CertPathBuilder 实现有用。

  例如,X509CRLSelector 的 setDateAndTime 方法允许 PKIX CertPathValidator 过滤掉在指定时间之后发布或之前过期的 X509CRL。通过在 X509CRLSelector 对象中设置此和其他标准,它允许 CertPathValidator 丢弃不相关的 CRL,并更容易地检查证书是否已被吊销。

  请参阅 RFC 5280,了解本节提到的 X.509 CRL 字段和扩展的定义。

2.4.3.1.1 Creating an X509CertSelector Object

  创建 X509CRLSelector 对象是通过调用默认构造函数完成的:

public X509CRLSelector()

最初没有设置任何标准(任何 X509CRL 都会匹配)。

2.4.3.1.2 Setting Selection Criteria

  选择标准允许调用者匹配 X.509 CRL 的不同组成部分。大多数设置选择标准的方法在这里进行了描述。有关其余方法的详细信息,请参阅 X509CRLSelector 类 API 文档。

  setIssuers 和 setIssuerNames 方法设置 issuerNames 标准:

public void setIssuers(Collection<X500Principal> issuers)
public void setIssuerNames(Collection<?> names)

  CRL 中的发行者可分辨名称必须至少与指定的一个可分辨名称匹配。推荐使用 setIssuers 方法,因为使用 X500Principals 来表示可分辨名称更高效且类型更合适。对于 setIssuerNames 方法,names 参数的每个条目可以是字符串或字节数组(分别表示 RFC 2253 或 ASN.1 DER 编码形式的名称)。如果为 null,则任何发行者可分辨名称都可以。

  setMinCRLNumber 和 setMaxCRLNumber 方法设置 minCRLNumber 和 maxCRLNumber 标准:

public void setMinCRLNumber(BigInteger minCRL)
public void setMaxCRLNumber(BigInteger maxCRL)

  如果调用了 setMinCRLNumber 方法,则 CRL 必须具有一个 CRL 编号扩展,其值大于或等于指定的值;如果调用了 setMaxCRLNumber 方法,则小于或等于指定的值。如果传递给这些方法之一的值为 null,则不进行相应的检查。

  setDateAndTime 方法设置 dateAndTime 标准:

public void setDateAndTime(Date dateAndTime)

  指定的日期必须等于或晚于 CRL 的 thisUpdate 组件的值,并且早于 nextUpdate 组件的值。如果为 null,则不进行 dateAndTime 检查。

  setCertificateChecking 方法设置正在检查吊销状态的证书:

public void setCertificateChecking(X509Certificate cert)

  这不是一个标准。相反,这是可选信息,可能有助于 CertStore 查找在检查指定证书的吊销状态时相关的 CRL。如果指定了 null,则不提供此类可选信息。当检查特定证书的吊销状态时,应用程序应始终调用此方法,因为它可能为 CertStore 提供更多信息,以找到正确的 CRL 并过滤掉不相关的 CRL。

2.4.3.1.3 Setting Selection Criteria

  选择标准允许调用者匹配 X.509 证书的不同组成部分。这里描述了一些设置选择标准的方法。请参阅 X509CertSelector 类。

  setIssuer 方法设置发行者标准:

public void setIssuer(X500Principal issuer)
public void setIssuer(String issuerDN)
public void setIssuer(byte[] issuerDN)

  指定的可分辨名称(以 X500Principal、RFC 2253 字符串或 ASN.1 DER 编码形式)必须与证书中的发行者可分辨名称匹配。如果为 null,则任何发行者可分辨名称都可以。注意,推荐使用 X500Principal 来表示可分辨名称,因为它更高效且类型更合适。

  同样地,setSubject 方法设置主题标准:

public void setSubject(X500Principal subject)
public void setSubject(String subjectDN)
public void setSubject(byte[] subjectDN)

  指定的可分辨名称(以 X500Principal、RFC 2253 字符串或 ASN.1 DER 编码形式)必须与证书中的主题可分辨名称匹配。如果为 null,则任何主题可分辨名称都可以。

  setSerialNumber 方法设置序列号标准:

public void setSerialNumber(BigInteger serial)

  指定的序列号必须与证书中的证书序列号匹配。如果为 null,则任何证书序列号都可以。

  setAuthorityKeyIdentifier 方法设置权威密钥标识符标准:

public void setAuthorityKeyIdentifier(byte[] authorityKeyID)

  证书必须包含一个与指定值匹配的权威密钥标识符扩展。如果为 null,则不对权威密钥标识符标准进行检查。

  setCertificateValid 方法设置证书有效性标准:

public void setCertificateValid(Date certValid)

  指定的日期必须在证书的有效期内。如果为 null,则任何日期都是有效的。

  setKeyUsage 方法设置密钥使用标准:

public void setKeyUsage(boolean[] keyUsage)

  证书的密钥使用扩展必须允许指定的密钥使用值(即设置为 true 的那些)。如果为 null,则不进行密钥使用检查。

2.4.3.1.4 Getting Selection Criteria

  可以使用适当的 get 方法检索每个选择标准当前的值。请参阅 X509CertSelector。

  以下是一个使用 X509CertSelector 类从 LDAP CertStore 检索 X.509 证书的示例。

  首先,我们创建 LDAPCertStoreParameters 对象,我们将使用它来使用 LDAP 服务器的主机名和端口初始化 CertStore 对象:

LDAPCertStoreParameters lcsp = new LDAPCertStoreParameters("ldap.sun.com", 389);

  接下来,创建 CertStore 对象,并像以下语句一样传递 LDAPCertStoreParameters 对象:

CertStore cs = CertStore.getInstance("LDAP", lcsp);

  这个调用创建了一个使用 RFC 2587 中定义的模式从 LDAP 存储库检索证书和 CRL 的 CertStore 对象。

  以下代码块设置了一个 X509CertSelector,用于检索所有未过期(截至当前日期和时间)的、针对特定主题颁发的终端实体证书,该证书具有 1)允许数字签名的使用密钥,以及 2)具有特定电子邮件地址的主题备用名称:

X509CertSelector xcs = new X509CertSelector();

// 仅选择未过期的证书
xcs.setCertificateValid(new Date());

// 仅选择颁发给
// 'CN=alice, O=xyz, C=us'
xcs.setSubject(new X500Principal("CN=alice, O=xyz, C=us"));

// 仅选择终端实体证书
xcs.setBasicConstraints(-2);

// 仅选择设置了数字签名的证书
// 密钥使用位(将布尔数组的第一个条目设置为 true)
boolean[] keyUsage = {true};
xcs.setKeyUsage(keyUsage);

// 仅选择具有主题备选名称的证书
// 'alice@xyz.example.com'(1 是 RFC822Name 的整数值)
xcs.addSubjectAlternativeName(1, "alice@xyz.example.com");

  然后我们将选择器传递给我们之前创建的 CertStore 对象的 getCertificates 方法:

Collection<Certificate> certs = cs.getCertificates(xcs);

  PKIX CertPathBuilder 可能使用类似的代码来帮助发现和筛选潜在的证书,通过丢弃那些不符合验证约束或其他标准证书。

2.4.3.2 The X509CRLSelector Class

  X509CRLSelector 类是 CRLSelector 接口的一个实现,它定义了选择 X.509 CRL 的一套标准。

  一个 X509CRL 对象必须符合所有指定的标准才能被 match 方法选中。选择标准旨在对需要从存储库中检索 CRL 以检查 X.509 认证路径中证书的吊销状态的 CertPathValidator 或 CertPathBuilder 实现有用。

  例如,X509CRLSelector 的 setDateAndTime 方法允许 PKIX CertPathValidator 过滤掉在指定时间之后发布或之前过期的 X509CRL。通过在 X509CRLSelector 对象中设置此和其他标准,它允许 CertPathValidator 丢弃不相关的 CRL,并更容易地检查证书是否已被吊销。

  有关本节中提到的 X.509 CRL 字段和扩展的定义,请参阅 RFC 5280。

2.4.3.2.1 Creating an X509CRLSelector Object

  通过调用默认构造函数来创建 X509CRLSelector 对象:

public X509CRLSelector()

  最初不设置任何标准(任何 X509CRL 都将匹配)。

2.4.3.2.2 Setting Selection Criteria

  选择标准允许调用者匹配 X.509 CRL 的不同组成部分。设置选择标准的大部分方法在这里进行了描述。有关其余方法的详细信息,请参阅 X509CRLSelector 类 API 文档。

  setIssuers 和 setIssuerNames 方法设置 issuerNames 标准:

public void setIssuers(Collection<X500Principal> issuers)
public void setIssuerNames(Collection<?> names)

  CRL 中的发行者可分辨名称必须至少与指定的一个可分辨名称匹配。推荐使用 setIssuers 方法,因为使用 X500Principals 表示可分辨名称更高效且类型更合适。对于 setIssuerNames 方法,names 参数的每个条目可以是字符串或字节数组(分别表示 RFC 2253 格式或 ASN.1 DER 编码形式的名称)。如果为 null,则任何发行者可分辨名称都可以。

  setMinCRLNumber 和 setMaxCRLNumber 方法设置 minCRLNumber 和 maxCRLNumber 标准:

public void setMinCRLNumber(BigInteger minCRL)
public void setMaxCRLNumber(BigInteger maxCRL)

如果调用了 setMinCRLNumber 方法,则 CRL 必须具有一个 CRL 编号扩展,其值大于或等于指定的值;如果调用了 setMaxCRLNumber 方法,则小于或等于指定的值。如果传递给这些方法之一的值为 null,则不进行相应的检查。

  setDateAndTime 方法设置 dateAndTime 标准:

public void setDateAndTime(Date dateAndTime)

  指定的日期必须等于或晚于 CRL 的 thisUpdate 组件的值,并且早于 nextUpdate 组件的值。如果为 null,则不进行 dateAndTime 检查。

  setCertificateChecking 方法设置正在检查吊销状态的证书:

public void setCertificateChecking(X509Certificate cert)

  这不是一个标准。相反,这是可选信息,可能有助于 CertStore 查找在检查指定证书的吊销状态时相关的 CRL。如果指定了 null,则不提供此类可选信息。当检查特定证书的吊销状态时,应用程序应始终调用此方法,因为它可能为 CertStore 提供更多信息,以找到正确的 CRL 并过滤掉不相关的 CRL。

2.4.3.2.3 Getting Selection Criteria

  可以使用适当的 get 方法检索每个选择标准当前的值。有关这些方法的更多详细信息,请参阅 X509CRLSelector 类 API 文档。

  创建一个 X509CRLSelector 以从 LDAP 存储库检索 CRL 与 X509CertSelector 示例类似。假设我们想要检索由特定 CA 发行的所有当前(截至当前日期和时间)的 CRL,并且具有最小 CRL 编号。首先,我们创建一个 X509CRLSelector 对象,并调用适当的方法来设置选择标准:

X509CRLSelector xcrls = new X509CRLSelector();
// 选择满足当前日期和时间的 CRL
xcrls.setDateAndTime(new Date());
// 选择由 'O=xyz, C=us' 发行的 CRL
xcrls.addIssuerName("O=xyz, C=us");
// 仅选择 CRL 编号至少为 '2' 的 CRL
xcrls.setMinCRLNumber(new BigInteger("2"));

  然后我们将选择器传递给我们的 CertStore 对象的 getCRLs 方法(在 X509CertSelector 示例中创建):

Collection<CRL> crls = cs.getCRLs(xcrls);

2.5 、PKIX类 PKIX Classes

  Java 认证路径 API 包括一组为 PKIX 认证路径验证算法建模的特定算法类。

  JPKIX 认证路径验证算法在 RFC 5280 中定义:互联网 X.509 公钥基础设施证书和证书撤销列表(CRL)配置文件。

2.5.1 The TrustAnchor Class

  TrustAnchor 类表示一个“最受信任的 CA”(证书颁发机构),它被用作验证 X.509 认证路径的信任锚点。

  TrustAnchor 包括 CA 的公钥、CA 的名称以及使用此密钥可以验证的路径集的任何限制。这些参数可以以受信任的 X509Certificate 的形式指定,也可以作为单独的参数指定。

  所有 TrustAnchor 对象都是不可变的和线程安全的。也就是说,多个线程可以同时调用此类中定义的方法在单个 TrustAnchor 对象(或多个对象)上,而不会产生不良影响。要求 TrustAnchor 对象是不可变的和线程安全的,允许它们在各种代码之间传递,而不必担心协调访问。

  注意:尽管这个类被描述为 PKIX 类,但它可能被用于其他 X.509 认证路径验证算法。

2.5.1.1 创建 TrustAnchor 对象

  要实例化一个 TrustAnchor 对象,调用者必须将“最受信任的 CA”指定为一个受信任的 X509Certificate 或公钥和可分辨名称对。调用者还可以选择性地指定在初始化期间由验证算法应用于信任锚点的名称限制。请注意,PKIX 算法并不要求支持对信任锚点的名称限制,因此 PKIX CertPathValidator 或 CertPathBuilder 可以选择不支持此参数,而是抛出一个异常。使用以下构造函数之一来创建 TrustAnchor 对象:

public TrustAnchor(X509Certificate trustedCert, 
        byte[] nameConstraints)
public TrustAnchor(X500Principal caPrincipal, PublicKey pubKey, 
        byte[] nameConstraints)
public TrustAnchor(String caName, PublicKey pubKey, 
        byte[] nameConstraints)

  nameConstraints 参数被指定为一个包含 NameConstraints 扩展的 ASN.1 DER 编码的字节数组。如果名称限制无法解码(格式不正确),则会抛出 IllegalArgumentException。

2.5.1.2 获取参数值

  每个参数都可以使用相应的 get 方法检索:

public final X509Certificate getTrustedCert()
public final X500Principal getCA()
public final String getCAName()
public final PublicKey getCAPublicKey()
public final byte[] getNameConstraints()

  注意:如果信任锚点是作为公钥和名称对指定的,则 getTrustedCert 方法返回 null。同样地,如果信任锚点是作为 X509Certificate 指定的,则 getCA、getCAName 和 getCAPublicKey 方法返回 null。

2.5.2 The PKIXParameters Class

  PKIXParameters 类指定了 PKIX 认证路径验证算法所定义的输入参数集。它还包括一些其他有用的参数。

  这个类实现了 CertPathParameters 接口。

  X.509 CertPath 对象和 PKIXParameters 对象被作为参数传递给实现 PKIX 算法的 CertPathValidator 实例的 validate 方法。CertPathValidator 使用这些参数来初始化 PKIX 认证路径验证算法。

2.5.2.1 创建 PKIXParameters 对象

  要实例化一个 PKIXParameters 对象,调用者必须按照 PKIX 验证算法所定义的方式指定“最受信任的 CA”。最受信任的 CA 可以使用以下两种构造函数之一来指定:

public PKIXParameters(Set<TrustAnchor> trustAnchors) 
    throws InvalidAlgorithmParameterException
public PKIXParameters(KeyStore keystore)
    throws KeyStoreException, InvalidAlgorithmParameterException

  第一个构造函数允许调用者将最受信任的 CA 指定为 TrustAnchor 对象的集合。或者,调用者可以使用第二个构造函数并指定一个包含受信任证书条目的 KeyStore 实例,每个条目都将被视为最受信任的 CA。

2.5.2.2 设置参数值

  在创建了 PKIXParameters 对象之后,调用者可以设置(或替换当前值)各种参数。这里描述了一些设置参数的方法。有关其他方法的详细信息,请参阅 PKIXParameters API 文档。

  setInitialPolicies 方法设置了初始策略标识符,由 PKIX 验证算法指定。集合中的元素是表示为字符串的对象标识符(OID)。如果 initialPolicies 参数为 null 或未设置,则任何策略都是可以接受的:

public void setInitialPolicies(Set<String> initialPolicies)

  setDate 方法设置了确定路径有效性的时间。如果日期参数未设置或为 null,则使用当前日期:

public void setDate(Date date)

  setPolicyMappingInhibited 方法设置了策略映射禁止标志的值。如果未指定标志的默认值,则为 false:

public void setPolicyMappingInhibited(boolean val)

  setExplicitPolicyRequired 方法设置了显式策略所需标志的值。如果未指定标志的默认值,则为 false:

public void setExplicitPolicyRequired(boolean val)

  setAnyPolicyInhibited 方法设置了任何策略禁止标志的值。如果未指定标志的默认值,则为 false:

public void setAnyPolicyInhibited(boolean val)

  setTargetCertConstraints 方法允许调用者设置目标或终端实体证书的限制。例如,调用者可以指定目标证书必须包含特定的主题名称。限制被指定为 CertSelector 对象。如果选择器参数为 null 或未设置,则未为目标证书定义限制:

public void setTargetCertConstraints(CertSelector selector)

  setCertStores 方法允许调用者指定一个 CertStore 对象列表,PKIX 实现的 CertPathValidator 将使用该列表来查找路径验证的 CRL。这提供了一个可扩展的机制,用于指定在哪里查找 CRL。setCertStores 方法将 CertStore 对象列表作为参数。列表中的第一个 CertStores 可能比后面的更受青睐。

public void setCertStores(List<CertStore> stores)

  setCertPathCheckers 方法允许调用者通过创建特定于实现的认证路径检查器来扩展 PKIX 验证算法。例如,这种机制可以用来处理私有证书扩展。setCertPathCheckers 方法将 PKIXCertPathChecker(稍后讨论)对象列表作为参数:

public void setCertPathCheckers(List<PKIXCertPathChecker> checkers)

  setRevocationEnabled 方法允许调用者禁用撤销检查。撤销检查默认启用,因为它是 PKIX 验证算法所需的检查。然而,PKIX 没有定义应该如何检查撤销。实现可能使用 CRL 或 OCSP 等。如果调用者认为不适当,此方法允许调用者禁用实现的默认撤销检查机制。然后,可以通过调用 setCertPathCheckers 方法,并传递一个实现替代机制的 PKIXCertPathChecker 来指定不同的撤销检查机制。

public void setRevocationEnabled(boolean val)

  setPolicyQualifiersRejected 方法允许调用者启用或禁用策略限定符处理。当创建 PKIXParameters 对象时,此标志设置为 true。这种设置反映了处理策略限定符的最常见(也是最简单的)策略。想要使用更复杂策略的应用程序必须将此标志设置为 false。

public void setPolicyQualifiersRejected(boolean qualifiersRejected)
2.5.2.3 获取参数值

  可以使用适当的 get 方法检索每个参数的当前值。有关这些方法的更多详细信息,请参阅 PKIXParameters 类 API 文档。

2.5.3 The CertPathValidatorResult Interface

  PKIXCertPathValidatorResult 类表示 PKIX 认证路径验证算法的结果。

  这个类实现了 CertPathValidatorResult 接口。它持有验证算法产生的有效策略树和主题公钥,并包括用于返回它们的方法(getPolicyTree() 和 getPublicKey())。PKIXCertPathValidatorResult 的实例由实现 PKIX 算法的 CertPathValidator 对象的 validate 方法返回。

  有关这个类的更详细信息,请参阅 PKIXCertPathValidatorResult API 文档。

2.5.4 The PolicyNode Interface and PolicyQualifierInfo Class

  PKIX验证算法定义了几个与证书策略处理相关的输出。大多数应用程序不需要使用这些输出,但所有实现PKIX验证或构建算法的提供者都必须支持它们。

  PolicyNode接口表示由PKIX证书路径验证成功执行后得到的一个有效策略树的节点。应用程序可以使用PKIXCertPathValidatorResult的getPolicyTree方法获取有效策略树的根。RFC 5280中更详细地讨论了策略树。

  PolicyNode的getPolicyQualifiers方法返回一组PolicyQualifierInfo对象,每个对象表示应用此策略的相关证书的证书策略扩展中包含的策略限定符。

  大多数应用程序不需要检查有效策略树和策略限定符。它们可以通过在PKIXParameters中设置与策略相关的参数来实现其策略处理目标。然而,对于更复杂的应用程序,特别是那些处理策略限定符的应用程序,有效策略树是可用的。

  请参考接口PolicyNode和PolicyQualifierInfo API文档以获取有关这些类的更详细信息。

  示例9-1 使用PKIX算法验证证书路径的示例

  这是一个使用PKIX验证算法验证证书路径的示例。示例忽略了大部分异常处理,并假设证书路径和信任锚的公钥已经被创建。

  首先,创建CertPathValidator,如下所示:

CertPathValidator cpv = CertPathValidator.getInstance("PKIX");

  下一步是创建TrustAnchor对象。这将用作验证证书路径的锚点。在这个示例中,最可信的CA被指定为公钥和名称(名称约束不适用,指定为null):

TrustAnchor anchor = new TrustAnchor("O=xyz,C=us", pubkey, null);

  下一步是创建PKIXParameters对象。这将用于填充PKIX算法使用的参数。在这个示例中,我们将一个包含单个元素的Set传递给构造函数 - 我们在上一步创建的TrustAnchor:

PKIXParameters params = new PKIXParameters(Collections.singleton(anchor));

  接下来,我们用验证算法使用的约束或其他参数填充参数对象。在这个示例中,我们启用了explicitPolicyRequired标志,并指定了一组初始策略OID(集合的内容未显示):

// 在此处设置其他PKIX参数
params.setExplicitPolicyRequired(true);
params.setInitialPolicies(policyIds);

  最后一步是使用我们创建的输入参数集验证证书路径:

try {
    PKIXCertPathValidatorResult result =
        (PKIXCertPathValidatorResult) cpv.validate(certPath, params);
    PolicyNode policyTree = result.getPolicyTree();
    PublicKey subjectPublicKey = result.getPublicKey();
} catch (CertPathValidatorException cpve) {
    System.out.println("Validation failure, cert[" 
        + cpve.getIndex() + "] :" + cpve.getMessage());
}

  如果验证算法成功,可以使用PKIXCertPathValidatorResult的getPolicyTree和getPublicKey方法获取验证算法产生的策略树和主题公钥。

  否则,将抛出CertPathValidatorException,调用者可以捕获异常并打印一些关于失败的详细信息,例如错误消息和导致失败的证书的索引。

2.5.5 The PKIXBuilderParameters Class

  PKIXBuilderParameters类指定了与CertPathBuilder类一起使用的参数集。

  这个类(它扩展了PKIXParameters类)指定了与构建针对PKIX证书路径验证算法验证的证书路径的CertPathBuilder类一起使用的参数集。

  PKIXBuilderParameters对象作为参数传递给实现PKIX算法的CertPathBuilder实例的build方法。所有PKIX CertPathBuilders必须返回根据PKIX证书路径验证算法验证过的证书路径。

  请注意,PKIX CertPathBuilder用来验证构建路径的机制是一个实现细节。例如,一个实现可能首先尝试以最小验证构建路径,然后使用PKIX CertPathValidator的实例进行完全验证,而更高效的实现可能在构建路径的同时进行更多的验证,并在遇到验证失败或死胡同时回溯到先前的阶段。

2.5.5.1 创建PKIXBuilderParameters对象

  创建PKIXBuilderParameters对象类似于创建PKIXParameters对象。然而,在创建PKIXBuilderParameters对象时,调用者必须指定目标或终端实体证书的约束条件。这些约束条件应该为CertPathBuilder提供足够的信息以找到目标证书。约束条件被指定为CertSelector对象。使用以下构造函数之一创建PKIXBuilderParameters对象:

public PKIXBuilderParameters(Set<TrustAnchor> trustAnchors, 
        CertSelector targetConstraints)
        throws InvalidAlgorithmParameterException
public PKIXBuilderParameters(KeyStore keystore, 
        CertSelector targetConstraints) 
        throws KeyStoreException, InvalidAlgorithmParameterException
2.5.5.2 获取/设置参数值

  PKIXBuilderParameters类继承了可以在PKIXParameters类中设置的所有参数。此外,可以调用setMaxPathLength方法来限制证书路径中证书的最大数量:

public void setMaxPathLength(int maxPathLength)

  maxPathLength参数指定了在证书路径中可能存在的非自签名中间证书的最大数量。实现PKIX算法的CertPathBuilder实例不能构建超过指定长度的路径。如果值为0,则路径只能包含单个证书。如果值为-1,则路径长度不受限制(即,没有最大值)。如果未指定,默认的最大路径长度为5。此方法可用于防止CertPathBuilder花费资源和时间构建可能或可能不符合调用者要求的长路径。

如果路径中的任何CA证书包含基本约束扩展,则扩展的pathLenConstraint组件的值将覆盖maxPathLength参数的值,只要结果是更短的证书路径。还有一个对应的getMaxPathLength方法用于检索此参数:

public int getMaxPathLength()

  此外,从PKIXParameters类继承的setCertStores方法通常由CertPathBuilder的PKIX实现用来寻找路径构建的证书以及寻找路径验证的CRL。这提供了一个可扩展的机制,用于指定在哪里定位证书和CRL。

2.5.6 The PKIXCertPathBuilderResult Class

  PKIXCertPathBuilderResult类表示PKIX证书路径构建算法的成功结果。

  这个类扩展了PKIXCertPathValidatorResult类并实现了CertPathBuilder接口。PKIXCertPathBuilderResult的实例由实现PKIX算法的CertPathBuilder对象的build方法返回。

  PKIXCertPathBuilderResult实例的getCertPath方法总是返回一个使用PKIX证书路径验证算法验证的CertPath对象。返回的CertPath对象不包括可能已用于锚定路径的最可信CA证书。相反,使用getTrustAnchor方法获取最可信CA的证书。

  有关这个类的更详细信息,请参见PKIXCertPathBuilderResult API文档。

  示例9-2 使用PKIX算法构建证书路径的示例

  这是一个针对PKIX算法验证的证书路径构建示例。一些细节已被省略,例如异常处理,以及创建用于填充CertStore的信任锚和证书。

  首先,创建CertPathBuilder,如下例所示:

CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX");

  这个调用创建了一个CertPathBuilder对象,该对象返回针对PKIX算法验证的路径。

  下一步是创建一个PKIXBuilderParameters对象。这将用于填充CertPathBuilder使用的PKIX参数:

// 创建参数对象,传递给它一个信任锚点集
// 用于锚定路径和目标主题DN。
X509CertSelector targetConstraints = new X509CertSelector();
targetConstraints.setSubject("CN=alice,O=xyz,C=us");
PKIXBuilderParameters params = 
    new PKIXBuilderParameters(trustAnchors, targetConstraints);

  下一步是指定CertPathBuilder将用于查找证书和CRL的CertStore。在这个示例中,我们将使用证书和CRL填充一个集合CertStore:

CollectionCertStoreParameters ccsp = 
    new CollectionCertStoreParameters(certsAndCrls);
CertStore store = CertStore.getInstance("Collection", ccsp);
params.addCertStore(store);

  下一步是使用我们创建的输入参数集构建证书路径:

try {
    PKIXCertPathBuilderResult result = 
        (PKIXCertPathBuilderResult) cpb.build(params);
    CertPath cp = result.getCertPath();
} catch (CertPathBuilderException cpbe) {
    System.out.println("build failed: " + cpbe.getMessage());
}

  如果CertPathBuilder无法构建符合所提供参数的路径,它将抛出CertPathBuilderException。否则,可以使用getCertPath方法从PKIXCertPathBuilderResult获取经过验证的证书路径。

2.5.7 The PKIXCertPathChecker Class

  PKIXCertPathChecker类允许用户扩展PKIX CertPathValidator或CertPathBuilder实现。这是一个高级特性,大多数用户不需要了解。然而,任何实现PKIX服务提供商的人都应该阅读本节。

  PKIXCertPathChecker类是一个抽象类,它对X.509证书执行一个或多个检查。开发者在需要在运行时动态扩展PKIX CertPathValidator或CertPathBuilder实现时,应该创建PKIXCertPathChecker类的具现实现。以下是PKIXCertPathChecker实现有用的几个示例:

  如果PKIX CertPathValidator或CertPathBuilder实现提供的撤销机制不够充分:例如,你可以使用PKIXRevocationChecker(在JDK 8中引入;见使用PKIXRevocationChecker类检查证书的撤销状态)来更控制撤销机制,或者你可以实现你自己的PKIXCertPathChecker来检查证书是否已被撤销。

  如果用户想要识别包含关键私有扩展的证书。由于该扩展是私有的,它将不被PKIX CertPathValidator或CertPathBuilder实现识别,并将抛出CertPathValidatorException。在这种情况下,开发者可以实现一个PKIXCertPathChecker来识别并处理关键私有扩展。

  如果开发者想要记录每个处理过的证书的信息,用于调试或显示目的。

  如果用户想要拒绝具有某些政策限定符的证书。

  PKIXParameters类的setCertPathCheckers方法允许用户向PKIX CertPathValidator或CertPathBuilder实现传递PKIXCertPathChecker对象的列表。每个PKIXCertPathChecker对象将依次被调用,用于PKIX CertPathValidator或CertPathBuilder实现处理的每个证书。

2.5.7.1 创建和使用PKIXCertPathChecker对象

  PKIXCertPathChecker类没有公共构造函数。这是有意为之,因为创建PKIXCertPathChecker的实例是一个特定于实现的问题。例如,使用OCSP检查证书撤销状态的PKIXCertPathChecker实现的构造函数可能需要OCSP服务器的主机名和端口:

PKIXCertPathChecker checker = new OCSPChecker("ocsp.sun.com", 1321);

  一旦检查器实例化后,它可以被添加为参数,使用PKIXParameters类的addCertPathChecker方法:

params.addCertPathChecker(checker);

  或者,可以使用PKIXParameters类的setCertPathCheckers方法添加检查器列表。

2.5.7.2 实现PKIXCertPathChecker对象

  PKIXCertPathChecker类是抽象的。它有四个方法(check、getSupportedExtensions、init和isForwardCheckingSupported),所有具现子类都必须实现。

  实现PKIXCertPathChecker可能很简单,也可能很复杂。PKIXCertPathChecker实现可以是无状态的或有状态的。无状态实现在连续调用check方法之间不维护状态。例如,检查每个证书是否包含特定政策限定符的PKIXCertPathChecker是无状态的。相反,有状态实现在连续调用check方法之间维护状态。有状态实现的check方法通常依赖于证书路径中先前证书的内容。例如,处理NameConstraints扩展的PKIXCertPathChecker是有状态的。

  此外,服务提供商实现处理的证书呈现(传递)给PKIXCertPathChecker的顺序非常重要,特别是如果实现是有状态的。根据服务提供商使用的算法,证书可能以相反或正向顺序呈现。相反的顺序意味着证书从最可信的CA(如果有的话)到目标主题排序,而正向排序意味着证书从目标主题到最可信的CA排序。顺序必须告知PKIXCertPathChecker实现,以便它知道如何处理连续的证书。

2.5.7.3 初始化PKIXCertPathChecker对象

  init方法初始化检查器的内部状态:

public abstract void init(boolean forward)

  所有有状态实现应该清除或初始化检查器中的任何内部状态。这防止服务提供商实现调用处于未初始化状态的检查器。它还允许有状态检查器在后续操作中重用,而无需重新实例化它们。forward参数指示呈现给PKIXCertPathChecker的证书的顺序。如果forward为true,则证书从目标到信任锚点呈现;如果为false,则从信任锚点到目标。

2.5.7.4 正向检查

  isForwardCheckingSupported方法返回一个布尔值,指示PKIXCertPathChecker是否支持正向检查:

public abstract boolean isForwardCheckingSupported()

  所有PKIXCertPathChecker实现都必须支持反向检查。PKIXCertPathChecker实现可能支持正向检查。

  支持正向检查可以提高构建正向的CertPathBuilders的效率,因为它允许在构建过程中检查路径。然而,一些有状态的PKIXCertPathCheckers可能发现支持正向检查很困难或不可能。

2.5.7.5 支持的扩展

  getSupportedExtensions方法返回PKIXCertPathChecker实现支持的X.509扩展的不可变集合的OID字符串(即,识别、能够处理):

public abstract Set<String> getSupportedExtensions()

  如果没有处理任何扩展,则该方法应该返回null。所有实现都应该返回check方法可能处理的OID字符串集合。

  CertPathBuilder可以使用这些信息来识别具有未识别关键扩展的证书,即使在使用不支持正向检查的PKIXCertPathChecker进行正向构建时也是如此。

2.5.7.6 执行检查

  以下方法对证书执行检查:

public abstract void 
        check(Certificate cert, Collection<String> unresolvedCritExts)
        throws CertPathValidatorException

  unresolvedCritExts参数包含作为字符串的OID集合。这些OID代表证书中尚未由证书路径验证算法解决的关键扩展集。check方法的具体实现应该从unresolvedCritExts参数中移除它处理的任何关键扩展。

  如果证书未通过检查,应该抛出CertPathValidatorException。

2.5.7.7 克隆PKIXCertPathChecker

  PKIXCertPathChecker类实现了Cloneable接口。所有有状态的PKIXCertPathChecker实现必须在必要时覆盖clone方法。clone方法的默认实现调用Object.clone方法,它通过复制原始对象的所有字段到新对象来执行简单克隆。无状态实现不应该覆盖clone方法。然而,所有有状态实现都必须确保默认的clone方法是正确的,并在必要时覆盖它。例如,存储状态在数组中的PKIXCertPathChecker必须覆盖clone方法来复制数组,而不仅仅是数组的引用。

  PKIXCertPathChecker对象是Cloneable的原因是为了允许PKIX CertPathBuilder实现在潜在证书路径达到死胡同时有效地回溯并尝试另一条路径。在这种情况下,实现能够通过恢复克隆的对象来恢复先前的路径验证状态。

  示例9-3 检查私有扩展的示例代码

  这是一个无状态PKIXCertPathChecker实现的示例。它检查证书中是否存在私有扩展,并根据某些规则进行处理。

import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.security.cert.PKIXCertPathChecker;
import java.security.cert.CertPathValidatorException;

public class MyChecker extends PKIXCertPathChecker {
    private static Set supportedExtensions =
        Collections.singleton("2.16.840.1.113730.1.1");

    /*
     * 初始化检查器
     */
    public void init(boolean forward) 
        throws CertPathValidatorException {
        // 无需初始化
    }

    public Set getSupportedExtensions() {        
        return supportedExtensions;
    }

    public boolean isForwardCheckingSupported() {
        return true;
    }

    /*
     * 检查证书是否存在Netscape的
     * 私有扩展
     * 带有OID "2.16.840.1.113730.1.1"
     */
    public void check(Certificate cert, 
                      Collection unresolvedCritExts)
        throws CertPathValidatorException 
    {
        X509Certificate xcert = (X509Certificate) cert;
        byte[] ext = 
            xcert.getExtensionValue("2.16.840.1.113730.1.1");
        if (ext == null)
            return;

        //
        // 根据某些规则处理私有扩展 - 如果检查失败,抛出一个 
        // CertPathValidatorException ...
        // {在这里插入代码}

        // 从未解决的扩展集合中移除扩展(如果存在)
        if (unresolvedCritExts != null)
            unresolvedCritExts.remove("2.16.840.1.113730.1.1");
    }
}
2.5.7.8 PKIX服务提供商实现应如何使用PKIXCertPathChecker

  在开始构建或验证算法之前,每个PKIXCertPathChecker对象都必须由服务提供商实现初始化,例如:

List<PKIXCertPathChecker> checkers = params.getCertPathCheckers();
for (PKIXCertPathChecker checker : checkers) {
    checker.init(false);
}

  对于它验证的每个证书,服务提供商实现必须依次调用每个PKIXCertPathChecker对象的check方法,传递给它证书和任何剩余的未解决的关键扩展:

for (PKIXCertPathChecker checker : checkers) {
    checker.check(cert, unresolvedCritExts);
}

  如果任何检查抛出CertPathValidatorException,CertPathValidator实现应该终止验证过程。然而,CertPathBuilder实现可能只是记录失败并继续寻找其他潜在路径。如果所有检查都成功

2.5.8 Using PKIXCertPathChecker in Certificate Path Validation

  使用PKIXCertPathChecker自定义证书路径验证相对直接。

2.5.8.1 基本证书路径验证

  首先,考虑验证证书路径的代码:

Set<TrustAnchor> trustAnchors = getTrustAnchors();
CertPath cp = getCertPath();

PKIXParameters pkixp = new PKIXParameters(trustAnchors);
pkixp.setRevocationEnabled(false);

CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
PKIXCertPathValidatorResult pcpvr =
    (PKIXCertPathValidatorResult)cpv.validate(cp, pkixp);
如果验证失败,validate()方法会抛出异常。

  基本步骤如下:

  1. 获取CA根证书和要验证的证书路径。
  2. 使用信任锚点创建PKIXParameters。
  3. 使用CertPathValidator验证证书路径。
    在这个示例中,getTrustAnchors()和getCertPath()是获取CA根证书和证书路径的方法。

  示例中的getTrustAnchors()方法必须返回一个表示要用于验证的CA根证书的TrustAnchors集合。以下是一个从文件中加载单个CA根证书的简单实现:

public Set<TrustAnchor> getTrustAnchors()
    throws IOException, CertificateException {

  CertificateFactory cf = CertificateFactory.getInstance("X.509");

  X509Certificate c;
  try (InputStream in = new FileInputStream("x509_ca-certificate.cer")) {
    c = (X509Certificate)cf.generateCertificate(in);
  }

  TrustAnchor anchor = new TrustAnchor(c, null);
  return Collections.singleton(anchor);
}

  类似地,以下是一个从文件中加载证书路径的getCertPath()的简单实现:

public CertPath getCertPath() throws IOException, CertificateException {
  CertificateFactory cf = CertificateFactory.getInstance("X.509");

  CertPath cp;
  try (InputStream in = new FileInputStream("certpath.pkcs7")) {     
    cp = cf.generateCertPath(in, "PKCS7");
  }   
  return cp;
}

  请注意,PKCS#7不要求文件中的证书有特定顺序,所以这段代码仅在证书从要验证的实体开始,并向CA根回溯时有序的情况下工作。如果证书顺序不正确,你需要进行一些额外的处理。CertificateFactory有一个接受Collection的generateCertPath()方法,这对于这种类型的处理很有用。

2.5.8.2 加入PKIXCertPathChecker

  要自定义证书路径验证,请按如下方式添加PKIXCertPathChecker。在这个示例中,SimpleChecker是PKIXCertPathChecker的一个子类。新行以粗体显示。

Set<TrustAnchor> trustAnchors = getTrustAnchors();
CertPath cp = getCertPath();

PKIXParameters pkixp = new PKIXParameters(trustAnchors);
pkixp.setRevocationEnabled(false);

SimpleChecker sc = new SimpleChecker();
pkixp.addCertPathChecker(sc);

CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
PKIXCertPathValidatorResult pcpvr =
    (PKIXCertPathValidatorResult)cpv.validate(cp, pkixp);

  SimpleChecker是PKIXCertPathChecker的一个基础子类。它的check()方法将对正在验证的证书路径中的每个证书被调用。SimpleChecker使用AlgorithmConstraints实现来检查每个证书的签名算法和公钥。

import java.security.AlgorithmConstraints;
import java.security.CryptoPrimitive;
import java.security.Key;
import java.security.cert.*;
import java.util.*;

public class SimpleChecker extends PKIXCertPathChecker {
  private final static Set<CryptoPrimitive> SIGNATURE_PRIMITIVE_SET =
      EnumSet.of(CryptoPrimitive.SIGNATURE);
  
  public void init(boolean forward) throws CertPathValidatorException {}
  
  public boolean isForwardCheckingSupported() { return true; }
  
  public Set<String> getSupportedExtensions() { return null; }
  
  public void check(Certificate cert,
      Collection<String> unresolvedCritExts)
      throws CertPathValidatorException {
    X509Certificate c = (X509Certificate)cert;
    String sa = c.getSigAlgName();
    Key key = c.getPublicKey();
    
    AlgorithmConstraints constraints = new SimpleConstraints();
    
    if (constraints.permits(SIGNATURE_PRIMITIVE_SET, sa, null) == false)
      throw new CertPathValidatorException("Forbidden algorithm: " + sa);

    if (constraints.permits(SIGNATURE_PRIMITIVE_SET, key) == false)
      throw new CertPathValidatorException("Forbidden key: " + key);
  }
}

  最后,SimpleConstraints是AlgorithmConstraints的一个实现,它要求使用RSA 2048。

import java.security.AlgorithmConstraints;
import java.security.AlgorithmParameters;
import java.security.CryptoPrimitive;
import java.security.Key;
import java.security.interfaces.RSAKey;
import java.util.Set;

public class SimpleConstraints implements AlgorithmConstraints {
  public boolean permits(Set<CryptoPrimitive> primitives,
      String algorithm, AlgorithmParameters parameters) {
    return permits(primitives, algorithm, null, parameters);
  }

  public boolean permits(Set<CryptoPrimitive> primitives, Key key) {
    return permits(primitives, null, key, null);
  }
  
  public boolean permits(Set<CryptoPrimitive> primitives,
      String algorithm, Key key, AlgorithmParameters parameters) {
    if (algorithm == null) algorithm = key.getAlgorithm();
    
    if (algorithm.indexOf("RSA") == -1) return false;
    
    if (key != null) {
      RSAKey rsaKey = (RSAKey)key;
      int size = rsaKey.getModulus().bitLength();
      if (size < 2048) return false;
    }

    return true;
  }
}
2.5.8.3 使用PKIXRevocationChecker类检查证书的撤销状态

  PKIXRevocationChecker的一个实例使用在线证书状态协议(OCSP)或证书撤销列表(CRL)检查证书的撤销状态。

  PKIXRevocationChecker(在JDK 8中引入),是PKIXCertPathChecker的一个子类,使用PKIX算法检查证书的撤销状态。

  PKIXRevocationChecker的一个实例使用在线证书状态协议(OCSP)或证书撤销列表(CRL)检查证书的撤销状态。OCSP在RFC 2560中描述,是一个用于确定证书状态的网络协议。CRL是一个带有时间戳的列表,用于识别已撤销的证书,RFC 5280描述了使用CRL确定证书撤销状态的算法。

  每个PKIX CertPathValidator和CertPathBuilder实例提供了一个默认的撤销实现,默认情况下是启用的。如果你想对那个实现使用的撤销设置有更多的控制,使用PKIXRevocationChecker类。

  使用PKIXRevocationChecker类检查证书路径的撤销状态,请遵循以下一般步骤:

  1. 通过调用PKIX CertPathValidator或CertPathBuilder实例的getRevocationChecker方法,获取PKIXRevocationChecker实例。
  2. 使用PKIXRevocationChecker类中包含的方法设置特定于证书撤销的附加参数和选项。这些方法包括setOCSPResponder(URI),它设置用于标识OCSP响应器位置的URI(尽管通常URI包含在证书中,不需要设置),以及setOptions(Set<PKIXRevocationChecker.Option>),它设置撤销选项。PKIXRevocationChecker.Option是一个枚举类型,用于指定以下选项:
    • ONLY_END_ENTITY:仅检查终端实体证书的撤销状态。
    • PREFER_CRLS:默认情况下,OCSP是检查撤销状态的首选机制,CRL作为备选机制。使用此选项将此偏好切换为CRL。
    • SOFT_FAIL:忽略网络故障。
  3. 获取PKIXRevocationChecker实例后,使用addCertPathChecker或setCertPathCheckers方法将其添加到PKIXParameters或PKIXBuilderParameters对象中。

根据你是使用PKIX CertPathValidator实例还是CertPathBuilder实例,执行以下步骤之一:

  • 如果你正在使用PKIX CertPathValidator实例,请使用要验证的证书路径和包含撤销检查器的PKIXParameters对象作为参数调用validate方法。
  • 如果你正在使用PKIX CertPathBuilder实例,请使用包含撤销检查器的PKIXBuilderParameters对象作为参数调用build方法。

  使用要验证的证书路径和包含撤销检查器的PKIXParameters或PKIXBuilderParameters对象作为参数,调用PKIX CertPathValidator或CertPathBuilder实例的validate方法。

  以下摘录检查了证书路径中包含的证书的撤销状态。CertPath对象path是证书路径,params是PKIXParameters类型的对象:

CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
PKIXRevocationChecker rc = (PKIXRevocationChecker)cpv.getRevocationChecker();
rc.setOptions(EnumSet.of(Option.SOFT_FAIL));
params.addCertPathChecker(rc);
params.setRevocationEnabled(false);
CertPathValidatorResult res = cpv.validate(path, params);

  在这个摘录中,SOFT_FAIL选项导致撤销检查器在检查撤销状态时忽略任何网络故障(例如无法建立与OCSP服务器的连接)。

三、Implementing a Service Provider

  经验丰富的程序员可以创建自己的服务提供者包,提供证书路径服务实现。

  本节假设您已经阅读了Java Cryptography Architecture(JCA)参考指南。
  在Java证书路径API中定义了以下引擎类:

  • CertPathValidator - 用于验证证书路径
  • CertPathBuilder - 用于构建证书路径
  • CertStore - 用于从存储库检索证书和CRL(证书撤销列表)
      此外,已有的CertificateFactory引擎类也支持生成证书路径。

  由引擎类提供的应用接口是按照“服务提供者接口”(SPI)实现的。每个SPI类的名称与其对应的引擎类名称相同,后面加上"Spi"。例如,与CertPathValidator引擎类对应的SPI类是CertPathValidatorSpi类。每个SPI类都是抽象的。为了提供特定算法或类型的特定服务类型的实现,服务提供者必须扩展相应的SPI类,并为所有抽象方法提供实现。例如,CertStore类提供从存储库检索证书和CRL的功能。在CertStoreSpi子类中提供的实现将是针对特定类型的证书存储库的实现,例如LDAP。

3.1 实现和集成服务提供者的步骤 Steps to Implement and Integrate a Provider

  当实现和集成证书路径服务的服务提供者时,您必须确保提供某些信息。

  开发者应遵循实现和集成服务提供者的步骤。以下是某些步骤需要遵循的额外规则:

  第三步:编写您的“主类”,即服务提供者的子类

  在第三步:编写您的服务提供者主类中,这些是必须为证书路径服务定义的属性,其中算法名称替换为algName,certstore类型替换为storeType:

  • CertPathValidator.algName
  • CertPathBuilder.algName
  • CertStore.storeType

  请参阅Java安全标准算法名称,了解为algName和storeType定义的标准名称。每个属性的值必须是实现指定算法或certstore类型的类的完全限定名称。也就是说,它必须是包名后跟类名,两者用句点分隔。例如,服务提供者设置CertPathValidator.PKIX属性的值为"sun.security.provider.certpath.PKIXCertPathValidator",如下所示:

put("CertPathValidator.PKIX", "sun.security.provider.certpath.PKIXCertPathValidator")

  此外,可以为证书路径服务定义服务属性。这些属性可以用作选择服务提供者的过滤器。请参阅附录A,了解一些标准服务属性的定义。例如,服务提供者可以将ValidationAlgorithm服务属性设置为定义PKIX验证算法的RFC或规范的名称:

put("CertPathValidator.PKIX ValidationAlgorithm", "RFC5280");

  第十一步:记录您的服务提供者及其支持的服务

  在第十二步:记录您的服务提供者及其支持的服务中,证书路径服务提供者应为每个SPI记录以下信息:

3.1.1 证书工厂

  服务提供者应记录工厂可以创建的证书路径类型(以及路径中证书的版本号,如果相关)。服务提供者应描述证书在证书路径中的顺序,以及内容。
   服务提供者应记录支持的编码格式列表。这在技术上不是必需的,因为客户端可以通过调用getCertPathEncodings方法请求它们。然而,文档应更详细地描述每种编码格式,并在适用时引用任何标准。

3.1.2 证书路径验证器

-  服务提供者应记录有关CertPathValidator实现的任何相关信息,包括它验证的证书路径类型。特别是,PKIX CertPathValidator实现应记录以下信息:

  • 它遵守的RFC或规范。
  • 它用来检查证书是否已被撤销的机制。
  • 它识别的任何可选证书或CRL扩展以及它如何处理它们。

3.1.3 证书路径构建器

   服务提供者应记录有关CertPathBuilder实现的任何相关信息,包括它创建的证书路径类型以及它们是否经过验证。特别是,PKIX CertPathBuilder实现应记录以下信息:

  • 它遵守的RFC或规范。
  • 它用来检查证书是否已被撤销的机制。
  • 它识别的任何可选证书或CRL扩展以及它如何处理它们。
  • 它用来寻找证书路径的算法细节。例如:深度优先、广度优先、正向(即,从目标到信任锚点)、反向(即,从信任锚点到目标)。
  • 它用来选择和排序潜在证书的算法。例如,面对两个可能成为路径中下一个证书的候选证书,使用什么标准来选择一个而不是另一个?使用什么标准来拒绝一个证书?
  • 如有适用,它用于回溯或构建另一条路径的算法(即,当潜在路径不符合约束时)。
  • 已经测试过的CertStore实现类型。实现应该设计为与任何CertStore类型一起工作,但这些信息仍然可能有用。

  所有CertPathBuilder实现都应提供额外的调试支持,以分析和纠正潜在的路径构建问题。应记录如何访问此调试信息。

3.1.4 证书/CRL存储

  服务提供者应记录CertStore检索的证书和CRL类型(如果相关,包括版本号)。
   服务提供者还应记录有关CertStore实现的任何相关信息(例如使用的协议或支持的格式)。例如,LDAP CertStore实现应描述支持的LDAP版本以及用于查找证书和CRL的标准属性。它还应记录实现是否缓存结果,以及多久刷新一次(即,在什么条件下它们被刷新)。
   如果实现以特定顺序返回证书和CRL,应描述排序算法。实现还应记录任何额外的或默认的初始化参数。最后,实现应记录它如何使用CertSelector或CRLSelector对象中的信息来查找证书和CRL。

3.1.5 服务依赖性

  证书路径服务实现中常见的算法依赖性类型。
  以下是证书路径服务实现中常见的一些算法依赖性类型:

  • 证书路径验证和签名算法
    CertPathValidator实现通常需要使用签名算法来验证每个证书的数字签名。PKIXParameters类的setSigProvider方法允许用户指定特定的Signature提供者。
  • 证书路径构建器和证书工厂
    CertPathBuilder实现通常会利用CertificateFactory从证书列表生成证书路径。
  • CertStores和证书工厂
    CertStore实现通常会利用CertificateFactory从它们的编码生成证书和CRL。例如,LDAP CertStore实现可能使用X.509 CertificateFactory从它们的ASN.1编码形式生成X.509证书和CRL。

3.1.6 证书路径参数规范接口

  证书路径API包含两个表示参数透明规范的接口,即CertPathParameters和CertStoreParameters接口。

   包括CertPathParameters接口的两个实现,PKIXParameters和PKIXBuilderParameters类。如果您正在使用PKIX证书路径验证和算法参数,可以使用这些类。如果您需要不同算法的参数,则需要为该算法提供自己的CertPathParameters实现。

   包括CertStoreParameters接口的两个实现,LDAPCertStoreParameters和CollectionCertStoreParameters类。这些类分别与LDAP和Collection CertStore实现一起使用。如果您需要不同类型的存储库参数,则需要为该类型提供自己的CertStoreParameters实现。

  CertPathParameters和CertStoreParameters接口各自定义了一个clone方法,实现应该覆盖此方法。典型的实现将执行对象的“深”复制,以便对副本的后续更改不会影响原始对象(反之亦然)。然而,这并不是CertStoreParameters实现的绝对要求。对于需要保存CertStoreParameters中包含的参数引用的应用程序,更适当的是浅拷贝实现。例如,由于CertStore.getInstance对指定的CertStoreParameters进行克隆,浅拷贝克隆允许应用程序保存对特定CertStore初始化参数的引用,并在稍后释放资源,而不是等待垃圾收集机制。这应该非常小心地完成,因为CertStore可能仍在被其他线程使用。

3.1.7 证书路径结果规范接口

  证书路径API包含两个表示结果透明规范的接口,即CertPathValidatorResult和CertPathBuilderResult接口。

  包括每个接口的一个实现:PKIXCertPathValidatorResult和PKIXCertPathBuilderResult类。如果您正在实现PKIX证书路径服务提供者,可以使用这些类。如果您需要不同算法的证书路径结果,则需要为该算法提供自己的CertPathValidatorResult或CertPathBuilderResult实现。

  PKIX实现的CertPathValidator或CertPathBuilder可能会发现在PKIXCertPathValidatorResult或PKIXCertPathBuilderResult中存储额外信息(如调试跟踪)很有用。在这些情况下,实现应该实现适当结果类的子类,并提供获取相关信息的方法。这些类必须与服务提供者类一起分发,例如,作为服务提供者JAR文件的一部分。

3.1.8 证书路径异常类

  证书路径API包含一组用于处理错误的异常类。CertPathValidatorException、CertPathBuilderException和CertStoreException是GeneralSecurityException的子类。

  您可能需要在服务提供者实现中扩展这些类。

  例如,CertPathBuilder实现在抛出CertPathBuilderException时可能提供额外信息,如调试跟踪。实现可能会抛出CertPathBuilderException的子类来保存这些信息。同样,当发生故障时,CertStore实现可以通过抛出CertStoreException的子类来提供额外信息。此外,您可能想要实现CertPathValidatorException的子类来描述您的CertPathValidator实现的特定故障模式。

  在每种情况下,新的异常类必须与服务提供者类一起分发,例如,作为服务提供者JAR文件的一部分。每个服务提供者都应记录异常子类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1911713.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows C++ vs2022环境中下载、安装和使用osmesa

第一步&#xff1a;安装 MinGW-w64 请参考这篇文章进行安装&#xff1a; 在Windows中安装MinGW-w64最新版本 第二步&#xff1a;安装DirectX SDK 请参考这篇文章进行安装&#xff1a; 下载安装Microsoft DirectX SDK(June 2010) 第三步&#xff1a;安装Windows SDK 请参考这篇…

数据仓库哈哈

数据仓库 基本概念数据库&#xff08;database&#xff09;和数据仓库&#xff08;Data Warehouse&#xff09;的异同 整体架构分层架构方法论ER模型&#xff08;建模理论&#xff09;维度模型 何为分层第一层&#xff1a;数据源&#xff08;ODS ER模型&#xff09;设计要点日志…

WSL2编译使用6.6版本内核

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、有什么变化二、下载6.6内核三、开始编译1.安装环境2.开始编译 四、使用1.杀死虚拟机2.防止内核文件3.修改配置文件 总结 前言 最近出了一件不大不小的事&a…

C++基础知识:数组,数组是什么,数组的特点是什么?一维数组的三种定义方式,以及代码案例

1.数组的定义&#xff1a; 数组&#xff0c;就是一个集合&#xff0c;里面存放了相同类型的数据元素 2.数组的特点&#xff1a; 特点1:数组中的每个数据元素都是相同的数据类型 特点2:数组是由连续的内存位置组成的 3. 一维数组定义方式 维数组定义的三种方式: 1.数据类型 …

【atcoder】习题——位元枚举

题意&#xff1a;求i&M的popcount的和&#xff0c;i属于0……N 主要思路还是变加为乘。 举个例子N22&#xff0c;即10110 假设M的第3位是1&#xff0c;分析N中&#xff1a; 00110 00111 00100 00101 发现其实等价于 0010 0011 0000 0001 也就是左边第4位和第5…

AE-关键帧

目录 关键帧操作步骤&#xff08;以位置变化为例&#xff09; 1.确定动画起点 2.设置起点的位置属性 3.为起点打上关键帧 4.确定动画终点 5.设置终点的位置属性 改变动画速度 1.选中所有关键帧 2.拖拽 时间反向关键帧 1.选中要反向的关键帧 2.使用时间反向关键帧 …

二叉树超详细解析

二叉树 目录 二叉树一级目录二级目录三级目录 1.树的介绍1.1树的定义1.2树的基本术语1.3相关性质 2.二叉树介绍2.1定义2.2 性质 3.二叉树的种类3.1 满二叉树3.2完全二叉树3.3 二叉查找树特点&#xff1a;二叉查找树的节点包含的基本信息&#xff1a; 3.4 平衡二叉树 4.二叉树的…

imx6ull/linux应用编程学习(15) 移植MQTT客户端库

1. 准备开发环境 确保你的Ubuntu系统已经安装了必要的工具和依赖项。打开终端并运行以下命令&#xff1a; sudo apt update sudo apt install build-essential cmake git2. 获取MQTT库 git clone https://github.com/eclipse/paho.mqtt.c.git cd paho.mqtt.c3. 编译MQTT库 mk…

【前端速通系列|第二篇】Vue3前置知识

文章目录 1.前言2.包管理工具npm2.1下载node.js2.2配置 npm 镜像源2.3 npm 常用命令 3.Vite构建工具4.Vue3组件化5.Vue3运行原理 1.前言 本系列文章旨在帮助大家快速上手前端开发。 2.包管理工具npm npm 是 node.js中进行 包管理 的工具. 类似于Java中的Maven。 2.1下载nod…

K8S 上部署大数据相关组件

文章目录 一、前言二、Redis2.1 安装方式一&#xff1a;2.2 安装方式二&#xff1a; 一、前言 Artifact Hub 是一个专注于云原生应用的集中式搜索和发布平台。它旨在简化开发者在 CNCF&#xff08;Cloud Native Computing Foundation&#xff09;项目中寻找、安装和分享包与配置…

计算理论复习

1.Turing Machine 确定性图灵机 图灵机有很多不同的定义&#xff0c;这里选取其中一种&#xff0c;其它定义下的图灵机往往与下面这种定义的图灵机计算能力等价。 图灵机是一个在一条可双向无限延伸且被划分为若干格子的纸带上进行操作的机器&#xff0c;其有内部状态&#…

C++ 是否变得比 C 更流行了?

每年都会出现一种新的编程语言。创造一种新语言来解决计算机科学中的挑战的诱惑很难抗拒。一些资料表明&#xff0c;目前有多达 2,500 种语言&#xff0c;这并不奇怪&#xff01; 对于我们嵌入式软件开发人员来说&#xff0c;这个列表并不长。事实上&#xff0c;我们可以用一只…

go-redis源码解析:连接池原理

1. 执行命令的入口方法 redis也是通过hook执行命令&#xff0c;initHooks时&#xff0c;会将redis的hook放在第一个 通过hook调用到process方法&#xff0c;process方法内部再调用_process 2. 线程池初始化 redis在新建单客户端、sentinel客户端、cluster客户端等&#xff0c…

ChatGPT提问提示指南PDF下载经典分享推荐书籍

ChatGPT提问提示指南PDF&#xff0c;在本书的帮助下&#xff0c;您将学习到如何有效地向 ChatGPT 提出问题&#xff0c;以获得更准确和有用的回答。我们希望这本书能够为您提供实用的指南和策略&#xff0c;帮助您更好地与 ChatGPT 交互。 ChatGPT提问提示指南PDF下载 无论您是…

UMI HTTP接口手册

Translate to English 命令行手册&#xff1a; README_CLI.mdHTTP接口手册&#xff1a; README_HTTP.md HTTP接口手册 &#xff08;本文档仅适用于 Umi-OCR 最新版本。旧版本请查看 Github备份分支 中对应版本的文档。&#xff09; 基础说明 如上图&#xff0c;必须允许HTT…

git只列出本地分支

git只列出本地分支 git branch --list git强制删除本地分支 git branch -D_error: the branch dlx-test is not fully merged. -CSDN博客文章浏览阅读648次。git branch -d 可以通过: git branch 查看所有本地分支及其名字&#xff0c;然后删除特定分支。git删除远程remote分支…

IDEA如何创建原生maven子模块

文件 -> 新建 -> 新模块 -> Maven ArcheTypeMaven ArcheType界面中的输入框介绍 名称&#xff1a;子模块的名称位置&#xff1a;子模块存放的路径名创建Git仓库&#xff1a;子模块不单独作为一个git仓库&#xff0c;无需勾选JDK&#xff1a;JDK版本号父项&#xff1a;…

【深度学习基础】MacOS PyCharm连接远程服务器

目录 一、需求描述二、建立与服务器的远程连接1. 新版Pycharm的界面有什么不同&#xff1f;2. 创建远程连接3. 建立本地项目与远程服务器项目之间的路径映射4.设置保存自动上传文件 三、设置解释器总结 写在前面&#xff0c;本人用的是Macbook Pro&#xff0c; M3 MAX处理器&am…

设计模式探索:装饰器模式

1. 装饰器模式定义 装饰器模式&#xff08;Decorator Pattern&#xff09; 装饰器模式是一种结构型设计模式&#xff0c;允许向一个对象动态添加行为。在不改变类的接口的情况下&#xff0c;装饰器模式在原始类上增加额外的职责&#xff0c;并且支持多个装饰器嵌套使用。 装…

双色球 | python

1. 玩法规则 “双色球”每注投注号码由 6 个红色球号码和 1 个蓝色球号码组成。红色球号码从 1—33 中选择&#xff0c;蓝色球号码从 1—16 中选择。 球的数字匹配数量和颜色决定了是否中奖。 2. 需求 生成本期双色球中奖号码。&#xff08;注意&#xff1a;1.生成的红球随机有…