New tool/pageant_proxy_to_gpg.py
authorNIIBE Yutaka <gniibe@fsij.org>
Mon, 21 Jan 2013 03:10:25 +0000 (12:10 +0900)
committerNIIBE Yutaka <gniibe@fsij.org>
Mon, 21 Jan 2013 03:10:25 +0000 (12:10 +0900)
ChangeLog
tool/pageant_proxy_to_gpg.py

index ecb14f5..255bf93 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,6 @@
 2013-01-21  Niibe Yutaka  <gniibe@fsij.org>
 
+       * tool/pageant_proxy_to_gpg.py: New.
        * tool/sexp.py: New.
 
 2013-01-20  Niibe Yutaka  <gniibe@fsij.org>
index 4bd09c9..23d2873 100644 (file)
@@ -1,47 +1,57 @@
 import os, sys, re, hashlib, binascii
 from struct import *
-from gpg_agent imort gpg_agent
+from gpg_agent import gpg_agent
+from sexp import sexp
 
-# Assume it's only OPENPGP.3 key
+# Assume it's only OPENPGP.3 key and it's 2048-bit
 
-def debug(str):
-    print "DEBUG: ", str
+def debug(string):
+    print "DEBUG: %s" % string
     sys.stdout.flush()
 
-def get_keylist(keyinfo_result):
+def get_keygrip_list(keyinfo_result):
     kl_str = keyinfo_result[0:-1] # Chop last newline
     kl = kl_str.split('\n')
     # filter by "OPENPGP.3", and only keygrip
     return [kg.split(' ')[0] for kg in kl if re.search("OPENPGP\\.3", kg)]
 
+# Connect GPG-Agent, and get list of KEYGRIPs.
 g = gpg_agent()
 g.read_line()                   # Greeting message
 
 g.send_command('KEYINFO --list --data\n')
 keyinfo_result = g.get_response()
-kl = get_keylist(keyinfo_result)
-print kl
-
-keygrip = kl[0]
-
-g.send_command('READKEY %s\n' % keygrip)
-key = g.get_response
-pos = key.index("(10:public-key(3:rsa(1:n257:") + 28
-pos_last = key.index(")(1:e3:")
-n = key[pos:pos_last]
-e = key[pos_last+7:pos_last+10]
-if len(n) != 257:
-    raise ValueError(keygrip)
-print binascii.hexlify(n)
-print binascii.hexlify(e)
+keygrip_list = get_keygrip_list(keyinfo_result)
+
+debug(keygrip_list)
+
+keylist = []
+# For each KEYGRIP, get its PUBLIC-KEY.
+for kg in keygrip_list:
+    g.send_command('READKEY %s\n' % kg)
+    key = sexp(g.get_response())
+    # [ "public-key" [ "rsa" [ "n" MODULUS ] [ "e" EXPONENT] ] ]
+    n = key[1][1][1]
+    e = key[1][2][1]
+    debug(binascii.hexlify(n))
+    debug(binascii.hexlify(e))
+    keylist.append([n, e, kg])
+
+# FIXME: should handle all keys, not only a single key
+# FIXME: should support different key size
+n = keylist[0][0]
+e = keylist[0][1]
+keygrip = keylist[0][2]
 
 ssh_rsa_public_blob = "\x00\x00\x00\x07ssh-rsa" + \
     "\x00\x00\x00\x03" + e + "\x00\x00\x01\x01" + n
 
-ssh_key_comment = "key_on_gpg"  # XXX: get login from card?
+ssh_key_comment = "key_on_gpg"  # XXX: get login from card for comment?
 
 import win32con, win32api, win32gui, ctypes, ctypes.wintypes
 
+
+# For WM_COPYDATA structure
 class COPYDATA(ctypes.Structure):
     _fields_ = [ ('dwData', ctypes.wintypes.LPARAM),
                  ('cbData', ctypes.wintypes.DWORD),
@@ -147,17 +157,18 @@ class windows_ipc_listener(object):
             g.send_command('SIGKEY %s\n' % keygrip)
             g.send_command('SETHASH --hash=sha1 %s\n' % hash)
             g.send_command('PKSIGN\n')
-            signature = g.get_response()
-            pos = signature.index("(7:sig-val(3:rsa(1:s256:") + 24
-            signature = "\x00\x00\x00\x07" + "ssh-rsa" + "\x00\x00\x01\x00" + signature[pos:pos+256]
-            siglen = len(signature)
+            sig = sexp(g.get_response())
+            # [ "sig-val" [ "rsa" [ "s" "xxx" ] ] ]
+            sig = sig[1][1][1]
+            sig = "\x00\x00\x00\x07" + "ssh-rsa" + "\x00\x00\x01\x00" + sig # FIXME: should support different key size
+            siglen = len(sig)
             debug("sig_len=%d" % siglen)
-            debug("sig=%s" % binascii.hexlify(signature))
+            debug("sig=%s" % binascii.hexlify(sig))
             pRes = ctypes.cast(pBuf, P_SSH_MSG_SIGN_RESPONSE)
             pRes.contents.msg_len = 1+4+siglen
             pRes.contents.msg_type = 14 # SSH2_AGENT_SIGN_RESPONSE
             pRes.contents.sig_len = siglen
-            ctypes.memmove(pBuf+4+1+4, signature, siglen)
+            ctypes.memmove(pBuf+4+1+4, sig, siglen)
             debug("answer is:")
             debug("   ssh_msg_len: %d" % pSshMsg.contents.msg_len)
             debug("   ssh_msg_type: %d" % pSshMsg.contents.msg_type)