Skip to content

Commit 9de892c

Browse files
authored
Merge pull request #517 from h2o/kazuho/pr501
MbedTLS sign certificate
2 parents 8b52beb + cc88d42 commit 9de892c

File tree

4 files changed

+183
-7
lines changed

4 files changed

+183
-7
lines changed

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ IF (WITH_MBEDTLS)
204204
message(STATUS "mbedtls/include: ${MBEDTLS_INCLUDE_DIRS}")
205205
message(STATUS "mbedtls libraries: ${MBEDTLS_LIBRARIES}")
206206
INCLUDE_DIRECTORIES(${MBEDTLS_INCLUDE_DIRS})
207-
ADD_LIBRARY(picotls-mbedtls lib/mbedtls.c)
207+
ADD_LIBRARY(picotls-mbedtls lib/mbedtls.c lib/mbedtls_sign.c)
208208
ADD_EXECUTABLE(test-mbedtls.t
209209
deps/picotest/picotest.c
210210
${CORE_TEST_FILES}

include/picotls/mbedtls.h

+3
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ extern ptls_key_exchange_algorithm_t *ptls_mbedtls_key_exchanges[];
6060

6161
void ptls_mbedtls_random_bytes(void *buf, size_t len);
6262

63+
int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname);
64+
void ptls_mbedtls_dispose_sign_certificate(ptls_sign_certificate_t *_self);
65+
6366
#ifdef __cplusplus
6467
}
6568
#endif

lib/mbedtls_sign.c

+9-6
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
#include <psa/crypto.h>
3737
#include <psa/crypto_struct.h>
3838
#include <psa/crypto_values.h>
39-
#include "ptls_mbedtls.h"
39+
/* #include "ptls_mbedtls.h" */
4040

