ssl入門

http://blog.csdn.net/c_4818/article/details/7825388

主要參考資料:

http://booby325.iteye.com/blog/448174

http://wwwww.iteye.com/blog/94854

1:理解keystore和cert認證文件的區別。

keystore包含多個認證文件,可以導出或者加入。

密钥库文件格式(Keystore)和证书文件格式(Certificate)


其他資料:

http://publib.boulder.ibm.com/infocenter/cicstg/v7r0m0/index.jsp?topic=/com.ibm.cics.tg.doc/ctgunx/ktsss.htm

http://tomcat.apache.org/tomcat-5.5-doc/ssl-howto.html#Download%20and%20Install%20JSSE

http://spdx4046.iteye.com/blog/1554578

http://www.blogjava.net/tbwshc/archive/2012/07/13/383009.html




C:\Program Files\Java\jdk1.6.0_25\bin>keytool -genkey -keystore sslKey -keyalg r
sa -alias ssl
输入keystore密码:
再次输入新密码:
您的名字与姓氏是什么?
  [Unknown]:  127.0.0.1
您的组织单位名称是什么?
  [Unknown]:  hw
您的组织名称是什么?
  [Unknown]:  houwen
您所在的城市或区域名称是什么?
  [Unknown]:  guangzhou
您所在的州或省份名称是什么?
  [Unknown]:  guangdong
该单位的两字母国家代码是什么
  [Unknown]:  CHN
CN=127.0.0.1, OU=hw, O=houwen, L=guangzhou, ST=guangdong, C=CHN 正确吗?
  [否]:  Y

输入<ssl>的主密码
        (如果和 keystore 密码相同,按回车):


C:\Program Files\Java\jdk1.6.0_25\bin>keytool -certreq -keyalg rsa -alias ssl -f
ile houwen.csr -keystore sslKey
输入keystore密码:

C:\Program Files\Java\jdk1.6.0_25\bin>type houwen.csr
-----BEGIN NEW CERTIFICATE REQUEST-----
MIIBqDCCARECAQAwaDEMMAoGA1UEBhMDQ0hOMRIwEAYDVQQIEwlndWFuZ2RvbmcxEjAQBgNVBAcT
CWd1YW5nemhvdTEPMA0GA1UEChMGaG91d2VuMQswCQYDVQQLEwJodzESMBAGA1UEAxMJMTI3LjAu
MC4xMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCtyvdmwmgLch7SgHocBv1/LLYoY7NoeCBN
Xk2179L2z2wb3n+N0+YBVIiKC8puIeUoCcFG5PbJ8MGTo3+wVcbECxN13fb3hStn7ipvP8d8/is4
TCQvpL7JQJxvRlSmaSaxAr1FYG3aEhIDFbPFZUDagNvNZwI3Csl7pNinwXjpdQIDAQABoAAwDQYJ
KoZIhvcNAQEFBQADgYEAmmIdqOzDAQhEYzKE31UvNh0zUhe1PY+7YIgX8cNJbcfRvXP8w2P+3UWt
Ro+pjZsHO+NPSRus+6+YZT9l0BNmHy+bbdGfgAxfEFoo0BUwn5hMjVU3r0xWgGN4PhoUUF7rgp65
+ZxYDvatOBGJfTsDZxBeKwqTBM9xL/j5WyBqOKY=
-----END NEW CERTIFICATE REQUEST-----




    下面的命令来检测是否已经正确完成了授权。

keytool -printcert -file my1cert.cer  (證書名稱)

keytool -list -v -keystore SSLKey(生成的keystore名称後綴名稱一般是jks)

keytool -list -v -keystore sslKey




常见错误:

1:  unable to find valid certification path to requested target.找不到對應的store(鑰匙庫文件,注意區分cert認證文件。),

It failed with: 
    sun.security.validator.ValidatorException: PKIX path building failed:       
    sun.security.provider.certpath.SunCertPathBuilderException: 
     unable to find valid certification path to requested target.

2: Javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: Java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty 异常,有两种情况:
1、没有设置或者文件路径设置错误;
2、证书就采用keytool的默认jks类型就可以,否则也会报错,参考内容
An implementation of PKCS12 as JCA keystore type “pkcs12″. Storing trusted anchors in PKCS12 is not supported. Users should store trust anchors in JKS format and save private keys in PKCS12 format.


3:No subject alternative names present


Hello,
I am having some troubles with a self-signed certificate that was given to me to allow my application to use some web services.

I installed the certificate in the operating system (Windows) and in the keystore cacerts.jks in glassfish.
When I try to consume the webservice I am getting the next error:

Error:com.sun.xml.ws.client.ClientTransportException: HTTP transport
error: javax.net.ssl.SSLHandshakeException:
java.security.cert.CertificateException: No subject alternative names present


I have spent more than 5 days looking for a solution but I do not know what can I do.

I read that the problem usually appears when the "cn" in the certificate does not match the address of the server.
The "CN" in my certificate is "PRESS44"
The server address that was given to me is an ip. https://xxx.xxx.xxx.xxx:123

I have read in different forums that I have to regenerate the certificate and change the cn to make it match with the
domain name of the server, in this case to make it match with the ip, but I cannot do it because I cannot change the
certificate.
I have called to the company who gave the certificate but they told that it was right, and that several people was using the
same certificate successfully.

I also tried to access the server address from the browser, and it shows me a message telling me that there is a problem
with the current certificate. It shows an error that says "mismatched address".






http://www.jroller.com/hasant/entry/no_subject_alternative_names_matching


"No subject alternative names matching IP address ..." & "No name matching ... found" 

If you're struggling with the exceptions in the title, read on...

When you want to establish an SSL connection like this;

URL url = new URL("https://localhost:9443/soap_rpc");

You may get an exception like this;

javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost found
    at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1591)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:187)
    at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:181)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:975)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:123)
    at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:516)
    at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:454)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:884)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1096)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1123)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1107)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:405)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
    at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:832)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java:230)
    at SSLPost.test(SSLPost.java:74)
    at SSLPost.<init>(SSLPost.java:29)
    at SSLPost.main(SSLPost.java:98)
Caused by: java.security.cert.CertificateException: No name matching localhost found
    at sun.security.util.HostnameChecker.matchDNS(HostnameChecker.java:210)
    at sun.security.util.HostnameChecker.match(HostnameChecker.java:77)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkIdentity(X509TrustManagerImpl.java:264)
    at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:250)
    at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:954)
    ... 14 more

But, you have installed the server certificate, generated keystore and all work fine. So, what may be the problem?

If you google for the above exception, most of the results will suggest you to write a custom HostNameVerifier which will always return truelike this;

/**
 * Host name verifier that does not perform nay checks.
 */
private static class NullHostnameVerifier implements HostnameVerifier {
    public boolean verify(String hostname, SSLSession session) {
        return true;
    }
}

... and apply this disabled host name checker for current connection only;

/* disabling hostnamechecking only for current connection */
URL url = new URL("https://localhost:9443/soap_rpc");
HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
connection.setHostnameVerifier(new NullHostNameVerifier());

... or for all SSL connections;

/* disabling hostnamechecking for all https connections statically */
....
HttpsURLConnection.setDefaultHostnameVerifier(new NullHostnameVerifier());

But, is this the way to go? It didn't satisfied me as most of the skin-deep ways :). So, i decided to go into deep and find a more pleasant solution. Because, regardless of the choosen method among the above ones, you open a gap for URL spoofing at the core of the system. Disabling host name verifier means accepting any hostname in the certificate.

BTW, Sun's default HostNameVerifier implementation always returns false since JDK1.4. We didn't get this exception while working on IBM's implementation since it always returns true which means disables host name verification-though their documentation says opposite.


Let's come to the solution;

While making an SSL connection, HttpsClient steps in and does basic server authentication to protect against URL spoofing which includes verifying that the name of the server is found in the certificate. HttpsClient#checkURLSpoofing method checks server identity according to "RFC 2818: HTTP over TLS" - "Section 3.1 Server Identity".

HttpsClient basically uses HostNameChecker first to check the hostname against the names specified in the certificate. Then, if it fails, HostNameVerifier's turn comes and it's used to verify the host name. As mentioned above, while not overridden, SUN's default behaviour is returning false for this verification. This means, if your HostNameChecker fails, you will get one of the exceptions written in the title according to your URL's hostname type.

So, what can be done to "not-fail" HostNameChecker?

HostNameChecker#match method's implementation is like below;

sun.security.util.HostNameChecker
public void match(String hostName, X509Certificate x509certificate) throws CertificateException {
    if (isIpAddress(hostName)) {
        matchIP(hostName, x509certificate);
    else {
        matchDNS(hostName, x509certificate);
    }
}

If the incoming hostname is IP, (by matchIP method), it will be searched in available subject alternative names and throw CertificateException("No subject alternative names matching IP address ...") if no matching ip value found.

On the other hand, if the incoming hostname is DNS, (by matchDNS method), it will be searched in available subject alternative names but, different from IP matching algorithm, DNS matching will compare the hostname with the CommonName value from certificate if available. If neither matches with the hostname, a CertificateException("No name matching ... found") will be thrown.

What we can conclude from these details is;

  • if you'd like to connect via using IP as hostname;your certificate should include that ip value as a subject alternative name value (of type IPAddress : key=7).
  • if you'd like to connect via using DNS as hostname;your certificate should either include that DNS name as a subject alternative name value (of type DNS : key=2) or as a CommonName(CN) value.

Hope it helps...


Posted by hasanT ( Nov 27 2008, 05:46:43 PM GMT+02:00 ) Permalink Comments [9] 

Comments:

Thanks Hasan. Your article saved me time and nerves. 

Posted by Nenad Popovic on April 03, 2009 at 03:34 PM GMT+02:00 #

Among all the ...
After all there's good stuff on the net!
Thanks a lot Hasan!

Posted by Paulo Martins on June 02, 2009 at 12:50 AM GMT+02:00 #

If the web service is exposed on an IP address, and the certificate doesn't contain the alternative name, is there some way to disable the check as I can't change the certificate?

Posted by Srgjan Srepfler on June 09, 2009 at 01:38 PM GMT+02:00 #

@Srgjan

You can disable hostnameverifier as mentioned in the post. But this opens a gate for url spoofing.. Although not a good practice, you can disable hostnameverification only for certain ip addresses like this;
/**
* Host name verifier that does not perform for certain ip address */
private static class SpecializedHostnameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return hostname.equals("xxx.yyy...") ? true : false;
}
}

Posted by Hasan Turksoy on June 09, 2009 at 02:10 PM GMT+02:00 #

Hi Hasan,
We have installed a SSL certificate with IP address in the Subject Alternate field. But the IP address is provided against key type 2. So matchbyIP is failing. When we checked with the CA, they mentioned that they don't provide certificates with IPAddress : key=7 in the SAN field. Is it a standard to use key type 7? Are you aware of any CA that issues certificates in this format?
Any help is appreciated.
thanks,

Posted by Lalitha Bhat on December 29, 2009 at 07:50 PM GMT+02:00 #

Thank you very much. I wished this post was #1 in google search instead of useless staff like disabling security or host name checks in Java. Saved me time and nerves (+1).

Posted by Sergey Karepov on February 07, 2011 at 10:28 AM GMT+02:00 #

It really solved my problem. I was struggling to connect to HTTPS using java. Thanks a ton. :)

Posted by Sumit Kumar on February 28, 2011 at 10:56 AM GMT+02:00 #

How would I handle this situation? I create a connection to a third party https: site (https://ipv4.tunnelbroker.net ) and am getting the " No name matching ipv4.tunnelbroker.net found " message. The certificate is for tunnelbroker.net, but doesn't list ipv4.tunnelbroker.net as an alternative (to my knowledge).

Since it's not my certificate, I can't change it. And I don't want to disable checking, unless that's my only option.

have a great day:)
Patrick.

Posted by Patrick Dickey on April 21, 2011 at 02:41 AM GMT+02:00 #

In my earlier post, I should add that I tried adding the certificate to my jssecacerts and cacerts files (using keytool), and specify those in my run-time arguments. 

Have a great day:)
Patrick.

Posted by Patrick Dickey on April 21, 2011 at 02:43 AM GMT+02:00 #

Post a Comment:

Comments are closed for this entry.

你可能感兴趣的:(ssl入門)