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:
sftcd
2024-09-11 00:28:32 +01:00
committed by Matt Caswell
parent 80efca5392
commit 4af71a7738
22 changed files with 2664 additions and 523 deletions
+111 -38
View File
@@ -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
+2
View File
@@ -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
+3
View File
@@ -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),
+5 -1
View File
@@ -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);
+32 -9
View File
@@ -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
+5 -2
View File
@@ -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
+2
View File
@@ -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
View File
@@ -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
-471
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
$LIBSSL=../../libssl
SOURCE[$LIBSSL]=ech_ssl_apis.c ech_store.c ech_internal.c ech_helper.c
+15
View 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 */
+15
View 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 ECH internal code here when we get to it */
+1
View File
@@ -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
*
+106
View File
@@ -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
View File
File diff suppressed because it is too large Load Diff
+25
View 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
View File
@@ -0,0 +1,7 @@
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VuBCIEIKBC3rocwIF5tGY+/TaYQrCxY+ULsch94ja9DojkcvlT
-----END PRIVATE KEY-----
-----BEGIN ECHCONFIG-----
ADn+DQA1agAgACBtuySC1pphjFlGYKTaSm2KWNg7GQVRS8uAYvLTm5QlGwAEAAEA
AQAGZWcuY29tAAA=
-----END ECHCONFIG-----
+37
View File
@@ -0,0 +1,37 @@
-----BEGIN ECHCONFIG-----
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
-----END ECHCONFIG-----`
+11
View 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
View 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-----
+1001 -1
View File
File diff suppressed because it is too large Load Diff
+93
View 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");
});