Skip to content
Merged
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
11 changes: 6 additions & 5 deletions examples/coap-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1648,17 +1648,18 @@ setup_pki(coap_context_t *ctx, coap_dtls_role_t role) {
* but this is used to define what checking actually takes place.
*/
dtls_pki.verify_peer_cert = verify_peer_cert;
dtls_pki.check_common_ca = !root_ca_file;
dtls_pki.allow_self_signed = 1;
dtls_pki.check_common_ca = ca_file != NULL;
dtls_pki.allow_self_signed = !(root_ca_file || ca_file);;
dtls_pki.allow_expired_certs = 1;
dtls_pki.cert_chain_validation = 1;
dtls_pki.cert_chain_verify_depth = 2;
dtls_pki.check_cert_revocation = 1;
dtls_pki.allow_no_crl = 1;
dtls_pki.allow_expired_crl = 1;
dtls_pki.is_rpk_not_cert = is_rpk_not_cert;
dtls_pki.use_cid = setup_cid;
dtls_pki.validate_cn_call_back = verify_cn_callback;
dtls_pki.is_rpk_not_cert = is_rpk_not_cert;
dtls_pki.use_cid = setup_cid;
dtls_pki.allow_sni_cn_mismatch = 0; /* Not recommended to set */
dtls_pki.validate_cn_call_back = verify_cn_callback;
if (role == COAP_DTLS_ROLE_CLIENT) {
if (proxy.host.length) {
snprintf(client_sni, sizeof(client_sni), "%*.*s", (int)proxy.host.length, (int)proxy.host.length,
Expand Down
11 changes: 6 additions & 5 deletions examples/tls_backend_testcases.sh
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@ run_pki_client () {

if [ -n "$root_ca_file" ]; then
client_args="$client_args -R $root_ca_file"
else
elif [ -n "$ca_file" ]; then
client_args="$client_args -C $ca_file"
fi

Expand Down Expand Up @@ -786,7 +786,8 @@ run_psk_identity_hint_callback () {
run_client "$case_name" "$PSK_KEY" "" "$CLIENT_TIMEOUT" "$TARGET_URI" \
"$hint_file"

if assert_contains "$LOGDIR/$case_name.client" "does not support Identity Hint selection"; then
if assert_contains "$LOGDIR/$case_name.client" "does not support Identity Hint" ||
assert_contains "$LOGDIR/$case_name.server" "does not support Identity Hint" ; then
skip_case "Identity Hint not supported"
elif assert_contains "$LOGDIR/$case_name.client" "Identity Hint '$PSK_HINT' provided" &&
assert_contains "$LOGDIR/$case_name.client" "Switching to using '$PSK_IDENTITY' identity \\+ '$PSK_KEY' key" &&
Expand Down Expand Up @@ -1167,7 +1168,7 @@ run_pki_chain_depth_too_long () {
assert_not_contains "$LOGDIR/$case_name.client" "2\\.05" &&
assert_not_contains "$LOGDIR/$case_name.server" "call handler for pseudo resource '.well-known/core'" &&
assert_either_contains "$LOGDIR/$case_name.client" "$LOGDIR/$case_name.server" \
"certificate chain too long|constraint limits|unknown_ca|0x400000f|alert|No response received"; then
"The certificate's verify depth is too long|certificate chain too long|constraint limits|unknown_ca|0x400000f|alert|No response received"; then
pass_case
else
fail_case "$case_name" "PKI chain beyond configured depth limit was accepted"
Expand All @@ -1189,7 +1190,7 @@ run_pki_self_signed_leaf () {
return
fi

run_pki_client "$case_name" "" "$CLIENT_TIMEOUT" no "$pki_dir/bad_ca.pem"
run_pki_client "$case_name" "" "$CLIENT_TIMEOUT"

if assert_contains "$LOGDIR/$case_name.client" "COAP_EVENT_DTLS_CONNECTED" &&
assert_contains "$LOGDIR/$case_name.client" "2\\.05" &&
Expand Down Expand Up @@ -1241,7 +1242,7 @@ run_pki_non_self_signed_override () {
return
fi

run_pki_client "$case_name" "" "$CLIENT_TIMEOUT" no "$pki_dir/bad_ca.pem"
run_pki_client "$case_name" "" "$CLIENT_TIMEOUT"

if assert_not_contains "$LOGDIR/$case_name.client" "COAP_EVENT_DTLS_CONNECTED" &&
assert_not_contains "$LOGDIR/$case_name.server" "call handler for pseudo resource '.well-known/core'" &&
Expand Down
7 changes: 5 additions & 2 deletions include/coap3/coap_dtls.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,14 +338,17 @@ struct coap_dtls_pki_t {
uint8_t use_cid; /**< 1 if DTLS Connection ID is to be
* used (Client only, server always enabled)
* if supported */
uint8_t reserved[2]; /**< Reserved - must be set to 0 for
uint8_t allow_sni_cn_mismatch:1; /**< 1 if SNI and returnd CN allowed to mismatch
* (Client only). Not normally set */
uint8_t reserved[1]; /**< Reserved - must be set to 0 for
future compatibility */
/* Size of 2 chosen to align to next
/* Size of 1 chosen to align to next
* parameter, so if newly defined option
* it can use one of the reserved slots so
* no need to change
* COAP_DTLS_PKI_SETUP_VERSION and just
* decrement the reserved[] count.
* [Now just adding 1 bit at a time].
*/

/** CN check callback function.
Expand Down
9 changes: 5 additions & 4 deletions man/coap-client.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -298,12 +298,13 @@ definitions have to be in DER, not PEM, format. Otherwise all of
Disable remote peer certificate checking.

*-C* cafile::
PEM file or PKCS11 URI for the CA certificate and any intermediate CAs that was
PEM file or PKCS11 URI for the CA certificate and any intermediate CAs that was
used to sign the server
certfile. Ideally the client certificate should be signed by the same CA so that
mutual authentication can take place. The contents of cafile are added
to the trusted store of root CAs. Using the *-C* or *-R* options will trigger
the validation of the server certificate unless overridden by the *-n* option.
the validation of the server certificate (including not allowing self-signed
certificates) unless overridden by the *-n* option.

*-J* pkcs11_pin::
The user pin to unlock access to the PKCS11 token.
Expand All @@ -320,8 +321,8 @@ PEM file or PKCS11 URI for the CA certificate and any intermediate CAs that was
to be in this list and is trusted for the validation. Using
*-R trust_casfile* disables common CA mutual authentication which can only
be done by using *-C cafile*. Using the *-C* or *-R* options will
trigger the validation of the server certificate unless overridden by the
*-n* option.
trigger the validation of the server certificate (including not allowing
self-signed certificates) unless overridden by the *-n* option.

*-Y* ::
Do not load the default system Trusted Root CA Store.
Expand Down
14 changes: 11 additions & 3 deletions man/coap_encryption.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,8 @@ typedef struct coap_dtls_pki_t {
uint8_t use_cid; /* 1 if DTLS Connection ID is to be
* used (Client only, server always enabled)
* if supported */
uint8_t allow_sni_cn_mismatch:1; /* 1 if SNI and returnd CN allowed to mismatch
* (Client only). Not normally set */
uint8_t reserved[2]; /* Reserved - must be set to 0 for
future compatibility */

Expand Down Expand Up @@ -574,8 +576,8 @@ for different versions of the coap_dtls_pki_t structure in the future.
*verify_peer_cert* Set to 1 to check that the peer's certificate is valid if
provided, else 0. If not set, check_common_ca, allow_self_signed,
allow_expired_certs, cert_chain_validation, cert_chain_verify_depth,
check_cert_revocation, allow_no_crl, allow_expired_crl, allow_bad_md_hash
and allow_short_rsa_length settings are all ignored.
check_cert_revocation, allow_no_crl, allow_expired_crl, allow_bad_md_hash,
allow_short_rsa_length and allow_sni_cn_mismatch settings are all ignored.

*check_common_ca* Set to 1 to check that the CA that signed the peer's
certificate is the same CA that signed the local certificate
Expand Down Expand Up @@ -624,7 +626,11 @@ allow_no_crl, allow_expired_crl, allow_bad_md_hash and
allow_short_rsa_length settings are all ignored.

*use_cid* Set to 1 if the DTLS Client is to try to used Connection-ID.
Server is alwys enabled if support available.
Server is always enabled if support available.

*allow_sni_cn_mismatch* Set to 1 if the DTLS Client is not to compare the
Common Name (CN) of the received certificate with the sent SNI hostname.
This is not recommended.

*SECTION: PKI/RPK: coap_dtls_pki_t: Reserved*

Expand Down Expand Up @@ -1168,6 +1174,8 @@ setup_server_context_pki(const char *public_cert_file,
dtls_pki.allow_bad_md_hash = 0;
dtls_pki.allow_short_rsa_length = 0;
dtls_pki.is_rpk_not_cert = 0; /* Set to 1 if RPK */
dtls_pki.use_cid = 0;
dtls_pki.allow_sni_cn_mismatch = 0;
dtls_pki.validate_cn_call_back = verify_cn_callback;
dtls_pki.cn_call_back_arg = valid_cn_list;
dtls_pki.validate_sni_call_back = verify_pki_sni_callback;
Expand Down
2 changes: 2 additions & 0 deletions man/coap_endpoint_client.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,8 @@ setup_client_session_pki(const char *host,
dtls_pki.allow_bad_md_hash = 0;
dtls_pki.allow_short_rsa_length = 0;
dtls_pki.is_rpk_not_cert = 0; /* Set to 1 if RPK */
dtls_pki.use_cid = 0;
dtls_pki.allow_sni_cn_mismatch = 0;
dtls_pki.validate_cn_call_back = verify_cn_callback;
dtls_pki.cn_call_back_arg = NULL;
dtls_pki.validate_sni_call_back = NULL;
Expand Down
2 changes: 2 additions & 0 deletions man/coap_endpoint_server.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ setup_server_context_pki(const char *public_cert_file,
dtls_pki.allow_bad_md_hash = 0;
dtls_pki.allow_short_rsa_length = 0;
dtls_pki.is_rpk_not_cert = 0; /* Set to 1 if RPK */
dtls_pki.use_cid = 0;
dtls_pki.allow_sni_cn_mismatch = 0;
dtls_pki.validate_cn_call_back = verify_cn_callback;
dtls_pki.cn_call_back_arg = valid_cn_list;
dtls_pki.validate_sni_call_back = verify_pki_sni_callback;
Expand Down
3 changes: 3 additions & 0 deletions man/coap_tls_library.txt.in
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ setup_server_context_pki(const char *public_cert_file,
dtls_pki.check_cert_revocation = 1;
dtls_pki.allow_no_crl = 1;
dtls_pki.allow_expired_crl = 1;
dtls_pki.is_rpk_not_cert = 0; /* Set to 1 if RPK */
dtls_pki.use_cid = 0;
dtls_pki.allow_sni_cn_mismatch = 0;
dtls_pki.pki_key.key_type = COAP_PKI_KEY_DEFINE;
dtls_pki.pki_key.key.define.ca.s_byte = ca_file;
dtls_pki.pki_key.key.define.public_cert.s_byte = public_cert_file;
Expand Down
31 changes: 29 additions & 2 deletions src/coap_gnutls.c
Original file line number Diff line number Diff line change
Expand Up @@ -867,8 +867,18 @@ cert_verify_gnutls(gnutls_session_t g_session) {
goto fail;
}

G_CHECK(gnutls_certificate_verify_peers(g_session, NULL, 0, &status),
"gnutls_certificate_verify_peers");
if (c_session->type == COAP_SESSION_TYPE_CLIENT && g_context->setup_data.client_sni) {
gnutls_typed_vdata_st host;

host.type = GNUTLS_DT_DNS_HOSTNAME;
host.data = (uint8_t *)g_context->setup_data.client_sni;
host.size = strlen(g_context->setup_data.client_sni);
G_CHECK(gnutls_certificate_verify_peers(g_session, &host, 1, &status),
"gnutls_certificate_verify_peers");
} else {
G_CHECK(gnutls_certificate_verify_peers(g_session, NULL, 0, &status),
"gnutls_certificate_verify_peers");
}

coap_dtls_log(COAP_LOG_DEBUG, "error %x cert '%s'\n",
status, cert_info.san_or_cn);
Expand Down Expand Up @@ -922,6 +932,23 @@ cert_verify_gnutls(gnutls_session_t g_session) {
OUTPUT_CERT_NAME);
}
}
if (status & (GNUTLS_CERT_UNEXPECTED_OWNER)) {
status &= ~(GNUTLS_CERT_UNEXPECTED_OWNER);
if (g_context->setup_data.allow_sni_cn_mismatch) {
coap_log_info(" %s: %s: overridden: '%s' v '%s'\n",
coap_session_str(c_session),
"The SNI does not match the returned CN",
g_context->setup_data.client_sni,
OUTPUT_CERT_NAME);
} else {
fail = 1;
coap_log_warn(" %s: %s: '%s' v '%s'\n",
coap_session_str(c_session),
"The SNI does not match the returned CN",
g_context->setup_data.client_sni,
OUTPUT_CERT_NAME);
}
}
if (status & (GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE)) {
status &= ~(GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
Expand Down
38 changes: 27 additions & 11 deletions src/coap_mbedtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -679,12 +679,15 @@ cert_verify_callback_mbedtls(void *data, mbedtls_x509_crt *crt,
char *cn = NULL;

cn = get_san_or_cn_from_cert(crt);
coap_dtls_log(COAP_LOG_DEBUG, "depth %d flags %x cert '%s'\n",
depth, *flags, cn);
if (depth == 0 && c_session->type == COAP_SESSION_TYPE_CLIENT && setup_data->client_sni && cn &&
strcmp(cn, setup_data->client_sni)) {
*flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
}
if (setup_data->validate_cn_call_back) {
int ret;

if (*flags & MBEDTLS_X509_BADCERT_CN_MISMATCH) {
*flags &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;
}
coap_lock_callback_ret(ret,
setup_data->validate_cn_call_back(cn,
crt->raw.p,
Expand All @@ -697,6 +700,14 @@ cert_verify_callback_mbedtls(void *data, mbedtls_x509_crt *crt,
*flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH;
}
}
if (setup_data->cert_chain_validation &&
depth > (setup_data->cert_chain_verify_depth + 2)) {
*flags |= MBEDTLS_X509_BADCERT_OTHER;
coap_log_warn(" %s: %s: '%s' depth %d\n",
coap_session_str(c_session),
"The certificate's verify depth is too long",
cn ? cn : "?", depth);
}
if (*flags == 0) {
if (cn)
mbedtls_free(cn);
Expand Down Expand Up @@ -735,6 +746,16 @@ cert_verify_callback_mbedtls(void *data, mbedtls_x509_crt *crt,
"The certificate has a short RSA length", cn ? cn : "?", depth);
}
}
if (*flags & MBEDTLS_X509_BADCERT_CN_MISMATCH) {
if (setup_data->allow_sni_cn_mismatch) {
*flags &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;
coap_log_info(" %s: %s: overridden: '%s' v '%s' depth %d\n",
coap_session_str(c_session),
"The SNI does not match the returned CN",
setup_data->client_sni ? setup_data->client_sni : "",
cn ? cn : "?", depth);
}
}
if (*flags & MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
uint32_t lflags;
int self_signed = !mbedtls_x509_crt_verify(crt, crt, NULL, NULL, &lflags,
Expand Down Expand Up @@ -785,14 +806,6 @@ cert_verify_callback_mbedtls(void *data, mbedtls_x509_crt *crt,
*flags &= ~MBEDTLS_X509_BADCRL_FUTURE;
}
}
if (setup_data->cert_chain_validation &&
depth > (setup_data->cert_chain_verify_depth + 1)) {
*flags |= MBEDTLS_X509_BADCERT_OTHER;
coap_log_warn(" %s: %s: '%s' depth %d\n",
coap_session_str(c_session),
"The certificate's verify depth is too long",
cn ? cn : "?", depth);
}

if (*flags != 0) {
char buf[128];
Expand Down Expand Up @@ -2401,6 +2414,9 @@ coap_dtls_context_set_spsk(coap_context_t *c_context,
coap_log_warn("Mbed TLS not compiled for EC-JPAKE support\n");
#endif /* ! MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */
}
if (setup_data->psk_info.hint.length) {
coap_log_warn("CoAP Server with Mbed TLS does not support Identity Hint\n");
}
m_context->psk_pki_enabled |= IS_PSK;
return 1;
}
Expand Down
21 changes: 13 additions & 8 deletions src/coap_openhitls.c
Original file line number Diff line number Diff line change
Expand Up @@ -796,10 +796,8 @@ coap_hitls_validate_cn_cert(coap_session_t *session,
uint8_t *der = NULL;
uint32_t der_len = 0;
BSL_Buffer cn;
int ret;
int ret = 1;

if (!setup_data->validate_cn_call_back)
return 1;
memset(&cn, 0, sizeof(cn));
(void)HITLS_X509_CertCtrl(cert, HITLS_X509_GET_ENCODELEN,
&der_len, sizeof(der_len));
Expand All @@ -809,11 +807,18 @@ coap_hitls_validate_cn_cert(coap_session_t *session,
(void)HITLS_X509_CertCtrl(cert, HITLS_X509_GET_SUBJECT_CN_STR,
&cn, sizeof(cn));

coap_lock_callback_ret(ret,
setup_data->validate_cn_call_back(
cn.data ? (const char *)cn.data : "",
der, der_len, session, depth, validated,
setup_data->cn_call_back_arg));
if (setup_data->validate_cn_call_back) {
coap_lock_callback_ret(ret,
setup_data->validate_cn_call_back(
cn.data ? (const char *)cn.data : "",
der, der_len, session, depth, validated,
setup_data->cn_call_back_arg));
}
if (depth == 0 && session->type == COAP_SESSION_TYPE_CLIENT &&
setup_data->client_sni && !setup_data->allow_sni_cn_mismatch &&
cn.data && strcmp((const char *)cn.data, setup_data->client_sni)) {
ret = 0;
}
if (cn.data)
BSL_SAL_Free(cn.data);
return ret;
Expand Down
13 changes: 11 additions & 2 deletions src/coap_openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2469,7 +2469,6 @@ tls_verify_call_back(int preverify_ok, X509_STORE_CTX *ctx) {
int err = X509_STORE_CTX_get_error(ctx);
X509 *x509 = X509_STORE_CTX_get_current_cert(ctx);
char *cn = x509 ? get_san_or_cn_from_cert(x509) : NULL;
int keep_preverify_ok = preverify_ok;

coap_dtls_log(COAP_LOG_DEBUG, "depth %d error %x preverify %d cert '%s'\n",
depth, err, preverify_ok, cn);
Expand All @@ -2478,6 +2477,12 @@ tls_verify_call_back(int preverify_ok, X509_STORE_CTX *ctx) {
OPENSSL_free(cn);
return 0;
}
if (depth == 0 && session->type == COAP_SESSION_TYPE_CLIENT && setup_data->client_sni &&
!setup_data->allow_sni_cn_mismatch && cn && strcmp(cn, setup_data->client_sni)) {
preverify_ok = 0;
X509_STORE_CTX_set_error(ctx, X509_V_ERR_SUBJECT_ISSUER_MISMATCH);
err = X509_V_ERR_SUBJECT_ISSUER_MISMATCH;
}
if (!preverify_ok) {
switch (err) {
case X509_V_ERR_CERT_NOT_YET_VALID:
Expand Down Expand Up @@ -2508,6 +2513,10 @@ tls_verify_call_back(int preverify_ok, X509_STORE_CTX *ctx) {
if (!setup_data->verify_peer_cert)
preverify_ok = 1;
break;
case X509_V_ERR_SUBJECT_ISSUER_MISMATCH:
if (setup_data->allow_sni_cn_mismatch)
preverify_ok = 1;
break;
default:
break;
}
Expand All @@ -2534,7 +2543,7 @@ tls_verify_call_back(int preverify_ok, X509_STORE_CTX *ctx) {
}
}
/* Certificate - depth == 0 is the Client Cert */
if (setup_data->validate_cn_call_back && keep_preverify_ok) {
if (setup_data->validate_cn_call_back) {
int length = i2d_X509(x509, NULL);
uint8_t *base_buf;
uint8_t *base_buf2 = base_buf = length > 0 ? OPENSSL_malloc(length) : NULL;
Expand Down
Loading
Loading