私がこのようなものを持っているとしましょう(クライアント側のコード):
TrustManager[] trustAllCerts = new TrustManager[]{
new X509TrustManager() {
@Override
public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(
Java.security.cert.X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(
Java.security.cert.X509Certificate[] certs, String authType) {
}
}
};
SSLContext sslc = SSLContext.getInstance("TLS");
sslc.init(null, trustAllCerts, null);
SocketFactory sf = sslc.getSocketFactory();
SSLSocket s = (SSLSocket) sf.createSocket("127.0.0.1", 9124);
このコードは完全に機能しますが、pemファイルで利用できる1つの具体的なCA証明書に対してサーバーの証明書を検証する方法を実際に理解することはできません。
すべての証明書は自己署名CAによって署名されており、検証する必要があるのはCAです(これに対してのみ)。
すべての答えをいただければ幸いです。
編集:
jglouie(このようにありがとうございました-あなたの答えに投票することはできません)に応えて。
私は解決策を見つけました:
new X509TrustManager() {
@Override
public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(
Java.security.cert.X509Certificate[] certs, String authType) {
}
@Override
public void checkServerTrusted(
Java.security.cert.X509Certificate[] certs, String authType)
throws CertificateException {
InputStream inStream = null;
try {
// Loading the CA cert
URL u = getClass().getResource("tcp/cacert.pem");
inStream = new FileInputStream(u.getFile());
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate ca = (X509Certificate) cf.generateCertificate(inStream);
inStream.close();
for (X509Certificate cert : certs) {
// Verifing by public key
cert.verify(ca.getPublicKey());
}
} catch (Exception ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
} finally {
try {
inStream.close();
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
};
CAの自己署名証明書は、次のようにすでにロードされていると思います。
CertificateFactory cf = CertificateFactory.getInstance("X.509");
FileInputStream finStream = new FileInputStream("CACertificate.pem");
X509Certificate caCertificate = (X509Certificate)cf.generateCertificate(finStream);
次に、証明書を確認する方法で:
@Override
public void checkServerTrusted(Java.security.cert.X509Certificate[] certs, String authType) throws CertificateException {
if (certs == null || certs.length == 0) {
throw new IllegalArgumentException("null or zero-length certificate chain");
}
if (authType == null || authType.length() == 0) {
throw new IllegalArgumentException("null or zero-length authentication type");
}
//Check if certificate send is your CA's
if(!certs[0].equals(caCertificate)){
try
{ //Not your CA's. Check if it has been signed by your CA
certs[0].verify(caCertificate.getPublicKey())
}
catch(Exception e){
throw new CertificateException("Certificate not trusted",e);
}
}
//If we end here certificate is trusted. Check if it has expired.
try{
certs[0].checkValidity();
}
catch(Exception e){
throw new CertificateException("Certificate not trusted. It has expired",e);
}
}
免責事項:コードのコンパイルも試みていません
受け入れられた答えは非常に間違っています。サーバー証明書と信頼できる認証局の間の接続を暗号で検証することはありません。一般に、独自のTrustManagerを実装する必要はほとんどありません。実装することは非常に危険です。
EJPが述べたように、独自のTrustManagerを実装する必要はありません。デフォルトのTrustManagerを使用するだけで、信頼できるCA証明書がデフォルトのTrustStoreに追加されていることを確認できます。詳細については、 この質問 を参照してください。
JDKの CertPathValidator クラスを見てください。これは、サーバー自体の証明書から信頼できるCAを介した信頼の継続的なチェーンを検証します。証明書チェーンの検証の概要については、 Oracleのドキュメント を参照してください。