Featured post

Maximize LastPass Security with a Yubikey

While LastPass is very convenient and I want to be as cautious as possible when putting all of my eggs (passwords) in one basket. I have two factor authentication enabled has native YubiKey support as a second authentication factor

Protections:

  • LastPass Premium – alows simple use of unique passwords for each account
  • Typed/Remembered Password – protects from a stolen YubiKey allowing access to your vault
  • YubiKey OTP – Prevents a keylogger from allowing access to your LastPass Vault
  • YubiKey Static Password – ensures your Master Password is strong enough to prevent an attacker from brute forcing your password if they are able dump the LastPass database

What you need:

Setup Your YubiKey

YubiKey Programming Dialog

YubiKey Programming Dialog (not my real password)

  1. Launch the YubiKey Personalization Tool
  2. Select "Static Password Mode"
  3. Click the "Scan Code" button
  4. Select:
    • Configuration Slot 2
    • Program Multiple YubiKeys
    • Keyboard: US Keyboard
  5. Enter a stong password
  6. Insert each YubiKey, and click "Write Configuration"

Configure LastPass

Add YubiKeys to LastPass

Add YubiKeys to LastPass

  1. Open your LastPass Vault and Click Account Settings
  2. If you have not already configured your Yubikey as a second factor
    1. Click Multifactor Options, Scroll down to yubico, Click the pencil
    2. Set Enabled to Yes
    3. If you use iOS, you will want to set Permit Mobile Device Access to Allow, even though it is slightly less secure
    4. Pick which ever option you like for Permit Offline Access. Since you should only be loging in to LastPass from trusted computers, there not much of a security risk
  3. For each of your YubiKeys, put the cursor in a YubiKey box and press the button on the YubiKey
  4. When all of your YubiKeys have been entered, click Update
  5. Under the General tab, Change Master Password. For your new master password, type a good password (it can be your current password), followed by the password in your YubiKey. This is the only time you will have to type the YubiKey password.

Use

Now when you log into LastPass, you will type your password, insert your YubiKey, press the YubiKey button for 2 seconds. The YubiKey will type its portion of your master password and <enter>. LastPass will prompt you for your second factor. Use a short press on the YubiKey button to enter the YubiKey OTP code.

Mobile Protection

Since my iPhone SE is not compatible with YubiKeys, I had to take a different approach. This one phone is the only mobile device allowed to access my account (restricted by UUID). I authorized it using the Google Authenticator app before disabling Google Authenticator. My phone is protected by TouchID and the LastPass app is protected by a PIN. I store the "YubiKey portion" of my master password in NoteCrypt which is proteced by a different/shorter password.

NoteCrypt https://itunes.apple.com/tc/app/notecrypt-encrypted-notes/id897154139 which appears to be developed by Tom King (LinkedIn). While I can’t audit what NoteCrypt actually does, it says all of the right things about encryption and password based key derivation. It also costs $2.99, so there is an economic model that doesn’t involve ads or selling of user data. Finally, the developer’s LinkedIn profile looks respectable.

Common Problems installing a Custom Certificate for RDP

There are a quite a few good guides for configuring your own CA signed certificate for RDP; however, details it’s easy to gloss over and most of the troubleshooting is buried in the comments:

  • Create an RDP certificate with an RSA key. The signing key of the CA does not matter.
  • Create an RDP certificate with the TLS (web) Server EKU, not the Remote Desktop EKU.
  • Add the certificate to the Personal certificate store, not the Remote Desktop certificate store.

Example errors:

Error log when using an RDP certificate with an ECDSA key.

An TLS 1.2 connection request was received from a remote client application, but none of the cipher suites supported by the client application are supported by the server. The TLS connection request has failed.
Schannel with an ECDSA certificate

Windows 10 and Remote Desktop 10 on macOS report an Unknown/Invalid EKU.

Unknown Key Usage
Unknown Key Usage on Windows 10

