KeyStore 和 KeyManager/TrustManager 的区别

Posted

技术标签:

【中文标题】KeyStore 和 KeyManager/TrustManager 的区别【英文标题】:Difference between KeyStore and KeyManager/TrustManager 【发布时间】:2012-12-21 21:26:58 【问题描述】:

使用 KeyStore 对象作为 keystore 和 truststore 的区别是什么?而不是使用 KeyManager 和 TrustManager?

让我解释一下我为什么要问。我正在使用 RESTEasy,需要使用 SSL 证书通过 HTTPS 进行 REST 调用。我需要增强 RESTEasy 创建 ClientRequest 的方式。这是我最初想到的:

public void afterPropertiesSet() throws Exception 
    Assert.isTrue(StringUtils.isNotBlank(getKeystoreName()), "Key Store Name is Blank");
    Assert.isTrue(StringUtils.isNotBlank(getKeystorePassword()), "Key Store Password is Blank.");
    Assert.isTrue(StringUtils.isNotBlank(getKeystorePath()), "Key Store Path is Blank");
    Assert.isTrue(StringUtils.isNotBlank(getTruststoreName()), "Trust Store Name is Blank");
    Assert.isTrue(StringUtils.isNotBlank(getTruststorePassword()), "Trust Store Password is Blank.");
    Assert.isTrue(StringUtils.isNotBlank(getTruststorePath()), "Trust Store Path is Blank");

    // Set the keystore and truststore for mutual authentication
    createKeystore();
    createTruststore();

    if (getHttpClient() == null) 
        // Initialize HTTP Client
        initializeHttpClient();
    

    Assert.notNull(getHttpClient(), "HTTP Client is NULL after initialization");


public ClientRequest createClientRequest(String uri) throws URISyntaxException 
    ClientExecutor clientExecutor = new ApacheHttpClient4Executor(getHttpClient());
    ClientRequestFactory fac = new ClientRequestFactory(clientExecutor, new URI(uri));
    return fac.createRequest(uri);


private void createTruststore() throws KeyStoreException, FileNotFoundException, IOException,
        NoSuchAlgorithmException, CertificateException 

    String truststoreFilePath = getTruststorePath() + getTruststoreName();

    KeyStore truststore = KeyStore.getInstance(KeyStore.getDefaultType());
    InputStream truststoreInput = getClass().getClassLoader().getResourceAsStream(truststoreFilePath);
    truststore.load(truststoreInput, getTruststorePassword().toCharArray());


private void createKeystore() throws KeyStoreException, FileNotFoundException, IOException,
        NoSuchAlgorithmException, CertificateException 

    String keystoreFilePath = getKeystorePath() + getKeystoreName();
    KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
    InputStream keystoreInput = getClass().getClassLoader().getResourceAsStream(keystoreFilePath);
    keystore.load(keystoreInput, getKeystorePassword().toCharArray());


/**
 * Initializes the HTTP Client
 * 
 * @throws KeyStoreException
 * @throws NoSuchAlgorithmException
 * @throws UnrecoverableKeyException
 * @throws KeyManagementException
 */
private void initializeHttpClient() throws KeyManagementException, UnrecoverableKeyException,
        NoSuchAlgorithmException, KeyStoreException 

    // Register https and http with scheme registry
    SchemeRegistry schemeRegistry = new SchemeRegistry();
    SSLSocketFactory sslSocketFactory = new SSLSocketFactory(getKeystore(), getKeystorePassword(), getTrustStore());
    schemeRegistry.register(new Scheme(HTTP, 80, PlainSocketFactory.getSocketFactory()));
    schemeRegistry.register(new Scheme(HTTPS, 443, sslSocketFactory));

    // Set connection params
    HttpConnectionParams.setConnectionTimeout(httpParameters, serviceConnectionTimeout);
    HttpConnectionParams.setSoTimeout(httpParameters, readTimeout);
    HttpConnectionParams.setStaleCheckingEnabled(httpParameters, true);

    // Create Connection Manager
    PoolingClientConnectionManager clientManager = new PoolingClientConnectionManager(schemeRegistry);
    clientManager.setMaxTotal(maxTotalConnections);
    clientManager.setDefaultMaxPerRoute(defaultMaxConnectionsPerHost);

    httpClient = new DefaultHttpClient(clientManager, httpParameters);

我遇到了对等证书的问题并不断收到异常:

javax.net.ssl.SSLPeerUnverifiedException:对等体未通过身份验证

然后我四处搜索,发现有关设置 HttpClient 但使用 TrustManager 和 KeyManager 的文章/博客。我重构了代码以执行以下操作:

public void afterPropertiesSet() throws Exception 
    Assert.isTrue(StringUtils.isNotBlank(getKeystoreName()), "Key Store Name is Blank");
    Assert.isTrue(StringUtils.isNotBlank(getKeystorePassword()), "Key Store Password is Blank.");
    Assert.isTrue(StringUtils.isNotBlank(getKeystorePath()), "Key Store Path is Blank");
    Assert.isTrue(StringUtils.isNotBlank(getTruststoreName()), "Trust Store Name is Blank");
    Assert.isTrue(StringUtils.isNotBlank(getTruststorePassword()), "Trust Store Password is Blank.");
    Assert.isTrue(StringUtils.isNotBlank(getTruststorePath()), "Trust Store Path is Blank");

    if (getHttpClient() == null) 
        // Initialize HTTP Client
        initializeHttpClient();
    

    Assert.notNull(getHttpClient(), "HTTP Client is NULL after initialization");


public ClientRequest createClientRequest(String uri) throws URISyntaxException 
    ClientExecutor clientExecutor = new ApacheHttpClient4Executor(getHttpClient());
    ClientRequestFactory fac = new ClientRequestFactory(clientExecutor, new URI(uri));
    return fac.createRequest(uri);


/**
 * Initializes the HTTP Client
 * 
 * @throws KeyStoreException
 * @throws NoSuchAlgorithmException
 * @throws UnrecoverableKeyException
 * @throws KeyManagementException
 */
private void initializeHttpClient() throws Exception 

    if (isCheckPeerCertificates()) 
        checkPeerCerts();
    

    // Create Trust and Key Managers
    // Use TrustManager and KeyManager instead of KeyStore
    TrustManager[] trustManagers = getTrustManagers(getTruststorePassword());
    KeyManager[] keyManagers = getKeyManagers(getKeystorePassword());

    // Create SSL Context
    SSLContext ctx = SSLContext.getInstance("TLS");
    ctx.init(keyManagers, trustManagers, new SecureRandom());

    // Create SSL Factory
    SSLSocketFactory sslSocketFactory = new SSLSocketFactory(ctx, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

    // Register https and http with scheme registry
    SchemeRegistry schemeRegistry = new SchemeRegistry();
    schemeRegistry.register(new Scheme(HTTP, 80, PlainSocketFactory.getSocketFactory()));
    schemeRegistry.register(new Scheme(HTTPS, 443, sslSocketFactory));

    // Set connection params
    HttpConnectionParams.setConnectionTimeout(httpParameters, serviceConnectionTimeout);
    HttpConnectionParams.setSoTimeout(httpParameters, readTimeout);
    HttpConnectionParams.setStaleCheckingEnabled(httpParameters, true);

    // Create Connection Manager
    PoolingClientConnectionManager clientManager = new PoolingClientConnectionManager(schemeRegistry);
    clientManager.setMaxTotal(maxTotalConnections);
    clientManager.setDefaultMaxPerRoute(defaultMaxConnectionsPerHost);

    httpClient = new DefaultHttpClient(clientManager, httpParameters);


private TrustManager[] getTrustManagers(String trustStorePassword) throws Exception 
    String truststoreFilePath = getTruststorePath() + getTruststoreName();
    InputStream trustStoreInput = getClass().getClassLoader().getResourceAsStream(truststoreFilePath);
    KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
    trustStore.load(trustStoreInput, trustStorePassword.toCharArray());
    TrustManagerFactory tmfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
    tmfactory.init(trustStore);
    return tmfactory.getTrustManagers();


private KeyManager[] getKeyManagers(String keyStorePassword) throws Exception 
    String keystoreFilePath = getKeystorePath() + getKeystoreName();
    InputStream keyStoreInput = getClass().getClassLoader().getResourceAsStream(keystoreFilePath);
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(keyStoreInput, keyStorePassword.toCharArray());
    KeyManagerFactory kmfactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmfactory.init(keyStore, keyStorePassword.toCharArray());
    return kmfactory.getKeyManagers();

第二个代码工作得很好。那么,这两种用法有什么区别呢?

【问题讨论】:

【参考方案1】:

我认为这可以帮助您: Difference between trustStore and keyStore in Java - SSL

trustStore 和 keyStore 之间的第一个和主要区别是 trustStore 由 TrustManager 使用,而 keyStore 由 Java 中的 KeyManager 类使用。 KeyManager 和 TrustManager 在 Java 中执行不同的工作,TrustManager 确定远程连接是否应该被信任,即远程方是否是它声称的对象,而 KeyManager 决定在 SSL 握手期间应该将哪些身份验证凭据发送到远程主机进行身份验证。如果您是 SSL 服务器,您将在密钥交换算法期间使用私钥并将与您的公钥对应的证书发送给客户端,该证书是从 keyStore 获取的。在 SSL 客户端,如果它是用 Java 编写的,它将使用存储在 trustStore 中的证书来验证服务器的身份。

阅读更多:JavaRevisited 博客:http://javarevisited.blogspot.com/2012/09/difference-between-truststore-vs-keyStore-Java-SSL.html(存档here。)

【讨论】:

以上是关于KeyStore 和 KeyManager/TrustManager 的区别的主要内容,如果未能解决你的问题,请参考以下文章

cacerts 和 keystore 有啥区别?

KeyStore 和 KeyManager/TrustManager 的区别

keystore文件

.keystore 文件和 .jks 文件之间的区别

KeyStore、HttpClient 和 HTTPS:有人可以向我解释这段代码吗?

“.android”文件夹和“debug.keystore”文件丢失