1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
#!/bin/bash
# Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
# Date: 2010-12-20 20:54:55-0500
# On a system with keys for https (or some other X.509-using protocol)
# already imported into monkeysphere-host, this script generates X.509
# certificate requests for each key, with appropriate subjectAltNames
# and the PGPExtension embedded.
# The generated requests get dumped to stdout. redirect to a file or
# copy/paste if you want to save them/send them someplace.
# This script uses bashisms
# It currently needs OpenSSL binaries, gpg, and gpgsm to work properly
# It assumes that the monkeysphere-host keyring is in
# /var/lib/monkeysphere/host (which it is on debian)
# This should probably eventually be incorporated into
# monkeysphere-host directly.
get_openssl_config() {
# first param is seconds since the epoch:
X509_PGP_EXTENSION="$(TZ=UTC date -d "@$1" '+%Y%m%d%H%M%SZ')"
# next parameter is SAN names, separated by newlines:
SUBJECTALTNAME=$(printf "%s" "$2" | sed 's/^/DNS:/' | tr '\n' ',' | \
sed -e 's/,*$//' -e 's/^,*//')
printf "sAN: %s\n" "$SUBJECTALTNAME" >&2
cat <<EOF
default_md = sha256
oid_section = new_oids
[ new_oids ]
PGPExtension = 1.3.6.1.4.1.3401.8.1.1
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req # The extensions to add to a certificate request
[ req_distinguished_name ]
commonName = Common Name (e.g. www.example.org)
commonName_max = 64
[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = $SUBJECTALTNAME
PGPExtension = ASN1:SEQUENCE:pgp_sect
[ pgp_sect ]
# see https://www.alvestrand.no/objectid/1.3.6.1.4.1.3401.8.1.1.html
# this is equivalent to:
# Version ::= INTEGER { v1(0) }
version = INTEGER:0
# this is the OpenPGP creation timestamp
keyCreation = GENERALIZEDTIME:$X509_PGP_EXTENSION
EOF
}
gencertreq() {
local keyid="$1"
# It would be great to be able to do all of this with gpgsm
# directly. See https://dev.gnupg.org/T4503 for why we need to
# use OpenSSL for now.
local timestamp=$(gpg --fixed-list-mode --with-colons --list-keys "0x$keyid!" | awk -F: '/^pub:/{ print $6 }')
local keygrip=$(gpg --fixed-list-mode --with-keygrip --with-colons --list-keys "0x$keyid!" | awk -F: '/^grp:/{ print $10 }')
local primary
# find all the $proto-using User IDs:
local uids=$(gpg --fixed-list-mode --with-colons --list-keys \&"$keygrip" | \
grep '^uid:' | cut -f10 -d: | \
grep '^'"${proto}"'\\x3a//' | \
sed -r -e 's!^'"${proto}"'\\x3a//!!' -e 's!:[0-9]+$!!')
primary=$(printf "%s" "$uids" | head -n1)
# does gpgsm know about this key?
if ! gpgsm --with-colons --with-keygrip --list-keys \&"$keygrip" | grep -q ^grp: ; then
# ensure that gpgsm has a dummy self-signed cert; otherwise, it
# cannot emit the secret key in the necessary form.
local batchcmd="Key-Type: RSA
Key-Grip: $keygrip
Name-DN: CN=$primary (monkeysphere dummy self-signed)
Serial: $keygrip
%commit"
local dummycert="$(gpgsm --armor --batch --generate-key <<<"$batchcmd")"
gpgsm --import <<<"$dummycert"
fi
printf "Certificate Request for TLS WWW server %s\n[OpenPGP key %s]\n" "$primary" "$keyid"
openssl req -text -new \
-config <(get_openssl_config "$timestamp" "$uids") \
-key <(gpgsm --armor --export-secret-key-raw \&"$keygrip") \
-subj "/CN=${primary}/"
}
export GNUPGHOME=/var/lib/monkeysphere/host
# default to looking for https keys.
proto="${1:-https}"
for fpr in $(gpg --fixed-list-mode --with-colons --fingerprint --list-secret-keys "${proto}://" | awk -F: '/^fpr:/{ if (ok) { print $10 } ; ok=0 } /^sec:/{ ok=1 }'); do
gencertreq "$fpr"
done
|