4141
typedef struct st_ptls_mbedtls_signature_scheme_t {
4242
uint16_t scheme_id;
@@ -58,6 +58,7 @@ static const ptls_mbedtls_signature_scheme_t rsa_signature_schemes[] = {{PTLS_SI
5858
{PTLS_SIGNATURE_RSA_PSS_RSAE_SHA384, PSA_ALG_SHA_384},
5959
{PTLS_SIGNATURE_RSA_PSS_RSAE_SHA512, PSA_ALG_SHA_512},
6060
{UINT16_MAX, PSA_ALG_NONE}};
61+
6162
static const ptls_mbedtls_signature_scheme_t secp256r1_signature_schemes[] = {
6263
{PTLS_SIGNATURE_ECDSA_SECP256R1_SHA256, PSA_ALG_SHA_256}, {UINT16_MAX, PSA_ALG_NONE}};
6364
static const ptls_mbedtls_signature_scheme_t secp384r1_signature_schemes[] = {
@@ -69,6 +70,8 @@ static const ptls_mbedtls_signature_scheme_t ed25519_signature_schemes[] = {{PTL
6970

7071
#if defined(MBEDTLS_PEM_PARSE_C)
7172

73+
/* Mapping of MBEDTLS APIs to Picotls */
74+
7275
static int ptls_mbedtls_parse_der_length(const unsigned char *pem_buf, size_t pem_len, size_t *px, size_t *pl)
7376
{
7477
int ret = 0;
@@ -94,8 +97,6 @@ static int ptls_mbedtls_parse_der_length(const unsigned char *pem_buf, size_t pe
9497
static int ptls_mbedtls_parse_ecdsa_field(const unsigned char *pem_buf, size_t pem_len, size_t *key_index, size_t *key_length)
9598
{
9699
int ret = 0;
97-
int param_index_index = -1;
98-
int param_length = 0;
99100
size_t x = 0;
100101

101102
// const unsigned char head = { 0x30, l-2, 0x02, 0x01, 0x01, 0x04 }
@@ -166,6 +167,7 @@ static int ptls_mbedtls_parse_eddsa_key(const unsigned char *pem_buf, size_t pem
166167
if (x + l_key != *key_index + *key_length) {
167168
ret = -1;
168169
} else {
170+
169171
*key_index = x;
170172
*key_length = l_key;
171173
}
@@ -241,7 +243,6 @@ int test_parse_private_key_field(const unsigned char *pem_buf, size_t pem_len, s
241243
/* At that point the oid has been identified.
242244
* The next parameter is an octet string containing the key info.
243245
*/
244-
size_t l = 0;
245246
if (x + 2 > pem_len || pem_buf[x++] != 0x04) {
246247
ret = -1;
247248
} else {
@@ -292,6 +293,7 @@ int ptls_mbedtls_get_der_key(mbedtls_pem_context *pem, mbedtls_pk_type_t *pk_typ
292293
} else if (ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED) {
293294
return MBEDTLS_ERR_PK_PASSWORD_REQUIRED;
294295
} else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
296+
295297
return ret;
296298
}
297299
#endif /* MBEDTLS_RSA_C */
@@ -352,6 +354,7 @@ const ptls_mbedtls_signature_scheme_t *ptls_mbedtls_select_signature_scheme(cons
352354
const uint16_t *algorithms, size_t num_algorithms)
353355
{
354356
const ptls_mbedtls_signature_scheme_t *scheme;
357+
355358
/* select the algorithm, driven by server-isde preference of `available` */
356359
for (scheme = available; scheme->scheme_id != UINT16_MAX; ++scheme) {
357360
for (size_t i = 0; i != num_algorithms; ++i) {
@@ -446,6 +449,7 @@ int ptls_mbedtls_sign_certificate(ptls_sign_certificate_t *_self, ptls_t *tls, p
446449
/* First prepare the hash */
447450
unsigned char hash_buffer[PTLS_MAX_DIGEST_SIZE];
448451
unsigned char *hash_value = NULL;
452+
449453
size_t hash_length = 0;
450454

451455
if (scheme->hash_algo == PSA_ALG_NONE) {
@@ -476,7 +480,6 @@ int ptls_mbedtls_sign_certificate(ptls_sign_certificate_t *_self, ptls_t *tls, p
476480
}
477481
if ((ret = ptls_buffer_reserve(outbuf, nb_bytes)) == 0) {
478482
size_t signature_length = 0;
479-
480483
if (psa_sign_hash(self->key_id, sign_algo, hash_value, hash_length, outbuf->base + outbuf->off, nb_bytes,
481484
&signature_length) != 0) {
482485
ret = PTLS_ERROR_INCOMPATIBLE_KEY;
@@ -602,7 +605,7 @@ int ptls_mbedtls_load_private_key(ptls_context_t *ctx, char const *pem_fname)
602605
unsigned char *buf;
603606
mbedtls_pem_context pem = {0};
604607
mbedtls_pk_type_t pk_type = 0;
605-
mbedtls_svc_key_id_t key_id = 0;
608+
/* mbedtls_svc_key_id_t key_id = 0; */
606609
size_t key_length = 0;
607610
size_t key_index = 0;
608611
ptls_mbedtls_sign_certificate_t *signer = (ptls_mbedtls_sign_certificate_t *)malloc(sizeof(ptls_mbedtls_sign_certificate_t));

t/mbedtls.c

+170
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,22 @@
3434
#include "../deps/picotest/picotest.h"
3535
#include "test.h"
3636

37+
typedef struct st_ptls_mbedtls_signature_scheme_t {
38+
uint16_t scheme_id;
39+
psa_algorithm_t hash_algo;
40+
} ptls_mbedtls_signature_scheme_t;
41+
42+
typedef struct st_ptls_mbedtls_sign_certificate_t {
43+
ptls_sign_certificate_t super;
44+
mbedtls_svc_key_id_t key_id;
45+
psa_key_attributes_t attributes;
46+
const ptls_mbedtls_signature_scheme_t *schemes;
47+
} ptls_mbedtls_sign_certificate_t;
48+
49+
int ptls_mbedtls_sign_certificate(ptls_sign_certificate_t *_self, ptls_t *tls, ptls_async_job_t **async,
50+
uint16_t *selected_algorithm, ptls_buffer_t *outbuf, ptls_iovec_t input,
51+
const uint16_t *algorithms, size_t num_algorithms);
52+
3753
static int random_trial()
3854
{
3955
/* The random test is just trying to check that we call the API properly.
@@ -89,6 +105,157 @@ static void test_key_exchanges(void)
89105
subtest("x25519", test_x25519);
90106
}
91107

108+
/*
109+
Sign certificate implements a callback:
110+
111+
if ((ret = tls->ctx->sign_certificate->cb(
112+
tls->ctx->sign_certificate, tls, tls->is_server ? &tls->server.async_job : NULL, &algo, sendbuf,
113+
ptls_iovec_init(data, datalen), signature_algorithms != NULL ? signature_algorithms->list : NULL,
114+
signature_algorithms != NULL ? signature_algorithms->count : 0)) != 0) {
115+
116+
or:
117+
118+
static int sign_certificate(ptls_sign_certificate_t *_self, ptls_t *tls, ptls_async_job_t **async, uint16_t *selected_algorithm,
119+
ptls_buffer_t *outbuf, ptls_iovec_t input, const uint16_t *algorithms, size_t num_algorithms)
120+
121+
The callback "super" type is ptls_sign_certificate_t, defined by the macro:
122+
PTLS_CALLBACK_TYPE(int, sign_certificate, ptls_t *tls, ptls_async_job_t **async, uint16_t *selected_algorithm,
123+
ptls_buffer_t *output, ptls_iovec_t input, const uint16_t *algorithms, size_t num_algorithms);
124+
125+
The notation is simple: input buffer and supported algorithms as input, selected algo and output buffer as output.
126+
Output buffer is already partially filled.
127+
128+
*/
129+
130+
#define ASSET_RSA_KEY "t/assets/rsa/key.pem"
131+
#define ASSET_RSA_PKCS8_KEY "t/assets/rsa-pkcs8/key.pem"
132+
#define ASSET_SECP256R1_KEY "t/assets/secp256r1/key.pem"
133+
#define ASSET_SECP384R1_KEY "t/assets/secp384r1/key.pem"
134+
#define ASSET_SECP521R1_KEY "t/assets/secp521r1/key.pem"
135+
#define ASSET_SECP256R1_PKCS8_KEY "t/assets/secp256r1-pkcs8/key.pem"
136+
137+
int test_load_one_der_key(char const *path)
138+
{
139+
int ret = -1;
140+
unsigned char hash[32];
141+
const unsigned char h0[32] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
142+
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32};
143+
ptls_context_t ctx = {0};
144+
145+
ret = ptls_mbedtls_load_private_key(&ctx, path);
146+
if (ret != 0) {
147+
printf("Cannot create sign_certificate from: %s\n", path);
148+
ret = -1;
149+
} else if (ctx.sign_certificate == NULL) {
150+
printf("Sign_certificate not set in ptls context for: %s\n", path);
151+
ret = -1;
152+
} else {
153+
/* Try to sign something */
154+
int ret;
155+
ptls_mbedtls_sign_certificate_t *signer =
156+
(ptls_mbedtls_sign_certificate_t *)(((unsigned char *)ctx.sign_certificate) -
157+
offsetof(struct st_ptls_mbedtls_sign_certificate_t, super));
158+
/* get the key algorithm */
159+
ptls_buffer_t outbuf;
160+
uint8_t outbuf_smallbuf[256];
161+
ptls_iovec_t input = {hash, sizeof(hash)};
162+
uint16_t selected_algorithm = 0;
163+
int num_algorithms = 0;
164+
uint16_t algorithms[16];
165+
memcpy(hash, h0, 32);
166+
while (signer->schemes[num_algorithms].scheme_id != UINT16_MAX && num_algorithms < 16) {
167+
algorithms[num_algorithms] = signer->schemes[num_algorithms].scheme_id;
168+
num_algorithms++;
169+
}
170+
171+
ptls_buffer_init(&outbuf, outbuf_smallbuf, sizeof(outbuf_smallbuf));
172+
173+
ret = ptls_mbedtls_sign_certificate(ctx.sign_certificate, NULL, NULL, &selected_algorithm, &outbuf, input, algorithms,
174+
num_algorithms);
175+
if (ret == 0) {
176+
printf("Signed a message, key: %s, scheme: %x, signature size: %zu\n", path, selected_algorithm, outbuf.off);
177+
} else {
178+
printf("Sign failed, key: %s, scheme: %x, signature size: %zu\n", path, selected_algorithm, outbuf.off);
179+
}
180+
ptls_buffer_dispose(&outbuf);
181+
ptls_mbedtls_dispose_sign_certificate(&signer->super);
182+
}
183+
return ret;
184+
}
185+
186+
static void test_load_rsa_key()
187+
{
188+
int ret = test_load_one_der_key(ASSET_RSA_KEY);
189+
190+
if (ret != 0) {
191+
ok(!"fail");
192+
return;
193+
}
194+
ok(!!"success");
195+
}
196+
197+
static void test_load_secp256r1_key()
198+
{
199+
int ret = test_load_one_der_key(ASSET_SECP256R1_KEY);
200+
if (ret != 0) {
201+
ok(!"fail");
202+
return;
203+
}
204+
ok(!!"success");
205+
}
206+
207+
static void test_load_secp384r1_key()
208+
{
209+
int ret = test_load_one_der_key(ASSET_SECP384R1_KEY);
210+
if (ret != 0) {
211+
ok(!"fail");
212+
return;
213+
}
214+
ok(!!"success");
215+
}
216+
217+
static void test_load_secp521r1_key()
218+
{
219+
int ret = test_load_one_der_key(ASSET_SECP521R1_KEY);
220+
if (ret != 0) {
221+
ok(!"fail");
222+
return;
223+
}
224+
ok(!!"success");
225+
}
226+
227+
static void test_load_secp256r1_pkcs8_key()
228+
{
229+
int ret = test_load_one_der_key(ASSET_SECP256R1_PKCS8_KEY);
230+
if (ret != 0) {
231+
ok(!"fail");
232+
return;
233+
}
234+
ok(!!"success");
235+
}
236+
237+
static void test_load_rsa_pkcs8_key()
238+
{
239+
int ret = test_load_one_der_key(ASSET_RSA_PKCS8_KEY);
240+
if (ret != 0) {
241+
ok(!"fail");
242+
return;
243+
}
244+
ok(!!"success");
245+
}
246+
247+
void test_sign_certificate(void)
248+
{
249+
subtest("load rsa key", test_load_rsa_key);
250+
subtest("load secp256r1 key", test_load_secp256r1_key);
251+
subtest("load secp384r1 key", test_load_secp384r1_key);
252+
subtest("load secp521r1 key", test_load_secp521r1_key);
253+
subtest("load secp521r1-pkcs8 key", test_load_secp256r1_pkcs8_key);
254+
subtest("load rsa-pkcs8 key", test_load_rsa_pkcs8_key);
255+
256+
/* we do not test EDDSA keys, because they are not yet supported */
257+
}
258+
92259
DEFINE_FFX_AES128_ALGORITHMS(mbedtls);
93260
DEFINE_FFX_CHACHA20_ALGORITHMS(mbedtls);
94261

@@ -143,6 +310,9 @@ int main(int argc, char **argv)
143310
ctx_peer = &mbedtls_ctx;
144311
subtest("minicrypto vs.", test_picotls);
145312

313+
/* test the sign certificate */
314+
subtest("sign certificate", test_sign_certificate);
315+
146316
/* Deinitialize the PSA crypto library. */
147317
mbedtls_psa_crypto_free();
148318

0 commit comments

Comments
 (0)