- Added openssl application-layer protocol negotiation
- Added restconf tests for http/1.0 and http/2
This commit is contained in:
parent
ad08200931
commit
6ed2202638
2 changed files with 96 additions and 2 deletions
|
|
@ -188,6 +188,8 @@
|
||||||
/* Forward */
|
/* Forward */
|
||||||
static int restconf_connection(int s, void* arg);
|
static int restconf_connection(int s, void* arg);
|
||||||
|
|
||||||
|
static int session_id_context = 1;
|
||||||
|
|
||||||
/*! Get restconf native handle
|
/*! Get restconf native handle
|
||||||
* @param[in] h Clicon handle
|
* @param[in] h Clicon handle
|
||||||
* @retval rh Restconf native handle
|
* @retval rh Restconf native handle
|
||||||
|
|
@ -740,8 +742,67 @@ restconf_verify_certs(int preverify_ok,
|
||||||
return preverify_ok;
|
return preverify_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int session_id_context = 1;
|
/*! Debug print of all incoming alpn alternatives, eg h2 and http/1.1
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
dump_alpn_proto_list(const unsigned char *in,
|
||||||
|
unsigned int inlen)
|
||||||
|
{
|
||||||
|
unsigned char *inp;
|
||||||
|
unsigned char len;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
inp = (unsigned char*)in;
|
||||||
|
while ((len = *inp) != 0) {
|
||||||
|
inp++;
|
||||||
|
if ((str = malloc(len+1)) == NULL){
|
||||||
|
clicon_err(OE_UNIX, errno, "malloc");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strncpy(str, (const char*)inp, len);
|
||||||
|
str[len] = '\0';
|
||||||
|
clicon_debug(1, "%s %s", __FUNCTION__, str);
|
||||||
|
free(str);
|
||||||
|
inp += len;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Application-layer Protocol Negotiation (alpn) callback
|
||||||
|
* The value of the out, outlen vector should be set to the value of a single protocol selected from
|
||||||
|
* the in, inlen vector. The out buffer may point directly into in, or to a buffer that outlives the
|
||||||
|
* handshake.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
alpn_select_proto_cb(SSL *ssl,
|
||||||
|
const unsigned char **out,
|
||||||
|
unsigned char *outlen,
|
||||||
|
const unsigned char *in,
|
||||||
|
unsigned int inlen,
|
||||||
|
void *arg)
|
||||||
|
{
|
||||||
|
unsigned char *inp;
|
||||||
|
unsigned char len;
|
||||||
|
|
||||||
|
if (clicon_debug_get())
|
||||||
|
dump_alpn_proto_list(in, inlen);
|
||||||
|
inp = (unsigned char*)in;
|
||||||
|
/* select http/1.1 */
|
||||||
|
inp = (unsigned char*)in;
|
||||||
|
while ((len = *inp) != 0) {
|
||||||
|
inp++;
|
||||||
|
if (len == 8 && strncmp((char*)inp, "http/1.1", len) == 0)
|
||||||
|
// if (len == 2 && strncmp((char*)inp, "h2", len) == 0)
|
||||||
|
break;
|
||||||
|
inp += len;
|
||||||
|
}
|
||||||
|
if (len == 0)
|
||||||
|
return SSL_TLSEXT_ERR_NOACK;
|
||||||
|
*outlen = len;
|
||||||
|
*out = inp;
|
||||||
|
return SSL_TLSEXT_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* see restconf_config ->cv_evhtp_init(x2) -> cx_evhtp_socket ->
|
* see restconf_config ->cv_evhtp_init(x2) -> cx_evhtp_socket ->
|
||||||
* evhtp_ssl_init:4794
|
* evhtp_ssl_init:4794
|
||||||
|
|
@ -768,6 +829,8 @@ restconf_ssl_context_create(clicon_handle h)
|
||||||
|
|
||||||
SSL_CTX_set_options(ctx, SSL_MODE_RELEASE_BUFFERS | SSL_OP_NO_COMPRESSION);
|
SSL_CTX_set_options(ctx, SSL_MODE_RELEASE_BUFFERS | SSL_OP_NO_COMPRESSION);
|
||||||
// SSL_CTX_set_timeout(ctx, cfg->ssl_ctx_timeout); /* default 300s */
|
// SSL_CTX_set_timeout(ctx, cfg->ssl_ctx_timeout); /* default 300s */
|
||||||
|
/* Application Layer Protocol Negotiation (alpn) callback */
|
||||||
|
SSL_CTX_set_alpn_select_cb(ctx, alpn_select_proto_cb, h);
|
||||||
done:
|
done:
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
@ -1145,6 +1208,8 @@ restconf_accept_client(int fd,
|
||||||
int er;
|
int er;
|
||||||
int readmore;
|
int readmore;
|
||||||
X509 *peercert;
|
X509 *peercert;
|
||||||
|
const unsigned char *alpn = NULL;
|
||||||
|
unsigned int alpnlen = 0;
|
||||||
|
|
||||||
clicon_debug(1, "%s %d", __FUNCTION__, fd);
|
clicon_debug(1, "%s %d", __FUNCTION__, fd);
|
||||||
if (rsock == NULL){
|
if (rsock == NULL){
|
||||||
|
|
@ -1293,6 +1358,17 @@ restconf_accept_client(int fd,
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Sets data and len to point to the client's requested protocol for this connection. */
|
||||||
|
SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
|
||||||
|
if (alpn == NULL) {
|
||||||
|
/* Returns a pointer to the selected protocol in data with length len. */
|
||||||
|
SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
|
||||||
|
}
|
||||||
|
clicon_debug(1, "%s ALPN: %d %s", __FUNCTION__, alpnlen, alpn);
|
||||||
|
if (alpn == NULL || alpnlen != 8 || memcmp("http/1.1", alpn, 8) != 0) {
|
||||||
|
clicon_err(OE_RESTCONF, 0, "Protocol http/1.1 not selected: %s", alpn);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
/* Get the actual peer, XXX this maybe could be done in ca-auth client-cert code ?
|
/* Get the actual peer, XXX this maybe could be done in ca-auth client-cert code ?
|
||||||
* Note this _only_ works if SSL_set1_host() was set previously,...
|
* Note this _only_ works if SSL_set1_host() was set previously,...
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,24 @@ function testrun()
|
||||||
new "restconf root discovery. RFC 8040 3.1 (xml+xrd)"
|
new "restconf root discovery. RFC 8040 3.1 (xml+xrd)"
|
||||||
expectpart "$(curl $CURLOPTS -X GET $proto://$addr/.well-known/host-meta)" 0 'HTTP/1.1 200 OK' "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>" "<Link rel='restconf' href='/restconf'/>" "</XRD>"
|
expectpart "$(curl $CURLOPTS -X GET $proto://$addr/.well-known/host-meta)" 0 'HTTP/1.1 200 OK' "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>" "<Link rel='restconf' href='/restconf'/>" "</XRD>"
|
||||||
|
|
||||||
|
if [ "${WITH_RESTCONF}" = "native" ]; then # XXX does not work with nginx
|
||||||
|
new "restconf GET http/1.0 - returns 1.0"
|
||||||
|
expectpart "$(curl $CURLOPTS --http1.0 -X GET $proto://$addr/.well-known/host-meta)" 0 'HTTP/1.0 200 OK' "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>" "<Link rel='restconf' href='/restconf'/>" "</XRD>"
|
||||||
|
fi
|
||||||
|
new "restconf GET http/1.1"
|
||||||
|
expectpart "$(curl $CURLOPTS --http1.1 -X GET $proto://$addr/.well-known/host-meta)" 0 'HTTP/1.1 200 OK' "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>" "<Link rel='restconf' href='/restconf'/>" "</XRD>"
|
||||||
|
|
||||||
|
new "restconf GET http/2"
|
||||||
|
expectpart "$(curl $CURLOPTS --http2 -X GET $proto://$addr/.well-known/host-meta)" 0 'HTTP/1.1 200 OK' "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>" "<Link rel='restconf' href='/restconf'/>" "</XRD>"
|
||||||
|
|
||||||
|
if [ $proto = http ]; then # see (2) https to http port in restconf_main_native.c
|
||||||
|
new "restconf GET http/2 prior-knowledge (http)"
|
||||||
|
expectpart "$(curl $CURLOPTS --http2-prior-knowledge -X GET $proto://$addr/.well-known/host-meta 2>&1)" "16 55" # "Error in the HTTP2 framing layer" "Connection reset by peer"
|
||||||
|
else
|
||||||
|
new "restconf GET http/2 prior-knowledge (https)"
|
||||||
|
expectpart "$(curl $CURLOPTS --http2-prior-knowledge -X GET $proto://$addr/.well-known/host-meta)" 0 'HTTP/1.1 200 OK' "<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>" "<Link rel='restconf' href='/restconf'/>" "</XRD>"
|
||||||
|
fi
|
||||||
|
|
||||||
# Negative test GET datastore
|
# Negative test GET datastore
|
||||||
if [ $proto = http ]; then # see (2) https to http port in restconf_main_native.c
|
if [ $proto = http ]; then # see (2) https to http port in restconf_main_native.c
|
||||||
new "Wrong proto=https on http port, expect err 35 wrong version number"
|
new "Wrong proto=https on http port, expect err 35 wrong version number"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue