How to run Linux desktop in a corporate environment =================================================== DISCLAIMER ---------- **Some of the practices described in this HOWTO are considered to be illegal as they often break internal corporate policies. Anything you do, you do at your own risk.** Description ----------- This HOWTO will show how to make running most of the tools used in a corporate environment under Linux. This HOWTO assumes that the company is using Windows as their main operating system and Cisco-based infrastructure (WiFi, VPN, communication tools). Why to use Linux? ----------------- Just to name few reasons: - No license fees - Stability, security and privacy - No need to run antivirus software - Better package management - Better automation of tasks - Better window management - Freedom Distribution ------------ Big corporations are either not supporting Linux desktops at all or are thinking to support the same Linux distribution for their production servers as well as for desktop. The second option is definitely more optimistic although still not very good. The Linux distribution used on servers is usually either RedHat Enterprise Linux or one of its derivatives (CentOS, Oracle Linux, ...). Those are good choice for servers but definitely not for desktop. More suitable distribution for desktop are Ubuntu, Fedora, Arch Linux or any other cutting edge distribution. User's certificates ------------------- Almost every corporation is using Microsoft Windows as their main desktop operating system. Windows desktops are usually secured with an user-specific certificate. This certificate is usually not possible to export and the only access to the certificate is usually provided only through a Public Key Infrastructure (e.g. Cisco PKI client) which normally doesn't support Linux. This is the root of all problems to run Linux desktop in the corporate environment. In order to make things working on Linux, we must get the user's certificate from Windows. ### User's certificate extraction For this we can use [Mimikatz](https://github.com/gentilkiwi/mimikatz). Mimikatz allows to [extract](http://theunixtips.com/export-nonexporteable-private-certificate-from-symantec-pki/) user's certificate directly from the Windows memory. In order to run Mimikatz, the Windows firewall/antivirus must be disabled (ask some friendly desktop support guy to help you with that). As Mimikatz extracts all certificates by default, we need to identify which of them is actually the user's certificate. Once the certificates are exported, you can delete all the installed certificates (run `certmgt.msc` command on Windows). Then import certificates one by one and try to connect to the corporate WiFi (and/or VPN). Once the connection is established, you found the user's certificate. Mimikatz secures all the exported certificates with a default password so it's recommended to change it: ``` $ openssl pkcs12 -des3 -in CURRENT_USER_My_1_.pfx -out user_cert.pfx ``` Now we can delete the original certificate: ``` $ rm -f ./CURRENT_USER_My_1_.pfx ``` ### Public certificate and private key extraction (optional) The user's certificate has two parts - the public certificate and the private key. You can extract each of them from the `.pfx` file like this: ``` $ openssl pkcs12 -in user_cert.pfx -nodes -nocerts -out Key.pem $ openssl pkcs12 -in user_cert.pfx -nodes -nokeys -clcerts -out ClientCert.pem ``` And set password on the private key: ``` $ openssl rsa -aes256 -in Key.pem -out KeyP.pem ``` Now we can delete the unsecured key: ``` $ rm -f ./Key.pem ``` ### Using YubiKey NEO Although we can secure the private key and with a password, it is still not very secure as anybody who get access to our PC can steal them. We can extend the security by encrypting the filesystem (eg. `ecryptfs`, `dm-crypt`) and allow to decrypt it only when we login. This is still not very secure as the private key is still available as a file. But if we use [Yubikey NEO](https://www.yubico.com/products/yubikey-hardware/yubikey-neo/), we can upload the public certificate and the private key on it and nobody, including us, can ever extract the private key from it. That makes it a very secure solution. That's possible only thanks to the NEO's Privilege and Identification Card (PIV) interface used to provide a platform-independent API to cryptographic tokens via PKCS#11 standard. That makes the Yubikey to work like a smart card. Access to the PIV interface is secured by a PIN - only person who knows the password can use the Yubikey to authenticate. To load the user's certificate on the Yubikey, we can either use [GUI](https://developers.yubico.com/yubikey-piv-manager/) or [CLI](https://developers.yubico.com/PIV/Tools/Yubico_PIV_Tool.html). Go ahead and use the GUI to set the PIN/PUK and import the user's certificate (`user_cert.pfx`) into the _Authenticate_ slot (9a). I will show here how to do it with the CLI as it allow us to do more things (e.g. change the number of PIN/PUK attempts). First we block the PIN and PUK to be able to reset the PIV application (both must be blocked before we can reset the application). Bear in mind that this action will destroy all keys stored in PIV application: ``` $ for N in $(seq 3); do yubico-piv-tool -a verify-pin -P wrongpin; yubico-piv-tool -a change-puk -P wrongpuk -N wrongpuk; done $ yubico-piv-tool -a reset ``` First we generate and set a new Management KEY (24 bits in hex): ``` $ dd if=/dev/random bs=1 count=24 2>/dev/null | hexdump -v -e '/1 "%02X"' | gpg -c -a -o MgmtKey.gpg $ KEY=$(gpg -d MgmtKey.gpg 2>/dev/null) $ yubico-piv-tool -a set-mgm-key -n $KEY ``` Keep the `MgmtKey.gpg` file secure for later use. Then we set PIN (4-8 chars) and PUK (4-8 chars): ``` $ read -s -p "Type your new PIN: " PIN $ read -s -p "Type your new PUK: " PUK $ yubico-piv-tool -a change-pin -P 123456 -N $PIN $ yubico-piv-tool -a change-puk -P 12345678 -N $PUK ``` Upload the user's certificate onto the Yubikey: ``` $ read -s -p "Type the user's certificate password: " PASS $ yubico-piv-tool -s 9a -a import-key -a import-cert -a set-chuid -i user_cert.pfx -K PKCS12 -p $PASS -k $KEY ``` Verify that the user's certificate is installed: ``` $ yubico-piv-tool -a status ``` Clean the KEY, PIN, PUK and PASS from the environment (or simply exit the shell): ``` $ unset KEY PIN PUK PASS ``` The following commands are showing other potentially useful tasks. If we by accident block the PIN (3 unsuccessful attempts), we can unblock it with the PUK: ``` $ yubico-piv-tool -a unblock-pin -N $PIN --pin $PUK ``` If the PUK is blocked (3 unsuccessful attempts), the PIV applet will be blocked and we need to reset it (see above). We can change the number of attempts for PIN/PUK: ``` $ yubico-piv-tool -a pin-retries --pin-retries=10 --puk-retries=5 -k $KEY ``` We can change the PIN/PUK: ``` $ yubico-piv-tool -a change-pin -P $PIN -N $NEW_PIN $ yubico-piv-tool -a change-puk -P $PUK -N $NEW_PUK ``` We can extract the public certificate (not the private key) from the Yubikey: ``` $ yubico-piv-tool -a read-certificate -s 9a > ClientCert.pem ``` WiFi ---- In order to connect to the WiFi from Linux, we need to have the user's certificate (see above how to get it). Then we can use either the `.pfx` file directly (not recomended): ``` # Path to the control interface ctrl_interface=/var/run/wpa_supplicant # Allow users from the group wheel to connect to the control interface ctrl_interface_group=wheel # Some more params eapol_version=1 ap_scan=1 fast_reauth=1 update_config=1 # Using the .pfx file (not recomended) network={ ssid="CORPORATE" key_mgmt=WPA-EAP eap=TLS identity="none" # Cert and key from the .pfx file private_key="/path/to/your/user_cert.pfx" # Run wpa_gui or wpa_cli to be asked for the password #private_key_passwd="password" } ``` Or we can use the user's certificate stored on the Yubikey (change the value of `disabled=1` to `0` for the relevant block): ``` # Path to the control interface ctrl_interface=/var/run/wpa_supplicant # Allow users of the group wheel to connect to the interface ctrl_interface_group=wheel # Some more params eapol_version=1 ap_scan=1 fast_reauth=1 update_config=1 # Make the pkcs11 engine available (requires engine_pkcs11 > v0.1.8 and libp11 > v2.8) pkcs11_engine_path=/usr/lib/engines/engine_pkcs11.so # Configure the path to the pkcs11 module required by the pkcs11 engine pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so # Using Yubikey - for wpa_supplicant < v2.4 network={ disabled=1 ssid="CORPORATE" key_mgmt=WPA-EAP eap=TLS identity="none" # Use yubico-piv-tool to read the certificate client_cert="/path/to/your/ClientCert.pem" # Select the right engine engine=1 engine_id="pkcs11" # Use "pkcs11-tool -L" to get the slot number # Use "pkcs11-tool -O" or "pkcs15-tool --list-keys" to get the ID key_id="slot_1-id_01" # Run wpa_gui or wpa_cli to be asked for the PIN - requires patch #pin="password" } # Using Yubikey - for wpa_supplicant >= v2.4 network={ disabled=1 ssid="CORPORATE" key_mgmt=WPA-EAP eap=TLS identity="none" # Use "p11tool --list-tokens | grep =piv" to get the value client_cert="pkcs11:manufacturer=piv_II;id=%01" private_key="pkcs11:manufacturer=piv_II;id=%01" # There is no password so define is as an empty string private_key_passwd="" # Run wpa_gui or wpa_cli to be asked for the PIN - requires patch #pin="password" } ``` It's recommended to keep running `wpa_gui` or `wpa_cli` in order to be asked for the password or PIN interactively. It's more secure than keep the password or PIN written in the `wpa_supplicant.conf` file. In the case of using Yubikey, it's necessary to apply the following patch and re-build the `wpa_supplicant`: ``` diff -u -r a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c --- a/src/eap_peer/eap_tls_common.c 2015-03-15 18:30:39.000000000 +0100 +++ b/src/eap_peer/eap_tls_common.c 2015-08-17 14:29:52.000000000 +0200 @@ -204,6 +204,11 @@ */ os_free(config->pin); config->pin = NULL; + eap_sm_request_pin(sm); + sm->ignore = TRUE; + tls_connection_deinit(data->ssl_ctx, data->conn); + data->conn = NULL; + return -1; } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) { wpa_printf(MSG_INFO, "TLS: Failed to load private key"); /* ``` That will make sure that the PIN is requested via `wpa_gui` or `wpa_cli`. VPN --- VPN is normally used to secure connection to the corporate network. Corporat solution for that are usually supported only for Windows desktops. The only tolerated solution for Linux desktop is by using virtualized Windows guest and tunnel the VPN connection to Linux host. Such solution is usually slow, impractical and mainly huge waste of resources. Therefore it's desirable to have native Linux client. ### Cisco AnyConnect Connection to Cisco AnyConnect VPN is possible with [OpenConnect](http://www.infradead.org/openconnect/) client. The best way how to connect to this device is to use [OpenConnect](http://www.infradead.org/openconnect/) client. The connection is usually secured by an user's certificate and the Cisco Secure Desktop (CSD) policy. CSD is a program which is stored on the VPN device and runs before every connection to verify certain facts about the client device. Full list of parameters sent by the CSD check back to the server can be found on Windows in the AnyConnect client log file (`C:\Users\\AppData\Local\Cisco\Cisco HostScan\log\cscan.log`). Just for information, the proprietary CSD for Linux is stored on the VPN device and can be downloaded like this: ``` # Change i386 to x64 for 64-bit binaries $ for N in $(wget -q -O - https://vpn.company.com/CACHE/sdesktop/hostscan/linux_i386/manifest | sed -r 's/.*\(//;s/\).*//'); do wget -q https://vpn.company.com/CACHE/sdesktop/hostscan/linux_i386/$N; done ``` CSD policy can be configured to deny connections from Linux clients. This can be verified in the policy file: ``` $ wget -q -O - https://vpn.company.com/CACHE/sdesktop/data.xml | grep -A1 'os_check.*linux' | grep denied 1>/dev/null && echo "Linux is denied" || echo "Linux is enabled" ``` If the Linux connection is denied, OpenConnect allows to fake CSD output with a script so the VPN server thinks that the connection was established from a client which is trusted: ``` $ cat <