Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Raw Public Key support (RFC 7250) WIP #172

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ SET(MINICRYPTO_LIBRARY_FILES

ADD_LIBRARY(picotls-core lib/picotls.c lib/pembase64.c)
ADD_LIBRARY(picotls-minicrypto ${MINICRYPTO_LIBRARY_FILES} lib/cifra.c lib/minicrypto-pem.c lib/uecc.c lib/asn1.c)
ADD_EXECUTABLE(cli-minicrypto t/cli-minicrypto.c lib/pembase64.c)
TARGET_LINK_LIBRARIES(cli-minicrypto picotls-minicrypto picotls-core)
ADD_EXECUTABLE(test-minicrypto.t ${MINICRYPTO_LIBRARY_FILES} deps/picotest/picotest.c t/picotls.c t/minicrypto.c lib/asn1.c lib/pembase64.c)

SET(TEST_EXES test-minicrypto.t)
Expand All @@ -34,8 +36,8 @@ IF (OPENSSL_FOUND AND NOT (OPENSSL_VERSION VERSION_LESS "1.0.1"))
MESSAGE(WARNING "Enabling OpenSSL support")
INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
ADD_LIBRARY(picotls-openssl lib/openssl.c)
ADD_EXECUTABLE(cli t/cli.c lib/pembase64.c)
TARGET_LINK_LIBRARIES(cli picotls-openssl picotls-core ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS})
ADD_EXECUTABLE(cli-openssl t/cli-openssl.c lib/pembase64.c)
TARGET_LINK_LIBRARIES(cli-openssl picotls-openssl picotls-core ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS})
ADD_EXECUTABLE(test-openssl.t ${MINICRYPTO_LIBRARY_FILES} lib/cifra.c lib/uecc.c lib/asn1.c lib/pembase64.c deps/picotest/picotest.c t/picotls.c t/openssl.c)
SET_TARGET_PROPERTIES(test-openssl.t PROPERTIES COMPILE_FLAGS "-DPTLS_MEMORY_DEBUG=1")
TARGET_LINK_LIBRARIES(test-openssl.t ${OPENSSL_LIBRARIES} ${CMAKE_DL_LIBS})
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,25 +49,25 @@ Using the cli command

Run the test server (at 127.0.0.1:8443):
```
% ./cli -c /path/to/certificate.pem -k /path/to/private-key.pem 127.0.0.1 8443
% ./cli-openssl -c /path/to/certificate.pem -k /path/to/private-key.pem 127.0.0.1 8443
```

Connect to the test server:
```
% ./cli 127.0.0.1 8443
% ./cli-openssl 127.0.0.1 8443
```

Using resumption:
```
% ./cli -s session-file 127.0.0.1 8443
% ./cli-openssl -s session-file 127.0.0.1 8443
```
The session-file is read-write.
The cli server implements a single-entry session cache.
The cli server sends NewSessionTicket when it first sends application data after receiving ClientFinished.

Using early-data:
```
% ./cli -s session-file -e 127.0.0.1 8443
% ./cli-openssl -s session-file -e 127.0.0.1 8443
```
When `-e` option is used, client first waits for user input, and then sends CLIENT_HELLO along with the early-data.

Expand Down
6 changes: 6 additions & 0 deletions include/picotls.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ extern "C" {
#define PTLS_ALERT_BAD_RECORD_MAC 20
#define PTLS_ALERT_HANDSHAKE_FAILURE 40
#define PTLS_ALERT_BAD_CERTIFICATE 42
#define PTLS_ALERT_UNSUPPORTED_CERTIFICATE 43
#define PTLS_ALERT_CERTIFICATE_REVOKED 44
#define PTLS_ALERT_CERTIFICATE_EXPIRED 45
#define PTLS_ALERT_CERTIFICATE_UNKNOWN 46
Expand Down Expand Up @@ -466,6 +467,11 @@ struct st_ptls_context_t {
* to authenticate the client.
*/
unsigned require_client_authentication : 1;
/*
* Ask for Raw Public Key instead of x509 certificate (RFC 7250)
*/
unsigned server_raw_public_key : 1;
unsigned client_raw_public_key : 1;
/**
*
*/
Expand Down
4 changes: 2 additions & 2 deletions lib/minicrypto-pem.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,10 +299,10 @@ static int ptls_set_ecdsa_private_key(ptls_context_t *ctx, ptls_asn1_pkcs8_priva

if (log_ctx != NULL) {
/* print the OID value */
log_ctx->fn(log_ctx->ctx, "Initialized SECP512R1 signing key with %d bytes.\n", ecdsa_key_data_length);
log_ctx->fn(log_ctx->ctx, "Initialized SECP256R1 signing key with %d bytes.\n", ecdsa_key_data_length);
}
} else if (log_ctx != NULL) {
log_ctx->fn(log_ctx->ctx, "SECP512R1 init with %d bytes returns %d.\n", ecdsa_key_data_length, decode_error);
log_ctx->fn(log_ctx->ctx, "SECP256R1 init with %d bytes returns %d.\n", ecdsa_key_data_length, decode_error);
}
}
} else {
Expand Down
3 changes: 3 additions & 0 deletions lib/pembase64.c
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,9 @@ int ptls_load_certificates(ptls_context_t *ctx, char const *cert_pem_file)
} else {
ret = ptls_load_pem_objects(cert_pem_file, "CERTIFICATE", ctx->certificates.list, PTLS_MAX_CERTS_IN_CONTEXT,
&ctx->certificates.count);
if (ret != 0)
ret = ptls_load_pem_objects(cert_pem_file, "PUBLIC KEY", ctx->certificates.list, PTLS_MAX_CERTS_IN_CONTEXT,
&ctx->certificates.count);
}

return ret;
Expand Down
107 changes: 105 additions & 2 deletions lib/picotls.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@
#define PTLS_HANDSHAKE_TYPE_KEY_UPDATE 24
#define PTLS_HANDSHAKE_TYPE_MESSAGE_HASH 254

/* 4.4.2 */
#define PTLS_CERTIFICATE_TYPE_X509 0
#define PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY 2

#define PTLS_PSK_KE_MODE_PSK 0
#define PTLS_PSK_KE_MODE_PSK_DHE 1

Expand All @@ -66,6 +70,8 @@
#define PTLS_EXTENSION_TYPE_SUPPORTED_GROUPS 10
#define PTLS_EXTENSION_TYPE_SIGNATURE_ALGORITHMS 13
#define PTLS_EXTENSION_TYPE_ALPN 16
#define PTLS_EXTENSION_TYPE_CLIENT_CERTIFICATE_TYPE 19
#define PTLS_EXTENSION_TYPE_SERVER_CERTIFICATE_TYPE 20
#define PTLS_EXTENSION_TYPE_PRE_SHARED_KEY 41
#define PTLS_EXTENSION_TYPE_EARLY_DATA 42
#define PTLS_EXTENSION_TYPE_SUPPORTED_VERSIONS 43
Expand Down Expand Up @@ -217,6 +223,11 @@ struct st_ptls_t {
unsigned is_psk_handshake : 1;
unsigned skip_early_data : 1; /* if early-data is not recognized by the server */
unsigned send_change_cipher_spec : 1;
/* RFC 7250 */
uint8_t client_certificate_types; /* bit field as should have been all along */
uint8_t server_certificate_types; /* bit field as should have been all along */
uint8_t client_certificate_type;
uint8_t server_certificate_type;
/**
* exporter master secret (either 0rtt or 1rtt)
*/
Expand Down Expand Up @@ -1538,6 +1549,22 @@ static int send_client_hello(ptls_t *tls, struct st_ptls_message_emitter_t *emit
}
});
});
/* RFC 7250 RawPublicKey
* TODO make sure all every ptls_key_exchange_algorithm_t implements RawPublicKey
* as per https://tools.ietf.org/html/rfc7250#section-4.1 P 5 and 6
* TODO allow accepting both RAW_PUBLIC_KEY and X509, and then extracting the public key from the certificate
* ptls_buffer_push(sendbuf, 2, PTLS_CERTIFICATE_TYPE_X509, PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY);
*/
if (tls->ctx->client_raw_public_key) {
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_CLIENT_CERTIFICATE_TYPE, {
ptls_buffer_push(sendbuf, 1, PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY);
});
}
if (tls->ctx->server_raw_public_key) {
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_SERVER_CERTIFICATE_TYPE, {
ptls_buffer_push(sendbuf, 1, PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY);
});
}
if (cookie != NULL && cookie->base != NULL) {
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_COOKIE, {
ptls_buffer_push_block(sendbuf, 2, { ptls_buffer_pushv(sendbuf, cookie->base, cookie->len); });
Expand Down Expand Up @@ -1730,12 +1757,43 @@ static int decode_server_hello(ptls_t *tls, struct st_ptls_server_hello_t *sh, c
goto Exit;
}
break;
default:
case PTLS_EXTENSION_TYPE_CLIENT_CERTIFICATE_TYPE:
case PTLS_EXTENSION_TYPE_SERVER_CERTIFICATE_TYPE: {
if (src == end) {
ret = PTLS_ALERT_DECODE_ERROR;
goto Exit;
}
uint8_t certificate_type = *src++;
if (certificate_type > PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY ||
certificate_type == 1/* OpenSSH, forbidden by TLS 1.3 */) {
ret = PTLS_ALERT_UNSUPPORTED_CERTIFICATE;
goto Exit;
}
switch (exttype) {
case PTLS_EXTENSION_TYPE_CLIENT_CERTIFICATE_TYPE:
tls->client_certificate_type = certificate_type;
break;
case PTLS_EXTENSION_TYPE_SERVER_CERTIFICATE_TYPE:
tls->server_certificate_type = certificate_type;
break;
default:
break;
}
break;
} default:
src = end;
break;
}
});

if (((tls->client_certificate_type == PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY) !=
tls->ctx->client_raw_public_key) || /* TODO handle this case by extracting public key from client certificate */
((tls->server_certificate_type == PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY) !=
tls->ctx->server_raw_public_key)) {
ret = PTLS_ALERT_UNSUPPORTED_CERTIFICATE;
goto Exit;
}

if (!is_supported_version(found_version)) {
ret = PTLS_ALERT_ILLEGAL_PARAMETER;
goto Exit;
Expand Down Expand Up @@ -2612,13 +2670,50 @@ static int decode_client_hello(ptls_t *tls, struct st_ptls_client_hello_t *ch, c
case PTLS_EXTENSION_TYPE_STATUS_REQUEST:
ch->status_request = 1;
break;
default:
case PTLS_EXTENSION_TYPE_CLIENT_CERTIFICATE_TYPE:
case PTLS_EXTENSION_TYPE_SERVER_CERTIFICATE_TYPE: {
if (src == end) {
ret = PTLS_ALERT_DECODE_ERROR;
goto Exit;
}
uint8_t length = *src++;
if (end - src != length) {
ret = PTLS_ALERT_DECODE_ERROR;
goto Exit;
}
for (;src != end; ++src) {
uint8_t certificate_type = *src;
if (certificate_type > PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY ||
certificate_type == 1/* OpenSSH, forbidden by TLS 1.3 */) {
ret = PTLS_ALERT_UNSUPPORTED_CERTIFICATE;
goto Exit;
}
if (exttype == PTLS_EXTENSION_TYPE_CLIENT_CERTIFICATE_TYPE) {
tls->client_certificate_types |= (1 << certificate_type);
} else if (exttype == PTLS_EXTENSION_TYPE_SERVER_CERTIFICATE_TYPE) {
tls->server_certificate_types |= (1 << certificate_type);
}
}
break;
} default:
handle_unknown_extension(tls, properties, exttype, src, end, ch->unknown_extensions);
break;
}
src = end;
});

if ((tls->client_certificate_types & (1 << PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY)) &&
!tls->ctx->client_raw_public_key ) {
ret = PTLS_ALERT_UNSUPPORTED_CERTIFICATE;
goto Exit;
}
/* TODO handle this case by extracting public key from certificate */
if ((tls->server_certificate_types & (1 << PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY) &&
!tls->ctx->server_raw_public_key)) {
ret = PTLS_ALERT_UNSUPPORTED_CERTIFICATE;
goto Exit;
}

/* check if client hello make sense */
if (is_supported_version(ch->selected_version)) {
if (!(ch->compression_methods.count == 1 && ch->compression_methods.ids[0] == 0)) {
Expand Down Expand Up @@ -3072,6 +3167,14 @@ static int server_handle_hello(ptls_t *tls, struct st_ptls_message_emitter_t *em
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_PRE_SHARED_KEY,
{ ptls_buffer_push16(sendbuf, (uint16_t)psk_index); });
}
if (tls->ctx->server_raw_public_key)
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_SERVER_CERTIFICATE_TYPE, {
ptls_buffer_push(sendbuf, PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY);
});
if (tls->ctx->client_raw_public_key)
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_CLIENT_CERTIFICATE_TYPE, {
ptls_buffer_push(sendbuf, PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY);
});
});
if ((ret = push_change_cipher_spec(tls, emitter->buf)) != 0)
goto Exit;
Expand Down
Loading