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
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
OPENHITLS_REPO: https://gitcode.com/openHiTLS/openhitls.git
# Pinned until the next openHiTLS release
OPENHITLS_REF: 0a7d5a3748f94c594832a16a7a970cb19d8b4b12
OPENHITLS_REF: 2d524d8e0f9c392a4bc3c244f976a69f9f6bb64a

jobs:
pre-commit:
Expand Down
114 changes: 114 additions & 0 deletions examples/tls_backend_testcases.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
# - PKI invalid root CA directory negative path
# - concurrent PSK and PKI server configuration
# - PKI missing client certificate negative path
# - PKI SAN preferred over CN
# - PKI CN fallback without SAN
# - PKI SNI certificate selection
# - wrong PKI CA negative path
#
Expand Down Expand Up @@ -322,6 +324,8 @@ generate_pki_files () {
ca_conf=$pki_dir/ca.cnf
server_conf=$pki_dir/server.cnf
alt_server_conf=$pki_dir/alt_server.cnf
san_server_conf=$pki_dir/san_server.cnf
cn_server_conf=$pki_dir/cn_server.cnf
sni_server_conf=$pki_dir/sni_server.cnf
client_conf=$pki_dir/client.cnf
inter_conf=$pki_dir/inter.cnf
Expand All @@ -331,6 +335,10 @@ generate_pki_files () {
if [ -f "$pki_dir/server.pem" ] &&
[ -f "$pki_dir/self_server.pem" ] &&
[ -f "$pki_dir/alt_server.pem" ] &&
[ -f "$pki_dir/san_server.pem" ] &&
[ -f "$pki_dir/san_server.key" ] &&
[ -f "$pki_dir/cn_server.pem" ] &&
[ -f "$pki_dir/cn_server.key" ] &&
[ -f "$pki_dir/sni_combined.pem" ] &&
[ -f "$pki_dir/chain_server.pem" ] &&
[ -f "$pki_dir/chain_depth_ok_server.pem" ] &&
Expand Down Expand Up @@ -392,6 +400,40 @@ subjectAltName = @alt_names

[alt_names]
DNS.1 = default.invalid
EOF

cat > "$san_server_conf" <<EOF
[req]
distinguished_name = dn
req_extensions = v3_req
prompt = no

[dn]
CN = default.invalid

[v3_req]
basicConstraints = CA:false
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = $SNI_HOST
EOF

cat > "$cn_server_conf" <<EOF
[req]
distinguished_name = dn
req_extensions = v3_req
prompt = no

[dn]
CN = $SNI_HOST

[v3_req]
basicConstraints = CA:false
keyUsage = critical,digitalSignature,keyEncipherment
extendedKeyUsage = serverAuth
EOF

cat > "$sni_server_conf" <<EOF
Expand Down Expand Up @@ -454,6 +496,22 @@ EOF
-out "$pki_dir/alt_server.pem" -days 1 -sha256 \
-extensions v3_req -extfile "$alt_server_conf" \
>> "$LOGDIR/$case_name.openssl" 2>&1 || return 1
openssl req -new -newkey rsa:2048 -nodes -sha256 \
-keyout "$pki_dir/san_server.key" -out "$pki_dir/san_server.csr" \
-config "$san_server_conf" >> "$LOGDIR/$case_name.openssl" 2>&1 || return 1
openssl x509 -req -in "$pki_dir/san_server.csr" \
-CA "$pki_dir/ca.pem" -CAkey "$pki_dir/ca.key" -CAcreateserial \
-out "$pki_dir/san_server.pem" -days 1 -sha256 \
-extensions v3_req -extfile "$san_server_conf" \
>> "$LOGDIR/$case_name.openssl" 2>&1 || return 1
openssl req -new -newkey rsa:2048 -nodes -sha256 \
-keyout "$pki_dir/cn_server.key" -out "$pki_dir/cn_server.csr" \
-config "$cn_server_conf" >> "$LOGDIR/$case_name.openssl" 2>&1 || return 1
openssl x509 -req -in "$pki_dir/cn_server.csr" \
-CA "$pki_dir/ca.pem" -CAkey "$pki_dir/ca.key" -CAcreateserial \
-out "$pki_dir/cn_server.pem" -days 1 -sha256 \
-extensions v3_req -extfile "$cn_server_conf" \
>> "$LOGDIR/$case_name.openssl" 2>&1 || return 1
openssl req -new -newkey rsa:2048 -nodes -sha256 \
-keyout "$pki_dir/sni_server.key" -out "$pki_dir/sni_server.csr" \
-config "$sni_server_conf" >> "$LOGDIR/$case_name.openssl" 2>&1 || return 1
Expand Down Expand Up @@ -1471,6 +1529,60 @@ run_pki_missing_client_cert () {
fi
}

run_pki_san_preferred_over_cn () {
case_name=pki_san_preferred_over_cn
echo -n "PKI SAN preferred over CN - "
pki_dir=$LOGDIR/pki

if ! generate_pki_files "$case_name"; then
fail_case "$case_name" "certificate generation failed"
return
fi
if ! start_pki_server "$case_name" "$pki_dir/san_server.pem" \
"$pki_dir/san_server.key"; then
fail_case "$case_name" "server did not start"
return
fi

run_pki_client "$case_name" "$pki_dir/ca.pem" "$CLIENT_TIMEOUT"

if assert_contains "$LOGDIR/$case_name.client" "COAP_EVENT_DTLS_CONNECTED" &&
assert_contains "$LOGDIR/$case_name.client" "2\\.05" &&
assert_contains "$LOGDIR/$case_name.client" "CN '$SNI_HOST' presented by server" &&
assert_contains "$LOGDIR/$case_name.server" "call handler for pseudo resource '.well-known/core'"; then
pass_case
else
fail_case "$case_name" "PKI SAN did not override mismatching CN"
fi
}

run_pki_cn_fallback () {
case_name=pki_cn_fallback
echo -n "PKI CN fallback without SAN - "
pki_dir=$LOGDIR/pki

if ! generate_pki_files "$case_name"; then
fail_case "$case_name" "certificate generation failed"
return
fi
if ! start_pki_server "$case_name" "$pki_dir/cn_server.pem" \
"$pki_dir/cn_server.key"; then
fail_case "$case_name" "server did not start"
return
fi

run_pki_client "$case_name" "$pki_dir/ca.pem" "$CLIENT_TIMEOUT"

if assert_contains "$LOGDIR/$case_name.client" "COAP_EVENT_DTLS_CONNECTED" &&
assert_contains "$LOGDIR/$case_name.client" "2\\.05" &&
assert_contains "$LOGDIR/$case_name.client" "CN '$SNI_HOST' presented by server" &&
assert_contains "$LOGDIR/$case_name.server" "call handler for pseudo resource '.well-known/core'"; then
pass_case
else
fail_case "$case_name" "PKI CN fallback without SAN did not complete"
fi
}

run_pki_sni () {
case_name=pki_sni
echo -n "PKI SNI certificate selection - "
Expand Down Expand Up @@ -1557,6 +1669,8 @@ run_pki_root_ca_file_invalid
run_pki_root_ca_dir_invalid
run_psk_pki_dual_mode
run_pki_missing_client_cert
run_pki_san_preferred_over_cn
run_pki_cn_fallback
run_pki_sni
run_wrong_pki_ca

Expand Down
85 changes: 77 additions & 8 deletions src/coap_openhitls.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include <hitls/pki/hitls_pki_cert.h>
#include <hitls/pki/hitls_pki_errno.h>
#include <hitls/pki/hitls_pki_types.h>
#include <hitls/pki/hitls_pki_utils.h>
#include <hitls/pki/hitls_pki_x509.h>
#if defined(__GNUC__)
#pragma GCC diagnostic pop
Expand Down Expand Up @@ -787,6 +788,76 @@ coap_hitls_verify_cb_self_signed_allowed(const coap_dtls_pki_t *setup_data,
depth == 0 && coap_hitls_cert_is_self_signed(cert);
}

static char *
coap_hitls_copy_name(const uint8_t *data, uint32_t data_len) {
char *copy;
size_t len = (size_t)data_len;

if (data_len && !data)
return NULL;
copy = (char *)coap_malloc_type(COAP_STRING, len + 1);
Comment thread
tlhc marked this conversation as resolved.
if (!copy)
return NULL;
if (len)
memcpy(copy, data, len);
copy[len] = '\000';
return copy;
}

static char *
coap_hitls_get_san_from_cert(HITLS_X509_Cert *cert) {
HITLS_X509_ExtSan san = {0};
char *dns_name = NULL;

if (HITLS_X509_CertCtrl(cert, HITLS_X509_EXT_GET_SAN, &san,
sizeof(san)) == HITLS_PKI_SUCCESS &&
san.names) {
for (BslListNode *name_node = BSL_LIST_FirstNode(san.names);
name_node != NULL;
name_node = BSL_LIST_GetNextNode(san.names, name_node)) {
const HITLS_X509_GeneralName *name =
(const HITLS_X509_GeneralName *)BSL_LIST_GetData(name_node);

if (!name || name->type != HITLS_X509_GN_DNS)
continue;
if (name->value.dataLen &&
memchr(name->value.data, '\000', name->value.dataLen))
continue;
dns_name = coap_hitls_copy_name(name->value.data, name->value.dataLen);
break;
}
}

HITLS_X509_ClearSubjectAltName(&san);
return dns_name;
}

static char *
coap_hitls_get_cn_from_cert(HITLS_X509_Cert *cert) {
BSL_Buffer cn = {0};
char *cn_name = NULL;

if (HITLS_X509_CertCtrl(cert, HITLS_X509_GET_SUBJECT_CN_STR,
&cn, sizeof(cn)) == HITLS_PKI_SUCCESS) {
cn_name = coap_hitls_copy_name(cn.data, cn.dataLen);
}
if (cn.data)
BSL_SAL_Free(cn.data);
return cn_name;
}

static char *
coap_hitls_get_san_or_cn_from_cert(HITLS_X509_Cert *cert) {
char *name;

if (!cert)
return NULL;
name = coap_hitls_get_san_from_cert(cert);
if (name)
return name;
return coap_hitls_get_cn_from_cert(cert);
}

static int
coap_hitls_validate_cn_cert(coap_session_t *session,
const coap_dtls_pki_t *setup_data,
Expand All @@ -795,32 +866,30 @@ coap_hitls_validate_cn_cert(coap_session_t *session,
int validated) {
uint8_t *der = NULL;
uint32_t der_len = 0;
BSL_Buffer cn;
char *san_or_cn;
int ret = 1;

memset(&cn, 0, sizeof(cn));
(void)HITLS_X509_CertCtrl(cert, HITLS_X509_GET_ENCODELEN,
&der_len, sizeof(der_len));
if (der_len)
(void)HITLS_X509_CertCtrl(cert, HITLS_X509_GET_ENCODE,
&der, sizeof(der));
(void)HITLS_X509_CertCtrl(cert, HITLS_X509_GET_SUBJECT_CN_STR,
&cn, sizeof(cn));
san_or_cn = coap_hitls_get_san_or_cn_from_cert(cert);

if (setup_data->validate_cn_call_back) {
coap_lock_callback_ret(ret,
setup_data->validate_cn_call_back(
cn.data ? (const char *)cn.data : "",
san_or_cn ? san_or_cn : "",
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)) {
san_or_cn && strcmp(san_or_cn, setup_data->client_sni)) {
ret = 0;
}
if (cn.data)
BSL_SAL_Free(cn.data);
if (san_or_cn)
coap_free_type(COAP_STRING, san_or_cn);
return ret;
}

Expand Down
Loading