Set-WmiInstance error trying to use a certificate in the Remote Desktop certificate store.

Set-WmiInstance : Invalid parameter

WMIC error trying to use a certificate in the Remote Desktop certificate store.

wmic error: Description = Invalid namespace

Adding OIDs to XCA

Adding OIDs to XCA is a straightforward process. I was able to follow the official guide at https://hohnstaedt.de/xca-doc/xca-13.html with minimal issues.

First, ensure you download XCA v2.x from the official download page https://hohnstaedt.de/xca/index.php/download. The instructions didn’t make sense at first since I was running xca v1.4.1.

Create a file named “oids.txt” in the user’s XCA directory:

  • Windows: C:\Users\<username>\AppData\Roaming\xca
  • macOS: ~/Library/Application Support/data/xca
  • Linux: ~/.xca
C:\Users\Admin\AppData\Roaming\xca\oids.txt
oids.txt on Windows

Add the OID(s) to oids.txt using the format “<oid> : <short_name> : <long_name>”. In the example below, I added a (Microsoft) Remote Desktop Authentication OID (1.3.6.1.4.1.311.54.1.2):

1.3.6.1.4.1.311.54.1.2: rdpAuth: Remote Desktop Authentication
oids.txt content

Copy the eku.txt file from the XCA installation location to the user’s XCA directory:

  • Windows: C:\Program Files\xca
  • macOS: /Applications/xca.app/Contents/Resources
    This can be accessed through the command line or right clicking on the xca application and selecting “Show Package Contents”
  • Linux: /usr/share/xca or /usr/local/share/xca

Note: The whole file eku.txt file must be copied, because xca only parses the first eku.txt it encounters.

Add a line to the user’s eku.txt referencing your new EKU:

rdpAuth
Add the new EKU to the list of pre-defined EKUs

Close and re-open XCA and your new EKU will be available:

xca: Remote Desktop Authentication EKU
XCA Key Usage Tab

After adding the Remote Desktop Authentication EKU, I found out it is no longer supported/recognized. The Microsoft Remote Desktop 10 app on macOS and Windows 10 both report the EKU as invalid/unknown.

Unknown Key Usage
Unknown Key Usage

Blocking Windows Updates

To block Windows 10 Updates, block lookup of the following domains:

  • *.windowsupdate.microsoft.com
  • *.update.microsoft.com
  • *.windowsupdate.com
  • *.wustat.windows.com
  • *.ntservicepack.microsoft.com
  • *.stats.microsoft.com
  • *.mp.microsoft.com
  • *.data.microsoft.com
  • *.events.data.microsoft.com

This list differs from the lists I’ve been able to find published by Microsoft; notably stats.microsoft.com, mp.microsoft.com, and data.microsoft.com. I developed the list above by watching DNS queries while checking for updates and blocking domain names until the check for updates failed.

Since I’m using Dnsmasq, I’ve added a config file in /etc/dnsmasq.d/ so I can easily disable the blocking when I am ready to install updates:

address=/windowsupdate.microsoft.com/#
address=/update.microsoft.com/#
address=/windowsupdate.com/#
address=/wustat.windows.com/#
address=/ntservicepack.microsoft.com/#
address=/stats.microsoft.com/#
address=/mp.microsoft.com/#
address=/data.microsoft.com/#
address=/events.data.microsoft.com/#

OpenVPN Authentication Script

Edit May 3, 2018: Updated to use a GitHub gist to enable syntax highlighting and added a link to GitHub.

My work related to OpenVPN can be found at https://github.com/tidgubi/openvpn.

I’ve been working on updating my OpenVPN installation and decided I wanted to switch to username/password authentication, so I don’t have to deal with managing client certificates. Personally, I use head -c 32 /dev/urandom | base64 to generate my client passwords, so they are as strong as any certificate authentication. I wrote the following script to perform username/password authentication for OpenVPN using the auth-user-pass-verify option and allow easy management of accounts.

This script uses /etc/openvpn/shadow as its username/password repository. The shadow file must be readable by the OpenVPN process; however, I suggest it is not writable by the OpenVPN process. I have the owner = root and group = openvpn, and permissions 640.

The script takes at least 1 second to verify a password. Passwords are salted with a unique 16 byte value and hashed 100,000 times.

The script works to verify that only one password verification is performed at any time.

Avoid misuse from special characters by Base64 encoding all values in the shadow file.

Usage:

  • ./openvpn-auth.py <credential file> – how the script is invoked by OpenVPN to verify a username and password.
  • ./openvpn-auth.py -a <username> [<password>] – add or update <username>. You will be prompted for a password if you do not provide one on the command line.
  • ./openvpn-auth.py -g <username> [<password>] – generate a string that contians the encoded username, salt, and hashed password. This can be useful if you want to generate strings and add them to the script (list of strings in the shadow_contents variable).
  • ./openvpn-auth.py -d <username> – delete the credentials for <username>.
  • ./openvpn-auth.py -l – list the configured usernames.

openvpn-auth.py

#!/usr/bin/python

# Username/Password Authentication Script for use with OpenVPN
# Copyright (c) 2018 Kenji Yoshino https://www.tidgubi.com
# This script is released under the Version 3 of the GNU General Public
# License https://www.gnu.org/licenses/gpl-3.0.txt

import sys
import os
from hashlib import pbkdf2_hmac
from time import time, sleep
from binascii import b2a_base64, a2b_base64
from getpass import getpass

SHADOW_FILE="/etc/openvpn/shadow"
LOCK_FILE="/dev/shm/openvpn-auth-lock"
HASH="sha256"
ITTERATIONS=100000
BASE_TIME=1.0 # set a minimum time in seconds for check function
SALT_SIZE=16
MAX_UN_PW_LEN=512
MAX_SHADOW_FILE=16384
INVALID=1
VALID=0
# If SHADOW_FILE is None, shadow_contents can be configured as a list of strings
# using the format :: for each line. Each value is base64
# encoded. Strings can be generated using the -g option
shadow_contents=None

def usage():
   print "./openvpn-auth.py "
   print "./openvpn-auth.py -[g|a|d]  [password]"
   print "./openvpn-auth.py -l"

def getHash(salt, password):
   return b2a_base64(pbkdf2_hmac(HASH, password, salt, ITTERATIONS)).strip()

def check(pw_file):
   while os.path.isfile(LOCK_FILE):
      sleep(0.1)
   with open(LOCK_FILE, 'a'):
      start=time()
   rtn=INVALID

   try:
      with open(pw_file, 'r') as f:
         username=b2a_base64(f.readline(MAX_UN_PW_LEN).rstrip("\r\n")).strip() + ":"
         password=f.readline(MAX_UN_PW_LEN).rstrip("\r\n")
         if len(f.readline(MAX_UN_PW_LEN)) > 0:
            return INVALID
   except Exception as e:
      print e
      return INVALID

   try:
      if SHADOW_FILE is not None:
         with open(SHADOW_FILE, 'r') as f:
            shadow_contents=f.readlines(MAX_SHADOW_FILE)
      
      for line in shadow_contents:
         if line.startswith(username):
            parts=line.split(":")
            if len(parts) != 3:
               break
            password=getHash(a2b_base64(parts[1]),password)
            if password == parts[2].strip():
               rtn=VALID
            break
   except Exception as e:
      print e
      rtn=INVALID

   # make this function run in constant time
   t=BASE_TIME-(time()-start)
   if t > 0.0:
      sleep(t)
   
   for x in range(3): #try to remove the lock file 3 times
      try:
         os.remove(LOCK_FILE)
         break
      except Exception:
         continue
   
   return rtn

def delete(username):
   if not os.path.isfile(SHADOW_FILE):
      return
   username=b2a_base64(username).strip() + ":"
   with open(SHADOW_FILE, 'r') as f:
      shadow_contents=f.readlines(MAX_SHADOW_FILE)
   
   with open(SHADOW_FILE, 'w') as f:
      for line in shadow_contents:
         if not line.startswith(username):
            f.write(line);
      f.truncate()

def generate(username, password, add):
   start=time()
   while password is None:
      password=getpass("Enter a password for %s: " % username)
      verifypass=getpass("Verify password: ")
      if password != verifypass:
         print("Passwords do not match. Try again.\n")
         password=None
   salt=os.urandom(SALT_SIZE)
   encusername=b2a_base64(username).strip()
   password=getHash(salt,password)
   salt=b2a_base64(salt).strip()
   #TODO: warn the user if SHADOW_FILE is larger than max shawow length
   if add:
      delete(username)
      with open(SHADOW_FILE, 'a') as f:
         f.write("%s:%s:%s\n" % (encusername, salt, password))
   else:
      print("%f seconds to compute hash" % (time()-start))
      print("%s:%s:%s" % (encusername, salt, password))

def list():
   try:
      if SHADOW_FILE is not None:
         with open(SHADOW_FILE, 'r') as f:
            shadow_contents=f.readlines(MAX_SHADOW_FILE)
      
      for line in shadow_contents:
         parts=line.split(":")
         if len(parts) != 3:
            continue
         print(a2b_base64(parts[0]) + "\n")
   except Exception as e:
      print e

args=len(sys.argv)
if args == 2:
   if sys.argv[1] == "-l":
      list()
   else:
      sys.exit(check(sys.argv[1]))
elif args == 3 or args == 4:
   if sys.argv[1] == "-g" or sys.argv[1] == "-a":
      if sys.argv[1] == "-a" and SHADOW_FILE is None:
         print("Error: You must configure a SHADOW_FILE to use -a.\n")
      else:
         password=None
         if args == 4:
            password=sys.argv[3]
         generate(sys.argv[2], password, sys.argv[1] == "-a")
   elif sys.argv[1] == "-d":
      delete(sys.argv[2])
   else:
      usage()
else:
   usage()

sys.exit(0)

Garmin Forerunner 35 Review

With the loss of the ability to sync with macOS High Sierra and long GPS acquisition times, I figured it was finally time to replace my Garmin Forerunner 305. Since Fitbit is shutting down most Pebble services, I figured I might as well replace my Pebble Time as well. I settled on the Garmin Forerunner 35 as an inexpensive smartwatch and exercise GPS with heart rate monitoring.

After two weeks with the Forerunner 35, I’m satisfied but not thrilled. It’s convenient going to a single device; however, it isn’t as good of a smartwatch or running GPS as the dedicated devices it replaces.

Pros:

  • Great Battery Life – After 10 days and 3×30 minute runs using GPS, the battery is still reading 25%
  • Fast GPS acquisition – When I step outside it’s usually less than 10 seconds to acquire GPS
  • Easy synchronization – synchronizing activities with a phone over Bluetooth is much more convenient than a USB connection

Cons:

  • Limited (almost no) customization:
    • Watch Face – The watch face only shows the battery, time and date. It cannot be customized (other than converting it from digital to analog)
    • Widgets – information screens (notifications, steps, weather, etc.) cannot be reordered
    • Notifications – There is no way to filter notifications. Selecting specific apps to show up on my Pebble was one of my favorite features
    • Exercise information – There are 4 screens of 3 fields for each. Fortunately these can be configured; however, they are not labeled. If you don’t have all screens configured, you still have to scroll through blank screens
  • Controls – Everything is controlled through the 4 physical buttons. There is only a down button for scrolling, so you have to scroll through everything if you hit down an extra time
  • Vibrator – I hear the vibration more than I feel it. I think it sounds cheap