mirror of
https://gitea.invidious.io/iv-org/litespeed-quic.git
synced 2024-08-15 00:53:43 +00:00
1.12.0: [FEATURE, API Change] Certificate verification
This commit is contained in:
parent
de1c35ddaf
commit
7f2bd84c85
11 changed files with 285 additions and 17 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
2018-08-17
|
||||||
|
|
||||||
|
- 1.12.0
|
||||||
|
- [FEATURE, API Change] Add support for certificate verification
|
||||||
|
|
||||||
2018-08-16
|
2018-08-16
|
||||||
|
|
||||||
- 1.11.1
|
- 1.11.1
|
||||||
|
|
|
@ -24,8 +24,8 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LSQUIC_MAJOR_VERSION 1
|
#define LSQUIC_MAJOR_VERSION 1
|
||||||
#define LSQUIC_MINOR_VERSION 11
|
#define LSQUIC_MINOR_VERSION 12
|
||||||
#define LSQUIC_PATCH_VERSION 1
|
#define LSQUIC_PATCH_VERSION 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Engine flags:
|
* Engine flags:
|
||||||
|
@ -496,6 +496,8 @@ struct lsquic_packout_mem_if
|
||||||
void (*pmi_release) (void *pmi_ctx, void *obj);
|
void (*pmi_release) (void *pmi_ctx, void *obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct stack_st_X509;
|
||||||
|
|
||||||
/* TODO: describe this important data structure */
|
/* TODO: describe this important data structure */
|
||||||
typedef struct lsquic_engine_api
|
typedef struct lsquic_engine_api
|
||||||
{
|
{
|
||||||
|
@ -509,6 +511,20 @@ typedef struct lsquic_engine_api
|
||||||
*/
|
*/
|
||||||
const struct lsquic_packout_mem_if *ea_pmi;
|
const struct lsquic_packout_mem_if *ea_pmi;
|
||||||
void *ea_pmi_ctx;
|
void *ea_pmi_ctx;
|
||||||
|
/**
|
||||||
|
* Function to verify server certificate. The chain contains at least
|
||||||
|
* one element. The first element in the chain is the server
|
||||||
|
* certificate. The chain belongs to the library. If you want to
|
||||||
|
* retain it, call sk_X509_up_ref().
|
||||||
|
*
|
||||||
|
* 0 is returned on success, -1 on error.
|
||||||
|
*
|
||||||
|
* If the function pointer is not set, no verification is performed
|
||||||
|
* (the connection is allowed to proceed).
|
||||||
|
*/
|
||||||
|
int (*ea_verify_cert)(void *verify_ctx,
|
||||||
|
struct stack_st_X509 *chain);
|
||||||
|
void *ea_verify_ctx;
|
||||||
} lsquic_engine_api_t;
|
} lsquic_engine_api_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -685,6 +701,18 @@ int lsquic_stream_shutdown(lsquic_stream_t *s, int how);
|
||||||
|
|
||||||
int lsquic_stream_close(lsquic_stream_t *s);
|
int lsquic_stream_close(lsquic_stream_t *s);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get certificate chain returned by the server. This can be used for
|
||||||
|
* server certificate verifiction.
|
||||||
|
*
|
||||||
|
* If server certificate cannot be verified, the connection can be closed
|
||||||
|
* using lsquic_conn_cert_verification_failed().
|
||||||
|
*
|
||||||
|
* The caller releases the stack using sk_X509_free().
|
||||||
|
*/
|
||||||
|
struct stack_st_X509 *
|
||||||
|
lsquic_conn_get_server_cert_chain (lsquic_conn_t *);
|
||||||
|
|
||||||
/** Returns ID of the stream */
|
/** Returns ID of the stream */
|
||||||
uint32_t
|
uint32_t
|
||||||
lsquic_stream_id (const lsquic_stream_t *s);
|
lsquic_stream_id (const lsquic_stream_t *s);
|
||||||
|
|
|
@ -36,7 +36,7 @@ SOFTWARE.
|
||||||
#if LS_HPACK_EMIT_TEST_CODE
|
#if LS_HPACK_EMIT_TEST_CODE
|
||||||
#include "lshpack-test.h"
|
#include "lshpack-test.h"
|
||||||
#endif
|
#endif
|
||||||
#include "lsquic_xxhash.h"
|
#include XXH_HEADER_NAME
|
||||||
|
|
||||||
#define HPACK_STATIC_TABLE_SIZE 61
|
#define HPACK_STATIC_TABLE_SIZE 61
|
||||||
#define INITIAL_DYNAMIC_TABLE_SIZE 4096
|
#define INITIAL_DYNAMIC_TABLE_SIZE 4096
|
||||||
|
|
|
@ -609,14 +609,6 @@ int gen_prof(const uint8_t *chlo_data, size_t chlo_data_len,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int verify_cert(const char *buf, int len)
|
|
||||||
{
|
|
||||||
//X509_verify_cert();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int verify_prof(const uint8_t *chlo_data, size_t chlo_data_len, lsquic_str_t * scfg,
|
int verify_prof(const uint8_t *chlo_data, size_t chlo_data_len, lsquic_str_t * scfg,
|
||||||
const EVP_PKEY *pub_key, const uint8_t *buf, size_t len)
|
const EVP_PKEY *pub_key, const uint8_t *buf, size_t len)
|
||||||
{
|
{
|
||||||
|
|
|
@ -335,6 +335,8 @@ lsquic_engine_new (unsigned flags,
|
||||||
engine->pub.enp_pmi = &stock_pmi;
|
engine->pub.enp_pmi = &stock_pmi;
|
||||||
engine->pub.enp_pmi_ctx = NULL;
|
engine->pub.enp_pmi_ctx = NULL;
|
||||||
}
|
}
|
||||||
|
engine->pub.enp_verify_cert = api->ea_verify_cert;
|
||||||
|
engine->pub.enp_verify_ctx = api->ea_verify_ctx;
|
||||||
engine->pub.enp_engine = engine;
|
engine->pub.enp_engine = engine;
|
||||||
conn_hash_init(&engine->conns_hash,
|
conn_hash_init(&engine->conns_hash,
|
||||||
hash_conns_by_addr(engine) ? CHF_USE_ADDR : 0);
|
hash_conns_by_addr(engine) ? CHF_USE_ADDR : 0);
|
||||||
|
|
|
@ -9,10 +9,14 @@
|
||||||
|
|
||||||
struct lsquic_conn;
|
struct lsquic_conn;
|
||||||
struct lsquic_engine;
|
struct lsquic_engine;
|
||||||
|
struct stack_st_X509;
|
||||||
|
|
||||||
struct lsquic_engine_public {
|
struct lsquic_engine_public {
|
||||||
struct lsquic_mm enp_mm;
|
struct lsquic_mm enp_mm;
|
||||||
struct lsquic_engine_settings enp_settings;
|
struct lsquic_engine_settings enp_settings;
|
||||||
|
int (*enp_verify_cert)(void *verify_ctx,
|
||||||
|
struct stack_st_X509 *chain);
|
||||||
|
void *enp_verify_ctx;
|
||||||
const struct lsquic_packout_mem_if
|
const struct lsquic_packout_mem_if
|
||||||
*enp_pmi;
|
*enp_pmi;
|
||||||
void *enp_pmi_ctx;
|
void *enp_pmi_ctx;
|
||||||
|
|
|
@ -2677,7 +2677,7 @@ immediate_close (struct full_conn *conn)
|
||||||
return TICK_CLOSE;
|
return TICK_CLOSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(conn->fc_flags & (FC_ERROR|FC_ABORTED|FC_TIMED_OUT));
|
assert(conn->fc_flags & (FC_ERROR|FC_ABORTED|FC_TIMED_OUT|FC_HSK_FAILED));
|
||||||
if (conn->fc_flags & FC_ERROR)
|
if (conn->fc_flags & FC_ERROR)
|
||||||
{
|
{
|
||||||
error_code = 0x01; /* QUIC_INTERNAL_ERROR */
|
error_code = 0x01; /* QUIC_INTERNAL_ERROR */
|
||||||
|
@ -2693,6 +2693,11 @@ immediate_close (struct full_conn *conn)
|
||||||
error_code = 0x19; /* QUIC_NETWORK_IDLE_TIMEOUT */
|
error_code = 0x19; /* QUIC_NETWORK_IDLE_TIMEOUT */
|
||||||
error_reason = "connection timed out";
|
error_reason = "connection timed out";
|
||||||
}
|
}
|
||||||
|
else if (conn->fc_flags & FC_HSK_FAILED)
|
||||||
|
{
|
||||||
|
error_code = 0x2A; /* QUIC_PROOF_INVALID */
|
||||||
|
error_reason = "handshake failed";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error_code = 0x10; /* QUIC_PEER_GOING_AWAY */
|
error_code = 0x10; /* QUIC_PEER_GOING_AWAY */
|
||||||
|
|
|
@ -1108,15 +1108,17 @@ static int handle_chlo_reply_verify_prof(lsquic_enc_session_t *enc_session,
|
||||||
in + lsquic_str_len(&enc_session->hs_ctx.crt);
|
in + lsquic_str_len(&enc_session->hs_ctx.crt);
|
||||||
EVP_PKEY *pub_key;
|
EVP_PKEY *pub_key;
|
||||||
int ret;
|
int ret;
|
||||||
X509 *cert;
|
size_t i;
|
||||||
|
X509 *cert, *server_cert;
|
||||||
|
STACK_OF(X509) *chain = NULL;
|
||||||
ret = decompress_certs(in, in_end,cached_certs, cached_certs_count,
|
ret = decompress_certs(in, in_end,cached_certs, cached_certs_count,
|
||||||
out_certs, out_certs_count);
|
out_certs, out_certs_count);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
cert = bio_to_crt((const char *)lsquic_str_cstr(out_certs[0]),
|
server_cert = bio_to_crt((const char *)lsquic_str_cstr(out_certs[0]),
|
||||||
lsquic_str_len(out_certs[0]), 0);
|
lsquic_str_len(out_certs[0]), 0);
|
||||||
pub_key = X509_get_pubkey(cert);
|
pub_key = X509_get_pubkey(server_cert);
|
||||||
ret = verify_prof((const uint8_t *)lsquic_str_cstr(&enc_session->chlo),
|
ret = verify_prof((const uint8_t *)lsquic_str_cstr(&enc_session->chlo),
|
||||||
(size_t)lsquic_str_len(&enc_session->chlo),
|
(size_t)lsquic_str_len(&enc_session->chlo),
|
||||||
&enc_session->info->scfg,
|
&enc_session->info->scfg,
|
||||||
|
@ -1124,7 +1126,36 @@ static int handle_chlo_reply_verify_prof(lsquic_enc_session_t *enc_session,
|
||||||
(const uint8_t *)lsquic_str_cstr(&enc_session->hs_ctx.prof),
|
(const uint8_t *)lsquic_str_cstr(&enc_session->hs_ctx.prof),
|
||||||
lsquic_str_len(&enc_session->hs_ctx.prof));
|
lsquic_str_len(&enc_session->hs_ctx.prof));
|
||||||
EVP_PKEY_free(pub_key);
|
EVP_PKEY_free(pub_key);
|
||||||
X509_free(cert);
|
if (ret != 0)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
if (enc_session->enpub->enp_verify_cert)
|
||||||
|
{
|
||||||
|
chain = sk_X509_new_null();
|
||||||
|
sk_X509_push(chain, server_cert);
|
||||||
|
for (i = 1; i < *out_certs_count; ++i)
|
||||||
|
{
|
||||||
|
cert = bio_to_crt((const char *)lsquic_str_cstr(out_certs[i]),
|
||||||
|
lsquic_str_len(out_certs[i]), 0);
|
||||||
|
if (cert)
|
||||||
|
sk_X509_push(chain, cert);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LSQ_WARN("cannot push certificate to stack");
|
||||||
|
ret = -1;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = enc_session->enpub->enp_verify_cert(
|
||||||
|
enc_session->enpub->enp_verify_ctx, chain);
|
||||||
|
LSQ_INFO("server certificate verification %ssuccessful",
|
||||||
|
ret == 0 ? "" : "not ");
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
if (chain)
|
||||||
|
sk_X509_free(chain);
|
||||||
|
X509_free(server_cert);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1837,6 +1868,41 @@ lsquic_enc_session_verify_reset_token (lsquic_enc_session_t *enc_session,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static STACK_OF(X509) *
|
||||||
|
lsquic_enc_session_get_server_cert_chain (lsquic_enc_session_t *enc_session)
|
||||||
|
{
|
||||||
|
const struct cert_hash_item_st *item;
|
||||||
|
STACK_OF(X509) *chain;
|
||||||
|
X509 *cert;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
item = c_find_certs(&enc_session->hs_ctx.sni);
|
||||||
|
if (!item)
|
||||||
|
{
|
||||||
|
LSQ_WARN("could not find certificates for `%.*s'",
|
||||||
|
(int) lsquic_str_len(&enc_session->hs_ctx.sni),
|
||||||
|
lsquic_str_cstr(&enc_session->hs_ctx.sni));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
chain = sk_X509_new_null();
|
||||||
|
for (i = 0; i < item->count; ++i)
|
||||||
|
{
|
||||||
|
cert = bio_to_crt(lsquic_str_cstr(&item->crts[i]),
|
||||||
|
lsquic_str_len(&item->crts[i]), 0);
|
||||||
|
if (cert)
|
||||||
|
sk_X509_push(chain, cert);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sk_X509_free(chain);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
const
|
const
|
||||||
#endif
|
#endif
|
||||||
|
@ -1859,6 +1925,7 @@ struct enc_session_funcs lsquic_enc_session_gquic_1 =
|
||||||
.esf_handle_chlo_reply = lsquic_enc_session_handle_chlo_reply,
|
.esf_handle_chlo_reply = lsquic_enc_session_handle_chlo_reply,
|
||||||
.esf_mem_used = lsquic_enc_session_mem_used,
|
.esf_mem_used = lsquic_enc_session_mem_used,
|
||||||
.esf_verify_reset_token = lsquic_enc_session_verify_reset_token,
|
.esf_verify_reset_token = lsquic_enc_session_verify_reset_token,
|
||||||
|
.esf_get_server_cert_chain = lsquic_enc_session_get_server_cert_chain,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
struct lsquic_engine_public;
|
struct lsquic_engine_public;
|
||||||
struct lsquic_enc_session;
|
struct lsquic_enc_session;
|
||||||
|
struct stack_st_X509;
|
||||||
|
|
||||||
typedef struct lsquic_enc_session lsquic_enc_session_t;
|
typedef struct lsquic_enc_session lsquic_enc_session_t;
|
||||||
|
|
||||||
|
@ -139,6 +140,9 @@ struct enc_session_funcs
|
||||||
int
|
int
|
||||||
(*esf_verify_reset_token) (lsquic_enc_session_t *, const unsigned char *,
|
(*esf_verify_reset_token) (lsquic_enc_session_t *, const unsigned char *,
|
||||||
size_t);
|
size_t);
|
||||||
|
|
||||||
|
struct stack_st_X509 *
|
||||||
|
(*esf_get_server_cert_chain) (lsquic_enc_session_t *);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern
|
extern
|
||||||
|
|
|
@ -25,10 +25,18 @@
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <dirent.h>
|
||||||
#endif
|
#endif
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/x509.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "lsquic.h"
|
#include "lsquic.h"
|
||||||
#include "test_common.h"
|
#include "test_common.h"
|
||||||
#include "prog.h"
|
#include "prog.h"
|
||||||
|
@ -160,6 +168,7 @@ struct lsquic_stream_ctx {
|
||||||
const char *path;
|
const char *path;
|
||||||
enum {
|
enum {
|
||||||
HEADERS_SENT = (1 << 0),
|
HEADERS_SENT = (1 << 0),
|
||||||
|
CHAIN_DISPLAYED = (1 << 1),
|
||||||
} sh_flags;
|
} sh_flags;
|
||||||
unsigned count;
|
unsigned count;
|
||||||
struct lsquic_reader reader;
|
struct lsquic_reader reader;
|
||||||
|
@ -274,11 +283,46 @@ send_headers (lsquic_stream_ctx_t *st_h)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This is here to exercise lsquic_conn_get_server_cert_chain() API */
|
||||||
|
static void
|
||||||
|
display_cert_chain (lsquic_conn_t *conn)
|
||||||
|
{
|
||||||
|
STACK_OF(X509) *chain;
|
||||||
|
X509_NAME *name;
|
||||||
|
X509 *cert;
|
||||||
|
unsigned i;
|
||||||
|
char buf[100];
|
||||||
|
|
||||||
|
chain = lsquic_conn_get_server_cert_chain(conn);
|
||||||
|
if (!chain)
|
||||||
|
{
|
||||||
|
LSQ_WARN("could not get server certificate chain");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < sk_X509_num(chain); ++i)
|
||||||
|
{
|
||||||
|
cert = sk_X509_value(chain, i);
|
||||||
|
name = X509_get_subject_name(cert);
|
||||||
|
LSQ_INFO("cert #%u: name: %s", i,
|
||||||
|
X509_NAME_oneline(name, buf, sizeof(buf)));
|
||||||
|
}
|
||||||
|
|
||||||
|
sk_X509_free(chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
http_client_on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
|
http_client_on_write (lsquic_stream_t *stream, lsquic_stream_ctx_t *st_h)
|
||||||
{
|
{
|
||||||
ssize_t nw;
|
ssize_t nw;
|
||||||
|
|
||||||
|
if (!(st_h->sh_flags & CHAIN_DISPLAYED))
|
||||||
|
{
|
||||||
|
display_cert_chain(lsquic_stream_conn(stream));
|
||||||
|
st_h->sh_flags |= CHAIN_DISPLAYED;
|
||||||
|
}
|
||||||
|
|
||||||
if (st_h->sh_flags & HEADERS_SENT)
|
if (st_h->sh_flags & HEADERS_SENT)
|
||||||
{
|
{
|
||||||
if (st_h->client_ctx->payload && test_reader_size(st_h->reader.lsqr_ctx) > 0)
|
if (st_h->client_ctx->payload && test_reader_size(st_h->reader.lsqr_ctx) > 0)
|
||||||
|
@ -433,10 +477,116 @@ usage (const char *prog)
|
||||||
" -I Abort on incomplete reponse from server\n"
|
" -I Abort on incomplete reponse from server\n"
|
||||||
" -4 Prefer IPv4 when resolving hostname\n"
|
" -4 Prefer IPv4 when resolving hostname\n"
|
||||||
" -6 Prefer IPv6 when resolving hostname\n"
|
" -6 Prefer IPv6 when resolving hostname\n"
|
||||||
|
#ifndef WIN32
|
||||||
|
" -C DIR Certificate store. If specified, server certificate will\n"
|
||||||
|
#endif
|
||||||
|
" be verified.\n"
|
||||||
, prog);
|
, prog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
static X509_STORE *store;
|
||||||
|
|
||||||
|
/* Windows does not have regex... */
|
||||||
|
static int
|
||||||
|
ends_in_pem (const char *s)
|
||||||
|
{
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = strlen(s);
|
||||||
|
|
||||||
|
return len >= 4
|
||||||
|
&& 0 == strcasecmp(s + len - 4, ".pem");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static X509 *
|
||||||
|
file2cert (const char *path)
|
||||||
|
{
|
||||||
|
X509 *cert = NULL;
|
||||||
|
BIO *in;
|
||||||
|
|
||||||
|
in = BIO_new(BIO_s_file());
|
||||||
|
if (!in)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
if (BIO_read_filename(in, path) <= 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
cert = PEM_read_bio_X509_AUX(in, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
end:
|
||||||
|
BIO_free(in);
|
||||||
|
return cert;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
init_x509_cert_store (const char *path)
|
||||||
|
{
|
||||||
|
struct dirent *ent;
|
||||||
|
X509 *cert;
|
||||||
|
DIR *dir;
|
||||||
|
char file_path[NAME_MAX];
|
||||||
|
|
||||||
|
dir = opendir(path);
|
||||||
|
if (!dir)
|
||||||
|
{
|
||||||
|
LSQ_WARN("Cannot open directory `%s': %s", path, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
store = X509_STORE_new();
|
||||||
|
|
||||||
|
while ((ent = readdir(dir)))
|
||||||
|
{
|
||||||
|
if (ends_in_pem(ent->d_name))
|
||||||
|
{
|
||||||
|
snprintf(file_path, sizeof(file_path), "%s/%s", path, ent->d_name);
|
||||||
|
cert = file2cert(file_path);
|
||||||
|
if (cert)
|
||||||
|
{
|
||||||
|
if (1 != X509_STORE_add_cert(store, cert))
|
||||||
|
LSQ_WARN("could not add cert from %s", file_path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LSQ_WARN("could not read cert from %s", file_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(void) closedir(dir);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
verify_server_cert (void *ctx, STACK_OF(X509) *chain)
|
||||||
|
{
|
||||||
|
X509_STORE_CTX store_ctx;
|
||||||
|
X509 *cert;
|
||||||
|
int ver;
|
||||||
|
|
||||||
|
if (!store)
|
||||||
|
{
|
||||||
|
if (0 != init_x509_cert_store(ctx))
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cert = sk_X509_shift(chain);
|
||||||
|
X509_STORE_CTX_init(&store_ctx, store, cert, chain);
|
||||||
|
|
||||||
|
ver = X509_verify_cert(&store_ctx);
|
||||||
|
|
||||||
|
X509_STORE_CTX_cleanup(&store_ctx);
|
||||||
|
|
||||||
|
if (ver != 1)
|
||||||
|
LSQ_WARN("could not verify server certificate");
|
||||||
|
|
||||||
|
return ver == 1 ? 0 : -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -464,7 +614,11 @@ main (int argc, char **argv)
|
||||||
|
|
||||||
prog_init(&prog, LSENG_HTTP, &sports, &http_client_if, &client_ctx);
|
prog_init(&prog, LSENG_HTTP, &sports, &http_client_if, &client_ctx);
|
||||||
|
|
||||||
while (-1 != (opt = getopt(argc, argv, PROG_OPTS "46r:R:IKu:EP:M:n:H:p:h")))
|
while (-1 != (opt = getopt(argc, argv, PROG_OPTS "46r:R:IKu:EP:M:n:H:p:h"
|
||||||
|
#ifndef WIN32
|
||||||
|
"C:"
|
||||||
|
#endif
|
||||||
|
)))
|
||||||
{
|
{
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case '4':
|
case '4':
|
||||||
|
@ -525,6 +679,12 @@ main (int argc, char **argv)
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
prog_print_common_options(&prog, stdout);
|
prog_print_common_options(&prog, stdout);
|
||||||
exit(0);
|
exit(0);
|
||||||
|
#ifndef WIN32
|
||||||
|
case 'C':
|
||||||
|
prog.prog_api.ea_verify_cert = verify_server_cert;
|
||||||
|
prog.prog_api.ea_verify_ctx = optarg;
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
default:
|
default:
|
||||||
if (0 != prog_set_opt(&prog, opt, optarg))
|
if (0 != prog_set_opt(&prog, opt, optarg))
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
|
@ -20,6 +20,7 @@ main (void)
|
||||||
NULL, NULL, /* stream if and ctx */
|
NULL, NULL, /* stream if and ctx */
|
||||||
(void *) (uintptr_t) 1, NULL, /* packets out and ctx */
|
(void *) (uintptr_t) 1, NULL, /* packets out and ctx */
|
||||||
NULL, NULL, /* packout mem interface and ctx */
|
NULL, NULL, /* packout mem interface and ctx */
|
||||||
|
NULL, NULL, /* verify server cert */
|
||||||
};
|
};
|
||||||
|
|
||||||
engine = lsquic_engine_new(flags, &api);
|
engine = lsquic_engine_new(flags, &api);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue