Bridging the airgap

Peter, Werber, As per the IRC discussion - below is a slightly hacked testscript of ours that allows you to abuse a suitable chipcart or yubico PGP card with x509 functionality to `bridge' an airgap during generation where one *also* wants the public key to be transported of the secure initial generation (or renewal of the expiry of the subkeys) by means of a smartcart itself (which you sort of axiomatically need to be able to trust they airgap). I've stripped the test case down somewhat - i.e. the bit that initialises the PGP applet, generates the master and 3 subkeys, moves them to smart cards, etc, etc. Dw. # Reset the card or key; and let it generate a public/private key # pair (as some do not allow the loading of a (ca or signed cert) # without it containing a private key. # #TMPDIR=${TMPDIR:-/tmp} DIR="${TMPDIR}/test-y-0012.$$" mkdir -p "$DIR" || exit 1 ( set -e cd "$DIR" chmod 700 . # Reset the card and generate a small public/private pair. # Then export a CSR we can import again signed. # # We do this as some cards do *not* accept (import) an x509 which is # not related to their own public key (and only acccept the CA key in # a later slot if you work your way up the chain from leaf to top). # yubico-piv-tool -a reset yubico-piv-tool -s 9a -A ECCP256 -a generate > pub.pem yubico-piv-tool -s 9a -S '/CN=foo/' -P 123456 -a verify -a request < pub.pem > pub.csr # Generate a defaultish public/private test pair. # gpg2 --homedir . --batch --passphrase 123456 --quick-generate-key test at test.com gpg2 --homedir . --export test at test.com > gpg.pub.raw # We create a raw OCTED string (sequence of 8 bit values) # of a given lengt. For length we need long form - as # it will be over 127 bytes. We sort of cheat and assume # that 4 bytes will always cut it. # OIDVAL=$( set `wc -c gpg.pub.raw` S=$(printf "%08x" $2 | sed -e 's/\(..\)/:\1/g') # Octed string (raw 8 bit bytes), of given length. # /bin/echo -n DER:04:84$S od -t x1 gpg.pub.raw | while read skip line do if [ ! -z "$line" ]; then set $line for i in $* do /bin/echo -n :$i done fi done ) # We need to provide the OIDs for each of our private # extensions. # cat <<EOM > oids 1.3.6.1.4.1.2692.99.1 geo Location (WGS84) 1.3.6.1.4.1.2692.99.1.1 geoLa Latitude (WGS84) 1.3.6.1.4.1.2692.99.1.2 geoLon Longitude (WGS84) 1.3.6.1.4.1.2692.99.3 imgSHA1 SHA1 of the image 1.3.6.1.4.1.2692.99.4 imgURL URL of the image 1.3.6.1.4.1.2692.99.5 screenURL URL of a medical DICOM screen 1.3.6.1.4.1.2692.99.6 rawPGP raw (byte) PGP public key file. 2.16.528.1.1003.1.3.2.4.1.1 uziZorgverlenerCA UZI-register, Zorgverlener CA, Royal Kingdom of the Netherlands EOM cat <<EOM > openssl.tmp [default] oid_file=oids [gpgraw] 1.3.6.1.4.1.2692.99.6=$OIDVAL EOM # Create myself a miniature CA. openssl req -new -x509 -out ca.pem -subj /CN=moi/ -nodes # And use that to sign the CSR; and give the signed cert # an extension with our PGP public key. # openssl x509 -req -in pub.csr -CA ca.pem -CAkey privkey.pem -set_serial 01 \ -outform DER -out pub.der \ -extfile openssl.tmp -extensions gpgraw yubico-piv-tool -s 9a -a import-certificate -K DER < pub.der # Now fake an removal of the smart card for 5 seconds. Specifically # for platforms like OSX that can cache things. # set `lsusb | grep Yu | head -1` usbpowerctrl $3 down sleep 5 usbpowerctrl $3 up # Extract again # As we have se the Serial to '01' -- we know what to ask for here. pkcs15-tool --read-certificate 01 | openssl asn1parse -oids oids | grep HEX # ... and pipe it back into GPG. ) E=$? rm -rf "${DIR}" exit $E