Skip to content
Open
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: 11 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ option(ENABLE_DNSSEC "Enable support for SSHFP retrieval using DNSSEC for SSH (r
option(ENABLE_PAM "Detect and use PAM" ON)
option(ENABLE_COMMON_TARGETS "Define common custom target names such as 'doc' or 'uninstall', may cause conflicts when using add_subdirectory() to build this project" ON)
option(ENABLE_IP_FREEBIND "Enable the IP_FREEBIND/IPV6_FREEBIND options on the listening TCP socket" OFF)
option(ENABLE_COMPLY_WITH_ORAN_WG11 "Comply with the O-RAN WG11 security spec (e.g. enforce the clientAuth Extended Key Usage and the digitalSignature Key Usage on client certificates)" OFF)
option(BUILD_SHARED_LIBS "By default, shared libs are enabled. Turn off for a static build." ON)
set(READ_INACTIVE_TIMEOUT 20 CACHE STRING "Maximum number of seconds waiting for new data once some data have arrived")
set(READ_ACTIVE_TIMEOUT 300 CACHE STRING "Maximum number of seconds for receiving a full message")
Expand Down Expand Up @@ -181,6 +182,11 @@ if(ENABLE_DNSSEC AND NOT ENABLE_SSH_TLS)
set(ENABLE_DNSSEC OFF)
endif()

if(ENABLE_COMPLY_WITH_ORAN_WG11 AND NOT ENABLE_SSH_TLS)
message(WARNING "O-RAN WG11 compliance cannot be used without TLS support.")
set(ENABLE_COMPLY_WITH_ORAN_WG11 OFF)
endif()

if(ENABLE_VALGRIND_TESTS)
find_program(VALGRIND_FOUND valgrind)
if(NOT VALGRIND_FOUND)
Expand Down Expand Up @@ -309,6 +315,11 @@ if(ENABLE_SSH_TLS)

# set compiler flag
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNC_ENABLED_SSH_TLS")

# comply with the O-RAN WG11 security spec (e.g. client cert Extended Key Usage and Key Usage checks)
if(ENABLE_COMPLY_WITH_ORAN_WG11)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DNC_COMPLY_WITH_ORAN_WG11")
endif()
endif()

# dependencies - libval
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,19 @@ interaction. Enable it with the following command.
$ cmake -DENABLE_DNSSEC=ON ..
```

### O-RAN WG11 Compliance

By default, **libnetconf2** implements only the base YANG and NETCONF
specifications. The O-RAN WG11 security specification (section 6.9.3) imposes
additional requirements on the client certificate used for TLS authentication,
namely that its end-entity certificate must carry the `clientAuth` Extended Key
Usage and the `digitalSignature` Key Usage. This behavior is not part of the
base specification, so it is disabled by default and can be enabled with the
following command (requires TLS support).
```
$ cmake -DENABLE_COMPLY_WITH_ORAN_WG11=ON ..
```

### Build Modes

There are two build modes:
Expand Down
50 changes: 50 additions & 0 deletions src/session_mbedtls.c
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,49 @@ nc_server_tls_prepend_issuer_chain(mbedtls_x509_crt *cert, mbedtls_x509_crt **ch
return -1;
}

#ifdef NC_COMPLY_WITH_ORAN_WG11
/**
* @brief Check that a client certificate complies with the O-RAN WG11 6.9.3 key usage requirements.
*
* The end-entity (client) certificate MUST carry the clientAuth Extended Key Usage and a Key Usage
* extension with the digitalSignature bit set (the client signs the CertificateVerify handshake message).
*
* @param[in] session Session for logging.
* @param[in] cert Client (leaf) certificate to check.
* @param[in,out] flags Verification flags, set on failure.
* @return 0 if the certificate complies, non-zero otherwise.
*/
static int
nc_server_tls_check_oran_wg11_usage(struct nc_session *session, mbedtls_x509_crt *cert, uint32_t *flags)
{
const mbedtls_x509_sequence *usage;
int has_client_auth = 0;

/* the client certificate MUST carry the clientAuth Extended Key Usage */
for (usage = &cert->ext_key_usage; usage && usage->buf.p; usage = usage->next) {
if (!MBEDTLS_OID_CMP(MBEDTLS_OID_CLIENT_AUTH, &usage->buf)) {
has_client_auth = 1;
break;
}
}
if (!has_client_auth) {
ERR(session, "Cert verify: fail (client certificate lacks the required clientAuth Extended Key Usage).");
*flags |= MBEDTLS_X509_BADCERT_EXT_KEY_USAGE;
return 1;
}

/* the client certificate MUST also carry a Key Usage extension with the digitalSignature bit set */
if (!mbedtls_x509_crt_has_ext_type(cert, MBEDTLS_X509_EXT_KEY_USAGE) ||
mbedtls_x509_crt_check_key_usage(cert, MBEDTLS_X509_KU_DIGITAL_SIGNATURE)) {
ERR(session, "Cert verify: fail (client certificate lacks the required digitalSignature Key Usage).");
*flags |= MBEDTLS_X509_BADCERT_KEY_USAGE;
return 1;
}

return 0;
}
#endif /* NC_COMPLY_WITH_ORAN_WG11 */

/**
* @brief Verify a certificate.
*
Expand Down Expand Up @@ -789,6 +832,13 @@ nc_server_tls_verify_cb(void *cb_data, mbedtls_x509_crt *cert, int depth, uint32
} else if (!ret) {
/* success */
if ((depth == 0) && (!data->session->opts.server.client_cert)) {
#ifdef NC_COMPLY_WITH_ORAN_WG11
/* O-RAN WG11 6.9.3: enforce the clientAuth Extended Key Usage and digitalSignature Key Usage */
if (nc_server_tls_check_oran_wg11_usage(data->session, cert, flags)) {
return 0;
}
#endif /* NC_COMPLY_WITH_ORAN_WG11 */

/* copy the client cert */
data->session->opts.server.client_cert = nc_tls_cert_dup(cert);
if (!data->session->opts.server.client_cert) {
Expand Down
57 changes: 57 additions & 0 deletions src/session_openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,56 @@ nc_server_tls_set_tls_versions_wrap(void *tls_cfg, enum nc_tls_version min, enum
return 0;
}

#ifdef NC_COMPLY_WITH_ORAN_WG11
/**
* @brief Check that a client certificate complies with the O-RAN WG11 6.9.3 key usage requirements.
*
* The end-entity (client) certificate MUST carry the clientAuth Extended Key Usage and a Key Usage
* extension with the digitalSignature bit set (the client signs the CertificateVerify handshake message).
*
* @param[in] session Session for logging.
* @param[in] cert Client (leaf) certificate to check.
* @return 0 if the certificate complies, non-zero otherwise.
*/
static int
nc_server_tls_check_oran_wg11_usage(struct nc_session *session, X509 *cert)
{
EXTENDED_KEY_USAGE *eku;
ASN1_BIT_STRING *ku;
int has_client_auth = 0, has_digital_signature = 0, i;

/* the client certificate MUST carry the clientAuth Extended Key Usage */
eku = X509_get_ext_d2i(cert, NID_ext_key_usage, NULL, NULL);
if (eku) {
for (i = 0; i < sk_ASN1_OBJECT_num(eku); ++i) {
if (OBJ_obj2nid(sk_ASN1_OBJECT_value(eku, i)) == NID_client_auth) {
has_client_auth = 1;
break;
}
}
EXTENDED_KEY_USAGE_free(eku);
}
if (!has_client_auth) {
ERR(session, "Cert verify: fail (client certificate lacks the required clientAuth Extended Key Usage).");
return 1;
}

/* the client certificate MUST also carry a Key Usage extension with the digitalSignature bit set */
ku = X509_get_ext_d2i(cert, NID_key_usage, NULL, NULL);
if (ku) {
/* bit 0 of the Key Usage bit string is digitalSignature */
has_digital_signature = ASN1_BIT_STRING_get_bit(ku, 0);
ASN1_BIT_STRING_free(ku);
}
if (!has_digital_signature) {
ERR(session, "Cert verify: fail (client certificate lacks the required digitalSignature Key Usage).");
return 1;
}

return 0;
}
#endif /* NC_COMPLY_WITH_ORAN_WG11 */

/**
* @brief Verify a certificate.
*
Expand Down Expand Up @@ -463,6 +513,13 @@ nc_server_tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
} else if (!ret) {
/* success */
if ((depth == 0) && (!data->session->opts.server.client_cert)) {
#ifdef NC_COMPLY_WITH_ORAN_WG11
/* O-RAN WG11 6.9.3: enforce the clientAuth Extended Key Usage and digitalSignature Key Usage */
if (nc_server_tls_check_oran_wg11_usage(data->session, cert)) {
return 0;
}
#endif /* NC_COMPLY_WITH_ORAN_WG11 */

/* copy the client cert */
data->session->opts.server.client_cert = X509_dup(cert);
NC_CHECK_ERRMEM_RET(!data->session->opts.server.client_cert, 0);
Expand Down
Loading