提交 f97d4c37 编写于 作者: M Matt Caswell

Extends extension parsing to take the Certificate

Continuing from the previous commit we also need to extend the extensions
framework to supply the Certificate we just read during parsing.
Reviewed-by: NRich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2020)
上级 30aeba43
......@@ -56,9 +56,9 @@ typedef struct extensions_definition_st {
*/
int (*init)(SSL *s, unsigned int context);
/* Parse extension sent from client to server */
int (*parse_ctos)(SSL *s, PACKET *pkt, int *al);
int (*parse_ctos)(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al);
/* Parse extension send from server to client */
int (*parse_stoc)(SSL *s, PACKET *pkt, int *al);
int (*parse_stoc)(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al);
/* Construct extension sent from server to client */
int (*construct_stoc)(SSL *s, WPACKET *pkt, X509 *x, size_t chain,
int *al);
......@@ -441,15 +441,18 @@ int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
* Runs the parser for a given extension with index |idx|. |exts| contains the
* list of all parsed extensions previously collected by
* tls_collect_extensions(). The parser is only run if it is applicable for the
* given |context| and the parser has not already been run. Returns 1 on success
* or 0 on failure. In the event of a failure |*al| is populated with a suitable
* alert code. If an extension is not present this counted as success.
* given |context| and the parser has not already been run. If this is for a
* Certificate message, then we also provide the parser with the relevant
* Certificate |x| and its position in the |chain| with 0 being the first
* Certificate. Returns 1 on success or 0 on failure. In the event of a failure
* |*al| is populated with a suitable alert code. If an extension is not present
* this counted as success.
*/
int tls_parse_extension(SSL *s, TLSEXT_INDEX idx, int context,
RAW_EXTENSION *exts, int *al)
RAW_EXTENSION *exts, X509 *x, size_t chain, int *al)
{
RAW_EXTENSION *currext = &exts[idx];
int (*parser)(SSL *s, PACKET *pkt, int *al) = NULL;
int (*parser)(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al) = NULL;
/* Skip if the extension is not present */
if (!currext->present)
......@@ -478,7 +481,7 @@ int tls_parse_extension(SSL *s, TLSEXT_INDEX idx, int context,
parser = s->server ? extdef->parse_ctos : extdef->parse_stoc;
if (parser != NULL)
return parser(s, &currext->data, al);
return parser(s, &currext->data, x, chain, al);
/*
* If the parser is NULL we fall through to the custom extension
......@@ -509,10 +512,13 @@ int tls_parse_extension(SSL *s, TLSEXT_INDEX idx, int context,
/*
* Parse all remaining extensions that have not yet been parsed. Also calls the
* finalisation for all extensions at the end, whether we collected them or not.
* Returns 1 for success or 0 for failure. On failure, |*al| is populated with a
* suitable alert code.
* Returns 1 for success or 0 for failure. If we are working on a Certificate
* message then we also pass the Certificate |x| and its position in the
* |chain|, with 0 being the first certificate. On failure, |*al| is populated
* with a suitable alert code.
*/
int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts, int *al)
int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts, X509 *x,
size_t chain, int *al)
{
size_t i, numexts = OSSL_NELEM(ext_defs);
const EXTENSION_DEFINITION *thisexd;
......@@ -526,7 +532,7 @@ int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts, int *al)
/* Parse each extension in turn */
for (i = 0; i < numexts; i++) {
if (!tls_parse_extension(s, i, context, exts, al))
if (!tls_parse_extension(s, i, context, exts, x, chain, al))
return 0;
}
......
......@@ -624,7 +624,8 @@ int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, X509 *x, size_t chain,
/*
* Parse the server's renegotiation binding and abort if it's not right
*/
int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, int *al)
int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al)
{
size_t expected_len = s->s3->previous_client_finished_len
+ s->s3->previous_server_finished_len;
......@@ -681,7 +682,8 @@ int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, int *al)
return 1;
}
int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, int *al)
int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al)
{
if (s->tlsext_hostname == NULL || PACKET_remaining(pkt) > 0) {
*al = SSL_AD_UNRECOGNIZED_NAME;
......@@ -704,7 +706,8 @@ int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, int *al)
}
#ifndef OPENSSL_NO_EC
int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, int *al)
int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al)
{
unsigned int ecpointformatlist_length;
PACKET ecptformatlist;
......@@ -739,7 +742,8 @@ int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, int *al)
}
#endif
int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, int *al)
int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al)
{
if (s->tls_session_ticket_ext_cb != NULL &&
!s->tls_session_ticket_ext_cb(s, PACKET_data(pkt),
......@@ -760,7 +764,8 @@ int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, int *al)
}
#ifndef OPENSSL_NO_OCSP
int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, int *al)
int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al)
{
/*
* MUST be empty and only sent if we've requested a status
......@@ -780,7 +785,7 @@ int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, int *al)
#ifndef OPENSSL_NO_CT
int tls_parse_stoc_sct(SSL *s, PACKET *pkt, int *al)
int tls_parse_stoc_sct(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al)
{
/*
* Only take it if we asked for it - i.e if there is no CT validation
......@@ -833,7 +838,7 @@ static int ssl_next_proto_validate(PACKET *pkt)
return 1;
}
int tls_parse_stoc_npn(SSL *s, PACKET *pkt, int *al)
int tls_parse_stoc_npn(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al)
{
unsigned char *selected;
unsigned char selected_len;
......@@ -883,7 +888,7 @@ int tls_parse_stoc_npn(SSL *s, PACKET *pkt, int *al)
}
#endif
int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, int *al)
int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al)
{
size_t len;
......@@ -920,7 +925,7 @@ int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, int *al)
}
#ifndef OPENSSL_NO_SRTP
int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, int *al)
int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al)
{
unsigned int id, ct, mki;
int i;
......@@ -973,7 +978,7 @@ int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, int *al)
}
#endif
int tls_parse_stoc_etm(SSL *s, PACKET *pkt, int *al)
int tls_parse_stoc_etm(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al)
{
/* Ignore if inappropriate ciphersuite */
if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)
......@@ -984,7 +989,7 @@ int tls_parse_stoc_etm(SSL *s, PACKET *pkt, int *al)
return 1;
}
int tls_parse_stoc_ems(SSL *s, PACKET *pkt, int *al)
int tls_parse_stoc_ems(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al)
{
s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS;
if (!s->hit)
......@@ -993,7 +998,8 @@ int tls_parse_stoc_ems(SSL *s, PACKET *pkt, int *al)
return 1;
}
int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, int *al)
int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al)
{
#ifndef OPENSSL_NO_TLS1_3
unsigned int group_id;
......
......@@ -14,7 +14,8 @@
/*
* Parse the client's renegotiation binding and abort if it's not right
*/
int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, int *al)
int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al)
{
unsigned int ilen;
const unsigned char *data;
......@@ -72,7 +73,8 @@ int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, int *al)
* extension.
* - On session reconnect, the servername extension may be absent.
*/
int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, int *al)
int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al)
{
unsigned int servname_type;
PACKET sni, hostname;
......@@ -134,7 +136,7 @@ int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, int *al)
}
#ifndef OPENSSL_NO_SRP
int tls_parse_ctos_srp(SSL *s, PACKET *pkt, int *al)
int tls_parse_ctos_srp(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al)
{
PACKET srp_I;
......@@ -158,7 +160,8 @@ int tls_parse_ctos_srp(SSL *s, PACKET *pkt, int *al)
#endif
#ifndef OPENSSL_NO_EC
int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, int *al)
int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al)
{
PACKET ec_point_format_list;
......@@ -181,7 +184,8 @@ int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, int *al)
}
#endif /* OPENSSL_NO_EC */
int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, int *al)
int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al)
{
if (s->tls_session_ticket_ext_cb &&
!s->tls_session_ticket_ext_cb(s, PACKET_data(pkt),
......@@ -194,7 +198,7 @@ int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, int *al)
return 1;
}
int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, int *al)
int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al)
{
PACKET supported_sig_algs;
......@@ -215,7 +219,8 @@ int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, int *al)
}
#ifndef OPENSSL_NO_OCSP
int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, int *al)
int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al)
{
PACKET responder_id_list, exts;
......@@ -309,7 +314,7 @@ int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, int *al)
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
int tls_parse_ctos_npn(SSL *s, PACKET *pkt, int *al)
int tls_parse_ctos_npn(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al)
{
/*
* We shouldn't accept this extension on a
......@@ -340,7 +345,7 @@ int tls_parse_ctos_npn(SSL *s, PACKET *pkt, int *al)
* extension, not including type and length. |al| is a pointer to the alert
* value to send in the event of a failure. Returns: 1 on success, 0 on error.
*/
int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, int *al)
int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al)
{
PACKET protocol_list, save_protocol_list, protocol;
......@@ -373,7 +378,7 @@ int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, int *al)
}
#ifndef OPENSSL_NO_SRTP
int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, int *al)
int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al)
{
STACK_OF(SRTP_PROTECTION_PROFILE) *srvr;
unsigned int ct, mki_len, id;
......@@ -443,7 +448,7 @@ int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, int *al)
}
#endif
int tls_parse_ctos_etm(SSL *s, PACKET *pkt, int *al)
int tls_parse_ctos_etm(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al)
{
if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC))
s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC;
......@@ -487,7 +492,8 @@ static int check_in_list(SSL *s, unsigned int group_id,
* the raw PACKET data for the extension. Returns 1 on success or 0 on failure.
* If a failure occurs then |*al| is set to an appropriate alert value.
*/
int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, int *al)
int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al)
{
#ifndef OPENSSL_NO_TLS1_3
unsigned int group_id;
......@@ -616,7 +622,8 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, int *al)
}
#ifndef OPENSSL_NO_EC
int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, int *al)
int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al)
{
PACKET supported_groups_list;
......@@ -640,7 +647,7 @@ int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, int *al)
}
#endif
int tls_parse_ctos_ems(SSL *s, PACKET *pkt, int *al)
int tls_parse_ctos_ems(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al)
{
/* The extension must always be empty */
if (PACKET_remaining(pkt) != 0) {
......
......@@ -1312,7 +1312,7 @@ MSG_PROCESS_RETURN tls_process_server_hello(SSL *s, PACKET *pkt)
context = SSL_IS_TLS13(s) ? EXT_TLS1_3_SERVER_HELLO
: EXT_TLS1_2_SERVER_HELLO;
if (!tls_collect_extensions(s, &extpkt, context, &extensions, &al)
|| !tls_parse_all_extensions(s, context, extensions, &al))
|| !tls_parse_all_extensions(s, context, extensions, NULL, 0, &al))
goto f_err;
#ifndef OPENSSL_NO_SCTP
......@@ -3120,7 +3120,7 @@ static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt)
|| !tls_parse_all_extensions(s,
EXT_TLS1_3_ENCRYPTED_EXTENSIONS
| EXT_TLS1_3_CERTIFICATE,
rawexts, &al))
rawexts, NULL, 0, &al))
goto err;
OPENSSL_free(rawexts);
......
......@@ -156,37 +156,47 @@ __owur int tls_construct_new_session_ticket(SSL *s, WPACKET *pkt);
__owur int tls_collect_extensions(SSL *s, PACKET *packet, unsigned int context,
RAW_EXTENSION **res, int *al);
__owur int tls_parse_extension(SSL *s, TLSEXT_INDEX idx, int context,
RAW_EXTENSION *exts, int *al);
RAW_EXTENSION *exts, X509 *x, size_t chain,
int *al);
__owur int tls_parse_all_extensions(SSL *s, int context, RAW_EXTENSION *exts,
int *al);
X509 *x, size_t chain, int *al);
__owur int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context,
X509 *x, size_t chain, int *al);
/* Server Extension processing */
int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, int *al);
int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, int *al);
int tls_parse_ctos_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
int tls_parse_ctos_server_name(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
#ifndef OPENSSL_NO_SRP
int tls_parse_ctos_srp(SSL *s, PACKET *pkt, int *al);
int tls_parse_ctos_srp(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al);
#endif
#ifndef OPENSSL_NO_EC
int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, int *al);
int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, int *al);
int tls_parse_ctos_ec_pt_formats(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
int tls_parse_ctos_supported_groups(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
#endif
int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, int *al);
int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, int *al);
int tls_parse_ctos_session_ticket(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
int tls_parse_ctos_sig_algs(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
#ifndef OPENSSL_NO_OCSP
int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, int *al);
int tls_parse_ctos_status_request(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
int tls_parse_ctos_npn(SSL *s, PACKET *pkt, int *al);
int tls_parse_ctos_npn(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al);
#endif
int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, int *al);
int tls_parse_ctos_alpn(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al);
#ifndef OPENSSL_NO_SRTP
int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, int *al);
int tls_parse_ctos_use_srtp(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
#endif
int tls_parse_ctos_etm(SSL *s, PACKET *pkt, int *al);
int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, int *al);
int tls_parse_ctos_ems(SSL *s, PACKET *pkt, int *al);
int tls_parse_ctos_etm(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al);
int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
int tls_parse_ctos_ems(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al);
int tls_construct_stoc_renegotiate(SSL *s, WPACKET *pkt, X509 *x, size_t chain,
int *al);
......@@ -273,25 +283,32 @@ int tls_construct_ctos_key_share(SSL *s, WPACKET *pkt, X509 *x, size_t chain,
int *al);
int tls_construct_ctos_padding(SSL *s, WPACKET *pkt, X509 *x, size_t chain,
int *al);
int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, int *al);
int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, int *al);
int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
int tls_parse_stoc_server_name(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
#ifndef OPENSSL_NO_EC
int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, int *al);
int tls_parse_stoc_ec_pt_formats(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
#endif
int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, int *al);
int tls_parse_stoc_session_ticket(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
#ifndef OPENSSL_NO_OCSP
int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, int *al);
int tls_parse_stoc_status_request(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
#endif
#ifndef OPENSSL_NO_CT
int tls_parse_stoc_sct(SSL *s, PACKET *pkt, int *al);
int tls_parse_stoc_sct(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al);
#endif
#ifndef OPENSSL_NO_NEXTPROTONEG
int tls_parse_stoc_npn(SSL *s, PACKET *pkt, int *al);
int tls_parse_stoc_npn(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al);
#endif
int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, int *al);
int tls_parse_stoc_alpn(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al);
#ifndef OPENSSL_NO_SRTP
int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, int *al);
int tls_parse_stoc_use_srtp(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
#endif
int tls_parse_stoc_etm(SSL *s, PACKET *pkt, int *al);
int tls_parse_stoc_ems(SSL *s, PACKET *pkt, int *al);
int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, int *al);
int tls_parse_stoc_etm(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al);
int tls_parse_stoc_ems(SSL *s, PACKET *pkt, X509 *x, size_t chain, int *al);
int tls_parse_stoc_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chain,
int *al);
......@@ -1400,7 +1400,7 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
/* We need to do this before getting the session */
if (!tls_parse_extension(s, TLSEXT_IDX_extended_master_secret,
EXT_CLIENT_HELLO,
clienthello.pre_proc_exts, &al)) {
clienthello.pre_proc_exts, NULL, 0, &al)) {
SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_CLIENTHELLO_TLSEXT);
goto f_err;
}
......@@ -1504,7 +1504,7 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
/* TLS extensions */
if (!tls_parse_all_extensions(s, EXT_CLIENT_HELLO,
clienthello.pre_proc_exts, &al)) {
clienthello.pre_proc_exts, NULL, 0, &al)) {
SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_PARSE_TLSEXT);
goto f_err;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册