Thinkpad X250 - Debian (cont'd)

After my original effort to get Debian to play nice on the X250 there were still a handful of things which weren't right. This mostly covers the remainder of the things that I had trouble with.

Automatically updating timezone based on location

I was recently in Vietnam and had to update my timezone manually - which was a minor inconvenience. There's an app called tzupdate which will attempt to determine your location and update the timezone accordingly whenever you run it. We can create a cron job to run tzupdate regularly to ensure the timezone is updated:

    $ sudo pip install -U tzupdate
    $ sudo crontab -e

enter the following - it'll cause tzupdate to run on the hour, every hour

    0 * * * * tzupdate

Two-fingered scroll left/right

When setting up my touchpad I neglected to setup the left/right scrolling - adding the followng line to /etc/X11/xorg.conf.d/50-synaptics.conf resolves this:

    Option "HorizTwoFingerScroll" "1"

For more info on the Synaptics touchpad driver, as always ArchLinux has some excellent documentation on the subject.

iPhone - Bluetooth and USB tethering 

Connecting over bluetooth is a little funny and can trouble you in unpredictable ways. Basically network manager overwrites /etc/resolv.conf when it connects/disconnects from a network and blueman doesn't touch it. So as you connect/disconnect from networks your bluetooth connection can be effectively useless as it'll be unable to resolve DNS queries (I'm guessing most people go to http://facebook.com and not http://31.13.76.68)

Easiest way is to prevent network manager from touching resolv.conf - and make sure you have a handful of good nameservers you can rely on. To do this edit /etc/NetworkManager/NetworkManager.conf and add the following to the [main] section:

    dns=none

Then add a handful of dns services to  /etc/resolv.conf:

    $ cat > /etc/resolv.conf << RESOLVEND
    #Google Public DNS
    nameserver 8.8.8.8
    nameserver 8.8.4.4
    
    # OpenDNS
    nameserver 208.67.222.222 
    nameserver 208.67.220.220
    RESOLVEND

Connecting over USB is a little easier

    $ sudo modprobe ipheth

If you're having trouble then apparently ipheth sometimes requires the iphone filesystem to be mounted - which means installing ifuse:

    $ sudo apt-get install libimobiledevice-dev libfuse-dev
    $ git clone https://github.com/libimobiledevice/ifuse
    $ cd ifuse/
    $ ./autogen.sh && ./configure && make && sudo make install
    $ mkdir ~/iPhone && sudo ifuse ~/iPhone

Thinkpad X250's Mobile Broadband setup (Vodafone CZ)

I had a bit of a nightmare of a time connecting to Vodafone using the builtin 4G modem. I think the main thing is that most places on the internet say that for pre-paid SIM you should set the APN to "ointernet" - when actually "internet" is correct. However I did find that I needed to set prefer_mbim to Y for the device:

    $ sudo echo "options cdc_ncm prefer_mbim=Y" >> /etc/modprobe.d/cdc_ncm.conf
You can either setup the connection using the NetworkManager UI and make it match the below:
... or manually create a file in /etc/NetworkManager/system-connections/ like the below:
    $ sudo cat /etc/NetworkManager/system-connections/Vodafone\ CZ
    [connection]
    id=Vodafone CZ
    uuid=2756323d-e364-49dc-9d86-92b8c2a44d15
    type=gsm
    autoconnect=false
    permissions=
    secondaries=

    [gsm]
    apn=internet
    number=*99***1#
    password-flags=1
    pin=1234

    [serial]
    baud=115200

    [ipv4]
    dns=8.8.8.8;
    dns-search=
    method=auto
 
    [ipv6]
    addr-gen-mode=stable-privacy
    dns-search=
    ip6-privacy=0
    method=auto

XTerm looks weird in XFCE

I've since moved nearly full-time to using Xmonad, but when I go back to XFCE and try to use xterm it has an extremely tiny font:

To make them appear a little nicer we need to edit ~/.Xresources - so that it looks like the below

Then fix up .Xresources:

    $ cat .Xresources 
    XTerm*faceName: Source Code Pro
    XTerm*faceSize: 10
    XTerm*metaSendsEscape: true
    ! Fonts {{{
    Xft.antialias: true
    Xft.hinting:   true
    Xft.rgba:      rgb
    Xft.hintstyle: hintfull
    Xft.dpi:       120
    ! }}}

After you restart X and relaunch an xterm everything should appear little nicer

Thinkpad X250 - SmartCards and GPG

This post describes setup and example usages of Smartcard with a Thinkpad's onboard reader and OpenPGP to handle keys for authentication and encryption. 

Your master key will be stored (securely I hope) on a USB drive and rarely used, with your Smart Card containing a couple of subkeys which will be used to sign and authenticate day-to-day.

At the end of the guide you should have a master key securely stored on a USB key, a hard-copy of revocation certificate,  some sub-keys stored on your Smart Card and some knowledge about how to use it to emails, and authenticate via ssh:

There are already very technical guides on how to set this up like the one on jclement.ca which steps 1-5 heavily lean on but even if you're pretty tech-savvy you may end up not 100% understanding exactly what you've actually done. 

I got my Smart Card by becoming a member of the EFSF fellowship or by picking up another OpenPGP smartcard (or a YubiKey if you don't have a reader, here).

Step 1. Securely create and boot from a Debian Live USB image

Download and verify a Debian live image per my previous guide here. We can now flash the USB key we're going to boot from:

    $ sudo dd bs=4M if=./debian-live-8.3.0-amd64-xfce-desktop+nonfree.iso of=/dev/sdb && sync
    272+0 records in
    272+0 records out
    1140850688 bytes (1.1 GB) copied, 214.052 s, 5.3 MB/s
Yes I used a very slow USB flash drive and it was rather painful.

Step 2. Setup the packages

Next couple of sections are pretty much the same steps as the jclement.ca guide - install gnupg2 and libraries we'll use:
    $ sudo apt-get install haveged gnupg2 gnupg-agent libpth20 pinentry-curses libccid pcscd scdaemon libksba8 paperkey opensc jpegoptim xloadimage
Change the configuration file for GnuPG so that it uses a different, stronger set of ciphers by default:
    $ mkdir ~/.gnupg
    $ cat > ~/.gnupg/gpg.conf << !
    no-emit-version
    no-comments
    keyid-format 0xlong
    with-fingerprint
    use-agent
    personal-cipher-preferences AES256 AES192 AES CAST5
    personal-digest-preferences SHA512 SHA384 SHA256 SHA224
    cert-digest-algo SHA512
    default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
    !

At this point jclement.ca advise that you disconnect from the network - which is probably a good idea since we're about to generate a handful of keys and we don't want anything to leak. 

What we're going to do is create a Master Key - which will be stored on a USB drive - and then use it to create a handful of Sub Keys which will be stored on the Smart Card for day-to-day use. Since the Sub Keys could conceivably be compromised we'll generate a revocation certificate which we can use to notify everyone that they should no longer be trusted - at this point we'd generate a new set of Sub Keys and load them onto our card.

Since there are a number of utilities and technologies you may not be familiar with I'm going to show a diagram at the end of each step in the key-creation process to help visualise what exactly is going on where. Here's a little diagram showing what symbols I'll be using.

Step 3. Creating the Master Key

    $ gpg2 --gen-key
    gpg (GnuPG) 2.0.26; Copyright (C) 2013 Free Software Foundation, Inc.
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    
    gpg: keyring `/home/sean/.gnupg/secring.gpg' created
    gpg: keyring `/home/sean/.gnupg/pubring.gpg' created
    Please select what kind of key you want:
       (1) RSA and RSA (default)
       (2) DSA and Elgamal
       (3) DSA (sign only)
       (4) RSA (sign only)
    Your selection? 4
    RSA keys may be between 1024 and 4096 bits long.
    What keysize do you want? (2048) 4096
    Requested keysize is 4096 bits
    Please specify how long the key should be valid.
             0 = key does not expire
            = key expires in n days
          w = key expires in n weeks
          m = key expires in n months
          y = key expires in n years
    Key is valid for? (0) 0
    Key does not expire at all
    Is this correct? (y/N) y
    
    GnuPG needs to construct a user ID to identify your key.
    
    Real name: Sean McLemon
    Email address: sean.mclemon@gmail.com
    Comment: 
    You selected this USER-ID:
        "Sean McLemon "
    
    Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? O
    You need a Passphrase to protect your secret key.
    
    We need to generate a lot of random bytes. It is a good idea to perform
    some other action (type on the keyboard, move the mouse, utilize the
    disks) during the prime generation; this gives the random number
    generator a better chance to gain enough entropy.
    gpg: /home/sean/.gnupg/trustdb.gpg: trustdb created
    gpg: key 0xC87419541EAC16A8 marked as ultimately trusted
    public and secret key created and signed.
    
    gpg: checking the trustdb
    gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
    gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
    pub   4096R/0xC87419541EAC16A8 2016-04-01
          Key fingerprint = D90B 2575 6FD3 D781 A856  9AE3 C874 1954 1EAC 16A8
    uid                 [ultimate] Sean McLemon 
    
    Note that this key cannot be used for encryption.  You may want to use
    the command "--edit-key" to generate a subkey for this purpose.

And add a pic:

    $ gpg2 --edit-key 0xC87419541EAC16A8
    gpg (GnuPG) 2.0.26; Copyright (C) 2013 Free Software Foundation, Inc.
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    
    Secret key is available.
    
    pub  4096R/0xC87419541EAC16A8  created: 2016-04-01  expires: never       usage: SC  
                                   trust: ultimate      validity: ultimate
    [ultimate] (1). Sean McLemon 
    
    gpg> addphoto
    
    Pick an image to use for your photo ID.  The image must be a JPEG file.
    Remember that the image is stored within your public key.  If you use a
    very large picture, your key will become very large as well!
    Keeping the image close to 240x288 is a good size to use.
    
    Enter JPEG filename for photo ID: test.jpg
    Is this photo correct (y/N/q)? y
    
    You need a passphrase to unlock the secret key for
    user: "Sean McLemon "
    4096-bit RSA key, ID 0xC87419541EAC16A8, created 2016-04-01
    
    
    pub  4096R/0xC87419541EAC16A8  created: 2016-04-01  expires: never       usage: SC  
                                   trust: ultimate      validity: ultimate
    [ultimate] (1). Sean McLemon 
    [ unknown] (2)  [jpeg image of size 746]
    
    gpg> save
So now we've got a Master Key our live distro's temporary filesystem. As I mentioned before this should only ever live on a USB key - to do anything useful we'll need to generate some Sub Keys.

Step 4. Creating the Sub Keys

A bit of a better explanation of Sub Keys is at https://wiki.debian.org/Subkeys. Remember, these are the keys we'll be using day-to-day and will be stored on our Smart Card.

    $ gpg2 --expert --edit-key 0xC87419541EAC16A8
    gpg (GnuPG) 2.0.26; Copyright (C) 2013 Free Software Foundation, Inc.
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    
    Secret key is available.
    
    gpg: checking the trustdb
    gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
    gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
    pub  4096R/0xC87419541EAC16A8  created: 2016-04-01  expires: never       usage: SC  
                                   trust: ultimate      validity: ultimate
    [ultimate] (1). Sean McLemon 
    [ultimate] (2)  [jpeg image of size 746]
    
    gpg> addkey
    Key is protected.
    
    You need a passphrase to unlock the secret key for
    user: "Sean McLemon "
    4096-bit RSA key, ID 0xC87419541EAC16A8, created 2016-04-01
    
    Please select what kind of key you want:
       (3) DSA (sign only)
       (4) RSA (sign only)
       (5) Elgamal (encrypt only)
       (6) RSA (encrypt only)
       (7) DSA (set your own capabilities)
       (8) RSA (set your own capabilities)
    Your selection? 4
    RSA keys may be between 1024 and 4096 bits long.
    What keysize do you want? (2048) 2048
    Requested keysize is 2048 bits
    Please specify how long the key should be valid.
             0 = key does not expire
            = key expires in n days
          w = key expires in n weeks
          m = key expires in n months
          y = key expires in n years
    Key is valid for? (0) 6m
    Key expires at Wed 28 Sep 2016 21:41:58 CEST
    Is this correct? (y/N) y
    Really create? (y/N) y
    We need to generate a lot of random bytes. It is a good idea to perform
    some other action (type on the keyboard, move the mouse, utilize the
    disks) during the prime generation; this gives the random number
    generator a better chance to gain enough entropy.
    
    pub  4096R/0xC87419541EAC16A8  created: 2016-04-01  expires: never       usage: SC  
                                   trust: ultimate      validity: ultimate
    sub  2048R/0x191900DBF062921B  created: 2016-04-01  expires: 2016-09-28  usage: S   
    [ultimate] (1). Sean McLemon 
    [ultimate] (2)  [jpeg image of size 746]
    
    gpg> addkey
    Key is protected.
    
    You need a passphrase to unlock the secret key for
    user: "Sean McLemon "
    4096-bit RSA key, ID 0xC87419541EAC16A8, created 2016-04-01
    
    Please select what kind of key you want:
       (3) DSA (sign only)
       (4) RSA (sign only)
       (5) Elgamal (encrypt only)
       (6) RSA (encrypt only)
       (7) DSA (set your own capabilities)
       (8) RSA (set your own capabilities)
    Your selection? 6
    RSA keys may be between 1024 and 4096 bits long.
    What keysize do you want? (2048) 2048
    Requested keysize is 2048 bits
    Please specify how long the key should be valid.
             0 = key does not expire
            = key expires in n days
          w = key expires in n weeks
          m = key expires in n months
          y = key expires in n years
    Key is valid for? (0) 6m
    Key expires at Wed 28 Sep 2016 21:42:14 CEST
    Is this correct? (y/N) y
    Really create? (y/N) y
    We need to generate a lot of random bytes. It is a good idea to perform
    some other action (type on the keyboard, move the mouse, utilize the
    disks) during the prime generation; this gives the random number
    generator a better chance to gain enough entropy.
    
    pub  4096R/0xC87419541EAC16A8  created: 2016-04-01  expires: never       usage: SC  
                                   trust: ultimate      validity: ultimate
    sub  2048R/0x191900DBF062921B  created: 2016-04-01  expires: 2016-09-28  usage: S   
    sub  2048R/0x46BDB50E980A2B9B  created: 2016-04-01  expires: 2016-09-28  usage: E   
    [ultimate] (1). Sean McLemon 
    [ultimate] (2)  [jpeg image of size 746]
    
    gpg> addkey
    Key is protected.
    
    You need a passphrase to unlock the secret key for
    user: "Sean McLemon "
    4096-bit RSA key, ID 0xC87419541EAC16A8, created 2016-04-01
    
    Please select what kind of key you want:
       (3) DSA (sign only)
       (4) RSA (sign only)
       (5) Elgamal (encrypt only)
       (6) RSA (encrypt only)
       (7) DSA (set your own capabilities)
       (8) RSA (set your own capabilities)
    Your selection? 8
    
    Possible actions for a RSA key: Sign Encrypt Authenticate 
    Current allowed actions: Sign Encrypt 
    
       (S) Toggle the sign capability
       (E) Toggle the encrypt capability
       (A) Toggle the authenticate capability
       (Q) Finished
    
    Your selection? s
    
    Possible actions for a RSA key: Sign Encrypt Authenticate 
    Current allowed actions: Encrypt 
    
       (S) Toggle the sign capability
       (E) Toggle the encrypt capability
       (A) Toggle the authenticate capability
       (Q) Finished
    
    Your selection? e
    
    Possible actions for a RSA key: Sign Encrypt Authenticate 
    Current allowed actions: 
    
       (S) Toggle the sign capability
       (E) Toggle the encrypt capability
       (A) Toggle the authenticate capability
       (Q) Finished
    
    Your selection? a
    
    Possible actions for a RSA key: Sign Encrypt Authenticate 
    Current allowed actions: Authenticate 
    
       (S) Toggle the sign capability
       (E) Toggle the encrypt capability
       (A) Toggle the authenticate capability
       (Q) Finished
    
    Your selection? q
    RSA keys may be between 1024 and 4096 bits long.
    What keysize do you want? (2048) 
    Requested keysize is 2048 bits
    Please specify how long the key should be valid.
             0 = key does not expire
            = key expires in n days
          w = key expires in n weeks
          m = key expires in n months
          y = key expires in n years
    Key is valid for? (0) 6m
    Key expires at Wed 28 Sep 2016 21:42:43 CEST
    Is this correct? (y/N) y
    Really create? (y/N) y
    We need to generate a lot of random bytes. It is a good idea to perform
    some other action (type on the keyboard, move the mouse, utilize the
    disks) during the prime generation; this gives the random number
    generator a better chance to gain enough entropy.
    
    pub  4096R/0xC87419541EAC16A8  created: 2016-04-01  expires: never       usage: SC  
                                   trust: ultimate      validity: ultimate
    sub  2048R/0x191900DBF062921B  created: 2016-04-01  expires: 2016-09-28  usage: S   
    sub  2048R/0x46BDB50E980A2B9B  created: 2016-04-01  expires: 2016-09-28  usage: E   
    sub  2048R/0xF1D25AD8AC008AA1  created: 2016-04-01  expires: 2016-09-28  usage: A   
    [ultimate] (1). Sean McLemon 
    [ultimate] (2)  [jpeg image of size 746]
    
    gpg> save

Now we've got the newly created Master and Sub-keys on the local filesystem. 

Step 5. Generate a revocation certificate

    $ gpg2 --gen-revoke 0xC87419541EAC16A8
    
    sec  4096R/0xC87419541EAC16A8 2016-04-01 Sean McLemon 
    
    Create a revocation certificate for this key? (y/N) y
    Please select the reason for the revocation:
      0 = No reason specified
      1 = Key has been compromised
      2 = Key is superseded
      3 = Key is no longer used
      Q = Cancel
    (Probably you want to select 1 here)
    Your decision? 1
    Enter an optional description; end it with an empty line:
    > FSB got hold of my private key
    > 
    Reason for revocation: Key has been compromised
    y
    Is this okay? (y/N) y
    
    You need a passphrase to unlock the secret key for
    user: "Sean McLemon "
    4096-bit RSA key, ID 0xC87419541EAC16A8, created 2016-04-01
    
    ASCII armored output forced.
    Revocation certificate created.
    
    Please move it to a medium which you can hide away; if Mallory gets
    access to this certificate he can use it to make your key unusable.
    It is smart to print this certificate and store it away, just in case
    your media become unreadable.  But have some caution:  The print system of
    your machine might store the data and make it available to others!
    -----BEGIN PGP PUBLIC KEY BLOCK-----
    Comment: A revocation certificate should follow
    
    iQIgBCABCgAKBQJW/s+XAx0CeQAKCRDIdBlUHqwWqEsbEACFj7ZDRgwcvG99F1Hb
    PHzqGPXh5X04nnjpPbnWaKviycvdCQtFT3N3Hg0c1fmgBBDMXHXKcP8dBwrsgmU0
    x1vEFUSmzvaW+s/EZXh8xwfXhGVmBG+H+i5JqfiPXelaKH12/pDPqIIE+jlwFx5O
    a+I3TMg5x5pBzpSWmCNmFgxU4jEJ6SBwsYYDCwGjStS3C8Dojk7RfJug/+wZAhk2
    nuGbHKeL48TmLwVsoqlbut57yUzqJ16wC9u46oOwKUeUnluEhOm8eT8fvQsHwM11
    THx8UshfjY1/2p5oA4e7GOyB93u7mS5+u57dkKiHwDbNKVq++rMnJH5nesgOT3f6
    D/5quHjQNUXwGJsxu3H+ZSxAmmj2q8ooaPZfDxeAqSgjLSu3vTQGK8HtsnJ3Cgu5
    tANW4SrDrqqvmpNzutGkmfLRgN/stSLi+MJz78h87nCDPQkMUmp6fEk2kEnVmj1B
    BEMY5SSrJrIDGwf4CGn4kzHDb9/GlS47x33LcE8g7F1lM1LQ7eNvRNpDU36dmiwj
    luJLtl0tKVW4YBz4Yo7AxmT0QYSCgXHWStt9XB1devps1CJ45dlbPNzAE8rJH2+1
    3YjZfFAgiSFFHMsq0C1M2+mQaqrAyGUVT/lR42Tok0GgwaZK48VWeP+cRZu07NDr
    pxodVfJ7TjcVUF04AEtSxayfbg==
    =ck5O
    -----END PGP PUBLIC KEY BLOCK-----
    
JClement suggests printing this out - if you do so it might want to create a QR code to make it easier to digitize. You might want avoid QR code generator sites since we're aiming for security, but you can generate one easily enough using python qrcode module:
    $ pip install qrcode
    Downloading/unpacking qrcode
      Downloading qrcode-5.2.2-py2.py3-none-any.whl (89kB): 89kB downloaded
    Requirement already satisfied (use --upgrade to upgrade): colorama in /usr/lib/python2.7/dist-packages (from qrcode)
    Requirement already satisfied (use --upgrade to upgrade): six in /usr/lib/python2.7/dist-packages (from qrcode)
    Installing collected packages: qrcode
    Successfully installed qrcode
    Cleaning up...
    $ python
    Python 2.7.9 (default, Mar  1 2015, 12:57:24) 
    [GCC 4.9.2] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import qrcode
    >>> cert = open("revoke_cert.asc")
    >>> cert_text = cert.read()
    >>> cert_qr = qrcode.make(cert_text)
    >>> cert_qr.save("revoke_cert.png")
The certificate itself is pretty sizeable, so the resulting QR code is pretty dense and you'll need a reasonable camera to successfully scan it (my iPhone 6S worked nicely). Using the lines above the resulting image will look a little like this - it's a little huge so I didn't want to include it in-line.

So assuming we've printed out revoke_cert.png and discarded the .asc file, at this point we should have created:

Step 6. Backup GPG and store keys on SD/USB

Now we've generated our keys we can copy them somewhere safe (an SD card, or USB)
    $ tar -czf gnupg.tgz ~/.gnupg
    tar: Removing leading `/' from member names
    $ gpg2 -a --export-secret-key 0xC87419541EAC16A8 >> 0xC87419541EAC16A8.master.key
    $ gpg2 -a --export-secret-subkeys 0xC87419541EAC16A8 >> 0xC87419541EAC16A8.subkeys.key
    $ gpg2 -a --export 0xC87419541EAC16A8 > 0xC87419541EAC16A8.public.key.asc
    $ sudo cp gnupg.tgz 0xC87419541EAC16A8.master.key 0xC87419541EAC16A8.subkeys.key 0xC87419541EAC16A8.public.key.asc /media/SDCARD/

Note - it is important to do this. Once we restart the filesystem of the live CD will no longer exist, and we'll lose all of our keys. then load the subkeys to the card.

Now we can distribute the key:

    $ gpg2 --keyserver hkp://pool.sks-keyservers.net --send-keys 0xC87419541EAC16A8
    gpg: sending key 0xC87419541EAC16A8 to hkp server pool.sks-keyservers.net

Now we can reboot, upload our public key to the internet and here's what we have - a master key stored offline/disconnected, a set of sub-keys on the smartcard we can use for everyday tasks, a printed certificate we can use to revoke our subkeys, and a public key somewhere on the net we can share with anyone we need to communicate securely with.

Step 7. Boot into usual OS + load keys

When you're sufficiently certain you've got a nice backup of the .gnupg directory, and the subkeys loaded to the card we can boot into our normal OS and remove the live USB card. 

We'll need to 

    $ gpg2 --import 0xC87419541EAC16A8.public.key.asc
    gpg: /home/sean/.gnupg/trustdb.gpg: trustdb created
    gpg: key C3969A6B: public key "Sean McLemon " imported
    gpg: Total number processed: 1
    gpg:               imported: 1  (RSA: 1)
Now everything is set - we explore a few situations where you might want to use a smart card.

Example 1. Signing/Encrypting a text file using your card

There's a very good guide produced by the Free Software Foundation @ https://emailselfdefense.fsf.org which you can follow if you want to use EnigMail and Thunderbird - if you want an easy way to sign/encrypt emails you should follow that. However if we just want to sign a message in a text file from the command line, we could do something like the below

    $ echo > msg << EOF
    > paddy schwartz party time
    > EOF
    $ gpg2 --output msg.sig --sign msg

Example 2. Decrypting a file using your card

If someone's sent you a file they'll encrypt it using your public key. You can use the keys stored on your card to decrypt it.

To set this up we'll first encrypt a simple text file using our own public key:

    $ echo "a funky test message" > plaintext.asc
    $ gpg2 --out cyphertext --recipient 0x2F3F79CDC3969A6B --encrypt plaintext.asc
    gpg: 720D24AD: There is no assurance this key belongs to the named user
    
    pub  2048R/720D24AD 2016-03-24 Sean McLemon 
     Primary key fingerprint: 63EB 6DF3 C42E 1AB3 92B5  BF02 2F3F 79CD C396 9A6B
          Subkey fingerprint: 3E3C 084E 622A BB06 EEFB  A739 A3FE 2BC1 720D 24AD

    It is NOT certain that the key belongs to the person named
    in the user ID.  If you *really* know what you are doing,
    you may answer the next question with yes.

    Use this key anyway? (y/N) y

OK now we'll verify that the card isn't connected, and that we cannot decrypt it without the card

    $ gpg2 --card-status
    gpg: selecting openpgp failed: Card not present
    gpg: OpenPGP card not available: Card not present
    $ gpg2 --out plaintext-decrypted.asc --decrypt cyphertext 
    gpg: selecting openpgp failed: Card not present
    gpg: encrypted with 2048-bit RSA key, ID 720D24AD, created 2016-03-24
          "Sean McLemon "
    gpg: public key decryption failed: Operation cancelled
    gpg: decryption failed: No secret key

Now if we insert the smart card and try to decrypt again we'll be prompted for our PIN, and the file will be decrypted successfully:

    $ gpg2 --out plaintext-decrypted.asc --decrypt cyphertext
    gpg: encrypted with 2048-bit RSA key, ID 720D24AD, created 2016-03-24
          "Sean McLemon "
    $ cat plaintext-decrypted.asc 
    a funky test message

Example 3. Authenticating with a remote machine using your card

    $ echo enable-ssh-support >> ~/.gnupg/gpg-agent.conf
    $ sudo emacs /etc/X11/Xsession.options # and comment/remove the line "use-ssh-agent"

Now we'll add our public key to the computer we want to connect to using ssh - in my case it's mokpo.local

    $ ssh-add -L | ssh mokpo.local 'cat >> ~/.ssh/authorized_keys'
and we can now test logging in

Example 4. Revoking your keys using the QR code

If our key is ever compromised and we'd like to revoke we will need to issue a revocation certificate to say that this key shouldn't ever be trusted. We can use the QR code we previously generated + printed out - first scan the QR code and save the results into a file revoke-certificate-qr.txt, and perform the following steps:

$ gpg2 --import revoke-certificate-qr.txt
$ gpg2 --keyserver hkp://pool.sks-keyservers.net --send-keys 0xC87419541EAC16A8

Now the world should know not to trust our old keypair, and we can go back to the start of this article and generate a completely new one - this time being extra careful to keep it safe!

Linux - networking without a UI using nmcli

The XMonad setup I described in this blog post should be functional and extendable enough to get started. However there is one glaring omission - no easy way to configure any wifi or 3G/4G networks you want to connect to. So it's useful to know a little about nmcli, the command-line interface to NetworkManager. This can also be useful if you're futzing around with a linux box remotely.

Fire up an xterm and run the following to check out which network interfaces you have available, and what state they are in:

    $ nmcli dev status
    DEVICE             TYPE      STATE            CONNECTION  
    cdc-wdm0           gsm       disconnected     -- 
    wlan0              wifi      disconnected     --
    F4:31:C3:30:E3:6F  bt        disconnected     --          
    eth0               ethernet  unavailable      --          
    lo                 loopback  unmanaged        --          

So we've five interfaces, none of which are connected to anything. I'll focus on the extremely common use-cases - connecting to open and secured wifi networks using the "wlan0" device, as well as connecting to 3G/4G networks using the "cdc/wdm0" device.

WiFi

To view available networks near you:

    $ nmcli dev wifi list
    *  SSID       MODE   CHAN  RATE       SIGNAL  BARS  SECURITY         
       Rotor bar  Infra  8     54 Mbit/s  72      ▂▄▆_                   
       ahnet      Infra  11    54 Mbit/s  42      ▂▄__  WEP              
       eduroam    Infra  1     54 Mbit/s  15      ▂___  WPA1 WPA2 802.1X 
       vakan      Infra  13    54 Mbit/s  12      ▂___  WEP              
       JAMU       Infra  1     54 Mbit/s  10      ▂___                   

If we want to connect to "Rotor bar" - an open, unsecured network, we can do the following

    $ nmcli device wifi connect "Rotor bar"
    Device 'wlan0' successfully activated with 'ccb0a5a1-ef8d-4fea-966f-7999f2611345'.

If this network was instead secured with the password "123456789" we would instead have used:

    $ nmcli dev wifi con "Rotor bar" password "123456789"

And when we want to disconnect from the WiFi, we can run:

    $ nmcli dev disconnect iface wlan0

And if we wanted to reconnect to this network:

    $ nmcli con up id "Rotor bar"

Mobile Broadband

We can check if you have already set up a Mobile Broadband (3G, LTE, etc seem to be appear as type "gsm") connection :
    $ nmcli connection show | grep gsm
    Vodafone CZ             2756323d-e364-49dc-9d86-92b8c2a44d15  gsm              --     

In my case I'd previously setup "Vodafone CZ" using the NetworkManager applet in XFCE, however if we want to do this in the CLI all we need to do is make sure a config file is present in the /etc/NetworkManager/system-connections folder which has the right setup

    $ sudo cat /etc/NetworkManager/system-connections/Vodafone\ CZ
    [connection]
    id=Vodafone CZ
    uuid=2756323d-e364-49dc-9d86-92b8c2a44d15
    type=gsm
    autoconnect=false
    permissions=
    secondaries=

    [gsm]
    apn=internet
    number=*99***1#
    password-flags=1
    pin=1234

    [serial]
    baud=115200

    [ipv4]
    dns=8.8.8.8;
    dns-search=
    method=auto
 
    [ipv6]
    addr-gen-mode=stable-privacy
    dns-search=
    ip6-privacy=0
    method=auto

So, assuming you're using Vodafone in the Czech Republic you can use this config, tweak the PIN as necessary (it's the SIM PIN, btw) rerun nmcli connection show to check NetworkManager knows about it, and then run the following to bring it up:

    $ nmcli connection up id "Vodafone CZ"
    Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/27)
And to disconnect
    $ nmcli connection down id "Vodafone CZ"
    Connection 'Vodafone CZ' successfully deactivated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/27)

So there we have it - it's possible there's a strange configuration that you need, so you may have to dig into the nmcli man pages - but as long as you have some sort of internet connection I found the followingpages useful:

XMonad - quickstart and intro

XMonad is a minimalist Window Manager written in Haskell. There are plenty of pretty screenshots of various xmonad setups on the net, but as a newbie it's not clear how to use them or how to get started. Say you find yourself in the  XMonad/Config archive page and find a pretty looking screenshot like NNoel's (below):

You install XMonad, update your .xinitrc, restart X and this is what you actually see:

It's a little intimidating to be confronted with this, and it's really tough to know how to go from "I have a blank screen" to "check out my shiny desktop". There's no easy way to get to a Settings/Configuration menu to customise things, and clicking around achieves very little indeed. Even firing up a web browser to google for some guides isn't very obvious. 

I recently went through this whole process, and managed to piece together a nice simple xmonad config. This is a guide to how to go from blank screen to a setup like the below:

We've got a status bar which shows handy things like workspaces, info about any active network interfaces, the usual cpu/memory usage shenanigans, volume (from a slightly hacky script, more on that later) date and the weather where I am. Also the little Tux emoji in the corner is clickable - by default it saves a screenshot of the whole screen, but you can customise it pretty easily since it's just executing a command in the shell.

To get this sort of setup we first need to make sure a couple of fonts are installed - Source Code Pro and Font Awesome. You could just run the commands below, but if you want could find the latest release of Source Code Pro on this page in case there's any updates:

    $ curl -LO https://github.com/adobe-fonts/source-code-pro/archive/2.010R-ro/1.030R-it.tar.gz
    $ tar -xzf 1.030R-it.tar.gz
    $ git clone https://github.com/FortAwesome/Font-Awesome
    $ sudo cp source-code-pro-2.010R-ro-1.030R-it/TTF/*.ttf Font-Awesome/fonts/*.ttf /usr/share/fonts
    $ fc-cache -f -v

Now we can install the necessary packages that we need:

    $ sudo apt-get install xmonad xmonad-contrib xmobar dmenu cabal-install
    $ cabal install xmonad-extras

Finally we can pull down my xmonad config from github

    $ cd && git clone http://github.com/smcl/xmonad .xmonad

Now all the packages are installed, and the Xmonad config is all setup we can restart X and should see something like this

Still a blank screen, but now we have a little status bar. To start with we can bring up an xterm by hitting Windows-Shift-Return:

Obviously from xterm we can launch whatever app we want from here, like firefox:

We can close windows using either some app-specific functionality (Ctrl-Q in firefox, or typing "exit" in xterm), but you can also close the current selected window from XMonad by holding down Windows-Shift-C.

Launching your apps from an xterm could be a little inconvenient, and the terminal itself could fill up with diagnostic messages unless you remember to redirect stderr to /Dev/null each time. 're squeezed side-by-side it's not ideal, plus your xterm will fill up with all sorts of fun diagnostic messages. A better way to work is to launch them using dmenu - a program we installed earlier that let's us launch applications from within monad easily. To bring up dmenu hit Windows-P, if you start typing it'll attempt to autocomplete programs from your PATH:

I tend to use workspaces to organise my windows - so I'll have firefox running on its own in one, then a couple of xterms in another, emacs on its own somewhere else etc. To create a new workspace and switch to it press Windows-1, Windows-2 ... Windows-9. If you're in, say, workspace 1 and you want to move the current window to workspace 2 you can his Windows-Shift-2.

The location used for the weather status is hardcoded in ~/.xmobar/xmobarrc. It's decided by the first arg to "Run Weather" - in my case I've used LKTB, which is the ICAO code for Brno airport. Find your nearest airport's ICAO code using this page and find/replace both instances of LKTB (there should be two) in the file.

Now that the irritating part of XMonad is out of the way, you can see what else you can do by checking out the XMonad tour or take a look at the cheat-sheet below and experimenting. 

I'd also recommend fiddling around with ~/.xmonad/xmobarrc (documentation is here) adding new items to the status bar. Particularly the "Run Com ..." which let's you run arbitrary commands and will display whatever the output was . The reason it might look a little odd is that it's written in Haskell, so you might want to spent a little time with the excellent Learn You A Haskell to get familiar - but honestly you could get pretty far just copy-pasting existing lines and tinkering with them.

RPi - exposing http and ssh to the internet

This is just a quick guide for my friend Gonza to describe how SSH tunnelling can let you connect to a Raspberry Pi (or any other box running a unix-like OS) from anywhere even if it's behind an internet connection with a dynamic IP. This lets you avoid bothering to set up dyndns or similar. What you need is:

  1. RPi on home network (we'll call this rpi)
  2. remote box running linux, with a known IP address (we'll call this remote)

What we're going to do is establish an SSH connection between rpi and remote that will remain up at all times, and which will re-establish the connection without any user intervention. We'll be authenticating using an SSH key, so if you don't already have one run the following, I think the defaults are ok:

    me@rpi~ $ ssh-keygen -t rsa

And upload it to your remote server, and test it works nicely:

    me@rpi~ $ ssh-copy-id me@remote-server.com
    me@rpi~ $ ssh remote-server.com
    me@remote~ $ 

Next we'll make sure the remote has sshd configured so that as a client connecting via SSH you can specify the ports involved - so open up /etc/ssh/sshd_conf in your favourite editor:

    me@remote~ $ sudo emacs -nw /etc/ssh/sshd_conf
And either uncomment or add the following line:
    GatewayPorts clientspecified
Now that we've got rpi able to connect to remote via SSH we'll setup SSH tunnelling between the two. What this means is that we'll nominate some ports on remote which will have any traffic forwarded directly to some given ports on rpi - in this case I'm using:

type rpi port remote port 
ssh 40022 22
http 40080 8080

This will mean that not only can I SSH to rpi, but there's another one I can use for running, say, some web site or service. To do this we'll use autossh which is responsible for establishing the connection and keeping it up:

    me@rpi~ $ sudo apt-get install autossh
    me@rpi~ $ sudo autossh -Nf -M 40980 -o "PubkeyAuthentication=yes" -o "PasswordAuthentication=no" -i /home/me/.ssh/id_rsa -R remote-server.com:40080:localhost:8080 me@remote-server.com
    me@rpi~ $ sudo autossh -Nf -M 40922 -o "PubkeyAuthentication=yes" -o "PasswordAuthentication=no" -i /home/me/.ssh/id_rsa -R remote-server.com:40022:localhost:22 me@remote-server.com

To test this out, we can run a simple server on our rpi using nc:

    me@rpi~ $ while true; do { echo -e "HTTP/1.1 200 OK\r\n"; date ; uname -a ; echo; echo; } | nc -l 8080; done

And we can cURL the IP address of remote, which will forward the request/response between your laptop and rpi - I've used xxx.yyy.zzz.www in place of the actual IP address:

    me@laptop~ $ curl xxx.yyy.zzz.www:40080
    Sun May  1 13:36:14 UTC 2016
    Linux rpi 3.2.0-4-amd64 #1 SMP Debian 3.2.41-2+deb7u2 x86_64 GNU/Linux
We can try out connecting via SSH:
    me@laptop~ $ ssh me@xxx.yyy.zzz.www -p 40020
    me@rpi~ $ 

To get this command to run after we reboot we can muck around with systemd, or we could create a cron job - the latter is easier, so let's do that:

    $ crontab -e
And enter
    @reboot autossh -Nf -M 40980 -o "PubkeyAuthentication=yes" -o "PasswordAuthentication=no" -i /home/me/.ssh/id_rsa -R remote-server.com:40080:localhost:8080 me@remote-server.com
    @reboot autossh -Nf -M 40922 -o "PubkeyAuthentication=yes" -o "PasswordAuthentication=no" -i /home/me/.ssh/id_rsa -R remote-server.com:40022:localhost:22 me@remote-server.com

And if you want things to be a little easier you could add the following to your ~/.ssh/config:

    Host rpi
        HostName xxx.yyy.zzz.www
        Port 40020
This lets you connect to ssh without having to remember the IP address and port, so you can connect like so:
    me@laptop ~$ ssh me@rpi
    me@rpi ~$

Update, 2016-09-08: There's actually an even simpler way to do this if you don't have a remote machine and a domain, you can expose a tor hidden service. The caveat is that you're only able to access it from within the tor network, which means you won't be able to access it from your iPhone.

Raspberry Pi - Hacking a Canon DSLR shutter release (part 1)

In a previous post I created a simple timed shutter release from an Arduino, and used this to create a couple of time lapse videos. The drawback of this was that changing timing was a little tough - you had to update the source code and reflash the program to the Arduino.

Since I had a Raspberry Pi sitting around with similarly simple programmable GPIO pins I created a simple web frontend. Again hooking up the shutter release involved a pretty simple circuit based around a NPN transistor - I selected a random GPIO pin (pin 12):

The program uses the RPi.GPIO package to take the pictures, and the web frontend is a simple Bootstrap interface served by CherryPy. Currently all you can do is start/stop the timer, change the timing, take a picture ad-hoc.

I wrote this during winter and tried to capture a bit of snowmelt:

Codehttps://github.com/smcl/RPiEOS

Debian - verifying a downloaded ISO image

Part of something I'm doing involved flashing a Debian live image to a USB thumb drive, which is a pretty straightforward process. However this time I realised that I always ignore the little checksum and signature files that sit alongside them and that if I wanted to use them to verify the integrity/security of the image I had no idea how. So here's a quick HOWTO describing the process I followed.

I needed to use a Debian non-free live image since the Thinkpad X250 has an intel wifi device which requires a closed source firmware blob:

    $ wget -c http://cdimage.debian.org/cdimage/unofficial/non-free/cd-including-firmware/8.3.0-live+nonfree/amd64/iso-hybrid/debian-live-8.3.0-amd64-xfce-desktop+nonfree.iso
    $ wget http://cdimage.debian.org/cdimage/unofficial/non-free/cd-including-firmware/8.3.0-live+nonfree/amd64/iso-hybrid/SHA512SUMS.sign
    $ wget http://cdimage.debian.org/cdimage/unofficial/non-free/cd-including-firmware/8.3.0-live+nonfree/amd64/iso-hybrid/SHA512SUMS

Firslty we need to check that the signature of the sha512sum file was created by someone we trust

    $ gpg2 --verify SHA512SUMS.sign SHA512SUMS
    gpg: Signature made Thu 28 Jan 2016 02:07:24 CET
    gpg:                using RSA key 0xDA87E80D6294BE9B
    gpg: Can't check signature: No public key

In this case gpg2 doesn't have any knowledge of the key used to sign this image - 0xDA87E80D6294BE9B. We'll need to retrieve it from the official Debian key server:

    $ gpg2 --keyserver keyring.debian.org --recv-keys 0xDA87E80D6294BE9B
    gpg: requesting key 0xDA87E80D6294BE9B from hkp server keyring.debian.org
    gpg: key 0xDA87E80D6294BE9B: public key "Debian CD signing key " imported
    gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model
    gpg: depth: 0  valid:   1  signed:   0  trust: 0-, 0q, 0n, 0m, 0f, 1u
    gpg: Total number processed: 1
    gpg:               imported: 1  (RSA: 1)

Now we have the key we can check the signature, checksums match the key:

    $ gpg2 --verify SHA512SUMS.sign SHA512SUMS
    gpg: Signature made Thu 28 Jan 2016 02:07:24 CET
    gpg:                using RSA key 0xDA87E80D6294BE9B
    gpg: Good signature from "Debian CD signing key " [unknown]
    gpg: WARNING: This key is not certified with a trusted signature!
    gpg:          There is no indication that the signature belongs to the owner.
    Primary key fingerprint: DF9B 9C49 EAA9 2984 3258  9D76 DA87 E80D 6294 BE9B

So the signature is fine, but since we haven't explicitly trusted this key yet we're getting a warning. I'm about 99% sure this is sufficiently secure. Now that is out of the way we can check the ISO using sha512sum:

    $ sha512sum -c <(grep "debian-live-8.3.0-amd64-xfce-desktop+nonfree.iso$" SHA512SUMS)
    debian-live-8.3.0-amd64-xfce-desktop+nonfree.iso: OK

So everything semes to check out and we can be confident the NSA haven't sneakily compromised the image somehow. Just to quickly summarise - here's what we've done:

  1. downloaded a Debian 8.3 live image, checksums and signature
  2. verified the signature was produced by the Debian organisation, and the signature represents the sha512sum 
  3. verified the ISO matches the sha512sum. 


ESP8266 - writing a Lua module for NodeMCU in C

Previously I wrote a little post about getting the NodeMCU firmware built and flashed to an ESP8266 board, with a couple of simple lua examples to get started. 

This is a follow-on exploring what it takes to add some new functionality to the lua libraries, so you can write slightly more complex or low-level functionality in C/assembly and expose it through a lua interface. So this could be considered a nice practical introduction to the C API section of the Programming in Lua book. 

To keep things simple in the previous post we used a prebuilt binary, but for the modifications we want to make we'll need to get the esp SDK and build NodeMCU from source.

Getting the ESP SDK

There's probably a package floating around with the ESP8266 cross-compiler and libraries (actually the processor is an xtensa lx106), but building it isn't too tough. You can either check the documentation on the project's README.md or (if you're on Debian like me) just run the following:

    $ sudo apt-get install make unrar autoconf automake libtool gcc g++ gperf flex bison texinfo gawk ncurses-dev libexpat-dev python python-serial sed git unzip bash
    $ cd /opt # assuming you have write access here
    $ git clone --recursive https://github.com/pfalcon/esp-open-sdk.git
    $ make

Then add /opt/esp-open-sdk/xtensa-lx106-elf/bin to your PATH and check you can use it:

    $ xtensa-lx106-elf-gcc -dumpmachine
    xtensa-lx106-elf

Building the NodeMCU firmware

Now we've got a working xtensa-lx106 cross-compiler so we can get started on the NodeMCU tools. Change to the directory you want to do development in and checkout the code

    $ cd ~/dev
    $ git clone https://github.com/nodemcu/nodemcu-firmware
    $ cd nodemcu-firmware

We then need to decide what modules to build by editing app/include/user_modules.h and commenting/uncommenting the various macro definitions (LUA_USE_MODULES_NET and friends) to decide what modules will be present. If you want to use the same config built in previous post then this gist can be copy-pasted in.

Once this is done we can build the firmware by calling make, and flash it to the board using make flash:

    $ make && sudo make flash

Creating our module and a simple function - test.identity()

To keep things as clean as possible we'll just create a nice new module - take a look in the app/modules directory and you'll see .c files that roughly match up with the names of the NodeMCU lua modules (take a look at their ReadTheDocs page)

I'm going to very imaginatively use "test" as my module name, so I'll create app/modules/test.c as follows:

And modify my app/include/user_modules.h again so that we include the following definition

    #define LUA_USE_MODULES_TEST

Then rebuild, reflash, reconnect and play about a little to make sure things work as expected:

    > print(test.identity(1))
    1
    > print(test.identity("foo"))
    foo

Take a closer look at test.c - I'll summarise what's going on to the best of my ability. We've defined a function test_identity(lua_State *L), this is the C function we want to expose to the lua environment. Because C and Lua have a slightly different programming model (different type sizes, multiple return value support in Lua etc) the way we pass values from a function call in Lua to our C function is via this lua_State parameter which is a sort of stack:

A major component in the communication between Lua and C is an omnipresent virtual stack. Almost all API calls operate on values on this stack. All data exchange from Lua to C and from C to Lua occurs through this stack

When we want to return values from the C function back to Lua, we push them on the stack and then return an integer which says how many there are. 

We can actually see this in action if we start playing around a bit - when we call this function with more than one arguments you'll get the last one returned - as it'll be at the top of the stack:

    > print(test.identity("foo", "bar", "baz"))
    baz

The way we do this in identity() is by leaving the stack unchanged and saying we return a single value. This will be familiar to anyone who has worked with Forth or other stack machines. Most of the remainder of the file is boilerplate to define our "test" module and the functions available in it - NodeMCU has a handy set of helper macros that let us easily these.

Handling parameters and return values - test.add()

OK now we've got a super-simple example we can move on a little. Let's create a function which accepts two numbers as arguments, adds them together and returns them. In terms of the Lua stack what we want to do is take the top two values, add them together and push the result to the stack. It's better to see this in action - so add this function after test_identity() in test.c:

    // test.add(x,y) - take two values and add them
    static int test_add(lua_State *L) {
      double x = lua_tonumber(L, 1);
      double y = lua_tonumber(L, 2);
      lua_pushnumber(L, x+y);
      return 1;
    } 

It might be a little clearer to see the interaction with the stack here. We read a couple of values (x and y) using lua_tonumber() and then push the result to the stack to be returned using lua_pushnumber(). There are a handful of different functions to get differently typed values from the stack:

    int            lua_toboolean (lua_State *L, int index);
    double         lua_tonumber (lua_State *L, int index);
    const char    *lua_tostring (lua_State *L, int index);
    size_t         lua_strlen (lua_State *L, int index);

And to push different types to the stack to return them there are some more which should be self-explanatory:

    void lua_pushnil (lua_State *L);
    void lua_pushboolean (lua_State *L, int bool);
    void lua_pushnumber (lua_State *L, double n);
    void lua_pushlstring (lua_State *L, const char *s, size_t length);
    void lua_pushstring (lua_State *L, const char *s);
Since we've added a new C function we need to add a new row to the test_map initialiser so that we can call it from lua - so to make sure test_add() can be called using test.add() we'll update it like so:
    static const LUA_REG_TYPE test_map[] = {
      { LSTRKEY( "identity" ),         LFUNCVAL( test_identity ) },
      { LSTRKEY( "add" ),              LFUNCVAL( test_add ) }, // this is our new line
      { LSTRKEY( "__metatable" ),      LROVAL( test_map ) },
      { LNILKEY, LNILVAL }
    };
If we re-build, reflash and reconnect to the ESP8266 we should now be able to call test.add():
    > test.add(1, 2)
    3 
    > test.add(1, test.add(2, 3)
    6

Testing the type of values on the stack - test.add2()

If we're feeling a bit mischevous we could extend this example so we have a sort of overloaded function - we can check the parameter types and perform some different actions depending on them. We can test the types of the arguments using lua_is* functions (we need to include c_stdlib.h, since we're using c_zalloc):
    // test.add2(x,y) - take two values and add them, or take two strings and concat them
    static int test_add2(lua_State *L) {
      if (lua_isnumber(L, 1) && lua_isnumber(L, 2)) {     
        double x = lua_tonumber(L, 1);
        double y = lua_tonumber(L, 2);
        lua_pushnumber(L, x+y);
      } else if (lua_isstring(L, 1) && lua_isstring(L, 2)) {
        const char *s1 = lua_tostring(L, 1);
        const char *s2 = lua_tostring(L, 2);
        char *s = c_zalloc(strlen(s1) + strlen(s2));
        c_sprintf(s, "%s%s", s1, s2);
        lua_pushstring(L, s);
      } else {
        lua_pushnil(L);
      }
      return 1;
    }
Be careful since the lua_isstring is a wee bit cheeky - it appears that if numbers can be parsed as strings in this context. And also note that this would be a pretty nasty way to design a function, but as an illustrative example it's fine. The full complement of these functions below:
    int lua_isnumber (lua_State *L, int index);
    int lua_isstring (lua_State *L, int index);
    int lua_isboolean (lua_State *L, int index);
    int lua_isnil (lua_State *L, int index);
    int lua_isfunction (lua_State *L, int index);

Handling Lua function callbacks - test.ping()

So now we're comfortable with the Lua functions in C we can get into a slightly tougher example. What we want to do is pass a function in and use it as a callback later on. This means interacting with the lua registry - which is a key/value store for Lua objects (way better description can be found here):

As ever a little demonstration is the best way - when we want to test whether element 3 on the stack is a function and if it is store it in the registry:

    int my_ref;
    if (lua_isfunction(L, 3))
        my_ref = luaL_ref(L, LUA_REGISTRYINDEX);

When we want to retrieve the value, we use lua_rawgeti() which will retrieve it and push it to the stack:

    lua_rawgeti(L, LUA_REGISTRYINDEX, my_ref);

So if our lua function is at the top of the stack, we can call it using lua_call():

    int num_args = 1;
    int num_retvals = 0;
    lua_call(gL, num_args, num_retvals);

The second argument to lua_call is used to indicate how many arguments we've pushed to the stack to pass to the function, we're also specifying how many values we expect to be returned.

To tie all this together we can wrap the ping example which comes with lwIP (lwIP is the IP stack used by NodeMCU). It's hard to take each part piece-by-piece so I'm just going to dump the final ping functionality in-place in a GitHub fork which you can access like so:

    $ git clone https://github.com/smcl/nodemcu-firmware
    $ git checkout -b dev origin/dev
    $ make && sudo make flash

The commit in question which demonstrates the changes (there were a handful of lwip headers needing fixed) is here if you want it highlighted.

If we wanted to ping google.com, and for each response print the ping details and flash the ESP8266 board's LED we could write something like this:

    > function ping_recv(bytes, ipaddr, seqno, ttl, ping)
    >> output = string.format("%d bytes from %s: icmp_seq = %d, ttl=%d, time=%d ms", bytes, ipaddr, seqno, ttl, ping)
    >> print(output)
    >> gpio.mode(4, gpio.OUTPUT)
    >> gpio.write(4, gpio.LOW) 
    >> tmr.alarm(0, 50, tmr.ALARM_SINGLE, function() gpio.write(4, gpio.HIGH) end)
    >> end
    > test.ping("google.com", 3, ping_recv)
    > 32 bytes from 216.58.214.206: icmp_seq = 1, ttl=53, time=14 ms
    32 bytes from 216.58.214.206: icmp_seq = 2, ttl=53, time=14 ms
    32 bytes from 216.58.214.206: icmp_seq = 3, ttl=53, time=14 ms

Conclusion

There's a reason that Lua widely deployed as an extension language - it's very easy to write Lua and it only takes a medium-sized blog post to describe how to create new Lua modules in C. And since C tends to have an FFI for most languages/libraries we can quickly expose a powerful yet lightweight programming interface for almost any application.

However, even though there are a number modules (checkout the ESP8266 page on ReadTheDocs) for different bits of hardware, I'm actually surprised there aren't more given how simple it was to hook all this up.

If you'd like some more in-depth Lua documentation you really cannot go wrong with Programming in Lua. In addition there's a nice quick-reference over at Luai. The homepage might seem a little overwhelming but once you drill into a single section, like Section 4.1 Functions and Types, you see that it's pretty well laid out.

If you'd like to see more complex examples then take a look through the sources in the app/modules directory. They're not so hard to wrap your head around since lwIP and the board's built-in wifi functions do most of the heavy lifting. A lot of what I learned when writing this post was just from scanning through these files.

I'm still keen to spend more time on the ESP8266 - though in some ways for me it's building up a set of skills I'm not sure I'll ever use - but I'm enjoying myself, and if even a single person reads through this and finds it useful it'll have been worth it.

BeagleBone Black - iPhone as keyboard/mouse

Note: I wrote this a while ago specifically for my BeagleBone Black so some of the instructions refer to "opkg" - the package manager used by Ångström Linux. It looks like they've moved on to use Debian instead of Angstrom nowadays, but realistically you can adapt this guide and use the software on any linux distro on any device.

I thought it would be an interesting exercise to use my iPhone as an input device instead of a physical mouse and keyboard. It turns out it's pretty simple, thanks to Tuomas Räsänen's cool python-uinput module together with pybonjour for simple device discovery via Bonjour.

The "server" running on the Beagle and the iOS "client" (bad metaphors, sorry) can be retrieved via git:

$ git clone https://github.com/smcl/iBeagle
$ cd iBeagle

Preparing your Beaglebone Black

First copy the file iBeagle.py file to your beagle.

$ cd iBeagleServer
$ scp iBeagle.py beaglebone.local: # or whatever the username/IP is

Next there's a little bit of setup on the BeagleBone Black is required, as a kernel module and a couple of libraries are required

$ ssh beaglebone.local

Load the "uinput" module. this requires libudev

$ sudo modprobe uinput

The python module for uinput we're using requires udev-systemd, so install via opkg

$ sudo opkg install udev-systemd
$ git clone https://github.com/tuomasjjrasanen/python-uinput.git
$ cd python-uinput && sudo python setup.py install

Ensure avahi-daemon process is up and running

$ ps ax | grep avahi | grep running

Finally setup pybonjour - bonjour library I used for this. If you're having trouble relating to libdns_sd.so see the section "Appendix - udev trouble" at the end.

$ pushd /usr/src
$ wget https://pybonjour.googlecode.com/files/pybonjour-1.1.1.tar.gz
$ pushd pybonjour-1.1.1
$ tar -xzf  pybonjour-1.1.1.tar.gz
$ cd pybonjour-1.1.1
$ python setup.py install

Finally return to your iBeagleServer directory and run the client

$ popd && popd
$ python iBeagle.py

Preparing the iPhone Client

Currently you need to load the application using Xcode, so you'll need an iOS dev account and an iOS device authorised to your account. Open up iBeagleClient/iBeagleClient.xcodeproj, and build + run on your hardware.

When the server is running you should see your BeagleBone Black listed on the table when you launch the app. If not then try restarting the server, or waiting a few seconds.

Appendix - libudev trouble

I actually had a bit of trouble with this step initially. libdns_sd.so was missing, so I retrieved the avahi sources and built my own copy. The libdns_sd.so library was missing on my version of Angstrom Linux, so I built and installed it separately (which is slightly hacky, there's probably a more sensible way to achieve this)

$ wget http://avahi.org/download/avahi-0.6.31.tar.gz
$ tar -xzf avahi-0.6.31.tar.gz && cd avahi-0.6.31

We need to grab some pre-requisites + set PTHREAD_CFLAGS

$ export PTHREAD_CFLAGS='-lpthread'
$ sudo opkg install libssp-dev
$ sudo opkg install libintltool

And run configure so we only build as little as possible to just get the library we want

$ ./configure --disable-static --disable-mono --disable-monodoc --disable-gtk3 --disable-gtk --disable-qt3 --disable-python --disable-qt4 --disable-core-docs --enable-compat-libdns_sd --disable-tests --with-distro=none
$ make

Then (without running make install) we copy libdns_sd.so and libdns_sd.h into /usr/lib and /usr/include respectively

$ cp ./avahi-compat-libdns_sd/.libs/libdns_sd.so /usr/lib
$ cp ./avahi-compat-libdns_sd/dns_sd.h /usr/include

In my case it was trying to use libdns_sd.so.1 - so I also created a symlink to libdns_sd.so.1.

Thinkpad X250 - Debian, XFCE and X.org config

My trusty 2011 Macbook Air started to die recently, and since I'm getting more and more frustrated with OS X (neutering root in El Capitan, for example) I bit the bullet and picked up a Thinkpad X250 on a nice deal and switched to linux full-time. My distro of choice is Debian 8.3 ("Jessie") which is very nice under the hood,but the out-of-the-box UI is a little bit unpolished. Over the last week or so I spent some time bashing it into shape, and since it wasn't so simple I thought I'd share the main steps with anyone else out there.

Display/DPI and Fonts

The first thing is that the X250's screen is 1920x1080 but only 12.5 inches and when you first boot up the text appears to be scaled at 96dpi - and it's pretty tiny. Annoyingly the screen is not high-res enough for the standard HiDPI/Retina approach - scaling everything 2x - to work, everything looks a little too big. Getting something halfway is involves fiddling around with a lot of settings, and this is compounded by the fact that various apps and desktops have different ways of handling it. 

Note that this is mostly for XFCE - some of the other environments look and behave semi-OK (for example Cinnamon is reasonably usable but it eats my battery for breakfast) but I prefer the look and feel of XFCE even if I have to jump through a couple of hoops to get it to play nice.

First thing's first - my display's DPI setting was being incorrectly detected and I didn't have an xorg.conf to modify, so needed to generate one. Logout, switch to a terminal prompt, kill the lightdm process and use Xorg to generate the file:

    $ sudo service lightdm stop
    $ sudo Xorg --configure
    $ sudo cp /root/xorg.conf.new /etc/X11/xorg.conf # or from wherever Xorg created it

Then open up /etc/X11/xorg.conf and edit the Monitor section's DisplaySize - the ThinkPad X250's size in millimetres, so since the X250's screen is 276mm x 155mm we can set it to the following:

    Section "Monitor"
        Identifier "Monitor0"
        VendorName "Monitor Vendor"
        ModelName "Monitor Model"
        DisplaySize 276 155
        Option "DPMS"
    EndSection

After you reboot X11 will have loaded with the correct DPI setting. Things will still look a little wonky - but we're on the right track so sit tight and keep going.

Fixing the XFCE UI element fonts is pretty simple, go to Settings -> Appearance, select the Fonts tab, check the "Custom DPI Setting" box and input 150. 

If you have Chrome or Chromium installed you'll notice that the UI elements and fonts are pretty huge - this is because it's detected that you have a high DPI and has defaulted to scaling things by 2x. You'll need to edit the launcher so that it uses the --force-device-scale-factor to use 1.3 (a number I reached by pure trial-and-error):

Change the following line in /usr/share/applications/google-chrome.desktop:
    Exec=/usr/bin/google-chrome-stable  %U

to 

    Exec=/usr/bin/google-chrome-stable  --force-device-scale-factor=1.3 %U

If you use Chromium you can make a similar change to /usr/share/applications/chromium.desktop. So now Chrome will look a little saner - I also copied over the Times and Helvetica Neue fonts from my Mac and downloaded  Source Code Pro to make things look even better.

Next the login window - we fixed XFCE's DPI but the login window is still using 177, to alter it we need to fix up /etc/lightdm/lightdm-gtk-greeter.conf:

    font-name=Helvetica Neue 8
    xft-antialias=true
    xft-dpi=150
    xft-hintstyle=hintslight
    xft-rgba=rgb
After all this here's what Chrome running with the updated fonts looks like:

Qt fonts

Qt uses some slightly different settings - you need to ensure that ~/.fonts.conf is as appears below:

$ cat ~/.fonts.conf
<!DOCTYPE fontconfig SYSTEM 'fonts.dtd'>
<fontconfig>
    <match target="font" >
        <edit mode="assign" name="hinting" >
            <bool>true</bool>
        </edit>
    </match>
    <match target="font" >
      <edit mode="assign" name="hintstyle" >
	<const>hintslight</const>
      </edit>
    </match>
    <match target="font" >
        <edit mode="assign" name="antialias" >
            <bool>true</bool>
        </edit>
    </match>
</fontconfig>

To keep the layout consistent I opened up Settings -> Qt 4 Settings, went to the fonts tab and set it as follows:

Video Playback

I found that video playback was pretty choppy - to resolve it I had to just uncomment out a single option in xorg.conf:

    Section "Device"
        # ... lots of commented out options
        Option     "TearFree"           "true" # <-- uncomment or add this one
        Identifier  "Card0"
        Driver      "intel"
        BusID       "PCI:0:2:0"
    EndSection

Trackpad

Now that things look a little better we can fix the next couple of things that bothered me. By default there's a little area in the corner with counts as a "right" click that personally I don't use. Disabling it was as simple as commenting out the SoftButtonAreas and SecondarySoftButtonAreas in /etc/X11/xorg.conf.d/50-synaptics.conf

    Section "InputClass"
        Identifier "Default clickpad buttons"
        MatchDriver "synaptics"
        #Option "SoftButtonAreas" "50% 0 82% 0 0 0 0 0"
        #Option "SecondarySoftButtonAreas" "58% 0 0 15% 42% 58% 0 15%"
    EndSection

There's another couple of problems - the trackpad is extremely fast and sensitive by default, and additionally scrolling is too fast and has a sort of inertia that irritates me (I found I'd end up accidentally zooming in/out a lot). Scrolling can be tamed by adding the VertScrollDelta, CoastingSpeed and CoastingFriction sections to the same 50-synaptics.conf file as above, under the Driver "synaptics" section:

    Section "InputClass"
            Identifier "touchpad catchall"
            Driver "synaptics"
            MatchIsTouchpad "on"
    # This option is recommend on all Linux systems using evdev, but cannot be
    # enabled by default. See the following link for details:
    # http://who-t.blogspot.com/2010/11/how-to-ignore-configuration-errors.html
    #       MatchDevicePath "/dev/input/event*"
    	Option "VertScrollDelta" "200"
    	Option "CoastingSpeed" "1"
    	Option "CoastingFriction" "200"
    EndSection

For me adding the MaxSpeed option (which controls pointer sensitivity/speed) to 50-synaptics.conf didn't work, so I added the following to my ~/.xinitrc:

    synclient MaxSpeed=1.0 # it is 2.5 by default

The final touchpad tweak is to prevent it from registering touches as clicks while you're typing. XFCE has a setting that looks like it should work, but it leaves an agonising 2 second delay after you type before it enables the touchpad again. There's a handy utility to alter this which is syndaemon.

    syndaemon -i .2 -K -t -R -d

This can also go  into .xinitrc.

Power Management

By default the power management settings are a bit of a farce - my battery was exhausted after a handful of hours use even though it's pretty hefty. Strangely it seems that power management is still a bit of a ridiculous scene, I'd last operated a Linux laptop back in 2007 - a Thinkpad T40 - and sadly the out-of-the-box power management is pretty dire. There's a handful of useful applications which can help with individually tweaking things - like powertop - but thankfully there's a useful utility called tlp which appears to improve things significantly with only a little config required.

First you need to add the correct depot to your /etc/apt/sources.list - so add the following line to the end

    deb http://repo.linrunner.de/debian DIST main

And install the tlp and thinkpad packages:

    $ sudo apt-key adv --keyserver pool.sks-keyservers.net --recv-keys CD4E8809
    $ sudo apt-get update
    $ sudo apt-get install tlp tlp-rdw acpi-call-dkms

I still find power management a little unreliable - when closing the lid the system doesn't always sleep/suspend, the battery charge is sometimes reported incorrectly (it was stuck at "52%" for a while, which I didn't notice before it died on me). In addition XScreenSaver appears to mess things up too - when I enabled its power management settings it would kill performance after resuming from sleep (with the xorg process consuming >100% of the cpu). Disabling this altogether was fine.

Sound

Sound through the built-in speakers worked out of the box for me. However I have a little Bose Soundlink II bluetooth speaker which I like to use that's a little bit tricky. After pairing in blueman (which weirdly was a little bit trial-and-error) I wasn't sure how to get sound to play out of it. The solution was to install PulseAudio Volume Control, a utility that provides a nice graphical interface to controlling PulseAudio:

    $ sudo apt-get install pavucontrol

Then start the process that's playing the sound - so for me it's Chrome as I was watching Netflix. Open up pavucontrol, switch to the Playback tab find your application and select the bluetooth speaker from the dropdown. 

This being manual is a little bit frustrating but it's actually a minor step-up from OS X - where sometimes some apps wouldn't output sound to the speaker.

Conclusion

After the above tweaks my experience on Debian as a user is roughly on par with OS X (as a developer, it's far better of course). However there are still a number of things I am missing which would make my life a lot better.

  • Expose style window switcher. I know that there's skippy-xd but it is pretty buggy. There's an xfce bounty for this, so if anyone fancies picking up a whopping $70 then go nuts: https://www.bountysource.com/issues/3327306-expose-like-task-switcher-for-xfce
  • Trackpad gestures. I was quite fond of multi-touch gestures in OS X to switch workspaces, I haven't got this working in Linux/X.org just yet and I'm not sure if it's available.
  • AirDrop-style file sharing from iPhone

Hopefully I can pick away at those.