Skip to content
Permalink
Browse files

new APIs for name/address visibility to application

  • Loading branch information...
sftcd committed Apr 4, 2019
1 parent a6b8da4 commit 526f751cf9819cbcb5b29d379c0a2b3973792373
Showing with 460 additions and 52 deletions.
  1. +1 −1 esnistuff/Makefile
  2. +14 −0 esnistuff/README.md
  3. +1 −1 esnistuff/doit.sh
  4. +4 −2 esnistuff/doit2.sh
  5. +61 −12 esnistuff/esnimain.c
  6. +68 −3 include/openssl/esni.h
  7. +310 −32 ssl/esni.c
  8. +1 −1 ssl/ssl_lib.c
@@ -42,7 +42,7 @@ esni: esnimain.o libssl.a libcrypto.a
${CC} -g -pthread -Wall -o $@ esnimain.o -L. -lssl -lcrypto -ldl

test:
./doit.sh fresh
./doit.sh fresh -v

staletest:
./doit.sh
@@ -25,6 +25,20 @@ There's a [TODO list](#todos) at the end.

Most recent first...

- Added new APIs for allowing application to access some (new) internals of
ESNIKeys RR. Not yet documented in design.md, and still need to add the
proper OpenSSL error string handling, but those are:

- ``SSL_esni_query`` to extract more easily understood bits
of ESNIKeys RR (public_name and addresses)
- ``SSL_esni_reduce`` to allow application to downselect
to the stuff from one RR based on output of the above
- ``SSL_ESNI_ext_free`` to allow application to free the
"nicer" format info from ``SSL_esni_query``
- ``SSL_ESNI_ext_print`` to whack that to stdout etc.

See the next point down for why...

- Added parsing of AddressSet extension into ``BIO_ADDR`` structure, with
a view to providing a new API that allows the application to see which
``public_name`` and IP address combinations exist and to then allow the
@@ -42,4 +42,4 @@ fi
#valgrind --leak-check=full ./esni -s $HIDDEN -f $COVER -e $ESNI -p $PRIV -r $CRND -k $HSKS -n $NONCE

# "normal" version - doesn't take other folks' internal crypto inputs
valgrind --leak-check=full ./esni -s $HIDDEN -f $COVER -e $ESNI
valgrind --leak-check=full ./esni -s $HIDDEN -f $COVER -e $ESNI $*
@@ -19,7 +19,9 @@
# an ESNI with some crap extensions (greased)
#ESNI="ff0238ed29ea0006666f6f2e69650024001d0020c01e55e8801e772487553cf6d0fc80e9887a58a7cf8a5361de0a0aca28a8b874000213010104000000005ca4aeb8000000005cade93800befff1003ecdc23775802e5360298901b92e140baf87fdcbc8b114fd4651ba9b76499b627cc67077c11792bc8a5da2c60189b49f63fccee0bd56d172b03fafc32fc30b1001001604b918e977062a042e0000010014000000000000000afff2005ef65696177cfe99e9c6cabf016a38bb12b958a74203c59caad88ca9fca60333fc0fb78764ccfaa39a41cadd535929d4dd76504d15acdef44ccc3b2b0148be5b665c115045586ea47862a37ca95cac6b5a32debe931bb6be4e9dae05315b0c"
# an ESNI with some crap extensions (greased) incl. one that's got an empty value
ESNI="ff023bc449be0006666f6f2e69650024001d0020c01e55e8801e772487553cf6d0fc80e9887a58a7cf8a5361de0a0aca28a8b874000213010104000000005ca4b35d000000005cadeddd0078fff30000fff10009c77963690088e3121a1001001604b918e977062a042e0000010014000000000000000afff30000fff20045a44ec709ebf763ba173374ba2fa41e26f58c5c39539975bba7d342d94bef9145cee7939ab87ec1c1d2010d537189cde0e8c7e598adb49330a72d065dd957ea293a726b52b2"
#ESNI="ff023bc449be0006666f6f2e69650024001d0020c01e55e8801e772487553cf6d0fc80e9887a58a7cf8a5361de0a0aca28a8b874000213010104000000005ca4b35d000000005cadeddd0078fff30000fff10009c77963690088e3121a1001001604b918e977062a042e0000010014000000000000000afff30000fff20045a44ec709ebf763ba173374ba2fa41e26f58c5c39539975bba7d342d94bef9145cee7939ab87ec1c1d2010d537189cde0e8c7e598adb49330a72d065dd957ea293a726b52b2"
# three ESNI's with some crap extensions (greased) incl. one that's got an empty value
ESNI="ff023bc449be0006666f6f2e69650024001d0020c01e55e8801e772487553cf6d0fc80e9887a58a7cf8a5361de0a0aca28a8b874000213010104000000005ca4b35d000000005cadeddd0078fff30000fff10009c77963690088e3121a1001001604b918e977062a042e0000010014000000000000000afff30000fff20045a44ec709ebf763ba173374ba2fa41e26f58c5c39539975bba7d342d94bef9145cee7939ab87ec1c1d2010d537189cde0e8c7e598adb49330a72d065dd957ea293a726b52b2ff0228b94458000e726573706f6e7369626c652e69650024001d0020c01e55e8801e772487553cf6d0fc80e9887a58a7cf8a5361de0a0aca28a8b874000213010104000000005ca475a0000000005cadb020001a1001001604b918e9d3062a042e0000010067000000000000000aff0235b744110006666f6f2e69650024001d0020c01e55e8801e772487553cf6d0fc80e9887a58a7cf8a5361de0a0aca28a8b874000213010104000000005ca4762c000000005cadb0ac001a1001001604b918e977062a042e0000010014000000000000000a"
HIDDEN="encryptedsni.com"
COVER="www.cloudflare.com"

@@ -49,4 +51,4 @@ fi
#valgrind --leak-check=full ./esni -s $HIDDEN -f $COVER -e $ESNI -p $PRIV -r $CRND -k $HSKS -n $NONCE

# "normal" version - doesn't take other folks' internal crypto inputs
valgrind --leak-check=full ./esni -s $HIDDEN -f $COVER -e "$ESNI"
valgrind --leak-check=full ./esni -s $HIDDEN -f $COVER -e "$ESNI" $*
@@ -37,7 +37,7 @@ void usage(char *prog)
/*
* TODO: moar text
*/
printf("%s -e ESNI [-p priv] [-r client_random] [-s encservername] [-f covername] [-k h/s key_share] [-n nonce]\n",prog);
printf("%s -e ESNI [-p priv] [-r client_random] [-s encservername] [-f covername] [-k h/s key_share] [-n nonce] [-R] [-v]\n",prog);
exit(1);
}

@@ -54,12 +54,16 @@ int main(int argc, char **argv)
char *private_str=NULL; // input ECDH private
int rv;
unsigned char *nbuf=NULL;
SSL_ESNI_ext *se=NULL;
int nses=0;
int reduce=0;
int verbose=0;

// getopt vars
int opt;

// check inputs with getopt
while((opt = getopt(argc, argv, "?hs:e:p:r:k:f:n:")) != -1) {
while((opt = getopt(argc, argv, "?hs:e:p:r:k:f:n:Rv")) != -1) {
switch(opt) {
case 'h':
case '?':
@@ -86,6 +90,12 @@ int main(int argc, char **argv)
case 'f':
covername=optarg;
break;
case 'R':
reduce=1;
break;
case 'v':
verbose=1;
break;
default:
fprintf(stderr, "Error - No such option: `%c'\n\n", optopt);
usage(argv[0]);
@@ -169,6 +179,47 @@ int main(int argc, char **argv)
goto end;
}

rv=SSL_esni_query(esnikeys,&se,&nses);
if (rv!=1) {
printf("Can't query SSL_ESNI from RR value!\n");
goto end;
}

fp=fopen("/dev/stdout","w");
if (fp==NULL)
goto end;

out=BIO_new_fp(fp,BIO_CLOSE|BIO_FP_TEXT);
if (out == NULL)
goto end;

if (reduce==1 && nses>1) {
/*
* Arbitrarily pick 2nd one
*/
SSL_ESNI *newesnikeys=NULL;
rv=SSL_esni_reduce(esnikeys,1,&newesnikeys);
if (rv!=1) {
printf("Can't reduce SSL_ESNI!\n");
goto end;
}
SSL_ESNI_free(esnikeys);
OPENSSL_free(esnikeys);
esnikeys=newesnikeys;
nesnis=1;
}

rv=SSL_ESNI_ext_print(out,se,nses);
if (rv!=1) {
printf("Can't print SSL_ESNI_ext!\n");
goto end;
}

SSL_ESNI_ext_free(se,nses);
OPENSSL_free(se);
se=NULL;
nses=0;

#ifdef ESNI_CRYPT_INTEROP
if (private_str!=NULL) {
SSL_ESNI_set_private(esnikeys,private_str);
@@ -196,14 +247,6 @@ int main(int argc, char **argv)
}
#endif

fp=fopen("/dev/stdout","w");
if (fp==NULL)
goto end;

out=BIO_new_fp(fp,BIO_CLOSE|BIO_FP_TEXT);
if (out == NULL)
goto end;

for (int i=0;i!=nesnis;i++) {

esnikeys[i].encservername=OPENSSL_strndup(encservername,TLSEXT_MAXLEN_host_name);
@@ -224,18 +267,24 @@ int main(int argc, char **argv)

}

if (!SSL_ESNI_print(out,esnikeys)) {
if (verbose==1 && !SSL_ESNI_print(out,esnikeys)) {
printf("Can't print SSL_ESNI!\n");
goto end;
}

end:
BIO_free_all(out);
if (se!=NULL) {
SSL_ESNI_ext_free(se,nses);
OPENSSL_free(se);
}
if (esnikeys!=NULL) {
SSL_ESNI_free(esnikeys);
OPENSSL_free(esnikeys);
}
OPENSSL_free(nbuf);
if (nbuf!=NULL) {
OPENSSL_free(nbuf);
}
return(0);
}
#endif
@@ -22,6 +22,8 @@

#define ESNI_MAX_RRVALUE_LEN 2000 ///< Max size of a collection of ESNI RR values

#define ESNI_SELECT_ALL -1 ///< used to duplicate all RRs in SSL_ESNI_dup


/*
* ESNIKeys Extensions we know about...
@@ -159,6 +161,10 @@ typedef struct client_esni_st {
* On the server-side, an array of these is part of the SSL_CTX
* structure, and we match one of 'em to be part of the SSL
* structure when a handshake is in porgress. (Well, hopefully:-)
*
* Note that SSL_ESNI_dup copies all these fields (when values are
* set), so if you add, change or remove a field here, you'll also
* need to modify that (in ssl/esni.c)
*/
typedef struct ssl_esni_st {
unsigned int version; ///< version from underlying ESNI_RECORD/ESNIKeys
@@ -230,6 +236,15 @@ typedef struct ssl_esni_st {
CLIENT_ESNI *the_esni; ///< the final outputs for the caller (note: not separately alloc'd)
} SSL_ESNI;

/*
* Exterally visible form of an ESNIKeys RR value
*/
typedef struct ssl_esni_ext_st {
int index; ///< externally re-usable reference to this RR value
char *public_name; ///< public_name from ESNIKeys
char *prefixes; ///< comman seperated list of IP address prefixes, in CIDR form
} SSL_ESNI_ext;

/*
* Non-external Prototypes
*/
@@ -326,9 +341,10 @@ void SSL_ESNI_free(SSL_ESNI *esnikeys);
*
* @param orig is the input array of SSL_ESNI to be partly deep-copied
* @param nesni is the number of elements in the array
* @param selector allows for picking all (ESNI_SELECT_ALL==-1) or just one of the RR values in orig
* @return a partial deep-copy array or NULL if errors occur
*/
SSL_ESNI* SSL_ESNI_dup(SSL_ESNI* orig, size_t nesni);
SSL_ESNI* SSL_ESNI_dup(SSL_ESNI* orig, size_t nesni, int selector);

/*
* Externally visible Prototypes
@@ -371,11 +387,60 @@ SSL_ESNI* SSL_ESNI_new_from_buffer(const short ekfmt, const size_t eklen, const
* @param esni is an array of SSL_ESNI structures
* @param nesnis says how many structures are in the esni array
* @param require_hidden_match say whether to require (==1) the TLS server cert matches the hidden name
* @return 1 for success, other otherwise
* @return 1 for success, error otherwise
*
*/
int SSL_esni_enable(SSL *s, const char *hidden, const char *cover, SSL_ESNI *esni, int nesnis, int require_hidden_match);

/**
* @brief query the content of an SSL_ESNI structure
*
* This function allows the application to examine some internals
* of an SSL_ESNI structure so that it can then down-select some
* options. In particular, the caller can see the public_name and
* IP address related information associated with each ESNIKeys
* RR value (after decoding and initial checking within the
* library), and can then choose which of the RR value options
* the application would prefer to use.
*
* @param in is the internal form of SSL_ESNI structure
* @param out is the returned externally visible detailed form of the SSL_ESNI structure
* @param nindices is an output saying how many indices are in the SSL_ESNI_ext structure
* @return 1 for success, error otherwise
*/
int SSL_esni_query(SSL_ESNI *in, SSL_ESNI_ext **out,int *nindices);

/**
* @brief free up memory for an SSL_ESNI_ext
*
* @param in is the structure to free up
* @param size says how many indices are in in
*/
void SSL_ESNI_ext_free(SSL_ESNI_ext *in,int size);

/**
* @brief utility fnc for application that wants to print an SSL_ESNI_ext
*
* @param out is the BIO to use (e.g. stdout/whatever)
* @param se is a pointer to an SSL_ESNI_ext struture
* @param count is the number of elements in se
* @return 1 for success, error othewise
*/
int SSL_ESNI_ext_print(BIO* out, SSL_ESNI_ext *se,int count);

/**
* @brief down-select to use of one option with an SSL_ESNI
*
* This allows the caller to select one of the RR values
* within an SSL_ESNI for later use.
*
* @param in is an SSL_ESNI structure with possibly multiple RR values
* @param index is the index value from an SSL_ESNI_ext produced from the 'in'
* @param out is a returned SSL_ESNI containing only that indexed RR value
* @return 1 for success, error otherwise
*/
int SSL_esni_reduce(SSL_ESNI *in, int index, SSL_ESNI **out);

/**
* Turn on SNI Encryption, server-side
*
@@ -411,7 +476,7 @@ int SSL_ESNI_get_esni_ctx(SSL_CTX *s, SSL_ESNI **esni);
* Print the content of an SSL_ESNI
*
* @param out is the BIO to use (e.g. stdout/whatever)
* @esni is an SSL_ESNI strucutre
* @param esni is an SSL_ESNI strucutre
* @return 1 for success, anything else for failure
*/
int SSL_ESNI_print(BIO* out, SSL_ESNI *esni);

0 comments on commit 526f751

Please sign in to comment.
You can’t perform that action at this time.