From 42d67ad4df9958cf8212ba0102aeacfc4a0e466b Mon Sep 17 00:00:00 2001 From: cliven Date: Fri, 5 Mar 2021 13:42:40 +0800 Subject: [PATCH 01/22] Added SM4 block encryption algorithm --- .../bouncycastle/tls/EncryptionAlgorithm.java | 5 ++++ .../tls/crypto/impl/bc/BcTlsCrypto.java | 30 ++++++++++++++----- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/tls/src/main/java/org/bouncycastle/tls/EncryptionAlgorithm.java b/tls/src/main/java/org/bouncycastle/tls/EncryptionAlgorithm.java index 847dba5ecb..73f8aebea5 100644 --- a/tls/src/main/java/org/bouncycastle/tls/EncryptionAlgorithm.java +++ b/tls/src/main/java/org/bouncycastle/tls/EncryptionAlgorithm.java @@ -66,4 +66,9 @@ public class EncryptionAlgorithm * RFC 7905 */ public static final int CHACHA20_POLY1305 = 21; + + /* + * GMT 0024-2014 + */ + public static final int SM4_CBC = 31; } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java index f0bba12c6e..a7942c64ac 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java @@ -23,13 +23,7 @@ import org.bouncycastle.crypto.digests.SHA384Digest; import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.encodings.PKCS1Encoding; -import org.bouncycastle.crypto.engines.AESEngine; -import org.bouncycastle.crypto.engines.ARIAEngine; -import org.bouncycastle.crypto.engines.CamelliaEngine; -import org.bouncycastle.crypto.engines.DESedeEngine; -import org.bouncycastle.crypto.engines.RC4Engine; -import org.bouncycastle.crypto.engines.RSABlindedEngine; -import org.bouncycastle.crypto.engines.SEEDEngine; +import org.bouncycastle.crypto.engines.*; import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.modes.AEADBlockCipher; import org.bouncycastle.crypto.modes.CBCBlockCipher; @@ -162,6 +156,8 @@ public TlsCipher createCipher(TlsCryptoParameters cryptoParams, int encryptionAl case EncryptionAlgorithm.CHACHA20_POLY1305: // NOTE: Ignores macAlgorithm return createChaCha20Poly1305(cryptoParams); + case EncryptionAlgorithm.SM4_CBC: + return createSm4(cryptoParams, macAlgorithm); case EncryptionAlgorithm.NULL: return createNullCipher(cryptoParams, macAlgorithm); case EncryptionAlgorithm.SEED_CBC: @@ -439,6 +435,16 @@ public static Digest cloneDigest(short hashAlgorithm, Digest hash) } } + protected TlsCipher createSm4(TlsCryptoParameters cryptoParams, int macAlgorithm) + throws IOException + { + return new TlsBlockCipher(this, cryptoParams, + new BlockOperator(createSM4BlockCipher(), true), + new BlockOperator(createSM4BlockCipher(), false), + createMAC(cryptoParams, macAlgorithm), + createMAC(cryptoParams, macAlgorithm), 16); + } + protected TlsCipher createAESCipher(TlsCryptoParameters cryptoParams, int cipherKeySize, int macAlgorithm) throws IOException { @@ -521,6 +527,11 @@ protected TlsBlockCipher createSEEDCipher(TlsCryptoParameters cryptoParams, int createMAC(cryptoParams, macAlgorithm), 16); } + protected BlockCipher createSM4Engine() + { + return new SM4Engine(); + } + protected BlockCipher createAESEngine() { return new AESEngine(); @@ -541,6 +552,11 @@ protected BlockCipher createAESBlockCipher() return new CBCBlockCipher(createAESEngine()); } + protected BlockCipher createSM4BlockCipher() + { + return new CBCBlockCipher(createSM4Engine()); + } + protected BlockCipher createARIABlockCipher() { return new CBCBlockCipher(createARIAEngine()); From 7eab95d91323c8e4e125d16baabe2fd6ceeb07ee Mon Sep 17 00:00:00 2001 From: cliven Date: Fri, 5 Mar 2021 14:12:01 +0800 Subject: [PATCH 02/22] Added SM3 hash hmac alg support --- .../main/java/org/bouncycastle/tls/HashAlgorithm.java | 10 ++++++++++ .../main/java/org/bouncycastle/tls/MACAlgorithm.java | 9 +++++++++ tls/src/main/java/org/bouncycastle/tls/TlsUtils.java | 2 ++ .../bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java | 9 +++++++-- 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/tls/src/main/java/org/bouncycastle/tls/HashAlgorithm.java b/tls/src/main/java/org/bouncycastle/tls/HashAlgorithm.java index 75332c0ed2..2ad2fea7df 100644 --- a/tls/src/main/java/org/bouncycastle/tls/HashAlgorithm.java +++ b/tls/src/main/java/org/bouncycastle/tls/HashAlgorithm.java @@ -18,6 +18,12 @@ public class HashAlgorithm */ public static final short Intrinsic = 8; + /* + * GMT 0024-2014 No value is specified, + * so a value is randomly specified here to avoid conflicts + */ + public static final short sm3 = 20; + public static String getName(short hashAlgorithm) { switch (hashAlgorithm) @@ -38,6 +44,8 @@ public static String getName(short hashAlgorithm) return "sha512"; case Intrinsic: return "Intrinsic"; + case sm3: + return "sm3"; default: return "UNKNOWN"; } @@ -54,6 +62,7 @@ public static int getOutputSize(short hashAlgorithm) case sha224: return 28; case sha256: + case sm3: return 32; case sha384: return 48; @@ -79,6 +88,7 @@ public static boolean isRecognized(short hashAlgorithm) switch (hashAlgorithm) { case md5: + case sm3: case sha1: case sha224: case sha256: diff --git a/tls/src/main/java/org/bouncycastle/tls/MACAlgorithm.java b/tls/src/main/java/org/bouncycastle/tls/MACAlgorithm.java index 5b556bbd5b..d1588740d5 100644 --- a/tls/src/main/java/org/bouncycastle/tls/MACAlgorithm.java +++ b/tls/src/main/java/org/bouncycastle/tls/MACAlgorithm.java @@ -21,6 +21,12 @@ public class MACAlgorithm public static final int hmac_sha384 = 4; public static final int hmac_sha512 = 5; + /* + * GMT 0024-2014 No value is specified, + * so a value is randomly specified here to avoid conflicts + */ + public static final int hmac_sm3 = 20; + public static String getName(int macAlgorithm) { switch (macAlgorithm) @@ -37,6 +43,8 @@ public static String getName(int macAlgorithm) return "hmac_sha384"; case hmac_sha512: return "hmac_sha512"; + case hmac_sm3: + return "hmac_sm3"; default: return "UNKNOWN"; } @@ -56,6 +64,7 @@ public static boolean isHMAC(int macAlgorithm) case hmac_sha256: case hmac_sha384: case hmac_sha512: + case hmac_sm3: return true; default: return false; diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java index 6c8f6df54e..d40dd62b27 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java @@ -1793,6 +1793,8 @@ public static short getHashAlgorithmForHMACAlgorithm(int macAlgorithm) return HashAlgorithm.sha384; case MACAlgorithm.hmac_sha512: return HashAlgorithm.sha512; + case MACAlgorithm.hmac_sm3: + return HashAlgorithm.sm3; default: throw new IllegalArgumentException("specified MACAlgorithm not an HMAC: " + MACAlgorithm.getText(macAlgorithm)); } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java index a7942c64ac..59ecb8d302 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java @@ -22,6 +22,7 @@ import org.bouncycastle.crypto.digests.SHA256Digest; import org.bouncycastle.crypto.digests.SHA384Digest; import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.crypto.digests.SM3Digest; import org.bouncycastle.crypto.encodings.PKCS1Encoding; import org.bouncycastle.crypto.engines.*; import org.bouncycastle.crypto.macs.HMac; @@ -157,7 +158,8 @@ public TlsCipher createCipher(TlsCryptoParameters cryptoParams, int encryptionAl // NOTE: Ignores macAlgorithm return createChaCha20Poly1305(cryptoParams); case EncryptionAlgorithm.SM4_CBC: - return createSm4(cryptoParams, macAlgorithm); + // Chinese GMSSL SM4 mode + return createSM4Cipher(cryptoParams, macAlgorithm); case EncryptionAlgorithm.NULL: return createNullCipher(cryptoParams, macAlgorithm); case EncryptionAlgorithm.SEED_CBC: @@ -369,6 +371,8 @@ public Digest createDigest(short hashAlgorithm) return new SHA384Digest(); case HashAlgorithm.sha512: return new SHA512Digest(); + case HashAlgorithm.sm3: + return new SM3Digest(); default: throw new IllegalArgumentException("invalid HashAlgorithm: " + HashAlgorithm.getText(hashAlgorithm)); } @@ -435,9 +439,10 @@ public static Digest cloneDigest(short hashAlgorithm, Digest hash) } } - protected TlsCipher createSm4(TlsCryptoParameters cryptoParams, int macAlgorithm) + protected TlsCipher createSM4Cipher(TlsCryptoParameters cryptoParams, int macAlgorithm) throws IOException { + // SM4 Block size 128bit => 16 byte return new TlsBlockCipher(this, cryptoParams, new BlockOperator(createSM4BlockCipher(), true), new BlockOperator(createSM4BlockCipher(), false), From 087209a5e136d53284f0ce6f0161f25976571bca Mon Sep 17 00:00:00 2001 From: cliven Date: Fri, 5 Mar 2021 15:53:42 +0800 Subject: [PATCH 03/22] Add the algorithm identifier related to ECC_SM4_SM3 --- .../java/org/bouncycastle/tls/CipherSuite.java | 7 +++++++ .../bouncycastle/tls/KeyExchangeAlgorithm.java | 5 +++++ .../org/bouncycastle/tls/ProtocolVersion.java | 12 ++++++++++++ .../org/bouncycastle/tls/TlsClientProtocol.java | 4 ++++ .../main/java/org/bouncycastle/tls/TlsUtils.java | 15 ++++++++++++++- 5 files changed, 42 insertions(+), 1 deletion(-) diff --git a/tls/src/main/java/org/bouncycastle/tls/CipherSuite.java b/tls/src/main/java/org/bouncycastle/tls/CipherSuite.java index 2d8ec979e5..f16e7316c7 100644 --- a/tls/src/main/java/org/bouncycastle/tls/CipherSuite.java +++ b/tls/src/main/java/org/bouncycastle/tls/CipherSuite.java @@ -444,4 +444,11 @@ public static boolean isSCSV(int cipherSuite) public static final int TLS_CHACHA20_POLY1305_SHA256 = 0x1303; public static final int TLS_AES_128_CCM_SHA256 = 0x1304; public static final int TLS_AES_128_CCM_8_SHA256 = 0x1305; + + /* + * GMT 0024-2014 + */ + public static final int GMSSL_ECC_SM4_SM3 = 0xe013; + + } diff --git a/tls/src/main/java/org/bouncycastle/tls/KeyExchangeAlgorithm.java b/tls/src/main/java/org/bouncycastle/tls/KeyExchangeAlgorithm.java index bc58335ded..c285e7cfe8 100644 --- a/tls/src/main/java/org/bouncycastle/tls/KeyExchangeAlgorithm.java +++ b/tls/src/main/java/org/bouncycastle/tls/KeyExchangeAlgorithm.java @@ -53,4 +53,9 @@ public class KeyExchangeAlgorithm * RFC 5489 */ public static final int ECDHE_PSK = 24; + + /* + * GMT 0024-2014 + */ + public static final int SM2 = 50; } diff --git a/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java b/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java index 2a4ab5c43f..67f6e93f99 100644 --- a/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java +++ b/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java @@ -14,6 +14,9 @@ public final class ProtocolVersion public static final ProtocolVersion DTLSv10 = new ProtocolVersion(0xFEFF, "DTLS 1.0"); public static final ProtocolVersion DTLSv12 = new ProtocolVersion(0xFEFD, "DTLS 1.2"); + public static final ProtocolVersion GMSSLv11 = new ProtocolVersion(0x0101, "GMSSL 1.1"); + + static final ProtocolVersion CLIENT_EARLIEST_SUPPORTED_DTLS = DTLSv10; static final ProtocolVersion CLIENT_EARLIEST_SUPPORTED_TLS = SSLv3; static final ProtocolVersion CLIENT_LATEST_SUPPORTED_DTLS = DTLSv12; @@ -347,6 +350,15 @@ public static ProtocolVersion get(int major, int minor) { switch (major) { + case 0x01: + { + switch (minor) + { + case 0x01: + return GMSSLv11; + } + return getUnknownVersion(major, minor, "GMSSL"); + } case 0x03: { switch (minor) diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java b/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java index 2b05fa5415..fc5907ede3 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java @@ -1612,6 +1612,10 @@ protected void sendClientHello() // TODO[tls13] Prevent offering SSLv3 AND TLSv13? recordStream.setWriteVersion(ProtocolVersion.SSLv3); } +// else if (ProtocolVersion.contains(tlsClientContext.getClientSupportedVersions(), ProtocolVersion.GMSSLv11)) +// { +// recordStream.setWriteVersion(ProtocolVersion.GMSSLv11); +// } else { recordStream.setWriteVersion(ProtocolVersion.TLSv10); diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java index d40dd62b27..713b41506e 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java @@ -2882,6 +2882,9 @@ public static int getEncryptionAlgorithm(int cipherSuite) case CipherSuite.TLS_RSA_WITH_SEED_CBC_SHA: return EncryptionAlgorithm.SEED_CBC; + case CipherSuite.GMSSL_ECC_SM4_SM3: + return EncryptionAlgorithm.SM4_CBC; + default: return -1; } @@ -3259,6 +3262,9 @@ public static int getKeyExchangeAlgorithm(int cipherSuite) case CipherSuite.TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA: return KeyExchangeAlgorithm.SRP_RSA; + case CipherSuite.GMSSL_ECC_SM4_SM3: + return KeyExchangeAlgorithm.SM2; + default: return -1; } @@ -3579,6 +3585,9 @@ public static int getMACAlgorithm(int cipherSuite) case CipherSuite.TLS_RSA_WITH_ARIA_256_CBC_SHA384: return MACAlgorithm.hmac_sha384; + case CipherSuite.GMSSL_ECC_SM4_SM3: + return MACAlgorithm.hmac_sm3; + default: return -1; } @@ -3775,6 +3784,9 @@ public static ProtocolVersion getMinimumVersion(int cipherSuite) case CipherSuite.TLS_RSA_WITH_NULL_SHA256: return ProtocolVersion.TLSv12; + case CipherSuite.GMSSL_ECC_SM4_SM3: + return ProtocolVersion.GMSSLv11; + default: return ProtocolVersion.SSLv3; } @@ -4193,7 +4205,8 @@ public static boolean isSupportedKeyExchange(TlsCrypto crypto, int keyExchangeAl case KeyExchangeAlgorithm.SRP_RSA: return crypto.hasSRPAuthentication() && hasAnyRSASigAlgs(crypto); - + case KeyExchangeAlgorithm.SM2: + return true; default: return false; } From 2423ca5b2dc323f793324ebade5c5b48af185ec9 Mon Sep 17 00:00:00 2001 From: cliven Date: Fri, 5 Mar 2021 16:36:22 +0800 Subject: [PATCH 04/22] Added GMSSL related algorithm identifier analysis to Spi --- .../jsse/provider/CipherSuiteInfo.java | 17 ++++++++++++++++- .../jsse/provider/ProvSSLContextSpi.java | 3 +++ .../java/org/bouncycastle/tls/TlsUtils.java | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java b/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java index 0e67d1db1e..fc8c88a39b 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java @@ -16,7 +16,7 @@ class CipherSuiteInfo { static CipherSuiteInfo forCipherSuite(int cipherSuite, String name) { - if (!name.startsWith("TLS_")) + if (!name.startsWith("TLS_") || !name.startsWith("GMSSL_")) { throw new IllegalArgumentException(); } @@ -150,6 +150,9 @@ private static void decomposeEncryptionAlgorithm(Set decomposition, int case EncryptionAlgorithm.CHACHA20_POLY1305: // NOTE: Following SunJSSE, nothing beyond the transformation added above (i.e "ChaCha20-Poly1305") break; + case EncryptionAlgorithm.SM4_CBC: + decomposition.add("SM4_CBC"); + break; case EncryptionAlgorithm.NULL: decomposition.add("C_NULL"); break; @@ -170,6 +173,9 @@ private static void decomposeHashAlgorithm(Set decomposition, short hash case HashAlgorithm.sha384: addAll(decomposition, "SHA384", "SHA-384", "HmacSHA384"); break; + case HashAlgorithm.sm3: + addAll(decomposition, "SM3"); + break; // case HashAlgorithm.sha512: // addAll(decomposition, "SHA512", "SHA-512", "HmacSHA512"); // break; @@ -200,6 +206,9 @@ private static void decomposeKeyExchangeAlgorithm(Set decomposition, int case KeyExchangeAlgorithm.RSA: addAll(decomposition, "RSA"); break; + case KeyExchangeAlgorithm.SM2: + addAll(decomposition, "SM2"); + break; default: throw new IllegalArgumentException(); } @@ -227,6 +236,9 @@ private static void decomposeMACAlgorithm(Set decomposition, int cipherT case MACAlgorithm.hmac_sha384: addAll(decomposition, "SHA384", "SHA-384", "HmacSHA384"); break; + case MACAlgorithm.hmac_sm3: + addAll(decomposition, "SM3", "HmacSM3"); + break; // case MACAlgorithm.hmac_sha512: // addAll(decomposition, "SHA512", "SHA-512", "HmacSHA512"); // break; @@ -354,6 +366,9 @@ private static short getHashAlgorithm(int cipherSuite) case CipherSuite.TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384: return HashAlgorithm.sha384; + case CipherSuite.GMSSL_ECC_SM4_SM3: + return HashAlgorithm.sm3; + default: throw new IllegalArgumentException(); } diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java index 52df1055a4..7823e9eec6 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java @@ -239,6 +239,8 @@ private static Map createSupportedCipherSuiteMap() addCipherSuite(cs, "TLS_RSA_WITH_NULL_SHA", CipherSuite.TLS_RSA_WITH_NULL_SHA); addCipherSuite(cs, "TLS_RSA_WITH_NULL_SHA256", CipherSuite.TLS_RSA_WITH_NULL_SHA256); + addCipherSuite(cs, "GMSSL_ECC_SM4_SM3", CipherSuite.GMSSL_ECC_SM4_SM3); + return Collections.unmodifiableMap(cs); } @@ -258,6 +260,7 @@ private static Map createSupportedProtocolMap() ps.put("TLSv1.1", ProtocolVersion.TLSv11); ps.put("TLSv1", ProtocolVersion.TLSv10); ps.put("SSLv3", ProtocolVersion.SSLv3); + ps.put("GMSSLv1.1", ProtocolVersion.GMSSLv11); return Collections.unmodifiableMap(ps); } diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java index 713b41506e..1a5e6e55e8 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java @@ -2919,6 +2919,7 @@ public static int getEncryptionAlgorithmType(int encryptionAlgorithm) case EncryptionAlgorithm.CAMELLIA_128_CBC: case EncryptionAlgorithm.CAMELLIA_256_CBC: case EncryptionAlgorithm.SEED_CBC: + case EncryptionAlgorithm.SM4_CBC: return CipherType.block; case EncryptionAlgorithm.NULL: From c42b9cbc2be7e09f28f5c912519190c9c8746ecd Mon Sep 17 00:00:00 2001 From: cliven Date: Fri, 5 Mar 2021 17:52:45 +0800 Subject: [PATCH 05/22] fix CipherSuiteInfo prefix check logic error addAlgorithmImplementation to provide --- .../jsse/provider/BouncyCastleJsseProvider.java | 9 +++++++++ .../org/bouncycastle/jsse/provider/CipherSuiteInfo.java | 4 +++- .../bouncycastle/jsse/provider/ProvSSLContextSpi.java | 3 ++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java b/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java index ae5add537b..5c06638aef 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java @@ -209,6 +209,14 @@ public Object createInstance(Object constructorParameter) new String[]{ "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1" }); } }); + addAlgorithmImplementation("SSLContext.GMSSLv1.1", "org.bouncycastle.jsse.provider.SSLContext.GMSSLv1_1", + new EngineCreator() + { + public Object createInstance(Object constructorParameter) + { + return new ProvSSLContextSpi(fipsMode, cryptoProvider, new String[]{ "GMSSLv1.1" }); + } + }); addAlgorithmImplementation("SSLContext.DEFAULT", "org.bouncycastle.jsse.provider.SSLContext.Default", new EngineCreator() { @@ -219,6 +227,7 @@ public Object createInstance(Object constructorParameter) throws GeneralSecurity }); addAlias("Alg.Alias.SSLContext.SSL", "TLS"); addAlias("Alg.Alias.SSLContext.SSLV3", "TLSV1"); + addAlias("Alg.Alias.SSLContext.GMSSL", "GMSSLv1.1"); return fipsMode; } diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java b/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java index fc8c88a39b..de3ffb9822 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java @@ -16,7 +16,7 @@ class CipherSuiteInfo { static CipherSuiteInfo forCipherSuite(int cipherSuite, String name) { - if (!name.startsWith("TLS_") || !name.startsWith("GMSSL_")) + if (!name.startsWith("TLS_") && !name.startsWith("GMSSL_")) { throw new IllegalArgumentException(); } @@ -407,6 +407,8 @@ private static String getTransformation(int encryptionAlgorithm) return "ChaCha20-Poly1305"; case EncryptionAlgorithm.NULL: return "NULL"; + case EncryptionAlgorithm.SM4_CBC: + return "SM4/CBC/NoPadding"; default: throw new IllegalArgumentException(); } diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java index 7823e9eec6..8bace2bcdf 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java @@ -66,7 +66,7 @@ class ProvSSLContextSpi private static final List DEFAULT_CIPHERSUITE_LIST_FIPS = createDefaultCipherSuiteListFips(DEFAULT_CIPHERSUITE_LIST); // TODO[tls13] Enable TLSv1.3 by default in due course - private static final String[] DEFAULT_ENABLED_PROTOCOLS = new String[]{ "TLSv1.2", "TLSv1.1", "TLSv1" }; + private static final String[] DEFAULT_ENABLED_PROTOCOLS = new String[]{ "TLSv1.2", "TLSv1.1", "TLSv1" ,"GMSSLv1.1"}; private static void addCipherSuite(Map cs, String name, int cipherSuite) { @@ -239,6 +239,7 @@ private static Map createSupportedCipherSuiteMap() addCipherSuite(cs, "TLS_RSA_WITH_NULL_SHA", CipherSuite.TLS_RSA_WITH_NULL_SHA); addCipherSuite(cs, "TLS_RSA_WITH_NULL_SHA256", CipherSuite.TLS_RSA_WITH_NULL_SHA256); + // GMSSL 1.1 addCipherSuite(cs, "GMSSL_ECC_SM4_SM3", CipherSuite.GMSSL_ECC_SM4_SM3); return Collections.unmodifiableMap(cs); From 5529e58211073cc09f9cf17b2fd336f3399a620f Mon Sep 17 00:00:00 2001 From: cliven Date: Tue, 9 Mar 2021 15:12:40 +0800 Subject: [PATCH 06/22] debug client hello message --- .../jsse/provider/CipherSuiteInfo.java | 8 ++ .../jsse/provider/ProvSSLContextSpi.java | 11 +++ .../org/bouncycastle/tls/ProtocolVersion.java | 9 +- .../bouncycastle/tls/TlsClientProtocol.java | 8 +- .../java/org/bouncycastle/tls/TlsUtils.java | 4 + .../tls/test/GMSSLClientTest.java | 84 +++++++++++++++++ .../tls/test/MockGMSSLClient.java | 91 +++++++++++++++++++ 7 files changed, 209 insertions(+), 6 deletions(-) create mode 100644 tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java create mode 100644 tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLClient.java diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java b/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java index de3ffb9822..06c50a3273 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/CipherSuiteInfo.java @@ -81,6 +81,14 @@ boolean isTLSv13() return isTLSv13; } + /** + * GMSSL 1.1 crypto suites Start with 0xe0 + * @return true - GMSSL suite; false - not + */ + boolean isGMSSLv11(){ + return ((cipherSuite >> 8) & 0xFF) == 0xe0; + } + private static void addAll(Set decomposition, String... entries) { for (String entry : entries) diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java index 8bace2bcdf..598d4b6e76 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java @@ -109,6 +109,9 @@ private static List createDefaultCipherSuiteList(Set supportedCi cs.add("TLS_RSA_WITH_AES_256_CBC_SHA"); cs.add("TLS_RSA_WITH_AES_128_CBC_SHA"); + // GMSSL 1.1 + cs.add("GMSSL_ECC_SM4_SM3"); + cs.retainAll(supportedCipherSuiteSet); cs.trimToSize(); return Collections.unmodifiableList(cs); @@ -480,6 +483,8 @@ int[] getActiveCipherSuites(JcaTlsCrypto crypto, ProvSSLParameters sslParameters boolean post13Active = TlsUtils.isTLSv13(latest); boolean pre13Active = !TlsUtils.isTLSv13(earliest); + boolean isGMSSLActive = TlsUtils.isGMSSLv11(latest); + int[] candidates = new int[enabledCipherSuites.length]; int count = 0; @@ -490,6 +495,12 @@ int[] getActiveCipherSuites(JcaTlsCrypto crypto, ProvSSLParameters sslParameters { continue; } + if (isGMSSLActive && !candidate.isGMSSLv11()) + { + // GMSSL specific suite different with TLS + // if found GMSSL active just keep gm related suites + continue; + } if (candidate.isTLSv13()) { if (!post13Active) diff --git a/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java b/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java index 67f6e93f99..01811b37f1 100644 --- a/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java +++ b/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java @@ -16,7 +16,7 @@ public final class ProtocolVersion public static final ProtocolVersion GMSSLv11 = new ProtocolVersion(0x0101, "GMSSL 1.1"); - + static final ProtocolVersion CLIENT_GM_SUPPORTED_TLS = GMSSLv11; static final ProtocolVersion CLIENT_EARLIEST_SUPPORTED_DTLS = DTLSv10; static final ProtocolVersion CLIENT_EARLIEST_SUPPORTED_TLS = SSLv3; static final ProtocolVersion CLIENT_LATEST_SUPPORTED_DTLS = DTLSv12; @@ -145,6 +145,9 @@ static boolean isSupportedTLSVersionClient(ProtocolVersion version) int fullVersion = version.getFullVersion(); + if(fullVersion == CLIENT_GM_SUPPORTED_TLS.getFullVersion()){ + return true; + } return fullVersion >= CLIENT_EARLIEST_SUPPORTED_TLS.getFullVersion() && fullVersion <= CLIENT_LATEST_SUPPORTED_TLS.getFullVersion(); } @@ -228,7 +231,8 @@ public boolean isSSL() public boolean isTLS() { - return getMajorVersion() == 0x03; + final int majorVersion = getMajorVersion(); + return majorVersion == 0x03 || majorVersion == 0x01; } public ProtocolVersion getEquivalentTLSVersion() @@ -243,6 +247,7 @@ public ProtocolVersion getEquivalentTLSVersion() case 0xFD: return TLSv12; default: return null; } + case 0x01: return GMSSLv11; default: return null; } } diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java b/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java index fc5907ede3..268b23105d 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java @@ -1612,10 +1612,10 @@ protected void sendClientHello() // TODO[tls13] Prevent offering SSLv3 AND TLSv13? recordStream.setWriteVersion(ProtocolVersion.SSLv3); } -// else if (ProtocolVersion.contains(tlsClientContext.getClientSupportedVersions(), ProtocolVersion.GMSSLv11)) -// { -// recordStream.setWriteVersion(ProtocolVersion.GMSSLv11); -// } + else if (ProtocolVersion.contains(tlsClientContext.getClientSupportedVersions(), ProtocolVersion.GMSSLv11)) + { + recordStream.setWriteVersion(ProtocolVersion.GMSSLv11); + } else { recordStream.setWriteVersion(ProtocolVersion.TLSv10); diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java index 1a5e6e55e8..448245403d 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java @@ -316,6 +316,10 @@ public static boolean isTLSv13(ProtocolVersion version) return ProtocolVersion.TLSv13.isEqualOrEarlierVersionOf(version.getEquivalentTLSVersion()); } + public static boolean isGMSSLv11(ProtocolVersion version) { + return ProtocolVersion.GMSSLv11.isEqualOrEarlierVersionOf(version.getEquivalentTLSVersion()); + } + public static boolean isTLSv13(TlsContext context) { return isTLSv13(context.getServerVersion()); diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java new file mode 100644 index 0000000000..ea210da8b3 --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java @@ -0,0 +1,84 @@ +package org.bouncycastle.tls.test; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; +import org.bouncycastle.tls.TlsClientProtocol; + +import javax.net.ssl.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.security.*; + +/** + * Test GMSSL's client connection status + * + * @author cliven + * @since 2021-03-05 11:31:29 + */ +public class GMSSLClientTest +{ + + public static void main(String[] args) + throws Exception { + final BouncyCastleProvider provider = new BouncyCastleProvider(); + Security.addProvider(provider); + Security.addProvider(new BouncyCastleJsseProvider()); + + InetAddress host = InetAddress.getByName("localhost"); + int port = 443; +// jsse(host, port); + bc(host, port); + } + + private static void bc(InetAddress HOST, int port) throws IOException + { + final MockGMSSLClient client = new MockGMSSLClient(); + Socket s = new Socket("localhost", port,null, 2222); + TlsClientProtocol protocol = new TlsClientProtocol(s.getInputStream(), s.getOutputStream()); + protocol.connect(client); + + + OutputStream out = protocol.getOutputStream(); + String req = "GET / HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Connection: close\r\n\r\n"; + + out.write(req.getBytes("UTF-8")); + out.flush(); + InputStream in = protocol.getInputStream(); + byte[] buffer = new byte[2048]; + in.read(buffer); + System.out.println(new String(buffer)); + + out.close(); + in.close(); + + } + + private static void jsse(InetAddress HOST, int port) throws IOException, NoSuchProviderException, NoSuchAlgorithmException, KeyManagementException + { + SSLContext clientContext = SSLContext.getInstance("GMSSL", BouncyCastleJsseProvider.PROVIDER_NAME); + clientContext.init(new KeyManager[]{}, new TrustManager[]{}, new SecureRandom()); + SSLSocketFactory fact = clientContext.getSocketFactory(); + SSLSocket cSock = (SSLSocket) fact.createSocket(HOST, port); + + OutputStream out = cSock.getOutputStream(); + String req = "GET / HTTP/1.1\r\n" + + "Host: localhost\r\n" + + "Connection: close\r\n\r\n"; + + out.write(req.getBytes("UTF-8")); + out.flush(); + InputStream in = cSock.getInputStream(); + byte[] buffer = new byte[2048]; + in.read(buffer); + System.out.println(new String(buffer)); + + out.close(); + in.close(); + } +} diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLClient.java b/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLClient.java new file mode 100644 index 0000000000..3cdcf0e930 --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLClient.java @@ -0,0 +1,91 @@ +package org.bouncycastle.tls.test; + +import org.bouncycastle.tls.*; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; + +import java.io.IOException; +import java.security.SecureRandom; +import java.util.Hashtable; + +/** + * @author 权观宇 + * @since 2021-03-09 14:01:50 + */ +public class MockGMSSLClient extends AbstractTlsClient +{ + private static final int[] DEFAULT_CIPHER_SUITES = new int[] + { + /* + * GMSSL 1.1 + */ + CipherSuite.GMSSL_ECC_SM4_SM3, + }; + + public MockGMSSLClient() + { + this(new BcTlsCrypto(new SecureRandom())); + } + + public MockGMSSLClient(TlsCrypto crypto) + { + super(crypto); + } + + @Override + protected ProtocolVersion[] getSupportedVersions() + { + return new ProtocolVersion[]{ProtocolVersion.GMSSLv11}; + } + + protected int[] getSupportedCipherSuites() + { + return TlsUtils.getSupportedCipherSuites(getCrypto(), DEFAULT_CIPHER_SUITES); + } + + public TlsAuthentication getAuthentication() throws IOException + { + return new TlsAuthentication() + { + + public void notifyServerCertificate(TlsServerCertificate serverCertificate) throws IOException + { + System.out.println(">> TlsAuthentication on notifyServerCertificate"); + } + + public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException + { + System.out.println(">> TlsAuthentication on getClientCredentials"); + return null; + } + }; + } + + /** + * GMSSL not support ClientExtensions + * + * @return empty list + * @throws IOException not happen + */ + @Override + public Hashtable getClientExtensions() throws IOException + { + return new Hashtable(0); + } + + /** + * GMSSL Client generate random struct should be + * struct + * { + * unit32 gmt_unix_time; + * opaque random_bytes[28]; + * } + * + * @return true - use GMTUnixTime + */ + @Override + public boolean shouldUseGMTUnixTime() + { + return true; + } +} From 3a2c0d4206bc43a6de89e093e590199916453901 Mon Sep 17 00:00:00 2001 From: cliven Date: Wed, 10 Mar 2021 10:36:52 +0800 Subject: [PATCH 07/22] add sm2 key exchange process --- .../tls/AbstractTlsKeyExchangeFactory.java | 5 + .../tls/ClientCertificateType.java | 9 ++ .../tls/DefaultTlsKeyExchangeFactory.java | 13 ++ .../org/bouncycastle/tls/PRFAlgorithm.java | 3 + .../bouncycastle/tls/SignatureAlgorithm.java | 5 + .../tls/SignatureAndHashAlgorithm.java | 2 + .../tls/TlsKeyExchangeFactory.java | 10 ++ .../bouncycastle/tls/TlsSM2KeyExchange.java | 151 ++++++++++++++++++ .../java/org/bouncycastle/tls/TlsUtils.java | 15 ++ .../tls/crypto/impl/bc/BcTlsCertificate.java | 27 ++++ .../tls/crypto/impl/bc/BcTlsSM2Verifier.java | 37 +++++ .../tls/test/GMSSLClientTest.java | 2 +- 12 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java create mode 100644 tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSM2Verifier.java diff --git a/tls/src/main/java/org/bouncycastle/tls/AbstractTlsKeyExchangeFactory.java b/tls/src/main/java/org/bouncycastle/tls/AbstractTlsKeyExchangeFactory.java index 4c84a9a06b..d2991bee0a 100644 --- a/tls/src/main/java/org/bouncycastle/tls/AbstractTlsKeyExchangeFactory.java +++ b/tls/src/main/java/org/bouncycastle/tls/AbstractTlsKeyExchangeFactory.java @@ -91,4 +91,9 @@ public TlsKeyExchange createSRPKeyExchangeServer(int keyExchange, TlsSRPLoginPar { throw new TlsFatalAlert(AlertDescription.internal_error); } + + public TlsKeyExchange createSM2KeyExchange(int keyExchange) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } } diff --git a/tls/src/main/java/org/bouncycastle/tls/ClientCertificateType.java b/tls/src/main/java/org/bouncycastle/tls/ClientCertificateType.java index bfff66402b..4c1ed40f4a 100644 --- a/tls/src/main/java/org/bouncycastle/tls/ClientCertificateType.java +++ b/tls/src/main/java/org/bouncycastle/tls/ClientCertificateType.java @@ -19,4 +19,13 @@ public class ClientCertificateType public static final short ecdsa_sign = 64; public static final short rsa_fixed_ecdh = 65; public static final short ecdsa_fixed_ecdh = 66; + + /* + * GMT0024 has not mentioned + * + * Just specify a number here + */ + public static final short sm2_encrypt = 128; + + } diff --git a/tls/src/main/java/org/bouncycastle/tls/DefaultTlsKeyExchangeFactory.java b/tls/src/main/java/org/bouncycastle/tls/DefaultTlsKeyExchangeFactory.java index 949860cd1f..2ff10a2d85 100644 --- a/tls/src/main/java/org/bouncycastle/tls/DefaultTlsKeyExchangeFactory.java +++ b/tls/src/main/java/org/bouncycastle/tls/DefaultTlsKeyExchangeFactory.java @@ -89,4 +89,17 @@ public TlsKeyExchange createSRPKeyExchangeServer(int keyExchange, TlsSRPLoginPar { return new TlsSRPKeyExchange(keyExchange, loginParameters); } + + /** + * GMSSL ECC_SM4_SM3 suite key exchange + * + * @param keyExchange enum type + * @return SM2 key exchange object + * @throws IOException err + */ + @Override + public TlsKeyExchange createSM2KeyExchange(int keyExchange) throws IOException + { + return new TlsSM2KeyExchange(keyExchange); + } } diff --git a/tls/src/main/java/org/bouncycastle/tls/PRFAlgorithm.java b/tls/src/main/java/org/bouncycastle/tls/PRFAlgorithm.java index e42bb83a71..58075861fc 100644 --- a/tls/src/main/java/org/bouncycastle/tls/PRFAlgorithm.java +++ b/tls/src/main/java/org/bouncycastle/tls/PRFAlgorithm.java @@ -14,6 +14,7 @@ public class PRFAlgorithm public static final int tls_prf_sha384 = 3; public static final int tls13_hkdf_sha256 = 4; public static final int tls13_hkdf_sha384 = 5; + public static final int gmssl11_prf_sm3 = 6; public static String getName(int prfAlgorithm) { @@ -31,6 +32,8 @@ public static String getName(int prfAlgorithm) return "tls13_hkdf_sha256"; case tls13_hkdf_sha384: return "tls13_hkdf_sha384"; + case gmssl11_prf_sm3: + return "gmssl11_prf_sm3"; default: return "UNKNOWN"; } diff --git a/tls/src/main/java/org/bouncycastle/tls/SignatureAlgorithm.java b/tls/src/main/java/org/bouncycastle/tls/SignatureAlgorithm.java index 778a8e832a..583c451798 100644 --- a/tls/src/main/java/org/bouncycastle/tls/SignatureAlgorithm.java +++ b/tls/src/main/java/org/bouncycastle/tls/SignatureAlgorithm.java @@ -9,6 +9,7 @@ public class SignatureAlgorithm public static final short rsa = 1; public static final short dsa = 2; public static final short ecdsa = 3; + public static final short sm2 = 23; /* * RFC 8422 @@ -26,6 +27,7 @@ public class SignatureAlgorithm public static final short rsa_pss_pss_sha384 = 10; public static final short rsa_pss_pss_sha512 = 11; + public static short getClientCertificateType(short signatureAlgorithm) { switch (signatureAlgorithm) @@ -45,6 +47,7 @@ public static short getClientCertificateType(short signatureAlgorithm) case SignatureAlgorithm.ecdsa: case SignatureAlgorithm.ed25519: case SignatureAlgorithm.ed448: + case SignatureAlgorithm.sm2: return ClientCertificateType.ecdsa_sign; default: @@ -80,6 +83,8 @@ public static String getName(short signatureAlgorithm) return "rsa_pss_pss_sha384"; case rsa_pss_pss_sha512: return "rsa_pss_pss_sha512"; + case sm2: + return "sm2"; default: return "UNKNOWN"; } diff --git a/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java b/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java index a6f98947a0..7ae48f84a0 100644 --- a/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java +++ b/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java @@ -17,6 +17,7 @@ public class SignatureAndHashAlgorithm public static final SignatureAndHashAlgorithm rsa_pss_pss_sha256 = new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, SignatureAlgorithm.rsa_pss_pss_sha256); public static final SignatureAndHashAlgorithm rsa_pss_pss_sha384 = new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, SignatureAlgorithm.rsa_pss_pss_sha384); public static final SignatureAndHashAlgorithm rsa_pss_pss_sha512 = new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, SignatureAlgorithm.rsa_pss_pss_sha512); + public static final SignatureAndHashAlgorithm sm2 = new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, SignatureAlgorithm.sm2); public static SignatureAndHashAlgorithm getInstance(short hashAlgorithm, short signatureAlgorithm) { @@ -41,6 +42,7 @@ public static SignatureAndHashAlgorithm getInstanceIntrinsic(short signatureAlgo case SignatureAlgorithm.rsa_pss_pss_sha256: return rsa_pss_pss_sha256; case SignatureAlgorithm.rsa_pss_pss_sha384: return rsa_pss_pss_sha384; case SignatureAlgorithm.rsa_pss_pss_sha512: return rsa_pss_pss_sha512; + case SignatureAlgorithm.sm2: default: return new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, signatureAlgorithm); } diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsKeyExchangeFactory.java b/tls/src/main/java/org/bouncycastle/tls/TlsKeyExchangeFactory.java index 81197f23ce..ae82c9fbd4 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsKeyExchangeFactory.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsKeyExchangeFactory.java @@ -44,4 +44,14 @@ TlsKeyExchange createSRPKeyExchangeClient(int keyExchange, TlsSRPIdentity srpIde TlsKeyExchange createSRPKeyExchangeServer(int keyExchange, TlsSRPLoginParameters loginParameters) throws IOException; + + /** + * GMSSL ECC_SM4_SM3 suite key exchange + * + * @param keyExchange enum type + * @return SM2 key exchange object + * @throws IOException err + */ + TlsKeyExchange createSM2KeyExchange(int keyExchange) + throws IOException; } diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java b/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java new file mode 100644 index 0000000000..c7ee9ce97a --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java @@ -0,0 +1,151 @@ +package org.bouncycastle.tls; + +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.tls.crypto.TlsVerifier; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * GMSSL SM2 exchange. + * + * @author Cliven + */ +public class TlsSM2KeyExchange extends AbstractTlsKeyExchange +{ + + + private static int checkKeyExchange(int keyExchange) + { + switch (keyExchange) + { + case KeyExchangeAlgorithm.SM2: + return keyExchange; + default: + throw new IllegalArgumentException("unsupported key exchange algorithm"); + } + } + + protected TlsCredentialedDecryptor serverCredentials = null; + /** + * first cert of certificate list + * use to sign server side key exchange message + *

+ * digitally-signed struct + * { + * opaque client_random[32]; + * opaque server_random[32]; + * opaque ASN.1Cert<1..2^24-1> + * } signed params + */ + protected TlsCertificate serverSigCertificate; + + /** + * second cert of certificate list + * use to encrypt client generate preMasterSecret. + */ + protected TlsCertificate serverEncCertificate; + protected TlsSecret preMasterSecret; + + public TlsSM2KeyExchange(int keyExchange) + { + super(checkKeyExchange(keyExchange)); + } + + public void skipServerCredentials() throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + public void processServerCredentials(TlsCredentials serverCredentials) throws IOException + { + this.serverCredentials = TlsUtils.requireDecryptorCredentials(serverCredentials); + } + + @Override + public void processServerKeyExchange(InputStream input) throws IOException + { + + final int n = TlsUtils.readUint16(input); + final byte[] signature = TlsUtils.readFully(n, input); + /* + * digitally-signed struct + * { + * opaque client_random[32]; + * opaque server_random[32]; + * opaque ASN.1Cert<1..2^24-1> + * } signed params + * + * the ASN.1Cert field is encrypt certificate + */ + final SecurityParameters securityParameters = context.getSecurityParametersHandshake(); + final byte[] clientRandom = securityParameters.getClientRandom(); + final byte[] serverRandom = securityParameters.getServerRandom(); + final byte[] encCert = serverEncCertificate.getEncoded(); + int totalSize = clientRandom.length + serverRandom.length + 3 + encCert.length; + byte[] plaintext = new byte[totalSize]; + System.arraycopy(clientRandom, 0, plaintext, 0, 32); + System.arraycopy(serverRandom, 0, plaintext, 32, 32); + plaintext[64] = (byte) (0xff & (encCert.length >> 16)); + plaintext[65] = (byte) (0xff & (encCert.length >> 8)); + plaintext[66] = (byte) (0xff & (encCert.length)); + System.arraycopy(encCert, 0, plaintext, 67, encCert.length); + final TlsVerifier verifier = serverSigCertificate.createVerifier(SignatureAlgorithm.sm2); + + DigitallySigned digitallySigned = new DigitallySigned(SignatureAndHashAlgorithm.sm2, signature); + final boolean pass = verifier.verifyRawSignature(digitallySigned, plaintext); + if(!pass) + { + throw new TlsFatalAlertReceived(AlertDescription.illegal_parameter); + } +// this.serverSigCertificate.createVerifier() + return; + } + + public void processServerCertificate(Certificate serverCertificate) throws IOException + { + // GMSSL has two certificates, first is for signing the second is for encryption + if(serverCertificate.getLength() < 2) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + // sign cert + this.serverSigCertificate = serverCertificate.getCertificateAt(0).useInRole(ConnectionEnd.server, KeyExchangeAlgorithm.SM2); + // encrypt cert + this.serverEncCertificate = serverCertificate.getCertificateAt(1).useInRole(ConnectionEnd.server, KeyExchangeAlgorithm.SM2); + } + + public short[] getClientCertificateTypes() + { + return new short[]{ClientCertificateType.sm2_encrypt}; + } + + public void processClientCredentials(TlsCredentials clientCredentials) throws IOException + { + TlsUtils.requireSignerCredentials(clientCredentials); + } + + public void generateClientKeyExchange(OutputStream output) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); +// // TODO: SM2加密工具 +// this.preMasterSecret = TlsRSAUtils.generateEncryptedPreMasterSecret(context, serverCertificate, output); + } + + public void processClientKeyExchange(InputStream input) throws IOException + { + throw new TlsFatalAlert(AlertDescription.internal_error); +// byte[] encryptedPreMasterSecret = TlsUtils.readEncryptedPMS(context, input); +// // TODO: 解密工具 +// this.preMasterSecret = serverCredentials.decrypt(new TlsCryptoParameters(context), encryptedPreMasterSecret); + } + + public TlsSecret generatePreMasterSecret() throws IOException + { + TlsSecret tmp = this.preMasterSecret; + this.preMasterSecret = null; + return tmp; + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java index 448245403d..0afb7fdfd9 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java @@ -1817,6 +1817,8 @@ public static short getHashAlgorithmForPRFAlgorithm(int prfAlgorithm) case PRFAlgorithm.tls_prf_sha384: case PRFAlgorithm.tls13_hkdf_sha384: return HashAlgorithm.sha384; + case PRFAlgorithm.gmssl11_prf_sm3: + return HashAlgorithm.sm3; default: throw new IllegalArgumentException("unknown PRFAlgorithm: " + PRFAlgorithm.getText(prfAlgorithm)); } @@ -1847,6 +1849,7 @@ static int getPRFAlgorithm(SecurityParameters securityParameters, int cipherSuit { ProtocolVersion negotiatedVersion = securityParameters.getNegotiatedVersion(); + final boolean isGMSSLv11 = isGMSSLv11(negotiatedVersion); final boolean isTLSv13 = isTLSv13(negotiatedVersion); final boolean isTLSv12Exactly = !isTLSv13 && isTLSv12(negotiatedVersion); final boolean isSSL = negotiatedVersion.isSSL(); @@ -2096,6 +2099,15 @@ static int getPRFAlgorithm(SecurityParameters securityParameters, int cipherSuit return PRFAlgorithm.tls_prf_legacy; } + case CipherSuite.GMSSL_ECC_SM4_SM3: + { + if (isGMSSLv11) + { + return PRFAlgorithm.gmssl11_prf_sm3; + } + throw new TlsFatalAlert(AlertDescription.illegal_parameter); + } + default: { if (isTLSv13) @@ -4289,6 +4301,9 @@ private static TlsKeyExchange createKeyExchangeClient(TlsClient client, int keyE return factory.createSRPKeyExchangeClient(keyExchange, client.getSRPIdentity(), client.getSRPConfigVerifier()); + case KeyExchangeAlgorithm.SM2: + return factory.createSM2KeyExchange(keyExchange); + default: /* * Note: internal error here; the TlsProtocol implementation verifies that the diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCertificate.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCertificate.java index 1bc5b12fd1..c12940a08e 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCertificate.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCertificate.java @@ -115,6 +115,9 @@ public TlsVerifier createVerifier(short signatureAlgorithm) throws IOException validateRSA_PSS_PSS(signatureAlgorithm); return new BcTlsRSAPSSVerifier(crypto, getPubKeyRSA(), signatureAlgorithm); + case SignatureAlgorithm.sm2: + return new BcTlsSM2Verifier(crypto, getPubKeyEC()); + default: throw new TlsFatalAlert(AlertDescription.certificate_unknown); } @@ -276,6 +279,24 @@ public RSAKeyParameters getPubKeyRSA() throws IOException } } + /** + * Get public key from sm2 certificate + * @return sm2 public key + * @throws IOException err + */ + public ECPublicKeyParameters getPubKeySM2() throws IOException + { + try + { + return (ECPublicKeyParameters)getPublicKey(); + } + catch (ClassCastException e) + { + throw new TlsFatalAlert(AlertDescription.certificate_unknown, e); + } + } + + public boolean supportsSignatureAlgorithm(short signatureAlgorithm) throws IOException { return supportsSignatureAlgorithm(signatureAlgorithm, KeyUsage.digitalSignature); @@ -318,6 +339,12 @@ public TlsCertificate useInRole(int connectionEnd, int keyExchangeAlgorithm) thr this.pubKeyRSA = getPubKeyRSA(); return this; } + case KeyExchangeAlgorithm.SM2: + { + // validateKeyUsage(KeyUsage.keyEncipherment); + pubKeyEC = getPubKeySM2(); + return this; + } } } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSM2Verifier.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSM2Verifier.java new file mode 100644 index 0000000000..51b1e8d1c5 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSM2Verifier.java @@ -0,0 +1,37 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.crypto.Signer; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.signers.SM2Signer; +import org.bouncycastle.tls.DigitallySigned; + +/** + * SM2 signature verifier + * + * force use SM2WithSM3 signature verify data. + * + * @author Cliven + */ +public class BcTlsSM2Verifier extends BcTlsVerifier +{ + protected BcTlsSM2Verifier(BcTlsCrypto crypto, ECPublicKeyParameters publicKey) + { + super(crypto, publicKey); + } + + /** + * verify signature + * + * @param signedParams signature + * @param hash raw message + * @return true/false (pass or not) + */ + public boolean verifyRawSignature(DigitallySigned signedParams, byte[] hash) + { + // ignore SignatureAndHashAlgorithm force use SM2WithSM3 signature alg. + Signer signer = new SM2Signer(); + signer.init(false, publicKey); + signer.update(hash, 0, hash.length); + return signer.verifySignature(signedParams.getSignature()); + } +} diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java index ea210da8b3..70dec11678 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java @@ -37,7 +37,7 @@ public static void main(String[] args) private static void bc(InetAddress HOST, int port) throws IOException { final MockGMSSLClient client = new MockGMSSLClient(); - Socket s = new Socket("localhost", port,null, 2222); + Socket s = new Socket("localhost", port,null, 2333); TlsClientProtocol protocol = new TlsClientProtocol(s.getInputStream(), s.getOutputStream()); protocol.connect(client); From f01c27ca942bf568a056748c6a1be494fb56a0a2 Mon Sep 17 00:00:00 2001 From: cliven Date: Wed, 10 Mar 2021 16:12:39 +0800 Subject: [PATCH 08/22] add gm client key exchange impl --- .../org/bouncycastle/asn1/gm/SM2Cipher.java | 107 ++++++++++++++++++ .../bouncycastle/tls/TlsSM2KeyExchange.java | 23 +++- .../tls/crypto/impl/BcGmsslEncryptor.java | 72 ++++++++++++ .../tls/crypto/impl/BcTlsRSAEncryptor.java | 46 ++++++++ .../tls/crypto/impl/bc/BcTlsCrypto.java | 56 ++++----- 5 files changed, 266 insertions(+), 38 deletions(-) create mode 100644 core/src/main/java/org/bouncycastle/asn1/gm/SM2Cipher.java create mode 100644 tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java create mode 100644 tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcTlsRSAEncryptor.java diff --git a/core/src/main/java/org/bouncycastle/asn1/gm/SM2Cipher.java b/core/src/main/java/org/bouncycastle/asn1/gm/SM2Cipher.java new file mode 100644 index 0000000000..b9c31b72fe --- /dev/null +++ b/core/src/main/java/org/bouncycastle/asn1/gm/SM2Cipher.java @@ -0,0 +1,107 @@ +package org.bouncycastle.asn1.gm; + +import org.bouncycastle.asn1.*; + +import java.util.Enumeration; + +/** + * GMT 0009-2012 + * + * sm2 encrypted data specific struct + * + * @author Cliven + * @since 2021-03-10 13:28:12 + */ +public class SM2Cipher extends ASN1Object +{ + /* + * SM2Cipher ::== SEQUENCE{ + * XCoordinate INTEGER, --X Portion + * YCoordinate INTEGER, --Y Portion + * HASH OCTET STRING SIZE(32), --Plaintext sm3 hash + * CipherText OCTET STRING --CipherText + * } + */ + + private ASN1Integer xCoordinate; + private ASN1Integer yCoordinate; + private ASN1OctetString hash; + private ASN1OctetString cipherText; + + public SM2Cipher() + { + super(); + } + + public SM2Cipher(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + xCoordinate = ASN1Integer.getInstance(e.nextElement()); + yCoordinate = ASN1Integer.getInstance(e.nextElement()); + hash = ASN1OctetString.getInstance(e.nextElement()); + cipherText = ASN1OctetString.getInstance(e.nextElement()); + } + + public static SM2Cipher getInstance(Object o) + { + if(o instanceof SM2Cipher) + { + return (SM2Cipher) o; + } + else if(o != null) + { + return new SM2Cipher(ASN1Sequence.getInstance(o)); + } + return null; + } + + public ASN1Integer getxCoordinate() + { + return xCoordinate; + } + + public void setxCoordinate(ASN1Integer xCoordinate) + { + this.xCoordinate = xCoordinate; + } + + public ASN1Integer getyCoordinate() + { + return yCoordinate; + } + + public void setyCoordinate(ASN1Integer yCoordinate) + { + this.yCoordinate = yCoordinate; + } + + public ASN1OctetString getHash() + { + return hash; + } + + public void setHash(ASN1OctetString hash) + { + this.hash = hash; + } + + public ASN1OctetString getCipherText() + { + return cipherText; + } + + public void setCipherText(ASN1OctetString cipherText) + { + this.cipherText = cipherText; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(4); + v.add(xCoordinate); + v.add(yCoordinate); + v.add(hash); + v.add(cipherText); + return new DERSequence(v); + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java b/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java index c7ee9ce97a..02048bae9b 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java @@ -127,11 +127,28 @@ public void processClientCredentials(TlsCredentials clientCredentials) throws IO TlsUtils.requireSignerCredentials(clientCredentials); } + /** + * generate preMasterSecret then use enc certificate public key + * enc preMasterSecret + * @param output + * @throws IOException + */ public void generateClientKeyExchange(OutputStream output) throws IOException { - throw new TlsFatalAlert(AlertDescription.internal_error); -// // TODO: SM2加密工具 -// this.preMasterSecret = TlsRSAUtils.generateEncryptedPreMasterSecret(context, serverCertificate, output); + /* + * GMSSL PreMasterSecret struct same with rsaPreMasterSecret + * + * struct + * { + * ProtocolVersion client_version; + * opaque random[46]; + * } PreMasterSecret + */ + this.preMasterSecret = context.getCrypto() + .generateRSAPreMasterSecret(context.getClientVersion()); + // add BcGmsslEncryptor to support encrypt preMasterSecret + byte[] encryptedPreMasterSecret = preMasterSecret.encrypt(serverEncCertificate); + TlsUtils.writeEncryptedPMS(context, encryptedPreMasterSecret, output); } public void processClientKeyExchange(InputStream input) throws IOException diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java new file mode 100644 index 0000000000..8b794533e4 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java @@ -0,0 +1,72 @@ +package org.bouncycastle.tls.crypto.impl; + +import org.bouncycastle.asn1.ASN1Integer; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.gm.SM2Cipher; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.engines.SM2Engine; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.TlsUtils; +import org.bouncycastle.util.encoders.Hex; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + * GMSSL basic chinese GMT 0009-2012 + * + * @author Cliven + * @since 2021-03-10 13:56:20 + */ +public class BcGmsslEncryptor implements TlsEncryptor +{ + + + private final ParametersWithRandom keyParameters; + + public BcGmsslEncryptor(ECPublicKeyParameters keyParameters, SecureRandom secureRandom) + { + this.keyParameters = new ParametersWithRandom(keyParameters, secureRandom); + + } + + public byte[] encrypt(byte[] input, int inOff, int length) throws IOException + { + try + { + SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C3C2); + engine.init(true, keyParameters); + byte[] c1c3c2 = engine.processBlock(input, inOff, length); + + /* + * construct GMT0009-2012 encrypted data struct + */ + ByteArrayInputStream stream = new ByteArrayInputStream(c1c3c2); + // read 1 byte for uncompressed point prefix 0x04 + stream.read(); + byte[] x = TlsUtils.readFully(32, stream); + byte[] y = TlsUtils.readFully(32, stream); + byte[] hash = TlsUtils.readFully(32, stream); + final byte[] cipherText = TlsUtils.readFully(length, stream); + + final SM2Cipher sm2Cipher = new SM2Cipher(); + sm2Cipher.setxCoordinate(new ASN1Integer(new BigInteger(x))); + sm2Cipher.setyCoordinate(new ASN1Integer(new BigInteger(y))); + sm2Cipher.setHash(new DEROctetString(hash)); + sm2Cipher.setCipherText(new DEROctetString(cipherText)); + final byte[] encoded = sm2Cipher.getEncoded(); + System.out.printf(">> PreMasterSecret Key: %s\n", Hex.toHexString(input).toUpperCase()); + System.out.printf(">> CipherTtext: %s\n", Hex.toHexString(encoded).toUpperCase()); + return encoded; + } + catch (InvalidCipherTextException e) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcTlsRSAEncryptor.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcTlsRSAEncryptor.java new file mode 100644 index 0000000000..072a88b601 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcTlsRSAEncryptor.java @@ -0,0 +1,46 @@ +package org.bouncycastle.tls.crypto.impl; + +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.InvalidCipherTextException; +import org.bouncycastle.crypto.encodings.PKCS1Encoding; +import org.bouncycastle.crypto.engines.RSABlindedEngine; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.params.RSAKeyParameters; +import org.bouncycastle.tls.AlertDescription; +import org.bouncycastle.tls.TlsFatalAlert; + +import java.io.IOException; +import java.security.SecureRandom; + +public class BcTlsRSAEncryptor + implements TlsEncryptor +{ + + private final SecureRandom secureRandom; + private CipherParameters pubKeyRSA; + + public BcTlsRSAEncryptor(RSAKeyParameters pubKeyRSA, SecureRandom secureRandom) + { + this.pubKeyRSA = pubKeyRSA; + this.secureRandom = secureRandom; + + } + + public byte[] encrypt(byte[] input, int inOff, int length) + throws IOException + { + try + { + PKCS1Encoding encoding = new PKCS1Encoding(new RSABlindedEngine()); + encoding.init(true, new ParametersWithRandom(pubKeyRSA, secureRandom)); + return encoding.processBlock(input, inOff, length); + } + catch (InvalidCipherTextException e) + { + /* + * This should never happen, only during decryption. + */ + throw new TlsFatalAlert(AlertDescription.internal_error, e); + } + } +} diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java index 59ecb8d302..22a271dd02 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java @@ -23,19 +23,13 @@ import org.bouncycastle.crypto.digests.SHA384Digest; import org.bouncycastle.crypto.digests.SHA512Digest; import org.bouncycastle.crypto.digests.SM3Digest; -import org.bouncycastle.crypto.encodings.PKCS1Encoding; import org.bouncycastle.crypto.engines.*; import org.bouncycastle.crypto.macs.HMac; import org.bouncycastle.crypto.modes.AEADBlockCipher; import org.bouncycastle.crypto.modes.CBCBlockCipher; import org.bouncycastle.crypto.modes.CCMBlockCipher; import org.bouncycastle.crypto.modes.GCMBlockCipher; -import org.bouncycastle.crypto.params.AEADParameters; -import org.bouncycastle.crypto.params.KeyParameter; -import org.bouncycastle.crypto.params.ParametersWithIV; -import org.bouncycastle.crypto.params.ParametersWithRandom; -import org.bouncycastle.crypto.params.RSAKeyParameters; -import org.bouncycastle.crypto.params.SRP6GroupParameters; +import org.bouncycastle.crypto.params.*; import org.bouncycastle.crypto.prng.DigestRandomGenerator; import org.bouncycastle.tls.AlertDescription; import org.bouncycastle.tls.EncryptionAlgorithm; @@ -62,14 +56,7 @@ import org.bouncycastle.tls.crypto.TlsSRP6VerifierGenerator; import org.bouncycastle.tls.crypto.TlsSRPConfig; import org.bouncycastle.tls.crypto.TlsSecret; -import org.bouncycastle.tls.crypto.impl.AbstractTlsCrypto; -import org.bouncycastle.tls.crypto.impl.TlsAEADCipher; -import org.bouncycastle.tls.crypto.impl.TlsAEADCipherImpl; -import org.bouncycastle.tls.crypto.impl.TlsBlockCipher; -import org.bouncycastle.tls.crypto.impl.TlsBlockCipherImpl; -import org.bouncycastle.tls.crypto.impl.TlsEncryptor; -import org.bouncycastle.tls.crypto.impl.TlsImplUtils; -import org.bouncycastle.tls.crypto.impl.TlsNullCipher; +import org.bouncycastle.tls.crypto.impl.*; import org.bouncycastle.util.Arrays; /** @@ -193,28 +180,25 @@ protected TlsEncryptor createEncryptor(TlsCertificate certificate) BcTlsCertificate bcCert = BcTlsCertificate.convert(this, certificate); bcCert.validateKeyUsage(KeyUsage.keyEncipherment); - final RSAKeyParameters pubKeyRSA = bcCert.getPubKeyRSA(); - return new TlsEncryptor() + final AsymmetricKeyParameter publicKey = bcCert.getPublicKey(); + + if(publicKey instanceof RSAKeyParameters) { - public byte[] encrypt(byte[] input, int inOff, int length) - throws IOException - { - try - { - PKCS1Encoding encoding = new PKCS1Encoding(new RSABlindedEngine()); - encoding.init(true, new ParametersWithRandom(pubKeyRSA, getSecureRandom())); - return encoding.processBlock(input, inOff, length); - } - catch (InvalidCipherTextException e) - { - /* - * This should never happen, only during decryption. - */ - throw new TlsFatalAlert(AlertDescription.internal_error, e); - } - } - }; + final RSAKeyParameters pubKeyRSA = (RSAKeyParameters) publicKey; + return new BcTlsRSAEncryptor(pubKeyRSA, getSecureRandom()); + } + else if(publicKey instanceof ECPublicKeyParameters) + { + final ECPublicKeyParameters pubKeySM2 = (ECPublicKeyParameters) publicKey; + return new BcGmsslEncryptor(pubKeySM2, getSecureRandom()); + } + else + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + + } public TlsNonceGenerator createNonceGenerator(byte[] additionalSeedMaterial) @@ -434,6 +418,8 @@ public static Digest cloneDigest(short hashAlgorithm, Digest hash) return new SHA384Digest((SHA384Digest)hash); case HashAlgorithm.sha512: return new SHA512Digest((SHA512Digest)hash); + case HashAlgorithm.sm3: + return new SM3Digest((SM3Digest)hash); default: throw new IllegalArgumentException("invalid HashAlgorithm: " + HashAlgorithm.getText(hashAlgorithm)); } From 0c7a24664d290f116f4a6ad7a5eb1eb0f493c99c Mon Sep 17 00:00:00 2001 From: cliven Date: Thu, 11 Mar 2021 09:26:26 +0800 Subject: [PATCH 09/22] fix big BigInteger need set flag to process byte array signum --- .../tls/crypto/impl/BcGmsslEncryptor.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java index 8b794533e4..755f66babb 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java @@ -49,22 +49,28 @@ public byte[] encrypt(byte[] input, int inOff, int length) throws IOException ByteArrayInputStream stream = new ByteArrayInputStream(c1c3c2); // read 1 byte for uncompressed point prefix 0x04 stream.read(); - byte[] x = TlsUtils.readFully(32, stream); - byte[] y = TlsUtils.readFully(32, stream); - byte[] hash = TlsUtils.readFully(32, stream); - final byte[] cipherText = TlsUtils.readFully(length, stream); + final byte[] x = new byte[32]; + final byte[] y = new byte[32]; + final byte[] hash = new byte[32]; + final byte[] cipherText = new byte[length]; + stream.read(x); + stream.read(y); + stream.read(hash); + stream.read(cipherText); final SM2Cipher sm2Cipher = new SM2Cipher(); - sm2Cipher.setxCoordinate(new ASN1Integer(new BigInteger(x))); - sm2Cipher.setyCoordinate(new ASN1Integer(new BigInteger(y))); + sm2Cipher.setxCoordinate(new ASN1Integer(new BigInteger(1, x))); + sm2Cipher.setyCoordinate(new ASN1Integer(new BigInteger(1, y))); sm2Cipher.setHash(new DEROctetString(hash)); sm2Cipher.setCipherText(new DEROctetString(cipherText)); final byte[] encoded = sm2Cipher.getEncoded(); System.out.printf(">> PreMasterSecret Key: %s\n", Hex.toHexString(input).toUpperCase()); System.out.printf(">> CipherTtext: %s\n", Hex.toHexString(encoded).toUpperCase()); + System.out.printf(">> C1C3C2: %s\n", Hex.toHexString(c1c3c2).toUpperCase()); + System.out.printf(">> X: %s\n", Hex.toHexString(x).toUpperCase()); + System.out.printf(">> Y: %s\n", Hex.toHexString(y).toUpperCase()); return encoded; - } - catch (InvalidCipherTextException e) + } catch (InvalidCipherTextException e) { throw new TlsFatalAlert(AlertDescription.internal_error); } From a26181edfbb465dfb7a8c86698f5fbe18240db0a Mon Sep 17 00:00:00 2001 From: cliven Date: Thu, 11 Mar 2021 15:44:32 +0800 Subject: [PATCH 10/22] TlsBlockCipher support gmssl struct encrypt and decrypt. The client can successfully establish a GMSSL connection --- .../tls/crypto/impl/BcGmsslEncryptor.java | 10 +---- .../tls/crypto/impl/TlsBlockCipher.java | 39 ++++++++++++++++++- .../tls/crypto/impl/bc/BcTlsCrypto.java | 6 +-- .../tls/test/GMSSLClientTest.java | 2 +- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java index 755f66babb..34bb2d3bb1 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java @@ -9,8 +9,6 @@ import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.tls.AlertDescription; import org.bouncycastle.tls.TlsFatalAlert; -import org.bouncycastle.tls.TlsUtils; -import org.bouncycastle.util.encoders.Hex; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -63,13 +61,7 @@ public byte[] encrypt(byte[] input, int inOff, int length) throws IOException sm2Cipher.setyCoordinate(new ASN1Integer(new BigInteger(1, y))); sm2Cipher.setHash(new DEROctetString(hash)); sm2Cipher.setCipherText(new DEROctetString(cipherText)); - final byte[] encoded = sm2Cipher.getEncoded(); - System.out.printf(">> PreMasterSecret Key: %s\n", Hex.toHexString(input).toUpperCase()); - System.out.printf(">> CipherTtext: %s\n", Hex.toHexString(encoded).toUpperCase()); - System.out.printf(">> C1C3C2: %s\n", Hex.toHexString(c1c3c2).toUpperCase()); - System.out.printf(">> X: %s\n", Hex.toHexString(x).toUpperCase()); - System.out.printf(">> Y: %s\n", Hex.toHexString(y).toUpperCase()); - return encoded; + return sm2Cipher.getEncoded(); } catch (InvalidCipherTextException e) { throw new TlsFatalAlert(AlertDescription.internal_error); diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsBlockCipher.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsBlockCipher.java index 5000b2bb99..d700d2e745 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsBlockCipher.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/TlsBlockCipher.java @@ -28,6 +28,7 @@ public class TlsBlockCipher protected final boolean useExplicitIV; protected final boolean acceptExtraPadding; protected final boolean useExtraPadding; + protected final boolean useGMSSL; protected final TlsBlockCipherImpl decryptCipher, encryptCipher; protected final TlsSuiteMac readMac, writeMac; @@ -49,6 +50,7 @@ public TlsBlockCipher(TlsCrypto crypto, TlsCryptoParameters cryptoParams, TlsBlo this.encryptThenMAC = securityParameters.isEncryptThenMAC(); this.useExplicitIV = TlsImplUtils.isTLSv11(negotiatedVersion); + this.useGMSSL = TlsUtils.isGMSSLv11(negotiatedVersion); this.acceptExtraPadding = !negotiatedVersion.isSSL(); @@ -205,7 +207,7 @@ public TlsEncodeResult encodePlaintext(long seqNo, short contentType, ProtocolVe } int totalSize = len + macSize + padding_length; - if (useExplicitIV) + if (useExplicitIV || useGMSSL) { totalSize += blockSize; } @@ -221,6 +223,29 @@ public TlsEncodeResult encodePlaintext(long seqNo, short contentType, ProtocolVe outOff += blockSize; } + if (useGMSSL) + { + /* + * GMSSL GenericBlockCipher struct same as RFC5246 TLS 1.2 + * struct { + * opaque IV[SecurityParameters.record_iv_length]; + * block-ciphered struct { + * opaque content[TLSCompressed.length]; + * opaque MAC[SecurityParameters.mac_length]; + * uint8 padding[GenericBlockCipher.padding_length]; + * uint8 padding_length; + * }; + * } GenericBlockCipher; + */ + byte[] explicitIV = cryptoParams.getNonceGenerator().generateNonce(blockSize); + System.arraycopy(explicitIV, 0, outBuf, outOff, blockSize); + // set cipher with new iv. + encryptCipher.init(explicitIV, 0, blockSize); + // GMSSL use explicit IV put after header, this part not be encrypted. + headerAllocation += blockSize; + outOff += blockSize; + } + System.arraycopy(plaintext, offset, outBuf, outOff, len); outOff += len; @@ -311,6 +336,18 @@ public TlsDecodeResult decodeCiphertext(long seqNo, short recordType, ProtocolVe } } + if(useGMSSL) + { + // Get explicit IV from begin of message + byte[] explicitIV = new byte[blockSize]; + System.arraycopy(ciphertext, offset, explicitIV, 0, blockSize); + // set explicit IV to decrypt cipher + decryptCipher.init(explicitIV, 0, blockSize); + // encrypted part does not include iv + offset += blockSize; + blocks_length -= blockSize; + } + decryptCipher.doFinal(ciphertext, offset, blocks_length, ciphertext, offset); if (useExplicitIV) diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java index 22a271dd02..fde889d82d 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java @@ -429,10 +429,8 @@ protected TlsCipher createSM4Cipher(TlsCryptoParameters cryptoParams, int macAlg throws IOException { // SM4 Block size 128bit => 16 byte - return new TlsBlockCipher(this, cryptoParams, - new BlockOperator(createSM4BlockCipher(), true), - new BlockOperator(createSM4BlockCipher(), false), - createMAC(cryptoParams, macAlgorithm), + return new TlsBlockCipher(this, cryptoParams, new BlockOperator(createSM4BlockCipher(), true), + new BlockOperator(createSM4BlockCipher(), false), createMAC(cryptoParams, macAlgorithm), createMAC(cryptoParams, macAlgorithm), 16); } diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java index 70dec11678..d57123b7e7 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java @@ -37,7 +37,7 @@ public static void main(String[] args) private static void bc(InetAddress HOST, int port) throws IOException { final MockGMSSLClient client = new MockGMSSLClient(); - Socket s = new Socket("localhost", port,null, 2333); + Socket s = new Socket(HOST, port); TlsClientProtocol protocol = new TlsClientProtocol(s.getInputStream(), s.getOutputStream()); protocol.connect(client); From e1ad0604e9497660d850c8a4ecc30b9be2c18f20 Mon Sep 17 00:00:00 2001 From: cliven Date: Thu, 11 Mar 2021 16:06:12 +0800 Subject: [PATCH 11/22] change test site. --- .../java/org/bouncycastle/tls/test/GMSSLClientTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java index d57123b7e7..06870b857c 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java @@ -28,23 +28,23 @@ public static void main(String[] args) Security.addProvider(provider); Security.addProvider(new BouncyCastleJsseProvider()); - InetAddress host = InetAddress.getByName("localhost"); + String host = "sm2test.ovssl.cn"; int port = 443; // jsse(host, port); bc(host, port); } - private static void bc(InetAddress HOST, int port) throws IOException + private static void bc(String host, int port) throws IOException { final MockGMSSLClient client = new MockGMSSLClient(); - Socket s = new Socket(HOST, port); + Socket s = new Socket(host, port); TlsClientProtocol protocol = new TlsClientProtocol(s.getInputStream(), s.getOutputStream()); protocol.connect(client); OutputStream out = protocol.getOutputStream(); String req = "GET / HTTP/1.1\r\n" + - "Host: localhost\r\n" + + "Host: "+ host + "\r\n" + "Connection: close\r\n\r\n"; out.write(req.getBytes("UTF-8")); From 79e8066dc0f96ff38965cc691620236086ee95be Mon Sep 17 00:00:00 2001 From: cliven Date: Fri, 12 Mar 2021 18:04:01 +0800 Subject: [PATCH 12/22] implement server side gmssl SM2_SM4_SM3 suite develop. Simplified the convertion of SM2 between ASN1 and C1C3C2 formats. add test needed certificates and keys --- .../org/bouncycastle/asn1/gm/SM2Cipher.java | 75 ++++++++++- .../org/bouncycastle/tls/ProtocolVersion.java | 4 + .../bouncycastle/tls/TlsSM2KeyExchange.java | 114 ++++++++++++----- .../bouncycastle/tls/TlsServerProtocol.java | 17 ++- .../java/org/bouncycastle/tls/TlsUtils.java | 5 +- .../tls/crypto/impl/BcGmsslEncryptor.java | 25 +--- .../crypto/impl/bc/BcGMSSLCredentials.java | 119 ++++++++++++++++++ .../tls/test/GMSSLClientTest.java | 21 ++-- .../tls/test/GMSSLServerTest.java | 101 +++++++++++++++ .../tls/test/MockGMSSLClient.java | 4 +- .../tls/test/MockGMSSLServer.java | 108 ++++++++++++++++ .../bouncycastle/tls/test/x509-ca-key-sm2.pem | 6 + .../org/bouncycastle/tls/test/x509-ca-sm2.pem | 13 ++ .../tls/test/x509-server-key-sm2-enc.pem | 6 + .../tls/test/x509-server-key-sm2-sign.pem | 6 + .../tls/test/x509-server-sm2-enc.pem | 13 ++ .../tls/test/x509-server-sm2-sign.pem | 14 +++ 17 files changed, 578 insertions(+), 73 deletions(-) create mode 100644 tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcGMSSLCredentials.java create mode 100644 tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java create mode 100644 tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLServer.java create mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-sm2.pem create mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-sm2.pem create mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-sm2-enc.pem create mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-sm2-sign.pem create mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-sm2-enc.pem create mode 100644 tls/src/test/resources/org/bouncycastle/tls/test/x509-server-sm2-sign.pem diff --git a/core/src/main/java/org/bouncycastle/asn1/gm/SM2Cipher.java b/core/src/main/java/org/bouncycastle/asn1/gm/SM2Cipher.java index b9c31b72fe..5592a7e049 100644 --- a/core/src/main/java/org/bouncycastle/asn1/gm/SM2Cipher.java +++ b/core/src/main/java/org/bouncycastle/asn1/gm/SM2Cipher.java @@ -1,12 +1,17 @@ package org.bouncycastle.asn1.gm; import org.bouncycastle.asn1.*; +import org.bouncycastle.util.BigIntegers; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; import java.util.Enumeration; /** * GMT 0009-2012 - * + *

* sm2 encrypted data specific struct * * @author Cliven @@ -104,4 +109,72 @@ public ASN1Primitive toASN1Primitive() v.add(cipherText); return new DERSequence(v); } + + /** + * Convert ASN.1 Struct to C1C3C2 format + * + * @return C1C3C2 + * @throws IOException + */ + public byte[] convertC1C3C2() throws IOException + { + /* + * construct GMT0009-2012 encrypted data struct + */ + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + + final byte[] x = new byte[32]; + final byte[] y = new byte[32]; + + byte[] tmp = BigIntegers.asUnsignedByteArray(getxCoordinate().getValue()); + System.arraycopy(tmp, 0, x, 32 - tmp.length, tmp.length); + tmp = BigIntegers.asUnsignedByteArray(getyCoordinate().getValue()); + System.arraycopy(tmp, 0, y, 32 - tmp.length, tmp.length); + + // C1 + // read 1 byte for uncompressed point prefix 0x04 + stream.write(0x04); + stream.write(x); + stream.write(y); + // C3 + stream.write(getHash().getOctets()); + // C2 + stream.write(getCipherText().getOctets()); + stream.flush(); + return stream.toByteArray(); + } + + /** + * Convert SM2 encrypted result format of c1c3c2 to ASN.1 SM2Cipher + * + * @param c1c3c2 encrypted result + * @return SM2Cipher + * @throws IOException + */ + static public SM2Cipher fromC1C3C2(byte[] c1c3c2) throws IOException + { + /* + * construct GMT0009-2012 encrypted data struct + */ + ByteArrayInputStream stream = new ByteArrayInputStream(c1c3c2); + // read 1 byte for uncompressed point prefix 0x04 + stream.read(); + final byte[] x = new byte[32]; + final byte[] y = new byte[32]; + final byte[] hash = new byte[32]; + int length = c1c3c2.length - 1 - 32 - 32 - 32; + final byte[] cipherText = new byte[length]; + stream.read(x); + stream.read(y); + stream.read(hash); + stream.read(cipherText); + + final SM2Cipher sm2Cipher = new SM2Cipher(); + sm2Cipher.setxCoordinate(new ASN1Integer(new BigInteger(1, x))); + sm2Cipher.setyCoordinate(new ASN1Integer(new BigInteger(1, y))); + sm2Cipher.setHash(new DEROctetString(hash)); + sm2Cipher.setCipherText(new DEROctetString(cipherText)); + return sm2Cipher; + } } diff --git a/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java b/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java index 01811b37f1..c351039c31 100644 --- a/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java +++ b/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java @@ -161,6 +161,9 @@ static boolean isSupportedTLSVersionServer(ProtocolVersion version) int fullVersion = version.getFullVersion(); + if(fullVersion == CLIENT_GM_SUPPORTED_TLS.getFullVersion()){ + return true; + } return fullVersion >= SERVER_EARLIEST_SUPPORTED_TLS.getFullVersion() && fullVersion <= SERVER_LATEST_SUPPORTED_TLS.getFullVersion(); } @@ -232,6 +235,7 @@ public boolean isSSL() public boolean isTLS() { final int majorVersion = getMajorVersion(); + // GMSSL is also a variants TLS return majorVersion == 0x03 || majorVersion == 0x01; } diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java b/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java index 02048bae9b..1f7744a39a 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java @@ -1,9 +1,11 @@ package org.bouncycastle.tls; import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; import org.bouncycastle.tls.crypto.TlsSecret; import org.bouncycastle.tls.crypto.TlsVerifier; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -28,7 +30,8 @@ private static int checkKeyExchange(int keyExchange) } } - protected TlsCredentialedDecryptor serverCredentials = null; + protected TlsCredentialedDecryptor serverDecryptor = null; + protected TlsCredentialedSigner serverSigner = null; /** * first cert of certificate list * use to sign server side key exchange message @@ -47,6 +50,7 @@ private static int checkKeyExchange(int keyExchange) * use to encrypt client generate preMasterSecret. */ protected TlsCertificate serverEncCertificate; + protected TlsSecret preMasterSecret; public TlsSM2KeyExchange(int keyExchange) @@ -61,7 +65,34 @@ public void skipServerCredentials() throws IOException public void processServerCredentials(TlsCredentials serverCredentials) throws IOException { - this.serverCredentials = TlsUtils.requireDecryptorCredentials(serverCredentials); + if(serverCredentials instanceof TlsCredentialedDecryptor && serverCredentials instanceof TlsCredentialedSigner) + { + serverSigner = (TlsCredentialedSigner) serverCredentials; + serverDecryptor = (TlsCredentialedDecryptor) serverCredentials; + final TlsCertificate[] certificateList = serverCredentials.getCertificate().getCertificateList(); + if(certificateList == null || certificateList.length < 2) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + // get certificate + serverSigCertificate = certificateList[0]; + serverEncCertificate = certificateList[1]; + } + else + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + } + + @Override + public byte[] generateServerKeyExchange() throws IOException + { + // build key exchange message plaintext, struct see #buildServerKeyExchangeParams method. + final byte[] plaintext = buildServerKeyExchangeParams(); + final byte[] signature = serverSigner.generateRawSignature(plaintext); + ByteArrayOutputStream bout = new ByteArrayOutputStream(signature.length+2); + TlsUtils.writeOpaque16(signature,bout); + return bout.toByteArray(); } @Override @@ -70,28 +101,8 @@ public void processServerKeyExchange(InputStream input) throws IOException final int n = TlsUtils.readUint16(input); final byte[] signature = TlsUtils.readFully(n, input); - /* - * digitally-signed struct - * { - * opaque client_random[32]; - * opaque server_random[32]; - * opaque ASN.1Cert<1..2^24-1> - * } signed params - * - * the ASN.1Cert field is encrypt certificate - */ - final SecurityParameters securityParameters = context.getSecurityParametersHandshake(); - final byte[] clientRandom = securityParameters.getClientRandom(); - final byte[] serverRandom = securityParameters.getServerRandom(); - final byte[] encCert = serverEncCertificate.getEncoded(); - int totalSize = clientRandom.length + serverRandom.length + 3 + encCert.length; - byte[] plaintext = new byte[totalSize]; - System.arraycopy(clientRandom, 0, plaintext, 0, 32); - System.arraycopy(serverRandom, 0, plaintext, 32, 32); - plaintext[64] = (byte) (0xff & (encCert.length >> 16)); - plaintext[65] = (byte) (0xff & (encCert.length >> 8)); - plaintext[66] = (byte) (0xff & (encCert.length)); - System.arraycopy(encCert, 0, plaintext, 67, encCert.length); + // build KeyExchangeParams plaintext. + byte[] plaintext = buildServerKeyExchangeParams(); final TlsVerifier verifier = serverSigCertificate.createVerifier(SignatureAlgorithm.sm2); DigitallySigned digitallySigned = new DigitallySigned(SignatureAndHashAlgorithm.sm2, signature); @@ -124,12 +135,13 @@ public short[] getClientCertificateTypes() public void processClientCredentials(TlsCredentials clientCredentials) throws IOException { - TlsUtils.requireSignerCredentials(clientCredentials); + } /** * generate preMasterSecret then use enc certificate public key * enc preMasterSecret + * * @param output * @throws IOException */ @@ -144,8 +156,7 @@ public void generateClientKeyExchange(OutputStream output) throws IOException * opaque random[46]; * } PreMasterSecret */ - this.preMasterSecret = context.getCrypto() - .generateRSAPreMasterSecret(context.getClientVersion()); + this.preMasterSecret = context.getCrypto().generateRSAPreMasterSecret(context.getClientVersion()); // add BcGmsslEncryptor to support encrypt preMasterSecret byte[] encryptedPreMasterSecret = preMasterSecret.encrypt(serverEncCertificate); TlsUtils.writeEncryptedPMS(context, encryptedPreMasterSecret, output); @@ -153,10 +164,8 @@ public void generateClientKeyExchange(OutputStream output) throws IOException public void processClientKeyExchange(InputStream input) throws IOException { - throw new TlsFatalAlert(AlertDescription.internal_error); -// byte[] encryptedPreMasterSecret = TlsUtils.readEncryptedPMS(context, input); -// // TODO: 解密工具 -// this.preMasterSecret = serverCredentials.decrypt(new TlsCryptoParameters(context), encryptedPreMasterSecret); + byte[] encryptedPreMasterSecret = TlsUtils.readEncryptedPMS(context, input); + this.preMasterSecret = serverDecryptor.decrypt(new TlsCryptoParameters(context), encryptedPreMasterSecret); } public TlsSecret generatePreMasterSecret() throws IOException @@ -165,4 +174,47 @@ public TlsSecret generatePreMasterSecret() throws IOException this.preMasterSecret = null; return tmp; } + + /** + * build Server side Key Exchange Params plaintext. + * @return params plaintext + * @throws IOException + */ + private byte[] buildServerKeyExchangeParams() throws IOException + { + /* + * SM2_SM4_SM3 suite ServerKeyExchange message struct + * + * GM0009-2012: SM2 is called ECC, + * + * enum {ECDHE,ECC,IBSDH,IBC,RSA} KeyExchangeAlgorithm; + * struct + * { + * select(KeyExchangeAlgorithm) { + * case ECC: + * digitally-signed struct + * { + * opaque client_random[32]; + * opaque server_random[32]; + * opaque ASN.1Cert<1..2^24-1> + * } signed_params + * } + * } ServerKeyExchange; + * + * the ASN.1Cert field is encrypt certificate + */ + final SecurityParameters securityParameters = context.getSecurityParametersHandshake(); + final byte[] clientRandom = securityParameters.getClientRandom(); + final byte[] serverRandom = securityParameters.getServerRandom(); + final byte[] encCert = serverEncCertificate.getEncoded(); + int totalSize = clientRandom.length + serverRandom.length + 3 + encCert.length; + byte[] plaintext = new byte[totalSize]; + System.arraycopy(clientRandom, 0, plaintext, 0, 32); + System.arraycopy(serverRandom, 0, plaintext, 32, 32); + plaintext[64] = (byte) (0xff & (encCert.length >> 16)); + plaintext[65] = (byte) (0xff & (encCert.length >> 8)); + plaintext[66] = (byte) (0xff & (encCert.length)); + System.arraycopy(encCert, 0, plaintext, 67, encCert.length); + return plaintext; + } } diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java b/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java index 774cfab599..4cdcb05789 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java @@ -399,12 +399,20 @@ protected ServerHello generateServerHello(ClientHello clientHello) throws IOExce ProtocolVersion clientVersion = clientLegacyVersion; if (null == tlsServerContext.getClientSupportedVersions()) { - if (clientVersion.isLaterVersionOf(ProtocolVersion.TLSv12)) + if(clientVersion.getEquivalentTLSVersion() == ProtocolVersion.GMSSLv11) { - clientVersion = ProtocolVersion.TLSv12; + tlsServerContext.setClientSupportedVersions(new ProtocolVersion[]{clientVersion}); + } + else + { + if (clientVersion.isLaterVersionOf(ProtocolVersion.TLSv12)) + { + clientVersion = ProtocolVersion.TLSv12; + } + + tlsServerContext.setClientSupportedVersions(clientVersion.downTo(ProtocolVersion.SSLv3)); } - tlsServerContext.setClientSupportedVersions(clientVersion.downTo(ProtocolVersion.SSLv3)); } else { @@ -414,7 +422,8 @@ protected ServerHello generateServerHello(ClientHello clientHello) throws IOExce // Set the legacy_record_version to use for early alerts recordStream.setWriteVersion(clientVersion); - if (!ProtocolVersion.SERVER_EARLIEST_SUPPORTED_TLS.isEqualOrEarlierVersionOf(clientVersion)) + if (!ProtocolVersion.SERVER_EARLIEST_SUPPORTED_TLS.isEqualOrEarlierVersionOf(clientVersion) + && !ProtocolVersion.CLIENT_GM_SUPPORTED_TLS.isEqualOrEarlierVersionOf(clientVersion)) { throw new TlsFatalAlert(AlertDescription.protocol_version); } diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java index 0afb7fdfd9..6fa3bd0575 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java @@ -4361,6 +4361,9 @@ private static TlsKeyExchange createKeyExchangeServer(TlsServer server, int keyE case KeyExchangeAlgorithm.SRP_RSA: return factory.createSRPKeyExchangeServer(keyExchange, server.getSRPLoginParameters()); + case KeyExchangeAlgorithm.SM2: + return factory.createSM2KeyExchange(keyExchange); + default: /* * Note: internal error here; the TlsProtocol implementation verifies that the @@ -5234,7 +5237,7 @@ static TlsCredentials validateCredentials(TlsCredentials credentials) throws IOE count += (credentials instanceof TlsCredentialedAgreement) ? 1 : 0; count += (credentials instanceof TlsCredentialedDecryptor) ? 1 : 0; count += (credentials instanceof TlsCredentialedSigner) ? 1 : 0; - if (count != 1) + if (count < 1) { throw new TlsFatalAlert(AlertDescription.internal_error); } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java index 34bb2d3bb1..9719a7b5f1 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java @@ -10,9 +10,7 @@ import org.bouncycastle.tls.AlertDescription; import org.bouncycastle.tls.TlsFatalAlert; -import java.io.ByteArrayInputStream; import java.io.IOException; -import java.math.BigInteger; import java.security.SecureRandom; /** @@ -40,28 +38,7 @@ public byte[] encrypt(byte[] input, int inOff, int length) throws IOException SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C3C2); engine.init(true, keyParameters); byte[] c1c3c2 = engine.processBlock(input, inOff, length); - - /* - * construct GMT0009-2012 encrypted data struct - */ - ByteArrayInputStream stream = new ByteArrayInputStream(c1c3c2); - // read 1 byte for uncompressed point prefix 0x04 - stream.read(); - final byte[] x = new byte[32]; - final byte[] y = new byte[32]; - final byte[] hash = new byte[32]; - final byte[] cipherText = new byte[length]; - stream.read(x); - stream.read(y); - stream.read(hash); - stream.read(cipherText); - - final SM2Cipher sm2Cipher = new SM2Cipher(); - sm2Cipher.setxCoordinate(new ASN1Integer(new BigInteger(1, x))); - sm2Cipher.setyCoordinate(new ASN1Integer(new BigInteger(1, y))); - sm2Cipher.setHash(new DEROctetString(hash)); - sm2Cipher.setCipherText(new DEROctetString(cipherText)); - return sm2Cipher.getEncoded(); + return SM2Cipher.fromC1C3C2(c1c3c2).getEncoded(); } catch (InvalidCipherTextException e) { throw new TlsFatalAlert(AlertDescription.internal_error); diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcGMSSLCredentials.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcGMSSLCredentials.java new file mode 100644 index 0000000000..1f07fc7044 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcGMSSLCredentials.java @@ -0,0 +1,119 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.asn1.gm.SM2Cipher; +import org.bouncycastle.crypto.CryptoException; +import org.bouncycastle.crypto.engines.SM2Engine; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.ParametersWithRandom; +import org.bouncycastle.crypto.signers.SM2Signer; +import org.bouncycastle.tls.*; +import org.bouncycastle.tls.crypto.TlsCryptoParameters; +import org.bouncycastle.tls.crypto.TlsSecret; +import org.bouncycastle.tls.crypto.TlsStreamSigner; + +import java.io.IOException; +import java.security.Signature; + +/** + * GMSSL need two certificate + * one for sign, one for encrypt + * so we need provider Signer and Decryptor both + * + * @author Cliven + * @since 2021-03-12 12:10:31 + */ +public class BcGMSSLCredentials implements TlsCredentialedSigner, TlsCredentialedDecryptor +{ + private BcTlsCrypto crypto; + /* + * first cert for sign, second sert for encrypt + */ + private Certificate certList; + + private AsymmetricKeyParameter signKey; + private AsymmetricKeyParameter encKey; + private Signature rawSigner; + + public BcGMSSLCredentials(BcTlsCrypto crypto, Certificate certList, AsymmetricKeyParameter signKey, AsymmetricKeyParameter encKey) + { + if(certList.getLength() < 2) + { + throw new IllegalArgumentException("GMSSL need two certificate, first one for sign second one for encrypt."); + } + + this.crypto = crypto; + this.certList = certList; + this.signKey = signKey; + this.encKey = encKey; + } + + /** + * Use encrypt key decrypt ciphertext + * + * @param cryptoParams the parameters to use for the decryption. + * @param ciphertext the cipher text containing the secret. + * @return + * @throws IOException + */ + public TlsSecret decrypt(TlsCryptoParameters cryptoParams, byte[] ciphertext) throws IOException + { + try + { + // Parser ciphertext as ASN.1 SM2Cipher object. + final SM2Cipher sm2Cipher = SM2Cipher.getInstance(ciphertext); + byte[] c1c3c2 = sm2Cipher.convertC1C3C2(); + SM2Engine engine = new SM2Engine(SM2Engine.Mode.C1C3C2); + engine.init(false, encKey); + byte[] preMasterSecret = engine.processBlock(c1c3c2, 0, c1c3c2.length); + return new BcTlsSecret(crypto, preMasterSecret); + } catch (Exception e) + { + throw new TlsFatalAlertReceived(AlertDescription.illegal_parameter); + } + } + + /** + * Use sign private key sign + * + * @param hash a message digest calculated across the message the signature is to apply to. + * @return signature + * @throws IOException + */ + public byte[] generateRawSignature(byte[] hash) throws IOException + { + try + { + final ParametersWithRandom prvKey = new ParametersWithRandom(signKey, crypto.getSecureRandom()); + SM2Signer sm2Signer = new SM2Signer(); + sm2Signer.init(true, prvKey); + sm2Signer.update(hash, 0, hash.length); + return sm2Signer.generateSignature(); + } catch (CryptoException e) + { + e.printStackTrace(); + throw new TlsFatalAlertReceived(AlertDescription.illegal_parameter); + } + } + + public SignatureAndHashAlgorithm getSignatureAndHashAlgorithm() + { + return SignatureAndHashAlgorithm.sm2; + } + + + /** + * GMSSL not support Stream mode + * + * @return null + * @throws IOException not happen + */ + public TlsStreamSigner getStreamSigner() throws IOException + { + return null; + } + + public Certificate getCertificate() + { + return certList; + } +} diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java index 06870b857c..d3e7d28430 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java @@ -3,6 +3,7 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.util.io.Streams; import javax.net.ssl.*; import java.io.IOException; @@ -28,8 +29,10 @@ public static void main(String[] args) Security.addProvider(provider); Security.addProvider(new BouncyCastleJsseProvider()); - String host = "sm2test.ovssl.cn"; - int port = 443; + String host = "localhost"; + int port = 5557; +// String host = "sm2test.ovssl.cn"; +// int port = 443; // jsse(host, port); bc(host, port); } @@ -49,26 +52,22 @@ private static void bc(String host, int port) throws IOException out.write(req.getBytes("UTF-8")); out.flush(); - InputStream in = protocol.getInputStream(); - byte[] buffer = new byte[2048]; - in.read(buffer); - System.out.println(new String(buffer)); - + Streams.pipeAll(protocol.getInputStream(), System.out); out.close(); - in.close(); + } - private static void jsse(InetAddress HOST, int port) throws IOException, NoSuchProviderException, NoSuchAlgorithmException, KeyManagementException + private static void jsse(String host, int port) throws IOException, NoSuchProviderException, NoSuchAlgorithmException, KeyManagementException { SSLContext clientContext = SSLContext.getInstance("GMSSL", BouncyCastleJsseProvider.PROVIDER_NAME); clientContext.init(new KeyManager[]{}, new TrustManager[]{}, new SecureRandom()); SSLSocketFactory fact = clientContext.getSocketFactory(); - SSLSocket cSock = (SSLSocket) fact.createSocket(HOST, port); + SSLSocket cSock = (SSLSocket) fact.createSocket(host, port); OutputStream out = cSock.getOutputStream(); String req = "GET / HTTP/1.1\r\n" + - "Host: localhost\r\n" + + "Host: "+host+"\r\n" + "Connection: close\r\n\r\n"; out.write(req.getBytes("UTF-8")); diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java new file mode 100644 index 0000000000..efc3f42504 --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java @@ -0,0 +1,101 @@ +package org.bouncycastle.tls.test; + +import org.bouncycastle.tls.*; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.util.io.Streams; +import org.bouncycastle.util.io.TeeOutputStream; + +import java.io.*; +import java.net.*; +import java.security.SecureRandom; + +/** + * A simple test designed to conduct a GMSSL handshake with an external GMSSL client. + *

+ * + *

+ */ +public class GMSSLServerTest +{ + public static void main(String[] args) throws Exception + { + + int port = 5557; + + ServerSocket ss = new ServerSocket(port, 16); + try + { + while (true) + { + Socket s = ss.accept(); + System.out.println("--------------------------------------------------------------------------------"); + System.out.println("Accepted " + s); + ServerThread t = new ServerThread(s); + t.start(); + } + } finally + { + ss.close(); + } + } + + static class ServerThread extends Thread + { + private final Socket s; + + ServerThread(Socket s) + { + this.s = s; + } + + public void run() + { + byte[] buff = new byte[2028]; + try + { + MockGMSSLServer server = new MockGMSSLServer(); + TlsServerProtocol serverProtocol = new TlsServerProtocol(s.getInputStream(), s.getOutputStream()); + serverProtocol.accept(server); + + final InputStream in = serverProtocol.getInputStream(); + InputStreamReader isr = new InputStreamReader(in); + BufferedReader br = new BufferedReader(isr); + System.out.println(">> Request:\n"); + String lineContent = null; + while ((lineContent = br.readLine()) != null) + { + if(lineContent.length() == 0) + { + break; + } + System.out.println("> " + lineContent); + } + System.out.println(); + + OutputStream outputStream = serverProtocol.getOutputStream(); + String resp = "HTTP/1.1 200 OK\r\n" + + "Content-Length: 6\r\n" + + "Content-Type: text/plain; charset=utf-8\r\n" + + "\r\n" + + "hello\n"; + outputStream.write(resp.getBytes("UTF-8")); + outputStream.flush(); + serverProtocol.close(); + System.out.println(">> Responded"); + } catch (Exception e) + { + throw new RuntimeException(e); + } finally + { + try + { + s.close(); + } catch (IOException e) + { + } finally + { + } + } + } + } +} diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLClient.java b/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLClient.java index 3cdcf0e930..e346d7c21d 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLClient.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLClient.java @@ -9,7 +9,9 @@ import java.util.Hashtable; /** - * @author 权观宇 + * Mock GMSSL client + * + * @author Cliven * @since 2021-03-09 14:01:50 */ public class MockGMSSLClient extends AbstractTlsClient diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLServer.java b/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLServer.java new file mode 100644 index 0000000000..d3f8ab956f --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLServer.java @@ -0,0 +1,108 @@ +package org.bouncycastle.tls.test; + +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.tls.*; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.impl.bc.BcGMSSLCredentials; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; +import java.io.PrintStream; +import java.security.SecureRandom; +import java.util.Vector; + +class MockGMSSLServer + extends DefaultTlsServer +{ + + MockGMSSLServer() + { + super(new BcTlsCrypto(new SecureRandom())); + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("GMSSL server raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("GMSSL server received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + + public ProtocolVersion getServerVersion() throws IOException + { + ProtocolVersion serverVersion = super.getServerVersion(); + + System.out.println("GMSSL server negotiated " + serverVersion); + + return serverVersion; + } + + public CertificateRequest getCertificateRequest() throws IOException + { + return null; + } + + public void notifyClientCertificate(org.bouncycastle.tls.Certificate clientCertificate) throws IOException + { + + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + byte[] tlsServerEndPoint = context.exportChannelBinding(ChannelBinding.tls_server_end_point); + System.out.println("Server 'tls-server-end-point': " + hex(tlsServerEndPoint)); + + byte[] tlsUnique = context.exportChannelBinding(ChannelBinding.tls_unique); + System.out.println("Server 'tls-unique': " + hex(tlsUnique)); + } + + @Override + public TlsCredentials getCredentials() throws IOException + { + final Certificate certList = TlsTestUtils.loadCertificateChain(this.context, new String[]{ + "x509-server-sm2-sign.pem", "x509-server-sm2-enc.pem"}); + final AsymmetricKeyParameter signKey = TlsTestUtils.loadBcPrivateKeyResource("x509-server-key-sm2-sign.pem"); + final AsymmetricKeyParameter encKey = TlsTestUtils.loadBcPrivateKeyResource("x509-server-key-sm2-enc.pem"); + return new BcGMSSLCredentials((BcTlsCrypto) getCrypto(), certList, signKey, encKey); + } + + @Override + public boolean shouldUseGMTUnixTime() + { + return true; + } + + protected int[] getSupportedCipherSuites() + { + return new int[]{CipherSuite.GMSSL_ECC_SM4_SM3}; + } + + protected ProtocolVersion[] getSupportedVersions() + { + return ProtocolVersion.GMSSLv11.only(); + } + + protected String hex(byte[] data) + { + return data == null ? "(null)" : Hex.toHexString(data); + } + +} diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-sm2.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-sm2.pem new file mode 100644 index 0000000000..d1433c53f3 --- /dev/null +++ b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-key-sm2.pem @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgPja9Wd7sQOI2ZEis +h1FZbHcsO4NUxqT9lSDiI9pQOBmgCgYIKoEcz1UBgi2hRANCAARnMDPZoNh72vvL +bO+8W5QjkV5wcOZormBLJf+ZCAi59jqJApvUUtmz9m/ALJMeIVur0oVUsvlI/hKz +vUvnv3XK +-----END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-sm2.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-sm2.pem new file mode 100644 index 0000000000..f8c16e8591 --- /dev/null +++ b/tls/src/test/resources/org/bouncycastle/tls/test/x509-ca-sm2.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB5DCCAYmgAwIBAgIIAs4Dt8fd5ncwCgYIKoEcz1UBg3UwRTELMAkGA1UEBhMC +Q04xETAPBgNVBAgTCFpoZWppYW5nMREwDwYDVQQHEwhIYW5nemhvdTEQMA4GA1UE +ChMHVGVzdCBDQTAeFw0yMTAzMTIwMzQ1MzVaFw0zMTAzMTIwMzQ1MzVaMEUxCzAJ +BgNVBAYTAkNOMREwDwYDVQQIEwhaaGVqaWFuZzERMA8GA1UEBxMISGFuZ3pob3Ux +EDAOBgNVBAoTB1Rlc3QgQ0EwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNCAARnMDPZ +oNh72vvLbO+8W5QjkV5wcOZormBLJf+ZCAi59jqJApvUUtmz9m/ALJMeIVur0oVU +svlI/hKzvUvnv3XKo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUJzDbP6IFeVDlegj4rMuWgPNPw8MwHwYDVR0jBBgwFoAUJzDb +P6IFeVDlegj4rMuWgPNPw8MwCgYIKoEcz1UBg3UDSQAwRgIhAIk4RUSafZ/Mx6Fi +vD0dzrehJyZ3NdTgfkpaGBtyU+xCAiEA5Pv54SXiCAH5RwYQbaCxCtml8NTn3WVd +DVM1URKXiNQ= +-----END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-sm2-enc.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-sm2-enc.pem new file mode 100644 index 0000000000..c432275800 --- /dev/null +++ b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-sm2-enc.pem @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgOwrsOroddxkoOYoE +xZlbDdPsrSY6ug08Saf/IkMSbxegCgYIKoEcz1UBgi2hRANCAARB5CzonabehIxs +RegFs1Vs3IZrXJXzZIPH2F1afv/NLj3OSngVUMbGK0sTOSfdn1wLKiLAvvzYuHgb +sA3LAW/E +-----END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-sm2-sign.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-sm2-sign.pem new file mode 100644 index 0000000000..3619dbfba6 --- /dev/null +++ b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-key-sm2-sign.pem @@ -0,0 +1,6 @@ +-----BEGIN PRIVATE KEY----- +MIGTAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBHkwdwIBAQQgsanX/ZPknQYj5Ihn +J394MHsOBFB7GI2QuqsOWm4B+kGgCgYIKoEcz1UBgi2hRANCAATdyAq+Ik8vkBPp +CyMn7Q+uRiipEvNWVNm+3+q5zM4oisxMuneyCt51HlnA2Iom9T7tL25ejnMYt0UB +L4Aj1aaU +-----END PRIVATE KEY----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-sm2-enc.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-sm2-enc.pem new file mode 100644 index 0000000000..5751eb0d0b --- /dev/null +++ b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-sm2-enc.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIIB7TCCAZOgAwIBAgIIAs4Dt8ftfmcwCgYIKoEcz1UBg3UwRTELMAkGA1UEBhMC +Q04xETAPBgNVBAgTCFpoZWppYW5nMREwDwYDVQQHEwhIYW5nemhvdTEQMA4GA1UE +ChMHVGVzdCBDQTAeFw0yMTAzMTIwMzQ2MzdaFw0zMTAzMTIwMzQ1MzVaMGAxCzAJ +BgNVBAYTAkNOMREwDwYDVQQIEwhaaGVqaWFuZzERMA8GA1UEBxMISGFuZ3pob3Ux +ETAPBgNVBAoTCHRlc3Qgb3JnMRgwFgYDVQQDDA9URVNUX1RMU19TRVJWRVIwWTAT +BgcqhkjOPQIBBggqgRzPVQGCLQNCAARB5CzonabehIxsRegFs1Vs3IZrXJXzZIPH +2F1afv/NLj3OSngVUMbGK0sTOSfdn1wLKiLAvvzYuHgbsA3LAW/Eo1IwUDAOBgNV +HQ8BAf8EBAMCBDAwHQYDVR0OBBYEFEmiOBKBDtDro5jJ45jyKG2NNjhFMB8GA1Ud +IwQYMBaAFCcw2z+iBXlQ5XoI+KzLloDzT8PDMAoGCCqBHM9VAYN1A0gAMEUCIQDd +XGPbrR1DZkqeXzkqAIlsLzXfS61EqW9mH/xkhD0UvgIgBKg3S1uRS4YL25ZC472v +Dl6tCE72cMM6xnBzSwQl6oY= +-----END CERTIFICATE----- diff --git a/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-sm2-sign.pem b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-sm2-sign.pem new file mode 100644 index 0000000000..24148aad6e --- /dev/null +++ b/tls/src/test/resources/org/bouncycastle/tls/test/x509-server-sm2-sign.pem @@ -0,0 +1,14 @@ +-----BEGIN CERTIFICATE----- +MIICDTCCAbKgAwIBAgIIAs4Dt8ftdtcwCgYIKoEcz1UBg3UwRTELMAkGA1UEBhMC +Q04xETAPBgNVBAgTCFpoZWppYW5nMREwDwYDVQQHEwhIYW5nemhvdTEQMA4GA1UE +ChMHVGVzdCBDQTAeFw0yMTAzMTIwMzQ2MzdaFw0zMTAzMTIwMzQ1MzVaMGAxCzAJ +BgNVBAYTAkNOMREwDwYDVQQIEwhaaGVqaWFuZzERMA8GA1UEBxMISGFuZ3pob3Ux +ETAPBgNVBAoTCHRlc3Qgb3JnMRgwFgYDVQQDDA9URVNUX1RMU19TRVJWRVIwWTAT +BgcqhkjOPQIBBggqgRzPVQGCLQNCAATdyAq+Ik8vkBPpCyMn7Q+uRiipEvNWVNm+ +3+q5zM4oisxMuneyCt51HlnA2Iom9T7tL25ejnMYt0UBL4Aj1aaUo3EwbzAOBgNV +HQ8BAf8EBAMCBsAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1Ud +DgQWBBSGSgh9dcFdcLn3NjQBJpYachVZYzAfBgNVHSMEGDAWgBQnMNs/ogV5UOV6 +CPisy5aA80/DwzAKBggqgRzPVQGDdQNJADBGAiEA6z2Jjhiok+e+Y6tEJlnn3dcE +kJX+cIBiHkDnjtQOIi0CIQD0nEDlrbC5PyZY9Ydk/dLfmpmjsknNmx3GJgG9MA/z +VA== +-----END CERTIFICATE----- From 92ca36cbdd388432151a6d1942238db9a7970003 Mon Sep 17 00:00:00 2001 From: cliven Date: Mon, 15 Mar 2021 17:18:06 +0800 Subject: [PATCH 13/22] add server version limit, if server dont have version of protocol then refuse connection. finish server side gmssl debug, gm browser access test. --- .../org/bouncycastle/tls/ProtocolVersion.java | 4 ++++ .../bouncycastle/tls/TlsServerProtocol.java | 19 ++++++++++++------- .../tls/test/GMSSLClientTest.java | 2 +- .../tls/test/MockGMSSLServer.java | 12 ++++++++---- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java b/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java index c351039c31..b9510bc4f0 100644 --- a/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java +++ b/tls/src/main/java/org/bouncycastle/tls/ProtocolVersion.java @@ -227,6 +227,10 @@ public boolean isDTLS() return getMajorVersion() == 0xFE; } + public boolean isGMSSL(){ + return getMajorVersion() == 0x01; + } + public boolean isSSL() { return this == SSLv3; diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java b/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java index 4cdcb05789..91b8fc5afd 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java @@ -174,7 +174,7 @@ protected ServerHello generate13ServerHello(ClientHello clientHello, boolean aft /* * TODO[tls13] Confirm fields in the ClientHello haven't changed - * + * * RFC 8446 4.1.2 [..] when the server has responded to its ClientHello with a * HelloRetryRequest [..] the client MUST send the same ClientHello without * modification, except as follows: [key_share, early_data, cookie, pre_shared_key, @@ -223,7 +223,7 @@ protected ServerHello generate13ServerHello(ClientHello clientHello, boolean aft /* * NOTE: Currently no server support for session resumption - * + * * If adding support, ensure securityParameters.tlsUnique is set to the localVerifyData, but * ONLY when extended_master_secret has been negotiated (otherwise NULL). */ @@ -334,7 +334,7 @@ protected ServerHello generate13ServerHello(ClientHello clientHello, boolean aft /* * TODO[tls13] RFC 8446 4.4.2.1. OCSP Status and SCT Extensions. - * + * * OCSP information is carried in an extension for a CertificateEntry. */ securityParameters.statusRequestVersion = clientHelloExtensions.containsKey(TlsExtensionsUtils.EXT_status_request) @@ -344,7 +344,7 @@ protected ServerHello generate13ServerHello(ClientHello clientHello, boolean aft { int namedGroup = clientShare.getNamedGroup(); - + TlsAgreement agreement; if (NamedGroup.refersToASpecificCurve(namedGroup)) { @@ -390,7 +390,6 @@ protected ServerHello generateServerHello(ClientHello clientHello) throws IOExce this.offeredCipherSuites = clientHello.getCipherSuites(); - SecurityParameters securityParameters = tlsServerContext.getSecurityParametersHandshake(); tlsServerContext.setClientSupportedVersions( @@ -419,6 +418,12 @@ protected ServerHello generateServerHello(ClientHello clientHello) throws IOExce clientVersion = ProtocolVersion.getLatestTLS(tlsServerContext.getClientSupportedVersions()); } + // check server client is support client versions + if(!ProtocolVersion.contains(tlsServer.getProtocolVersions(), clientVersion)) + { + throw new TlsFatalAlert(AlertDescription.protocol_version); + } + // Set the legacy_record_version to use for early alerts recordStream.setWriteVersion(clientVersion); @@ -730,7 +735,7 @@ protected void handle13HandshakeMessage(short type, HandshakeMessageInput buf) { /* * TODO[tls13] Abbreviated handshakes (PSK resumption) - * + * * NOTE: No CertificateRequest, Certificate, CertificateVerify messages, but client * might now send EndOfEarlyData after receiving server Finished message. */ @@ -1108,7 +1113,7 @@ else if (TlsUtils.isTLSv12(tlsServerContext)) /* * RFC 5246 If no suitable certificate is available, the client MUST send a * certificate message containing no certificates. - * + * * NOTE: In previous RFCs, this was SHOULD instead of MUST. */ throw new TlsFatalAlert(AlertDescription.unexpected_message); diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java index d3e7d28430..f3f625c827 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java @@ -30,7 +30,7 @@ public static void main(String[] args) Security.addProvider(new BouncyCastleJsseProvider()); String host = "localhost"; - int port = 5557; + int port = 446; // String host = "sm2test.ovssl.cn"; // int port = 443; // jsse(host, port); diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLServer.java b/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLServer.java index d3f8ab956f..8b579e3588 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLServer.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLServer.java @@ -44,13 +44,17 @@ public void notifyAlertReceived(short alertLevel, short alertDescription) + ", " + AlertDescription.getText(alertDescription)); } - public ProtocolVersion getServerVersion() throws IOException + @Override + public void notifySecureRenegotiation(boolean secureRenegotiation) throws IOException { - ProtocolVersion serverVersion = super.getServerVersion(); - System.out.println("GMSSL server negotiated " + serverVersion); + } - return serverVersion; + public ProtocolVersion getServerVersion() throws IOException + { +// ProtocolVersion serverVersion = super.getServerVersion(); +// System.out.println("GMSSL server negotiated " + serverVersion); + return ProtocolVersion.GMSSLv11; } public CertificateRequest getCertificateRequest() throws IOException From 5dfe15eaa3201b5e4038e4643602ad46487d6bee Mon Sep 17 00:00:00 2001 From: Quan guanyu Date: Tue, 16 Mar 2021 10:05:35 +0800 Subject: [PATCH 14/22] change mock GMSSL CLient/Server to SimpleGMSSL public access. --- .../jsse/provider/gm/SimpleGMSSLClient.java} | 17 ++- .../jsse/provider/gm/SimpleGMSSLServer.java | 121 ++++++++++++++++++ .../tls/test/GMSSLClientTest.java | 6 +- .../tls/test/GMSSLServerTest.java | 33 +++-- .../tls/test/MockGMSSLServer.java | 112 ---------------- 5 files changed, 157 insertions(+), 132 deletions(-) rename tls/src/{test/java/org/bouncycastle/tls/test/MockGMSSLClient.java => main/java/org/bouncycastle/jsse/provider/gm/SimpleGMSSLClient.java} (81%) create mode 100644 tls/src/main/java/org/bouncycastle/jsse/provider/gm/SimpleGMSSLServer.java delete mode 100644 tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLServer.java diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLClient.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/SimpleGMSSLClient.java similarity index 81% rename from tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLClient.java rename to tls/src/main/java/org/bouncycastle/jsse/provider/gm/SimpleGMSSLClient.java index e346d7c21d..9da7f04e46 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLClient.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/SimpleGMSSLClient.java @@ -1,4 +1,4 @@ -package org.bouncycastle.tls.test; +package org.bouncycastle.jsse.provider.gm; import org.bouncycastle.tls.*; import org.bouncycastle.tls.crypto.TlsCrypto; @@ -9,12 +9,15 @@ import java.util.Hashtable; /** - * Mock GMSSL client + * Simple GMSSL client + * + * - make handshake connection + * - no authentication * * @author Cliven * @since 2021-03-09 14:01:50 */ -public class MockGMSSLClient extends AbstractTlsClient +public class SimpleGMSSLClient extends AbstractTlsClient { private static final int[] DEFAULT_CIPHER_SUITES = new int[] { @@ -24,12 +27,12 @@ public class MockGMSSLClient extends AbstractTlsClient CipherSuite.GMSSL_ECC_SM4_SM3, }; - public MockGMSSLClient() + public SimpleGMSSLClient() { this(new BcTlsCrypto(new SecureRandom())); } - public MockGMSSLClient(TlsCrypto crypto) + public SimpleGMSSLClient(TlsCrypto crypto) { super(crypto); } @@ -52,12 +55,12 @@ public TlsAuthentication getAuthentication() throws IOException public void notifyServerCertificate(TlsServerCertificate serverCertificate) throws IOException { - System.out.println(">> TlsAuthentication on notifyServerCertificate"); +// System.out.println(">> TlsAuthentication on notifyServerCertificate"); } public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException { - System.out.println(">> TlsAuthentication on getClientCredentials"); +// System.out.println(">> TlsAuthentication on getClientCredentials"); return null; } }; diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/SimpleGMSSLServer.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/SimpleGMSSLServer.java new file mode 100644 index 0000000000..e5be82ed7d --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/SimpleGMSSLServer.java @@ -0,0 +1,121 @@ +package org.bouncycastle.jsse.provider.gm; + +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.tls.*; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.impl.bc.BcGMSSLCredentials; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; +import java.io.PrintStream; +import java.security.SecureRandom; + +/** + * Simple GMSSL Server + * + * @author Cliven + * @since 2021-03-16 09:31:14 + */ +public class SimpleGMSSLServer + extends DefaultTlsServer +{ + /* + * contain two cert, first for sign, second for encrypt + */ + protected Certificate certList; + protected AsymmetricKeyParameter signKey; + protected AsymmetricKeyParameter encKey; + + /** + * Create GMSSL Server Instance + * + * @param crypto crypto + * @param certList contain two cert, first for sign, second for encrypt + * @param signKey sign private key + * @param encKey encrypt private key + */ + public SimpleGMSSLServer(TlsCrypto crypto, Certificate certList, AsymmetricKeyParameter signKey, AsymmetricKeyParameter encKey) + { + super(crypto); + this.certList = certList; + this.signKey = signKey; + this.encKey = encKey; + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { +// PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; +// out.println("GMSSL server raised alert: " + AlertLevel.getText(alertLevel) +// + ", " + AlertDescription.getText(alertDescription)); +// if (message != null) +// { +// out.println("> " + message); +// } +// if (cause != null) +// { +// cause.printStackTrace(out); +// } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { +// PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; +// out.println("GMSSL server received alert: " + AlertLevel.getText(alertLevel) +// + ", " + AlertDescription.getText(alertDescription)); + } + + @Override + public void notifySecureRenegotiation(boolean secureRenegotiation) throws IOException + { + + } + + public ProtocolVersion getServerVersion() throws IOException + { + return ProtocolVersion.GMSSLv11; + } + + public CertificateRequest getCertificateRequest() throws IOException + { + return null; + } + + public void notifyClientCertificate(Certificate clientCertificate) throws IOException + { + + } + + public void notifyHandshakeComplete() throws IOException + { + + } + + @Override + public TlsCredentials getCredentials() throws IOException + { + return new BcGMSSLCredentials((BcTlsCrypto) getCrypto(), certList, signKey, encKey); + } + + @Override + public boolean shouldUseGMTUnixTime() + { + return true; + } + + protected int[] getSupportedCipherSuites() + { + return new int[]{CipherSuite.GMSSL_ECC_SM4_SM3}; + } + + protected ProtocolVersion[] getSupportedVersions() + { + return ProtocolVersion.GMSSLv11.only(); + } + + protected String hex(byte[] data) + { + return data == null ? "(null)" : Hex.toHexString(data); + } + +} diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java index f3f625c827..58c6bcbb10 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java @@ -2,6 +2,7 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; +import org.bouncycastle.jsse.provider.gm.SimpleGMSSLClient; import org.bouncycastle.tls.TlsClientProtocol; import org.bouncycastle.util.io.Streams; @@ -30,16 +31,15 @@ public static void main(String[] args) Security.addProvider(new BouncyCastleJsseProvider()); String host = "localhost"; - int port = 446; + int port = 5557; // String host = "sm2test.ovssl.cn"; // int port = 443; -// jsse(host, port); bc(host, port); } private static void bc(String host, int port) throws IOException { - final MockGMSSLClient client = new MockGMSSLClient(); + final SimpleGMSSLClient client = new SimpleGMSSLClient(); Socket s = new Socket(host, port); TlsClientProtocol protocol = new TlsClientProtocol(s.getInputStream(), s.getOutputStream()); protocol.connect(client); diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java index efc3f42504..2a82426001 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java @@ -1,6 +1,9 @@ package org.bouncycastle.tls.test; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.jsse.provider.gm.SimpleGMSSLServer; import org.bouncycastle.tls.*; +import org.bouncycastle.tls.crypto.TlsCertificate; import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.TeeOutputStream; @@ -11,18 +14,33 @@ /** * A simple test designed to conduct a GMSSL handshake with an external GMSSL client. - *

* - *

+ * @author Cliven + * @since 2021-03-16 09:57:58 */ public class GMSSLServerTest { + static BcTlsCrypto crypto; + static AsymmetricKeyParameter signKey; + static AsymmetricKeyParameter encKey; + static Certificate certList; + public static void main(String[] args) throws Exception { int port = 5557; - ServerSocket ss = new ServerSocket(port, 16); + + crypto = new BcTlsCrypto(new SecureRandom()); + + certList = new Certificate(new TlsCertificate[]{ + TlsTestUtils.loadCertificateResource(crypto, "x509-server-sm2-sign.pem"), + TlsTestUtils.loadCertificateResource(crypto, "x509-server-sm2-enc.pem"), + }); + + signKey = TlsTestUtils.loadBcPrivateKeyResource("x509-server-key-sm2-sign.pem"); + encKey = TlsTestUtils.loadBcPrivateKeyResource("x509-server-key-sm2-enc.pem"); + try { while (true) @@ -50,10 +68,9 @@ static class ServerThread extends Thread public void run() { - byte[] buff = new byte[2028]; try { - MockGMSSLServer server = new MockGMSSLServer(); + SimpleGMSSLServer server = new SimpleGMSSLServer(crypto, certList, signKey, encKey); TlsServerProtocol serverProtocol = new TlsServerProtocol(s.getInputStream(), s.getOutputStream()); serverProtocol.accept(server); @@ -73,11 +90,7 @@ public void run() System.out.println(); OutputStream outputStream = serverProtocol.getOutputStream(); - String resp = "HTTP/1.1 200 OK\r\n" - + "Content-Length: 6\r\n" - + "Content-Type: text/plain; charset=utf-8\r\n" - + "\r\n" - + "hello\n"; + String resp = "HTTP/1.1 200 OK\r\n" + "Content-Length: 6\r\n" + "Content-Type: text/plain; charset=utf-8\r\n" + "\r\n" + "hello\n"; outputStream.write(resp.getBytes("UTF-8")); outputStream.flush(); serverProtocol.close(); diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLServer.java b/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLServer.java deleted file mode 100644 index 8b579e3588..0000000000 --- a/tls/src/test/java/org/bouncycastle/tls/test/MockGMSSLServer.java +++ /dev/null @@ -1,112 +0,0 @@ -package org.bouncycastle.tls.test; - -import org.bouncycastle.asn1.x500.X500Name; -import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.tls.*; -import org.bouncycastle.tls.crypto.TlsCertificate; -import org.bouncycastle.tls.crypto.impl.bc.BcGMSSLCredentials; -import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; -import org.bouncycastle.util.encoders.Hex; - -import java.io.IOException; -import java.io.PrintStream; -import java.security.SecureRandom; -import java.util.Vector; - -class MockGMSSLServer - extends DefaultTlsServer -{ - - MockGMSSLServer() - { - super(new BcTlsCrypto(new SecureRandom())); - } - - public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) - { - PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; - out.println("GMSSL server raised alert: " + AlertLevel.getText(alertLevel) - + ", " + AlertDescription.getText(alertDescription)); - if (message != null) - { - out.println("> " + message); - } - if (cause != null) - { - cause.printStackTrace(out); - } - } - - public void notifyAlertReceived(short alertLevel, short alertDescription) - { - PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; - out.println("GMSSL server received alert: " + AlertLevel.getText(alertLevel) - + ", " + AlertDescription.getText(alertDescription)); - } - - @Override - public void notifySecureRenegotiation(boolean secureRenegotiation) throws IOException - { - - } - - public ProtocolVersion getServerVersion() throws IOException - { -// ProtocolVersion serverVersion = super.getServerVersion(); -// System.out.println("GMSSL server negotiated " + serverVersion); - return ProtocolVersion.GMSSLv11; - } - - public CertificateRequest getCertificateRequest() throws IOException - { - return null; - } - - public void notifyClientCertificate(org.bouncycastle.tls.Certificate clientCertificate) throws IOException - { - - } - - public void notifyHandshakeComplete() throws IOException - { - super.notifyHandshakeComplete(); - - byte[] tlsServerEndPoint = context.exportChannelBinding(ChannelBinding.tls_server_end_point); - System.out.println("Server 'tls-server-end-point': " + hex(tlsServerEndPoint)); - - byte[] tlsUnique = context.exportChannelBinding(ChannelBinding.tls_unique); - System.out.println("Server 'tls-unique': " + hex(tlsUnique)); - } - - @Override - public TlsCredentials getCredentials() throws IOException - { - final Certificate certList = TlsTestUtils.loadCertificateChain(this.context, new String[]{ - "x509-server-sm2-sign.pem", "x509-server-sm2-enc.pem"}); - final AsymmetricKeyParameter signKey = TlsTestUtils.loadBcPrivateKeyResource("x509-server-key-sm2-sign.pem"); - final AsymmetricKeyParameter encKey = TlsTestUtils.loadBcPrivateKeyResource("x509-server-key-sm2-enc.pem"); - return new BcGMSSLCredentials((BcTlsCrypto) getCrypto(), certList, signKey, encKey); - } - - @Override - public boolean shouldUseGMTUnixTime() - { - return true; - } - - protected int[] getSupportedCipherSuites() - { - return new int[]{CipherSuite.GMSSL_ECC_SM4_SM3}; - } - - protected ProtocolVersion[] getSupportedVersions() - { - return ProtocolVersion.GMSSLv11.only(); - } - - protected String hex(byte[] data) - { - return data == null ? "(null)" : Hex.toHexString(data); - } - -} From 45a747f2ec683861b905af65efc2a21f2a22022e Mon Sep 17 00:00:00 2001 From: Quan guanyu Date: Tue, 16 Mar 2021 17:00:29 +0800 Subject: [PATCH 15/22] Add GM Simple Socket Factory. --- .../provider/BouncyCastleJsseProvider.java | 9 - .../jsse/provider/ProvSSLContextSpi.java | 17 +- ...MSSLClient.java => GMSimpleSSLClient.java} | 6 +- ...MSSLServer.java => GMSimpleSSLServer.java} | 4 +- .../jsse/provider/gm/GMSimpleSSLSocket.java | 285 ++++++++++++++++++ .../provider/gm/GMSimpleSSLSocketFactory.java | 135 +++++++++ .../provider/gm/GMSimpleSSLSocketWrap.java | 283 +++++++++++++++++ .../tls/test/GMSSLClientTest.java | 22 +- .../tls/test/GMSSLServerTest.java | 12 +- .../test/GMSimpleSSLSocketFactoryTest.java | 139 +++++++++ 10 files changed, 865 insertions(+), 47 deletions(-) rename tls/src/main/java/org/bouncycastle/jsse/provider/gm/{SimpleGMSSLClient.java => GMSimpleSSLClient.java} (94%) rename tls/src/main/java/org/bouncycastle/jsse/provider/gm/{SimpleGMSSLServer.java => GMSimpleSSLServer.java} (97%) create mode 100644 tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java create mode 100644 tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketFactory.java create mode 100644 tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketWrap.java create mode 100644 tls/src/test/java/org/bouncycastle/tls/test/GMSimpleSSLSocketFactoryTest.java diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java b/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java index 5c06638aef..ae5add537b 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/BouncyCastleJsseProvider.java @@ -209,14 +209,6 @@ public Object createInstance(Object constructorParameter) new String[]{ "TLSv1.3", "TLSv1.2", "TLSv1.1", "TLSv1" }); } }); - addAlgorithmImplementation("SSLContext.GMSSLv1.1", "org.bouncycastle.jsse.provider.SSLContext.GMSSLv1_1", - new EngineCreator() - { - public Object createInstance(Object constructorParameter) - { - return new ProvSSLContextSpi(fipsMode, cryptoProvider, new String[]{ "GMSSLv1.1" }); - } - }); addAlgorithmImplementation("SSLContext.DEFAULT", "org.bouncycastle.jsse.provider.SSLContext.Default", new EngineCreator() { @@ -227,7 +219,6 @@ public Object createInstance(Object constructorParameter) throws GeneralSecurity }); addAlias("Alg.Alias.SSLContext.SSL", "TLS"); addAlias("Alg.Alias.SSLContext.SSLV3", "TLSV1"); - addAlias("Alg.Alias.SSLContext.GMSSL", "GMSSLv1.1"); return fipsMode; } diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java index 271f277dec..aed465c24c 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLContextSpi.java @@ -66,7 +66,7 @@ class ProvSSLContextSpi private static final List DEFAULT_CIPHERSUITE_LIST_FIPS = createDefaultCipherSuiteListFips(DEFAULT_CIPHERSUITE_LIST); // TODO[tls13] Enable TLSv1.3 by default in due course - private static final String[] DEFAULT_ENABLED_PROTOCOLS = new String[]{ "TLSv1.2", "TLSv1.1", "TLSv1" ,"GMSSLv1.1"}; + private static final String[] DEFAULT_ENABLED_PROTOCOLS = new String[]{ "TLSv1.2", "TLSv1.1", "TLSv1" }; private static void addCipherSuite(Map cs, String name, int cipherSuite) { @@ -109,9 +109,6 @@ private static List createDefaultCipherSuiteList(Set supportedCi cs.add("TLS_RSA_WITH_AES_256_CBC_SHA"); cs.add("TLS_RSA_WITH_AES_128_CBC_SHA"); - // GMSSL 1.1 - cs.add("GMSSL_ECC_SM4_SM3"); - cs.retainAll(supportedCipherSuiteSet); cs.trimToSize(); return Collections.unmodifiableList(cs); @@ -242,9 +239,6 @@ private static Map createSupportedCipherSuiteMap() addCipherSuite(cs, "TLS_RSA_WITH_NULL_SHA", CipherSuite.TLS_RSA_WITH_NULL_SHA); addCipherSuite(cs, "TLS_RSA_WITH_NULL_SHA256", CipherSuite.TLS_RSA_WITH_NULL_SHA256); - // GMSSL 1.1 - addCipherSuite(cs, "GMSSL_ECC_SM4_SM3", CipherSuite.GMSSL_ECC_SM4_SM3); - return Collections.unmodifiableMap(cs); } @@ -264,7 +258,6 @@ private static Map createSupportedProtocolMap() ps.put("TLSv1.1", ProtocolVersion.TLSv11); ps.put("TLSv1", ProtocolVersion.TLSv10); ps.put("SSLv3", ProtocolVersion.SSLv3); - ps.put("GMSSLv1.1", ProtocolVersion.GMSSLv11); return Collections.unmodifiableMap(ps); } @@ -483,8 +476,6 @@ int[] getActiveCipherSuites(JcaTlsCrypto crypto, ProvSSLParameters sslParameters boolean post13Active = TlsUtils.isTLSv13(latest); boolean pre13Active = !TlsUtils.isTLSv13(earliest); - boolean isGMSSLActive = TlsUtils.isGMSSLv11(latest); - int[] candidates = new int[enabledCipherSuites.length]; int count = 0; @@ -495,12 +486,6 @@ int[] getActiveCipherSuites(JcaTlsCrypto crypto, ProvSSLParameters sslParameters { continue; } - if (isGMSSLActive && !candidate.isGMSSLv11()) - { - // GMSSL specific suite different with TLS - // if found GMSSL active just keep gm related suites - continue; - } if (candidate.isTLSv13()) { if (!post13Active) diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/SimpleGMSSLClient.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java similarity index 94% rename from tls/src/main/java/org/bouncycastle/jsse/provider/gm/SimpleGMSSLClient.java rename to tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java index 9da7f04e46..2c7b294870 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/SimpleGMSSLClient.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java @@ -17,7 +17,7 @@ * @author Cliven * @since 2021-03-09 14:01:50 */ -public class SimpleGMSSLClient extends AbstractTlsClient +public class GMSimpleSSLClient extends AbstractTlsClient { private static final int[] DEFAULT_CIPHER_SUITES = new int[] { @@ -27,12 +27,12 @@ public class SimpleGMSSLClient extends AbstractTlsClient CipherSuite.GMSSL_ECC_SM4_SM3, }; - public SimpleGMSSLClient() + public GMSimpleSSLClient() { this(new BcTlsCrypto(new SecureRandom())); } - public SimpleGMSSLClient(TlsCrypto crypto) + public GMSimpleSSLClient(TlsCrypto crypto) { super(crypto); } diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/SimpleGMSSLServer.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLServer.java similarity index 97% rename from tls/src/main/java/org/bouncycastle/jsse/provider/gm/SimpleGMSSLServer.java rename to tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLServer.java index e5be82ed7d..5ad6f7a061 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/SimpleGMSSLServer.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLServer.java @@ -17,7 +17,7 @@ * @author Cliven * @since 2021-03-16 09:31:14 */ -public class SimpleGMSSLServer +public class GMSimpleSSLServer extends DefaultTlsServer { /* @@ -35,7 +35,7 @@ public class SimpleGMSSLServer * @param signKey sign private key * @param encKey encrypt private key */ - public SimpleGMSSLServer(TlsCrypto crypto, Certificate certList, AsymmetricKeyParameter signKey, AsymmetricKeyParameter encKey) + public GMSimpleSSLServer(TlsCrypto crypto, Certificate certList, AsymmetricKeyParameter signKey, AsymmetricKeyParameter encKey) { super(crypto); this.certList = certList; diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java new file mode 100644 index 0000000000..10051bf164 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java @@ -0,0 +1,285 @@ +package org.bouncycastle.jsse.provider.gm; + +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsProtocol; +import org.bouncycastle.tls.TlsServerProtocol; +import org.bouncycastle.tls.crypto.TlsCrypto; + +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.SocketAddress; + +/** + * GMSSL Socket simple implement. + * + * @author Cliven + * @since 2021-03-16 13:18:06 + */ +public class GMSimpleSSLSocket extends SSLSocket +{ + public static final String[] SUPPORT_CRYPTO_SUITES = { + "GMSSL_SM2_SM4_SM3" + }; + + public static final String[] SUPPORT_PROTOCOL_VERSIONS = { + "GMSSLv1.1" + }; + + protected boolean useClientMode = true; + protected TlsProtocol protocol; + + protected TlsCrypto crypto; + protected Certificate certList; + protected AsymmetricKeyParameter signKey, encKey; + + + protected GMSimpleSSLSocket() + { + super(); + } + + public GMSimpleSSLSocket(String host, int port) throws IOException + { + super(host, port); + } + + public GMSimpleSSLSocket(InetAddress host, int port) throws IOException + { + super(host, port); + } + + public GMSimpleSSLSocket(String host, int port, InetAddress localAddress, int localPort) throws IOException + { + super(host, port, localAddress, localPort); + } + + public GMSimpleSSLSocket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException + { + super(host, port, localAddress, localPort); + } + + /** + * set socket use client mode + * + * @param crypto crypto + * @return GMSimpleSSLSocket + */ + public GMSimpleSSLSocket useClientMode(TlsCrypto crypto) + { + this.useClientMode = true; + this.crypto = crypto; + this.certList = null; + this.signKey = null; + this.encKey = null; + return this; + } + + /** + * set socket use server mode + * + * @param crypto crypto + * @param certList sign cert and encrypt cert + * @param signKey sign keypair + * @param encKey enc keypair + * @return GMSimpleSSLSocket + */ + public GMSimpleSSLSocket useServerMode(TlsCrypto crypto, Certificate certList, AsymmetricKeyParameter signKey, AsymmetricKeyParameter encKey) + { + this.useClientMode = false; + this.crypto = crypto; + this.certList = certList; + this.signKey = signKey; + this.encKey = encKey; + return this; + } + + + @Override + public String[] getSupportedCipherSuites() + { + return SUPPORT_CRYPTO_SUITES; + } + + @Override + public String[] getEnabledCipherSuites() + { + return SUPPORT_CRYPTO_SUITES; + } + + @Override + public void setEnabledCipherSuites(String[] strings) + { + + } + + @Override + public String[] getSupportedProtocols() + { + return SUPPORT_PROTOCOL_VERSIONS; + } + + @Override + public String[] getEnabledProtocols() + { + return SUPPORT_PROTOCOL_VERSIONS; + } + + @Override + public void setEnabledProtocols(String[] strings) + { + + } + + @Override + public void connect(SocketAddress endpoint) throws IOException + { + super.connect(endpoint); + } + + @Override + public SSLSession getSession() + { + return null; + } + + @Override + public void addHandshakeCompletedListener(HandshakeCompletedListener handshakeCompletedListener) + { + + } + + @Override + public void removeHandshakeCompletedListener(HandshakeCompletedListener handshakeCompletedListener) + { + + } + + @Override + public void startHandshake() throws IOException + { + InputStream input = super.getInputStream(); + OutputStream output = super.getOutputStream(); + + makeHandshake(input, output); + } + + protected void makeHandshake(InputStream input, OutputStream output) throws IOException + { + if(this.useClientMode) + { + TlsClientProtocol clientProtocol = new TlsClientProtocol(input, output); + this.protocol = clientProtocol; + GMSimpleSSLClient client = new GMSimpleSSLClient(crypto); + clientProtocol.connect(client); + } + else + { + GMSimpleSSLServer server = new GMSimpleSSLServer(crypto, certList, signKey, encKey); + TlsServerProtocol serverProtocol = new TlsServerProtocol(input, output); + this.protocol = serverProtocol; + serverProtocol.accept(server); + } + } + + synchronized void handshakeIfNecessary() throws IOException + { + + if (protocol == null || protocol.isHandshaking()) + { + startHandshake(); + } + } + + + @Override + public InputStream getInputStream() throws IOException + { + handshakeIfNecessary(); + return this.protocol.getInputStream(); + } + + @Override + public OutputStream getOutputStream() throws IOException + { + handshakeIfNecessary(); + return this.protocol.getOutputStream(); + } + + @Override + public void setUseClientMode(boolean b) + { + this.useClientMode = b; + } + + @Override + public boolean getUseClientMode() + { + return useClientMode; + } + + @Override + public void setNeedClientAuth(boolean b) + { + } + + @Override + public boolean getNeedClientAuth() + { + return false; + } + + @Override + public void setWantClientAuth(boolean b) + { + + } + + @Override + public boolean getWantClientAuth() + { + return false; + } + + @Override + public void setEnableSessionCreation(boolean b) + { + + } + + @Override + public boolean getEnableSessionCreation() + { + return false; + } + + @Override + public synchronized void close() throws IOException + { + if(protocol != null) + { + protocol.close(); + } + } + + @Override + protected void finalize() throws Throwable + { + try + { + close(); + } catch (IOException e) + { + // Ignore + } finally + { + super.finalize(); + } + } +} diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketFactory.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketFactory.java new file mode 100644 index 0000000000..3a32e71cc7 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketFactory.java @@ -0,0 +1,135 @@ +package org.bouncycastle.jsse.provider.gm; + +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.jcajce.provider.asymmetric.GM; +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.crypto.TlsCrypto; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; + +import javax.net.ssl.SSLSocketFactory; +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.SecureRandom; + +/** + * Simple GMSSL Socket Factory + * + * @author Cliven + * @since 2021-03-16 13:15:00 + */ +public class GMSimpleSSLSocketFactory extends SSLSocketFactory +{ + + private TlsCrypto crypto; + private Certificate certList; + private AsymmetricKeyParameter signKey, encKey; + private Boolean clientMode = true; + + + /** + * Create Client side socket factory Instance + */ + public GMSimpleSSLSocketFactory() + { + this.crypto = new BcTlsCrypto(new SecureRandom()); + } + + /** + * Create server side socket factory Instance + * + * @param certList sign cert and encrypt cert + * @param signKey sign key + * @param encKey enc key + */ + public GMSimpleSSLSocketFactory(Certificate certList, AsymmetricKeyParameter signKey, AsymmetricKeyParameter encKey) + { + this(); + this.certList = certList; + this.signKey = signKey; + this.encKey = encKey; + clientMode = false; + } + + /** + * Create Client side socket factory Instance + * @return factory Instance + */ + public static GMSimpleSSLSocketFactory ClientFactory() + { + return new GMSimpleSSLSocketFactory(); + } + + /** + * Create server side socket factory Instance + * + * @param certList sign cert and encrypt cert + * @param signKey sign key + * @param encKey enc key + */ + public static GMSimpleSSLSocketFactory ServerFactory(Certificate certList, AsymmetricKeyParameter signKey, + AsymmetricKeyParameter encKey) + { + return new GMSimpleSSLSocketFactory(certList, signKey,encKey); + } + + @Override + public String[] getDefaultCipherSuites() + { + return GMSimpleSSLSocket.SUPPORT_CRYPTO_SUITES; + } + + @Override + public String[] getSupportedCipherSuites() + { + return GMSimpleSSLSocket.SUPPORT_CRYPTO_SUITES; + } + + private GMSimpleSSLSocket ret(GMSimpleSSLSocket socket) + { + if(clientMode) + { + return socket.useClientMode(crypto); + } + else + { + return socket.useServerMode(crypto, certList, signKey, encKey); + } + } + + @Override + public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException + { + final GMSimpleSSLSocketWrap wrap = new GMSimpleSSLSocketWrap(socket, autoClose); + return ret(wrap); + } + + @Override + public Socket createSocket(String host, int port) throws IOException, UnknownHostException + { + final GMSimpleSSLSocket socket = new GMSimpleSSLSocket(host, port); + return ret(socket); + } + + @Override + public Socket createSocket(String host, int port, InetAddress inetAddress, int localPort) throws IOException, UnknownHostException + { + final GMSimpleSSLSocket socket = new GMSimpleSSLSocket(host, port, inetAddress, localPort); + return ret(socket); + } + + @Override + public Socket createSocket(InetAddress inetAddress, int port) throws IOException + { + final GMSimpleSSLSocket socket = new GMSimpleSSLSocket(inetAddress, port); + return ret(socket); + } + + @Override + public Socket createSocket(InetAddress inetAddress, int port, InetAddress localAddress, int localPort) throws IOException + { + final GMSimpleSSLSocket socket = new GMSimpleSSLSocket(inetAddress, port, localAddress, localPort); + return ret(socket); + } +} diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketWrap.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketWrap.java new file mode 100644 index 0000000000..602dbbe440 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketWrap.java @@ -0,0 +1,283 @@ +package org.bouncycastle.jsse.provider.gm; + +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.TlsClientProtocol; +import org.bouncycastle.tls.TlsProtocol; +import org.bouncycastle.tls.TlsServerProtocol; +import org.bouncycastle.tls.crypto.TlsCrypto; + +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.channels.SocketChannel; + +/** + * GMSSL Socket simple implement. + * + * @author Cliven + * @since 2021-03-16 13:18:06 + */ +public class GMSimpleSSLSocketWrap extends GMSimpleSSLSocket +{ + protected Socket wrapScoket = null; + protected boolean autoClose; + + public GMSimpleSSLSocketWrap(Socket wrapScoket, boolean autoClose) + { + super(); + this.wrapScoket = wrapScoket; + this.autoClose = autoClose; + } + + @Override + public void connect(SocketAddress endpoint) throws IOException + { + throw new SocketException("Wrapped socket should already be connected"); + } + + @Override + public void connect(SocketAddress endpoint, int timeout) throws IOException + { + throw new SocketException("Wrapped socket should already be connected"); + } + + @Override + public void bind(SocketAddress bindpoint) throws IOException + { + wrapScoket.bind(bindpoint); + } + + @Override + public InetAddress getInetAddress() + { + return wrapScoket.getInetAddress(); + } + + @Override + public InetAddress getLocalAddress() + { + return wrapScoket.getLocalAddress(); + } + + @Override + public int getPort() + { + return wrapScoket.getPort(); + } + + @Override + public int getLocalPort() + { + return wrapScoket.getLocalPort(); + } + + @Override + public SocketAddress getRemoteSocketAddress() + { + return wrapScoket.getRemoteSocketAddress(); + } + + @Override + public SocketAddress getLocalSocketAddress() + { + return wrapScoket.getLocalSocketAddress(); + } + + @Override + public SocketChannel getChannel() + { + return wrapScoket.getChannel(); + } + + @Override + public void setTcpNoDelay(boolean on) throws SocketException + { + wrapScoket.setTcpNoDelay(on); + } + + @Override + public boolean getTcpNoDelay() throws SocketException + { + return wrapScoket.getTcpNoDelay(); + } + + @Override + public void setSoLinger(boolean on, int linger) throws SocketException + { + wrapScoket.setSoLinger(on, linger); + } + + @Override + public int getSoLinger() throws SocketException + { + return wrapScoket.getSoLinger(); + } + + @Override + public void sendUrgentData(int data) throws IOException + { + wrapScoket.sendUrgentData(data); + } + + @Override + public void setOOBInline(boolean on) throws SocketException + { + wrapScoket.setOOBInline(on); + } + + @Override + public boolean getOOBInline() throws SocketException + { + return wrapScoket.getOOBInline(); + } + + @Override + public synchronized void setSoTimeout(int timeout) throws SocketException + { + wrapScoket.setSoTimeout(timeout); + } + + @Override + public synchronized int getSoTimeout() throws SocketException + { + return wrapScoket.getSoTimeout(); + } + + @Override + public synchronized void setSendBufferSize(int size) throws SocketException + { + wrapScoket.setSendBufferSize(size); + } + + @Override + public synchronized int getSendBufferSize() throws SocketException + { + return wrapScoket.getSendBufferSize(); + } + + @Override + public synchronized void setReceiveBufferSize(int size) throws SocketException + { + wrapScoket.setReceiveBufferSize(size); + } + + @Override + public synchronized int getReceiveBufferSize() throws SocketException + { + return wrapScoket.getReceiveBufferSize(); + } + + @Override + public void setKeepAlive(boolean on) throws SocketException + { + wrapScoket.setKeepAlive(on); + } + + @Override + public boolean getKeepAlive() throws SocketException + { + return wrapScoket.getKeepAlive(); + } + + @Override + public void setTrafficClass(int tc) throws SocketException + { + wrapScoket.setTrafficClass(tc); + } + + @Override + public int getTrafficClass() throws SocketException + { + return wrapScoket.getTrafficClass(); + } + + @Override + public void setReuseAddress(boolean on) throws SocketException + { + wrapScoket.setReuseAddress(on); + } + + @Override + public boolean getReuseAddress() throws SocketException + { + return wrapScoket.getReuseAddress(); + } + + @Override + public void shutdownInput() throws IOException + { + wrapScoket.shutdownInput(); + } + + @Override + public void shutdownOutput() throws IOException + { + wrapScoket.shutdownOutput(); + } + + @Override + public String toString() + { + return wrapScoket.toString(); + } + + @Override + public boolean isConnected() + { + return wrapScoket.isConnected(); + } + + @Override + public boolean isBound() + { + return wrapScoket.isBound(); + } + + @Override + public boolean isClosed() + { + return wrapScoket.isClosed(); + } + + @Override + public boolean isInputShutdown() + { + return wrapScoket.isInputShutdown(); + } + + @Override + public boolean isOutputShutdown() + { + return wrapScoket.isOutputShutdown(); + } + + @Override + public void setPerformancePreferences(int connectionTime, int latency, int bandwidth) + { + wrapScoket.setPerformancePreferences(connectionTime, latency, bandwidth); + } + + @Override + public void startHandshake() throws IOException + { + makeHandshake(wrapScoket.getInputStream(), wrapScoket.getOutputStream()); + } + @Override + public synchronized void close() throws IOException + { + super.close(); + if(autoClose) + { + wrapScoket.close(); + } + } + +} diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java index 58c6bcbb10..10f0dfba17 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java @@ -2,17 +2,16 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; -import org.bouncycastle.jsse.provider.gm.SimpleGMSSLClient; +import org.bouncycastle.jsse.provider.gm.GMSimpleSSLClient; import org.bouncycastle.tls.TlsClientProtocol; import org.bouncycastle.util.io.Streams; import javax.net.ssl.*; import java.io.IOException; + import java.io.InputStream; import java.io.OutputStream; -import java.net.InetAddress; import java.net.Socket; -import java.net.SocketAddress; import java.security.*; /** @@ -30,16 +29,17 @@ public static void main(String[] args) Security.addProvider(provider); Security.addProvider(new BouncyCastleJsseProvider()); - String host = "localhost"; - int port = 5557; -// String host = "sm2test.ovssl.cn"; -// int port = 443; - bc(host, port); +// String host = "localhost"; +// int port = 5557; + String host = "sm2test.ovssl.cn"; + int port = 443; +// bc(host, port); + jsse(host, port); } private static void bc(String host, int port) throws IOException { - final SimpleGMSSLClient client = new SimpleGMSSLClient(); + final GMSimpleSSLClient client = new GMSimpleSSLClient(); Socket s = new Socket(host, port); TlsClientProtocol protocol = new TlsClientProtocol(s.getInputStream(), s.getOutputStream()); protocol.connect(client); @@ -54,13 +54,11 @@ private static void bc(String host, int port) throws IOException out.flush(); Streams.pipeAll(protocol.getInputStream(), System.out); out.close(); - - } private static void jsse(String host, int port) throws IOException, NoSuchProviderException, NoSuchAlgorithmException, KeyManagementException { - SSLContext clientContext = SSLContext.getInstance("GMSSL", BouncyCastleJsseProvider.PROVIDER_NAME); + SSLContext clientContext = SSLContext.getInstance("TLS", BouncyCastleJsseProvider.PROVIDER_NAME); clientContext.init(new KeyManager[]{}, new TrustManager[]{}, new SecureRandom()); SSLSocketFactory fact = clientContext.getSocketFactory(); SSLSocket cSock = (SSLSocket) fact.createSocket(host, port); diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java index 2a82426001..983b133d2b 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java @@ -1,12 +1,10 @@ package org.bouncycastle.tls.test; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.jsse.provider.gm.SimpleGMSSLServer; +import org.bouncycastle.jsse.provider.gm.GMSimpleSSLServer; import org.bouncycastle.tls.*; import org.bouncycastle.tls.crypto.TlsCertificate; import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; -import org.bouncycastle.util.io.Streams; -import org.bouncycastle.util.io.TeeOutputStream; import java.io.*; import java.net.*; @@ -28,7 +26,7 @@ public class GMSSLServerTest public static void main(String[] args) throws Exception { - int port = 5557; + int port = 5559; ServerSocket ss = new ServerSocket(port, 16); crypto = new BcTlsCrypto(new SecureRandom()); @@ -70,7 +68,7 @@ public void run() { try { - SimpleGMSSLServer server = new SimpleGMSSLServer(crypto, certList, signKey, encKey); + GMSimpleSSLServer server = new GMSimpleSSLServer(crypto, certList, signKey, encKey); TlsServerProtocol serverProtocol = new TlsServerProtocol(s.getInputStream(), s.getOutputStream()); serverProtocol.accept(server); @@ -97,6 +95,10 @@ public void run() System.out.println(">> Responded"); } catch (Exception e) { + if(e instanceof EOFException) + { + return; + } throw new RuntimeException(e); } finally { diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSimpleSSLSocketFactoryTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSimpleSSLSocketFactoryTest.java new file mode 100644 index 0000000000..8b7577fed4 --- /dev/null +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSimpleSSLSocketFactoryTest.java @@ -0,0 +1,139 @@ +package org.bouncycastle.tls.test; + + +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.jsse.provider.gm.GMSimpleSSLSocketFactory; +import org.bouncycastle.tls.Certificate; +import org.bouncycastle.tls.crypto.TlsCertificate; +import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto; +import org.bouncycastle.util.io.Streams; + +import java.io.*; +import java.net.ServerSocket; +import java.net.Socket; +import java.security.SecureRandom; + +public class GMSimpleSSLSocketFactoryTest +{ + static final int port = 5558; + + public static void main(String[] args) throws IOException, InterruptedException + { + + BcTlsCrypto crypto = new BcTlsCrypto(new SecureRandom()); + final Certificate certList = new Certificate(new TlsCertificate[]{ + TlsTestUtils.loadCertificateResource(crypto, "x509-server-sm2-sign.pem"), + TlsTestUtils.loadCertificateResource(crypto, "x509-server-sm2-enc.pem"), + }); + final AsymmetricKeyParameter signKey = TlsTestUtils.loadBcPrivateKeyResource("x509-server-key-sm2-sign.pem"); + final AsymmetricKeyParameter encKey = TlsTestUtils.loadBcPrivateKeyResource("x509-server-key-sm2-enc.pem"); + + + bootServer(port, certList, signKey, encKey); + +// bootClient("localhost", port); + + } + + private static void bootServer(int port, Certificate certList, AsymmetricKeyParameter signKey, AsymmetricKeyParameter encKey) + { + ServerSocket ss = null; + try + { + final GMSimpleSSLSocketFactory socketFactory = GMSimpleSSLSocketFactory.ServerFactory(certList, signKey, encKey); + ss = new ServerSocket(port, 16); + + while (true) + { + Socket s = ss.accept(); + System.out.println("--------------------------------------------------------------------------------"); + System.out.println("Accepted " + s); + s = socketFactory.createSocket(s, "", 0, true); + new Thread(new ServerThread(s)).start(); + } + } catch (IOException e) + { + e.printStackTrace(); + } finally + { + try + { + if(ss != null) + { + ss.close(); + } + } catch (IOException e) + { + } + } + } + + private static void bootClient(String host, int port) throws IOException + { + final GMSimpleSSLSocketFactory socketFactory = GMSimpleSSLSocketFactory.ClientFactory(); + final Socket cSock = socketFactory.createSocket(host, port); + OutputStream out = cSock.getOutputStream(); + String req = "GET / HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"; + + out.write(req.getBytes("UTF-8")); + out.flush(); + InputStream in = cSock.getInputStream(); + Streams.pipeAll(in, System.out); + out.close(); + in.close(); + } + + static class ServerThread implements Runnable + { + private final Socket socket; + + public ServerThread(Socket s) + { + this.socket = s; + } + + public void run() + { + try + { + InputStreamReader isr = new InputStreamReader(socket.getInputStream()); + BufferedReader br = new BufferedReader(isr); + System.out.println(">> Request:\n"); + String lineContent = null; + while ((lineContent = br.readLine()) != null) + { + if(lineContent.length() == 0) + { + break; + } + System.out.println("> " + lineContent); + } + System.out.println(); + + OutputStream outputStream = socket.getOutputStream(); + String resp = "HTTP/1.1 200 OK\r\n" + "Content-Length: 6\r\n" + "Content-Type: text/plain; charset=utf-8\r\n" + "\r\n" + "hello\n"; + outputStream.write(resp.getBytes("UTF-8")); + outputStream.flush(); + socket.close(); + System.out.println(">> Responded"); + } catch (IOException e) + { + if(e instanceof EOFException) + { + return; + } + e.printStackTrace(); + } finally + { + try + { + socket.close(); + } catch (IOException e) + { + + } + } + } + } + +} \ No newline at end of file From 13731921fb774d716d262c82bf16ca2fcb9c0581 Mon Sep 17 00:00:00 2001 From: Quan guanyu Date: Tue, 16 Mar 2021 17:28:29 +0800 Subject: [PATCH 16/22] Manually resolve merge conflicts --- .../bouncycastle/tls/SignatureAlgorithm.java | 49 +++++++++++-- .../tls/SignatureAndHashAlgorithm.java | 68 ++++++++++++++----- 2 files changed, 93 insertions(+), 24 deletions(-) diff --git a/tls/src/main/java/org/bouncycastle/tls/SignatureAlgorithm.java b/tls/src/main/java/org/bouncycastle/tls/SignatureAlgorithm.java index 583c451798..d745feb544 100644 --- a/tls/src/main/java/org/bouncycastle/tls/SignatureAlgorithm.java +++ b/tls/src/main/java/org/bouncycastle/tls/SignatureAlgorithm.java @@ -9,7 +9,7 @@ public class SignatureAlgorithm public static final short rsa = 1; public static final short dsa = 2; public static final short ecdsa = 3; - public static final short sm2 = 23; + /* * RFC 8422 @@ -18,7 +18,7 @@ public class SignatureAlgorithm public static final short ed448 = 8; /* - * RFC 8446 (implied for TLS 1.2 use) + * RFC 8446 (implied from SignatureScheme values) */ public static final short rsa_pss_rsae_sha256 = 4; public static final short rsa_pss_rsae_sha384 = 5; @@ -27,6 +27,18 @@ public class SignatureAlgorithm public static final short rsa_pss_pss_sha384 = 10; public static final short rsa_pss_pss_sha512 = 11; + /* + * RFC 8734 (implied from SignatureScheme values) + */ + public static final short ecdsa_brainpoolP256r1tls13_sha256 = 26; + public static final short ecdsa_brainpoolP384r1tls13_sha384 = 27; + public static final short ecdsa_brainpoolP512r1tls13_sha512 = 28; + + /** + * GMSSL GMT 0009-2012 + */ + public static final short sm2 = 200; + public static short getClientCertificateType(short signatureAlgorithm) { @@ -50,6 +62,10 @@ public static short getClientCertificateType(short signatureAlgorithm) case SignatureAlgorithm.sm2: return ClientCertificateType.ecdsa_sign; + // NOTE: Only valid from TLS 1.3, where ClientCertificateType is not used + case SignatureAlgorithm.ecdsa_brainpoolP256r1tls13_sha256: + case SignatureAlgorithm.ecdsa_brainpoolP384r1tls13_sha384: + case SignatureAlgorithm.ecdsa_brainpoolP512r1tls13_sha512: default: return -1; } @@ -83,6 +99,12 @@ public static String getName(short signatureAlgorithm) return "rsa_pss_pss_sha384"; case rsa_pss_pss_sha512: return "rsa_pss_pss_sha512"; + case ecdsa_brainpoolP256r1tls13_sha256: + return "ecdsa_brainpoolP256r1tls13_sha256"; + case ecdsa_brainpoolP384r1tls13_sha384: + return "ecdsa_brainpoolP384r1tls13_sha384"; + case ecdsa_brainpoolP512r1tls13_sha512: + return "ecdsa_brainpoolP512r1tls13_sha512"; case sm2: return "sm2"; default: @@ -90,29 +112,41 @@ public static String getName(short signatureAlgorithm) } } - public static short getRSAPSSHashAlgorithm(short signatureAlgorithm) + public static short getIntrinsicHashAlgorithm(short signatureAlgorithm) { switch (signatureAlgorithm) { - case rsa_pss_rsae_sha256: + case ecdsa_brainpoolP256r1tls13_sha256: case rsa_pss_pss_sha256: + case rsa_pss_rsae_sha256: return HashAlgorithm.sha256; - case rsa_pss_rsae_sha384: + case ecdsa_brainpoolP384r1tls13_sha384: case rsa_pss_pss_sha384: + case rsa_pss_rsae_sha384: return HashAlgorithm.sha384; - case rsa_pss_rsae_sha512: + case ecdsa_brainpoolP512r1tls13_sha512: case rsa_pss_pss_sha512: + case rsa_pss_rsae_sha512: return HashAlgorithm.sha512; + case ed25519: + case ed448: default: return -1; } } + /** @deprecated Use {@link #getIntrinsicHashAlgorithm(int)} instead. */ + public static short getRSAPSSHashAlgorithm(short signatureAlgorithm) + { + return getIntrinsicHashAlgorithm(signatureAlgorithm); + } + public static String getText(short signatureAlgorithm) { return getName(signatureAlgorithm) + "(" + signatureAlgorithm + ")"; } + /** deprecated Will be removed. */ public static boolean hasIntrinsicHash(short signatureAlgorithm) { switch (signatureAlgorithm) @@ -125,6 +159,9 @@ public static boolean hasIntrinsicHash(short signatureAlgorithm) case rsa_pss_pss_sha256: case rsa_pss_pss_sha384: case rsa_pss_pss_sha512: + case ecdsa_brainpoolP256r1tls13_sha256: + case ecdsa_brainpoolP384r1tls13_sha384: + case ecdsa_brainpoolP512r1tls13_sha512: return true; default: return false; diff --git a/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java b/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java index 7ae48f84a0..8cf08750d0 100644 --- a/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java +++ b/tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java @@ -9,15 +9,27 @@ */ public class SignatureAndHashAlgorithm { - public static final SignatureAndHashAlgorithm ed25519 = new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, SignatureAlgorithm.ed25519); - public static final SignatureAndHashAlgorithm ed448 = new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, SignatureAlgorithm.ed448); - public static final SignatureAndHashAlgorithm rsa_pss_rsae_sha256 = new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, SignatureAlgorithm.rsa_pss_rsae_sha256); - public static final SignatureAndHashAlgorithm rsa_pss_rsae_sha384 = new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, SignatureAlgorithm.rsa_pss_rsae_sha384); - public static final SignatureAndHashAlgorithm rsa_pss_rsae_sha512 = new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, SignatureAlgorithm.rsa_pss_rsae_sha512); - public static final SignatureAndHashAlgorithm rsa_pss_pss_sha256 = new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, SignatureAlgorithm.rsa_pss_pss_sha256); - public static final SignatureAndHashAlgorithm rsa_pss_pss_sha384 = new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, SignatureAlgorithm.rsa_pss_pss_sha384); - public static final SignatureAndHashAlgorithm rsa_pss_pss_sha512 = new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, SignatureAlgorithm.rsa_pss_pss_sha512); - public static final SignatureAndHashAlgorithm sm2 = new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, SignatureAlgorithm.sm2); + public static final SignatureAndHashAlgorithm ed25519 = createInstanceIntrinsic(SignatureAlgorithm.ed25519); + public static final SignatureAndHashAlgorithm ed448 = createInstanceIntrinsic(SignatureAlgorithm.ed448); + public static final SignatureAndHashAlgorithm rsa_pss_rsae_sha256 = createInstanceIntrinsic( + SignatureAlgorithm.rsa_pss_rsae_sha256); + public static final SignatureAndHashAlgorithm rsa_pss_rsae_sha384 = createInstanceIntrinsic( + SignatureAlgorithm.rsa_pss_rsae_sha384); + public static final SignatureAndHashAlgorithm rsa_pss_rsae_sha512 = createInstanceIntrinsic( + SignatureAlgorithm.rsa_pss_rsae_sha512); + public static final SignatureAndHashAlgorithm rsa_pss_pss_sha256 = createInstanceIntrinsic( + SignatureAlgorithm.rsa_pss_pss_sha256); + public static final SignatureAndHashAlgorithm rsa_pss_pss_sha384 = createInstanceIntrinsic( + SignatureAlgorithm.rsa_pss_pss_sha384); + public static final SignatureAndHashAlgorithm rsa_pss_pss_sha512 = createInstanceIntrinsic( + SignatureAlgorithm.rsa_pss_pss_sha512); + public static final SignatureAndHashAlgorithm ecdsa_brainpoolP256r1tls13_sha256 = createInstanceIntrinsic( + SignatureAlgorithm.ecdsa_brainpoolP256r1tls13_sha256); + public static final SignatureAndHashAlgorithm ecdsa_brainpoolP384r1tls13_sha384 = createInstanceIntrinsic( + SignatureAlgorithm.ecdsa_brainpoolP384r1tls13_sha384); + public static final SignatureAndHashAlgorithm ecdsa_brainpoolP512r1tls13_sha512 = createInstanceIntrinsic( + SignatureAlgorithm.ecdsa_brainpoolP512r1tls13_sha512); + public static final SignatureAndHashAlgorithm sm2 = createInstanceIntrinsic(SignatureAlgorithm.sm2); public static SignatureAndHashAlgorithm getInstance(short hashAlgorithm, short signatureAlgorithm) { @@ -34,20 +46,40 @@ public static SignatureAndHashAlgorithm getInstanceIntrinsic(short signatureAlgo { switch (signatureAlgorithm) { - case SignatureAlgorithm.ed25519: return ed25519; - case SignatureAlgorithm.ed448: return ed448; - case SignatureAlgorithm.rsa_pss_rsae_sha256: return rsa_pss_rsae_sha256; - case SignatureAlgorithm.rsa_pss_rsae_sha384: return rsa_pss_rsae_sha384; - case SignatureAlgorithm.rsa_pss_rsae_sha512: return rsa_pss_rsae_sha512; - case SignatureAlgorithm.rsa_pss_pss_sha256: return rsa_pss_pss_sha256; - case SignatureAlgorithm.rsa_pss_pss_sha384: return rsa_pss_pss_sha384; - case SignatureAlgorithm.rsa_pss_pss_sha512: return rsa_pss_pss_sha512; + case SignatureAlgorithm.ed25519: + return ed25519; + case SignatureAlgorithm.ed448: + return ed448; + case SignatureAlgorithm.rsa_pss_rsae_sha256: + return rsa_pss_rsae_sha256; + case SignatureAlgorithm.rsa_pss_rsae_sha384: + return rsa_pss_rsae_sha384; + case SignatureAlgorithm.rsa_pss_rsae_sha512: + return rsa_pss_rsae_sha512; + case SignatureAlgorithm.rsa_pss_pss_sha256: + return rsa_pss_pss_sha256; + case SignatureAlgorithm.rsa_pss_pss_sha384: + return rsa_pss_pss_sha384; + case SignatureAlgorithm.rsa_pss_pss_sha512: + return rsa_pss_pss_sha512; + case SignatureAlgorithm.ecdsa_brainpoolP256r1tls13_sha256: + return ecdsa_brainpoolP256r1tls13_sha256; + case SignatureAlgorithm.ecdsa_brainpoolP384r1tls13_sha384: + return ecdsa_brainpoolP384r1tls13_sha384; + case SignatureAlgorithm.ecdsa_brainpoolP512r1tls13_sha512: + return ecdsa_brainpoolP512r1tls13_sha512; case SignatureAlgorithm.sm2: + return sm2; default: return new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, signatureAlgorithm); } } + private static SignatureAndHashAlgorithm createInstanceIntrinsic(short signatureAlgorithm) + { + return new SignatureAndHashAlgorithm(HashAlgorithm.Intrinsic, signatureAlgorithm); + } + protected final short hash; protected final short signature; @@ -120,7 +152,7 @@ public static SignatureAndHashAlgorithm parse(InputStream input) short hash = TlsUtils.readUint8(input); short signature = TlsUtils.readUint8(input); - return SignatureAndHashAlgorithm.getInstance(hash, signature); + return getInstance(hash, signature); } public boolean equals(Object obj) From b90aab19dc5bd5247652c79c981ac60b9a02907a Mon Sep 17 00:00:00 2001 From: Quan guanyu Date: Wed, 17 Mar 2021 16:46:27 +0800 Subject: [PATCH 17/22] Fix apache HttpClient get session null throw error. and attach apache HttpClient HTTP Client example. --- .../jsse/provider/gm/GMEmptySession.java | 121 ++++++++++++++++++ .../jsse/provider/gm/GMSimpleSSLSocket.java | 3 +- .../test/GMSimpleSSLSocketFactoryTest.java | 32 ++++- 3 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMEmptySession.java diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMEmptySession.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMEmptySession.java new file mode 100644 index 0000000000..a09304ecf0 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMEmptySession.java @@ -0,0 +1,121 @@ +package org.bouncycastle.jsse.provider.gm; + +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionContext; +import javax.security.cert.X509Certificate; +import java.security.Principal; +import java.security.cert.Certificate; + +/** + * Empty session to prevent errors + * + * @author Cliven + * @since 2021-03-17 16:35:18 + */ +public class GMEmptySession implements SSLSession +{ + public byte[] getId() + { + return new byte[0]; + } + + public SSLSessionContext getSessionContext() + { + return null; + } + + public long getCreationTime() + { + return 0; + } + + public long getLastAccessedTime() + { + return 0; + } + + public void invalidate() + { + } + + public boolean isValid() + { + return true; + } + + public void putValue(String s, Object o) + { + + } + + public Object getValue(String s) + { + return null; + } + + public void removeValue(String s) + { + + } + + public String[] getValueNames() + { + return new String[0]; + } + + public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException + { + return new Certificate[0]; + } + + public Certificate[] getLocalCertificates() + { + return new Certificate[0]; + } + + public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException + { + return new X509Certificate[0]; + } + + public Principal getPeerPrincipal() throws SSLPeerUnverifiedException + { + return null; + } + + public Principal getLocalPrincipal() + { + return null; + } + + public String getCipherSuite() + { + return null; + } + + public String getProtocol() + { + return null; + } + + public String getPeerHost() + { + return null; + } + + public int getPeerPort() + { + return 0; + } + + public int getPacketBufferSize() + { + return 0; + } + + public int getApplicationBufferSize() + { + return 0; + } +} diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java index 10051bf164..f158750fdf 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java @@ -146,7 +146,8 @@ public void connect(SocketAddress endpoint) throws IOException @Override public SSLSession getSession() { - return null; + // prevent apache HttpClient get session null throw error + return new GMEmptySession(); } @Override diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSimpleSSLSocketFactoryTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSimpleSSLSocketFactoryTest.java index 8b7577fed4..4e552f352a 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/GMSimpleSSLSocketFactoryTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSimpleSSLSocketFactoryTest.java @@ -30,10 +30,40 @@ public static void main(String[] args) throws IOException, InterruptedException bootServer(port, certList, signKey, encKey); +// bootClient("sm2test.ovssl.cn", 443); -// bootClient("localhost", port); + } + /* + // GMSSL HttpClient Example + import org.apache.http.HttpResponse; + import org.apache.http.client.HttpClient; + import org.apache.http.client.methods.HttpGet; + import org.apache.http.conn.ssl.NoopHostnameVerifier; + import org.apache.http.conn.ssl.SSLConnectionSocketFactory; + import org.apache.http.impl.client.HttpClientBuilder; + import org.bouncycastle.jce.provider.BouncyCastleProvider; + import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; + import org.bouncycastle.jsse.provider.gm.GMSimpleSSLSocketFactory; + + import java.security.Security; + public class GMHttpClient { + public static void main(String[] args) throws Exception { + Security.addProvider(new BouncyCastleProvider()); + Security.addProvider(new BouncyCastleJsseProvider()); + + GMSimpleSSLSocketFactory factory = new GMSimpleSSLSocketFactory(); + + SSLConnectionSocketFactory sf = new SSLConnectionSocketFactory(factory, new NoopHostnameVerifier()); + HttpClient client = HttpClientBuilder.create() + .setSSLSocketFactory(sf) + .build(); + + final HttpResponse response = client.execute(new HttpGet("https://127.0.0.1:5558")); + response.getEntity().writeTo(System.out); + } } + */ private static void bootServer(int port, Certificate certList, AsymmetricKeyParameter signKey, AsymmetricKeyParameter encKey) { From a608f56f8ff1bf283472c3bdd9ac1ed78c655728 Mon Sep 17 00:00:00 2001 From: cliven Date: Sun, 21 Mar 2021 12:49:10 +0800 Subject: [PATCH 18/22] remove author tag --- core/src/main/java/org/bouncycastle/asn1/gm/SM2Cipher.java | 2 +- .../java/org/bouncycastle/jsse/provider/gm/GMEmptySession.java | 2 +- .../org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java | 2 +- .../org/bouncycastle/jsse/provider/gm/GMSimpleSSLServer.java | 2 +- .../org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java | 2 +- .../bouncycastle/jsse/provider/gm/GMSimpleSSLSocketFactory.java | 2 +- .../bouncycastle/jsse/provider/gm/GMSimpleSSLSocketWrap.java | 2 +- tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java | 2 +- .../java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java | 2 +- .../org/bouncycastle/tls/crypto/impl/bc/BcGMSSLCredentials.java | 2 +- .../org/bouncycastle/tls/crypto/impl/bc/BcTlsSM2Verifier.java | 2 +- .../test/java/org/bouncycastle/tls/test/GMSSLClientTest.java | 2 +- .../test/java/org/bouncycastle/tls/test/GMSSLServerTest.java | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/bouncycastle/asn1/gm/SM2Cipher.java b/core/src/main/java/org/bouncycastle/asn1/gm/SM2Cipher.java index 5592a7e049..5a9b149a74 100644 --- a/core/src/main/java/org/bouncycastle/asn1/gm/SM2Cipher.java +++ b/core/src/main/java/org/bouncycastle/asn1/gm/SM2Cipher.java @@ -14,7 +14,7 @@ *

* sm2 encrypted data specific struct * - * @author Cliven + * * @since 2021-03-10 13:28:12 */ public class SM2Cipher extends ASN1Object diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMEmptySession.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMEmptySession.java index a09304ecf0..57dcc75fc3 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMEmptySession.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMEmptySession.java @@ -10,7 +10,7 @@ /** * Empty session to prevent errors * - * @author Cliven + * * @since 2021-03-17 16:35:18 */ public class GMEmptySession implements SSLSession diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java index 2c7b294870..7156b9bfcd 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java @@ -14,7 +14,7 @@ * - make handshake connection * - no authentication * - * @author Cliven + * * @since 2021-03-09 14:01:50 */ public class GMSimpleSSLClient extends AbstractTlsClient diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLServer.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLServer.java index 5ad6f7a061..a6f4782fff 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLServer.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLServer.java @@ -14,7 +14,7 @@ /** * Simple GMSSL Server * - * @author Cliven + * * @since 2021-03-16 09:31:14 */ public class GMSimpleSSLServer diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java index f158750fdf..3ae0a4cc9e 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java @@ -19,7 +19,7 @@ /** * GMSSL Socket simple implement. * - * @author Cliven + * * @since 2021-03-16 13:18:06 */ public class GMSimpleSSLSocket extends SSLSocket diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketFactory.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketFactory.java index 3a32e71cc7..ffd910d3a0 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketFactory.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketFactory.java @@ -16,7 +16,7 @@ /** * Simple GMSSL Socket Factory * - * @author Cliven + * * @since 2021-03-16 13:15:00 */ public class GMSimpleSSLSocketFactory extends SSLSocketFactory diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketWrap.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketWrap.java index 602dbbe440..3c64ae709d 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketWrap.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocketWrap.java @@ -22,7 +22,7 @@ /** * GMSSL Socket simple implement. * - * @author Cliven + * * @since 2021-03-16 13:18:06 */ public class GMSimpleSSLSocketWrap extends GMSimpleSSLSocket diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java b/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java index 1f7744a39a..ba959707c0 100644 --- a/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java +++ b/tls/src/main/java/org/bouncycastle/tls/TlsSM2KeyExchange.java @@ -13,7 +13,7 @@ /** * GMSSL SM2 exchange. * - * @author Cliven + * */ public class TlsSM2KeyExchange extends AbstractTlsKeyExchange { diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java index 9719a7b5f1..03a37bc29f 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java @@ -16,7 +16,7 @@ /** * GMSSL basic chinese GMT 0009-2012 * - * @author Cliven + * * @since 2021-03-10 13:56:20 */ public class BcGmsslEncryptor implements TlsEncryptor diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcGMSSLCredentials.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcGMSSLCredentials.java index 1f07fc7044..ecdad56586 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcGMSSLCredentials.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcGMSSLCredentials.java @@ -19,7 +19,7 @@ * one for sign, one for encrypt * so we need provider Signer and Decryptor both * - * @author Cliven + * * @since 2021-03-12 12:10:31 */ public class BcGMSSLCredentials implements TlsCredentialedSigner, TlsCredentialedDecryptor diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSM2Verifier.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSM2Verifier.java index 51b1e8d1c5..2de5291c13 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSM2Verifier.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsSM2Verifier.java @@ -10,7 +10,7 @@ * * force use SM2WithSM3 signature verify data. * - * @author Cliven + * */ public class BcTlsSM2Verifier extends BcTlsVerifier { diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java index 10f0dfba17..83fab2d324 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java @@ -17,7 +17,7 @@ /** * Test GMSSL's client connection status * - * @author cliven + * * @since 2021-03-05 11:31:29 */ public class GMSSLClientTest diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java index 983b133d2b..c42b2b5821 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java @@ -13,7 +13,7 @@ /** * A simple test designed to conduct a GMSSL handshake with an external GMSSL client. * - * @author Cliven + * * @since 2021-03-16 09:57:58 */ public class GMSSLServerTest From 2c7bdad6cbf23acb639766562922a4e8025cd4ef Mon Sep 17 00:00:00 2001 From: Quan guanyu Date: Wed, 20 Oct 2021 11:49:00 +0800 Subject: [PATCH 19/22] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BA=86Alert=2040=20?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jsse/provider/gm/GMSimpleSSLClient.java | 56 +++--- .../tls/crypto/impl/BcGmsslEncryptor.java | 7 +- .../crypto/impl/bc/BcGMSSLCredentials.java | 4 +- .../tls/crypto/impl/bc/SM2Cipher.java | 180 ++++++++++++++++++ 4 files changed, 209 insertions(+), 38 deletions(-) create mode 100644 tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/SM2Cipher.java diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java index 7156b9bfcd..a762ddb220 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java @@ -10,56 +10,46 @@ /** * Simple GMSSL client - * + *

* - make handshake connection * - no authentication * - * * @since 2021-03-09 14:01:50 */ -public class GMSimpleSSLClient extends AbstractTlsClient -{ +public class GMSimpleSSLClient extends AbstractTlsClient { private static final int[] DEFAULT_CIPHER_SUITES = new int[] - { - /* - * GMSSL 1.1 - */ - CipherSuite.GMSSL_ECC_SM4_SM3, - }; + { + /* + * GMSSL 1.1 + */ + CipherSuite.GMSSL_ECC_SM4_SM3, + }; - public GMSimpleSSLClient() - { + public GMSimpleSSLClient() { this(new BcTlsCrypto(new SecureRandom())); } - public GMSimpleSSLClient(TlsCrypto crypto) - { + public GMSimpleSSLClient(TlsCrypto crypto) { super(crypto); } @Override - protected ProtocolVersion[] getSupportedVersions() - { + protected ProtocolVersion[] getSupportedVersions() { return new ProtocolVersion[]{ProtocolVersion.GMSSLv11}; } - protected int[] getSupportedCipherSuites() - { + protected int[] getSupportedCipherSuites() { return TlsUtils.getSupportedCipherSuites(getCrypto(), DEFAULT_CIPHER_SUITES); } - public TlsAuthentication getAuthentication() throws IOException - { - return new TlsAuthentication() - { + public TlsAuthentication getAuthentication() throws IOException { + return new TlsAuthentication() { - public void notifyServerCertificate(TlsServerCertificate serverCertificate) throws IOException - { + public void notifyServerCertificate(TlsServerCertificate serverCertificate) throws IOException { // System.out.println(">> TlsAuthentication on notifyServerCertificate"); } - public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException - { + public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException { // System.out.println(">> TlsAuthentication on getClientCredentials"); return null; } @@ -73,8 +63,7 @@ public TlsCredentials getClientCredentials(CertificateRequest certificateRequest * @throws IOException not happen */ @Override - public Hashtable getClientExtensions() throws IOException - { + public Hashtable getClientExtensions() throws IOException { return new Hashtable(0); } @@ -82,15 +71,18 @@ public Hashtable getClientExtensions() throws IOException * GMSSL Client generate random struct should be * struct * { - * unit32 gmt_unix_time; - * opaque random_bytes[28]; + * unit32 gmt_unix_time; + * opaque random_bytes[28]; * } * * @return true - use GMTUnixTime */ @Override - public boolean shouldUseGMTUnixTime() - { + public boolean shouldUseGMTUnixTime() { return true; } + + @Override + public void notifySecureRenegotiation(boolean secureRenegotiation) throws IOException { + } } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java index 03a37bc29f..dffa954dd3 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/BcGmsslEncryptor.java @@ -1,14 +1,12 @@ package org.bouncycastle.tls.crypto.impl; -import org.bouncycastle.asn1.ASN1Integer; -import org.bouncycastle.asn1.DEROctetString; -import org.bouncycastle.asn1.gm.SM2Cipher; import org.bouncycastle.crypto.InvalidCipherTextException; import org.bouncycastle.crypto.engines.SM2Engine; import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.crypto.params.ParametersWithRandom; import org.bouncycastle.tls.AlertDescription; import org.bouncycastle.tls.TlsFatalAlert; +import org.bouncycastle.tls.crypto.impl.bc.SM2Cipher; import java.io.IOException; import java.security.SecureRandom; @@ -39,7 +37,8 @@ public byte[] encrypt(byte[] input, int inOff, int length) throws IOException engine.init(true, keyParameters); byte[] c1c3c2 = engine.processBlock(input, inOff, length); return SM2Cipher.fromC1C3C2(c1c3c2).getEncoded(); - } catch (InvalidCipherTextException e) + } + catch (InvalidCipherTextException e) { throw new TlsFatalAlert(AlertDescription.internal_error); } diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcGMSSLCredentials.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcGMSSLCredentials.java index ecdad56586..f004ac9de0 100644 --- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcGMSSLCredentials.java +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcGMSSLCredentials.java @@ -1,6 +1,5 @@ package org.bouncycastle.tls.crypto.impl.bc; -import org.bouncycastle.asn1.gm.SM2Cipher; import org.bouncycastle.crypto.CryptoException; import org.bouncycastle.crypto.engines.SM2Engine; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; @@ -88,7 +87,8 @@ public byte[] generateRawSignature(byte[] hash) throws IOException sm2Signer.init(true, prvKey); sm2Signer.update(hash, 0, hash.length); return sm2Signer.generateSignature(); - } catch (CryptoException e) + } + catch (CryptoException e) { e.printStackTrace(); throw new TlsFatalAlertReceived(AlertDescription.illegal_parameter); diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/SM2Cipher.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/SM2Cipher.java new file mode 100644 index 0000000000..074d2cf0ba --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/SM2Cipher.java @@ -0,0 +1,180 @@ +package org.bouncycastle.tls.crypto.impl.bc; + +import org.bouncycastle.asn1.*; +import org.bouncycastle.util.BigIntegers; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.util.Enumeration; + +/** + * GMT 0009-2012 + *

+ * sm2 encrypted data specific struct + * + * + * @since 2021-03-10 13:28:12 + */ +public class SM2Cipher extends ASN1Object +{ + /* + * SM2Cipher ::== SEQUENCE{ + * XCoordinate INTEGER, --X Portion + * YCoordinate INTEGER, --Y Portion + * HASH OCTET STRING SIZE(32), --Plaintext sm3 hash + * CipherText OCTET STRING --CipherText + * } + */ + + private ASN1Integer xCoordinate; + private ASN1Integer yCoordinate; + private ASN1OctetString hash; + private ASN1OctetString cipherText; + + public SM2Cipher() + { + super(); + } + + public SM2Cipher(ASN1Sequence seq) + { + Enumeration e = seq.getObjects(); + xCoordinate = ASN1Integer.getInstance(e.nextElement()); + yCoordinate = ASN1Integer.getInstance(e.nextElement()); + hash = ASN1OctetString.getInstance(e.nextElement()); + cipherText = ASN1OctetString.getInstance(e.nextElement()); + } + + public static SM2Cipher getInstance(Object o) + { + if(o instanceof SM2Cipher) + { + return (SM2Cipher) o; + } + else if(o != null) + { + return new SM2Cipher(ASN1Sequence.getInstance(o)); + } + return null; + } + + public ASN1Integer getxCoordinate() + { + return xCoordinate; + } + + public void setxCoordinate(ASN1Integer xCoordinate) + { + this.xCoordinate = xCoordinate; + } + + public ASN1Integer getyCoordinate() + { + return yCoordinate; + } + + public void setyCoordinate(ASN1Integer yCoordinate) + { + this.yCoordinate = yCoordinate; + } + + public ASN1OctetString getHash() + { + return hash; + } + + public void setHash(ASN1OctetString hash) + { + this.hash = hash; + } + + public ASN1OctetString getCipherText() + { + return cipherText; + } + + public void setCipherText(ASN1OctetString cipherText) + { + this.cipherText = cipherText; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(4); + v.add(xCoordinate); + v.add(yCoordinate); + v.add(hash); + v.add(cipherText); + return new DERSequence(v); + } + + /** + * Convert ASN.1 Struct to C1C3C2 format + * + * @return C1C3C2 + * @throws IOException + */ + public byte[] convertC1C3C2() throws IOException + { + /* + * construct GMT0009-2012 encrypted data struct + */ + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + + final byte[] x = new byte[32]; + final byte[] y = new byte[32]; + + byte[] tmp = BigIntegers.asUnsignedByteArray(getxCoordinate().getValue()); + System.arraycopy(tmp, 0, x, 32 - tmp.length, tmp.length); + tmp = BigIntegers.asUnsignedByteArray(getyCoordinate().getValue()); + System.arraycopy(tmp, 0, y, 32 - tmp.length, tmp.length); + + // C1 + // read 1 byte for uncompressed point prefix 0x04 + stream.write(0x04); + stream.write(x); + stream.write(y); + // C3 + stream.write(getHash().getOctets()); + // C2 + stream.write(getCipherText().getOctets()); + stream.flush(); + return stream.toByteArray(); + } + + /** + * Convert SM2 encrypted result format of c1c3c2 to ASN.1 SM2Cipher + * + * @param c1c3c2 encrypted result + * @return SM2Cipher + * @throws IOException + */ + static public SM2Cipher fromC1C3C2(byte[] c1c3c2) throws IOException + { + /* + * construct GMT0009-2012 encrypted data struct + */ + ByteArrayInputStream stream = new ByteArrayInputStream(c1c3c2); + // read 1 byte for uncompressed point prefix 0x04 + stream.read(); + final byte[] x = new byte[32]; + final byte[] y = new byte[32]; + final byte[] hash = new byte[32]; + int length = c1c3c2.length - 1 - 32 - 32 - 32; + final byte[] cipherText = new byte[length]; + stream.read(x); + stream.read(y); + stream.read(hash); + stream.read(cipherText); + + final SM2Cipher sm2Cipher = new SM2Cipher(); + sm2Cipher.setxCoordinate(new ASN1Integer(new BigInteger(1, x))); + sm2Cipher.setyCoordinate(new ASN1Integer(new BigInteger(1, y))); + sm2Cipher.setHash(new DEROctetString(hash)); + sm2Cipher.setCipherText(new DEROctetString(cipherText)); + return sm2Cipher; + } +} From 621e688c3452e33cf37b4daff74d53052961f1d6 Mon Sep 17 00:00:00 2001 From: Quan guanyu Date: Wed, 20 Oct 2021 11:51:37 +0800 Subject: [PATCH 20/22] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jsse/provider/gm/GMSimpleSSLClient.java | 36 ++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java index a762ddb220..b4e4946b42 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java @@ -16,7 +16,8 @@ * * @since 2021-03-09 14:01:50 */ -public class GMSimpleSSLClient extends AbstractTlsClient { +public class GMSimpleSSLClient extends AbstractTlsClient +{ private static final int[] DEFAULT_CIPHER_SUITES = new int[] { /* @@ -25,31 +26,39 @@ public class GMSimpleSSLClient extends AbstractTlsClient { CipherSuite.GMSSL_ECC_SM4_SM3, }; - public GMSimpleSSLClient() { + public GMSimpleSSLClient() + { this(new BcTlsCrypto(new SecureRandom())); } - public GMSimpleSSLClient(TlsCrypto crypto) { + public GMSimpleSSLClient(TlsCrypto crypto) + { super(crypto); } @Override - protected ProtocolVersion[] getSupportedVersions() { + protected ProtocolVersion[] getSupportedVersions() + { return new ProtocolVersion[]{ProtocolVersion.GMSSLv11}; } - protected int[] getSupportedCipherSuites() { + protected int[] getSupportedCipherSuites() + { return TlsUtils.getSupportedCipherSuites(getCrypto(), DEFAULT_CIPHER_SUITES); } - public TlsAuthentication getAuthentication() throws IOException { - return new TlsAuthentication() { + public TlsAuthentication getAuthentication() throws IOException + { + return new TlsAuthentication() + { - public void notifyServerCertificate(TlsServerCertificate serverCertificate) throws IOException { + public void notifyServerCertificate(TlsServerCertificate serverCertificate) throws IOException + { // System.out.println(">> TlsAuthentication on notifyServerCertificate"); } - public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException { + public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException + { // System.out.println(">> TlsAuthentication on getClientCredentials"); return null; } @@ -63,7 +72,8 @@ public TlsCredentials getClientCredentials(CertificateRequest certificateRequest * @throws IOException not happen */ @Override - public Hashtable getClientExtensions() throws IOException { + public Hashtable getClientExtensions() throws IOException + { return new Hashtable(0); } @@ -78,11 +88,13 @@ public Hashtable getClientExtensions() throws IOException { * @return true - use GMTUnixTime */ @Override - public boolean shouldUseGMTUnixTime() { + public boolean shouldUseGMTUnixTime() + { return true; } @Override - public void notifySecureRenegotiation(boolean secureRenegotiation) throws IOException { + public void notifySecureRenegotiation(boolean secureRenegotiation) throws IOException + { } } From abfb0393325973251596bedfe6adb7e566b4a0e1 Mon Sep 17 00:00:00 2001 From: cliven Date: Sat, 23 Oct 2021 22:00:17 +0800 Subject: [PATCH 21/22] Completed the GMSSL session. --- .../jsse/provider/gm/GMEmptySession.java | 121 -------- .../jsse/provider/gm/GMSession.java | 289 ++++++++++++++++++ .../jsse/provider/gm/GMSimpleSSLClient.java | 5 +- .../jsse/provider/gm/GMSimpleSSLSocket.java | 25 +- .../gm/GmSimpleTlsClientProtocol.java | 25 ++ .../gm/GmSimpleTlsServerProtocol.java | 25 ++ .../gm/SecurityParameterProvider.java | 9 + .../tls/test/GMSSLClientTest.java | 51 +++- 8 files changed, 417 insertions(+), 133 deletions(-) delete mode 100644 tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMEmptySession.java create mode 100644 tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSession.java create mode 100644 tls/src/main/java/org/bouncycastle/jsse/provider/gm/GmSimpleTlsClientProtocol.java create mode 100644 tls/src/main/java/org/bouncycastle/jsse/provider/gm/GmSimpleTlsServerProtocol.java create mode 100644 tls/src/main/java/org/bouncycastle/jsse/provider/gm/SecurityParameterProvider.java diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMEmptySession.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMEmptySession.java deleted file mode 100644 index 57dcc75fc3..0000000000 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMEmptySession.java +++ /dev/null @@ -1,121 +0,0 @@ -package org.bouncycastle.jsse.provider.gm; - -import javax.net.ssl.SSLPeerUnverifiedException; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSessionContext; -import javax.security.cert.X509Certificate; -import java.security.Principal; -import java.security.cert.Certificate; - -/** - * Empty session to prevent errors - * - * - * @since 2021-03-17 16:35:18 - */ -public class GMEmptySession implements SSLSession -{ - public byte[] getId() - { - return new byte[0]; - } - - public SSLSessionContext getSessionContext() - { - return null; - } - - public long getCreationTime() - { - return 0; - } - - public long getLastAccessedTime() - { - return 0; - } - - public void invalidate() - { - } - - public boolean isValid() - { - return true; - } - - public void putValue(String s, Object o) - { - - } - - public Object getValue(String s) - { - return null; - } - - public void removeValue(String s) - { - - } - - public String[] getValueNames() - { - return new String[0]; - } - - public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException - { - return new Certificate[0]; - } - - public Certificate[] getLocalCertificates() - { - return new Certificate[0]; - } - - public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException - { - return new X509Certificate[0]; - } - - public Principal getPeerPrincipal() throws SSLPeerUnverifiedException - { - return null; - } - - public Principal getLocalPrincipal() - { - return null; - } - - public String getCipherSuite() - { - return null; - } - - public String getProtocol() - { - return null; - } - - public String getPeerHost() - { - return null; - } - - public int getPeerPort() - { - return 0; - } - - public int getPacketBufferSize() - { - return 0; - } - - public int getApplicationBufferSize() - { - return 0; - } -} diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSession.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSession.java new file mode 100644 index 0000000000..03d291cd08 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSession.java @@ -0,0 +1,289 @@ +package org.bouncycastle.jsse.provider.gm; + +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.tls.crypto.TlsCertificate; + +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionContext; +import javax.security.cert.CertificateException; +import javax.security.cert.X509Certificate; +import java.io.IOException; +import java.net.SocketException; +import java.security.Principal; +import java.security.cert.Certificate; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +/** + * Empty session to prevent errors + * + * @since 2021-03-17 16:35:18 + */ +public class GMSession implements SSLSession +{ + private boolean valid = true; + + private long created; + private long updated; + + private Map contextValue; + + private GMSimpleSSLSocket gmScoket; + + private SecurityParameterProvider secParamProvider; + + public GMSession(GMSimpleSSLSocket scoket) + { + gmScoket = scoket; + contextValue = new HashMap(); + renew(null); + } + + public void renew(SecurityParameterProvider secParamProvider) + { + final long now = System.currentTimeMillis(); + if (created == 0) { + created = now; + } + updated = now; + this.secParamProvider = secParamProvider; + } + + public byte[] getId() + { + if (secParamProvider == null) + { + return new byte[0]; + } + return secParamProvider.getSecurityParameters().getSessionID(); + } + + public SSLSessionContext getSessionContext() + { + return null; + } + + public long getCreationTime() + { + return this.created; + } + + public long getLastAccessedTime() + { + return this.updated; + } + + public void invalidate() + { + valid = false; + } + + public boolean isValid() + { + return valid; + } + + public void putValue(String s, Object o) + { + this.contextValue.put(s, o); + } + + public Object getValue(String s) + { + return this.contextValue.get(s); + } + + public void removeValue(String s) + { + this.contextValue.remove(s); + } + + public String[] getValueNames() + { + final Set keySet = this.contextValue.keySet(); + final int len = keySet.size(); + String[] res = new String[len]; + int i = 0; + for (String s : keySet) + { + res[i] = s; + i++; + } + return res; + } + + public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException + { + if (secParamProvider == null) + { + return new Certificate[0]; + } + final org.bouncycastle.tls.Certificate peerCertificate = + secParamProvider.getSecurityParameters().getPeerCertificate(); + final TlsCertificate[] list = peerCertificate.getCertificateList(); + final JcaX509CertificateConverter converter = new JcaX509CertificateConverter() + .setProvider(new BouncyCastleProvider()); + Certificate[] res = new Certificate[list.length]; + for (int i = 0; i < list.length; i++) + { + try + { + final byte[] encoded = list[i].getEncoded(); + res[i] = converter.getCertificate(new X509CertificateHolder(encoded)); + } + catch (java.security.cert.CertificateException e) + { + throw new SSLPeerUnverifiedException("peer cert encoded error: " + e.getMessage()); + } + catch (IOException e) + { + throw new SSLPeerUnverifiedException("peer cert encoded error: " + e.getMessage()); + } + } + return res; + } + + public Certificate[] getLocalCertificates() + { + if (secParamProvider == null) + { + return new Certificate[0]; + } + final org.bouncycastle.tls.Certificate localCertificate = + secParamProvider.getSecurityParameters().getLocalCertificate(); + final TlsCertificate[] list = localCertificate.getCertificateList(); + final JcaX509CertificateConverter converter = new JcaX509CertificateConverter() + .setProvider(new BouncyCastleProvider()); + Certificate[] res = new Certificate[list.length]; + for (int i = 0; i < list.length; i++) + { + try + { + final byte[] encoded = list[i].getEncoded(); + res[i] = converter.getCertificate(new X509CertificateHolder(encoded)); + } + catch (java.security.cert.CertificateException e) + { + throw new RuntimeException("local cert encoded error: " + e.getMessage()); + } + catch (IOException e) + { + throw new RuntimeException("local cert encoded error: " + e.getMessage()); + } + } + return res; + } + + public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException + { + if (secParamProvider == null) + { + return new X509Certificate[0]; + } + + org.bouncycastle.tls.Certificate peerCert = + secParamProvider.getSecurityParameters().getPeerCertificate(); + + final TlsCertificate[] list = peerCert.getCertificateList(); + X509Certificate[] res = new X509Certificate[list.length]; + for (int i = 0; i < list.length; i++) { + try + { + final byte[] encoded = list[i].getEncoded(); + res[i] = X509Certificate.getInstance(encoded); + } + catch (IOException e) + { + throw new SSLPeerUnverifiedException("peer cert encoded error: " + e.getMessage()); + } + catch (CertificateException e) + { + throw new SSLPeerUnverifiedException("peer cert encoded error: " + e.getMessage()); + } + + } + return res; + } + + public Principal getPeerPrincipal() throws SSLPeerUnverifiedException + { + final X509Certificate[] peerCertificateChain = this.getPeerCertificateChain(); + if (peerCertificateChain == null || peerCertificateChain.length == 0) + { + return null; + } + return peerCertificateChain[0].getSubjectDN(); + } + + public Principal getLocalPrincipal() + { + org.bouncycastle.tls.Certificate cert = + secParamProvider.getSecurityParameters().getLocalCertificate(); + + final TlsCertificate[] list = cert.getCertificateList(); + if (list.length == 0){ + return null; + } + final byte[] encoded; + try { + encoded = list[0].getEncoded(); + return X509Certificate.getInstance(encoded).getSubjectDN(); + } + catch (IOException e) + { + throw new RuntimeException(e); + } + catch (CertificateException e) + { + throw new RuntimeException(e); + } + } + + public String getCipherSuite() + { + return "GMSSL_SM2_SM4_SM3"; + } + + public String getProtocol() + { + return "GMSSLv1.1"; + } + + public String getPeerHost() + { + return gmScoket.getRemoteSocketAddress().toString(); + } + + public int getPeerPort() + { + return gmScoket.getPort(); + } + + public int getPacketBufferSize() + { + try + { + return gmScoket.getSendBufferSize(); + } + catch (SocketException e) + { + return 0; + } + } + + public int getApplicationBufferSize() + { + try + { + return gmScoket.getSendBufferSize(); + } + catch (SocketException e) + { + return 0; + } + } +} diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java index b4e4946b42..59e7202257 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java @@ -18,6 +18,8 @@ */ public class GMSimpleSSLClient extends AbstractTlsClient { + + private static final int[] DEFAULT_CIPHER_SUITES = new int[] { /* @@ -54,7 +56,8 @@ public TlsAuthentication getAuthentication() throws IOException public void notifyServerCertificate(TlsServerCertificate serverCertificate) throws IOException { -// System.out.println(">> TlsAuthentication on notifyServerCertificate"); + System.out.println(">> TlsAuthentication on notifyServerCertificate"); + System.out.println(serverCertificate.getCertificate()); } public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java index 3ae0a4cc9e..cd2bac2d63 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLSocket.java @@ -1,10 +1,7 @@ package org.bouncycastle.jsse.provider.gm; import org.bouncycastle.crypto.params.AsymmetricKeyParameter; -import org.bouncycastle.tls.Certificate; -import org.bouncycastle.tls.TlsClientProtocol; -import org.bouncycastle.tls.TlsProtocol; -import org.bouncycastle.tls.TlsServerProtocol; +import org.bouncycastle.tls.*; import org.bouncycastle.tls.crypto.TlsCrypto; import javax.net.ssl.HandshakeCompletedListener; @@ -33,12 +30,14 @@ public class GMSimpleSSLSocket extends SSLSocket }; protected boolean useClientMode = true; - protected TlsProtocol protocol; + private TlsProtocol protocol; protected TlsCrypto crypto; protected Certificate certList; protected AsymmetricKeyParameter signKey, encKey; + private GMSession session; + protected GMSimpleSSLSocket() { @@ -147,7 +146,7 @@ public void connect(SocketAddress endpoint) throws IOException public SSLSession getSession() { // prevent apache HttpClient get session null throw error - return new GMEmptySession(); + return session; } @Override @@ -173,20 +172,28 @@ public void startHandshake() throws IOException protected void makeHandshake(InputStream input, OutputStream output) throws IOException { + if(session == null) + { + session = new GMSession(this); + } if(this.useClientMode) { - TlsClientProtocol clientProtocol = new TlsClientProtocol(input, output); + GmSimpleTlsClientProtocol clientProtocol = new GmSimpleTlsClientProtocol(input, output); this.protocol = clientProtocol; + session.renew(clientProtocol); GMSimpleSSLClient client = new GMSimpleSSLClient(crypto); + clientProtocol.connect(client); } else { GMSimpleSSLServer server = new GMSimpleSSLServer(crypto, certList, signKey, encKey); - TlsServerProtocol serverProtocol = new TlsServerProtocol(input, output); + GmSimpleTlsServerProtocol serverProtocol = new GmSimpleTlsServerProtocol(input, output); + session.renew(serverProtocol); this.protocol = serverProtocol; serverProtocol.accept(server); } + } synchronized void handshakeIfNecessary() throws IOException @@ -269,6 +276,8 @@ public synchronized void close() throws IOException } } + + @Override protected void finalize() throws Throwable { diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GmSimpleTlsClientProtocol.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GmSimpleTlsClientProtocol.java new file mode 100644 index 0000000000..b17ba2bf5b --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GmSimpleTlsClientProtocol.java @@ -0,0 +1,25 @@ +package org.bouncycastle.jsse.provider.gm; + + +import org.bouncycastle.tls.SecurityParameters; +import org.bouncycastle.tls.TlsClientProtocol; + +import java.io.InputStream; +import java.io.OutputStream; + +public class GmSimpleTlsClientProtocol extends TlsClientProtocol implements SecurityParameterProvider +{ + public GmSimpleTlsClientProtocol() + { + } + + public GmSimpleTlsClientProtocol(InputStream input, OutputStream output) + { + super(input, output); + } + + public SecurityParameters getSecurityParameters() + { + return super.getContext().getSecurityParameters(); + } +} diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GmSimpleTlsServerProtocol.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GmSimpleTlsServerProtocol.java new file mode 100644 index 0000000000..fc072669d9 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GmSimpleTlsServerProtocol.java @@ -0,0 +1,25 @@ +package org.bouncycastle.jsse.provider.gm; + + +import org.bouncycastle.tls.SecurityParameters; +import org.bouncycastle.tls.TlsServerProtocol; + +import java.io.InputStream; +import java.io.OutputStream; + +public class GmSimpleTlsServerProtocol extends TlsServerProtocol implements SecurityParameterProvider +{ + public GmSimpleTlsServerProtocol() + { + } + + public GmSimpleTlsServerProtocol(InputStream input, OutputStream output) + { + super(input, output); + } + + public SecurityParameters getSecurityParameters() + { + return super.getContext().getSecurityParameters(); + } +} diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/SecurityParameterProvider.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/SecurityParameterProvider.java new file mode 100644 index 0000000000..31cb351e16 --- /dev/null +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/SecurityParameterProvider.java @@ -0,0 +1,9 @@ +package org.bouncycastle.jsse.provider.gm; + +import org.bouncycastle.tls.SecurityParameters; + + +public interface SecurityParameterProvider { + + SecurityParameters getSecurityParameters(); +} diff --git a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java index 83fab2d324..f8cab2696b 100644 --- a/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java +++ b/tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java @@ -3,6 +3,7 @@ import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jsse.provider.BouncyCastleJsseProvider; import org.bouncycastle.jsse.provider.gm.GMSimpleSSLClient; +import org.bouncycastle.jsse.provider.gm.GMSimpleSSLSocketFactory; import org.bouncycastle.tls.TlsClientProtocol; import org.bouncycastle.util.io.Streams; @@ -12,6 +13,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; +import java.net.URL; import java.security.*; /** @@ -31,10 +33,18 @@ public static void main(String[] args) // String host = "localhost"; // int port = 5557; - String host = "sm2test.ovssl.cn"; - int port = 443; +// String host = "sm2test.ovssl.cn"; +// int port = 443; // bc(host, port); - jsse(host, port); +// jsse(host, port); + HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() + { + public boolean verify(String s, SSLSession sslSession) + { + return true; + } + }); + httpGet("https://sm2test.ovssl.cn/"); } private static void bc(String host, int port) throws IOException @@ -78,4 +88,39 @@ private static void jsse(String host, int port) throws IOException, NoSuchProvid out.close(); in.close(); } + + + private static void httpGet(String urlStr) + { + + HttpsURLConnection connection = null; + + try + { + URL url = new URL(urlStr); + connection = (HttpsURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.setSSLSocketFactory(new GMSimpleSSLSocketFactory()); + final InputStream input = connection.getInputStream(); + byte[] buff = new byte[4096]; + + int n; + while((n=input.read(buff)) != -1) + { + System.out.write(buff, 0, n); + } + input.close(); + } + catch (Exception e) + { + e.printStackTrace(); + } + finally + { + if (connection != null) + { + connection.disconnect(); + } + } + } } From fb72a85cf8eb432f9abe044207f1e29f83996ae2 Mon Sep 17 00:00:00 2001 From: cliven Date: Sat, 23 Oct 2021 22:28:39 +0800 Subject: [PATCH 22/22] remove debug info and change certificate parer method. --- .../jsse/provider/gm/GMSession.java | 25 +++++++++++++------ .../jsse/provider/gm/GMSimpleSSLClient.java | 4 +-- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSession.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSession.java index 03d291cd08..86cd5923be 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSession.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSession.java @@ -1,7 +1,5 @@ package org.bouncycastle.jsse.provider.gm; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.tls.crypto.TlsCertificate; @@ -10,10 +8,12 @@ import javax.net.ssl.SSLSessionContext; import javax.security.cert.CertificateException; import javax.security.cert.X509Certificate; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.SocketException; import java.security.Principal; import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -36,11 +36,22 @@ public class GMSession implements SSLSession private SecurityParameterProvider secParamProvider; + private CertificateFactory cf; + public GMSession(GMSimpleSSLSocket scoket) { gmScoket = scoket; contextValue = new HashMap(); renew(null); + + try + { + cf = CertificateFactory.getInstance("X.509", new BouncyCastleProvider()); + } + catch (java.security.cert.CertificateException e) + { + throw new RuntimeException(e); + } } public void renew(SecurityParameterProvider secParamProvider) @@ -125,15 +136,13 @@ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException final org.bouncycastle.tls.Certificate peerCertificate = secParamProvider.getSecurityParameters().getPeerCertificate(); final TlsCertificate[] list = peerCertificate.getCertificateList(); - final JcaX509CertificateConverter converter = new JcaX509CertificateConverter() - .setProvider(new BouncyCastleProvider()); Certificate[] res = new Certificate[list.length]; for (int i = 0; i < list.length; i++) { try { final byte[] encoded = list[i].getEncoded(); - res[i] = converter.getCertificate(new X509CertificateHolder(encoded)); + res[i] = cf.generateCertificate(new ByteArrayInputStream(encoded)); } catch (java.security.cert.CertificateException e) { @@ -153,18 +162,18 @@ public Certificate[] getLocalCertificates() { return new Certificate[0]; } + final org.bouncycastle.tls.Certificate localCertificate = secParamProvider.getSecurityParameters().getLocalCertificate(); final TlsCertificate[] list = localCertificate.getCertificateList(); - final JcaX509CertificateConverter converter = new JcaX509CertificateConverter() - .setProvider(new BouncyCastleProvider()); Certificate[] res = new Certificate[list.length]; for (int i = 0; i < list.length; i++) { try { + final byte[] encoded = list[i].getEncoded(); - res[i] = converter.getCertificate(new X509CertificateHolder(encoded)); + res[i] = cf.generateCertificate(new ByteArrayInputStream(encoded)); } catch (java.security.cert.CertificateException e) { diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java index 59e7202257..21c552d3cc 100644 --- a/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java +++ b/tls/src/main/java/org/bouncycastle/jsse/provider/gm/GMSimpleSSLClient.java @@ -56,8 +56,8 @@ public TlsAuthentication getAuthentication() throws IOException public void notifyServerCertificate(TlsServerCertificate serverCertificate) throws IOException { - System.out.println(">> TlsAuthentication on notifyServerCertificate"); - System.out.println(serverCertificate.getCertificate()); +// System.out.println(">> TlsAuthentication on notifyServerCertificate"); +// System.out.println(serverCertificate.getCertificate()); } public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException