支持国密ssl的curl编译和测试验证(下)

上接支持国密ssl的curl编译和测试验证(上)

4.4 验证国密http2协议功能

命令:
 /opt/gmcurl/bin/curl --http2 --tlcp "https://www.test.com:9443/" -kv

输出:

* Host www.test.com:9441 was resolved.
* IPv6: (none)
* IPv4: 127.0.0.1
*   Trying 127.0.0.1:9441...
* Connected to www.test.com (127.0.0.1) port 9441
* ALPN: curl offers h2,http/1.1
* (101) (OUT), , Unknown (1):
* (101) (IN), , Unknown (2):
* (101) (IN), , Unknown (11):
* (101) (IN), , Unknown (12):
* (101) (IN), , Unknown (14):
* (101) (OUT), , Unknown (16):
* (101) (OUT), , Change cipher spec (1):
* (101) (OUT), , Unknown (20):
* (101) (IN), , Unknown (20):
* SSL connection using NTLSv1.1 / ECC-SM2-SM4-GCM-SM3 / UNDEF / SM2
* ALPN: server did not agree on a protocol. Uses default.
* Server certificate:
*  subject: C=CN; ST=BJ; L=HaiDian; O=Beijing JNTA Technology LTD.; OU=BSRC of TASS; CN=server sign (SM2)
*  start date: May 23 02:45:48 2019 GMT
*  expire date: Jul  1 02:45:48 2023 GMT
*  issuer: C=CN; ST=BJ; L=HaiDian; O=Beijing JNTA Technology LTD.; OU=SORB of TASS; CN=Test CA (SM2)
*  SSL certificate verify result: unable to get local issuer certificate (20), continuing anyway.
*   Certificate level 0: Public key type SM2/SM2 (256/128 Bits/secBits), signed using SM2-with-SM3
*   Certificate level 1: Public key type SM2/SM2 (256/128 Bits/secBits), signed using SM2-with-SM3
* using HTTP/1.x
> GET / HTTP/1.1
> Host: www.test.com:9441
> User-Agent: curl/8.5.0-DEV
> Accept: */*
> 
* Received HTTP/0.9 when not allowed
* Closing connection
* (101) (OUT), , close notify (256):
curl: (1) Received HTTP/0.9 when not allowed

发现用国密ssl握手的http2协议支持是有问题的。

5. 原因分析

分析后发现,铜锁可以读取客户端Client Hello报文中的ALPN信息,而且nginx正常地处理了ALPN消息并选择了h2协议,然而抓包发现铜锁SSL在握手响应的时候是没有生成应用扩展信息响应给客户端,导致客户端不能知道nginx是否能够支持http2,而nginx却已经将该连接切换到http2模式,所以客户端发送过来的是HTTP/1.1的请求的nginx,nginx不能处理该响应,发送了一个HTTP/0.9的消息进行拒绝。

然后对比了一下tls和ntls的实现源码,发现ossl_statem_server13_write_transition和ossl_statem_server_write_transition_ntls两个写状态转移函数,确实有差异:

// tls部分代码:

    case TLS_ST_SW_CHANGE:
        if (s->hello_retry_request == SSL_HRR_PENDING)
            st->hand_state = TLS_ST_EARLY_DATA;
        else
            st->hand_state = TLS_ST_SW_ENCRYPTED_EXTENSIONS;
        return WRITE_TRAN_CONTINUE;

    case TLS_ST_SW_ENCRYPTED_EXTENSIONS:
        if (s->hit)
            st->hand_state = TLS_ST_SW_FINISHED;
        else if (send_certificate_request(s))
            st->hand_state = TLS_ST_SW_CERT_REQ;
        else
            st->hand_state = TLS_ST_SW_CERT;

        return WRITE_TRAN_CONTINUE;

// ntls部分代码:
	case TLS_ST_SW_SRVR_HELLO:
        if (s->hit) {
            if (s->ext.ticket_expected)
                st->hand_state = TLS_ST_SW_SESSION_TICKET;
            else
                st->hand_state = TLS_ST_SW_CHANGE;
        } else {
            /* Check if it is anon DH or anon ECDH, */
            /* normal PSK or SRP */
            if (!(s->s3->tmp.new_cipher->algorithm_auth &
                  (SSL_aNULL | SSL_aSRP | SSL_aPSK))) {
                st->hand_state = TLS_ST_SW_CERT;
            } else if (send_server_key_exchange(s)) {
                st->hand_state = TLS_ST_SW_KEY_EXCH;
            } else if (send_certificate_request_ntls(s)) {
                st->hand_state = TLS_ST_SW_CERT_REQ;
            } else {
                st->hand_state = TLS_ST_SW_SRVR_DONE;
            }
        }
        return WRITE_TRAN_CONTINUE;

......
    case TLS_ST_SW_CHANGE:
        st->hand_state = TLS_ST_SW_FINISHED;
        return WRITE_TRAN_CONTINUE;

导致ntls即国密ssl协议在写状态转义逻辑中没有机会进入到TLS_ST_SW_ENCRYPTED_EXTENSIONS状态,而TLS_ST_SW_ENCRYPTED_EXTENSIONS状态就是写应用扩展信息的逻辑,所以产生了以上问题。

至于怎么修改铜锁的代码,暂时还没有了解透里面的代码逻辑,只能先搁置了。

你可能感兴趣的:(LINUX,c++开发,ssl,网络协议,网络,铜锁,nlts)