上接支持国密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;elsest->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;elsest->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;elsest->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状态就是写应用扩展信息的逻辑,所以产生了以上问题。
至于怎么修改铜锁的代码,暂时还没有了解透里面的代码逻辑,只能先搁置了。