net: sockets: tls: Support for DER cert chain and NOCOPY optimisation
Add TLS socket option "TLS_CERT_NOCOPY" to prevent the copy of certificates to mbedTLS heap if possible. Add support to provide a chain of DER certificates by registering them with multiple tags. Signed-off-by: Lucas Dietrich <ld.adecy@gmail.com>
This commit is contained in:
parent
2fe6127425
commit
4e103bcb20
2 changed files with 118 additions and 29 deletions
|
@ -139,6 +139,12 @@ struct zsock_pollfd {
|
||||||
#define TLS_DTLS_HANDSHAKE_TIMEOUT_MIN 8
|
#define TLS_DTLS_HANDSHAKE_TIMEOUT_MIN 8
|
||||||
#define TLS_DTLS_HANDSHAKE_TIMEOUT_MAX 9
|
#define TLS_DTLS_HANDSHAKE_TIMEOUT_MAX 9
|
||||||
|
|
||||||
|
/** Socket option for preventing certificates from being copied to the mbedTLS
|
||||||
|
* heap if possible. The option is only effective for DER certificates and is
|
||||||
|
* ignored for PEM certificates.
|
||||||
|
*/
|
||||||
|
#define TLS_CERT_NOCOPY 10
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/* Valid values for TLS_PEER_VERIFY option */
|
/* Valid values for TLS_PEER_VERIFY option */
|
||||||
|
@ -150,6 +156,10 @@ struct zsock_pollfd {
|
||||||
#define TLS_DTLS_ROLE_CLIENT 0 /**< Client role in a DTLS session. */
|
#define TLS_DTLS_ROLE_CLIENT 0 /**< Client role in a DTLS session. */
|
||||||
#define TLS_DTLS_ROLE_SERVER 1 /**< Server role in a DTLS session. */
|
#define TLS_DTLS_ROLE_SERVER 1 /**< Server role in a DTLS session. */
|
||||||
|
|
||||||
|
/* Valid values for TLS_CERT_NOCOPY option */
|
||||||
|
#define TLS_CERT_NOCOPY_NONE 0 /**< Cert duplicated in heap */
|
||||||
|
#define TLS_CERT_NOCOPY_OPTIONAL 1 /**< Cert not copied in heap if DER */
|
||||||
|
|
||||||
struct zsock_addrinfo {
|
struct zsock_addrinfo {
|
||||||
struct zsock_addrinfo *ai_next;
|
struct zsock_addrinfo *ai_next;
|
||||||
int ai_flags;
|
int ai_flags;
|
||||||
|
|
|
@ -132,6 +132,11 @@ __net_socket struct tls_context {
|
||||||
/** Peer verification level. */
|
/** Peer verification level. */
|
||||||
int8_t verify_level;
|
int8_t verify_level;
|
||||||
|
|
||||||
|
/** Indicating on whether DER certificates should not be copied
|
||||||
|
* to the heap.
|
||||||
|
*/
|
||||||
|
int8_t cert_nocopy;
|
||||||
|
|
||||||
/** DTLS role, client by default. */
|
/** DTLS role, client by default. */
|
||||||
int8_t role;
|
int8_t role;
|
||||||
|
|
||||||
|
@ -654,12 +659,30 @@ static int tls_rx(void *ctx, unsigned char *buf, size_t len)
|
||||||
return received;
|
return received;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_X509_CRT_PARSE_C)
|
||||||
|
static bool crt_is_pem(const unsigned char *buf, size_t buflen)
|
||||||
|
{
|
||||||
|
return (buflen != 0 && buf[buflen - 1] == '\0' &&
|
||||||
|
strstr((const char *)buf, "-----BEGIN CERTIFICATE-----") != NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int tls_add_ca_certificate(struct tls_context *tls,
|
static int tls_add_ca_certificate(struct tls_context *tls,
|
||||||
struct tls_credential *ca_cert)
|
struct tls_credential *ca_cert)
|
||||||
{
|
{
|
||||||
#if defined(MBEDTLS_X509_CRT_PARSE_C)
|
#if defined(MBEDTLS_X509_CRT_PARSE_C)
|
||||||
int err = mbedtls_x509_crt_parse(&tls->ca_chain,
|
int err;
|
||||||
ca_cert->buf, ca_cert->len);
|
|
||||||
|
if (tls->options.cert_nocopy == TLS_CERT_NOCOPY_NONE ||
|
||||||
|
crt_is_pem(ca_cert->buf, ca_cert->len)) {
|
||||||
|
err = mbedtls_x509_crt_parse(&tls->ca_chain, ca_cert->buf,
|
||||||
|
ca_cert->len);
|
||||||
|
} else {
|
||||||
|
err = mbedtls_x509_crt_parse_der_nocopy(&tls->ca_chain,
|
||||||
|
ca_cert->buf,
|
||||||
|
ca_cert->len);
|
||||||
|
}
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
@ -679,17 +702,53 @@ static void tls_set_ca_chain(struct tls_context *tls)
|
||||||
#endif /* MBEDTLS_X509_CRT_PARSE_C */
|
#endif /* MBEDTLS_X509_CRT_PARSE_C */
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tls_set_own_cert(struct tls_context *tls,
|
static int tls_add_own_cert(struct tls_context *tls,
|
||||||
struct tls_credential *own_cert,
|
struct tls_credential *own_cert)
|
||||||
struct tls_credential *priv_key)
|
|
||||||
{
|
{
|
||||||
#if defined(MBEDTLS_X509_CRT_PARSE_C)
|
#if defined(MBEDTLS_X509_CRT_PARSE_C)
|
||||||
int err = mbedtls_x509_crt_parse(&tls->own_cert,
|
int err;
|
||||||
own_cert->buf, own_cert->len);
|
|
||||||
|
if (tls->options.cert_nocopy == TLS_CERT_NOCOPY_NONE ||
|
||||||
|
crt_is_pem(own_cert->buf, own_cert->len)) {
|
||||||
|
err = mbedtls_x509_crt_parse(&tls->own_cert,
|
||||||
|
own_cert->buf, own_cert->len);
|
||||||
|
} else {
|
||||||
|
err = mbedtls_x509_crt_parse_der_nocopy(&tls->own_cert,
|
||||||
|
own_cert->buf,
|
||||||
|
own_cert->len);
|
||||||
|
}
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#endif /* MBEDTLS_X509_CRT_PARSE_C */
|
||||||
|
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tls_set_own_cert(struct tls_context *tls)
|
||||||
|
{
|
||||||
|
#if defined(MBEDTLS_X509_CRT_PARSE_C)
|
||||||
|
int err = mbedtls_ssl_conf_own_cert(&tls->config, &tls->own_cert,
|
||||||
|
&tls->priv_key);
|
||||||
|
if (err != 0) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
#endif /* MBEDTLS_X509_CRT_PARSE_C */
|
||||||
|
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tls_set_private_key(struct tls_context *tls,
|
||||||
|
struct tls_credential *priv_key)
|
||||||
|
{
|
||||||
|
#if defined(MBEDTLS_X509_CRT_PARSE_C)
|
||||||
|
int err;
|
||||||
|
|
||||||
err = mbedtls_pk_parse_key(&tls->priv_key, priv_key->buf,
|
err = mbedtls_pk_parse_key(&tls->priv_key, priv_key->buf,
|
||||||
priv_key->len, NULL, 0,
|
priv_key->len, NULL, 0,
|
||||||
tls_ctr_drbg_random, NULL);
|
tls_ctr_drbg_random, NULL);
|
||||||
|
@ -697,12 +756,6 @@ static int tls_set_own_cert(struct tls_context *tls,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = mbedtls_ssl_conf_own_cert(&tls->config, &tls->own_cert,
|
|
||||||
&tls->priv_key);
|
|
||||||
if (err != 0) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif /* MBEDTLS_X509_CRT_PARSE_C */
|
#endif /* MBEDTLS_X509_CRT_PARSE_C */
|
||||||
|
|
||||||
|
@ -736,21 +789,11 @@ static int tls_set_credential(struct tls_context *tls,
|
||||||
return tls_add_ca_certificate(tls, cred);
|
return tls_add_ca_certificate(tls, cred);
|
||||||
|
|
||||||
case TLS_CREDENTIAL_SERVER_CERTIFICATE:
|
case TLS_CREDENTIAL_SERVER_CERTIFICATE:
|
||||||
{
|
return tls_add_own_cert(tls, cred);
|
||||||
struct tls_credential *priv_key =
|
|
||||||
credential_get(cred->tag, TLS_CREDENTIAL_PRIVATE_KEY);
|
|
||||||
if (!priv_key) {
|
|
||||||
return -ENOENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tls_set_own_cert(tls, cred, priv_key);
|
|
||||||
}
|
|
||||||
|
|
||||||
case TLS_CREDENTIAL_PRIVATE_KEY:
|
case TLS_CREDENTIAL_PRIVATE_KEY:
|
||||||
/* Ignore private key - it will be used together
|
return tls_set_private_key(tls, cred);
|
||||||
* with public certificate
|
break;
|
||||||
*/
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TLS_CREDENTIAL_PSK:
|
case TLS_CREDENTIAL_PSK:
|
||||||
{
|
{
|
||||||
|
@ -781,7 +824,7 @@ static int tls_mbedtls_set_credentials(struct tls_context *tls)
|
||||||
struct tls_credential *cred;
|
struct tls_credential *cred;
|
||||||
sec_tag_t tag;
|
sec_tag_t tag;
|
||||||
int i, err = 0;
|
int i, err = 0;
|
||||||
bool tag_found, ca_cert_present = false;
|
bool tag_found, ca_cert_present = false, own_cert_present = false;
|
||||||
|
|
||||||
credentials_lock();
|
credentials_lock();
|
||||||
|
|
||||||
|
@ -800,6 +843,8 @@ static int tls_mbedtls_set_credentials(struct tls_context *tls)
|
||||||
|
|
||||||
if (cred->type == TLS_CREDENTIAL_CA_CERTIFICATE) {
|
if (cred->type == TLS_CREDENTIAL_CA_CERTIFICATE) {
|
||||||
ca_cert_present = true;
|
ca_cert_present = true;
|
||||||
|
} else if (cred->type == TLS_CREDENTIAL_SERVER_CERTIFICATE) {
|
||||||
|
own_cert_present = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -812,8 +857,13 @@ static int tls_mbedtls_set_credentials(struct tls_context *tls)
|
||||||
exit:
|
exit:
|
||||||
credentials_unlock();
|
credentials_unlock();
|
||||||
|
|
||||||
if (err == 0 && ca_cert_present) {
|
if (err == 0) {
|
||||||
tls_set_ca_chain(tls);
|
if (ca_cert_present) {
|
||||||
|
tls_set_ca_chain(tls);
|
||||||
|
}
|
||||||
|
if (own_cert_present) {
|
||||||
|
err = tls_set_own_cert(tls);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
@ -1327,6 +1377,31 @@ static int tls_opt_peer_verify_set(struct tls_context *context,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tls_opt_cert_nocopy_set(struct tls_context *context,
|
||||||
|
const void *optval, socklen_t optlen)
|
||||||
|
{
|
||||||
|
int *cert_nocopy;
|
||||||
|
|
||||||
|
if (!optval) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optlen != sizeof(int)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cert_nocopy = (int *)optval;
|
||||||
|
|
||||||
|
if (*cert_nocopy != TLS_CERT_NOCOPY_NONE &&
|
||||||
|
*cert_nocopy != TLS_CERT_NOCOPY_OPTIONAL) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
context->options.cert_nocopy = *cert_nocopy;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int tls_opt_dtls_role_set(struct tls_context *context,
|
static int tls_opt_dtls_role_set(struct tls_context *context,
|
||||||
const void *optval, socklen_t optlen)
|
const void *optval, socklen_t optlen)
|
||||||
{
|
{
|
||||||
|
@ -2464,6 +2539,10 @@ int ztls_setsockopt_ctx(struct tls_context *ctx, int level, int optname,
|
||||||
err = tls_opt_peer_verify_set(ctx, optval, optlen);
|
err = tls_opt_peer_verify_set(ctx, optval, optlen);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TLS_CERT_NOCOPY:
|
||||||
|
err = tls_opt_cert_nocopy_set(ctx, optval, optlen);
|
||||||
|
break;
|
||||||
|
|
||||||
case TLS_DTLS_ROLE:
|
case TLS_DTLS_ROLE:
|
||||||
err = tls_opt_dtls_role_set(ctx, optval, optlen);
|
err = tls_opt_dtls_role_set(ctx, optval, optlen);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue