Skip to content

Commit bd883b4

Browse files
committed
core: basic RawPublicKey support (RFC 7250)
1 parent 99351f0 commit bd883b4

File tree

4 files changed

+123
-3
lines changed

4 files changed

+123
-3
lines changed

include/picotls.h

+6
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ extern "C" {
9292
#define PTLS_ALERT_BAD_RECORD_MAC 20
9393
#define PTLS_ALERT_HANDSHAKE_FAILURE 40
9494
#define PTLS_ALERT_BAD_CERTIFICATE 42
95+
#define PTLS_ALERT_UNSUPPORTED_CERTIFICATE 43
9596
#define PTLS_ALERT_CERTIFICATE_REVOKED 44
9697
#define PTLS_ALERT_CERTIFICATE_EXPIRED 45
9798
#define PTLS_ALERT_CERTIFICATE_UNKNOWN 46
@@ -466,6 +467,11 @@ struct st_ptls_context_t {
466467
* to authenticate the client.
467468
*/
468469
unsigned require_client_authentication : 1;
470+
/*
471+
* As for Raw Public Key instead of x509 certificate
472+
*/
473+
unsigned server_raw_public_key : 1;
474+
unsigned client_raw_public_key : 1;
469475
/**
470476
*
471477
*/

lib/pembase64.c

+3
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,9 @@ int ptls_load_certificates(ptls_context_t *ctx, char const *cert_pem_file)
367367
} else {
368368
ret = ptls_load_pem_objects(cert_pem_file, "CERTIFICATE", ctx->certificates.list, PTLS_MAX_CERTS_IN_CONTEXT,
369369
&ctx->certificates.count);
370+
if (ret != 0)
371+
ret = ptls_load_pem_objects(cert_pem_file, "PUBLIC KEY", ctx->certificates.list, PTLS_MAX_CERTS_IN_CONTEXT,
372+
&ctx->certificates.count);
370373
}
371374

372375
return ret;

lib/picotls.c

+107-2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@
5656
#define PTLS_HANDSHAKE_TYPE_KEY_UPDATE 24
5757
#define PTLS_HANDSHAKE_TYPE_MESSAGE_HASH 254
5858

59+
/* 4.4.2 */
60+
#define PTLS_CERTIFICATE_TYPE_X509 0
61+
#define PTLS_CERTIFICATE_TYPE_X509_BIT 1 << PTLS_CERTIFICATE_TYPE_X509
62+
#define PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY 2
63+
#define PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY_BIT 1 << PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY
64+
5965
#define PTLS_PSK_KE_MODE_PSK 0
6066
#define PTLS_PSK_KE_MODE_PSK_DHE 1
6167

@@ -66,6 +72,8 @@
6672
#define PTLS_EXTENSION_TYPE_SUPPORTED_GROUPS 10
6773
#define PTLS_EXTENSION_TYPE_SIGNATURE_ALGORITHMS 13
6874
#define PTLS_EXTENSION_TYPE_ALPN 16
75+
#define PTLS_EXTENSION_TYPE_CLIENT_CERTIFICATE_TYPE 19
76+
#define PTLS_EXTENSION_TYPE_SERVER_CERTIFICATE_TYPE 20
6977
#define PTLS_EXTENSION_TYPE_PRE_SHARED_KEY 41
7078
#define PTLS_EXTENSION_TYPE_EARLY_DATA 42
7179
#define PTLS_EXTENSION_TYPE_SUPPORTED_VERSIONS 43
@@ -217,6 +225,11 @@ struct st_ptls_t {
217225
unsigned is_psk_handshake : 1;
218226
unsigned skip_early_data : 1; /* if early-data is not recognized by the server */
219227
unsigned send_change_cipher_spec : 1;
228+
/* RFC 7250 */
229+
uint8_t client_certificate_types; /* bit field as should have been all along */
230+
uint8_t server_certificate_types; /* bit field as should have been all along */
231+
uint8_t client_certificate_type;
232+
uint8_t server_certificate_type;
220233
/**
221234
* exporter master secret (either 0rtt or 1rtt)
222235
*/
@@ -1538,6 +1551,22 @@ static int send_client_hello(ptls_t *tls, struct st_ptls_message_emitter_t *emit
15381551
}
15391552
});
15401553
});
1554+
/* RFC 7250 RawPublicKey
1555+
* TODO make sure all every ptls_key_exchange_algorithm_t implements RawPublicKey
1556+
* as per https://tools.ietf.org/html/rfc7250#section-4.1 P 5 and 6
1557+
* TODO allow accepting both RAW_PUBLIC_KEY and X509, and then extracting the public key from the certificate
1558+
* ptls_buffer_push(sendbuf, 2, PTLS_CERTIFICATE_TYPE_X509, PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY);
1559+
*/
1560+
if (tls->ctx->client_raw_public_key) {
1561+
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_CLIENT_CERTIFICATE_TYPE, {
1562+
ptls_buffer_push(sendbuf, 1, PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY);
1563+
});
1564+
}
1565+
if (tls->ctx->server_raw_public_key) {
1566+
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_SERVER_CERTIFICATE_TYPE, {
1567+
ptls_buffer_push(sendbuf, 1, PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY);
1568+
});
1569+
}
15411570
if (cookie != NULL && cookie->base != NULL) {
15421571
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_COOKIE, {
15431572
ptls_buffer_push_block(sendbuf, 2, { ptls_buffer_pushv(sendbuf, cookie->base, cookie->len); });
@@ -1730,12 +1759,43 @@ static int decode_server_hello(ptls_t *tls, struct st_ptls_server_hello_t *sh, c
17301759
goto Exit;
17311760
}
17321761
break;
1733-
default:
1762+
case PTLS_EXTENSION_TYPE_CLIENT_CERTIFICATE_TYPE:
1763+
case PTLS_EXTENSION_TYPE_SERVER_CERTIFICATE_TYPE: {
1764+
if (src == end) {
1765+
ret = PTLS_ALERT_DECODE_ERROR;
1766+
goto Exit;
1767+
}
1768+
uint8_t certificate_type = *src++;
1769+
if (certificate_type > PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY ||
1770+
certificate_type == 1/* OpenSSH, forbidden by TLS 1.3 */) {
1771+
ret = PTLS_ALERT_UNSUPPORTED_CERTIFICATE;
1772+
goto Exit;
1773+
}
1774+
switch (exttype) {
1775+
case PTLS_EXTENSION_TYPE_CLIENT_CERTIFICATE_TYPE:
1776+
tls->client_certificate_type = certificate_type;
1777+
break;
1778+
case PTLS_EXTENSION_TYPE_SERVER_CERTIFICATE_TYPE:
1779+
tls->server_certificate_type = certificate_type;
1780+
break;
1781+
default:
1782+
break;
1783+
}
1784+
break;
1785+
} default:
17341786
src = end;
17351787
break;
17361788
}
17371789
});
17381790

1791+
if (((tls->client_certificate_type == PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY) !=
1792+
tls->ctx->client_raw_public_key) || /* TODO handle this case by extracting public key from client certificate */
1793+
((tls->server_certificate_type == PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY) !=
1794+
tls->ctx->server_raw_public_key)) {
1795+
ret = PTLS_ALERT_UNSUPPORTED_CERTIFICATE;
1796+
goto Exit;
1797+
}
1798+
17391799
if (!is_supported_version(found_version)) {
17401800
ret = PTLS_ALERT_ILLEGAL_PARAMETER;
17411801
goto Exit;
@@ -2612,13 +2672,50 @@ static int decode_client_hello(ptls_t *tls, struct st_ptls_client_hello_t *ch, c
26122672
case PTLS_EXTENSION_TYPE_STATUS_REQUEST:
26132673
ch->status_request = 1;
26142674
break;
2615-
default:
2675+
case PTLS_EXTENSION_TYPE_CLIENT_CERTIFICATE_TYPE:
2676+
case PTLS_EXTENSION_TYPE_SERVER_CERTIFICATE_TYPE: {
2677+
if (src == end) {
2678+
ret = PTLS_ALERT_DECODE_ERROR;
2679+
goto Exit;
2680+
}
2681+
uint8_t length = *src++;
2682+
if (end - src != length) {
2683+
ret = PTLS_ALERT_DECODE_ERROR;
2684+
goto Exit;
2685+
}
2686+
for (;src != end; ++src) {
2687+
uint8_t certificate_type = *src;
2688+
if (certificate_type > PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY ||
2689+
certificate_type == 1/* OpenSSH, forbidden by TLS 1.3 */) {
2690+
ret = PTLS_ALERT_UNSUPPORTED_CERTIFICATE;
2691+
goto Exit;
2692+
}
2693+
if (exttype == PTLS_EXTENSION_TYPE_CLIENT_CERTIFICATE_TYPE) {
2694+
tls->client_certificate_types |= (1 << certificate_type);
2695+
} else if (exttype == PTLS_EXTENSION_TYPE_SERVER_CERTIFICATE_TYPE) {
2696+
tls->server_certificate_types |= (1 << certificate_type);
2697+
}
2698+
}
2699+
break;
2700+
} default:
26162701
handle_unknown_extension(tls, properties, exttype, src, end, ch->unknown_extensions);
26172702
break;
26182703
}
26192704
src = end;
26202705
});
26212706

2707+
if ((tls->client_certificate_types & PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY_BIT) &&
2708+
!tls->ctx->client_raw_public_key ) {
2709+
ret = PTLS_ALERT_UNSUPPORTED_CERTIFICATE;
2710+
goto Exit;
2711+
}
2712+
/* TODO handle this case by extracting public key from certificate */
2713+
if ((tls->server_certificate_types & PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY_BIT) &&
2714+
!tls->ctx->server_raw_public_key) {
2715+
ret = PTLS_ALERT_UNSUPPORTED_CERTIFICATE;
2716+
goto Exit;
2717+
}
2718+
26222719
/* check if client hello make sense */
26232720
if (is_supported_version(ch->selected_version)) {
26242721
if (!(ch->compression_methods.count == 1 && ch->compression_methods.ids[0] == 0)) {
@@ -3072,6 +3169,14 @@ static int server_handle_hello(ptls_t *tls, struct st_ptls_message_emitter_t *em
30723169
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_PRE_SHARED_KEY,
30733170
{ ptls_buffer_push16(sendbuf, (uint16_t)psk_index); });
30743171
}
3172+
if (tls->ctx->server_raw_public_key)
3173+
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_SERVER_CERTIFICATE_TYPE, {
3174+
ptls_buffer_push(sendbuf, PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY);
3175+
});
3176+
if (tls->ctx->client_raw_public_key)
3177+
buffer_push_extension(sendbuf, PTLS_EXTENSION_TYPE_CLIENT_CERTIFICATE_TYPE, {
3178+
ptls_buffer_push(sendbuf, PTLS_CERTIFICATE_TYPE_RAW_PUBLIC_KEY);
3179+
});
30753180
});
30763181
if ((ret = push_change_cipher_spec(tls, emitter->buf)) != 0)
30773182
goto Exit;

t/cli-minicrypto.c

+7-1
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ int main(int argc, char **argv)
317317
socklen_t salen;
318318
int family = 0;
319319

320-
while ((ch = getopt(argc, argv, "46aC:c:i:k:nN:es:Sl:vh:jJ")) != -1) {
320+
while ((ch = getopt(argc, argv, "46aC:c:i:k:nN:es:Sl:vh:jJrR")) != -1) {
321321
switch (ch) {
322322
case '4':
323323
family = AF_INET;
@@ -337,6 +337,12 @@ int main(int argc, char **argv)
337337
load_certificate_chain(&ctx, optarg);
338338
is_server = ch == 'c';
339339
break;
340+
case 'r':
341+
ctx.server_raw_public_key = 1;
342+
break;
343+
case 'R':
344+
ctx.client_raw_public_key = 1;
345+
break;
340346
case 'i':
341347
file = optarg;
342348
break;

0 commit comments

Comments
 (0)