Compare commits
6 commits
master
...
feature/ec
Author | SHA1 | Date | |
---|---|---|---|
|
000b8958c9 | ||
|
9e8986d01d | ||
|
4cdbe04d98 | ||
|
4666604387 | ||
|
02e3203e40 | ||
|
cb616bf86c |
47 changed files with 5935 additions and 252 deletions
|
@ -1328,7 +1328,8 @@ errors:
|
|||
include/openssl/dtls1.h
|
||||
include/openssl/srtp.h
|
||||
include/openssl/quic.h
|
||||
include/openssl/sslerr_legacy.h );
|
||||
include/openssl/sslerr_legacy.h
|
||||
include/openssl/ech.h);
|
||||
my @cryptoheaders_tmpl =
|
||||
qw( include/internal/dso.h
|
||||
include/internal/o_dir.h
|
||||
|
|
|
@ -464,6 +464,7 @@ my @disablables = (
|
|||
"ecdh",
|
||||
"ecdsa",
|
||||
"ecx",
|
||||
"ech",
|
||||
"egd",
|
||||
"engine",
|
||||
"err",
|
||||
|
@ -619,7 +620,7 @@ my @disable_cascades = (
|
|||
"blake2", "bf", "camellia", "cast", "chacha",
|
||||
"cmac", "cms", "cmp", "comp", "ct",
|
||||
"des", "dgram", "dh", "dsa",
|
||||
"ec", "engine",
|
||||
"ec", "ech", "engine",
|
||||
"filenames",
|
||||
"idea", "ktls",
|
||||
"md4", "multiblock", "nextprotoneg",
|
||||
|
|
|
@ -781,6 +781,11 @@ Don't build support for Elliptic Curves.
|
|||
|
||||
Don't build support for binary Elliptic Curves
|
||||
|
||||
### no-ech
|
||||
|
||||
Don't build support for Encrypted Client Hello (ECH) extension (draft-ietf-tls-esni)
|
||||
TODO(ECH) update link to RFC.
|
||||
|
||||
### enable-ec_nistp_64_gcc_128
|
||||
|
||||
Enable support for optimised implementations of some commonly used NIST
|
||||
|
|
|
@ -18,6 +18,7 @@ $OPENSSLSRC=\
|
|||
pkcs8.c pkey.c pkeyparam.c pkeyutl.c prime.c rand.c req.c \
|
||||
s_client.c s_server.c s_time.c sess_id.c smime.c speed.c \
|
||||
spkac.c verify.c version.c x509.c rehash.c storeutl.c \
|
||||
ech.c \
|
||||
list.c info.c fipsinstall.c pkcs12.c
|
||||
IF[{- !$disabled{'ec'} -}]
|
||||
$OPENSSLSRC=$OPENSSLSRC ec.c ecparam.c
|
||||
|
|
277
apps/ech.c
Normal file
277
apps/ech.c
Normal file
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "apps.h"
|
||||
#include "progs.h"
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/hpke.h>
|
||||
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/x509.h>
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
|
||||
# define OSSL_ECH_KEYGEN_MODE 0 /* default: generate a key pair/ECHConfig */
|
||||
# define OSSL_ECH_SELPRINT_MODE 1 /* we can print/down-select ECHConfigList */
|
||||
# define OSSL_ECH_MAXINFILES 5 /* we'll only take this many inputs */
|
||||
|
||||
typedef enum OPTION_choice {
|
||||
/* standard openssl options */
|
||||
OPT_ERR = -1, OPT_EOF = 0, OPT_HELP, OPT_VERBOSE, OPT_TEXT,
|
||||
OPT_OUT, OPT_IN,
|
||||
/* ECHConfig specifics */
|
||||
OPT_PUBLICNAME, OPT_ECHVERSION,
|
||||
OPT_MAXNAMELENGTH, OPT_HPKESUITE,
|
||||
OPT_SELECT
|
||||
} OPTION_CHOICE;
|
||||
|
||||
const OPTIONS ech_options[] = {
|
||||
OPT_SECTION("General options"),
|
||||
{"help", OPT_HELP, '-', "Display this summary"},
|
||||
{"verbose", OPT_VERBOSE, '-', "Provide additional output"},
|
||||
{"text", OPT_TEXT, '-', "Provide human-readable output"},
|
||||
OPT_SECTION("Key generation"),
|
||||
{"out", OPT_OUT, '>',
|
||||
"Private key and/or ECHConfig [default: echconfig.pem]"},
|
||||
{"public_name", OPT_PUBLICNAME, 's', "public_name value"},
|
||||
{"max_name_len", OPT_MAXNAMELENGTH, 'n',
|
||||
"Maximum host name length value [default: 0]"},
|
||||
{"suite", OPT_HPKESUITE, 's', "HPKE ciphersuite: e.g. \"0x20,1,3\""},
|
||||
{"ech_version", OPT_ECHVERSION, 'n',
|
||||
"ECHConfig version [default: 0xff0d (13)]"},
|
||||
OPT_SECTION("ECH PEM file downselect/display"),
|
||||
{"in", OPT_IN, '<', "An ECH PEM file"},
|
||||
{"select", OPT_SELECT, 'n', "Downselect to the numbered ECH config"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief map version string like 0xff01 or 65291 to uint16_t
|
||||
* @param arg is the version string, from command line
|
||||
* @return is the uint16_t value (with zero for error cases)
|
||||
*/
|
||||
static uint16_t verstr2us(char *arg)
|
||||
{
|
||||
long lv = strtol(arg, NULL, 0);
|
||||
uint16_t rv = 0;
|
||||
|
||||
if (lv < 0xffff && lv > 0)
|
||||
rv = (uint16_t)lv;
|
||||
return rv;
|
||||
}
|
||||
|
||||
int ech_main(int argc, char **argv)
|
||||
{
|
||||
char *prog = NULL;
|
||||
OPTION_CHOICE o;
|
||||
int i, rv = 1, verbose = 0, text = 0, outsupp = 0;
|
||||
int select = OSSL_ECHSTORE_ALL, numinfiles = 0;
|
||||
char *outfile = NULL, *infile = NULL;
|
||||
char *infiles[OSSL_ECH_MAXINFILES] = { NULL };
|
||||
char *public_name = NULL, *suitestr = NULL;
|
||||
uint16_t ech_version = OSSL_ECH_CURRENT_VERSION;
|
||||
uint8_t max_name_length = 0;
|
||||
OSSL_HPKE_SUITE hpke_suite = OSSL_HPKE_SUITE_DEFAULT;
|
||||
int mode = OSSL_ECH_KEYGEN_MODE; /* key generation */
|
||||
OSSL_ECHSTORE *es = NULL;
|
||||
BIO *ecf = NULL;
|
||||
|
||||
prog = opt_init(argc, argv, ech_options);
|
||||
while ((o = opt_next()) != OPT_EOF) {
|
||||
switch (o) {
|
||||
case OPT_EOF:
|
||||
case OPT_ERR:
|
||||
BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
|
||||
goto end;
|
||||
case OPT_HELP:
|
||||
opt_help(ech_options);
|
||||
rv = 0;
|
||||
goto end;
|
||||
case OPT_VERBOSE:
|
||||
verbose = 1;
|
||||
break;
|
||||
case OPT_TEXT:
|
||||
text = 1;
|
||||
break;
|
||||
case OPT_SELECT:
|
||||
mode = OSSL_ECH_SELPRINT_MODE;
|
||||
select = strtol(opt_arg(), NULL, 10);
|
||||
break;
|
||||
case OPT_OUT:
|
||||
outfile = opt_arg();
|
||||
outsupp = 1;
|
||||
break;
|
||||
case OPT_IN:
|
||||
mode = OSSL_ECH_SELPRINT_MODE;
|
||||
infile = opt_arg();
|
||||
if (numinfiles >= OSSL_ECH_MAXINFILES) {
|
||||
BIO_printf(bio_err, "too many input files, only %d allowed\n",
|
||||
OSSL_ECH_MAXINFILES);
|
||||
goto opthelp;
|
||||
}
|
||||
infiles[numinfiles] = infile;
|
||||
numinfiles++;
|
||||
break;
|
||||
case OPT_PUBLICNAME:
|
||||
public_name = opt_arg();
|
||||
break;
|
||||
case OPT_ECHVERSION:
|
||||
ech_version = verstr2us(opt_arg());
|
||||
break;
|
||||
case OPT_MAXNAMELENGTH:
|
||||
{
|
||||
long tmp = strtol(opt_arg(), NULL, 10);
|
||||
|
||||
if (tmp < 0 || tmp > OSSL_ECH_MAX_MAXNAMELEN) {
|
||||
BIO_printf(bio_err,
|
||||
"max name length out of range [0,%d] (%ld)\n",
|
||||
OSSL_ECH_MAX_MAXNAMELEN, tmp);
|
||||
goto opthelp;
|
||||
} else {
|
||||
max_name_length = (uint8_t)tmp;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OPT_HPKESUITE:
|
||||
suitestr = opt_arg();
|
||||
break;
|
||||
}
|
||||
}
|
||||
argc = opt_num_rest();
|
||||
argv = opt_rest();
|
||||
if (argc != 0) {
|
||||
BIO_printf(bio_err, "%s: Unknown parameter %s\n", prog, argv[0]);
|
||||
goto opthelp;
|
||||
}
|
||||
/* Check ECH-specific inputs */
|
||||
switch (ech_version) {
|
||||
case OSSL_ECH_RFCXXXX_VERSION: /* fall through */
|
||||
case 13:
|
||||
ech_version = OSSL_ECH_RFCXXXX_VERSION;
|
||||
break;
|
||||
default:
|
||||
BIO_printf(bio_err, "Un-supported version (0x%04x)\n", ech_version);
|
||||
goto end;
|
||||
}
|
||||
if (max_name_length > OSSL_ECH_MAX_MAXNAMELEN) {
|
||||
BIO_printf(bio_err, "Weird max name length (0x%04x) - biggest is "
|
||||
"(0x%04x) - exiting\n", max_name_length,
|
||||
OSSL_ECH_MAX_MAXNAMELEN);
|
||||
ERR_print_errors(bio_err);
|
||||
goto end;
|
||||
}
|
||||
if (suitestr != NULL) {
|
||||
if (OSSL_HPKE_str2suite(suitestr, &hpke_suite) != 1) {
|
||||
BIO_printf(bio_err, "Bad OSSL_HPKE_SUITE (%s)\n", suitestr);
|
||||
ERR_print_errors(bio_err);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
/* Set default if needed */
|
||||
if (outfile == NULL)
|
||||
outfile = "echconfig.pem";
|
||||
es = OSSL_ECHSTORE_new(NULL, NULL);
|
||||
if (es == NULL)
|
||||
goto end;
|
||||
if (mode == OSSL_ECH_KEYGEN_MODE) {
|
||||
if (verbose)
|
||||
BIO_printf(bio_err, "Calling OSSL_ECHSTORE_new_config\n");
|
||||
if ((ecf = BIO_new_file(outfile, "w")) == NULL
|
||||
|| OSSL_ECHSTORE_new_config(es, ech_version, max_name_length,
|
||||
public_name, hpke_suite) != 1
|
||||
|| OSSL_ECHSTORE_write_pem(es, 0, ecf) != 1) {
|
||||
BIO_printf(bio_err, "OSSL_ECHSTORE_new_config error\n");
|
||||
goto end;
|
||||
}
|
||||
if (verbose)
|
||||
BIO_printf(bio_err, "OSSL_ECHSTORE_new_config success\n");
|
||||
rv = 0;
|
||||
}
|
||||
if (mode == OSSL_ECH_SELPRINT_MODE) {
|
||||
if (numinfiles == 0)
|
||||
goto opthelp;
|
||||
for (i = 0; i != numinfiles; i++) {
|
||||
if ((ecf = BIO_new_file(infiles[i], "r")) == NULL
|
||||
|| OSSL_ECHSTORE_read_pem(es, ecf, OSSL_ECH_FOR_RETRY) != 1) {
|
||||
if (verbose)
|
||||
BIO_printf(bio_err, "OSSL_ECHSTORE_read_pem error for %s\n",
|
||||
infiles[i]);
|
||||
/* try read it as an ECHConfigList */
|
||||
goto end;
|
||||
}
|
||||
BIO_free(ecf);
|
||||
ecf = NULL;
|
||||
}
|
||||
if (verbose)
|
||||
BIO_printf(bio_err, "Success reading %d files\n", numinfiles);
|
||||
if (outsupp == 1) {
|
||||
/* write result to that, with downselection if required */
|
||||
if (verbose)
|
||||
BIO_printf(bio_err, "Will write to %s\n", outfile);
|
||||
if (verbose && select != OSSL_ECHSTORE_ALL)
|
||||
BIO_printf(bio_err, "Selected entry: %d\n", select);
|
||||
if ((ecf = BIO_new_file(outfile, "w")) == NULL
|
||||
|| OSSL_ECHSTORE_write_pem(es, select, ecf) != 1) {
|
||||
BIO_printf(bio_err, "OSSL_ECHSTORE_write_pem error\n");
|
||||
goto end;
|
||||
}
|
||||
if (verbose)
|
||||
BIO_printf(bio_err, "Success writing to %s\n", outfile);
|
||||
}
|
||||
rv = 0;
|
||||
}
|
||||
if (text) {
|
||||
int oi_ind, oi_cnt = 0;
|
||||
|
||||
if (OSSL_ECHSTORE_num_entries(es, &oi_cnt) != 1)
|
||||
goto end;
|
||||
if (verbose)
|
||||
BIO_printf(bio_err, "Printing %d ECHConfigList\n", oi_cnt);
|
||||
for (oi_ind = 0; oi_ind != oi_cnt; oi_ind++) {
|
||||
time_t secs = 0;
|
||||
char *pn = NULL, *ec = NULL;
|
||||
int has_priv, for_retry;
|
||||
|
||||
if (OSSL_ECHSTORE_get1_info(es, oi_ind, &secs, &pn, &ec,
|
||||
&has_priv, &for_retry) != 1) {
|
||||
OPENSSL_free(pn); /* just in case */
|
||||
OPENSSL_free(ec);
|
||||
goto end;
|
||||
}
|
||||
BIO_printf(bio_err, "ECH entry: %d public_name: %s age: %lld%s\n",
|
||||
oi_ind, pn, (long long)secs,
|
||||
has_priv ? " (has private key)" : "");
|
||||
BIO_printf(bio_err, "\t%s\n", ec);
|
||||
OPENSSL_free(pn);
|
||||
OPENSSL_free(ec);
|
||||
}
|
||||
if (verbose)
|
||||
BIO_printf(bio_err, "Success printing %d ECHConfigList\n", oi_cnt);
|
||||
rv = 0;
|
||||
}
|
||||
end:
|
||||
OSSL_ECHSTORE_free(es);
|
||||
BIO_free_all(ecf);
|
||||
return rv;
|
||||
opthelp:
|
||||
BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
|
||||
BIO_printf(bio_err, "\tup to %d -in instances allowed\n", OSSL_ECH_MAXINFILES);
|
||||
return rv;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -772,6 +772,10 @@ static const STRINT_PAIR tlsext_types[] = {
|
|||
{"certificate authorities", TLSEXT_TYPE_certificate_authorities},
|
||||
{"post handshake auth", TLSEXT_TYPE_post_handshake_auth},
|
||||
{"early_data", TLSEXT_TYPE_early_data},
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
{"encrypted ClientHello (draft-13)", TLSEXT_TYPE_ech},
|
||||
{"outer exts", TLSEXT_TYPE_outer_extensions},
|
||||
#endif
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -1498,6 +1498,9 @@ static void list_disabled(void)
|
|||
#ifdef OPENSSL_NO_ZSTD
|
||||
BIO_puts(bio_out, "ZSTD\n");
|
||||
#endif
|
||||
#ifdef OPENSSL_NO_ECH
|
||||
BIO_puts(bio_out, "ECH\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Unified enum for help and list commands. */
|
||||
|
|
|
@ -1340,6 +1340,7 @@ SSL_R_BAD_DH_VALUE:102:bad dh value
|
|||
SSL_R_BAD_DIGEST_LENGTH:111:bad digest length
|
||||
SSL_R_BAD_EARLY_DATA:233:bad early data
|
||||
SSL_R_BAD_ECC_CERT:304:bad ecc cert
|
||||
SSL_R_BAD_ECHCONFIG_EXTENSION:422:bad echconfig extension
|
||||
SSL_R_BAD_ECPOINT:306:bad ecpoint
|
||||
SSL_R_BAD_EXTENSION:110:bad extension
|
||||
SSL_R_BAD_HANDSHAKE_LENGTH:332:bad handshake length
|
||||
|
@ -1419,6 +1420,8 @@ SSL_R_DTLS_MESSAGE_TOO_BIG:334:dtls message too big
|
|||
SSL_R_DUPLICATE_COMPRESSION_ID:309:duplicate compression id
|
||||
SSL_R_ECC_CERT_NOT_FOR_SIGNING:318:ecc cert not for signing
|
||||
SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE:374:ecdh required for suiteb mode
|
||||
SSL_R_ECH_DECODE_ERROR:423:ech decode error
|
||||
SSL_R_ECH_REQUIRED:421:ech required
|
||||
SSL_R_EE_KEY_TOO_SMALL:399:ee key too small
|
||||
SSL_R_EMPTY_RAW_PUBLIC_KEY:349:empty raw public key
|
||||
SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST:354:empty srtp protection profile list
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# LD_LIBRARY_PATH=../.. ./sslecho
|
||||
|
||||
TESTS = sslecho
|
||||
TESTS = sslecho echecho
|
||||
|
||||
CFLAGS = -I../../include -g -Wall
|
||||
LDFLAGS = -L../..
|
||||
|
@ -14,6 +14,8 @@ all: $(TESTS)
|
|||
|
||||
sslecho: main.o
|
||||
|
||||
echecho: echecho.o
|
||||
|
||||
$(TESTS):
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LDLIBS)
|
||||
|
||||
|
|
|
@ -24,3 +24,48 @@ The cert.pem and key.pem files included are self signed certificates with the
|
|||
"Common Name" of 'localhost'.
|
||||
|
||||
Best to create the 'pem' files using an actual hostname.
|
||||
|
||||
Encrypted Client Hello (ECH) Variant
|
||||
====================================
|
||||
|
||||
``echecho.c`` implements the same functionality but demonstrates minimal code
|
||||
changes needed to use ECH. The ``echecho`` binary has the same user interface
|
||||
discussed above but enables ECH for the connection, based on hard-coded ECH
|
||||
configuration data. A real server would load file(s), and a real client would
|
||||
acquire an ECHConfigList from the DNS.
|
||||
|
||||
All that's required to use ECH is to load ECH data via `OSSL_ECHSTORE_read_*`
|
||||
APIs and then enable ECH via ``SSL_CTX_set1_echstore()``. Both client and
|
||||
server check and print out the status of ECH using ``SSL_ech_get1_status()``,
|
||||
but that's optional.
|
||||
|
||||
To run the server:
|
||||
|
||||
$ LD_LIBRARY_PATH=../.. ./echecho s
|
||||
|
||||
To run the client:
|
||||
|
||||
$ LD_LIBRARY_PATH=../.. ./echecho c localhost
|
||||
|
||||
All going well both server and client will print the ECH status at the
|
||||
start of each connection. That looks like:
|
||||
|
||||
ECH worked (status: 1, inner: localhost, outer: example.com)
|
||||
|
||||
If the non-ECH demo client (``sslecho``) is used instead the server will
|
||||
output:
|
||||
|
||||
ECH failed/not-tried (status: -101, inner: (null), outer: (null))
|
||||
|
||||
If the non-ECH demo server (i.e., ``sslecho``) is used, the client will exit
|
||||
with an error as ECH was attempted and failed. In a debug build, that looks
|
||||
like:
|
||||
|
||||
80EBEE54227F0000:error:0A000163:SSL routines:tls_process_initial_server_flight:ech required:ssl/statem/statem_clnt.c:3274:
|
||||
|
||||
A real client would likely fall back to not using ECH, but the above
|
||||
is ok for a demo.
|
||||
|
||||
In that case, the server will also exit based on the ECH alert from the client:
|
||||
|
||||
403787A8307F0000:error:0A000461:SSL routines:ssl3_read_bytes:reason(1121):../ssl/record/rec_layer_s3.c:1588:SSL alert number 121
|
||||
|
|
405
demos/sslecho/echecho.c
Normal file
405
demos/sslecho/echecho.c
Normal file
|
@ -0,0 +1,405 @@
|
|||
/*
|
||||
* Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
static const int server_port = 4433;
|
||||
|
||||
static const char echconfig[] = "AD7+DQA65wAgACA8wVN2BtscOl3vQheUzHeIkVmKIiydUhDCliA4iyQRCwAEAAEAAQALZXhhbXBsZS5jb20AAA==";
|
||||
static const char echprivbuf[] =
|
||||
"-----BEGIN PRIVATE KEY-----\n"
|
||||
"MC4CAQAwBQYDK2VuBCIEICjd4yGRdsoP9gU7YT7My8DHx1Tjme8GYDXrOMCi8v1V\n"
|
||||
"-----END PRIVATE KEY-----\n"
|
||||
"-----BEGIN ECHCONFIG-----\n"
|
||||
"AD7+DQA65wAgACA8wVN2BtscOl3vQheUzHeIkVmKIiydUhDCliA4iyQRCwAEAAEAAQALZXhhbXBsZS5jb20AAA==\n"
|
||||
"-----END ECHCONFIG-----\n";
|
||||
|
||||
typedef unsigned char bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
|
||||
/*
|
||||
* This flag won't be useful until both accept/read (TCP & SSL) methods
|
||||
* can be called with a timeout. TBD.
|
||||
*/
|
||||
static volatile bool server_running = true;
|
||||
|
||||
int create_socket(bool isServer)
|
||||
{
|
||||
int s;
|
||||
int optval = 1;
|
||||
struct sockaddr_in addr = { 0 };
|
||||
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (s < 0) {
|
||||
perror("Unable to create socket");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (isServer) {
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(server_port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
/* Reuse the address; good for quick restarts */
|
||||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))
|
||||
< 0) {
|
||||
perror("setsockopt(SO_REUSEADDR) failed");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (bind(s, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
|
||||
perror("Unable to bind");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (listen(s, 1) < 0) {
|
||||
perror("Unable to listen");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
SSL_CTX* create_context(bool isServer)
|
||||
{
|
||||
const SSL_METHOD *method;
|
||||
SSL_CTX *ctx;
|
||||
|
||||
if (isServer)
|
||||
method = TLS_server_method();
|
||||
else
|
||||
method = TLS_client_method();
|
||||
|
||||
ctx = SSL_CTX_new(method);
|
||||
if (ctx == NULL) {
|
||||
perror("Unable to create SSL context");
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static int configure_ech(SSL_CTX *ctx, int server,
|
||||
unsigned char *buf, size_t len)
|
||||
{
|
||||
OSSL_ECHSTORE *es = NULL;
|
||||
BIO *es_in = BIO_new_mem_buf(buf, len);
|
||||
|
||||
if (es_in == NULL || (es = OSSL_ECHSTORE_new(NULL, NULL)) == NULL)
|
||||
goto err;
|
||||
if (server && OSSL_ECHSTORE_read_pem(es, es_in, 1) != 1)
|
||||
goto err;
|
||||
if (!server && OSSL_ECHSTORE_read_echconfiglist(es, es_in) != 1)
|
||||
goto err;
|
||||
if (SSL_CTX_set1_echstore(ctx, es) != 1)
|
||||
goto err;
|
||||
BIO_free_all(es_in);
|
||||
return 1;
|
||||
err:
|
||||
OSSL_ECHSTORE_free(es);
|
||||
BIO_free_all(es_in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void configure_server_context(SSL_CTX *ctx)
|
||||
{
|
||||
/* Set the key and cert */
|
||||
if (SSL_CTX_use_certificate_chain_file(ctx, "cert.pem") <= 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (SSL_CTX_use_PrivateKey_file(ctx, "key.pem", SSL_FILETYPE_PEM) <= 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (configure_ech(ctx, 1, (unsigned char*)echprivbuf,
|
||||
sizeof(echprivbuf) - 1) != 1) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void configure_client_context(SSL_CTX *ctx)
|
||||
{
|
||||
/*
|
||||
* Configure the client to abort the handshake if certificate verification
|
||||
* fails
|
||||
*/
|
||||
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
|
||||
/*
|
||||
* In a real application you would probably just use the default system certificate trust store and call:
|
||||
* SSL_CTX_set_default_verify_paths(ctx);
|
||||
* In this demo though we are using a self-signed certificate, so the client must trust it directly.
|
||||
*/
|
||||
if (!SSL_CTX_load_verify_locations(ctx, "cert.pem", NULL)) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (configure_ech(ctx, 0, (unsigned char*)echconfig,
|
||||
sizeof(echconfig) - 1) != 1) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void usage()
|
||||
{
|
||||
printf("Usage: echecho s\n");
|
||||
printf(" --or--\n");
|
||||
printf(" echecho c ip\n");
|
||||
printf(" c=client, s=server, ip=dotted ip of server\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bool isServer;
|
||||
int result;
|
||||
|
||||
SSL_CTX *ssl_ctx = NULL;
|
||||
SSL *ssl = NULL;
|
||||
|
||||
int server_skt = -1;
|
||||
int client_skt = -1;
|
||||
|
||||
/* used by getline relying on realloc, can't be statically allocated */
|
||||
char *txbuf = NULL;
|
||||
size_t txcap = 0;
|
||||
int txlen;
|
||||
|
||||
char rxbuf[128];
|
||||
size_t rxcap = sizeof(rxbuf);
|
||||
int rxlen;
|
||||
|
||||
char *rem_server_ip = NULL;
|
||||
|
||||
struct sockaddr_in addr = { 0 };
|
||||
unsigned int addr_len = sizeof(addr);
|
||||
|
||||
char *outer_sni = NULL, *inner_sni = NULL;
|
||||
int ech_status;
|
||||
|
||||
/* Splash */
|
||||
printf("\nechecho : Simple Echo Client/Server: %s : %s\n\n", __DATE__,
|
||||
__TIME__);
|
||||
|
||||
/* Need to know if client or server */
|
||||
if (argc < 2) {
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
isServer = (argv[1][0] == 's') ? true : false;
|
||||
/* If client get remote server address (could be 127.0.0.1) */
|
||||
if (!isServer) {
|
||||
if (argc != 3) {
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
rem_server_ip = argv[2];
|
||||
}
|
||||
|
||||
/* Create context used by both client and server */
|
||||
ssl_ctx = create_context(isServer);
|
||||
|
||||
/* If server */
|
||||
if (isServer) {
|
||||
|
||||
printf("We are the server on port: %d\n\n", server_port);
|
||||
|
||||
/* Configure server context with appropriate key files */
|
||||
configure_server_context(ssl_ctx);
|
||||
|
||||
/* Create server socket; will bind with server port and listen */
|
||||
server_skt = create_socket(true);
|
||||
|
||||
/*
|
||||
* Loop to accept clients.
|
||||
* Need to implement timeouts on TCP & SSL connect/read functions
|
||||
* before we can catch a CTRL-C and kill the server.
|
||||
*/
|
||||
while (server_running) {
|
||||
/* Wait for TCP connection from client */
|
||||
client_skt = accept(server_skt, (struct sockaddr*) &addr,
|
||||
&addr_len);
|
||||
if (client_skt < 0) {
|
||||
perror("Unable to accept");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
printf("Client TCP connection accepted\n");
|
||||
|
||||
/* Create server SSL structure using newly accepted client socket */
|
||||
ssl = SSL_new(ssl_ctx);
|
||||
SSL_set_fd(ssl, client_skt);
|
||||
|
||||
/* Wait for SSL connection from the client */
|
||||
if (SSL_accept(ssl) <= 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
server_running = false;
|
||||
} else {
|
||||
|
||||
printf("Client SSL connection accepted\n\n");
|
||||
|
||||
ech_status = SSL_ech_get1_status(ssl, &inner_sni, &outer_sni);
|
||||
printf("ECH %s (status: %d, inner: %s, outer: %s)\n",
|
||||
(ech_status == 1 ? "worked" : "failed/not-tried"),
|
||||
ech_status, inner_sni, outer_sni);
|
||||
OPENSSL_free(inner_sni);
|
||||
OPENSSL_free(outer_sni);
|
||||
inner_sni = outer_sni = NULL;
|
||||
|
||||
/* Echo loop */
|
||||
while (true) {
|
||||
/* Get message from client; will fail if client closes connection */
|
||||
if ((rxlen = SSL_read(ssl, rxbuf, rxcap)) <= 0) {
|
||||
if (rxlen == 0) {
|
||||
printf("Client closed connection\n");
|
||||
}
|
||||
ERR_print_errors_fp(stderr);
|
||||
break;
|
||||
}
|
||||
/* Insure null terminated input */
|
||||
rxbuf[rxlen] = 0;
|
||||
/* Look for kill switch */
|
||||
if (strcmp(rxbuf, "kill\n") == 0) {
|
||||
/* Terminate...with extreme prejudice */
|
||||
printf("Server received 'kill' command\n");
|
||||
server_running = false;
|
||||
break;
|
||||
}
|
||||
/* Show received message */
|
||||
printf("Received: %s", rxbuf);
|
||||
/* Echo it back */
|
||||
if (SSL_write(ssl, rxbuf, rxlen) <= 0) {
|
||||
ERR_print_errors_fp(stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (server_running) {
|
||||
/* Cleanup for next client */
|
||||
SSL_shutdown(ssl);
|
||||
SSL_free(ssl);
|
||||
close(client_skt);
|
||||
}
|
||||
}
|
||||
printf("Server exiting...\n");
|
||||
}
|
||||
/* Else client */
|
||||
else {
|
||||
|
||||
printf("We are the client\n\n");
|
||||
|
||||
/* Configure client context so we verify the server correctly */
|
||||
configure_client_context(ssl_ctx);
|
||||
|
||||
/* Create "bare" socket */
|
||||
client_skt = create_socket(false);
|
||||
/* Set up connect address */
|
||||
addr.sin_family = AF_INET;
|
||||
inet_pton(AF_INET, rem_server_ip, &addr.sin_addr.s_addr);
|
||||
addr.sin_port = htons(server_port);
|
||||
/* Do TCP connect with server */
|
||||
if (connect(client_skt, (struct sockaddr*) &addr, sizeof(addr)) != 0) {
|
||||
perror("Unable to TCP connect to server");
|
||||
goto exit;
|
||||
} else {
|
||||
printf("TCP connection to server successful\n");
|
||||
}
|
||||
|
||||
/* Create client SSL structure using dedicated client socket */
|
||||
ssl = SSL_new(ssl_ctx);
|
||||
SSL_set_fd(ssl, client_skt);
|
||||
/* Set hostname for SNI */
|
||||
SSL_set_tlsext_host_name(ssl, rem_server_ip);
|
||||
/* Configure server hostname check */
|
||||
SSL_set1_host(ssl, rem_server_ip);
|
||||
|
||||
/* Now do SSL connect with server */
|
||||
if (SSL_connect(ssl) == 1) {
|
||||
|
||||
printf("SSL connection to server successful\n\n");
|
||||
|
||||
ech_status = SSL_ech_get1_status(ssl, &inner_sni, &outer_sni);
|
||||
printf("ECH %s (status: %d, inner: %s, outer: %s)\n",
|
||||
(ech_status == 1 ? "worked" : "failed/not-tried"),
|
||||
ech_status, inner_sni, outer_sni);
|
||||
OPENSSL_free(inner_sni);
|
||||
OPENSSL_free(outer_sni);
|
||||
inner_sni = outer_sni = NULL;
|
||||
|
||||
/* Loop to send input from keyboard */
|
||||
while (true) {
|
||||
/* Get a line of input */
|
||||
txlen = getline(&txbuf, &txcap, stdin);
|
||||
/* Exit loop on error */
|
||||
if (txlen < 0 || txbuf == NULL) {
|
||||
break;
|
||||
}
|
||||
/* Exit loop if just a carriage return */
|
||||
if (txbuf[0] == '\n') {
|
||||
break;
|
||||
}
|
||||
/* Send it to the server */
|
||||
if ((result = SSL_write(ssl, txbuf, txlen)) <= 0) {
|
||||
printf("Server closed connection\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Wait for the echo */
|
||||
rxlen = SSL_read(ssl, rxbuf, rxcap);
|
||||
if (rxlen <= 0) {
|
||||
printf("Server closed connection\n");
|
||||
ERR_print_errors_fp(stderr);
|
||||
break;
|
||||
} else {
|
||||
/* Show it */
|
||||
rxbuf[rxlen] = 0;
|
||||
printf("Received: %s", rxbuf);
|
||||
}
|
||||
}
|
||||
printf("Client exiting...\n");
|
||||
} else {
|
||||
|
||||
printf("SSL connection to server failed\n\n");
|
||||
|
||||
ERR_print_errors_fp(stderr);
|
||||
}
|
||||
}
|
||||
exit:
|
||||
/* Close up */
|
||||
if (ssl != NULL) {
|
||||
SSL_shutdown(ssl);
|
||||
SSL_free(ssl);
|
||||
}
|
||||
SSL_CTX_free(ssl_ctx);
|
||||
|
||||
if (client_skt != -1)
|
||||
close(client_skt);
|
||||
if (server_skt != -1)
|
||||
close(server_skt);
|
||||
|
||||
if (txbuf != NULL && txcap > 0)
|
||||
free(txbuf);
|
||||
|
||||
printf("echecho exiting\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -82,6 +82,12 @@ DEPEND[man/man1/openssl-ec.1]=man1/openssl-ec.pod
|
|||
GENERATE[man/man1/openssl-ec.1]=man1/openssl-ec.pod
|
||||
DEPEND[man1/openssl-ec.pod]{pod}=man1/openssl-ec.pod.in
|
||||
GENERATE[man1/openssl-ec.pod]=man1/openssl-ec.pod.in
|
||||
DEPEND[html/man1/openssl-ech.html]=man1/openssl-ech.pod
|
||||
GENERATE[html/man1/openssl-ech.html]=man1/openssl-ech.pod
|
||||
DEPEND[man/man1/openssl-ech.1]=man1/openssl-ech.pod
|
||||
GENERATE[man/man1/openssl-ech.1]=man1/openssl-ech.pod
|
||||
DEPEND[man1/openssl-ech.pod]{pod}=man1/openssl-ech.pod.in
|
||||
GENERATE[man1/openssl-ech.pod]=man1/openssl-ech.pod.in
|
||||
DEPEND[html/man1/openssl-ecparam.html]=man1/openssl-ecparam.pod
|
||||
GENERATE[html/man1/openssl-ecparam.html]=man1/openssl-ecparam.pod
|
||||
DEPEND[man/man1/openssl-ecparam.1]=man1/openssl-ecparam.pod
|
||||
|
@ -361,6 +367,7 @@ html/man1/openssl-dhparam.html \
|
|||
html/man1/openssl-dsa.html \
|
||||
html/man1/openssl-dsaparam.html \
|
||||
html/man1/openssl-ec.html \
|
||||
html/man1/openssl-ech.html \
|
||||
html/man1/openssl-ecparam.html \
|
||||
html/man1/openssl-enc.html \
|
||||
html/man1/openssl-engine.html \
|
||||
|
@ -421,6 +428,7 @@ man/man1/openssl-dhparam.1 \
|
|||
man/man1/openssl-dsa.1 \
|
||||
man/man1/openssl-dsaparam.1 \
|
||||
man/man1/openssl-ec.1 \
|
||||
man/man1/openssl-ech.1 \
|
||||
man/man1/openssl-ecparam.1 \
|
||||
man/man1/openssl-enc.1 \
|
||||
man/man1/openssl-engine.1 \
|
||||
|
@ -2739,6 +2747,10 @@ DEPEND[html/man3/SSL_session_reused.html]=man3/SSL_session_reused.pod
|
|||
GENERATE[html/man3/SSL_session_reused.html]=man3/SSL_session_reused.pod
|
||||
DEPEND[man/man3/SSL_session_reused.3]=man3/SSL_session_reused.pod
|
||||
GENERATE[man/man3/SSL_session_reused.3]=man3/SSL_session_reused.pod
|
||||
DEPEND[html/man3/SSL_set1_echstore.html]=man3/SSL_set1_echstore.pod
|
||||
GENERATE[html/man3/SSL_set1_echstore.html]=man3/SSL_set1_echstore.pod
|
||||
DEPEND[man/man3/SSL_set1_echstore.3]=man3/SSL_set1_echstore.pod
|
||||
GENERATE[man/man3/SSL_set1_echstore.3]=man3/SSL_set1_echstore.pod
|
||||
DEPEND[html/man3/SSL_set1_host.html]=man3/SSL_set1_host.pod
|
||||
GENERATE[html/man3/SSL_set1_host.html]=man3/SSL_set1_host.pod
|
||||
DEPEND[man/man3/SSL_set1_host.3]=man3/SSL_set1_host.pod
|
||||
|
@ -3692,6 +3704,7 @@ html/man3/SSL_read.html \
|
|||
html/man3/SSL_read_early_data.html \
|
||||
html/man3/SSL_rstate_string.html \
|
||||
html/man3/SSL_session_reused.html \
|
||||
html/man3/SSL_set1_echstore.html \
|
||||
html/man3/SSL_set1_host.html \
|
||||
html/man3/SSL_set1_initial_peer_addr.html \
|
||||
html/man3/SSL_set1_server_cert_type.html \
|
||||
|
@ -4356,6 +4369,7 @@ man/man3/SSL_read.3 \
|
|||
man/man3/SSL_read_early_data.3 \
|
||||
man/man3/SSL_rstate_string.3 \
|
||||
man/man3/SSL_session_reused.3 \
|
||||
man/man3/SSL_set1_echstore.3 \
|
||||
man/man3/SSL_set1_host.3 \
|
||||
man/man3/SSL_set1_initial_peer_addr.3 \
|
||||
man/man3/SSL_set1_server_cert_type.3 \
|
||||
|
|
645
doc/designs/ech-api.md
Normal file
645
doc/designs/ech-api.md
Normal file
|
@ -0,0 +1,645 @@
|
|||
Encrypted ClientHello (ECH) APIs
|
||||
================================
|
||||
|
||||
TODO(ECH): replace references/links to the [sftcd
|
||||
ECH-draft-13c](https://github.com/sftcd/openssl/tree/ECH-draft-13c) (the branch
|
||||
that has good integration and interop) with relative links as files are
|
||||
migrated into (PRs for) the feature branch.
|
||||
|
||||
The `OSSL_ECHSTORE` related text here matches the ECH
|
||||
[feature branch](https://github.com/openssl/openssl/tree/feature/ech).
|
||||
|
||||
There is an [OpenSSL fork](https://github.com/sftcd/openssl/tree/ECH-draft-13c)
|
||||
that has an implementation of Encrypted Client Hello (ECH) and these are design
|
||||
notes taking the APIs implemented there as a starting point.
|
||||
|
||||
The ECH Protocol
|
||||
----------------
|
||||
|
||||
ECH involves creating an "inner" ClientHello (CH) that contains the potentially
|
||||
sensitive content of a CH, primarily the SNI and perhaps the ALPN values. That
|
||||
inner CH is then encrypted and embedded (as a CH extension) in an outer CH that
|
||||
contains presumably less sensitive values. The spec includes a "compression"
|
||||
scheme that allows the inner CH to refer to extensions from the outer CH where
|
||||
the same value would otherwise be present in both.
|
||||
|
||||
ECH makes use of [HPKE](https://datatracker.ietf.org/doc/rfc9180/) for the
|
||||
encryption of the inner CH. HPKE code was merged to the master branch in
|
||||
November 2022.
|
||||
|
||||
The ECH APIs are also documented
|
||||
[here](https://github.com/sftcd/openssl/blob/ECH-draft-13c/doc/man3/SSL_ech_set1_echconfig.pod).
|
||||
The descriptions here are less formal and provide some justification for the
|
||||
API design.
|
||||
|
||||
Unless otherwise stated all APIs return 1 in the case of success and 0 for
|
||||
error. All APIs call `SSLfatal` or `ERR_raise` macros as appropriate before
|
||||
returning an error.
|
||||
|
||||
Prototypes are mostly in
|
||||
[`include/openssl/ech.h`](https://github.com/sftcd/openssl/blob/ECH-draft-13c/include/openssl/ech.h)
|
||||
for now.
|
||||
|
||||
General Approach
|
||||
----------------
|
||||
|
||||
This ECH implementation has been prototyped via integrations with curl, apache2,
|
||||
lighttpd, nginx and haproxy. The implementation interoperates with all other
|
||||
known ECH implementations, including browsers, the libraries they use
|
||||
(NSS/BoringSSL), a closed-source server implementation (Cloudflare's test
|
||||
server) and with wolfssl and (reportedly) a rusttls client.
|
||||
|
||||
To date, the approach taken has been to minimise the application layer code
|
||||
changes required to ECH-enable those applications. There is of course a tension
|
||||
between that minimisation goal and providing generic and future-proof
|
||||
interfaces.
|
||||
|
||||
In terms of implementation, it is expected (and welcome) that many details of
|
||||
the current ECH implementation will change during review.
|
||||
|
||||
Specification
|
||||
-------------
|
||||
|
||||
ECH is an IETF TLS WG specification. It has been stable since
|
||||
[draft-13](https://datatracker.ietf.org/doc/draft-ietf-tls-esni/13/), published
|
||||
in August 2021. The latest draft can be found
|
||||
[here](https://datatracker.ietf.org/doc/draft-ietf-tls-esni/).
|
||||
|
||||
Once browsers and others have done sufficient testing the plan is to
|
||||
proceed to publishing ECH as an RFC.
|
||||
|
||||
The only current ECHConfig version supported is 0xfe0d which will be the
|
||||
value to be used in the eventual RFC when that issues. (We'll replace the
|
||||
XXXX with the relevant RFC number once that's known.)
|
||||
|
||||
```c
|
||||
/* version from RFC XXXX */
|
||||
# define OSSL_ECH_RFCXXXX_VERSION 0xfe0d
|
||||
/* latest version from an RFC */
|
||||
# define OSSL_ECH_CURRENT_VERSION OSSL_ECH_RFCXXXX_VERSION
|
||||
```
|
||||
|
||||
Note that 0xfe0d is also the value of the ECH extension codepoint:
|
||||
|
||||
```c
|
||||
# define TLSEXT_TYPE_ech 0xfe0d
|
||||
```
|
||||
|
||||
The uses of those should be correctly differentiated in the implementation, to
|
||||
more easily avoid problems if/when new versions are defined.
|
||||
|
||||
Minimal Sample Code
|
||||
-------------------
|
||||
|
||||
TODO(ECH): This sample code has only been compiled. The `OSSL_ECHSTORE` stuff
|
||||
doesn't work yet.
|
||||
|
||||
OpenSSL includes code for an [`sslecho`](../../demos/sslecho) demo. We've
|
||||
added a minimal [`echecho`](../../demos/sslecho/echecho.c) that shows how to
|
||||
ECH-enable this demo.
|
||||
|
||||
Handling Custom Extensions
|
||||
--------------------------
|
||||
|
||||
OpenSSL supports custom extensions (via `SSL_CTX_add_custom_ext()`) so that
|
||||
extension values are supplied and parsed by client and server applications via
|
||||
a callback. The ECH specification of course doesn't deal with such
|
||||
implementation matters, but comprehensive ECH support for such custom
|
||||
extensions could quickly become complex. At present, in the absence of evidence
|
||||
of sensitive custom extension values, we handle all such extensions by using
|
||||
the ECH compression mechanism. That means we require no API changes, only make
|
||||
one call to the application callbacks and get interoperability, but that such
|
||||
extension values remain visible to network observers. That could change if some
|
||||
custom value turns out to be sensitive such that we'd prefer to not include it
|
||||
in the outer CH.
|
||||
|
||||
Padding
|
||||
-------
|
||||
|
||||
The privacy protection provided by ECH benefits from an observer not being able
|
||||
to differentiate access to different web origins based on TLS handshake
|
||||
packets. Some TLS handshake messages can however reduce the size of the
|
||||
anonymity-set due to message-sizes. In particular the Certificate message size
|
||||
will depend on the name of the SNI from the inner ClientHello. TLS however does
|
||||
allow for record layer padding which can reduce the impact of underlying
|
||||
message sizes on the size of the anonymity set. The recently added
|
||||
`SSL_CTX_record_padding_ex()` and `SSL_record_padding_ex()` APIs allow for
|
||||
setting separate padding sizes for the handshake messages, (that most affect
|
||||
ECH), and application data messages (where padding may affect efficiency more).
|
||||
|
||||
ECHConfig Extensions
|
||||
--------------------
|
||||
|
||||
The ECH protocol supports extensibility [within the ECHConfig
|
||||
structure](https://www.ietf.org/archive/id/draft-ietf-tls-esni-18.html#section-4.2)
|
||||
via a typical TLS type, length, value scheme. However, to date, there are no
|
||||
extensions defined, nor do other implementations provide APIs for adding or
|
||||
manipulating ECHConfig extensions. We therefore take the same approach here.
|
||||
|
||||
When running the ECH protocol, implementations are required to skip over
|
||||
unknown ECHConfig extensions, or to fail for so-called "mandatory" unsupported
|
||||
ECHConfig extensions. Our library code is compliant in that respect - it will
|
||||
skip over extensions that are not "mandatory" (extension type high bit clear)
|
||||
and fail if any "mandatory" ECHConfig extension (extension type high bit set)
|
||||
is seen.
|
||||
|
||||
For testing purposes, ECHConfigList values that contain ECHConfig extensions
|
||||
can be produced using external scripts, and used with the library, but there is
|
||||
no API support for generating such, and the library has no support for any
|
||||
specific ECHConfig extension type. (Other than skipping over or failing as
|
||||
described above.)
|
||||
|
||||
In general, the ECHConfig extensibility mechanism seems to have no proven
|
||||
utility. (If new fields for an ECHConfig are required, a new ECHConfig version
|
||||
with the proposed changes can just as easily be developed/deployed.)
|
||||
|
||||
The theory for ECHConfig extensions is that such values might be used to
|
||||
control the outer ClientHello - controls to affect the inner ClientHello, when
|
||||
ECH is used, are envisaged to be published as SvcParamKey values in SVCB/HTTP
|
||||
resource records in the DNS.
|
||||
|
||||
To repeat though: after a number of years of the development of ECH, no such
|
||||
ECHConfig extensions have been proposed.
|
||||
|
||||
Should some useful ECHConfig extensions be defined in future, then the
|
||||
`OSSL_ECHSTORE` APIs could be extended to enable management of such, or, new
|
||||
opaque types could be developed enabling further manipulation of ECHConfig and
|
||||
ECHConfigList values.
|
||||
|
||||
ECH keys versus TLS server keys
|
||||
-------------------------------
|
||||
|
||||
ECH private keys are similar to, but different from, TLS server private keys
|
||||
used to authenticate servers. Notably:
|
||||
|
||||
- ECH private keys are expected to be rotated roughly hourly, rather than every
|
||||
month or two for TLS server private keys. Hourly ECH key rotation is an
|
||||
attempt to provide better forward secrecy, given ECH implements an
|
||||
ephemeral-static ECDH scheme.
|
||||
|
||||
- ECH private keys stand alone - there are no hierarchies and there is no
|
||||
chaining, and no certificates and no defined relationships between current
|
||||
and older ECH private keys. The expectation is that a "current" ECH public key
|
||||
will be published in the DNS and that plus approx. 2 "older" ECH private keys
|
||||
will remain usable for decryption at any given time. This is a way to balance
|
||||
DNS TTLs versus forward secrecy and robustness.
|
||||
|
||||
- In particular, the above means that we do not see any need to repeatedly
|
||||
parse or process related ECHConfigList structures - each can be processed
|
||||
independently for all practical purposes.
|
||||
|
||||
- There are all the usual algorithm variations, and those will likely result in
|
||||
the same x25519 versus p256 combinatorics. How that plays out has yet to be
|
||||
seen as FIPS compliance for ECH is not (yet) a thing. For OpenSSL, it seems
|
||||
wise to be agnostic and support all relevant combinations. (And doing so is not
|
||||
that hard.)
|
||||
|
||||
ECH Store APIs
|
||||
--------------
|
||||
|
||||
We introduce an externally opaque type `OSSL_ECHSTORE` to allow applications
|
||||
to create and manage ECHConfigList values and associated meta-data. The
|
||||
external APIs using `OSSL_ECHSTORE` are:
|
||||
|
||||
```c
|
||||
typedef struct ossl_echstore_st OSSL_ECHSTORE;
|
||||
|
||||
/* if a caller wants to index the last entry in the store */
|
||||
# define OSSL_ECHSTORE_LAST -1
|
||||
/* if a caller wants all entries in the store, e.g. to print public values */
|
||||
# define OSSL_ECHSTORE_ALL -2
|
||||
|
||||
OSSL_ECHSTORE *OSSL_ECHSTORE_new(OSSL_LIB_CTX *libctx, const char *propq);
|
||||
void OSSL_ECHSTORE_free(OSSL_ECHSTORE *es);
|
||||
int OSSL_ECHSTORE_new_config(OSSL_ECHSTORE *es,
|
||||
uint16_t echversion, uint8_t max_name_length,
|
||||
const char *public_name, OSSL_HPKE_SUITE suite);
|
||||
int OSSL_ECHSTORE_write_pem(OSSL_ECHSTORE *es, int index, BIO *out);
|
||||
|
||||
int OSSL_ECHSTORE_read_echconfiglist(OSSL_ECHSTORE *es, BIO *in);
|
||||
|
||||
int OSSL_ECHSTORE_get1_info(OSSL_ECHSTORE *es, int index, time_t *loaded_secs,
|
||||
char **public_name, char **echconfig,
|
||||
int *has_private, int *for_retry);
|
||||
int OSSL_ECHSTORE_downselect(OSSL_ECHSTORE *es, int index);
|
||||
|
||||
int OSSL_ECHSTORE_set1_key_and_read_pem(OSSL_ECHSTORE *es, EVP_PKEY *priv,
|
||||
BIO *in, int for_retry);
|
||||
int OSSL_ECHSTORE_read_pem(OSSL_ECHSTORE *es, BIO *in, int for_retry);
|
||||
int OSSL_ECHSTORE_num_entries(OSSL_ECHSTORE *es, int *numentries);
|
||||
int OSSL_ECHSTORE_num_keys(OSSL_ECHSTORE *es, int *numkeys);
|
||||
int OSSL_ECHSTORE_flush_keys(OSSL_ECHSTORE *es, time_t age);
|
||||
```
|
||||
|
||||
`OSSL_ECHSTORE_new()` and `OSSL_ECHSTORE_free()` are relatively obvious.
|
||||
|
||||
`OSSL_ECHSTORE_new_config()` allows the caller to create a new private key
|
||||
value and the related "singleton" ECHConfigList structure.
|
||||
`OSSL_ECHSTORE_write_pem()` allows the caller to produce a "PEM" data
|
||||
structure (conforming to the [PEMECH
|
||||
specification](https://datatracker.ietf.org/doc/draft-farrell-tls-pemesni/))
|
||||
from the `OSSL_ECHSTORE` entry identified by the `index`. (An `index` of
|
||||
`OSSL_ECHSTORE_LAST` will select the last entry. An `index` of
|
||||
`OSSL_ECHSTORE_ALL` will output all public values, and no private values.)
|
||||
These two APIs will typically be used via the `openssl ech` command line tool.
|
||||
|
||||
`OSSL_ECHSTORE_read_echconfiglist()` will typically be used by a client to
|
||||
ingest the "ech=" SvcParamKey value found in an SVCB or HTTPS RR retrieved from
|
||||
the DNS. The resulting set of ECHConfig values can then be associated with an
|
||||
`SSL_CTX` or `SSL` structure for TLS connections.
|
||||
|
||||
`OSSL_ECHSTORE_get1_info()` presents the caller with information about the
|
||||
content of the store for logging or for display, e.g. in a command line tool.
|
||||
`OSSL_ECHSTORE_downselect()` API gives the client a way to select one
|
||||
particular ECHConfig value from the set stored (discarding the rest).
|
||||
|
||||
`OSSL_ECHSTORE_set1_key_and_read_pem()` and `OSSL_ECHSTORE_read_pem()` can be
|
||||
used to load a private key value and associated "singleton" ECHConfigList.
|
||||
Those can be used (by servers) to enable ECH for an `SSL_CTX` or `SSL`
|
||||
connection. In addition to loading those values, the application can also
|
||||
indicate via `for_retry` which ECHConfig value(s) are to be included in the
|
||||
`retry_configs` fallback scheme defined by the ECH protocol.
|
||||
|
||||
`OSSL_ECHSTORE_num_entries()` and `OSSL_ECHSTORE_num_keys()` allow an
|
||||
application to see how many usable ECH configs and private keys are currently
|
||||
in the store, and `OSSL_ECHSTORE_flush_keys()` allows a server to flush keys
|
||||
that are older than `age` seconds. The general model is that a server can
|
||||
maintain an `OSSL_ECHSTORE` into which it periodically loads the "latest" set
|
||||
of keys, e.g. hourly, and also discards the keys that are too old, e.g. more
|
||||
than 3 hours old. This allows for more robust private key management even if
|
||||
public key distribution suffers temporary failures.
|
||||
|
||||
The APIs the clients and servers can use to associate an `OSSL_ECHSTORE`
|
||||
with an `SSL_CTX` or `SSL` structure:
|
||||
|
||||
```c
|
||||
int SSL_CTX_set1_echstore(SSL_CTX *ctx, OSSL_ECHSTORE *es);
|
||||
int SSL_set1_echstore(SSL *s, OSSL_ECHSTORE *es);
|
||||
```
|
||||
|
||||
ECH will be enabled for the relevant `SSL_CTX` or `SSL` connection
|
||||
when these functions succeed. Any previously associated `OSSL_ECHSTORE`
|
||||
will be `OSSL_ECHSTORE_free()`ed.
|
||||
|
||||
There is also an API that allows setting an ECHConfigList for an SSL
|
||||
connection, that is compatible with BoringSSL. Note that the input
|
||||
`ecl` here can be either base64 or binary encoded, but for
|
||||
BoringSSL it must be binary encoded.
|
||||
|
||||
```c
|
||||
int SSL_set1_ech_config_list(SSL *ssl, const uint8_t *ecl, size_t ecl_len);
|
||||
```
|
||||
|
||||
To access the `OSSL_ECHSTORE` associated with an `SSL_CTX` or
|
||||
`SSL` connection:
|
||||
|
||||
```c
|
||||
OSSL_ECHSTORE *SSL_CTX_get1_echstore(const SSL_CTX *ctx);
|
||||
OSSL_ECHSTORE *SSL_get1_echstore(const SSL *s);
|
||||
```
|
||||
|
||||
The resulting `OSSL_ECHSTORE` can be modified and then re-associated
|
||||
with an `SSL_CTX` or `SSL` connection.
|
||||
|
||||
ECH Store Internals
|
||||
-------------------
|
||||
|
||||
The internal structure of an ECH Store is as described below:
|
||||
|
||||
```c
|
||||
typedef struct ossl_echext_st {
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
unsigned char *val;
|
||||
} OSSL_ECHEXT;
|
||||
|
||||
DEFINE_STACK_OF(OSSL_ECHEXT)
|
||||
|
||||
typedef struct ossl_echstore_entry_st {
|
||||
uint16_t version; /* 0xff0d for draft-13 */
|
||||
char *public_name;
|
||||
size_t pub_len;
|
||||
unsigned char *pub;
|
||||
unsigned int nsuites;
|
||||
OSSL_HPKE_SUITE *suites;
|
||||
uint8_t max_name_length;
|
||||
uint8_t config_id;
|
||||
STACK_OF(OSSL_ECHEXT) *exts;
|
||||
time_t loadtime; /* time public and private key were loaded from file */
|
||||
EVP_PKEY *keyshare; /* long(ish) term ECH private keyshare on a server */
|
||||
int for_retry; /* whether to use this ECHConfigList in a retry */
|
||||
size_t encoded_len; /* length of overall encoded content */
|
||||
unsigned char *encoded; /* overall encoded content */
|
||||
} OSSL_ECHSTORE_ENTRY;
|
||||
|
||||
DEFINE_STACK_OF(OSSL_ECHSTORE_ENTRY)
|
||||
|
||||
struct ossl_echstore_st {
|
||||
STACK_OF(OSSL_ECHSTORE_ENTRY) *entries;
|
||||
OSSL_LIB_CTX *libctx;
|
||||
const char *propq;
|
||||
};
|
||||
```
|
||||
|
||||
Some notes on the above ECHConfig fields:
|
||||
|
||||
- `version` should be `OSSL_ECH_CURRENT_VERSION` for the current version.
|
||||
|
||||
- `public_name` field is the name used in the SNI of the outer ClientHello, and
|
||||
that a server ought be able to authenticate if using the `retry_configs`
|
||||
fallback mechanism.
|
||||
|
||||
- `config_id` is a one-octet value used by servers to select which private
|
||||
value to use to attempt ECH decryption. Servers can also do trial decryption
|
||||
if desired, as clients might use a random value for the `confid_id` as an
|
||||
anti-fingerprinting mechanism. (The use of one octet for this value was the
|
||||
result of an extended debate about efficiency versus fingerprinting.)
|
||||
|
||||
- The `max_name_length` is an element of the ECHConfigList that is used by
|
||||
clients as part of a padding algorithm. (That design is part of the spec, but
|
||||
isn't necessarily great - the idea is to include the longest value that might
|
||||
be the length of a DNS name included as an inner CH SNI.) A value of 0 is
|
||||
perhaps most likely to be used, indicating that the maximum isn't known.
|
||||
|
||||
Essentially, an ECH store is a set of ECHConfig values, plus optionally
|
||||
(for servers), relevant private key value information.
|
||||
|
||||
When a non-singleton ECHConfigList is ingested, that is expanded into
|
||||
a store that is the same as if a set of singleton ECHConfigList values
|
||||
had been ingested sequentially.
|
||||
|
||||
In addition to the obvious fields from each ECHConfig, we also store:
|
||||
|
||||
- The `encoded` value (and length) of the ECHConfig, as that is used
|
||||
as an input for the HPKE encapsulation of the inner ClientHello. (Used
|
||||
by both clients and servers.)
|
||||
|
||||
- The `EVP_PKEY` pointer to the private key value associated with the
|
||||
relevant ECHConfig, for use by servers.
|
||||
|
||||
- The PEM filename and file modification time from which a private key value
|
||||
and ECHConfigList were loaded. If those values are loaded from memory,
|
||||
the filename value is the SHA-256 hash of the encoded ECHConfigList and
|
||||
the load time is the time of loading. These values assist when servers
|
||||
periodically re-load sets of files or PEM structures from memory.
|
||||
|
||||
Split-mode handling
|
||||
-------------------
|
||||
|
||||
TODO(ECH): This ECH split-mode API should be considered tentative. It's design
|
||||
will be revisited as we get to considering the internals.
|
||||
|
||||
ECH split-mode involves a front-end server that only does ECH decryption and
|
||||
then passes on the decrypted inner CH to a back-end TLS server that negotiates
|
||||
the actual TLS session with the client, based on the inner CH content. The
|
||||
function to support this simply takes the outer CH, indicates whether
|
||||
decryption has succeeded or not, and if it has, returns the inner CH and SNI
|
||||
values (allowing routing to the correct back-end). Both the supplied (outer)
|
||||
CH and returned (inner) CH here include the record layer header.
|
||||
|
||||
```c
|
||||
int SSL_CTX_ech_raw_decrypt(SSL_CTX *ctx,
|
||||
int *decrypted_ok,
|
||||
char **inner_sni, char **outer_sni,
|
||||
unsigned char *outer_ch, size_t outer_len,
|
||||
unsigned char *inner_ch, size_t *inner_len,
|
||||
unsigned char **hrrtok, size_t *toklen);
|
||||
```
|
||||
|
||||
The caller allocates the `inner_ch` buffer, on input `inner_len` should
|
||||
contain the size of the `inner_ch` buffer, on output the size of the actual
|
||||
inner CH. Note that, when ECH decryption succeeds, the inner CH will always be
|
||||
smaller than the outer CH.
|
||||
|
||||
If there is no ECH present in the outer CH then this will return 1 (i.e., the
|
||||
call will succeed) but `decrypted_ok` will be zero. The same will result if a
|
||||
GREASEd ECH is present or decryption fails for some other (indistinguishable)
|
||||
reason.
|
||||
|
||||
If the caller wishes to support HelloRetryRequest (HRR), then it must supply
|
||||
the same `hrrtok` and `toklen` pointers to both calls to
|
||||
`SSL_CTX_ech_raw_decrypt()` (for the initial and second ClientHello
|
||||
messages). When done, the caller must free the `hrrtok` using
|
||||
`OPENSSL_free()`. If the caller doesn't need to support HRR, then it can
|
||||
supply NULL values for these parameters. The value of the token is the client's
|
||||
ephemeral public value, which is not sensitive having being sent in clear in
|
||||
the first ClientHello. This value is missing from the second ClientHello but
|
||||
is needed for ECH decryption.
|
||||
|
||||
Note that `SSL_CTX_ech_raw_decrypt()` only takes a ClientHello as input. If
|
||||
the flight containing the ClientHello contains other messages (e.g. a
|
||||
ChangeCipherSuite or Early data), then the caller is responsible for
|
||||
disentangling those, and for assembling a new flight containing the inner
|
||||
ClientHello.
|
||||
|
||||
Different encodings
|
||||
-------------------
|
||||
|
||||
ECHConfigList values may be provided via a command line argument to the calling
|
||||
application or (more likely) have been retrieved from DNS resource records by
|
||||
the application. ECHConfigList values may be provided in various encodings
|
||||
(base64 or binary) each of which may suit different applications.
|
||||
|
||||
If the input contains more than one (syntactically correct) ECHConfigList, then only
|
||||
those that contain locally supported options (e.g. AEAD ciphers) will be
|
||||
returned. If no ECHConfigList found has supported options then none will be
|
||||
returned and the function will return NULL.
|
||||
|
||||
Additional Client Controls
|
||||
--------------------------
|
||||
|
||||
Clients can additionally more directly control the values to be used for inner
|
||||
and outer SNI and ALPN values via specific APIs. This allows a client to
|
||||
override the `public_name` present in an ECHConfigList that will otherwise
|
||||
be used for the outer SNI. The `no_outer` input allows a client to emit an
|
||||
outer CH with no SNI at all. Providing a `NULL` for the `outer_name` means
|
||||
to send the `public_name` provided from the ECHConfigList.
|
||||
|
||||
```c
|
||||
int SSL_ech_set1_server_names(SSL *s, const char *inner_name,
|
||||
const char *outer_name, int no_outer);
|
||||
int SSL_ech_set1_outer_server_name(SSL *s, const char *outer_name, int no_outer);
|
||||
int SSL_ech_set1_outer_alpn_protos(SSL *s, const unsigned char *protos,
|
||||
size_t protos_len);
|
||||
int SSL_CTX_ech_set1_outer_alpn_protos(SSL_CTX *s, const unsigned char *protos,
|
||||
size_t protos_len);
|
||||
```
|
||||
|
||||
If a client attempts ECH but that fails, or sends an ECH-GREASEd CH, to
|
||||
an ECH-supporting server, then that server may return an ECH "retry-config"
|
||||
value that the client could choose to use in a subsequent connection. The
|
||||
client can detect this situation via the `SSL_ech_get1_status()` API and
|
||||
can access the retry config value via:
|
||||
|
||||
```c
|
||||
OSSL_ECHSTORE *SSL_ech_get1_retry_config(SSL *s);
|
||||
```
|
||||
|
||||
GREASEing
|
||||
---------
|
||||
|
||||
"GREASEing" is defined in
|
||||
[RFC8701](https://datatracker.ietf.org/doc/html/rfc8701) and is a mechanism
|
||||
intended to discourage protocol ossification that can be used for ECH. GREASEd
|
||||
ECH may turn out to be important as an initial step towards widespread
|
||||
deployment of ECH.
|
||||
|
||||
If a client wishes to GREASE ECH using a specific HPKE suite or ECH version
|
||||
(represented by the TLS extension type code-point) then it can set those values
|
||||
via:
|
||||
|
||||
```c
|
||||
int SSL_ech_set1_grease_suite(SSL *s, const char *suite);
|
||||
int SSL_ech_set_grease_type(SSL *s, uint16_t type);
|
||||
```
|
||||
|
||||
ECH Status API
|
||||
--------------
|
||||
|
||||
Clients and servers can check the status of ECH processing
|
||||
on an SSL connection using this API:
|
||||
|
||||
```c
|
||||
int SSL_ech_get1_status(SSL *s, char **inner_sni, char **outer_sni);
|
||||
|
||||
/* Return codes from SSL_ech_get1_status */
|
||||
# define SSL_ECH_STATUS_BACKEND 4 /* ECH back-end: saw an ech_is_inner */
|
||||
# define SSL_ECH_STATUS_GREASE_ECH 3 /* GREASEd and got an ECH in return */
|
||||
# define SSL_ECH_STATUS_GREASE 2 /* ECH GREASE happened */
|
||||
# define SSL_ECH_STATUS_SUCCESS 1 /* Success */
|
||||
# define SSL_ECH_STATUS_FAILED 0 /* Some internal or protocol error */
|
||||
# define SSL_ECH_STATUS_BAD_CALL -100 /* Some in/out arguments were NULL */
|
||||
# define SSL_ECH_STATUS_NOT_TRIED -101 /* ECH wasn't attempted */
|
||||
# define SSL_ECH_STATUS_BAD_NAME -102 /* ECH ok but server cert bad */
|
||||
# define SSL_ECH_STATUS_NOT_CONFIGURED -103 /* ECH wasn't configured */
|
||||
# define SSL_ECH_STATUS_FAILED_ECH -105 /* We tried, failed and got an ECH, from a good name */
|
||||
# define SSL_ECH_STATUS_FAILED_ECH_BAD_NAME -106 /* We tried, failed and got an ECH, from a bad name */
|
||||
```
|
||||
|
||||
The `inner_sni` and `outer_sni` values should be freed by callers
|
||||
via `OPENSSL_free()`.
|
||||
|
||||
The function returns one of the status values above.
|
||||
|
||||
Call-backs and options
|
||||
----------------------
|
||||
|
||||
Clients and servers can set a callback that will be triggered when ECH is
|
||||
attempted and the result of ECH processing is known. The callback function can
|
||||
access a string (`str`) that can be used for logging (but not for branching).
|
||||
Callback functions might typically call `SSL_ech_get1_status()` if branching
|
||||
is required.
|
||||
|
||||
```c
|
||||
typedef unsigned int (*SSL_ech_cb_func)(SSL *s, const char *str);
|
||||
|
||||
void SSL_ech_set_callback(SSL *s, SSL_ech_cb_func f);
|
||||
void SSL_CTX_ech_set_callback(SSL_CTX *ctx, SSL_ech_cb_func f);
|
||||
```
|
||||
|
||||
The following options are defined for ECH and may be set via
|
||||
`SSL_set_options()`:
|
||||
|
||||
```c
|
||||
/* set this to tell client to emit greased ECH values when not doing
|
||||
* "real" ECH */
|
||||
#define SSL_OP_ECH_GREASE SSL_OP_BIT(36)
|
||||
/* If this is set then the server side will attempt trial decryption */
|
||||
/* of ECHs even if there is no matching record_digest. That's a bit */
|
||||
/* inefficient, but more privacy friendly */
|
||||
#define SSL_OP_ECH_TRIALDECRYPT SSL_OP_BIT(37)
|
||||
/* If set, clients will ignore the supplied ECH config_id and replace
|
||||
* that with a random value */
|
||||
#define SSL_OP_ECH_IGNORE_CID SSL_OP_BIT(38)
|
||||
/* If set, servers will add GREASEy ECHConfig values to those sent
|
||||
* in retry_configs */
|
||||
#define SSL_OP_ECH_GREASE_RETRY_CONFIG SSL_OP_BIT(39)
|
||||
```
|
||||
|
||||
Build Options
|
||||
-------------
|
||||
|
||||
All ECH code is protected via `#ifndef OPENSSL_NO_ECH` and there is
|
||||
a `no-ech` option to build without this code.
|
||||
|
||||
BoringSSL APIs
|
||||
--------------
|
||||
|
||||
Brief descriptions of BoringSSL APIs are below together with initial comments
|
||||
comparing those to the above. (It may be useful to consider the extent to
|
||||
which it is useful to make OpenSSL and BoringSSL APIs resemble one another.)
|
||||
|
||||
Just as our implementation is under development, BoringSSL's
|
||||
`include/openssl/ssl.h` says: "ECH support in BoringSSL is still experimental
|
||||
and under development."
|
||||
|
||||
### GREASE
|
||||
|
||||
BoringSSL uses an API to enable GREASEing rather than an option.
|
||||
|
||||
```c
|
||||
OPENSSL_EXPORT void SSL_set_enable_ech_grease(SSL *ssl, int enable);
|
||||
```
|
||||
|
||||
This could work as well for our implementation, or BoringSSL could probably
|
||||
change to use an option, unless there's some reason to prefer not adding new
|
||||
options.
|
||||
|
||||
### Verifying the outer CH rather than inner
|
||||
|
||||
BoringSSL seems to use this API to change the DNS name being verified in order
|
||||
to validate a `retry_config`.
|
||||
|
||||
```c
|
||||
OPENSSL_EXPORT void SSL_get0_ech_name_override(const SSL *ssl,
|
||||
const char **out_name,
|
||||
size_t *out_name_len);
|
||||
```
|
||||
|
||||
I'm not sure how this compares. Need to investigate.
|
||||
|
||||
### Create an ECHConfigList
|
||||
|
||||
The first function below outputs an ECHConfig, the second adds one of those to
|
||||
an `SSL_ECH_KEYS` structure, the last emits an ECHConfigList from that
|
||||
structure. There are other APIs for managing memory for `SSL_ECH_KEYS`
|
||||
|
||||
These APIs also expose HPKE to the application via `EVP_HPKE_KEY` which is
|
||||
defined in `include/openssl/hpke.h`. HPKE handling differs quite a bit from
|
||||
the HPKE APIs merged to OpenSSL.
|
||||
|
||||
```c
|
||||
OPENSSL_EXPORT int SSL_marshal_ech_config(uint8_t **out, size_t *out_len,
|
||||
uint8_t config_id,
|
||||
const EVP_HPKE_KEY *key,
|
||||
const char *public_name,
|
||||
size_t max_name_len);
|
||||
OPENSSL_EXPORT int SSL_ECH_KEYS_add(SSL_ECH_KEYS *keys, int is_retry_config,
|
||||
const uint8_t *ech_config,
|
||||
size_t ech_config_len,
|
||||
const EVP_HPKE_KEY *key);
|
||||
OPENSSL_EXPORT int SSL_ECH_KEYS_marshal_retry_configs(const SSL_ECH_KEYS *keys,
|
||||
uint8_t **out,
|
||||
size_t *out_len);
|
||||
```
|
||||
|
||||
Collectively these are similar to `OSSL_ECH_make_echconfig()`.
|
||||
|
||||
### Setting ECH keys on a server
|
||||
|
||||
Again using the `SSL_ECH_KEYS` type and APIs, servers can build up a set of
|
||||
ECH keys using:
|
||||
|
||||
```c
|
||||
OPENSSL_EXPORT int SSL_CTX_set1_ech_keys(SSL_CTX *ctx, SSL_ECH_KEYS *keys);
|
||||
```
|
||||
|
||||
### Getting status
|
||||
|
||||
BoringSSL has:
|
||||
|
||||
```c
|
||||
OPENSSL_EXPORT int SSL_ech_accepted(const SSL *ssl);
|
||||
```
|
||||
|
||||
That seems to be a subset of `SSL_ech_get1_status()`.
|
|
@ -16,6 +16,7 @@ DEPEND[openssl-dsaparam.pod]=../perlvars.pm
|
|||
DEPEND[openssl-dsa.pod]=../perlvars.pm
|
||||
DEPEND[openssl-ecparam.pod]=../perlvars.pm
|
||||
DEPEND[openssl-ec.pod]=../perlvars.pm
|
||||
DEPEND[openssl-ech.pod]=../perlvars.pm
|
||||
DEPEND[openssl-enc.pod]=../perlvars.pm
|
||||
DEPEND[openssl-engine.pod]=../perlvars.pm
|
||||
DEPEND[openssl-errstr.pod]=../perlvars.pm
|
||||
|
|
117
doc/man1/openssl-ech.pod.in
Normal file
117
doc/man1/openssl-ech.pod.in
Normal file
|
@ -0,0 +1,117 @@
|
|||
=pod
|
||||
{- OpenSSL::safe::output_do_not_edit_headers(); -}
|
||||
|
||||
=head1 NAME
|
||||
|
||||
openssl-ech - ECH key generation
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
B<openssl> B<ech>
|
||||
[B<-help>]
|
||||
[B<-verbose>]
|
||||
[B<-in> I<files>]
|
||||
[B<-out> I<file>]
|
||||
[B<-public_name> I<name>]
|
||||
[B<-max_name_len> I<len>]
|
||||
[B<-suite> I<suite_str>]
|
||||
[B<-ech_version> I<version>]
|
||||
[B<-select> I<number>]
|
||||
[B<-text>]
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The L<openssl-ech(1)> command generates Encrypted Client Hello (ECH) key pairs
|
||||
in the ECHConfig PEM file format as specified in
|
||||
L<https://datatracker.ietf.org/doc/draft-farrell-tls-pemesni/>.
|
||||
TODO(ECH): update I-D reference to RFC when possible.
|
||||
|
||||
That format consists of an optional private key in PKCS#8 format and a base64
|
||||
encoded ECHConfigList containing an entry with a matching public value (and
|
||||
possibly other entries as well).
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
The following options are supported:
|
||||
|
||||
=over 4
|
||||
|
||||
=item B<-help>
|
||||
|
||||
Print out a usage message.
|
||||
|
||||
=item B<-verbose>
|
||||
|
||||
Print more verbosely.
|
||||
|
||||
=item B<-in>
|
||||
|
||||
Provide an input ECH PEM file for printing or merging. Up to five
|
||||
input files can be provided via use of multiple B<in> arguments.
|
||||
|
||||
=item B<-out> I<file>
|
||||
|
||||
Name of output ECHConfig PEM file. If a new key pair was generated the output
|
||||
file will contain the private key and encoded ECHConfigList. If one or more
|
||||
input files was provided the output file will contain a set of ECHConfigList
|
||||
values with public keys from the inputs, and no private key(s).
|
||||
|
||||
=item B<-text>
|
||||
|
||||
Provide human-readable text ouput.
|
||||
|
||||
=item B<-public_name> I<name>
|
||||
|
||||
The DNS name to use in the "public_name" field of the ECHConfig.
|
||||
|
||||
=item B<-max_name_len> I<num>
|
||||
|
||||
Maximum name length field value to use in the ECHConfig.
|
||||
|
||||
=item B<-suite> I<str>
|
||||
|
||||
HPKE suite to use in the ECHConfig.
|
||||
|
||||
=item B<-ech_version> I<version>
|
||||
|
||||
The ECH version to use in the ECHConfig. Only 0xfe0d is supported in this version.
|
||||
|
||||
=item B<-select> I<number>
|
||||
|
||||
Select the N-th ECHConfig/public key from the set of input ECH PEM files and output
|
||||
that.
|
||||
|
||||
=back
|
||||
|
||||
=head1 NOTES
|
||||
|
||||
Ciphersuites are specified using a comma-separated list of IANA-registered
|
||||
codes/numbers e.g. "-c 0x20,1,3" or a comma-separated list of strings from:
|
||||
- KEMs: p256, p384, p521, x25519, x448
|
||||
- KDFs: hkdf-sha256, hkdf-sha384, hkdf-sha512
|
||||
- AEADs: aes128gcm, aes256gcm, chachapoly1305
|
||||
|
||||
For example the default is: x25519, hkdf-sha256, aes128gcm
|
||||
See L<OSSL_HPKE_CTX_new(3)> for details.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<openssl(1)>,
|
||||
L<openssl-s_client(1)>,
|
||||
L<openssl-s_server(1)>,
|
||||
L<SSL_set1_echstore(3)>
|
||||
|
||||
=head1 HISTORY
|
||||
|
||||
This functionality described here was added in OpenSSL 3.5.
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
this file except in compliance with the License. You can obtain a copy
|
||||
in the file LICENSE in the source distribution or at
|
||||
L<https://www.openssl.org/source/license.html>.
|
||||
|
||||
=cut
|
|
@ -121,6 +121,10 @@ L<openssl-genpkey(1)> and L<openssl-pkeyparam(1)>.
|
|||
|
||||
EC (Elliptic curve) key processing.
|
||||
|
||||
=item B<ech>
|
||||
|
||||
Encrypted Client Hello (ECH) admin. See L<openssl-ech(1)>.
|
||||
|
||||
=item B<ecparam>
|
||||
|
||||
EC parameter manipulation and generation.
|
||||
|
|
|
@ -362,6 +362,30 @@ only understands up to SSLv3. In this case the client must still use the
|
|||
same SSLv3.1=TLSv1 announcement. Some clients step down to SSLv3 with respect
|
||||
to the server's answer and violate the version rollback protection.)
|
||||
|
||||
=item SSL_OP_ECH_GREASE
|
||||
|
||||
If set, TLS ClientHello messages emitted by the client will include GREASE
|
||||
Encrypted ClientHello (ECH) extension values, if ECH is not really being
|
||||
attempted.
|
||||
|
||||
=item SSL_OP_ECH_TRIALDECRYPT
|
||||
|
||||
If set, servers will attempt to decrypt ECH extensions using all loaded
|
||||
ECH key pairs. By default, servers will only attempt decryption using
|
||||
an ECH key pair that matches the config_id in the ECH extension value
|
||||
received.
|
||||
|
||||
=item SSL_OP_ECH_GREASE_RETRY_CONFIG
|
||||
|
||||
If set, servers will add GREASEy ECHConfig values to those sent to the
|
||||
client after the client GREASEd or the client tried and failed to use
|
||||
ECH.
|
||||
|
||||
=item SSL_OP_ECH_IGNORED_CID
|
||||
|
||||
If set, TLS ClientHello messages emitted by the client will ignore the
|
||||
ECHConfig config_id chosen by the server and use a random octet.
|
||||
|
||||
=back
|
||||
|
||||
The following options no longer have any effect but their identifiers are
|
||||
|
|
201
doc/man3/SSL_set1_echstore.pod
Normal file
201
doc/man3/SSL_set1_echstore.pod
Normal file
|
@ -0,0 +1,201 @@
|
|||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
SSL_set1_echstore,
|
||||
OSSL_ECHSTORE_new, OSSL_ECHSTORE_free,
|
||||
OSSL_ECHSTORE_new_config, OSSL_ECHSTORE_write_pem,
|
||||
OSSL_ECHSTORE_read_echconfiglist, OSSL_ECHSTORE_get1_info,
|
||||
OSSL_ECHSTORE_downselect, OSSL_ECHSTORE_set1_key_and_read_pem,
|
||||
OSSL_ECHSTORE_read_pem, OSSL_ECHSTORE_num_entries,
|
||||
OSSL_ECHSTORE_num_keys, OSSL_ECHSTORE_flush_keys,
|
||||
SSL_CTX_set1_echstore,
|
||||
SSL_CTX_get1_echstore, SSL_get1_echstore, SSL_ech_set1_server_names,
|
||||
SSL_ech_set1_outer_server_name, SSL_ech_set1_outer_alpn_protos,
|
||||
SSL_ech_get1_status, SSL_ech_set1_grease_suite, SSL_ech_set_grease_type,
|
||||
SSL_ech_set_callback, SSL_ech_get1_retry_config,
|
||||
SSL_CTX_ech_set1_outer_alpn_protos, SSL_CTX_ech_raw_decrypt,
|
||||
SSL_CTX_ech_set_callback,SSL_set1_ech_config_list
|
||||
- Encrypted Client Hello (ECH) functions
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
#include <openssl/ech.h>
|
||||
|
||||
OSSL_ECHSTORE *OSSL_ECHSTORE_new(OSSL_LIB_CTX *libctx, const char *propq);
|
||||
void OSSL_ECHSTORE_free(OSSL_ECHSTORE *es);
|
||||
int OSSL_ECHSTORE_new_config(OSSL_ECHSTORE *es,
|
||||
uint16_t echversion, uint16_t max_name_length,
|
||||
const char *public_name, OSSL_HPKE_SUITE suite);
|
||||
int OSSL_ECHSTORE_write_pem(OSSL_ECHSTORE *es, int index, BIO *out);
|
||||
int OSSL_ECHSTORE_read_echconfiglist(OSSL_ECHSTORE *es, BIO *in);
|
||||
int OSSL_ECHSTORE_get1_info(OSSL_ECHSTORE *es, int index, time_t *loaded_secs,
|
||||
char **public_name, char **echconfig,
|
||||
int *has_private, int *for_retry);
|
||||
int OSSL_ECHSTORE_downselect(OSSL_ECHSTORE *es, int index);
|
||||
int OSSL_ECHSTORE_set1_key_and_read_pem(OSSL_ECHSTORE *es, EVP_PKEY *priv,
|
||||
BIO *in, int for_retry);
|
||||
int OSSL_ECHSTORE_read_pem(OSSL_ECHSTORE *es, BIO *in, int for_retry);
|
||||
int OSSL_ECHSTORE_num_entries(OSSL_ECHSTORE *es, int *numentries);
|
||||
int OSSL_ECHSTORE_num_keys(OSSL_ECHSTORE *es, int *numkeys);
|
||||
int OSSL_ECHSTORE_flush_keys(OSSL_ECHSTORE *es, time_t age);
|
||||
int SSL_CTX_set1_echstore(SSL_CTX *ctx, OSSL_ECHSTORE *es);
|
||||
int SSL_set1_echstore(SSL *s, OSSL_ECHSTORE *es);
|
||||
OSSL_ECHSTORE *SSL_CTX_get1_echstore(const SSL_CTX *ctx);
|
||||
OSSL_ECHSTORE *SSL_get1_echstore(const SSL *s);
|
||||
int SSL_ech_set1_server_names(SSL *s, const char *inner_name,
|
||||
const char *outer_name, int no_outer);
|
||||
int SSL_ech_set1_outer_server_name(SSL *s, const char *outer_name, int no_outer);
|
||||
int SSL_ech_set1_outer_alpn_protos(SSL *s, const unsigned char *protos,
|
||||
const size_t protos_len);
|
||||
int SSL_ech_get1_status(SSL *s, char **inner_sni, char **outer_sni);
|
||||
int SSL_ech_set1_grease_suite(SSL *s, const char *suite);
|
||||
int SSL_ech_set_grease_type(SSL *s, uint16_t type);
|
||||
void SSL_ech_set_callback(SSL *s, SSL_ech_cb_func f);
|
||||
int SSL_ech_get1_retry_config(SSL *s, unsigned char **ec, size_t *eclen);
|
||||
int SSL_CTX_ech_raw_decrypt(SSL_CTX *ctx,
|
||||
int *decrypted_ok,
|
||||
char **inner_sni, char **outer_sni,
|
||||
unsigned char *outer_ch, size_t outer_len,
|
||||
unsigned char *inner_ch, size_t *inner_len,
|
||||
unsigned char **hrrtok, size_t *toklen);
|
||||
void SSL_CTX_ech_set_callback(SSL_CTX *ctx, SSL_ech_cb_func f);
|
||||
int SSL_CTX_ech_set1_outer_alpn_protos(SSL_CTX *ctx,
|
||||
const unsigned char *protos,
|
||||
const size_t protos_len);
|
||||
int SSL_set1_ech_config_list(SSL *ssl, const uint8_t *ecl, size_t ecl_len);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
TODO(ECH): Complete this text...
|
||||
|
||||
The Encrypted Client Hello (ECH) APIs described here are built around
|
||||
the concept of an `OSSL_ECHSTORE` which contains ECH configuration
|
||||
information relevant for the current 'SSL_CTX' or 'SSL' connection.
|
||||
|
||||
Mention SSL_set1_echstore() is a thing
|
||||
Mention OSSL_ECHSTORE_new() is a thing
|
||||
Mention OSSL_ECHSTORE_free() is a thing
|
||||
Mention OSSL_ECHSTORE_new_config() is a thing
|
||||
Mention OSSL_ECHSTORE_write_pem() is a thing
|
||||
Mention OSSL_ECHSTORE_read_echconfiglist() is a thing
|
||||
Mention OSSL_ECHSTORE_get1_info() is a thing
|
||||
Mention OSSL_ECHSTORE_downselect() is a thing
|
||||
Mention OSSL_ECHSTORE_set1_key_and_read_pem() is a thing
|
||||
Mention OSSL_ECHSTORE_read_pem() is a thing
|
||||
Mention OSSL_ECHSTORE_num_keys() is a thing
|
||||
Mention OSSL_ECHSTORE_num_entries() is a thing
|
||||
Mention OSSL_ECHSTORE_flush_keys() is a thing
|
||||
Mention SSL_CTX_set1_echstore() is a thing
|
||||
Mention SSL_CTX_get1_echstore() is a thing
|
||||
Mention SSL_get1_echstore() is a thing
|
||||
Mention SSL_ech_set1_server_names() is a thing
|
||||
Mention SSL_ech_set1_outer_server_name() is a thing
|
||||
Mention SSL_ech_set1_outer_alpn_protos() is a thing
|
||||
Mention SSL_ech_get1_status() is a thing
|
||||
Mention SSL_ech_set1_grease_suite() is a thing
|
||||
Mention SSL_ech_set_grease_type() is a thing
|
||||
Mention SSL_ech_set_callback() is a thing
|
||||
Mention SSL_ech_get1_retry_config() is a thing
|
||||
Mention SSL_CTX_ech1_set_outer_alpn_protos() is a thing
|
||||
Mention SSL_CTX_ech_raw_decrypt() is a thing
|
||||
Mention SSL_CTX_ech_set_callback() is a thing
|
||||
Mention SSL_set1_ech_config_list() is a thing
|
||||
|
||||
=head2 Callback Function
|
||||
|
||||
Applications can set a callback function that will be called when the
|
||||
outcome from an attempt at ECH has been determined. On the server,
|
||||
that happens early, as part of construction of the ServerHello message.
|
||||
On the client, the callback will happen after the SeverHello has
|
||||
been processed. In the event of HelloRetryRequest, the callback will
|
||||
only be triggered when processing the second ServerHello. The callback
|
||||
function will be triggered even if the client is only GREASEing.
|
||||
|
||||
The callback function prototype is:
|
||||
|
||||
typedef unsigned int (*SSL_ech_cb_func)(SSL *s, const char *str);
|
||||
|
||||
To set a callback function use SSL_ech_set_callback() or
|
||||
SSL_CTX_ech_set_callback() - the I<f> input should match the
|
||||
above prototype.
|
||||
|
||||
When the callback function is called, the I<str> will point at a string
|
||||
intended for logging describing the state of ECH processing.
|
||||
Applications should not attempt to parse that string as the value depends
|
||||
on compile time settings, local configuration and the specific processing
|
||||
that happened prior to the callback. Applications that need to branch based
|
||||
on the outcome of ECH processing should instead make a call to
|
||||
SSL_ech_get1_status() from within their callback function.
|
||||
|
||||
An example string I<str> as seen on a client might be:
|
||||
|
||||
ech_attempted=1
|
||||
ech_attempted_type=0xfe0d
|
||||
ech_atttempted_cid=0x5d
|
||||
ech_done=1
|
||||
ech_grease=0
|
||||
ech_returned_len=0
|
||||
ech_backend=0
|
||||
ech_success=1
|
||||
2 ECHConfig values loaded
|
||||
cfg(0): [fe0d,5d,cover.defo.ie,0020,[0001,0001],190984309c1a24cb944c005eb79d9c72ca9a4a979194b553dfd0bffc6b5c152d,00,00]
|
||||
cfg(1): [fe0d,fd,cover.defo.ie,0020,[0001,0001],46dd4e2c81bb15ef9d194c99b86983844e2a1387e4fb7e7d3b8d368c8e1b4d2a,00,00]
|
||||
|
||||
=head1 RETURN VALUES
|
||||
|
||||
All functions named here return one on success and zero on error.
|
||||
|
||||
SSL_set1_echstore() returns zero on error
|
||||
SSL_set1_ech_config_list() returns zero on error
|
||||
OSSL_ECHSTORE_new() returns zero on error
|
||||
OSSL_ECHSTORE_free() returns zero on error
|
||||
OSSL_ECHSTORE_new_config() returns zero on error
|
||||
OSSL_ECHSTORE_write_pem() returns zero on error
|
||||
OSSL_ECHSTORE_read_echconfiglist() returns zero on error
|
||||
OSSL_ECHSTORE_get1_info() returns zero on error
|
||||
OSSL_ECHSTORE_downselect() returns zero on error
|
||||
OSSL_ECHSTORE_set1_key_and_read_pem() returns zero on error
|
||||
OSSL_ECHSTORE_read_pem() returns zero on error
|
||||
OSSL_ECHSTORE_num_keys() returns zero on error
|
||||
OSSL_ECHSTORE_num_entries() returns zero on error
|
||||
OSSL_ECHSTORE_flush_keys() returns zero on error
|
||||
SSL_CTX_set1_echstore() returns zero on error
|
||||
SSL_CTX_get1_echstore() returns zero on error
|
||||
SSL_get1_echstore() returns zero on error
|
||||
SSL_ech_set_server_names() returns zero on error
|
||||
SSL_ech_set_outer_server_name() returns zero on error
|
||||
SSL_ech_set_outer_alpn_protos() returns zero on error
|
||||
SSL_ech_get1_status() returns zero on error
|
||||
SSL_ech_set_grease_suite() returns zero on error
|
||||
SSL_ech_set_grease_type() returns zero on error
|
||||
SSL_ech_set_callback() returns zero on error
|
||||
SSL_ech_get_retry_config() returns zero on error
|
||||
SSL_CTX_ech_set1_outer_alpn_protos() returns zero on error
|
||||
SSL_CTX_ech_raw_decrypt() returns zero on error
|
||||
SSL_CTX_ech_set_callback() returns zero on error
|
||||
|
||||
Note that SSL_CTX_ech_set1_outer_alpn_protos() and
|
||||
SSL_ech_set1_outer_alpn_protos() return zero on error and 1 on success.
|
||||
This is in contrast to SSL_CTX_set1_alpn_protos() and SSL_set1_alpn_protos()
|
||||
which (unusually for OpenSSL) return 0 on success and 1 on error.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
The Encrypted ClientHello specification: L<https://datatracker.ietf.org/doc/draft-ietf-tls-esni/>
|
||||
TODO(ECH) update link to RFC.
|
||||
|
||||
=head1 HISTORY
|
||||
|
||||
The functionality described here was added in OpenSSL 3.5.
|
||||
|
||||
=head1 COPYRIGHT
|
||||
|
||||
Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
this file except in compliance with the License. You can obtain a copy
|
||||
in the file LICENSE in the source distribution or at
|
||||
L<https://www.openssl.org/source/license.html>.
|
||||
|
||||
=cut
|
133
include/openssl/ech.h
Normal file
133
include/openssl/ech.h
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* Externally-visible data structures and prototypes for handling
|
||||
* Encrypted ClientHello (ECH).
|
||||
*/
|
||||
#ifndef OPENSSL_ECH_H
|
||||
# define OPENSSL_ECH_H
|
||||
# pragma once
|
||||
|
||||
# include <openssl/ssl.h>
|
||||
# include <openssl/hpke.h>
|
||||
|
||||
# ifndef OPENSSL_NO_ECH
|
||||
|
||||
/*
|
||||
* Some externally visible limits - most used for sanity checks that could be
|
||||
* bigger if needed, but that work for now
|
||||
*/
|
||||
# define OSSL_ECH_MAX_PAYLOAD_LEN 1500 /* max ECH ciphertext to en/decode */
|
||||
# define OSSL_ECH_MIN_ECHCONFIG_LEN 32 /* min for all encodings */
|
||||
# define OSSL_ECH_MAX_ECHCONFIG_LEN 1500 /* max for all encodings */
|
||||
# define OSSL_ECH_MAX_ECHCONFIGEXT_LEN 512 /* ECHConfig extension max */
|
||||
# define OSSL_ECH_MAX_MAXNAMELEN 255 /* ECHConfig max for max name length */
|
||||
# define OSSL_ECH_MAX_PUBLICNAME 255 /* max ECHConfig public name length */
|
||||
# define OSSL_ECH_MAX_ALPNLEN 255 /* max alpn length */
|
||||
# define OSSL_ECH_OUTERS_MAX 20 /* max extensions we compress via outer-exts */
|
||||
# define OSSL_ECH_ALLEXTS_MAX 32 /* max total number of extension we allow */
|
||||
|
||||
/*
|
||||
* ECH version. We only support RFC XXXX as of now. As/if new ECHConfig
|
||||
* versions are added, those will be noted here.
|
||||
* TODO(ECH): Replace XXXX with the actual RFC number once known.
|
||||
*/
|
||||
# define OSSL_ECH_RFCXXXX_VERSION 0xfe0d /* official ECHConfig version */
|
||||
/* latest version from an RFC */
|
||||
# define OSSL_ECH_CURRENT_VERSION OSSL_ECH_RFCXXXX_VERSION
|
||||
|
||||
/* Return codes from SSL_ech_get1_status */
|
||||
# define SSL_ECH_STATUS_BACKEND 4 /* ECH backend: saw an ech_is_inner */
|
||||
# define SSL_ECH_STATUS_GREASE_ECH 3 /* GREASEd and got an ECH in return */
|
||||
# define SSL_ECH_STATUS_GREASE 2 /* ECH GREASE happened */
|
||||
# define SSL_ECH_STATUS_SUCCESS 1 /* Success */
|
||||
# define SSL_ECH_STATUS_FAILED 0 /* Some internal or protocol error */
|
||||
# define SSL_ECH_STATUS_BAD_CALL -100 /* Some in/out arguments were NULL */
|
||||
# define SSL_ECH_STATUS_NOT_TRIED -101 /* ECH wasn't attempted */
|
||||
# define SSL_ECH_STATUS_BAD_NAME -102 /* ECH ok but server cert bad */
|
||||
# define SSL_ECH_STATUS_NOT_CONFIGURED -103 /* ECH wasn't configured */
|
||||
# define SSL_ECH_STATUS_FAILED_ECH -105 /* Tried, failed, got an ECH, from a good name */
|
||||
# define SSL_ECH_STATUS_FAILED_ECH_BAD_NAME -106 /* Tried, failed, got an ECH, from a bad name */
|
||||
|
||||
/* if a caller wants to index the last entry in the store */
|
||||
# define OSSL_ECHSTORE_LAST -1
|
||||
/* if a caller wants all entries in the store, e.g. to print public values */
|
||||
# define OSSL_ECHSTORE_ALL -2
|
||||
|
||||
/* Values for the for_retry inputs */
|
||||
# define OSSL_ECH_FOR_RETRY 1
|
||||
# define OSSL_ECH_NO_RETRY 0
|
||||
|
||||
/*
|
||||
* API calls built around OSSL_ECHSTORE
|
||||
*/
|
||||
OSSL_ECHSTORE *OSSL_ECHSTORE_new(OSSL_LIB_CTX *libctx, const char *propq);
|
||||
void OSSL_ECHSTORE_free(OSSL_ECHSTORE *es);
|
||||
int OSSL_ECHSTORE_new_config(OSSL_ECHSTORE *es,
|
||||
uint16_t echversion, uint8_t max_name_length,
|
||||
const char *public_name, OSSL_HPKE_SUITE suite);
|
||||
int OSSL_ECHSTORE_write_pem(OSSL_ECHSTORE *es, int index, BIO *out);
|
||||
int OSSL_ECHSTORE_read_echconfiglist(OSSL_ECHSTORE *es, BIO *in);
|
||||
int OSSL_ECHSTORE_get1_info(OSSL_ECHSTORE *es, int index, time_t *loaded_secs,
|
||||
char **public_name, char **echconfig,
|
||||
int *has_private, int *for_retry);
|
||||
int OSSL_ECHSTORE_downselect(OSSL_ECHSTORE *es, int index);
|
||||
int OSSL_ECHSTORE_set1_key_and_read_pem(OSSL_ECHSTORE *es, EVP_PKEY *priv,
|
||||
BIO *in, int for_retry);
|
||||
int OSSL_ECHSTORE_read_pem(OSSL_ECHSTORE *es, BIO *in, int for_retry);
|
||||
int OSSL_ECHSTORE_num_entries(const OSSL_ECHSTORE *es, int *numentries);
|
||||
int OSSL_ECHSTORE_num_keys(OSSL_ECHSTORE *es, int *numkeys);
|
||||
int OSSL_ECHSTORE_flush_keys(OSSL_ECHSTORE *es, time_t age);
|
||||
|
||||
/*
|
||||
* APIs relating OSSL_ECHSTORE to SSL/SSL_CTX
|
||||
*/
|
||||
int SSL_CTX_set1_echstore(SSL_CTX *ctx, OSSL_ECHSTORE *es);
|
||||
int SSL_set1_echstore(SSL *s, OSSL_ECHSTORE *es);
|
||||
|
||||
OSSL_ECHSTORE *SSL_CTX_get1_echstore(const SSL_CTX *ctx);
|
||||
OSSL_ECHSTORE *SSL_get1_echstore(const SSL *s);
|
||||
|
||||
int SSL_ech_set1_server_names(SSL *s, const char *inner_name,
|
||||
const char *outer_name, int no_outer);
|
||||
int SSL_ech_set1_outer_server_name(SSL *s, const char *outer_name, int no_outer);
|
||||
/*
|
||||
* Note that this function returns 1 for success and 0 for error. This
|
||||
* contrasts with SSL_set1_alpn_protos() which (unusually for OpenSSL)
|
||||
* returns 0 for success and 1 on error.
|
||||
*/
|
||||
int SSL_ech_set1_outer_alpn_protos(SSL *s, const unsigned char *protos,
|
||||
const size_t protos_len);
|
||||
|
||||
int SSL_ech_get1_status(SSL *s, char **inner_sni, char **outer_sni);
|
||||
int SSL_ech_set1_grease_suite(SSL *s, const char *suite);
|
||||
int SSL_ech_set_grease_type(SSL *s, uint16_t type);
|
||||
typedef unsigned int (*SSL_ech_cb_func)(SSL *s, const char *str);
|
||||
void SSL_ech_set_callback(SSL *s, SSL_ech_cb_func f);
|
||||
int SSL_ech_get1_retry_config(SSL *s, unsigned char **ec, size_t *eclen);
|
||||
|
||||
/*
|
||||
* Note that this function returns 1 for success and 0 for error. This
|
||||
* contrasts with SSL_set1_alpn_protos() which (unusually for OpenSSL)
|
||||
* returns 0 for success and 1 on error.
|
||||
*/
|
||||
int SSL_CTX_ech_set1_outer_alpn_protos(SSL_CTX *s, const unsigned char *protos,
|
||||
const size_t protos_len);
|
||||
int SSL_CTX_ech_raw_decrypt(SSL_CTX *ctx,
|
||||
int *decrypted_ok,
|
||||
char **inner_sni, char **outer_sni,
|
||||
unsigned char *outer_ch, size_t outer_len,
|
||||
unsigned char *inner_ch, size_t *inner_len,
|
||||
unsigned char **hrrtok, size_t *toklen);
|
||||
void SSL_CTX_ech_set_callback(SSL_CTX *ctx, SSL_ech_cb_func f);
|
||||
int SSL_set1_ech_config_list(SSL *ssl, const uint8_t *ecl, size_t ecl_len);
|
||||
|
||||
# endif
|
||||
#endif
|
|
@ -59,6 +59,7 @@ extern "C" {
|
|||
# define PEM_STRING_CMS "CMS"
|
||||
# define PEM_STRING_SM2PARAMETERS "SM2 PARAMETERS"
|
||||
# define PEM_STRING_ACERT "ATTRIBUTE CERTIFICATE"
|
||||
# define PEM_STRING_ECHCONFIG "ECHCONFIG"
|
||||
|
||||
# define PEM_TYPE_ENCRYPTED 10
|
||||
# define PEM_TYPE_MIC_ONLY 20
|
||||
|
|
|
@ -44,6 +44,9 @@ use OpenSSL::stackhash qw(generate_stack_macros generate_const_stack_macros);
|
|||
# include <openssl/ct.h>
|
||||
# include <openssl/sslerr.h>
|
||||
# include <openssl/prov_ssl.h>
|
||||
# ifndef OPENSSL_NO_ECH
|
||||
# include <openssl/ech.h>
|
||||
# endif
|
||||
# ifndef OPENSSL_NO_STDIO
|
||||
# include <stdio.h>
|
||||
# endif
|
||||
|
@ -426,6 +429,28 @@ typedef int (*SSL_async_callback_fn)(SSL *s, void *arg);
|
|||
|
||||
#define SSL_OP_PREFER_NO_DHE_KEX SSL_OP_BIT(35)
|
||||
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
/* Set this to tell client to emit greased ECH values */
|
||||
# define SSL_OP_ECH_GREASE SSL_OP_BIT(36)
|
||||
/*
|
||||
* If this is set then the server side will attempt trial decryption
|
||||
* of ECHs even if there is no matching ECH config_id. That's a bit
|
||||
* inefficient, but more privacy friendly.
|
||||
*/
|
||||
# define SSL_OP_ECH_TRIALDECRYPT SSL_OP_BIT(37)
|
||||
/*
|
||||
* If set, clients will ignore the supplied ECH config_id and replace
|
||||
* that with a random value.
|
||||
*/
|
||||
# define SSL_OP_ECH_IGNORE_CID SSL_OP_BIT(38)
|
||||
/*
|
||||
* If set, servers will add GREASEy ECHConfig values to those sent
|
||||
* in retry_configs.
|
||||
*/
|
||||
# define SSL_OP_ECH_GREASE_RETRY_CONFIG SSL_OP_BIT(39)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Option "collections."
|
||||
*/
|
||||
|
@ -1191,6 +1216,9 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
|
|||
# define SSL_AD_NO_RENEGOTIATION TLS1_AD_NO_RENEGOTIATION
|
||||
# define SSL_AD_MISSING_EXTENSION TLS13_AD_MISSING_EXTENSION
|
||||
# define SSL_AD_CERTIFICATE_REQUIRED TLS13_AD_CERTIFICATE_REQUIRED
|
||||
# ifndef OPENSSL_NO_ECH
|
||||
# define SSL_AD_ECH_REQUIRED TLS1_AD_ECH_REQUIRED
|
||||
# endif
|
||||
# define SSL_AD_UNSUPPORTED_EXTENSION TLS1_AD_UNSUPPORTED_EXTENSION
|
||||
# define SSL_AD_CERTIFICATE_UNOBTAINABLE TLS1_AD_CERTIFICATE_UNOBTAINABLE
|
||||
# define SSL_AD_UNRECOGNIZED_NAME TLS1_AD_UNRECOGNIZED_NAME
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
# define SSL_R_BAD_DIGEST_LENGTH 111
|
||||
# define SSL_R_BAD_EARLY_DATA 233
|
||||
# define SSL_R_BAD_ECC_CERT 304
|
||||
# define SSL_R_BAD_ECHCONFIG_EXTENSION 422
|
||||
# define SSL_R_BAD_ECPOINT 306
|
||||
# define SSL_R_BAD_EXTENSION 110
|
||||
# define SSL_R_BAD_HANDSHAKE_LENGTH 332
|
||||
|
@ -112,6 +113,8 @@
|
|||
# define SSL_R_DUPLICATE_COMPRESSION_ID 309
|
||||
# define SSL_R_ECC_CERT_NOT_FOR_SIGNING 318
|
||||
# define SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE 374
|
||||
# define SSL_R_ECH_DECODE_ERROR 423
|
||||
# define SSL_R_ECH_REQUIRED 421
|
||||
# define SSL_R_EE_KEY_TOO_SMALL 399
|
||||
# define SSL_R_EMPTY_RAW_PUBLIC_KEY 349
|
||||
# define SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST 354
|
||||
|
|
|
@ -78,6 +78,9 @@ extern "C" {
|
|||
# define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114
|
||||
# define TLS1_AD_UNKNOWN_PSK_IDENTITY 115/* fatal */
|
||||
# define TLS1_AD_NO_APPLICATION_PROTOCOL 120 /* fatal */
|
||||
# ifndef OPENSSL_NO_ECH
|
||||
# define TLS1_AD_ECH_REQUIRED 121 /* fatal */
|
||||
# endif
|
||||
|
||||
/* ExtensionType values from RFC3546 / RFC4366 / RFC6066 */
|
||||
# define TLSEXT_TYPE_server_name 0
|
||||
|
@ -168,6 +171,11 @@ extern "C" {
|
|||
# define TLSEXT_TYPE_next_proto_neg 13172
|
||||
# endif
|
||||
|
||||
# ifndef OPENSSL_NO_ECH
|
||||
# define TLSEXT_TYPE_ech 0xfe0d
|
||||
# define TLSEXT_TYPE_outer_extensions 0xfd00
|
||||
# endif
|
||||
|
||||
/* NameType value from RFC3546 */
|
||||
# define TLSEXT_NAMETYPE_host_name 0
|
||||
/* status request value from RFC3546 */
|
||||
|
|
|
@ -238,6 +238,12 @@ typedef struct ossl_decoder_ctx_st OSSL_DECODER_CTX;
|
|||
|
||||
typedef struct ossl_self_test_st OSSL_SELF_TEST;
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
/* opaque type for ECH related information */
|
||||
typedef struct ossl_echstore_st OSSL_ECHSTORE;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -6,6 +6,10 @@ IF[{- !$disabled{quic} -}]
|
|||
SUBDIRS=quic
|
||||
ENDIF
|
||||
|
||||
IF[{- !$disabled{ech} -}]
|
||||
SUBDIRS=ech
|
||||
ENDIF
|
||||
|
||||
SOURCE[../libssl]=\
|
||||
pqueue.c \
|
||||
statem/statem_srvr.c statem/statem_clnt.c s3_lib.c s3_enc.c \
|
||||
|
|
3
ssl/ech/build.info
Normal file
3
ssl/ech/build.info
Normal file
|
@ -0,0 +1,3 @@
|
|||
$LIBSSL=../../libssl
|
||||
|
||||
SOURCE[$LIBSSL]=ech_ssl_apis.c ech_store.c ech_internal.c ech_helper.c
|
15
ssl/ech/ech_helper.c
Normal file
15
ssl/ech/ech_helper.c
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/ech.h>
|
||||
#include "../ssl_local.h"
|
||||
#include "ech_local.h"
|
||||
|
||||
/* TODO(ECH): move code that's used by internals and test here */
|
163
ssl/ech/ech_internal.c
Normal file
163
ssl/ech/ech_internal.c
Normal file
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/ech.h>
|
||||
#include "../ssl_local.h"
|
||||
#include "ech_local.h"
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
|
||||
/* ECH internal API functions */
|
||||
|
||||
static OSSL_ECHSTORE_ENTRY *ossl_echstore_entry_dup(const OSSL_ECHSTORE_ENTRY *orig)
|
||||
{
|
||||
OSSL_ECHSTORE_ENTRY *ret = NULL;
|
||||
|
||||
if (orig == NULL)
|
||||
return NULL;
|
||||
ret = OPENSSL_zalloc(sizeof(*ret));
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
ret->version = orig->version;
|
||||
if (orig->public_name != NULL) {
|
||||
ret->public_name = OPENSSL_strdup(orig->public_name);
|
||||
if (ret->public_name == NULL)
|
||||
goto err;
|
||||
}
|
||||
ret->pub_len = orig->pub_len;
|
||||
if (orig->pub != NULL) {
|
||||
ret->pub = OPENSSL_memdup(orig->pub, orig->pub_len);
|
||||
if (ret->pub == NULL)
|
||||
goto err;
|
||||
}
|
||||
ret->nsuites = orig->nsuites;
|
||||
ret->suites = OPENSSL_memdup(orig->suites, sizeof(OSSL_HPKE_SUITE) * ret->nsuites);
|
||||
if (ret->suites == NULL)
|
||||
goto err;
|
||||
ret->max_name_length = orig->max_name_length;
|
||||
ret->config_id = orig->config_id;
|
||||
if (orig->exts != NULL) {
|
||||
ret->exts = sk_OSSL_ECHEXT_deep_copy(orig->exts, ossl_echext_dup,
|
||||
ossl_echext_free);
|
||||
if (ret->exts == NULL)
|
||||
goto err;
|
||||
}
|
||||
ret->loadtime = orig->loadtime;
|
||||
if (orig->keyshare != NULL) {
|
||||
if (!EVP_PKEY_up_ref(orig->keyshare))
|
||||
goto err;
|
||||
ret->keyshare = orig->keyshare;
|
||||
}
|
||||
ret->for_retry = orig->for_retry;
|
||||
if (orig->encoded != NULL) {
|
||||
ret->encoded_len = orig->encoded_len;
|
||||
ret->encoded = OPENSSL_memdup(orig->encoded, ret->encoded_len);
|
||||
if (ret->encoded == NULL)
|
||||
goto err;
|
||||
}
|
||||
return ret;
|
||||
err:
|
||||
ossl_echstore_entry_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* duplicate an OSSL_ECHSTORE as needed */
|
||||
OSSL_ECHSTORE *ossl_echstore_dup(const OSSL_ECHSTORE *old)
|
||||
{
|
||||
OSSL_ECHSTORE *cp = NULL;
|
||||
|
||||
if (old == NULL)
|
||||
return NULL;
|
||||
cp = OPENSSL_zalloc(sizeof(*cp));
|
||||
if (cp == NULL)
|
||||
return NULL;
|
||||
cp->libctx = old->libctx;
|
||||
if (old->propq != NULL) {
|
||||
cp->propq = OPENSSL_strdup(old->propq);
|
||||
if (cp->propq == NULL)
|
||||
goto err;
|
||||
}
|
||||
if (old->entries != NULL) {
|
||||
cp->entries = sk_OSSL_ECHSTORE_ENTRY_deep_copy(old->entries,
|
||||
ossl_echstore_entry_dup,
|
||||
ossl_echstore_entry_free);
|
||||
if (cp->entries == NULL)
|
||||
goto err;
|
||||
}
|
||||
return cp;
|
||||
err:
|
||||
OSSL_ECHSTORE_free(cp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ossl_ech_ctx_clear(OSSL_ECH_CTX *ce)
|
||||
{
|
||||
if (ce == NULL)
|
||||
return;
|
||||
OSSL_ECHSTORE_free(ce->es);
|
||||
OPENSSL_free(ce->alpn_outer);
|
||||
return;
|
||||
}
|
||||
|
||||
void ossl_ech_conn_clear(OSSL_ECH_CONN *ec)
|
||||
{
|
||||
if (ec == NULL)
|
||||
return;
|
||||
OSSL_ECHSTORE_free(ec->es);
|
||||
OPENSSL_free(ec->outer_hostname);
|
||||
OPENSSL_free(ec->alpn_outer);
|
||||
OPENSSL_free(ec->former_inner);
|
||||
OPENSSL_free(ec->innerch);
|
||||
OPENSSL_free(ec->encoded_innerch);
|
||||
OPENSSL_free(ec->innerch1);
|
||||
OPENSSL_free(ec->kepthrr);
|
||||
OPENSSL_free(ec->grease_suite);
|
||||
OPENSSL_free(ec->sent);
|
||||
OPENSSL_free(ec->returned);
|
||||
OPENSSL_free(ec->pub);
|
||||
OSSL_HPKE_CTX_free(ec->hpke_ctx);
|
||||
EVP_PKEY_free(ec->tmp_pkey);
|
||||
return;
|
||||
}
|
||||
|
||||
/* called from ssl/ssl_lib.c: ossl_ssl_connection_new_int */
|
||||
int ossl_ech_conn_init(SSL_CONNECTION *s, SSL_CTX *ctx,
|
||||
const SSL_METHOD *method)
|
||||
{
|
||||
memset(&s->ext.ech, 0, sizeof(s->ext.ech));
|
||||
if (ctx->ext.ech.es != NULL
|
||||
&& (s->ext.ech.es = ossl_echstore_dup(ctx->ext.ech.es)) == NULL)
|
||||
goto err;
|
||||
s->ext.ech.cb = ctx->ext.ech.cb;
|
||||
if (ctx->ext.ech.alpn_outer != NULL) {
|
||||
s->ext.ech.alpn_outer = OPENSSL_memdup(ctx->ext.ech.alpn_outer,
|
||||
ctx->ext.ech.alpn_outer_len);
|
||||
if (s->ext.ech.alpn_outer == NULL)
|
||||
goto err;
|
||||
s->ext.ech.alpn_outer_len = ctx->ext.ech.alpn_outer_len;
|
||||
}
|
||||
/* initialise type/cid to unknown */
|
||||
s->ext.ech.attempted_type = OSSL_ECH_type_unknown;
|
||||
s->ext.ech.attempted_cid = OSSL_ECH_config_id_unset;
|
||||
if (s->ext.ech.es != NULL)
|
||||
s->ext.ech.attempted = 1;
|
||||
if (ctx->options & SSL_OP_ECH_GREASE)
|
||||
s->options |= SSL_OP_ECH_GREASE;
|
||||
return 1;
|
||||
err:
|
||||
OSSL_ECHSTORE_free(s->ext.ech.es);
|
||||
s->ext.ech.es = NULL;
|
||||
OPENSSL_free(s->ext.ech.alpn_outer);
|
||||
s->ext.ech.alpn_outer = NULL;
|
||||
s->ext.ech.alpn_outer_len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
222
ssl/ech/ech_local.h
Normal file
222
ssl/ech/ech_local.h
Normal file
|
@ -0,0 +1,222 @@
|
|||
/*
|
||||
* Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
/*
|
||||
* Internal data structures and prototypes for handling
|
||||
* Encrypted ClientHello (ECH)
|
||||
*/
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
|
||||
# ifndef HEADER_ECH_LOCAL_H
|
||||
# define HEADER_ECH_LOCAL_H
|
||||
|
||||
# include <openssl/ssl.h>
|
||||
# include <openssl/ech.h>
|
||||
# include <openssl/hpke.h>
|
||||
|
||||
/*
|
||||
* Define this to get loads more lines of tracing which is
|
||||
* very useful for interop.
|
||||
* This needs tracing enabled at build time, e.g.:
|
||||
* $ ./config enable-ssl-trace enable-trace
|
||||
* This added tracing will finally (mostly) disappear once the ECH RFC
|
||||
* has issued, but is very useful for interop testing so some of it might
|
||||
* be retained.
|
||||
*/
|
||||
# define OSSL_ECH_SUPERVERBOSE
|
||||
|
||||
/* values for s->ext.ech.grease */
|
||||
# define OSSL_ECH_GREASE_UNKNOWN -1 /* when we're not yet sure */
|
||||
# define OSSL_ECH_NOT_GREASE 0 /* when decryption worked */
|
||||
# define OSSL_ECH_IS_GREASE 1 /* when decryption failed or GREASE wanted */
|
||||
|
||||
/* value for uninitialised ECH version */
|
||||
# define OSSL_ECH_type_unknown 0xffff
|
||||
/* value for not yet set ECH config_id */
|
||||
# define OSSL_ECH_config_id_unset -1
|
||||
|
||||
# define OSSL_ECH_CIPHER_LEN 4 /* ECHCipher length (2 for kdf, 2 for aead) */
|
||||
/*
|
||||
* Reminder of what goes in DNS for ECH RFC XXXX
|
||||
*
|
||||
* opaque HpkePublicKey<1..2^16-1>;
|
||||
* uint16 HpkeKemId; // Defined in I-D.irtf-cfrg-hpke
|
||||
* uint16 HpkeKdfId; // Defined in I-D.irtf-cfrg-hpke
|
||||
* uint16 HpkeAeadId; // Defined in I-D.irtf-cfrg-hpke
|
||||
* struct {
|
||||
* HpkeKdfId kdf_id;
|
||||
* HpkeAeadId aead_id;
|
||||
* } HpkeSymmetricCipherSuite;
|
||||
* struct {
|
||||
* uint8 config_id;
|
||||
* HpkeKemId kem_id;
|
||||
* HpkePublicKey public_key;
|
||||
* HpkeSymmetricCipherSuite cipher_suites<4..2^16-4>;
|
||||
* } HpkeKeyConfig;
|
||||
* struct {
|
||||
* HpkeKeyConfig key_config;
|
||||
* uint8 maximum_name_length;
|
||||
* opaque public_name<1..255>;
|
||||
* Extension extensions<0..2^16-1>;
|
||||
* } ECHConfigContents;
|
||||
* struct {
|
||||
* uint16 version;
|
||||
* uint16 length;
|
||||
* select (ECHConfig.version) {
|
||||
* case 0xfe0d: ECHConfigContents contents;
|
||||
* }
|
||||
* } ECHConfig;
|
||||
* ECHConfig ECHConfigList<1..2^16-1>;
|
||||
*/
|
||||
|
||||
typedef struct ossl_echext_st {
|
||||
uint16_t type;
|
||||
uint16_t len;
|
||||
unsigned char *val;
|
||||
} OSSL_ECHEXT;
|
||||
|
||||
DEFINE_STACK_OF(OSSL_ECHEXT)
|
||||
|
||||
typedef struct ossl_echstore_entry_st {
|
||||
uint16_t version; /* 0xff0d for draft-13 */
|
||||
char *public_name;
|
||||
size_t pub_len;
|
||||
unsigned char *pub;
|
||||
unsigned int nsuites;
|
||||
OSSL_HPKE_SUITE *suites;
|
||||
uint8_t max_name_length;
|
||||
uint8_t config_id;
|
||||
STACK_OF(OSSL_ECHEXT) *exts;
|
||||
time_t loadtime; /* time public and private key were loaded from file */
|
||||
EVP_PKEY *keyshare; /* long(ish) term ECH private keyshare on a server */
|
||||
int for_retry; /* whether to use this ECHConfigList in a retry */
|
||||
size_t encoded_len; /* length of overall encoded content */
|
||||
unsigned char *encoded; /* overall encoded content */
|
||||
} OSSL_ECHSTORE_ENTRY;
|
||||
|
||||
DEFINE_STACK_OF(OSSL_ECHSTORE_ENTRY)
|
||||
|
||||
struct ossl_echstore_st {
|
||||
STACK_OF(OSSL_ECHSTORE_ENTRY) *entries;
|
||||
OSSL_LIB_CTX *libctx;
|
||||
char *propq;
|
||||
};
|
||||
|
||||
/* ECH details associated with an SSL_CTX */
|
||||
typedef struct ossl_ech_ctx_st {
|
||||
/* TODO(ECH): consider making es ref-counted */
|
||||
OSSL_ECHSTORE *es;
|
||||
unsigned char *alpn_outer;
|
||||
size_t alpn_outer_len;
|
||||
SSL_ech_cb_func cb; /* callback function for when ECH "done" */
|
||||
} OSSL_ECH_CTX;
|
||||
|
||||
/* ECH details associated with an SSL_CONNECTION */
|
||||
typedef struct ossl_ech_conn_st {
|
||||
/* TODO(ECH): consider making es ref-counted */
|
||||
OSSL_ECHSTORE *es; /* ECHConfigList details */
|
||||
int no_outer; /* set to 1 if we should send no outer SNI at all */
|
||||
char *outer_hostname;
|
||||
unsigned char *alpn_outer;
|
||||
size_t alpn_outer_len;
|
||||
SSL_ech_cb_func cb; /* callback function for when ECH "done" */
|
||||
/*
|
||||
* If ECH fails, then we switch to verifying the cert for the
|
||||
* outer_hostname, meanwhile we still want to be able to trace
|
||||
* the value we tried as the inner SNI for debug purposes
|
||||
*/
|
||||
char *former_inner;
|
||||
/*
|
||||
* TODO(ECH): The next 4 buffers (and lengths) may change later
|
||||
* if a better way to handle the mutiple transcripts needed is
|
||||
* suggested/invented. I'd suggest we review these when that code
|
||||
* is part of a PR (which won't be for a few PR's yet.)
|
||||
*/
|
||||
/*
|
||||
* encoded inner ClientHello before/after ECH compression, which`
|
||||
* is nitty/complex (to avoid repeating the same extenstion value
|
||||
* in outer and inner, thus saving bandwidth) but (re-)calculating
|
||||
* the compression is a pain, so we'll store those as we make them
|
||||
*/
|
||||
unsigned char *innerch; /* before compression */
|
||||
size_t innerch_len;
|
||||
unsigned char *encoded_innerch; /* after compression */
|
||||
size_t encoded_innerch_len;
|
||||
/*
|
||||
* in case of HRR, we need to record the 1st inner client hello, and
|
||||
* the first server hello (aka the HRR) so we can independently
|
||||
* generate the transcript and accept confirmation when making the
|
||||
* 2nd server hello
|
||||
*/
|
||||
unsigned char *innerch1;
|
||||
size_t innerch1_len;
|
||||
unsigned char *kepthrr;
|
||||
size_t kepthrr_len;
|
||||
/*
|
||||
* Extensions are "outer-only" if the value is only sent in the
|
||||
* outer CH and only the type is sent in the inner CH.
|
||||
* We use this array to keep track of the extension types that
|
||||
* have values only in the outer CH
|
||||
* Currently, this is basically controlled at compile time, but
|
||||
* in a way that could be varied, or, in future, put under
|
||||
* run-time control, so having this isn't so much an overhead.
|
||||
*/
|
||||
uint16_t outer_only[OSSL_ECH_OUTERS_MAX];
|
||||
size_t n_outer_only; /* the number of outer_only extensions so far */
|
||||
/*
|
||||
* Index of the current extension's entry in ext_defs - this is
|
||||
* to avoid the need to change a couple of extension APIs.
|
||||
* TODO(ECH): check if there's another way to get that value
|
||||
*/
|
||||
size_t ext_ind;
|
||||
/* ECH status vars */
|
||||
int ch_depth; /* set during CH creation, 0: doing outer, 1: doing inner */
|
||||
int attempted; /* 1 if ECH was or is being attempted, 0 otherwise */
|
||||
int done; /* 1 if we've finished ECH calculations, 0 otherwise */
|
||||
uint16_t attempted_type; /* ECH version used */
|
||||
int attempted_cid; /* ECH config id sent/rx'd */
|
||||
int backend; /* 1 if we're a server backend in split-mode, 0 otherwise */
|
||||
/*
|
||||
* success is 1 if ECH succeeded, 0 otherwise, on the server this
|
||||
* is known early, on the client we need to wait for the ECH confirm
|
||||
* calculation based on the SH (or 2nd SH in case of HRR)
|
||||
*/
|
||||
int success;
|
||||
int grease; /* 1 if we're GREASEing, 0 otherwise */
|
||||
char *grease_suite; /* HPKE suite string for GREASEing */
|
||||
unsigned char *sent; /* GREASEy ECH value sent, in case needed for re-tx */
|
||||
size_t sent_len;
|
||||
unsigned char *returned; /* binary ECHConfigList retry-configs value */
|
||||
size_t returned_len;
|
||||
unsigned char *pub; /* client ephemeral public kept by server in case HRR */
|
||||
size_t pub_len;
|
||||
OSSL_HPKE_CTX *hpke_ctx; /* HPKE context, needed for HRR */
|
||||
/*
|
||||
* Fields that differ on client between inner and outer that we need to
|
||||
* keep and swap over IFF ECH has succeeded. Same names chosen as are
|
||||
* used in SSL_CONNECTION
|
||||
*/
|
||||
EVP_PKEY *tmp_pkey; /* client's key share for inner */
|
||||
int group_id; /* key share group */
|
||||
unsigned char client_random[SSL3_RANDOM_SIZE]; /* CH random */
|
||||
} OSSL_ECH_CONN;
|
||||
|
||||
/* Internal ECH APIs */
|
||||
|
||||
OSSL_ECHSTORE *ossl_echstore_dup(const OSSL_ECHSTORE *old);
|
||||
void ossl_echstore_entry_free(OSSL_ECHSTORE_ENTRY *ee);
|
||||
void ossl_ech_ctx_clear(OSSL_ECH_CTX *ce);
|
||||
int ossl_ech_conn_init(SSL_CONNECTION *s, SSL_CTX *ctx,
|
||||
const SSL_METHOD *method);
|
||||
void ossl_ech_conn_clear(OSSL_ECH_CONN *ec);
|
||||
void ossl_echext_free(OSSL_ECHEXT *e);
|
||||
OSSL_ECHEXT *ossl_echext_dup(const OSSL_ECHEXT *src);
|
||||
|
||||
# endif
|
||||
#endif
|
426
ssl/ech/ech_ssl_apis.c
Normal file
426
ssl/ech/ech_ssl_apis.c
Normal file
|
@ -0,0 +1,426 @@
|
|||
/*
|
||||
* Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
|
||||
*
|
||||
* Licensed under the OpenSSL license (the "License"). You may not use
|
||||
* this file except in compliance with the License. You can obtain a copy
|
||||
* in the file LICENSE in the source distribution or at
|
||||
* https://www.openssl.org/source/license.html
|
||||
*/
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/ech.h>
|
||||
#include "../ssl_local.h"
|
||||
|
||||
int SSL_CTX_set1_echstore(SSL_CTX *ctx, OSSL_ECHSTORE *es)
|
||||
{
|
||||
if (ctx == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
OSSL_ECHSTORE_free(ctx->ext.ech.es);
|
||||
ctx->ext.ech.es = NULL;
|
||||
if (es == NULL)
|
||||
return 1;
|
||||
if ((ctx->ext.ech.es = ossl_echstore_dup(es)) == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SSL_set1_echstore(SSL *ssl, OSSL_ECHSTORE *es)
|
||||
{
|
||||
SSL_CONNECTION *s;
|
||||
|
||||
s = SSL_CONNECTION_FROM_SSL(ssl);
|
||||
if (s == NULL)
|
||||
return 0;
|
||||
OSSL_ECHSTORE_free(s->ext.ech.es);
|
||||
s->ext.ech.es = NULL;
|
||||
if (es == NULL)
|
||||
return 1;
|
||||
if ((s->ext.ech.es = ossl_echstore_dup(es)) == NULL) {
|
||||
SSLfatal(s, SSL_AD_INTERNAL_ERROR, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Here, and below, if the application calls an API that implies it
|
||||
* wants to try ECH, then we set attempted to 1
|
||||
*/
|
||||
s->ext.ech.attempted = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
OSSL_ECHSTORE *SSL_CTX_get1_echstore(const SSL_CTX *ctx)
|
||||
{
|
||||
OSSL_ECHSTORE *dup = NULL;
|
||||
|
||||
if (ctx == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return NULL;
|
||||
}
|
||||
if (ctx->ext.ech.es == NULL)
|
||||
return NULL;
|
||||
if ((dup = ossl_echstore_dup(ctx->ext.ech.es)) == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
|
||||
OSSL_ECHSTORE *SSL_get1_echstore(const SSL *ssl)
|
||||
{
|
||||
SSL_CONNECTION *s;
|
||||
OSSL_ECHSTORE *dup = NULL;
|
||||
|
||||
s = SSL_CONNECTION_FROM_SSL(ssl);
|
||||
if (s == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return NULL;
|
||||
}
|
||||
if (s->ext.ech.es == NULL)
|
||||
return NULL;
|
||||
if ((dup = ossl_echstore_dup(s->ext.ech.es)) == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
return dup;
|
||||
}
|
||||
|
||||
int SSL_ech_set1_server_names(SSL *ssl, const char *inner_name,
|
||||
const char *outer_name, int no_outer)
|
||||
{
|
||||
SSL_CONNECTION *s;
|
||||
|
||||
s = SSL_CONNECTION_FROM_SSL(ssl);
|
||||
if (s == NULL)
|
||||
return 0;
|
||||
OPENSSL_free(s->ext.hostname);
|
||||
s->ext.hostname = NULL;
|
||||
if (inner_name != NULL) {
|
||||
s->ext.hostname = OPENSSL_strdup(inner_name);
|
||||
if (s->ext.hostname == NULL)
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_free(s->ext.ech.outer_hostname);
|
||||
s->ext.ech.outer_hostname = NULL;
|
||||
if (no_outer == 0 && outer_name != NULL && strlen(outer_name) > 0) {
|
||||
s->ext.ech.outer_hostname = OPENSSL_strdup(outer_name);
|
||||
if (s->ext.ech.outer_hostname == NULL)
|
||||
return 0;
|
||||
}
|
||||
s->ext.ech.no_outer = no_outer;
|
||||
s->ext.ech.attempted = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SSL_ech_set1_outer_server_name(SSL *ssl, const char *outer_name,
|
||||
int no_outer)
|
||||
{
|
||||
SSL_CONNECTION *s;
|
||||
|
||||
s = SSL_CONNECTION_FROM_SSL(ssl);
|
||||
if (s == NULL)
|
||||
return 0;
|
||||
OPENSSL_free(s->ext.ech.outer_hostname);
|
||||
s->ext.ech.outer_hostname = NULL;
|
||||
if (no_outer == 0 && outer_name != NULL && strlen(outer_name) > 0) {
|
||||
s->ext.ech.outer_hostname = OPENSSL_strdup(outer_name);
|
||||
if (s->ext.ech.outer_hostname == NULL)
|
||||
return 0;
|
||||
}
|
||||
s->ext.ech.no_outer = no_outer;
|
||||
s->ext.ech.attempted = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that this function returns 1 for success and 0 for error. This
|
||||
* contrasts with SSL_set1_alpn_protos() which (unusually for OpenSSL)
|
||||
* returns 0 for success and 1 on error.
|
||||
*/
|
||||
int SSL_ech_set1_outer_alpn_protos(SSL *ssl, const unsigned char *protos,
|
||||
const size_t protos_len)
|
||||
{
|
||||
SSL_CONNECTION *s;
|
||||
|
||||
s = SSL_CONNECTION_FROM_SSL(ssl);
|
||||
if (s == NULL)
|
||||
return 0;
|
||||
OPENSSL_free(s->ext.ech.alpn_outer);
|
||||
s->ext.ech.alpn_outer = NULL;
|
||||
if (protos == NULL)
|
||||
return 1;
|
||||
if (protos_len == 0) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
s->ext.ech.alpn_outer = OPENSSL_memdup(protos, protos_len);
|
||||
if (s->ext.ech.alpn_outer == NULL)
|
||||
return 0;
|
||||
s->ext.ech.alpn_outer_len = protos_len;
|
||||
s->ext.ech.attempted = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SSL_ech_get1_status(SSL *ssl, char **inner_sni, char **outer_sni)
|
||||
{
|
||||
char *sinner = NULL;
|
||||
char *souter = NULL;
|
||||
SSL_CONNECTION *s = SSL_CONNECTION_FROM_SSL(ssl);
|
||||
|
||||
if (s == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return SSL_ECH_STATUS_FAILED;
|
||||
}
|
||||
if (outer_sni == NULL || inner_sni == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
return SSL_ECH_STATUS_FAILED;
|
||||
}
|
||||
*outer_sni = NULL;
|
||||
*inner_sni = NULL;
|
||||
if (s->ext.ech.grease == OSSL_ECH_IS_GREASE) {
|
||||
if (s->ext.ech.returned != NULL)
|
||||
return SSL_ECH_STATUS_GREASE_ECH;
|
||||
return SSL_ECH_STATUS_GREASE;
|
||||
}
|
||||
if (s->options & SSL_OP_ECH_GREASE)
|
||||
return SSL_ECH_STATUS_GREASE;
|
||||
if (s->ext.ech.backend == 1) {
|
||||
if (s->ext.hostname != NULL
|
||||
&& (*inner_sni = OPENSSL_strdup(s->ext.hostname)) == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
return SSL_ECH_STATUS_FAILED;
|
||||
}
|
||||
return SSL_ECH_STATUS_BACKEND;
|
||||
}
|
||||
if (s->ext.ech.es == NULL)
|
||||
return SSL_ECH_STATUS_NOT_CONFIGURED;
|
||||
/* Set output vars - note we may be pointing to NULL which is fine */
|
||||
if (s->server == 0) {
|
||||
sinner = s->ext.hostname;
|
||||
if (s->ext.ech.attempted == 1 && s->ext.ech.success == 0)
|
||||
sinner = s->ext.ech.former_inner;
|
||||
if (s->ext.ech.no_outer == 0)
|
||||
souter = s->ext.ech.outer_hostname;
|
||||
else
|
||||
souter = NULL;
|
||||
} else {
|
||||
if (s->ext.ech.es != NULL && s->ext.ech.success == 1) {
|
||||
sinner = s->ext.hostname;
|
||||
souter = s->ext.ech.outer_hostname;
|
||||
}
|
||||
}
|
||||
if (s->ext.ech.es != NULL && s->ext.ech.attempted == 1
|
||||
&& s->ext.ech.attempted_type == TLSEXT_TYPE_ech
|
||||
&& s->ext.ech.grease != OSSL_ECH_IS_GREASE) {
|
||||
long vr = X509_V_OK;
|
||||
|
||||
vr = SSL_get_verify_result(ssl);
|
||||
if (sinner != NULL
|
||||
&& (*inner_sni = OPENSSL_strdup(sinner)) == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
return SSL_ECH_STATUS_FAILED;
|
||||
}
|
||||
if (souter != NULL
|
||||
&& (*outer_sni = OPENSSL_strdup(souter)) == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
return SSL_ECH_STATUS_FAILED;
|
||||
}
|
||||
if (s->ext.ech.success == 1) {
|
||||
if (vr == X509_V_OK)
|
||||
return SSL_ECH_STATUS_SUCCESS;
|
||||
else
|
||||
return SSL_ECH_STATUS_BAD_NAME;
|
||||
} else {
|
||||
if (vr == X509_V_OK && s->ext.ech.returned != NULL)
|
||||
return SSL_ECH_STATUS_FAILED_ECH;
|
||||
else if (vr != X509_V_OK && s->ext.ech.returned != NULL)
|
||||
return SSL_ECH_STATUS_FAILED_ECH_BAD_NAME;
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
return SSL_ECH_STATUS_FAILED;
|
||||
}
|
||||
}
|
||||
return SSL_ECH_STATUS_NOT_TRIED;
|
||||
}
|
||||
|
||||
int SSL_ech_set1_grease_suite(SSL *ssl, const char *suite)
|
||||
{
|
||||
SSL_CONNECTION *s;
|
||||
|
||||
s = SSL_CONNECTION_FROM_SSL(ssl);
|
||||
if (s == NULL)
|
||||
return 0;
|
||||
OPENSSL_free(s->ext.ech.grease_suite);
|
||||
s->ext.ech.grease_suite = NULL;
|
||||
if (suite == NULL)
|
||||
return 1;
|
||||
s->ext.ech.grease_suite = OPENSSL_strdup(suite);
|
||||
if (s->ext.ech.grease_suite == NULL)
|
||||
return 0;
|
||||
s->ext.ech.attempted = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SSL_ech_set_grease_type(SSL *ssl, uint16_t type)
|
||||
{
|
||||
SSL_CONNECTION *s;
|
||||
|
||||
s = SSL_CONNECTION_FROM_SSL(ssl);
|
||||
if (s == NULL)
|
||||
return 0;
|
||||
s->ext.ech.attempted_type = type;
|
||||
s->ext.ech.attempted = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void SSL_ech_set_callback(SSL *ssl, SSL_ech_cb_func f)
|
||||
{
|
||||
SSL_CONNECTION *s;
|
||||
|
||||
s = SSL_CONNECTION_FROM_SSL(ssl);
|
||||
if (s == NULL)
|
||||
return;
|
||||
s->ext.ech.cb = f;
|
||||
return;
|
||||
}
|
||||
|
||||
int SSL_ech_get1_retry_config(SSL *ssl, unsigned char **ec, size_t *eclen)
|
||||
{
|
||||
SSL_CONNECTION *s;
|
||||
OSSL_ECHSTORE *ve = NULL;
|
||||
BIO *in = NULL;
|
||||
int rv = 0;
|
||||
|
||||
s = SSL_CONNECTION_FROM_SSL(ssl);
|
||||
if (s == NULL || ec == NULL || eclen == NULL)
|
||||
goto err;
|
||||
if (s->ext.ech.returned == NULL) {
|
||||
*ec = NULL;
|
||||
*eclen = 0;
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* To not hand rubbish to application, we'll decode the value we have
|
||||
* so only syntactically good things are passed up. We won't insist
|
||||
* though that every entry in the retry_config list seems good - it
|
||||
* could be that e.g. one is a newer version than we support now,
|
||||
* and letting the application see that might cause someone to do an
|
||||
* upgrade.
|
||||
*/
|
||||
if ((in = BIO_new(BIO_s_mem())) == NULL
|
||||
|| BIO_write(in, s->ext.ech.returned, s->ext.ech.returned_len) <= 0
|
||||
|| (ve = OSSL_ECHSTORE_new(s->ext.ech.es->libctx,
|
||||
s->ext.ech.es->propq)) == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
if (OSSL_ECHSTORE_read_echconfiglist(ve, in) != 1) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
/* all good, copy and return */
|
||||
*ec = OPENSSL_memdup(s->ext.ech.returned, s->ext.ech.returned_len);
|
||||
if (*ec == NULL)
|
||||
goto err;
|
||||
*eclen = s->ext.ech.returned_len;
|
||||
rv = 1;
|
||||
err:
|
||||
OSSL_ECHSTORE_free(ve);
|
||||
BIO_free_all(in);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that this function returns 1 for success and 0 for error. This
|
||||
* contrasts with SSL_CTX_set1_alpn_protos() which (unusually for OpenSSL)
|
||||
* returns 0 for success and 1 on error.
|
||||
*/
|
||||
int SSL_CTX_ech_set1_outer_alpn_protos(SSL_CTX *ctx,
|
||||
const unsigned char *protos,
|
||||
const size_t protos_len)
|
||||
{
|
||||
if (ctx == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
OPENSSL_free(ctx->ext.ech.alpn_outer);
|
||||
ctx->ext.ech.alpn_outer = NULL;
|
||||
if (protos == NULL)
|
||||
return 1;
|
||||
if (protos_len == 0) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
ctx->ext.ech.alpn_outer = OPENSSL_memdup(protos, protos_len);
|
||||
if (ctx->ext.ech.alpn_outer == NULL)
|
||||
return 0;
|
||||
ctx->ext.ech.alpn_outer_len = protos_len;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int SSL_CTX_ech_raw_decrypt(SSL_CTX *ctx,
|
||||
int *decrypted_ok,
|
||||
char **inner_sni, char **outer_sni,
|
||||
unsigned char *outer_ch, size_t outer_len,
|
||||
unsigned char *inner_ch, size_t *inner_len,
|
||||
unsigned char **hrrtok, size_t *toklen)
|
||||
{
|
||||
if (ctx == NULL) {
|
||||
/*
|
||||
* TODO(ECH): this is a bit of a bogus error, just so as
|
||||
* to get the `make update` command to add the required
|
||||
* error number. We don't need it yet, but it's involved
|
||||
* in some of the build artefacts, so may as well jump
|
||||
* the gun a bit on it.
|
||||
*/
|
||||
ERR_raise(ERR_LIB_SSL, SSL_R_ECH_REQUIRED);
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SSL_CTX_ech_set_callback(SSL_CTX *ctx, SSL_ech_cb_func f)
|
||||
{
|
||||
if (ctx == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return;
|
||||
}
|
||||
ctx->ext.ech.cb = f;
|
||||
return;
|
||||
}
|
||||
|
||||
int SSL_set1_ech_config_list(SSL *ssl, const uint8_t *ecl, size_t ecl_len)
|
||||
{
|
||||
int rv = 0;
|
||||
SSL_CONNECTION *s;
|
||||
OSSL_ECHSTORE *es = NULL;
|
||||
BIO *es_in = NULL;
|
||||
|
||||
s = SSL_CONNECTION_FROM_SSL(ssl);
|
||||
if (s == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);
|
||||
goto err;
|
||||
}
|
||||
if (ecl == NULL) {
|
||||
OSSL_ECHSTORE_free(s->ext.ech.es);
|
||||
s->ext.ech.es = NULL;
|
||||
return 1;
|
||||
}
|
||||
if (ecl_len == 0) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
if ((es_in = BIO_new_mem_buf(ecl, ecl_len)) == NULL
|
||||
|| (es = OSSL_ECHSTORE_new(NULL, NULL)) == NULL
|
||||
|| OSSL_ECHSTORE_read_echconfiglist(es, es_in) != 1
|
||||
|| SSL_set1_echstore(ssl, es) != 1) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
rv = 1;
|
||||
err:
|
||||
OSSL_ECHSTORE_free(es);
|
||||
BIO_free_all(es_in);
|
||||
return rv;
|
||||
}
|
1133
ssl/ech/ech_store.c
Normal file
1133
ssl/ech/ech_store.c
Normal file
File diff suppressed because it is too large
Load diff
498
ssl/ssl_err.c
498
ssl/ssl_err.c
|
@ -16,33 +16,35 @@
|
|||
|
||||
static const ERR_STRING_DATA SSL_str_reasons[] = {
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY),
|
||||
"application data after close notify"},
|
||||
"application data after close notify"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_APP_DATA_IN_HANDSHAKE),
|
||||
"app data in handshake"},
|
||||
"app data in handshake"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ATTEMPT_TO_REUSE_SESSION_IN_DIFFERENT_CONTEXT),
|
||||
"attempt to reuse session in different context"},
|
||||
"attempt to reuse session in different context"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_AT_LEAST_TLS_1_2_NEEDED_IN_SUITEB_MODE),
|
||||
"at least (D)TLS 1.2 needed in Suite B mode"},
|
||||
"at least (D)TLS 1.2 needed in Suite B mode"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CERTIFICATE), "bad certificate"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CHANGE_CIPHER_SPEC),
|
||||
"bad change cipher spec"},
|
||||
"bad change cipher spec"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_CIPHER), "bad cipher"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_COMPRESSION_ALGORITHM),
|
||||
"bad compression algorithm"},
|
||||
"bad compression algorithm"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA), "bad data"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DATA_RETURNED_BY_CALLBACK),
|
||||
"bad data returned by callback"},
|
||||
"bad data returned by callback"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DECOMPRESSION), "bad decompression"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DH_VALUE), "bad dh value"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_DIGEST_LENGTH), "bad digest length"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_EARLY_DATA), "bad early data"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_ECC_CERT), "bad ecc cert"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_ECHCONFIG_EXTENSION),
|
||||
"bad echconfig extension"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_ECPOINT), "bad ecpoint"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_EXTENSION), "bad extension"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HANDSHAKE_LENGTH),
|
||||
"bad handshake length"},
|
||||
"bad handshake length"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HANDSHAKE_STATE),
|
||||
"bad handshake state"},
|
||||
"bad handshake state"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HELLO_REQUEST), "bad hello request"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_HRR_VERSION), "bad hrr version"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_KEY_SHARE), "bad key share"},
|
||||
|
@ -52,7 +54,7 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
|
|||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PACKET), "bad packet"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PACKET_LENGTH), "bad packet length"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PROTOCOL_VERSION_NUMBER),
|
||||
"bad protocol version number"},
|
||||
"bad protocol version number"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PSK), "bad psk"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_PSK_IDENTITY), "bad psk identity"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_RECORD_TYPE), "bad record type"},
|
||||
|
@ -62,560 +64,562 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
|
|||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRP_PARAMETERS), "bad srp parameters"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRTP_MKI_VALUE), "bad srtp mki value"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SRTP_PROTECTION_PROFILE_LIST),
|
||||
"bad srtp protection profile list"},
|
||||
"bad srtp protection profile list"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_SSL_FILETYPE), "bad ssl filetype"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_VALUE), "bad value"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BAD_WRITE_RETRY), "bad write retry"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BINDER_DOES_NOT_VERIFY),
|
||||
"binder does not verify"},
|
||||
"binder does not verify"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BIO_NOT_SET), "bio not set"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BLOCK_CIPHER_PAD_IS_WRONG),
|
||||
"block cipher pad is wrong"},
|
||||
"block cipher pad is wrong"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_BN_LIB), "bn lib"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CALLBACK_FAILED), "callback failed"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CANNOT_CHANGE_CIPHER),
|
||||
"cannot change cipher"},
|
||||
"cannot change cipher"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CANNOT_GET_GROUP_NAME),
|
||||
"cannot get group name"},
|
||||
"cannot get group name"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CA_DN_LENGTH_MISMATCH),
|
||||
"ca dn length mismatch"},
|
||||
"ca dn length mismatch"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CA_KEY_TOO_SMALL), "ca key too small"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CA_MD_TOO_WEAK), "ca md too weak"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CCS_RECEIVED_EARLY), "ccs received early"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CERTIFICATE_VERIFY_FAILED),
|
||||
"certificate verify failed"},
|
||||
"certificate verify failed"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CERT_CB_ERROR), "cert cb error"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CERT_LENGTH_MISMATCH),
|
||||
"cert length mismatch"},
|
||||
"cert length mismatch"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CIPHERSUITE_DIGEST_HAS_CHANGED),
|
||||
"ciphersuite digest has changed"},
|
||||
"ciphersuite digest has changed"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CIPHER_CODE_WRONG_LENGTH),
|
||||
"cipher code wrong length"},
|
||||
"cipher code wrong length"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CLIENTHELLO_TLSEXT), "clienthello tlsext"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSED_LENGTH_TOO_LONG),
|
||||
"compressed length too long"},
|
||||
"compressed length too long"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_DISABLED),
|
||||
"compression disabled"},
|
||||
"compression disabled"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_FAILURE),
|
||||
"compression failure"},
|
||||
"compression failure"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_ID_NOT_WITHIN_PRIVATE_RANGE),
|
||||
"compression id not within private range"},
|
||||
"compression id not within private range"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COMPRESSION_LIBRARY_ERROR),
|
||||
"compression library error"},
|
||||
"compression library error"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CONNECTION_TYPE_NOT_SET),
|
||||
"connection type not set"},
|
||||
"connection type not set"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CONN_USE_ONLY), "conn use only"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CONTEXT_NOT_DANE_ENABLED),
|
||||
"context not dane enabled"},
|
||||
"context not dane enabled"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COOKIE_GEN_CALLBACK_FAILURE),
|
||||
"cookie gen callback failure"},
|
||||
"cookie gen callback failure"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COOKIE_MISMATCH), "cookie mismatch"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_COPY_PARAMETERS_FAILED),
|
||||
"copy parameters failed"},
|
||||
"copy parameters failed"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_CUSTOM_EXT_HANDLER_ALREADY_INSTALLED),
|
||||
"custom ext handler already installed"},
|
||||
"custom ext handler already installed"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_ALREADY_ENABLED),
|
||||
"dane already enabled"},
|
||||
"dane already enabled"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_CANNOT_OVERRIDE_MTYPE_FULL),
|
||||
"dane cannot override mtype full"},
|
||||
"dane cannot override mtype full"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_NOT_ENABLED), "dane not enabled"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_BAD_CERTIFICATE),
|
||||
"dane tlsa bad certificate"},
|
||||
"dane tlsa bad certificate"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_BAD_CERTIFICATE_USAGE),
|
||||
"dane tlsa bad certificate usage"},
|
||||
"dane tlsa bad certificate usage"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_BAD_DATA_LENGTH),
|
||||
"dane tlsa bad data length"},
|
||||
"dane tlsa bad data length"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_BAD_DIGEST_LENGTH),
|
||||
"dane tlsa bad digest length"},
|
||||
"dane tlsa bad digest length"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_BAD_MATCHING_TYPE),
|
||||
"dane tlsa bad matching type"},
|
||||
"dane tlsa bad matching type"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_BAD_PUBLIC_KEY),
|
||||
"dane tlsa bad public key"},
|
||||
"dane tlsa bad public key"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_BAD_SELECTOR),
|
||||
"dane tlsa bad selector"},
|
||||
"dane tlsa bad selector"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DANE_TLSA_NULL_DATA),
|
||||
"dane tlsa null data"},
|
||||
"dane tlsa null data"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DATA_BETWEEN_CCS_AND_FINISHED),
|
||||
"data between ccs and finished"},
|
||||
"data between ccs and finished"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DATA_LENGTH_TOO_LONG),
|
||||
"data length too long"},
|
||||
"data length too long"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DECRYPTION_FAILED), "decryption failed"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC),
|
||||
"decryption failed or bad record mac"},
|
||||
"decryption failed or bad record mac"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DH_KEY_TOO_SMALL), "dh key too small"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DH_PUBLIC_VALUE_LENGTH_IS_WRONG),
|
||||
"dh public value length is wrong"},
|
||||
"dh public value length is wrong"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DIGEST_CHECK_FAILED),
|
||||
"digest check failed"},
|
||||
"digest check failed"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DTLS_MESSAGE_TOO_BIG),
|
||||
"dtls message too big"},
|
||||
"dtls message too big"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_DUPLICATE_COMPRESSION_ID),
|
||||
"duplicate compression id"},
|
||||
"duplicate compression id"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECC_CERT_NOT_FOR_SIGNING),
|
||||
"ecc cert not for signing"},
|
||||
"ecc cert not for signing"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECDH_REQUIRED_FOR_SUITEB_MODE),
|
||||
"ecdh required for suiteb mode"},
|
||||
"ecdh required for suiteb mode"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECH_DECODE_ERROR), "ech decode error"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ECH_REQUIRED), "ech required"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EE_KEY_TOO_SMALL), "ee key too small"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EMPTY_RAW_PUBLIC_KEY),
|
||||
"empty raw public key"},
|
||||
"empty raw public key"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EMPTY_SRTP_PROTECTION_PROFILE_LIST),
|
||||
"empty srtp protection profile list"},
|
||||
"empty srtp protection profile list"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ENCRYPTED_LENGTH_TOO_LONG),
|
||||
"encrypted length too long"},
|
||||
"encrypted length too long"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST),
|
||||
"error in received cipher list"},
|
||||
"error in received cipher list"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ERROR_IN_SYSTEM_DEFAULT_CONFIG),
|
||||
"error in system default config"},
|
||||
"error in system default config"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ERROR_SETTING_TLSA_BASE_DOMAIN),
|
||||
"error setting tlsa base domain"},
|
||||
"error setting tlsa base domain"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXCEEDS_MAX_FRAGMENT_SIZE),
|
||||
"exceeds max fragment size"},
|
||||
"exceeds max fragment size"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXCESSIVE_MESSAGE_SIZE),
|
||||
"excessive message size"},
|
||||
"excessive message size"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXTENSION_NOT_RECEIVED),
|
||||
"extension not received"},
|
||||
"extension not received"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXTRA_DATA_IN_MESSAGE),
|
||||
"extra data in message"},
|
||||
"extra data in message"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_EXT_LENGTH_MISMATCH),
|
||||
"ext length mismatch"},
|
||||
"ext length mismatch"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_FAILED_TO_GET_PARAMETER),
|
||||
"failed to get parameter"},
|
||||
"failed to get parameter"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_FAILED_TO_INIT_ASYNC),
|
||||
"failed to init async"},
|
||||
"failed to init async"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_FEATURE_NEGOTIATION_NOT_COMPLETE),
|
||||
"feature negotiation not complete"},
|
||||
"feature negotiation not complete"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_FEATURE_NOT_RENEGOTIABLE),
|
||||
"feature not renegotiable"},
|
||||
"feature not renegotiable"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_FRAGMENTED_CLIENT_HELLO),
|
||||
"fragmented client hello"},
|
||||
"fragmented client hello"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_GOT_A_FIN_BEFORE_A_CCS),
|
||||
"got a fin before a ccs"},
|
||||
"got a fin before a ccs"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HTTPS_PROXY_REQUEST),
|
||||
"https proxy request"},
|
||||
"https proxy request"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_HTTP_REQUEST), "http request"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ILLEGAL_POINT_COMPRESSION),
|
||||
"illegal point compression"},
|
||||
"illegal point compression"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_ILLEGAL_SUITEB_DIGEST),
|
||||
"illegal Suite B digest"},
|
||||
"illegal Suite B digest"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INAPPROPRIATE_FALLBACK),
|
||||
"inappropriate fallback"},
|
||||
"inappropriate fallback"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_COMPRESSION),
|
||||
"inconsistent compression"},
|
||||
"inconsistent compression"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_EARLY_DATA_ALPN),
|
||||
"inconsistent early data alpn"},
|
||||
"inconsistent early data alpn"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_EARLY_DATA_SNI),
|
||||
"inconsistent early data sni"},
|
||||
"inconsistent early data sni"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INCONSISTENT_EXTMS), "inconsistent extms"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INSUFFICIENT_SECURITY),
|
||||
"insufficient security"},
|
||||
"insufficient security"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_ALERT), "invalid alert"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CCS_MESSAGE),
|
||||
"invalid ccs message"},
|
||||
"invalid ccs message"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CERTIFICATE_OR_ALG),
|
||||
"invalid certificate or alg"},
|
||||
"invalid certificate or alg"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_COMMAND), "invalid command"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_COMPRESSION_ALGORITHM),
|
||||
"invalid compression algorithm"},
|
||||
"invalid compression algorithm"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CONFIG), "invalid config"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CONFIGURATION_NAME),
|
||||
"invalid configuration name"},
|
||||
"invalid configuration name"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CONTEXT), "invalid context"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_CT_VALIDATION_TYPE),
|
||||
"invalid ct validation type"},
|
||||
"invalid ct validation type"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_KEY_UPDATE_TYPE),
|
||||
"invalid key update type"},
|
||||
"invalid key update type"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_MAX_EARLY_DATA),
|
||||
"invalid max early data"},
|
||||
"invalid max early data"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_NULL_CMD_NAME),
|
||||
"invalid null cmd name"},
|
||||
"invalid null cmd name"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_RAW_PUBLIC_KEY),
|
||||
"invalid raw public key"},
|
||||
"invalid raw public key"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_RECORD), "invalid record"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SEQUENCE_NUMBER),
|
||||
"invalid sequence number"},
|
||||
"invalid sequence number"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SERVERINFO_DATA),
|
||||
"invalid serverinfo data"},
|
||||
"invalid serverinfo data"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SESSION_ID), "invalid session id"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_SRP_USERNAME),
|
||||
"invalid srp username"},
|
||||
"invalid srp username"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_STATUS_RESPONSE),
|
||||
"invalid status response"},
|
||||
"invalid status response"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_INVALID_TICKET_KEYS_LENGTH),
|
||||
"invalid ticket keys length"},
|
||||
"invalid ticket keys length"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED),
|
||||
"legacy sigalg disallowed or unsupported"},
|
||||
"legacy sigalg disallowed or unsupported"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LENGTH_MISMATCH), "length mismatch"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LENGTH_TOO_LONG), "length too long"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LENGTH_TOO_SHORT), "length too short"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LIBRARY_BUG), "library bug"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_LIBRARY_HAS_NO_CIPHERS),
|
||||
"library has no ciphers"},
|
||||
"library has no ciphers"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MAXIMUM_ENCRYPTED_PKTS_REACHED),
|
||||
"maximum encrypted pkts reached"},
|
||||
"maximum encrypted pkts reached"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_DSA_SIGNING_CERT),
|
||||
"missing dsa signing cert"},
|
||||
"missing dsa signing cert"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_ECDSA_SIGNING_CERT),
|
||||
"missing ecdsa signing cert"},
|
||||
"missing ecdsa signing cert"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_FATAL), "missing fatal"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_PARAMETERS), "missing parameters"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_PSK_KEX_MODES_EXTENSION),
|
||||
"missing psk kex modes extension"},
|
||||
"missing psk kex modes extension"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_CERTIFICATE),
|
||||
"missing rsa certificate"},
|
||||
"missing rsa certificate"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_ENCRYPTING_CERT),
|
||||
"missing rsa encrypting cert"},
|
||||
"missing rsa encrypting cert"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_RSA_SIGNING_CERT),
|
||||
"missing rsa signing cert"},
|
||||
"missing rsa signing cert"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_SIGALGS_EXTENSION),
|
||||
"missing sigalgs extension"},
|
||||
"missing sigalgs extension"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_SIGNING_CERT),
|
||||
"missing signing cert"},
|
||||
"missing signing cert"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_SRP_PARAM),
|
||||
"can't find SRP server param"},
|
||||
"can't find SRP server param"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_SUPPORTED_GROUPS_EXTENSION),
|
||||
"missing supported groups extension"},
|
||||
"missing supported groups extension"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_SUPPORTED_VERSIONS_EXTENSION),
|
||||
"missing supported versions extension"},
|
||||
"missing supported versions extension"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_DH_KEY), "missing tmp dh key"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MISSING_TMP_ECDH_KEY),
|
||||
"missing tmp ecdh key"},
|
||||
"missing tmp ecdh key"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA),
|
||||
"mixed handshake and non handshake data"},
|
||||
"mixed handshake and non handshake data"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_ON_RECORD_BOUNDARY),
|
||||
"not on record boundary"},
|
||||
"not on record boundary"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_REPLACING_CERTIFICATE),
|
||||
"not replacing certificate"},
|
||||
"not replacing certificate"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NOT_SERVER), "not server"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_APPLICATION_PROTOCOL),
|
||||
"no application protocol"},
|
||||
"no application protocol"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATES_RETURNED),
|
||||
"no certificates returned"},
|
||||
"no certificates returned"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATE_ASSIGNED),
|
||||
"no certificate assigned"},
|
||||
"no certificate assigned"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CERTIFICATE_SET), "no certificate set"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CHANGE_FOLLOWING_HRR),
|
||||
"no change following hrr"},
|
||||
"no change following hrr"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHERS_AVAILABLE),
|
||||
"no ciphers available"},
|
||||
"no ciphers available"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHERS_SPECIFIED),
|
||||
"no ciphers specified"},
|
||||
"no ciphers specified"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CIPHER_MATCH), "no cipher match"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_CLIENT_CERT_METHOD),
|
||||
"no client cert method"},
|
||||
"no client cert method"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_COMPRESSION_SPECIFIED),
|
||||
"no compression specified"},
|
||||
"no compression specified"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_COOKIE_CALLBACK_SET),
|
||||
"no cookie callback set"},
|
||||
"no cookie callback set"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_GOST_CERTIFICATE_SENT_BY_PEER),
|
||||
"Peer haven't sent GOST certificate, required for selected ciphersuite"},
|
||||
"Peer haven't sent GOST certificate, required for selected ciphersuite"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_METHOD_SPECIFIED),
|
||||
"no method specified"},
|
||||
"no method specified"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PEM_EXTENSIONS), "no pem extensions"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PRIVATE_KEY_ASSIGNED),
|
||||
"no private key assigned"},
|
||||
"no private key assigned"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_PROTOCOLS_AVAILABLE),
|
||||
"no protocols available"},
|
||||
"no protocols available"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_RENEGOTIATION), "no renegotiation"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_REQUIRED_DIGEST), "no required digest"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SHARED_CIPHER), "no shared cipher"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SHARED_GROUPS), "no shared groups"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS),
|
||||
"no shared signature algorithms"},
|
||||
"no shared signature algorithms"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SRTP_PROFILES), "no srtp profiles"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_STREAM), "no stream"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SUITABLE_DIGEST_ALGORITHM),
|
||||
"no suitable digest algorithm"},
|
||||
"no suitable digest algorithm"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SUITABLE_GROUPS), "no suitable groups"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SUITABLE_KEY_SHARE),
|
||||
"no suitable key share"},
|
||||
"no suitable key share"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SUITABLE_RECORD_LAYER),
|
||||
"no suitable record layer"},
|
||||
"no suitable record layer"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM),
|
||||
"no suitable signature algorithm"},
|
||||
"no suitable signature algorithm"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_VALID_SCTS), "no valid scts"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NO_VERIFY_COOKIE_CALLBACK),
|
||||
"no verify cookie callback"},
|
||||
"no verify cookie callback"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NULL_SSL_CTX), "null ssl ctx"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_NULL_SSL_METHOD_PASSED),
|
||||
"null ssl method passed"},
|
||||
"null ssl method passed"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_OCSP_CALLBACK_FAILURE),
|
||||
"ocsp callback failure"},
|
||||
"ocsp callback failure"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED),
|
||||
"old session cipher not returned"},
|
||||
"old session cipher not returned"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_OLD_SESSION_COMPRESSION_ALGORITHM_NOT_RETURNED),
|
||||
"old session compression algorithm not returned"},
|
||||
"old session compression algorithm not returned"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_OVERFLOW_ERROR), "overflow error"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PACKET_LENGTH_TOO_LONG),
|
||||
"packet length too long"},
|
||||
"packet length too long"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PARSE_TLSEXT), "parse tlsext"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PATH_TOO_LONG), "path too long"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEER_DID_NOT_RETURN_A_CERTIFICATE),
|
||||
"peer did not return a certificate"},
|
||||
"peer did not return a certificate"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEM_NAME_BAD_PREFIX),
|
||||
"pem name bad prefix"},
|
||||
"pem name bad prefix"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PEM_NAME_TOO_SHORT), "pem name too short"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PIPELINE_FAILURE), "pipeline failure"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_POLL_REQUEST_NOT_SUPPORTED),
|
||||
"poll request not supported"},
|
||||
"poll request not supported"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_POST_HANDSHAKE_AUTH_ENCODING_ERR),
|
||||
"post handshake auth encoding err"},
|
||||
"post handshake auth encoding err"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PRIVATE_KEY_MISMATCH),
|
||||
"private key mismatch"},
|
||||
"private key mismatch"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PROTOCOL_IS_SHUTDOWN),
|
||||
"protocol is shutdown"},
|
||||
"protocol is shutdown"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PSK_IDENTITY_NOT_FOUND),
|
||||
"psk identity not found"},
|
||||
"psk identity not found"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PSK_NO_CLIENT_CB), "psk no client cb"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_PSK_NO_SERVER_CB), "psk no server cb"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_QUIC_HANDSHAKE_LAYER_ERROR),
|
||||
"quic handshake layer error"},
|
||||
"quic handshake layer error"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_QUIC_NETWORK_ERROR), "quic network error"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_QUIC_PROTOCOL_ERROR),
|
||||
"quic protocol error"},
|
||||
"quic protocol error"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_READ_BIO_NOT_SET), "read bio not set"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_READ_TIMEOUT_EXPIRED),
|
||||
"read timeout expired"},
|
||||
"read timeout expired"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORDS_NOT_RELEASED),
|
||||
"records not released"},
|
||||
"records not released"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORD_LAYER_FAILURE),
|
||||
"record layer failure"},
|
||||
"record layer failure"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORD_LENGTH_MISMATCH),
|
||||
"record length mismatch"},
|
||||
"record length mismatch"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RECORD_TOO_SMALL), "record too small"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REMOTE_PEER_ADDRESS_NOT_SET),
|
||||
"remote peer address not set"},
|
||||
"remote peer address not set"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RENEGOTIATE_EXT_TOO_LONG),
|
||||
"renegotiate ext too long"},
|
||||
"renegotiate ext too long"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RENEGOTIATION_ENCODING_ERR),
|
||||
"renegotiation encoding err"},
|
||||
"renegotiation encoding err"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_RENEGOTIATION_MISMATCH),
|
||||
"renegotiation mismatch"},
|
||||
"renegotiation mismatch"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUEST_PENDING), "request pending"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUEST_SENT), "request sent"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUIRED_CIPHER_MISSING),
|
||||
"required cipher missing"},
|
||||
"required cipher missing"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_REQUIRED_COMPRESSION_ALGORITHM_MISSING),
|
||||
"required compression algorithm missing"},
|
||||
"required compression algorithm missing"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SCSV_RECEIVED_WHEN_RENEGOTIATING),
|
||||
"scsv received when renegotiating"},
|
||||
"scsv received when renegotiating"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SCT_VERIFICATION_FAILED),
|
||||
"sct verification failed"},
|
||||
"sct verification failed"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SEQUENCE_CTR_WRAPPED),
|
||||
"sequence ctr wrapped"},
|
||||
"sequence ctr wrapped"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SERVERHELLO_TLSEXT), "serverhello tlsext"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SESSION_ID_CONTEXT_UNINITIALIZED),
|
||||
"session id context uninitialized"},
|
||||
"session id context uninitialized"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SHUTDOWN_WHILE_IN_INIT),
|
||||
"shutdown while in init"},
|
||||
"shutdown while in init"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SIGNATURE_ALGORITHMS_ERROR),
|
||||
"signature algorithms error"},
|
||||
"signature algorithms error"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SIGNATURE_FOR_NON_SIGNING_CERTIFICATE),
|
||||
"signature for non signing certificate"},
|
||||
"signature for non signing certificate"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRP_A_CALC), "error with the srp params"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRTP_COULD_NOT_ALLOCATE_PROFILES),
|
||||
"srtp could not allocate profiles"},
|
||||
"srtp could not allocate profiles"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRTP_PROTECTION_PROFILE_LIST_TOO_LONG),
|
||||
"srtp protection profile list too long"},
|
||||
"srtp protection profile list too long"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SRTP_UNKNOWN_PROTECTION_PROFILE),
|
||||
"srtp unknown protection profile"},
|
||||
"srtp unknown protection profile"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_EXT_INVALID_MAX_FRAGMENT_LENGTH),
|
||||
"ssl3 ext invalid max fragment length"},
|
||||
"ssl3 ext invalid max fragment length"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_EXT_INVALID_SERVERNAME),
|
||||
"ssl3 ext invalid servername"},
|
||||
"ssl3 ext invalid servername"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_EXT_INVALID_SERVERNAME_TYPE),
|
||||
"ssl3 ext invalid servername type"},
|
||||
"ssl3 ext invalid servername type"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL3_SESSION_ID_TOO_LONG),
|
||||
"ssl3 session id too long"},
|
||||
"ssl3 session id too long"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_BAD_CERTIFICATE),
|
||||
"ssl/tls alert bad certificate"},
|
||||
"ssl/tls alert bad certificate"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_BAD_RECORD_MAC),
|
||||
"ssl/tls alert bad record mac"},
|
||||
"ssl/tls alert bad record mac"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED),
|
||||
"ssl/tls alert certificate expired"},
|
||||
"ssl/tls alert certificate expired"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED),
|
||||
"ssl/tls alert certificate revoked"},
|
||||
"ssl/tls alert certificate revoked"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN),
|
||||
"ssl/tls alert certificate unknown"},
|
||||
"ssl/tls alert certificate unknown"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE),
|
||||
"ssl/tls alert decompression failure"},
|
||||
"ssl/tls alert decompression failure"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE),
|
||||
"ssl/tls alert handshake failure"},
|
||||
"ssl/tls alert handshake failure"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER),
|
||||
"ssl/tls alert illegal parameter"},
|
||||
"ssl/tls alert illegal parameter"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_NO_CERTIFICATE),
|
||||
"ssl/tls alert no certificate"},
|
||||
"ssl/tls alert no certificate"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE),
|
||||
"ssl/tls alert unexpected message"},
|
||||
"ssl/tls alert unexpected message"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE),
|
||||
"ssl/tls alert unsupported certificate"},
|
||||
"ssl/tls alert unsupported certificate"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_COMMAND_SECTION_EMPTY),
|
||||
"ssl command section empty"},
|
||||
"ssl command section empty"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_COMMAND_SECTION_NOT_FOUND),
|
||||
"ssl command section not found"},
|
||||
"ssl command section not found"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_CTX_HAS_NO_DEFAULT_SSL_VERSION),
|
||||
"ssl ctx has no default ssl version"},
|
||||
"ssl ctx has no default ssl version"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_HANDSHAKE_FAILURE),
|
||||
"ssl handshake failure"},
|
||||
"ssl handshake failure"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_LIBRARY_HAS_NO_CIPHERS),
|
||||
"ssl library has no ciphers"},
|
||||
"ssl library has no ciphers"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_NEGATIVE_LENGTH),
|
||||
"ssl negative length"},
|
||||
"ssl negative length"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SECTION_EMPTY), "ssl section empty"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SECTION_NOT_FOUND),
|
||||
"ssl section not found"},
|
||||
"ssl section not found"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_CALLBACK_FAILED),
|
||||
"ssl session id callback failed"},
|
||||
"ssl session id callback failed"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_CONFLICT),
|
||||
"ssl session id conflict"},
|
||||
"ssl session id conflict"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_CONTEXT_TOO_LONG),
|
||||
"ssl session id context too long"},
|
||||
"ssl session id context too long"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_HAS_BAD_LENGTH),
|
||||
"ssl session id has bad length"},
|
||||
"ssl session id has bad length"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_ID_TOO_LONG),
|
||||
"ssl session id too long"},
|
||||
"ssl session id too long"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_SSL_SESSION_VERSION_MISMATCH),
|
||||
"ssl session version mismatch"},
|
||||
"ssl session version mismatch"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_STILL_IN_INIT), "still in init"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_STREAM_COUNT_LIMITED),
|
||||
"stream count limited"},
|
||||
"stream count limited"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_STREAM_FINISHED), "stream finished"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_STREAM_RECV_ONLY), "stream recv only"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_STREAM_RESET), "stream reset"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_STREAM_SEND_ONLY), "stream send only"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED),
|
||||
"tlsv13 alert certificate required"},
|
||||
"tlsv13 alert certificate required"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV13_ALERT_MISSING_EXTENSION),
|
||||
"tlsv13 alert missing extension"},
|
||||
"tlsv13 alert missing extension"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_ACCESS_DENIED),
|
||||
"tlsv1 alert access denied"},
|
||||
"tlsv1 alert access denied"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECODE_ERROR),
|
||||
"tlsv1 alert decode error"},
|
||||
"tlsv1 alert decode error"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECRYPTION_FAILED),
|
||||
"tlsv1 alert decryption failed"},
|
||||
"tlsv1 alert decryption failed"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_DECRYPT_ERROR),
|
||||
"tlsv1 alert decrypt error"},
|
||||
"tlsv1 alert decrypt error"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION),
|
||||
"tlsv1 alert export restriction"},
|
||||
"tlsv1 alert export restriction"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK),
|
||||
"tlsv1 alert inappropriate fallback"},
|
||||
"tlsv1 alert inappropriate fallback"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY),
|
||||
"tlsv1 alert insufficient security"},
|
||||
"tlsv1 alert insufficient security"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_INTERNAL_ERROR),
|
||||
"tlsv1 alert internal error"},
|
||||
"tlsv1 alert internal error"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_NO_APPLICATION_PROTOCOL),
|
||||
"tlsv1 alert no application protocol"},
|
||||
"tlsv1 alert no application protocol"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_NO_RENEGOTIATION),
|
||||
"tlsv1 alert no renegotiation"},
|
||||
"tlsv1 alert no renegotiation"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_PROTOCOL_VERSION),
|
||||
"tlsv1 alert protocol version"},
|
||||
"tlsv1 alert protocol version"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_RECORD_OVERFLOW),
|
||||
"tlsv1 alert record overflow"},
|
||||
"tlsv1 alert record overflow"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_UNKNOWN_CA),
|
||||
"tlsv1 alert unknown ca"},
|
||||
"tlsv1 alert unknown ca"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_UNKNOWN_PSK_IDENTITY),
|
||||
"tlsv1 alert unknown psk identity"},
|
||||
"tlsv1 alert unknown psk identity"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_ALERT_USER_CANCELLED),
|
||||
"tlsv1 alert user cancelled"},
|
||||
"tlsv1 alert user cancelled"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_BAD_CERTIFICATE_HASH_VALUE),
|
||||
"tlsv1 bad certificate hash value"},
|
||||
"tlsv1 bad certificate hash value"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_BAD_CERTIFICATE_STATUS_RESPONSE),
|
||||
"tlsv1 bad certificate status response"},
|
||||
"tlsv1 bad certificate status response"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_CERTIFICATE_UNOBTAINABLE),
|
||||
"tlsv1 certificate unobtainable"},
|
||||
"tlsv1 certificate unobtainable"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_UNRECOGNIZED_NAME),
|
||||
"tlsv1 unrecognized name"},
|
||||
"tlsv1 unrecognized name"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLSV1_UNSUPPORTED_EXTENSION),
|
||||
"tlsv1 unsupported extension"},
|
||||
"tlsv1 unsupported extension"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL),
|
||||
"tls illegal exporter label"},
|
||||
"tls illegal exporter label"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TLS_INVALID_ECPOINTFORMAT_LIST),
|
||||
"tls invalid ecpointformat list"},
|
||||
"tls invalid ecpointformat list"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TOO_MANY_KEY_UPDATES),
|
||||
"too many key updates"},
|
||||
"too many key updates"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TOO_MANY_WARN_ALERTS),
|
||||
"too many warn alerts"},
|
||||
"too many warn alerts"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_TOO_MUCH_EARLY_DATA),
|
||||
"too much early data"},
|
||||
"too much early data"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS),
|
||||
"unable to find ecdh parameters"},
|
||||
"unable to find ecdh parameters"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_FIND_PUBLIC_KEY_PARAMETERS),
|
||||
"unable to find public key parameters"},
|
||||
"unable to find public key parameters"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL3_MD5_ROUTINES),
|
||||
"unable to load ssl3 md5 routines"},
|
||||
"unable to load ssl3 md5 routines"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNABLE_TO_LOAD_SSL3_SHA1_ROUTINES),
|
||||
"unable to load ssl3 sha1 routines"},
|
||||
"unable to load ssl3 sha1 routines"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_CCS_MESSAGE),
|
||||
"unexpected ccs message"},
|
||||
"unexpected ccs message"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_END_OF_EARLY_DATA),
|
||||
"unexpected end of early data"},
|
||||
"unexpected end of early data"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_EOF_WHILE_READING),
|
||||
"unexpected eof while reading"},
|
||||
"unexpected eof while reading"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_MESSAGE), "unexpected message"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNEXPECTED_RECORD), "unexpected record"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNINITIALIZED), "uninitialized"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_ALERT_TYPE), "unknown alert type"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CERTIFICATE_TYPE),
|
||||
"unknown certificate type"},
|
||||
"unknown certificate type"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CIPHER_RETURNED),
|
||||
"unknown cipher returned"},
|
||||
"unknown cipher returned"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CIPHER_TYPE),
|
||||
"unknown cipher type"},
|
||||
"unknown cipher type"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_CMD_NAME), "unknown cmd name"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_COMMAND), "unknown command"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_DIGEST), "unknown digest"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE),
|
||||
"unknown key exchange type"},
|
||||
"unknown key exchange type"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_MANDATORY_PARAMETER),
|
||||
"unknown mandatory parameter"},
|
||||
"unknown mandatory parameter"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_PKEY_TYPE), "unknown pkey type"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_PROTOCOL), "unknown protocol"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_SSL_VERSION),
|
||||
"unknown ssl version"},
|
||||
"unknown ssl version"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNKNOWN_STATE), "unknown state"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSAFE_LEGACY_RENEGOTIATION_DISABLED),
|
||||
"unsafe legacy renegotiation disabled"},
|
||||
"unsafe legacy renegotiation disabled"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSOLICITED_EXTENSION),
|
||||
"unsolicited extension"},
|
||||
"unsolicited extension"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_COMPRESSION_ALGORITHM),
|
||||
"unsupported compression algorithm"},
|
||||
"unsupported compression algorithm"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_CONFIG_VALUE),
|
||||
"unsupported config value"},
|
||||
"unsupported config value"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_CONFIG_VALUE_CLASS),
|
||||
"unsupported config value class"},
|
||||
"unsupported config value class"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_CONFIG_VALUE_OP),
|
||||
"unsupported config value op"},
|
||||
"unsupported config value op"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_ELLIPTIC_CURVE),
|
||||
"unsupported elliptic curve"},
|
||||
"unsupported elliptic curve"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_PROTOCOL),
|
||||
"unsupported protocol"},
|
||||
"unsupported protocol"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_SSL_VERSION),
|
||||
"unsupported ssl version"},
|
||||
"unsupported ssl version"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_STATUS_TYPE),
|
||||
"unsupported status type"},
|
||||
"unsupported status type"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_UNSUPPORTED_WRITE_FLAG),
|
||||
"unsupported write flag"},
|
||||
"unsupported write flag"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_USE_SRTP_NOT_NEGOTIATED),
|
||||
"use srtp not negotiated"},
|
||||
"use srtp not negotiated"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_VERSION_TOO_HIGH), "version too high"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_VERSION_TOO_LOW), "version too low"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CERTIFICATE_TYPE),
|
||||
"wrong certificate type"},
|
||||
"wrong certificate type"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CIPHER_RETURNED),
|
||||
"wrong cipher returned"},
|
||||
"wrong cipher returned"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_CURVE), "wrong curve"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_RPK_TYPE), "wrong rpk type"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_LENGTH),
|
||||
"wrong signature length"},
|
||||
"wrong signature length"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_SIZE),
|
||||
"wrong signature size"},
|
||||
"wrong signature size"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SIGNATURE_TYPE),
|
||||
"wrong signature type"},
|
||||
"wrong signature type"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_SSL_VERSION), "wrong ssl version"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_WRONG_VERSION_NUMBER),
|
||||
"wrong version number"},
|
||||
"wrong version number"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_X509_LIB), "x509 lib"},
|
||||
{ERR_PACK(ERR_LIB_SSL, 0, SSL_R_X509_VERIFICATION_SETUP_PROBLEMS),
|
||||
"x509 verification setup problems"},
|
||||
"x509 verification setup problems"},
|
||||
{0, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -919,6 +919,11 @@ SSL *ossl_ssl_connection_new_int(SSL_CTX *ctx, SSL *user_ssl,
|
|||
goto sslerr;
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
if (!ossl_ech_conn_init(s, ctx, method))
|
||||
goto sslerr;
|
||||
#endif
|
||||
|
||||
s->ssl_pkey_num = SSL_PKEY_NUM + ctx->sigalg_list_len;
|
||||
return ssl;
|
||||
cerr:
|
||||
|
@ -1495,6 +1500,9 @@ void ossl_ssl_connection_free(SSL *ssl)
|
|||
BIO_free_all(s->rbio);
|
||||
s->rbio = NULL;
|
||||
OPENSSL_free(s->s3.tmp.valid_flags);
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
ossl_ech_conn_clear(&s->ext.ech);
|
||||
#endif
|
||||
}
|
||||
|
||||
void SSL_set0_rbio(SSL *s, BIO *rbio)
|
||||
|
@ -4375,6 +4383,10 @@ void SSL_CTX_free(SSL_CTX *a)
|
|||
OPENSSL_free(a->qlog_title);
|
||||
#endif
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
ossl_ech_ctx_clear(&a->ext.ech);
|
||||
#endif
|
||||
|
||||
OPENSSL_free(a);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
# include "internal/ssl.h"
|
||||
# include "internal/cryptlib.h"
|
||||
# include "record/record.h"
|
||||
# ifndef OPENSSL_NO_ECH
|
||||
# include "ech/ech_local.h"
|
||||
# endif
|
||||
|
||||
# ifdef OPENSSL_BUILD_SHLIBSSL
|
||||
# undef OPENSSL_EXTERN
|
||||
|
@ -1065,6 +1068,9 @@ struct ssl_ctx_st {
|
|||
# endif
|
||||
|
||||
unsigned char cookie_hmac_key[SHA256_DIGEST_LENGTH];
|
||||
# ifndef OPENSSL_NO_ECH
|
||||
OSSL_ECH_CTX ech;
|
||||
# endif
|
||||
} ext;
|
||||
|
||||
# ifndef OPENSSL_NO_PSK
|
||||
|
@ -1680,6 +1686,10 @@ struct ssl_connection_st {
|
|||
uint8_t client_cert_type_ctos;
|
||||
uint8_t server_cert_type;
|
||||
uint8_t server_cert_type_ctos;
|
||||
|
||||
# ifndef OPENSSL_NO_ECH
|
||||
OSSL_ECH_CONN ech;
|
||||
# endif
|
||||
} ext;
|
||||
|
||||
/*
|
||||
|
|
|
@ -64,7 +64,8 @@ IF[{- !$disabled{tests} -}]
|
|||
ca_internals_test bio_tfo_test membio_test bio_dgram_test list_test \
|
||||
fips_version_test x509_test hpke_test pairwise_fail_test \
|
||||
nodefltctxtest evp_xof_test x509_load_cert_file_test bio_meth_test \
|
||||
x509_acert_test x509_req_test strtoultest bio_pw_callback_test
|
||||
x509_acert_test x509_req_test strtoultest bio_pw_callback_test \
|
||||
ech_test
|
||||
|
||||
IF[{- !$disabled{'rpk'} -}]
|
||||
PROGRAMS{noinst}=rpktest
|
||||
|
@ -209,6 +210,10 @@ IF[{- !$disabled{tests} -}]
|
|||
INCLUDE[hpke_test]=../include ../apps/include
|
||||
DEPEND[hpke_test]=../libcrypto.a libtestutil.a
|
||||
|
||||
SOURCE[ech_test]=ech_test.c helpers/ssltestlib.c filterprov.c tls-provider.c
|
||||
INCLUDE[ech_test]=../include ../apps/include
|
||||
DEPEND[ech_test]=../libssl.a ../libcrypto.a libtestutil.a
|
||||
|
||||
SOURCE[evp_extra_test2]=evp_extra_test2.c $INITSRC tls-provider.c
|
||||
INCLUDE[evp_extra_test2]=../include ../apps/include
|
||||
DEPEND[evp_extra_test2]=../libcrypto libtestutil.a
|
||||
|
|
25
test/certs/ech-big.pem
Normal file
25
test/certs/ech-big.pem
Normal file
|
@ -0,0 +1,25 @@
|
|||
-----BEGIN ECHCONFIG-----
|
||||
BNj+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBs
|
||||
ZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERvEyykM5zxnfFVLlpClg/QLGlzYBY8AAQAAQABAAtl
|
||||
eGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQznPGd8VUuWkKWD9AsaXNgFjwABAAB
|
||||
AAEAC2V4YW1wbGUuY29tAAD+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AW
|
||||
PAAEAAEAAQALZXhhbXBsZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERvEyykM5zxnfFVLlpClg/Q
|
||||
LGlzYBY8AAQAAQABAAtleGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQznPGd8VUu
|
||||
WkKWD9AsaXNgFjwABAABAAEAC2V4YW1wbGUuY29tAAD+DQA6uwAgACBix2B78sX+EQhEbxMspDOc
|
||||
8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERv
|
||||
EyykM5zxnfFVLlpClg/QLGlzYBY8AAQAAQABAAtleGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdge/LF
|
||||
/hEIRG8TLKQznPGd8VUuWkKWD9AsaXNgFjwABAABAAEAC2V4YW1wbGUuY29tAAD+DQA6uwAgACBi
|
||||
x2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAP4NADq7
|
||||
ACAAIGLHYHvyxf4RCERvEyykM5zxnfFVLlpClg/QLGlzYBY8AAQAAQABAAtleGFtcGxlLmNvbQAA
|
||||
/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQznPGd8VUuWkKWD9AsaXNgFjwABAABAAEAC2V4YW1wbGUu
|
||||
Y29tAAD+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhh
|
||||
bXBsZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERvEyykM5zxnfFVLlpClg/QLGlzYBY8AAQAAQAB
|
||||
AAtleGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQznPGd8VUuWkKWD9AsaXNgFjwA
|
||||
BAABAAEAC2V4YW1wbGUuY29tAAD+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxp
|
||||
c2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERvEyykM5zxnfFVLlpC
|
||||
lg/QLGlzYBY8AAQAAQABAAtleGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQznPGd
|
||||
8VUuWkKWD9AsaXNgFjwABAABAAEAC2V4YW1wbGUuY29tAAD+DQA6uwAgACBix2B78sX+EQhEbxMs
|
||||
pDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAP4NADq7ACAAIGLHYHvyxf4R
|
||||
CERvEyykM5zxnfFVLlpClg/QLGlzYBY8AAQAAQABAAtleGFtcGxlLmNvbQAA
|
||||
-----END ECHCONFIG-----
|
||||
|
7
test/certs/ech-eg.pem
Normal file
7
test/certs/ech-eg.pem
Normal file
|
@ -0,0 +1,7 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MC4CAQAwBQYDK2VuBCIEIKBC3rocwIF5tGY+/TaYQrCxY+ULsch94ja9DojkcvlT
|
||||
-----END PRIVATE KEY-----
|
||||
-----BEGIN ECHCONFIG-----
|
||||
ADn+DQA1agAgACBtuySC1pphjFlGYKTaSm2KWNg7GQVRS8uAYvLTm5QlGwAEAAEA
|
||||
AQAGZWcuY29tAAA=
|
||||
-----END ECHCONFIG-----
|
37
test/certs/ech-giant.pem
Normal file
37
test/certs/ech-giant.pem
Normal file
|
@ -0,0 +1,37 @@
|
|||
-----BEGIN ECHCONFIG-----
|
||||
B8D+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBs
|
||||
ZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERvEyykM5zxnfFVLlpClg/QLGlzYBY8AAQAAQABAAtl
|
||||
eGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQznPGd8VUuWkKWD9AsaXNgFjwABAAB
|
||||
AAEAC2V4YW1wbGUuY29tAAD+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AW
|
||||
PAAEAAEAAQALZXhhbXBsZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERvEyykM5zxnfFVLlpClg/Q
|
||||
LGlzYBY8AAQAAQABAAtleGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQznPGd8VUu
|
||||
WkKWD9AsaXNgFjwABAABAAEAC2V4YW1wbGUuY29tAAD+DQA6uwAgACBix2B78sX+EQhEbxMspDOc
|
||||
8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERv
|
||||
EyykM5zxnfFVLlpClg/QLGlzYBY8AAQAAQABAAtleGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdge/LF
|
||||
/hEIRG8TLKQznPGd8VUuWkKWD9AsaXNgFjwABAABAAEAC2V4YW1wbGUuY29tAAD+DQA6uwAgACBi
|
||||
x2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAP4NADq7
|
||||
ACAAIGLHYHvyxf4RCERvEyykM5zxnfFVLlpClg/QLGlzYBY8AAQAAQABAAtleGFtcGxlLmNvbQAA
|
||||
/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQznPGd8VUuWkKWD9AsaXNgFjwABAABAAEAC2V4YW1wbGUu
|
||||
Y29tAAD+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhh
|
||||
bXBsZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERvEyykM5zxnfFVLlpClg/QLGlzYBY8AAQAAQAB
|
||||
AAtleGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQznPGd8VUuWkKWD9AsaXNgFjwA
|
||||
BAABAAEAC2V4YW1wbGUuY29tAAD+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxp
|
||||
c2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERvEyykM5zxnfFVLlpC
|
||||
lg/QLGlzYBY8AAQAAQABAAtleGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQznPGd
|
||||
8VUuWkKWD9AsaXNgFjwABAABAAEAC2V4YW1wbGUuY29tAAD+DQA6uwAgACBix2B78sX+EQhEbxMs
|
||||
pDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAP4NADq7ACAAIGLHYHvyxf4R
|
||||
CERvEyykM5zxnfFVLlpClg/QLGlzYBY8AAQAAQABAAtleGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdg
|
||||
e/LF/hEIRG8TLKQznPGd8VUuWkKWD9AsaXNgFjwABAABAAEAC2V4YW1wbGUuY29tAAD+DQA6uwAg
|
||||
ACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAP4N
|
||||
ADq7ACAAIGLHYHvyxf4RCERvEyykM5zxnfFVLlpClg/QLGlzYBY8AAQAAQABAAtleGFtcGxlLmNv
|
||||
bQAA/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQznPGd8VUuWkKWD9AsaXNgFjwABAABAAEAC2V4YW1w
|
||||
bGUuY29tAAD+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQAL
|
||||
ZXhhbXBsZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERvEyykM5zxnfFVLlpClg/QLGlzYBY8AAQA
|
||||
AQABAAtleGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQznPGd8VUuWkKWD9AsaXNg
|
||||
FjwABAABAAEAC2V4YW1wbGUuY29tAAD+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP
|
||||
0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERvEyykM5zxnfFV
|
||||
LlpClg/QLGlzYBY8AAQAAQABAAtleGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQz
|
||||
nPGd8VUuWkKWD9AsaXNgFjwABAABAAEAC2V4YW1wbGUuY29tAAD+DQA6uwAgACBix2B78sX+EQhE
|
||||
bxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAP4NADq7ACAAIGLHYHvy
|
||||
xf4RCERvEyykM5zxnfFVLlpClg/QLGlzYBY8AAQAAQABAAtleGFtcGxlLmNvbQAA
|
||||
-----END ECHCONFIG-----`
|
11
test/certs/ech-mid.pem
Normal file
11
test/certs/ech-mid.pem
Normal file
|
@ -0,0 +1,11 @@
|
|||
-----BEGIN ECHCONFIG-----
|
||||
AfD+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBs
|
||||
ZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERvEyykM5zxnfFVLlpClg/QLGlzYBY8AAQAAQABAAtl
|
||||
eGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQznPGd8VUuWkKWD9AsaXNgFjwABAAB
|
||||
AAEAC2V4YW1wbGUuY29tAAD+DQA6uwAgACBix2B78sX+EQhEbxMspDOc8Z3xVS5aQpYP0Cxpc2AW
|
||||
PAAEAAEAAQALZXhhbXBsZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERvEyykM5zxnfFVLlpClg/Q
|
||||
LGlzYBY8AAQAAQABAAtleGFtcGxlLmNvbQAA/g0AOrsAIAAgYsdge/LF/hEIRG8TLKQznPGd8VUu
|
||||
WkKWD9AsaXNgFjwABAABAAEAC2V4YW1wbGUuY29tAAD+DQA6uwAgACBix2B78sX+EQhEbxMspDOc
|
||||
8Z3xVS5aQpYP0Cxpc2AWPAAEAAEAAQALZXhhbXBsZS5jb20AAP4NADq7ACAAIGLHYHvyxf4RCERv
|
||||
EyykM5zxnfFVLlpClg/QLGlzYBY8AAQAAQABAAtleGFtcGxlLmNvbQAA
|
||||
-----END ECHCONFIG-----
|
14
test/certs/ech-rsa.pem
Normal file
14
test/certs/ech-rsa.pem
Normal file
|
@ -0,0 +1,14 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEApeb9fP5SDxyOQZQT
|
||||
qGg2QeE0ypxY6Th33aDkRCRVB69rDMSA1Thfeyk65IfaPaA3bC4hsqAIBgslcFfk
|
||||
1/i8KQIDAQABAkAsH3EPizwb1MZo3o8T3ROBFfpKYKas8F3Azgenr9oFfs5kPgya
|
||||
VDdtZu+UweG5nTo+fZG5ZFmcwWXJTLtiUfABAiEAz2gvTuc0lPTQi3t6RFB5nGCt
|
||||
h75Ofx/ceusHa2a36QECIQDMxXJQnuWY+bH/wSfPY/ySltQ6U2cy0LHQ37FIfSFr
|
||||
KQIgUo++hUI0BDeP7HYyrY77WeyCJ07yIFimg6ebRH2XKAECIQCSavhTd1q6qIhD
|
||||
VMzveRInixvTXMGkzx7mOJzeNUMJCQIhAJjjVdRjUpWPMquRDCddmwegh88ptsFX
|
||||
T/Ygm1OubAyM
|
||||
-----END PRIVATE KEY-----
|
||||
-----BEGIN ECHCONFIG-----
|
||||
AD7+DQA6bAAgACCY7B0f/3KvHIFdoqFaObdU8YYU+MdBf4vzbLhAAL2QCwAEAAEA
|
||||
AQALZXhhbXBsZS5jb20AAA==
|
||||
-----END ECHCONFIG-----
|
28
test/certs/echserver.key
Normal file
28
test/certs/echserver.key
Normal file
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCJHNs4e27KjdYU
|
||||
8IgiT539WbEl16Eve6tu1UFpGdkqsHH8+yceoFkMWSdpr+Sh3PYDRk/Ek0qB33uK
|
||||
y3FKlIejtolxVhBybtja5zYMmVXnRHsB/qe7FgyM/lv0xtO1nfSGFkVZVz1+xWPr
|
||||
aslJN3U4HPaaL4SGghw5KIRD8FPx174v8FDOBeVhn6pzTK/xpTeqXLvAAxgPhF+Q
|
||||
HOQ0pTXrOHbaiK4l+8JfVm+0fCJjMnT20mmGuTNjvdWZ4XIgPPYkEQrf1CpdONcU
|
||||
kiiFcpcYtbVS0YyC91qqJLKFv51eki9STwUQISn5jLWIRQlXkBXhK6aGlkLWnov/
|
||||
kqqUWEQTAgMBAAECggEAAah0LDAt7EwfyRwJgWS2E+C4SC1d2R2lOo9gnZ0+54m/
|
||||
rx/4XqHwwbn4RIpoeN6bqPl6MHXZgk2KCGkiYxT9uOiVq+WvCDs36xm9qRRXmhbV
|
||||
Z/ZE3/nJyBCxWvnmiH0y/kYZq5Vm/Hf1l9ywN27wv292OfIWJ6w+HCDVzJ6E3VlK
|
||||
fuzBFhZmnBjul6Nlo76blNXwn5loWYomkg6nVWzrTjYWosGd0aKpZJR948nWpuEj
|
||||
fkevLqMMfSuB+cXQ+zB4lttqB5dphFxbNv5gHOd1rllzHFdhK+/7e7ktGYmpQtuH
|
||||
WRKPD1y173ek5FtvTxtcrL2rST+hoSDWcCQCws/70QKBgQC5QGlldraTs0JXhoH9
|
||||
6X+V1mvsAWCItq7JhUvFHFtAxHuYacrlnsJRxv8aRS8AhuNYTtThJQcWzFL2UU7W
|
||||
CdiB0VZr7phPNOVYsa95V8a8A1CHllfdTzxw1TyiOJ0sdeU7irWo3vnTDxftfySP
|
||||
lkdPNbItO1RXqeIR6mJf+rVGowKBgQC9egaDDdM2YsMtl61fIRoPMPdJB3fGcL0A
|
||||
FwUAtGQ1twETykzcUCeAqx0yx7zCAyPeA9WmpHzuz/LR8uA3TP/nDcLlCaQowfeR
|
||||
VPdS3Q1iAnSyaCsF1THQPvhFsYMXbIn/svSSpddLOrP6ltSr+PORLOXXUmQJnffk
|
||||
hxKaxK6T0QKBgFzyVm9UGtMMk/K6SCqPpzYUuV1Wa4rsrdHqkVO6oIZkjuav3d9L
|
||||
wo+pWoFhyO1owFSkaOb13xKvPcjcjsOReRHZaJUKx1ymW5Qewr4NLmdS+mqtIjSl
|
||||
9tteAegao7GVDYjMVcz+4zXkUssUidGJQwoZFObg57Z8RDNc+DLT5XQlAoGAYaO8
|
||||
L1S0ftYuFhSPdvIr56AoDi4W/t+hxaYXIeHTsgp4N6aMLQvxD1EeXsim8KOFnCcF
|
||||
tjYVW0s1qhMqj9TSGlLxF+379jTeSroqKT1YZCU31afwY7UVUmbgsalkEHISOv4R
|
||||
InDrnQzHKl8HgQdtHGayml8OxhXtZIpmf/LSs8ECgYBrFbKl8ylhlzw5rC8DuP8n
|
||||
hzKLOKzipKmHLn4eDBEFyLTyoyYrqx/nxLi3kSIyNP4fJ9vHOXgdjdrp9xRMcFEx
|
||||
IA2sdywI5VuymxktP8OlORa0NK4eFZXkDNsQlkathYiKqCwGjUWdGk5+Ry5qO/UC
|
||||
9ua9adjNa108aBzWLYZFCw==
|
||||
-----END PRIVATE KEY-----
|
80
test/certs/echserver.pem
Normal file
80
test/certs/echserver.pem
Normal file
|
@ -0,0 +1,80 @@
|
|||
Certificate:
|
||||
Data:
|
||||
Version: 3 (0x2)
|
||||
Serial Number:
|
||||
18:45:8f:30:1d:fe:dc:22:9d:95:40:8c:e5:36:f9:38:0d:d5:58:a0
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Issuer: CN=Root CA
|
||||
Validity
|
||||
Not Before: Oct 6 18:36:12 2023 GMT
|
||||
Not After : Sep 12 18:36:12 2123 GMT
|
||||
Subject: CN=server.example
|
||||
Subject Public Key Info:
|
||||
Public Key Algorithm: rsaEncryption
|
||||
Public-Key: (2048 bit)
|
||||
Modulus:
|
||||
00:89:1c:db:38:7b:6e:ca:8d:d6:14:f0:88:22:4f:
|
||||
9d:fd:59:b1:25:d7:a1:2f:7b:ab:6e:d5:41:69:19:
|
||||
d9:2a:b0:71:fc:fb:27:1e:a0:59:0c:59:27:69:af:
|
||||
e4:a1:dc:f6:03:46:4f:c4:93:4a:81:df:7b:8a:cb:
|
||||
71:4a:94:87:a3:b6:89:71:56:10:72:6e:d8:da:e7:
|
||||
36:0c:99:55:e7:44:7b:01:fe:a7:bb:16:0c:8c:fe:
|
||||
5b:f4:c6:d3:b5:9d:f4:86:16:45:59:57:3d:7e:c5:
|
||||
63:eb:6a:c9:49:37:75:38:1c:f6:9a:2f:84:86:82:
|
||||
1c:39:28:84:43:f0:53:f1:d7:be:2f:f0:50:ce:05:
|
||||
e5:61:9f:aa:73:4c:af:f1:a5:37:aa:5c:bb:c0:03:
|
||||
18:0f:84:5f:90:1c:e4:34:a5:35:eb:38:76:da:88:
|
||||
ae:25:fb:c2:5f:56:6f:b4:7c:22:63:32:74:f6:d2:
|
||||
69:86:b9:33:63:bd:d5:99:e1:72:20:3c:f6:24:11:
|
||||
0a:df:d4:2a:5d:38:d7:14:92:28:85:72:97:18:b5:
|
||||
b5:52:d1:8c:82:f7:5a:aa:24:b2:85:bf:9d:5e:92:
|
||||
2f:52:4f:05:10:21:29:f9:8c:b5:88:45:09:57:90:
|
||||
15:e1:2b:a6:86:96:42:d6:9e:8b:ff:92:aa:94:58:
|
||||
44:13
|
||||
Exponent: 65537 (0x10001)
|
||||
X509v3 extensions:
|
||||
X509v3 Basic Constraints:
|
||||
CA:FALSE
|
||||
X509v3 Subject Key Identifier:
|
||||
8C:E0:38:04:70:7E:B4:CB:1F:BF:AA:E6:67:42:74:63:46:88:58:74
|
||||
X509v3 Authority Key Identifier:
|
||||
70:7F:2E:AE:83:68:59:98:04:23:2A:CD:EB:3E:17:CD:24:DD:01:49
|
||||
X509v3 Subject Alternative Name:
|
||||
DNS:*.server.example, DNS:server.example
|
||||
Signature Algorithm: sha256WithRSAEncryption
|
||||
Signature Value:
|
||||
9b:fe:bc:b1:40:d4:08:91:f6:1f:b4:0f:8c:50:ac:49:36:6f:
|
||||
27:93:e8:94:13:bc:fe:1a:2a:cf:93:98:13:b3:b4:85:a5:62:
|
||||
4d:58:8f:da:cd:f7:1b:c3:1f:42:ba:2a:89:45:11:33:49:86:
|
||||
2c:3a:0a:99:17:4f:0c:f1:1e:35:31:2c:69:f9:15:d5:37:54:
|
||||
cc:9e:e3:67:9f:d5:6e:ad:b1:26:60:df:aa:84:63:da:a7:31:
|
||||
c9:69:a0:d8:c2:96:d3:82:b4:99:70:8c:3c:92:a4:c0:f0:7c:
|
||||
3f:04:d3:29:4f:6c:c5:fd:39:12:95:65:7f:37:fb:52:5b:12:
|
||||
99:d6:d7:b5:ba:44:6e:36:ec:5d:f2:5d:d4:aa:2d:8a:46:ce:
|
||||
29:66:c1:ed:36:13:f2:f3:ae:92:4a:97:db:99:ed:8f:4e:4e:
|
||||
ed:73:1b:fa:3e:64:63:40:5c:c2:03:76:2c:dc:58:01:3f:17:
|
||||
d0:ae:a6:b2:64:85:47:ba:7d:5a:36:53:e4:90:00:8e:f5:17:
|
||||
a5:ff:a3:81:ee:ed:25:ca:10:76:75:2d:65:ff:f8:b1:8c:3c:
|
||||
a3:ff:81:12:72:c7:bc:b5:17:06:d8:c6:13:97:cb:8e:58:51:
|
||||
2a:a4:be:91:59:40:4b:07:8d:69:2f:92:ee:ea:9c:bf:eb:42:
|
||||
b7:62:b8:e3
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDNTCCAh2gAwIBAgIUGEWPMB3+3CKdlUCM5Tb5OA3VWKAwDQYJKoZIhvcNAQEL
|
||||
BQAwEjEQMA4GA1UEAwwHUm9vdCBDQTAgFw0yMzEwMDYxODM2MTJaGA8yMTIzMDkx
|
||||
MjE4MzYxMlowGTEXMBUGA1UEAwwOc2VydmVyLmV4YW1wbGUwggEiMA0GCSqGSIb3
|
||||
DQEBAQUAA4IBDwAwggEKAoIBAQCJHNs4e27KjdYU8IgiT539WbEl16Eve6tu1UFp
|
||||
GdkqsHH8+yceoFkMWSdpr+Sh3PYDRk/Ek0qB33uKy3FKlIejtolxVhBybtja5zYM
|
||||
mVXnRHsB/qe7FgyM/lv0xtO1nfSGFkVZVz1+xWPraslJN3U4HPaaL4SGghw5KIRD
|
||||
8FPx174v8FDOBeVhn6pzTK/xpTeqXLvAAxgPhF+QHOQ0pTXrOHbaiK4l+8JfVm+0
|
||||
fCJjMnT20mmGuTNjvdWZ4XIgPPYkEQrf1CpdONcUkiiFcpcYtbVS0YyC91qqJLKF
|
||||
v51eki9STwUQISn5jLWIRQlXkBXhK6aGlkLWnov/kqqUWEQTAgMBAAGjejB4MAkG
|
||||
A1UdEwQCMAAwHQYDVR0OBBYEFIzgOARwfrTLH7+q5mdCdGNGiFh0MB8GA1UdIwQY
|
||||
MBaAFHB/Lq6DaFmYBCMqzes+F80k3QFJMCsGA1UdEQQkMCKCECouc2VydmVyLmV4
|
||||
YW1wbGWCDnNlcnZlci5leGFtcGxlMA0GCSqGSIb3DQEBCwUAA4IBAQCb/ryxQNQI
|
||||
kfYftA+MUKxJNm8nk+iUE7z+GirPk5gTs7SFpWJNWI/azfcbwx9CuiqJRREzSYYs
|
||||
OgqZF08M8R41MSxp+RXVN1TMnuNnn9VurbEmYN+qhGPapzHJaaDYwpbTgrSZcIw8
|
||||
kqTA8Hw/BNMpT2zF/TkSlWV/N/tSWxKZ1te1ukRuNuxd8l3Uqi2KRs4pZsHtNhPy
|
||||
866SSpfbme2PTk7tcxv6PmRjQFzCA3Ys3FgBPxfQrqayZIVHun1aNlPkkACO9Rel
|
||||
/6OB7u0lyhB2dS1l//ixjDyj/4EScse8tRcG2MYTl8uOWFEqpL6RWUBLB41pL5Lu
|
||||
6py/60K3Yrjj
|
||||
-----END CERTIFICATE-----
|
1408
test/ech_test.c
Normal file
1408
test/ech_test.c
Normal file
File diff suppressed because it is too large
Load diff
93
test/recipes/20-test_app_ech.t
Normal file
93
test/recipes/20-test_app_ech.t
Normal file
|
@ -0,0 +1,93 @@
|
|||
#! /usr/bin/env perl
|
||||
# Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
#
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use OpenSSL::Test::Utils;
|
||||
use OpenSSL::Test qw/:DEFAULT srctop_file srctop_dir bldtop_dir bldtop_file with/;
|
||||
|
||||
setup("test_app_ech");
|
||||
|
||||
plan skip_all => "ECH tests not supported in this build"
|
||||
if disabled("ech") || disabled("tls1_3")
|
||||
|| disabled("ec") || disabled("ecx");
|
||||
|
||||
plan tests => 13;
|
||||
|
||||
ok(run(app(["openssl", "ech", "-help"])),
|
||||
"Run openssl ech with help");
|
||||
ok(run(app(["openssl", "ech",
|
||||
"-ech_version", "13",
|
||||
"-public_name", "example.com",
|
||||
"-out", "eg1.pem",
|
||||
"-verbose",
|
||||
"-text"])),
|
||||
"Generate an ECH key pair for example.com");
|
||||
ok(run(app(["openssl", "ech",
|
||||
"-suite", "0x10,2,2",
|
||||
"-public_name", "example.com",
|
||||
"-out", "eg2.pem",
|
||||
"-text"])),
|
||||
"Generate an ECDSA ECH key pair for example.com");
|
||||
ok(run(app(["openssl", "ech",
|
||||
"-max_name_len", "13",
|
||||
"-public_name", "example.com",
|
||||
"-out", "eg2.pem",
|
||||
"-text"])),
|
||||
"Generate an ECH key pair for example.com with max name len 13");
|
||||
ok(run(app(["openssl", "ech",
|
||||
"-in", "eg1.pem",
|
||||
"-in", "eg2.pem",
|
||||
"-out", "eg3.pem",
|
||||
"-verbose"])),
|
||||
"Catenate the ECH for example.com twice");
|
||||
ok(run(app(["openssl", "ech",
|
||||
"-in", "eg3.pem",
|
||||
"-select", "1",
|
||||
"-verbose",
|
||||
"-out", "eg4.pem"])),
|
||||
"Select one ECH Config");
|
||||
|
||||
with({ exit_checker => sub { return shift == 1; } },
|
||||
sub {
|
||||
ok(run(app(["openssl", "ech" ])),
|
||||
"Run openssl ech with no arg");
|
||||
ok(run(app(["openssl", "ech", "-nohelpatall"])),
|
||||
"Run openssl ech with unknown arg");
|
||||
ok(run(app(["openssl", "ech", "nohelpatall"])),
|
||||
"Run openssl ech with unknown non arg");
|
||||
ok(run(app(["openssl", "ech",
|
||||
"-ech_version", "0xfe09",
|
||||
"-public_name", "example.com",
|
||||
"-out", "eg1.pem",
|
||||
"-text"])),
|
||||
"Fail to generate an ECH key pair for old draft version");
|
||||
ok(run(app(["openssl", "ech",
|
||||
"-suite", "not,a,good,one",
|
||||
"-public_name", "example.com",
|
||||
"-out", "eg2.pem",
|
||||
"-text"])),
|
||||
"Fail to generate an ECH key pair with bad suite");
|
||||
ok(run(app(["openssl", "ech",
|
||||
"-max_name_len", "1300",
|
||||
"-public_name", "example.com",
|
||||
"-text"])),
|
||||
"(Fail to) Generate an ECH key pair for example.com with max name len 1300");
|
||||
ok(run(app(["openssl", "ech",
|
||||
"-in", "eg1.pem",
|
||||
"-in", "eg2.pem",
|
||||
"-in", "eg3.pem",
|
||||
"-in", "eg4.pem",
|
||||
"-in", "eg1.pem",
|
||||
"-in", "eg2.pem",
|
||||
"-in", "eg3.pem",
|
||||
"-in", "eg4.pem"])),
|
||||
"Too many input files");
|
||||
});
|
21
test/recipes/30-test_ech.t
Normal file
21
test/recipes/30-test_ech.t
Normal file
|
@ -0,0 +1,21 @@
|
|||
#! /usr/bin/env perl
|
||||
# Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
|
||||
# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
#
|
||||
# Licensed under the Apache License 2.0 (the "License"). You may not use
|
||||
# this file except in compliance with the License. You can obtain a copy
|
||||
# in the file LICENSE in the source distribution or at
|
||||
# https://www.openssl.org/source/license.html
|
||||
|
||||
use strict;
|
||||
use OpenSSL::Test::Utils;
|
||||
use OpenSSL::Test qw/:DEFAULT srctop_file srctop_dir bldtop_dir bldtop_file/;
|
||||
|
||||
setup("test_ech");
|
||||
|
||||
plan skip_all => "ECH tests not supported in this build"
|
||||
if disabled("ech") || disabled("tls1_3") || disabled("ec") || disabled("ecx");
|
||||
|
||||
plan tests => 1;
|
||||
|
||||
ok(run(test(["ech_test", srctop_dir("test", "certs")])))
|
|
@ -587,3 +587,31 @@ SSL_CTX_flush_sessions_ex 587 3_4_0 EXIST::FUNCTION:
|
|||
SSL_CTX_set_block_padding_ex 588 3_4_0 EXIST::FUNCTION:
|
||||
SSL_set_block_padding_ex 589 3_4_0 EXIST::FUNCTION:
|
||||
SSL_get1_builtin_sigalgs 590 3_4_0 EXIST::FUNCTION:
|
||||
OSSL_ECHSTORE_free ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
OSSL_ECHSTORE_new_config ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
OSSL_ECHSTORE_write_pem ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
OSSL_ECHSTORE_read_echconfiglist ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
OSSL_ECHSTORE_get1_info ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
OSSL_ECHSTORE_downselect ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
OSSL_ECHSTORE_set1_key_and_read_pem ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
OSSL_ECHSTORE_read_pem ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
OSSL_ECHSTORE_num_keys ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
OSSL_ECHSTORE_flush_keys ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_CTX_set1_echstore ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_set1_echstore ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_CTX_get1_echstore ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_get1_echstore ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_ech_get1_status ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_ech_set_grease_type ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_ech_set_callback ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_CTX_ech_raw_decrypt ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_CTX_ech_set_callback ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
OSSL_ECHSTORE_new ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_set1_ech_config_list ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_ech_set1_server_names ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_ech_set1_outer_server_name ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_ech_set1_outer_alpn_protos ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_ech_set1_grease_suite ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_ech_get1_retry_config ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
SSL_CTX_ech_set1_outer_alpn_protos ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
OSSL_ECHSTORE_num_entries ? 3_5_0 EXIST::FUNCTION:ECH
|
||||
|
|
|
@ -99,6 +99,8 @@ use constant {
|
|||
EXT_RENEGOTIATE => 65281,
|
||||
EXT_NPN => 13172,
|
||||
EXT_CRYPTOPRO_BUG_EXTENSION => 0xfde8,
|
||||
EXT_ECH => 0xfe0d,
|
||||
EXT_ECH_OUTER => 0xfd00,
|
||||
EXT_UNKNOWN => 0xfffe,
|
||||
#Unknown extension that should appear last
|
||||
EXT_FORCE_LAST => 0xffff
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue