Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add GMSSL support #908

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open

Add GMSSL support #908

wants to merge 25 commits into from

Conversation

Trisia
Copy link
Contributor

@Trisia Trisia commented Mar 16, 2021

GMSSL follow the specification《GMT 0024-2014 SSL VPN技术规范》

GMSSL a variant of TLS1.1(RFC4346)

Use independent protocol version number 0x0101
Cipher suite using GM algorithm SM2_SM4_SM3

  • SM2 for auth
  • SM4 for encrypt
  • SM3 for hmac

certficate message contain two cert, first for sign second for encypt.

more difference see https://blog.csdn.net/q1009020096/article/details/114321986?spm=1001.2014.3001.5501

For testing and use, see:

  • tls/src/test/java/org/bouncycastle/tls/test/GMSimpleSSLSocketFactoryTest.java
  • tls/src/test/java/org/bouncycastle/tls/test/GMSSLClientTest.java
  • tls/src/test/java/org/bouncycastle/tls/test/GMSSLServerTest.java

more:

reference:

[1]. IETF. RFC4346 . 2006
[2]. 密码行业标准化技术委员会 . GMT 0024-2014 SSL VPN技术规范 . 2014

Trisia and others added 20 commits March 5, 2021 13:42
addAlgorithmImplementation to provide
The client can successfully establish a GMSSL connection
Simplified the convertion of SM2 between ASN1 and C1C3C2 formats.

add test needed certificates and keys
…n refuse connection.

finish server side gmssl debug, gm browser access test.
…master

# Conflicts:
#	tls/src/main/java/org/bouncycastle/tls/SignatureAlgorithm.java
#	tls/src/main/java/org/bouncycastle/tls/SignatureAndHashAlgorithm.java
and attach apache HttpClient HTTP Client example.
@Trisia
Copy link
Contributor Author

Trisia commented Mar 17, 2021

Apache HTTPClient GMSSL 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;

/**
 * GMSSL Http Client test
 *
 * @author Cliven
 * @since 2021-02-05 13:25:06
 */
public class GMHttpClient {

    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        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:5557"));
        response.getEntity().writeTo(System.out);
    }
}

@dghgit
Copy link
Contributor

dghgit commented Mar 21, 2021

Just one thing, we do not allow author tags (which I'll admit can be annoying as most IDEs now insist on inserting one when you create a file, here we take the attitude that if anything's broken, it's all our problem). I think we can accept this otherwise. I just wanted to check that was understood.

@Trisia
Copy link
Contributor Author

Trisia commented Mar 21, 2021

Just one thing, we do not allow author tags (which I'll admit can be annoying as most IDEs now insist on inserting one when you create a file, here we take the attitude that if anything's broken, it's all our problem). I think we can accept this otherwise. I just wanted to check that was understood.

I have removed all @author tags. Is there anything else I need to adjust?

@dghgit
Copy link
Contributor

dghgit commented Mar 21, 2021

Thanks. Just one other thing, is this meant to be compliant with RFC 8998? I just noticed there was a comment concerning TLS 1.1. at the top.

Okay, I've done a bit more reading. This is different from RFC 8998 isn't it? In some ways it's not really TLS is it, it's more a TLS like protocol. Would that be correct?

@Trisia
Copy link
Contributor Author

Trisia commented Mar 21, 2021

Thanks. Just one other thing, is this meant to be compliant with RFC 8998? I just noticed there was a comment concerning TLS 1.1. at the top.

Okay, I've done a bit more reading. This is different from RFC 8998 isn't it? In some ways it's not really TLS is it, it's more a TLS like protocol. Would that be correct?

Correct.

It is more like a dialect based on a standard language.

Although it is called SSL, it is closer to TLS because it is modified from TLS RFC4346. Most of the content is the same as TLS1.1, except that ShangMi (SM) Cipher is used.

I personally think that it may be more appropriate to call it GMTLS, but it is called GMSSL in GMT0024-2012, which is just a difference in name.

The latest version of Chinese cipher algorithm has been added in TLS1.3, I remember the protocol number is RFC8998 ShangMi (SM) Cipher Suites for TLS 1.3, they are not the same thing.

RFC8998 describes the addition of ShangMi (SM) algorithm suite to TLS1.3, while and GMT0024-2012 is an independent revision branch based on TLS1.1.

@dghgit
Copy link
Contributor

dghgit commented Mar 22, 2021

One question that has come up is how does the Certificate message work in the SM2 key exchange algorithm. There appear to be 2 end-entity certificates in the message, are there going to be others in the chain and do the two certificate have a common issuer?

@Trisia
Copy link
Contributor Author

Trisia commented Mar 22, 2021

One question that has come up is how does the Certificate message work in the SM2 key exchange algorithm. There appear to be 2 end-entity certificates in the message, are there going to be others in the chain and do the two certificate have a common issuer?

Yes, the two certificate have same issuer, and the server certificate message contains only two certificates without other certificate chains, one for signing and the other is used for encryption

GMT0024-2012 6.4.4.2 Server Certificate Message struct as follows:
image

Server certificate: The signing certificate comes first, and the encryption certificate comes behind.

If you need to a SM2 server certificate, you need to submit a certificate request to CA, then you will receive:

  • two certificates(one cert for signing, other for encryption )
  • one SignedAndEnvelopedData (encrypted a SM2 key pair inside), you can use priviate key of sign cert to decrypt this.

It is different from RSA in TLS1.1. In TLS1.1, both signature and encryption use the same pair of secret keys, while GMSSL uses two keypairs to work independently.

The handshake message flow is basically the same as TLS1.1:

image

I drew a picture about the key exchange of SM2_SM4_SM3 cipher suite below:

GM密钥交换流程

The picture only describes the key exchange related messages, and does not completely cover the entire handshake process.

@dghgit
Copy link
Contributor

dghgit commented Mar 24, 2021

We've finished analysing the patches. It's been quite a valuable exercise in the sense that it has shown up some shortcomings in our approach. We feel that treating GM SSL as a branch of TLS 1.1 may be the best way to go also. You'll notice more and more conflicts with your patch as we do the merge. We'll let you know when we are done, hopefully at that point we'll something you can simply start using. There is no need to make any changes at the moment.

@Trisia
Copy link
Contributor Author

Trisia commented Mar 24, 2021

We've finished analysing the patches. It's been quite a valuable exercise in the sense that it has shown up some shortcomings in our approach. We feel that treating GM SSL as a branch of TLS 1.1 may be the best way to go also. You'll notice more and more conflicts with your patch as we do the merge. We'll let you know when we are done, hopefully at that point we'll something you can simply start using. There is no need to make any changes at the moment.

ok, thanks

@Trisia
Copy link
Contributor Author

Trisia commented Apr 27, 2021

We've finished analysing the patches. It's been quite a valuable exercise in the sense that it has shown up some shortcomings in our approach. We feel that treating GM SSL as a branch of TLS 1.1 may be the best way to go also. You'll notice more and more conflicts with your patch as we do the merge. We'll let you know when we are done, hopefully at that point we'll something you can simply start using. There is no need to make any changes at the moment.

When will this branch be merged

@dghgit
Copy link
Contributor

dghgit commented May 12, 2021

We're still working through it. You should see bits of it showing up now though.

@sixinyiyu
Copy link

sixinyiyu commented May 21, 2021

Apache HTTPClient GMSSL 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;

/**
 * GMSSL Http Client test
 *
 * @author Cliven
 * @since 2021-02-05 13:25:06
 */
public class GMHttpClient {

    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        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:5557"));
        response.getEntity().writeTo(System.out);
    }
}

请问下 示例中客户端的证书改如何设置?客户端连接的时候不是传递ca证书、签名证书|密钥、加密证书|密钥即可,但是 GMSSKeyParameters 构造函数很不明确

@Trisia
Copy link
Contributor Author

Trisia commented May 22, 2021

Apache HTTPClient GMSSL 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;

/**
 * GMSSL Http Client test
 *
 * @author Cliven
 * @since 2021-02-05 13:25:06
 */
public class GMHttpClient {

    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        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:5557"));
        response.getEntity().writeTo(System.out);
    }
}

请问下 示例中客户端的证书改如何设置?客户端连接的时候不是传递ca证书、签名证书|密钥、加密证书|密钥即可,但是 GMSSKeyParameters 构造函数很不明确

目前我还没有时间去处理客户端对服务端证书的验证,以及双向身份认证,目前的这个分支仅仅实现了单向的gmssl

@cleverpig
Copy link

cleverpig commented Sep 16, 2021

Apache HTTPClient GMSSL 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;

/**
 * GMSSL Http Client test
 *
 * @author Cliven
 * @since 2021-02-05 13:25:06
 */
public class GMHttpClient {

    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        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:5557"));
        response.getEntity().writeTo(System.out);
    }
}

请问下 示例中客户端的证书改如何设置?客户端连接的时候不是传递ca证书、签名证书|密钥、加密证书|密钥即可,但是 GMSSKeyParameters 构造函数很不明确

目前我还没有时间去处理客户端对服务端证书的验证,以及双向身份认证,目前的这个分支仅仅实现了单向的gmssl

访问 https://demo.gmssl.cn 没有问题,但有一些使用国密证书的URL会抛出这样的握手失败的异常,造成连接失败:
出现问题的URL使用了SM4_CBC(加密)+HMAC_SM3(数字摘要)+SM2(密钥交换) 密码套件。好奇怪

Exception in thread "main" org.bouncycastle.tls.TlsFatalAlert: handshake_failure(40)
        at org.bouncycastle.tls.AbstractTlsPeer.notifySecureRenegotiation(AbstractTlsPeer.java:121)
        at org.bouncycastle.tls.TlsClientProtocol.processServerHello(TlsClientProtocol.java:1216)
        at org.bouncycastle.tls.TlsClientProtocol.handleHandshakeMessage(TlsClientProtocol.java:497)
        at org.bouncycastle.tls.TlsProtocol.processHandshakeQueue(TlsProtocol.java:629)
        at org.bouncycastle.tls.TlsProtocol.processRecord(TlsProtocol.java:519)
        at org.bouncycastle.tls.RecordStream.readRecord(RecordStream.java:245)
        at org.bouncycastle.tls.TlsProtocol.safeReadRecord(TlsProtocol.java:777)

        at org.bouncycastle.tls.TlsProtocol.blockForHandshake(TlsProtocol.java:370)
        at org.bouncycastle.tls.TlsClientProtocol.connect(TlsClientProtocol.java:86)
        at org.bouncycastle.jsse.provider.gm.GMSimpleSSLSocket.makeHandshake(GMSimpleSSLSocket.java:181)
        at org.bouncycastle.jsse.provider.gm.GMSimpleSSLSocketWrap.startHandshake(GMSimpleSSLSocketWrap.java:271)
        at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:396)
        at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:355)
        at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:142)
        at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:373)
        at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:394)
        at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:237)
        at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
        at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
        at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
        at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
        at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)

UPDATE:找到原因了,在TlsClientProtocol类里发送了重新协商请求,如果server端不支持重新协商那么就会Alert40。目前暂时注释掉这行即可。

 // TODO[compat-gnutls] GnuTLS test server fails to send renegotiation_info extension when resuming
tlsClient.notifySecureRenegotiation(securityParameters.isSecureRenegotiation());

@jsuper
Copy link

jsuper commented May 19, 2023

Hi @dghgit , Do you have plan to merge this pr or there is another solution to support GMSSL from official?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants