3

我似乎无法掌握 SSL 的工作方式……或者至少我无法解释 java 的 ssl 调试输出,所以我(计划)这样做:客户端和服务器生成自己的密钥对和自签名证书。(我只需要在重新连接时确保身份。)为了测试,我在服务器和客户端都使用相同的密钥和信任(只有一个密钥和证书)。握手过程中出了点问题,但我不明白错误消息。阅读了大约 20 个论坛和有关此的帖子,但到目前为止还没有弄清楚。那么有人可以告诉我底部的这条消息到底是什么意思吗?如果您需要更多详细信息,请告诉我。谢谢!

服务器 SSL 调试

trigger seeding of SecureRandom
done seeding SecureRandom
Using SSLEngineImpl.
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA
EndpointIdentificationAlgorithm: null
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
[Raw read]: length = 5
0000: 16 03 01 00 95                                     .....
[Raw read]: length = 149
0000: 01 00 00 91 03 01 51 0F   F6 C7 F3 99 F4 4B 77 A8  ......Q......Kw.
0010: 43 BB A0 89 E0 D9 20 4D   9F 5A C2 E2 0E 80 87 9F  C..... M.Z......
0020: 59 9A 13 71 F7 4F 00 00   2A 00 33 C0 04 00 16 00  Y..q.O..*.3.....
0030: 05 C0 03 C0 11 C0 02 C0   07 C0 13 C0 08 C0 0C 00  ................
0040: FF C0 0D C0 0E C0 09 00   2F C0 12 00 04 00 32 00  ......../.....2.
0050: 13 00 0A 01 00 00 3E 00   0A 00 34 00 32 00 17 00  ......>...4.2...
0060: 01 00 03 00 13 00 15 00   06 00 07 00 09 00 0A 00  ................
0070: 18 00 0B 00 0C 00 19 00   0D 00 0E 00 0F 00 10 00  ................
0080: 11 00 02 00 12 00 04 00   05 00 14 00 08 00 16 00  ................
0090: 0B 00 02 01 00                                     .....
New I/O worker #1, READ: TLSv1 Handshake, length = 149
*** ClientHello, TLSv1
RandomCookie:  GMT: 1359934919 bytes = { 243, 153, 244, 75, 119, 168, 67, 187, 160, 137, 224, 217, 32, 77, 159, 90, 194, 226, 14, 128, 135, 159, 89, 154, 19, 113, 247, 79 }
Session ID:  {}
Cipher Suites: [TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
***
[read] MD5 and SHA1 hashes:  len = 149
0000: 01 00 00 91 03 01 51 0F   F6 C7 F3 99 F4 4B 77 A8  ......Q......Kw.
0010: 43 BB A0 89 E0 D9 20 4D   9F 5A C2 E2 0E 80 87 9F  C..... M.Z......
0020: 59 9A 13 71 F7 4F 00 00   2A 00 33 C0 04 00 16 00  Y..q.O..*.3.....
0030: 05 C0 03 C0 11 C0 02 C0   07 C0 13 C0 08 C0 0C 00  ................
0040: FF C0 0D C0 0E C0 09 00   2F C0 12 00 04 00 32 00  ......../.....2.
0050: 13 00 0A 01 00 00 3E 00   0A 00 34 00 32 00 17 00  ......>...4.2...
0060: 01 00 03 00 13 00 15 00   06 00 07 00 09 00 0A 00  ................
0070: 18 00 0B 00 0C 00 19 00   0D 00 0E 00 0F 00 10 00  ................
0080: 11 00 02 00 12 00 04 00   05 00 14 00 08 00 16 00  ................
0090: 0B 00 02 01 00                                     .....
%% Initialized:  [Session-1, SSL_NULL_WITH_NULL_NULL]
keymanager chooseEngineServerAlias
keymanager getPrivateKey: 3eb9936d-2240-4687-bf4e-6518460e3e40
keymanager getCertificateChain: 3eb9936d-2240-4687-bf4e-6518460e3e40
%% Negotiating:  [Session-1, TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
*** ServerHello, TLSv1
RandomCookie:  GMT: 1359934920 bytes = { 242, 252, 196, 36, 227, 154, 97, 148, 214, 170, 109, 188, 122, 223, 161, 62, 131, 201, 214, 11, 223, 36, 74, 224, 72, 78, 94, 50 }
Session ID:  {81, 15, 246, 200, 127, 240, 115, 234, 52, 13, 73, 40, 137, 163, 243, 8, 51, 244, 147, 87, 128, 39, 210, 175, 163, 244, 86, 238, 138, 87, 29, 43}
Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA
Compression Method: 0
Extension renegotiation_info, renegotiated_connection: <empty>
***
Cipher suite:  TLS_DHE_RSA_WITH_AES_128_CBC_SHA
*** Certificate chain
chain [0] = [
[
  Version: V3
  Subject: CN=3eb9936d-2240-4687-bf4e-6518460e3e40
  Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5

  Key:  Sun RSA public key, 1024 bits
  modulus: 130292698947319747550411805428932496764788133931614615268432511412918979081774531703795353050388491281785406619160787220723201364083891450242081089010992812611565317265297099663990262828027908909326882453616292013722474448961222856631109497585792129874215397389474004374746492345728806709616072944360825031857
  public exponent: 65537
  Validity: [From: Sun Feb 03 03:52:37 CET 2013,
               To: Wed Feb 01 03:52:37 CET 2023]
  Issuer: CN=3eb9936d-2240-4687-bf4e-6518460e3e40
  SerialNumber: [    1bd22c7d 61d1a1eb]

]
  Algorithm: [SHA1withRSA]
  Signature:
0000: 94 5E 4F 74 28 A7 6C 94   25 60 4B 38 9F 7F 2D DE  .^Ot(.l.%`K8..-.
0010: 6D 3E E5 1F 55 E4 F2 14   3F 80 FF D4 24 55 B9 60  m>..U...?...$U.`
0020: 4C C3 B6 BB 68 CD 12 AD   FA BA 6D B0 76 5F 91 96  L...h.....m.v_..
0030: 08 97 9D 53 E8 28 5C DE   69 DD 30 92 F1 FE 59 21  ...S.(\.i.0...Y!
0040: 81 05 E6 E6 8D 89 6E 77   A4 6A EC 13 E5 0B D9 17  ......nw.j......
0050: 03 51 85 FB 14 D8 FA 6A   A3 52 71 57 F2 A5 CC 80  .Q.....j.RqW....
0060: 31 6D EA 64 81 4F C9 53   AC 01 FA EF AF 9D 0A F0  1m.d.O.S........
0070: 9F 67 1E 76 D7 41 C9 62   2B 5B FB 42 E1 AF 55 F8  .g.v.A.b+[.B..U.

]
***
*** Diffie-Hellman ServerKeyExchange
DH Modulus:  { 233, 230, 66, 89, 157, 53, 95, 55, 201, 127, 253, 53, 103, 18, 11, 142, 37, 201, 205, 67, 233, 39, 179, 169, 103, 15, 190, 197, 216, 144, 20, 25, 34, 210, 195, 179, 173, 36, 128, 9, 55, 153, 134, 157, 30, 132, 106, 171, 73, 250, 176, 173, 38, 210, 206, 106, 34, 33, 157, 71, 11, 206, 125, 119, 125, 74, 33, 251, 233, 194, 112, 181, 127, 96, 112, 2, 243, 206, 248, 57, 54, 148, 207, 69, 238, 54, 136, 193, 26, 140, 86, 171, 18, 122, 61, 175 }
DH Base:  { 48, 71, 10, 213, 160, 5, 251, 20, 206, 45, 157, 205, 135, 227, 139, 199, 209, 177, 197, 250, 203, 174, 203, 233, 95, 25, 10, 167, 163, 29, 35, 196, 219, 188, 190, 6, 23, 69, 68, 64, 26, 91, 44, 2, 9, 101, 216, 194, 189, 33, 113, 211, 102, 132, 69, 119, 31, 116, 186, 8, 77, 32, 41, 216, 60, 28, 21, 133, 71, 243, 169, 241, 162, 113, 91, 226, 61, 81, 174, 77, 62, 90, 31, 106, 112, 100, 243, 22, 147, 58, 52, 109, 63, 82, 146, 82 }
Server DH Public Key:  { 73, 233, 14, 202, 89, 13, 188, 236, 57, 124, 97, 186, 86, 30, 193, 15, 117, 169, 125, 103, 204, 9, 145, 52, 184, 3, 58, 205, 66, 147, 131, 141, 40, 92, 208, 244, 197, 165, 243, 13, 18, 43, 68, 74, 135, 150, 21, 31, 181, 224, 98, 239, 200, 95, 130, 97, 202, 11, 152, 181, 123, 206, 248, 248, 146, 117, 167, 55, 30, 106, 64, 247, 45, 147, 134, 46, 36, 96, 50, 200, 140, 102, 166, 231, 229, 207, 210, 48, 211, 107, 181, 111, 6, 113, 57, 195 }
Signed with a DSA or RSA public key
New I/O worker #1, fatal error: 80: problem unwrapping net record
java.lang.RuntimeException: Delegated task threw Exception/Error
%% Invalidated:  [Session-1, TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
New I/O worker #1, SEND TLSv1 ALERT:  fatal, description = internal_error
New I/O worker #1, WRITE: TLSv1 Alert, length = 2
[Raw write]: length = 7
0000: 15 03 01 00 02 02 50                               ......P
New I/O worker #1, called closeOutbound()
New I/O worker #1, closeOutboundInternal()

客户端 SSL 调试

testClient
trigger seeding of SecureRandom
done seeding SecureRandom
Using SSLEngineImpl.
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA256
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
Ignoring unavailable cipher suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
Ignoring unavailable cipher suite: TLS_RSA_WITH_AES_256_CBC_SHA
client.start(): true
Allow unsafe renegotiation: false
Allow legacy hello messages: true
Is initial handshake: true
Is secure renegotiation: false
Ignoring unsupported cipher suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
Ignoring unsupported cipher suite: TLS_RSA_WITH_AES_128_CBC_SHA256
%% No cached client session
*** ClientHello, TLSv1
RandomCookie:  GMT: 1360012393 bytes = { 134, 128, 126, 2, 241, 35, 109, 215, 218, 46, 141, 218, 44, 43, 228, 29, 9, 155, 72, 100, 59, 29, 177, 236, 197, 205, 21, 138 }
Session ID:  {}
Cipher Suites: [TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_ECDH_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_RC4_128_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_RC4_128_MD5, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA]
Compression Methods:  { 0 }
Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]
***
[write] MD5 and SHA1 hashes:  len = 149
0000: 01 00 00 91 03 01 51 10   24 69 86 80 7E 02 F1 23  ......Q.$i.....#
0010: 6D D7 DA 2E 8D DA 2C 2B   E4 1D 09 9B 48 64 3B 1D  m.....,+....Hd;.
0020: B1 EC C5 CD 15 8A 00 00   2A 00 33 C0 04 00 16 00  ........*.3.....
0030: 05 C0 03 C0 11 C0 02 C0   07 C0 13 C0 08 C0 0C 00  ................
0040: FF C0 0D C0 0E C0 09 00   2F C0 12 00 04 00 32 00  ......../.....2.
0050: 13 00 0A 01 00 00 3E 00   0A 00 34 00 32 00 17 00  ......>...4.2...
0060: 01 00 03 00 13 00 15 00   06 00 07 00 09 00 0A 00  ................
0070: 18 00 0B 00 0C 00 19 00   0D 00 0E 00 0F 00 10 00  ................
0080: 11 00 02 00 12 00 04 00   05 00 14 00 08 00 16 00  ................
0090: 0B 00 02 01 00                                     .....
pool-5-thread-2, WRITE: TLSv1 Handshake, length = 149
[Raw write]: length = 154
0000: 16 03 01 00 95 01 00 00   91 03 01 51 10 24 69 86  ...........Q.$i.
0010: 80 7E 02 F1 23 6D D7 DA   2E 8D DA 2C 2B E4 1D 09  ....#m.....,+...
0020: 9B 48 64 3B 1D B1 EC C5   CD 15 8A 00 00 2A 00 33  .Hd;.........*.3
0030: C0 04 00 16 00 05 C0 03   C0 11 C0 02 C0 07 C0 13  ................
0040: C0 08 C0 0C 00 FF C0 0D   C0 0E C0 09 00 2F C0 12  ............./..
0050: 00 04 00 32 00 13 00 0A   01 00 00 3E 00 0A 00 34  ...2.......>...4
0060: 00 32 00 17 00 01 00 03   00 13 00 15 00 06 00 07  .2..............
0070: 00 09 00 0A 00 18 00 0B   00 0C 00 19 00 0D 00 0E  ................
0080: 00 0F 00 10 00 11 00 02   00 12 00 04 00 05 00 14  ................
0090: 00 08 00 16 00 0B 00 02   01 00                    ..........
[Raw read]: length = 5
0000: 15 03 01 00 02                                     .....
[Raw read]: length = 2
0000: 02 50                                              .P
New I/O worker #1, READ: TLSv1 Alert, length = 2
New I/O worker #1, RECV TLSv1 ALERT:  fatal, internal_error
New I/O worker #1, fatal: engine already closed.  Rethrowing javax.net.ssl.SSLException: Received fatal alert: internal_error
New I/O worker #1, fatal: engine already closed.  Rethrowing javax.net.ssl.SSLException: Received fatal alert: internal_error
New I/O worker #1, called closeOutbound()
New I/O worker #1, closeOutboundInternal()
New I/O worker #1, SEND TLSv1 ALERT:  warning, description = close_notify
New I/O worker #1, WRITE: TLSv1 Alert, length = 2
New I/O worker #1, called closeInbound()
New I/O worker #1, fatal: engine already closed.  Rethrowing javax.net.ssl.SSLException: Inbound closed before receiving peer's close_notify: possible truncation attack?
[Raw write]: length = 7
0000: 15 03 01 00 02 01 00                               .......
main, called closeOutbound()
main, closeOutboundInternal()
New I/O worker #1, called closeOutbound()
New I/O worker #1, closeOutboundInternal()

Security.java(对所有安全相关的东西进行分组)

public class Security
{
    private static final String protocol    = "TLS";

    @SuppressWarnings("restriction")
    private static X509Certificate generateCertificate(String dn, KeyPair pair, String algorithm) throws GeneralSecurityException, IOException
    {
        PrivateKey privkey = pair.getPrivate();
        X509CertInfo info = new X509CertInfo();
        Date from = new Date();
        Date to = new Date(from.getTime() + 10l * 365 * 24 * 60 * 60 * 1000);
        CertificateValidity interval = new CertificateValidity(from, to);
        BigInteger sn = new BigInteger(64, new SecureRandom());
        X500Name owner = new X500Name(dn);

        info.set(X509CertInfo.VALIDITY, interval);
        info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(sn));
        info.set(X509CertInfo.SUBJECT, new CertificateSubjectName(owner));
        info.set(X509CertInfo.ISSUER, new CertificateIssuerName(owner));
        info.set(X509CertInfo.KEY, new CertificateX509Key(pair.getPublic()));
        info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
        AlgorithmId algo = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);
        info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(algo));

        // Sign the cert to identify the algorithm that's used.
        X509CertImpl cert = new X509CertImpl(info);
        cert.sign(privkey, algorithm);

        // Update the algorith, and resign.
        algo = (AlgorithmId) cert.get(X509CertImpl.SIG_ALG);
        info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, algo);
        cert = new X509CertImpl(info);
        cert.sign(privkey, algorithm);
        return cert;
    }

    protected static char[] getPassword()
    {
        return "test".toCharArray();
    }

    private static void pushKeyStoreToConfig(KeyStore ks, String configKey) throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
        IOException
    {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ks.store(baos, Security.getPassword());
        Configuration.set(configKey, baos.toByteArray());
    }

    private KeyManager[]    keyManagers;
    private KeyStore        keyStore;
    private KeyStore        trustStore;
    private SSLContext      sslContext;

    private TrustManager[]  trustManagers;

    public Security()
    {
        LoggerFactory.getLogger(Security.class).debug("constructing...");
    }

    public synchronized void addCertificate(String guid, Certificate certificate) throws KeyStoreException, NoSuchAlgorithmException, CertificateException,
        IOException
    {
        this.getTrustStore().setCertificateEntry(guid, certificate);
        Security.pushKeyStoreToConfig(this.getTrustStore(), Configuration.TRUST_STORE);
        Configuration.getInstance().save();
    }

    public SslHandler createSslHandler()
    {
        SSLEngine engine = this.getSslContext().createSSLEngine();
        engine.setUseClientMode(true);
        engine.setNeedClientAuth(true);
        return new SslHandler(engine);
    }

    public synchronized KeyManager[] getKeyManagers()
    {
        if (this.keyManagers == null)
        {
            KeyManager keyManager = new X509ExtendedKeyManager()
            {
                @Override
                public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket)
                {
                    System.out.println("keymanager chooseClientAlias");
                    return Configuration.get(Configuration.GUID, String.class);
                }

                @Override
                public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine)
                {
                    System.out.println("keymanager chooseEngineClientAlias");
                    return Configuration.get(Configuration.GUID, String.class);
                }

                @Override
                public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine)
                {
                    System.out.println("keymanager chooseEngineServerAlias");
                    return Configuration.get(Configuration.GUID, String.class);
                }

                @Override
                public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket)
                {
                    System.out.println("keymanager chooseServerAlias");
                    return Configuration.get(Configuration.GUID, String.class);
                }

                @Override
                public X509Certificate[] getCertificateChain(String alias)
                {
                    System.out.println("keymanager getCertificateChain: " + alias);
                    try
                    {
                        Certificate[] certs = Security.this.getKeyStore().getCertificateChain(alias);
                        X509Certificate[] xcerts = new X509Certificate[certs.length];
                        for (int i = 0; i < certs.length; i++)
                        {
                            xcerts[i] = (X509Certificate) certs[i];
                        }
                        return xcerts;
                    }
                    catch (Exception e)
                    {
                        LoggerFactory.getLogger(Security.class).error("Error while getting security chain", e);
                        return null;
                    }
                }

                @Override
                public String[] getClientAliases(String keyType, Principal[] issuers)
                {
                    System.out.println("keymanager getClientAliases");
                    // TODO Auto-generated method stub
                    return null;
                }

                @Override
                public PrivateKey getPrivateKey(String alias)
                {
                    System.out.println("keymanager getPrivateKey: " + alias);
                    try
                    {
                        return (PrivateKey) Security.this.getKeyStore().getKey(alias, Security.getPassword());
                    }
                    catch (Exception e)
                    {
                        LoggerFactory.getLogger(Security.class).error("Error while getting private key", e);
                        return null;
                    }
                }

                @Override
                public String[] getServerAliases(String keyType, Principal[] issuers)
                {
                    System.out.println("keymanager getServerAliases");
                    // TODO Auto-generated method stub
                    return null;
                }
            };
            this.keyManagers = new KeyManager[] { keyManager };
        }
        return this.keyManagers;
    }

    public synchronized KeyStore getKeyStore() throws IOException, GeneralSecurityException
    {
        if (this.keyStore == null)
        {
            this.keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            try
            {
                ByteArrayInputStream bais = new ByteArrayInputStream(Configuration.get(Configuration.KEY_STORE, byte[].class));
                this.keyStore.load(bais, Security.getPassword());
            }
            catch (Exception e)
            {
                LoggerFactory.getLogger(Security.class).warn("Could not load key store, creating new one", e);
                this.keyStore.load(null);
            }

            String guid = Configuration.get(Configuration.GUID, String.class);
            if (this.keyStore.getKey(guid, Security.getPassword()) == null)
            {
                this.resetKey(this.keyStore);
            }
            // TODO certificate expired? create new one!
        }
        return this.keyStore;
    }

    public synchronized SSLContext getSslContext()
    {
        if (this.sslContext == null)
        {
            SSLContext context = null;
            try
            {
                context = SSLContext.getInstance(Security.protocol);
                context.init(this.getKeyManagers(), this.getTrustManagers(), Controller.getInstance().getRandom());
            }
            catch (Exception e)
            {
                throw new Error("Failed to initialize the server-side SSLContext", e);
            }

            this.sslContext = context;
        }
        return this.sslContext;
    }

    private synchronized TrustManager[] getTrustManagers()
    {
        if (this.trustManagers == null)
        {
            TrustManager trustManager = new X509TrustManager()
            {
                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException
                {
                    System.out.println("trustmanager checkClientTrusted");
                    this.checkTrusted(chain, authType);
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException
                {
                    System.out.println("trustmanager checkServerTrusted");
                    this.checkTrusted(chain, authType);
                }

                public void checkTrusted(X509Certificate[] chain, String authType) throws CertificateException
                {
                    Certificate cert = null;
                    try
                    {
                        cert = Security.this.getTrustStore().getCertificate(chain[0].getSubjectX500Principal().getName());
                        if (cert == null)
                        {
                            throw new CertificateException("Certificate is not trusted: " + chain[0]);
                        }
                    }
                    catch (Exception e)
                    {
                        throw new CertificateException("Error while validating certificate: " + chain[0], e);
                    }
                }

                @Override
                public X509Certificate[] getAcceptedIssuers()
                {
                    return null;
                }
            };
            this.trustManagers = new TrustManager[] { trustManager };
        }
        return this.trustManagers;
    }

    protected synchronized KeyStore getTrustStore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException
    {
        if (this.trustStore == null)
        {
            this.trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
            try
            {
                this.trustStore.load(new ByteArrayInputStream(Configuration.get(Configuration.TRUST_STORE, byte[].class)), Security.getPassword());
            }
            catch (Exception e)
            {
                LoggerFactory.getLogger(Security.class).warn("Could not load trust store, creating new one", e);
                this.trustStore.load(null);
            }
        }
        return this.trustStore;
    }

    public synchronized void resetKey() throws IOException, GeneralSecurityException
    {
        this.resetKey(this.getKeyStore());
    }

    private synchronized void resetKey(KeyStore ks) throws IOException, GeneralSecurityException
    {
        LoggerFactory.getLogger(Security.class).info("Creating a new key pair and certificate");
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(1024, Controller.getInstance().getRandom());
        KeyPair kp = kpg.generateKeyPair();

        PrivateKey key = kp.getPrivate();
        String dn = "cn=" + Configuration.get(Configuration.GUID, String.class);
        X509Certificate[] chain = new X509Certificate[] { Security.generateCertificate(dn, kp, "SHA1withRSA") };

        ks.setKeyEntry(Configuration.get(Configuration.GUID, String.class), key, Security.getPassword(), chain);
        Security.pushKeyStoreToConfig(ks, Configuration.KEY_STORE);

        this.addCertificate(Configuration.get(Configuration.GUID, String.class), chain[0]);
    }
}

附加信息

在服务器引擎的情况下从外部设置 setUseClientMode()。

4

1 回答 1

5

这个非常不具表现力的错误消息是由 Java 的握手器中引发的 NullPointerException 引起的,可以通过在 TrustManager.getAcceptedIssuers() 中返回至少一个空列表(您可能想要更多)来修复。

有关更多详细信息,请参见Oracle 错误 ID 7148699:如果 TrustManager 从 getAcceptedIssuers 返回 null,Handshaker 将引发 NPE

于 2013-02-06T11:48:48.673 回答