1

I'm working on an application that will eventually graph the gpg signature connections between a predefined set of email addresses. I need it to programmatically collect the public keys from a key server. I have a working model that will use the --search-keys option to gpg. However, when run with the --batch flag, I get the error "gpg: Sorry, we are in batchmode - can't get input". When I run with out the --batch flag, gpg expects input.

I'm hoping there is some flag to gpg that I've missed. Alternatively, a library (preferably python) that will interact with a key server would do.

Elros
  • 313
  • 1
  • 3
  • 10

5 Answers5

2

Use

gpg --batch --keyserver hkp://pool.sks-keyservers.net --search-keys ...

and parse the output to get key IDs.

After that

gpg --batch --keyserver hkp://pool.sks-keyservers.net  --recv-keys key-id key-id ..

should work

radiospiel
  • 2,450
  • 21
  • 28
0

Use --recv-keys to get the keys without prompting.

user2804197
  • 354
  • 5
  • 13
  • --recv-keys requires the key id. I am attempting to look up a key id by email address. I should note that if --recv-keys would take an email, perform the search, and import any resulting keys it would be the exact option I am looking for. – Elros Jul 18 '14 at 20:18
0

GnuPG is not performing very well anyway when you import very large portions of the web of trust, especially during the import phase.

I'd go for setting up a local keyserver, just dumping all the keys in there (less than 10GB of download size in 2014) and directly querying your own, local keyserver.

Hockeypuck is rather easy to setup and especially query, as it stores the data in a PostgreSQL database.

Jens Erat
  • 37,523
  • 16
  • 80
  • 96
  • In my particular case, I wouldn't have been dealing with more than about 100 keys. However, running a local key server and dealing with the data in that form would likely help quite a bit. I'll give it a try. Thanks! – Elros Jul 21 '14 at 12:41
0

In the case of a hkps server the following would work :

gpg --keyserver hkps://***HKPSDOMAIN*** --recv-keys \
$(curl -s "https://***HKPSDOMAIN***/?op=index&options=mr&search=***SEARCHSTRING***"\
|grep pub|awk -F ":" '{print $2}')
user123456
  • 364
  • 1
  • 3
  • 16
drcursor
  • 126
  • 1
  • 4
0

We can store the std and err output of the gpg --search-keys commands into variables by specifying 2>&1, then do work on those variables. For example, get the public key ids or those with *.amazon.com email addresses:

pubkeyids=$(gpg --batch --keyserver hkp://keyserver.ubuntu.com --search-keys amazon.com 2>&1 | grep -Po '\d+\s*bit\s*\S+\s*key\s*[^,]+' | cut -d' ' -f5)

The regular expression is fully explained on regex101.com. We can automate searching for keys by their IDs and add them to the keyring using bash by parsing that output. As an illustration, I created the following GitHub gist to host the code below.

Example address list example.csv:

First Name Last Name Email Address
Hi Bye hi@bye.com
Yes No yes@no.com
Why Not why@not.com

Then we can pass the csv path to a bash script which will add all keys belonging to the email addresses in the csv:

$ getPubKeysFromCSV.sh ~/example.csv

Here is an implementation of the above idea, getPubKeysFromCSV.sh:

# CSV of email address
csv=$1

# Get headers from CSV
headers=$(head -1 $csv)

# Find the column number of the email address
emailCol=$(echo $headers | tr ',' '\n' | grep -n "Email Address" | cut -d':' -f1)

# Content of the CSV at emailCol column, skipping the first line
emailAddrs=$(tail -n +2 $csv | cut -d',' -f$emailCol)
gpgListPatrn='(?<entropy>\d+)\s*bit\s*(?<algo>\S+)\s*key\s*(?<pubkeyid>[^,]+)'
# Loop through the array and get the public keys
for email in "${emailAddrs[@]}"
do
    # Get the public key ids for the email address by matching the regex gpgListPatt
    pubkeyids=$(gpg --batch --keyserver hkp://keyserver.ubuntu.com --search-keys $email 2>&1 | grep -Po $gpgListPatrn | cut -d' ' -f5)
    # For each public key id, get the public key
    for pubkeyid in $pubkeyids
    do
        # Add the public key to the local keyring
        recvr=$(gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys $pubkeyids 2>&1)
        # Check exit code to see if the key was added
        if [ $? -eq 0 ]; then
            # If the public key is added, do some extra work with it
            # [do stuff] 
        fi
    done
done

If we wanted, we could make getPubKeysFromCSV.sh more complex by verifying a file signature in the body of the loop, after successfully adding the public key. In addition to the CSV path, we will pass the signature path and file path as arguments two and three respectively:

$ getPubKeysFromCSV.sh ~/example.csv ./example.file.sig ./example.file

Here is the updated script difference as a diff:

--- original.sh
+++ updated.sh
@@ -1,6 +1,12 @@
 # CSV of email address
 csv=$1
 
+# signature file
+sig=$2
+
+# file to verify
+file=$3
+
 # Get headers from CSV
 headers=$(head -1 $csv)
 
@@ -22,5 +28,17 @@
         recvr=$(gpg --keyserver hkp://keyserver.ubuntu.com --recv-keys $pubkeyids 2>&1)
        # Check exit code to see if the key was added
+       if [ $? -eq 0 ]; then
+           verify=$(gpg --batch --verify $sig $file 2>&1)
+           # If the signature is verified, announce it was verified
+           # else, print error not verified and exit
+           if [[ $verify =~ "^gpg: Good signature from" ]]; then 
+               echo "$file was verified by $email using $pubkeyid" 
+           else 
+               printf '%s\n' "$file was unable to be verified" >&2
+               exit 1
+           fi
+       fi
     done
 done
Mavaddat Javid
  • 491
  • 4
  • 19