mirror of
https://github.com/openssl/openssl.git
synced 2026-05-07 20:12:39 +00:00
ECH CLI implementation
Reviewed-by: Tomas Mraz <tomas@openssl.org> Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/25420)
This commit is contained in:
+111
-38
@@ -28,8 +28,7 @@
|
||||
|
||||
#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 PEM_SELECT_ALL -1 /* to indicate we're not downselecting another */
|
||||
#define OSSL_ECH_MAXINFILES 5 /* we'll only take this many inputs */
|
||||
|
||||
typedef enum OPTION_choice {
|
||||
/* standard openssl options */
|
||||
@@ -37,27 +36,34 @@ typedef enum OPTION_choice {
|
||||
OPT_EOF = 0,
|
||||
OPT_HELP,
|
||||
OPT_VERBOSE,
|
||||
OPT_PEMOUT,
|
||||
OPT_TEXT,
|
||||
OPT_OUT,
|
||||
OPT_IN,
|
||||
/* ECHConfig specifics */
|
||||
OPT_PUBLICNAME,
|
||||
OPT_ECHVERSION,
|
||||
OPT_MAXNAMELENGTH,
|
||||
OPT_HPKESUITE
|
||||
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"),
|
||||
{ "pemout", OPT_PEMOUT, '>',
|
||||
"Private key and ECHConfig [default echconfig.pem]" },
|
||||
{ "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)]" },
|
||||
"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 }
|
||||
};
|
||||
|
||||
@@ -71,9 +77,8 @@ static uint16_t verstr2us(char *arg)
|
||||
long lv = strtol(arg, NULL, 0);
|
||||
uint16_t rv = 0;
|
||||
|
||||
if (lv < 0xffff && lv > 0) {
|
||||
if (lv < 0xffff && lv > 0)
|
||||
rv = (uint16_t)lv;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -81,14 +86,19 @@ int ech_main(int argc, char **argv)
|
||||
{
|
||||
char *prog = NULL;
|
||||
OPTION_CHOICE o;
|
||||
int verbose = 0;
|
||||
char *pemfile = NULL;
|
||||
int i, rv = 1, verbose = 0, text = 0, outsupp = 0;
|
||||
int select = OSSL_ECHSTORE_ALL;
|
||||
char *outfile = NULL, *infile = NULL;
|
||||
char *infiles[OSSL_ECH_MAXINFILES] = { NULL };
|
||||
int numinfiles = 0;
|
||||
char *public_name = NULL;
|
||||
char *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) {
|
||||
@@ -99,12 +109,32 @@ int ech_main(int argc, char **argv)
|
||||
goto end;
|
||||
case OPT_HELP:
|
||||
opt_help(ech_options);
|
||||
rv = 0;
|
||||
goto end;
|
||||
case OPT_VERBOSE:
|
||||
verbose = 1;
|
||||
break;
|
||||
case OPT_PEMOUT:
|
||||
pemfile = opt_arg();
|
||||
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();
|
||||
@@ -149,16 +179,6 @@ int ech_main(int argc, char **argv)
|
||||
BIO_printf(bio_err, "Un-supported version (0x%04x)\n", ech_version);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (max_name_length > TLSEXT_MAXLEN_host_name) {
|
||||
BIO_printf(bio_err, "Weird max name length (0x%04x) - biggest is "
|
||||
"(0x%04x) - exiting\n",
|
||||
max_name_length,
|
||||
TLSEXT_MAXLEN_host_name);
|
||||
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);
|
||||
@@ -168,17 +188,15 @@ int ech_main(int argc, char **argv)
|
||||
}
|
||||
|
||||
/* Set default if needed */
|
||||
if (pemfile == NULL)
|
||||
pemfile = "echconfig.pem";
|
||||
|
||||
if (outfile == NULL)
|
||||
outfile = "echconfig.pem";
|
||||
es = OSSL_ECHSTORE_new(NULL, NULL);
|
||||
if (es == NULL)
|
||||
goto end;
|
||||
if (mode == OSSL_ECH_KEYGEN_MODE) {
|
||||
OSSL_ECHSTORE *es = NULL;
|
||||
BIO *ecf = NULL;
|
||||
|
||||
if (verbose)
|
||||
BIO_printf(bio_err, "Calling OSSL_ECHSTORE_new_config\n");
|
||||
if ((ecf = BIO_new_file(pemfile, "w")) == NULL
|
||||
|| (es = OSSL_ECHSTORE_new(NULL, NULL)) == NULL
|
||||
if ((ecf = BIO_new_file(outfile, "w")) == NULL
|
||||
|| OSSL_ECHSTORE_new_config(es, ech_version, max_name_length,
|
||||
public_name, hpke_suite)
|
||||
!= 1
|
||||
@@ -188,17 +206,72 @@ int ech_main(int argc, char **argv)
|
||||
}
|
||||
if (verbose)
|
||||
BIO_printf(bio_err, "OSSL_ECHSTORE_new_config success\n");
|
||||
OSSL_ECHSTORE_free(es);
|
||||
BIO_free_all(ecf);
|
||||
return 1;
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
opthelp:
|
||||
BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
|
||||
goto end;
|
||||
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) {
|
||||
OSSL_ECH_INFO *oi = NULL;
|
||||
int oi_ind, oi_cnt = 0;
|
||||
|
||||
if (OSSL_ECHSTORE_get1_info(es, &oi, &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++) {
|
||||
if (OSSL_ECH_INFO_print(bio_out, oi, oi_ind) != 1) {
|
||||
BIO_printf(bio_err, "OSSL_ECH_INFO_print error entry (%d)\n",
|
||||
oi_ind);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
OSSL_ECH_INFO_free(oi, oi_cnt);
|
||||
if (verbose)
|
||||
BIO_printf(bio_err, "Success printing %d ECHConfigList\n", oi_cnt);
|
||||
rv = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
return 0;
|
||||
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
|
||||
|
||||
@@ -1348,6 +1348,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:425: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
|
||||
@@ -1428,6 +1429,7 @@ 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:426:ech decode error
|
||||
SSL_R_ECH_REQUIRED:424:ech required
|
||||
SSL_R_EE_KEY_TOO_SMALL:399:ee key too small
|
||||
SSL_R_EMPTY_RAW_PUBLIC_KEY:349:empty raw public key
|
||||
|
||||
@@ -37,6 +37,8 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
|
||||
{ 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),
|
||||
@@ -156,6 +158,7 @@ static const ERR_STRING_DATA SSL_str_reasons[] = {
|
||||
"ecc cert not for signing" },
|
||||
{ ERR_PACK(ERR_LIB_SSL, 0, SSL_R_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),
|
||||
|
||||
@@ -205,6 +205,8 @@ 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);
|
||||
@@ -234,7 +236,8 @@ value and the related "singleton" ECHConfigList structure.
|
||||
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.)
|
||||
`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
|
||||
@@ -323,6 +326,7 @@ typedef struct ossl_ech_info_st {
|
||||
unsigned char *inner_alpns; /* inner ALPN string */
|
||||
size_t inner_alpns_len;
|
||||
char *echconfig; /* a JSON-like version of the associated ECHConfig */
|
||||
int has_private_key; /* 0 if we don't have a related private key */
|
||||
} OSSL_ECH_INFO;
|
||||
|
||||
void OSSL_ECH_INFO_free(OSSL_ECH_INFO *info, int count);
|
||||
|
||||
@@ -10,24 +10,30 @@ openssl-ech - ECH key generation
|
||||
B<openssl> B<ech>
|
||||
[B<-help>]
|
||||
[B<-verbose>]
|
||||
[B<-pemout> I<file>]
|
||||
[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) private keys
|
||||
and public keys in the ECHConfig format.
|
||||
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.
|
||||
|
||||
The "ECHConfig PEM file" format mentioned below is specified in
|
||||
L<https://datatracker.ietf.org/doc/draft-farrell-tls-pemesni/> and consists of
|
||||
one private key in PKCS#8 format and a base64 encoded ECHConfig containing one
|
||||
matching public value.
|
||||
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>
|
||||
@@ -38,9 +44,21 @@ Print out a usage message.
|
||||
|
||||
Print more verbosely.
|
||||
|
||||
=item B<-pemout> I<file>
|
||||
=item B<-in>
|
||||
|
||||
Name of output ECHConfig PEM file.
|
||||
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 output.
|
||||
|
||||
=item B<-public_name> I<name>
|
||||
|
||||
@@ -58,6 +76,11 @@ HPKE suite to use in the ECHConfig.
|
||||
|
||||
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
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
|
||||
/* 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
|
||||
|
||||
/*
|
||||
* Application-visible form of ECH information from the DNS, from config
|
||||
@@ -73,11 +75,12 @@ typedef struct ossl_ech_info_st {
|
||||
unsigned char *inner_alpns; /* inner ALPN string */
|
||||
size_t inner_alpns_len;
|
||||
char *echconfig; /* a JSON-like version of the associated ECHConfig */
|
||||
int has_private_key; /* 0 if we don't have a related private key */
|
||||
} OSSL_ECH_INFO;
|
||||
|
||||
/* Values for the for_retry inputs */
|
||||
#define SSL_ECH_USE_FOR_RETRY 1
|
||||
#define SSL_ECH_NOT_FOR_RETRY 0
|
||||
#define OSSL_ECH_FOR_RETRY 1
|
||||
#define OSSL_ECH_NO_RETRY 0
|
||||
|
||||
/*
|
||||
* API calls built around OSSL_ECHSTORE
|
||||
|
||||
@@ -34,6 +34,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 425
|
||||
#define SSL_R_BAD_ECPOINT 306
|
||||
#define SSL_R_BAD_EXTENSION 110
|
||||
#define SSL_R_BAD_HANDSHAKE_LENGTH 332
|
||||
@@ -111,6 +112,7 @@
|
||||
#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 426
|
||||
#define SSL_R_ECH_REQUIRED 424
|
||||
#define SSL_R_EE_KEY_TOO_SMALL 399
|
||||
#define SSL_R_EMPTY_RAW_PUBLIC_KEY 349
|
||||
|
||||
+4
-1
@@ -2,6 +2,10 @@ SUBDIRS=record rio quic
|
||||
|
||||
LIBS=../libssl
|
||||
|
||||
IF[{- !$disabled{ech} -}]
|
||||
SUBDIRS=ech
|
||||
ENDIF
|
||||
|
||||
SOURCE[../libssl]=\
|
||||
pqueue.c \
|
||||
statem/statem_srvr.c statem/statem_clnt.c s3_lib.c s3_enc.c \
|
||||
@@ -16,7 +20,6 @@ SOURCE[../libssl]=\
|
||||
bio_ssl.c ssl_err_legacy.c tls_srp.c t1_trce.c ssl_utst.c \
|
||||
statem/statem.c \
|
||||
ssl_cert_comp.c \
|
||||
ech.c \
|
||||
tls_depr.c
|
||||
|
||||
# For shared builds we need to include the libcrypto packet.c and quic_vlint.c
|
||||
|
||||
@@ -1,471 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "statem/statem_local.h"
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/trace.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/kdf.h>
|
||||
|
||||
#ifndef OPENSSL_NO_ECH
|
||||
|
||||
/* a size for some crypto vars */
|
||||
#define OSSL_ECH_CRYPTO_VAR_SIZE 2048
|
||||
|
||||
/*
|
||||
* @brief hash a buffer as a pretend file name being ascii-hex of hashed buffer
|
||||
* @param es is the OSSL_ECHSTORE we're dealing with
|
||||
* @param buf is the input buffer
|
||||
* @param blen is the length of buf
|
||||
* @param ah_hash is a pointer to where to put the result
|
||||
* @param ah_len is the length of ah_hash
|
||||
*/
|
||||
static int ech_hash_pub_as_fname(OSSL_ECHSTORE *es,
|
||||
const unsigned char *buf, size_t blen,
|
||||
char *ah_hash, size_t ah_len)
|
||||
{
|
||||
unsigned char hashval[EVP_MAX_MD_SIZE];
|
||||
size_t hashlen, actual_ah_len;
|
||||
|
||||
if (es == NULL
|
||||
|| EVP_Q_digest(es->libctx, "SHA2-256", es->propq,
|
||||
buf, blen, hashval, &hashlen)
|
||||
!= 1
|
||||
|| OPENSSL_buf2hexstr_ex(ah_hash, ah_len, &actual_ah_len,
|
||||
hashval, hashlen, '\0')
|
||||
!= 1) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* API calls built around OSSL_ECHSTORE
|
||||
*/
|
||||
|
||||
OSSL_ECHSTORE *OSSL_ECHSTORE_new(OSSL_LIB_CTX *libctx, const char *propq)
|
||||
{
|
||||
OSSL_ECHSTORE *es = NULL;
|
||||
|
||||
es = OPENSSL_zalloc(sizeof(*es));
|
||||
if (es == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
return 0;
|
||||
}
|
||||
es->libctx = libctx;
|
||||
es->propq = propq;
|
||||
return es;
|
||||
}
|
||||
|
||||
static void ossl_echext_free(OSSL_ECHEXT *e)
|
||||
{
|
||||
if (e == NULL)
|
||||
return;
|
||||
OPENSSL_free(e->val);
|
||||
OPENSSL_free(e);
|
||||
return;
|
||||
}
|
||||
|
||||
static void ossl_echstore_entry_free(OSSL_ECHSTORE_ENTRY *ee)
|
||||
{
|
||||
if (ee == NULL)
|
||||
return;
|
||||
OPENSSL_free(ee->public_name);
|
||||
OPENSSL_free(ee->pub);
|
||||
OPENSSL_free(ee->pemfname);
|
||||
EVP_PKEY_free(ee->keyshare);
|
||||
OPENSSL_free(ee->encoded);
|
||||
OPENSSL_free(ee->suites);
|
||||
sk_OSSL_ECHEXT_pop_free(ee->exts, ossl_echext_free);
|
||||
OPENSSL_free(ee);
|
||||
return;
|
||||
}
|
||||
|
||||
void OSSL_ECHSTORE_free(OSSL_ECHSTORE *es)
|
||||
{
|
||||
if (es == NULL)
|
||||
return;
|
||||
sk_OSSL_ECHSTORE_ENTRY_pop_free(es->entries, ossl_echstore_entry_free);
|
||||
OPENSSL_free(es);
|
||||
return;
|
||||
}
|
||||
|
||||
int OSSL_ECHSTORE_new_config(OSSL_ECHSTORE *es,
|
||||
uint16_t echversion, uint8_t max_name_length,
|
||||
const char *public_name, OSSL_HPKE_SUITE suite)
|
||||
{
|
||||
size_t pnlen = 0;
|
||||
size_t publen = OSSL_ECH_CRYPTO_VAR_SIZE;
|
||||
unsigned char pub[OSSL_ECH_CRYPTO_VAR_SIZE];
|
||||
int rv = 0;
|
||||
unsigned char *bp = NULL;
|
||||
size_t bblen = 0;
|
||||
EVP_PKEY *privp = NULL;
|
||||
uint8_t config_id = 0;
|
||||
WPACKET epkt;
|
||||
BUF_MEM *epkt_mem = NULL;
|
||||
OSSL_ECHSTORE_ENTRY *ee = NULL;
|
||||
char pembuf[2 * EVP_MAX_MD_SIZE + 1];
|
||||
size_t pembuflen = 2 * EVP_MAX_MD_SIZE + 1;
|
||||
|
||||
/* basic checks */
|
||||
if (es == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_NULL_PARAMETER);
|
||||
return 0;
|
||||
}
|
||||
pnlen = (public_name == NULL ? 0 : strlen(public_name));
|
||||
if (pnlen == 0 || pnlen > OSSL_ECH_MAX_PUBLICNAME
|
||||
|| max_name_length > OSSL_ECH_MAX_MAXNAMELEN) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
/* this used have more versions and will again in future */
|
||||
switch (echversion) {
|
||||
case OSSL_ECH_RFCXXXX_VERSION:
|
||||
break;
|
||||
default:
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* so WPACKET_cleanup() won't go wrong */
|
||||
memset(&epkt, 0, sizeof(epkt));
|
||||
/* random config_id */
|
||||
if (RAND_bytes_ex(es->libctx, (unsigned char *)&config_id, 1,
|
||||
RAND_DRBG_STRENGTH)
|
||||
<= 0) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
/* key pair */
|
||||
if (OSSL_HPKE_keygen(suite, pub, &publen, &privp, NULL, 0,
|
||||
es->libctx, es->propq)
|
||||
!= 1) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
/*
|
||||
* Reminder, for draft-13 we want this:
|
||||
*
|
||||
* 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>;
|
||||
*/
|
||||
if ((epkt_mem = BUF_MEM_new()) == NULL
|
||||
|| !BUF_MEM_grow(epkt_mem, OSSL_ECH_MAX_ECHCONFIG_LEN)) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
/* config id, KEM, public, KDF, AEAD, max name len, public_name, exts */
|
||||
if (!WPACKET_init(&epkt, epkt_mem)
|
||||
|| (bp = WPACKET_get_curr(&epkt)) == NULL
|
||||
|| !WPACKET_start_sub_packet_u16(&epkt)
|
||||
|| !WPACKET_put_bytes_u16(&epkt, echversion)
|
||||
|| !WPACKET_start_sub_packet_u16(&epkt)
|
||||
|| !WPACKET_put_bytes_u8(&epkt, config_id)
|
||||
|| !WPACKET_put_bytes_u16(&epkt, suite.kem_id)
|
||||
|| !WPACKET_start_sub_packet_u16(&epkt)
|
||||
|| !WPACKET_memcpy(&epkt, pub, publen)
|
||||
|| !WPACKET_close(&epkt)
|
||||
|| !WPACKET_start_sub_packet_u16(&epkt)
|
||||
|| !WPACKET_put_bytes_u16(&epkt, suite.kdf_id)
|
||||
|| !WPACKET_put_bytes_u16(&epkt, suite.aead_id)
|
||||
|| !WPACKET_close(&epkt)
|
||||
|| !WPACKET_put_bytes_u8(&epkt, max_name_length)
|
||||
|| !WPACKET_start_sub_packet_u8(&epkt)
|
||||
|| !WPACKET_memcpy(&epkt, public_name, pnlen)
|
||||
|| !WPACKET_close(&epkt)
|
||||
|| !WPACKET_start_sub_packet_u16(&epkt)
|
||||
|| !WPACKET_memcpy(&epkt, NULL, 0) /* no extensions */
|
||||
|| !WPACKET_close(&epkt)
|
||||
|| !WPACKET_close(&epkt)
|
||||
|| !WPACKET_close(&epkt)) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
/* bp, bblen has encoding */
|
||||
WPACKET_get_total_written(&epkt, &bblen);
|
||||
if ((ee = OPENSSL_zalloc(sizeof(*ee))) == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
ee->suites = OPENSSL_malloc(sizeof(OSSL_HPKE_SUITE));
|
||||
if (ee->suites == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
if (ech_hash_pub_as_fname(es, pub, publen, pembuf, pembuflen) != 1) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
ee->version = echversion;
|
||||
ee->pub_len = publen;
|
||||
ee->pub = OPENSSL_memdup(pub, publen);
|
||||
if (ee->pub == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
ee->nsuites = 1;
|
||||
ee->suites[0] = suite;
|
||||
ee->public_name = OPENSSL_strdup(public_name);
|
||||
if (ee->public_name == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
ee->max_name_length = max_name_length;
|
||||
ee->config_id = config_id;
|
||||
ee->keyshare = privp;
|
||||
ee->encoded = OPENSSL_memdup(bp, bblen);
|
||||
if (ee->encoded == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
ee->encoded_len = bblen;
|
||||
ee->pemfname = OPENSSL_strdup(pembuf);
|
||||
if (ee->pemfname == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
ee->loadtime = time(0);
|
||||
/* push entry into store */
|
||||
if (es->entries == NULL)
|
||||
es->entries = sk_OSSL_ECHSTORE_ENTRY_new_null();
|
||||
if (es->entries == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
if (!sk_OSSL_ECHSTORE_ENTRY_push(es->entries, ee)) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
WPACKET_finish(&epkt);
|
||||
BUF_MEM_free(epkt_mem);
|
||||
return 1;
|
||||
|
||||
err:
|
||||
EVP_PKEY_free(privp);
|
||||
WPACKET_cleanup(&epkt);
|
||||
BUF_MEM_free(epkt_mem);
|
||||
ossl_echstore_entry_free(ee);
|
||||
OPENSSL_free(ee);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int OSSL_ECHSTORE_write_pem(OSSL_ECHSTORE *es, int index, BIO *out)
|
||||
{
|
||||
OSSL_ECHSTORE_ENTRY *ee = NULL;
|
||||
int rv = 0, num = 0, chosen = 0;
|
||||
|
||||
if (es == 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;
|
||||
}
|
||||
num = sk_OSSL_ECHSTORE_ENTRY_num(es->entries);
|
||||
if (num <= 0) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
if (index >= num) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
if (index == OSSL_ECHSTORE_LAST)
|
||||
chosen = num - 1;
|
||||
else
|
||||
chosen = index;
|
||||
ee = sk_OSSL_ECHSTORE_ENTRY_value(es->entries, chosen);
|
||||
if (ee == NULL || ee->keyshare == NULL || ee->encoded == NULL) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT);
|
||||
return 0;
|
||||
}
|
||||
/* private key first */
|
||||
if (!PEM_write_bio_PrivateKey(out, ee->keyshare, NULL, NULL, 0,
|
||||
NULL, NULL)) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
if (PEM_write_bio(out, PEM_STRING_ECHCONFIG, NULL,
|
||||
ee->encoded, ee->encoded_len)
|
||||
<= 0) {
|
||||
ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR);
|
||||
goto err;
|
||||
}
|
||||
rv = 1;
|
||||
err:
|
||||
return rv;
|
||||
}
|
||||
|
||||
int OSSL_ECHSTORE_read_echconfiglist(OSSL_ECHSTORE *es, BIO *in)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OSSL_ECHSTORE_get1_info(OSSL_ECHSTORE *es, OSSL_ECH_INFO **info,
|
||||
int *count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OSSL_ECHSTORE_downselect(OSSL_ECHSTORE *es, int index)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OSSL_ECHSTORE_set1_key_and_read_pem(OSSL_ECHSTORE *es, EVP_PKEY *priv,
|
||||
BIO *in, int for_retry)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OSSL_ECHSTORE_read_pem(OSSL_ECHSTORE *es, BIO *in, int for_retry)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OSSL_ECHSTORE_num_keys(OSSL_ECHSTORE *es, int *numkeys)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int OSSL_ECHSTORE_flush_keys(OSSL_ECHSTORE *es, time_t age)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OSSL_ECH_INFO_free(OSSL_ECH_INFO *info, int count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int OSSL_ECH_INFO_print(BIO *out, OSSL_ECH_INFO *info, int count)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_CTX_set1_echstore(SSL_CTX *ctx, OSSL_ECHSTORE *es)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_set1_echstore(SSL *s, OSSL_ECHSTORE *es)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
OSSL_ECHSTORE *SSL_CTX_get1_echstore(const SSL_CTX *ctx)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OSSL_ECHSTORE *SSL_get1_echstore(const SSL *s)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int SSL_ech_set_server_names(SSL *s, const char *inner_name,
|
||||
const char *outer_name, int no_outer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_ech_set_outer_server_name(SSL *s, const char *outer_name, int no_outer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_ech_set_outer_alpn_protos(SSL *s, const unsigned char *protos,
|
||||
const size_t protos_len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_ech_get1_status(SSL *s, char **inner_sni, char **outer_sni)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_ech_set_grease_suite(SSL *s, const char *suite)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_ech_set_grease_type(SSL *s, uint16_t type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SSL_ech_set_callback(SSL *s, SSL_ech_cb_func f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int SSL_ech_get_retry_config(SSL *s, unsigned char **ec, size_t *eclen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_CTX_ech_set_outer_alpn_protos(SSL_CTX *s, const unsigned char *protos,
|
||||
const size_t protos_len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SSL_CTX_ech_set_callback(SSL_CTX *ctx, SSL_ech_cb_func f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
$LIBSSL=../../libssl
|
||||
|
||||
SOURCE[$LIBSSL]=ech_ssl_apis.c ech_store.c ech_internal.c ech_helper.c
|
||||
@@ -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 */
|
||||
@@ -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 ECH internal code here when we get to it */
|
||||
@@ -31,6 +31,7 @@
|
||||
*/
|
||||
#define OSSL_ECH_SUPERVERBOSE
|
||||
|
||||
#define OSSL_ECH_CIPHER_LEN 4 /* ECHCipher length (2 for kdf, 2 for aead) */
|
||||
/*
|
||||
* Reminder of what goes in DNS for ECH RFC XXXX
|
||||
*
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_set1_echstore(SSL *s, OSSL_ECHSTORE *es)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
OSSL_ECHSTORE *SSL_CTX_get1_echstore(const SSL_CTX *ctx)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OSSL_ECHSTORE *SSL_get1_echstore(const SSL *s)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int SSL_ech_set_server_names(SSL *s, const char *inner_name,
|
||||
const char *outer_name, int no_outer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_ech_set_outer_server_name(SSL *s, const char *outer_name, int no_outer)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_ech_set_outer_alpn_protos(SSL *s, const unsigned char *protos,
|
||||
const size_t protos_len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_ech_get1_status(SSL *s, char **inner_sni, char **outer_sni)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_ech_set_grease_suite(SSL *s, const char *suite)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_ech_set_grease_type(SSL *s, uint16_t type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SSL_ech_set_callback(SSL *s, SSL_ech_cb_func f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int SSL_ech_get_retry_config(SSL *s, unsigned char **ec, size_t *eclen)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SSL_CTX_ech_set_outer_alpn_protos(SSL_CTX *s, const unsigned char *protos,
|
||||
const size_t protos_len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return;
|
||||
}
|
||||
+1172
File diff suppressed because it is too large
Load Diff
@@ -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-----
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MC4CAQAwBQYDK2VuBCIEIKBC3rocwIF5tGY+/TaYQrCxY+ULsch94ja9DojkcvlT
|
||||
-----END PRIVATE KEY-----
|
||||
-----BEGIN ECHCONFIG-----
|
||||
ADn+DQA1agAgACBtuySC1pphjFlGYKTaSm2KWNg7GQVRS8uAYvLTm5QlGwAEAAEA
|
||||
AQAGZWcuY29tAAA=
|
||||
-----END ECHCONFIG-----
|
||||
@@ -0,0 +1,37 @@
|
||||
-----BEGIN ECHCONFIG-----
|
||||
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
|
||||
-----END ECHCONFIG-----`
|
||||
@@ -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-----
|
||||
@@ -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-----
|
||||
+1001
-1
File diff suppressed because it is too large
Load Diff
@@ -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");
|
||||
});
|
||||
Reference in New Issue
Block a user