Key Generation "file open error" Problem with 1.0.6
Ed Suominen
ed@eepatents.com
Wed Dec 26 18:58:02 2001
I am having an intermittent problem (the worst kind to debug!) with GPG
1.0.6 during batch key generation. First, I generate a "vapor key"
(destroyed when the crypto session's over) with TCL (see script copied
below). That step always works, but when I try to --list-keys to get the
hex ID for the newly generated key, after a 2-second delay, I sometimes
(20%?) get the following error:
>Keyinfo Result: gpg: c:/tksec/crypto/pubvapor.gpg: keyring created
>gpg: can't open `c:/tksec/crypto/pubvapor.gpg'
>gpg: enum_keyblocks(open) failed: file open error
"keyinfo" is a TCL procedure that creates a list of GPG key emails + hex ID
codes. (See below.)
My script currently retries the --list-keys operation in hopes of getting
it done, but it seems that once GPG produces the file open error, it can
never get over it. I may have to try deleting the new keyring files
(pubvapor.gpg, secvapor.gpg) on error and redoing the key generation
command. That would probably help, but I'm uncomfortable with this apparent
file locking bug with GPG 1.0.6.
Werner, am I doing something wrong in the scripts, or is this a GPG bug
that can be fixed in 1.0.7?
P.S. - The scripts are part of my free, open-source (but not public domain)
TKSEC package on SourceForge (http://sf.net/projects/tksec) which I'll be
announcing here with the first stable release. I don't have time to go into
the details right now, but briefly, TKSEC uses GPG as a security platform
for a suite of secure communication tools, all conveniently accessible from
a single menu, including voice-over-IP, document transfer, and remote
desktop access. A major benefit is that it uses an FTP command/reply
channel to get around firewalls, and that the "vapor keys" used for
encryption are permanently wiped out after the session. The vapor key
passphrases are pseudorandomly generated and stored only in RAM during the
session. So, no keyboard sniffer or demand for a key can be used to get at
your data after you're done with it.
Best regards,
Ed Suominen
#<<<<<<<<<<<< KEYGEN >>>>>>>>>>>>>>#
proc keygen { nameID emailID pass } {
global tempPath cryptoPath
### Create keygen parameter file
### Key type ElGamal (sign & encrypt) to avoid
### generating two keys. Key length set to 1024
### for quick keygen, reasonable security
set fileData [subst {
Key-Type: 20
Key-Length: 1024
Name-Real: aaa
Name-Email: bbb
Expire-Date: 0
Passphrase: ccc
%pubring [file join $cryptoPath pubvapor.gpg]
%secring [file join $cryptoPath secvapor.gpg]
%commit }]
# Substitute provided values for blanks
regsub aaa $fileData $nameID fileData
regsub bbb $fileData $emailID fileData
regsub ccc $fileData $pass fileData
# Write file
set tempSpec1 [file join $tempPath [tempfile keygen.txt]]
set fh [open $tempSpec1 w]
puts $fh $fileData
close $fh
set err1 1; set err2 1
while { $err1 || $err2 } {
### Have GnuPG Generate the key
saymsg "Generating Crypto Key Pair" cmd
set waitMsg "One Moment: ~~~~~~~~~~~"
set err1 [catch \
{exec [file join $cryptoPath gpg] --batch --gen-key
$tempSpec1 &} pid]
# Wait for pid of GPG to go away
while { [ lsearch [winlist] [list * [format 0x%04x $pid]] ] >= 0 } {
saymsg [string range $waitMsg 0 34] cmd
regsub {~} $waitMsg + waitMsg
# System-dependent delay, hopefully makes steps match time
per step
# Also, exercises hard disk while the key generation is
using entropy
exec fc C:\\tksec\\tcl\\lib\\tcl8.3\\encoding\\*.* \
C:\\tksec\\tcl\\lib\\tcl8.3\\encoding\\*.*
}
if { $err1 } {
saymsg "Key Generation Error" error
} else {
saymsg "Vapor Key Generated" result
idle 2
set keyID [keyinfo $emailID -vapor]
set err2 [catch {exec [file join $cryptoPath gpg] --batch \
--no-default-keyring --keyring [file join
$cryptoPath pubvapor.gpg] \
--armor --export $keyID \
} key]
}
if { $err2 } {
saymsg "Key Export Error" error
saymsg "Keyinfo Result: $keyID" data
saymsg "Export Result: $key" data
} else {
saymsg "Vapor Key Exported" result
}
### END while loop
}
### Delete tempfiles
catch {file delete $tempSpec1}
### END KEYGEN
return $key
}
#<<<<<<<<<<<< KEYINFO >>>>>>>>>>>>>>#
proc keyinfo { arg {arg2 null} } {
global cryptoPath
### Get raw keylist output
if { [regexp {^-[sS]} $arg2] } {
### -[s]ecret option, use secret keyring
set err [catch {exec $cryptoPath/gpg --list-secret-keys} keyList]
if { $err } {
set arg error
} else {
set keyList [split $keyList \n]
set pat1 {sec\s+[0-9]{3,5}[a-z]\/([a-f0-9]{8})}
}
} elseif { [regexp {^-[vV]} $arg2] } {
### -[v]apor option, use vapor keyring
set err [catch {exec $cryptoPath/gpg \
--no-default-keyring --keyring [file join $cryptoPath
pubvapor.gpg] \
--list-keys} keyList]
if { $err } {
set arg error
} else {
set keyList [split $keyList \n]
set pat1 {pub\s+[0-9]{3,5}[a-z]\/([a-f0-9]{8})}
}
} else {
### No option set, look for one specified public key
set err [catch {exec $cryptoPath/gpg --list-keys} keyList]
if { $err } {
set arg error
} else {
set keyList [split $keyList \n]
set pat1 {pub\s+[0-9]{3,5}[a-z]\/([a-f0-9]{8})}
}
}
### Parse keylist
set pat2 {<([a-z0-9@\.]*)>}
switch -regexp -- $arg {
{error} { ### KeyList contains error output if error above
set result $keyList
}
{^-[lL]} { ### -list option, parse all lines for public key listings
foreach {i} $keyList {
# If this line contains a public key listing,
# add the email userID to the result list
if { [regexp -nocase $pat1 $i] } {
regexp -nocase $pat2 $i match x
lappend result $x
}
}
}
default { ### Process just one matching line, not -list option
### Caution - case sensitive list search
set k [lsearch -regexp $keyList [subst {<$arg>}] ]
if { ($k < 0) || \
( [regexp -nocase $pat1 [lindex $keyList \
[max 0 $k] ] match result] == 0 ) } {
set result -1
}
}
}
### END KEYINFO
return $result
}