external keystore option?
Mikolaj J. Habryn
dichro-gnupg-devel at rcpt.to
Tue May 16 20:31:06 CEST 2000
>>>>> "MJH" == Mikolaj J Habryn <dichro-gnupg-devel at rcpt.to> writes:
MJH> A comment later in the code suggests that the search
MJH> interface is used preparatory to doing modifications to the
MJH> keystore - is it /only/ used for this?
To answer my own question, this does indeed appear to be the
case. I've attached a patch which implements some basic agent support
for gnupg. Using this and a modified keymgr, I've managed to
sign/verify, and encrypt/decrypt a file using the ssh key I keep on my
Java iButton. This is how I get my kicks.
Observations. The exercise was a little bit gruesome. The keys that
originate with the agent are marked with an is_protected of 23, and
check_secret_key adjusted to not try to checksum them.
In addition, the pubkey_decrypt and pubkey_sign methods look to see
if the secret MPI fields are NULL, and redirect the query to the agent
if so. This is suboptimal, but by the time we hit those queries, we've
lost all the other information about the key.
Just FYI.
m.
-------------- next part --------------
diff --exclude *.orig --exclude TAGS --exclude *.in --exclude *~ -Nru gnupg-1.0.1-orig/cipher/pubkey.c gnupg-work/cipher/pubkey.c
--- gnupg-1.0.1-orig/cipher/pubkey.c Fri Jul 23 22:02:52 1999
+++ gnupg-work/cipher/pubkey.c Tue May 16 18:51:47 2000
@@ -492,6 +492,9 @@
log_mpidump(" data:", data[i] );
}
+ if(!skey[pubkey_get_npkey(algo)])
+ return agent_process(algo, result, *data, skey);
+ else
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo ) {
@@ -526,6 +529,9 @@
log_mpidump(" data:", data );
}
+ if(!skey[pubkey_get_npkey(algo)])
+ return agent_process(algo, resarr, data, skey);
+ else
do {
for(i=0; pubkey_table[i].name; i++ )
if( pubkey_table[i].algo == algo ) {
diff --exclude *.orig --exclude TAGS --exclude *.in --exclude *~ -Nru gnupg-1.0.1-orig/g10/Makefile.am gnupg-work/g10/Makefile.am
--- gnupg-1.0.1-orig/g10/Makefile.am Sun Oct 10 03:23:41 1999
+++ gnupg-work/g10/Makefile.am Tue May 16 15:58:39 2000
@@ -57,6 +57,7 @@
keylist.c \
sig-check.c \
signal.c \
+ agent.c \
helptext.c
gpg_SOURCES = g10.c \
diff --exclude *.orig --exclude TAGS --exclude *.in --exclude *~ -Nru gnupg-1.0.1-orig/g10/agent.c gnupg-work/g10/agent.c
--- gnupg-1.0.1-orig/g10/agent.c Thu Jan 1 10:00:00 1970
+++ gnupg-work/g10/agent.c Tue May 16 19:00:55 2000
@@ -0,0 +1,214 @@
+#include <sys/socket.h>
+#include <sys/un.h>
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX 63
+#endif
+#include <string.h>
+#include <sys/uio.h>
+#include <unistd.h>
+#include <alloca.h>
+#include <stdlib.h>
+
+#include "config.h"
+#include "keydb.h"
+#include "errors.h"
+#include "packet.h"
+
+static int agent_socket;
+
+static unsigned char *hextable = NULL;
+
+int agent_connect(char *path) {
+ struct sockaddr_un sun;
+
+ sun.sun_family = AF_LOCAL;
+ strncpy(sun.sun_path, path, UNIX_PATH_MAX - 1);
+
+ agent_socket = socket(PF_LOCAL, SOCK_STREAM, 0);
+ if(agent_socket < 0)
+ return G10ERR_NETWORK;
+ if(connect(agent_socket, &sun, sizeof(sun)))
+ return G10ERR_OPEN_FILE;
+ return 0;
+}
+
+int agent_read(void *buf, int len) {
+ return read(agent_socket, buf, len);
+}
+
+int agent_write(void *buf, int len) {
+ return write(agent_socket, buf, len);
+}
+
+int agent_enum(KBPOS *kbpos, KBNODE *ret_root) {
+ char buf[600], *ptr, *end;
+ int len = 0, i, algo;
+ PKT_public_key *p;
+ PKT_secret_key *s;
+ PKT_user_id *u;
+ PACKET *t;
+
+ snprintf(buf, 599, "ENUMERATE %ld\r\n", kbpos->offset++);
+ if(agent_write(buf, strlen(buf)) != strlen(buf))
+ return G10ERR_NETWORK;
+ do {
+ int ret;
+
+ ret = agent_read(buf + len, 600 - len);
+ if(ret < 0)
+ return G10ERR_NETWORK;
+ len += ret;
+ if(len < 2)
+ continue;
+ if(buf[len - 1] == '\n' &&
+ buf[len - 2] == '\r')
+ break;
+ } while(len < 600);
+ if(len == 2)
+ return -1;
+ ptr = memchr(buf, ' ', len);
+ if(!ptr)
+ return G10ERR_BAD_PUBKEY;
+ *ptr++ = 0;
+ len -= ptr - buf;
+ algo = string_to_pubkey_algo(buf);
+ end = memchr(ptr, ' ', len);
+ if(!end)
+ return G10ERR_BAD_PUBKEY;
+ *end++ = 0;
+ len -= end - ptr;
+ ptr = end;
+ p = m_alloc_clear(sizeof(*p));
+ s = m_alloc_clear(sizeof(*s));
+ p->pubkey_algo = algo;
+ s->pubkey_algo = algo;
+ for(i = 0; i < pubkey_get_npkey(algo); i++) {
+ end = memchr(ptr, ' ', len);
+ if(!end)
+ return G10ERR_NETWORK; /* leaking MPIs! */
+ *end++ = 0;
+ len -= end - ptr;
+ p->pkey[i] = mpi_alloc(0);
+ mpi_fromstr(p->pkey[i], ptr);
+ s->skey[i] = mpi_copy(p->pkey[i]);
+ ptr = end;
+ }
+ s->is_protected = 23;
+
+ end = memchr(ptr, '\r', len);
+ *end = 0;
+ u = m_alloc_clear(sizeof(*u) + strlen(ptr));
+ u->len = strlen(ptr);
+ strcpy(u->name, ptr);
+
+ t = m_alloc_clear(sizeof(*t));
+ if(kbpos->secret) {
+ t->pkttype = PKT_SECRET_KEY;
+ t->pkt.secret_key = s;
+ } else {
+ t->pkttype = PKT_PUBLIC_KEY;
+ t->pkt.public_key = p;
+ }
+ *ret_root = new_kbnode(t);
+
+ t = m_alloc_clear(sizeof(*t));
+ t->pkttype = PKT_USER_ID;
+ t->pkt.user_id = u;
+ add_kbnode(*ret_root, new_kbnode(t));
+
+ return 0;
+}
+
+unsigned char kmsl_nybble_char(unsigned char c) {
+ switch(c) {
+ case 0:
+ return '0';
+ case 1:
+ return '1';
+ case 2:
+ return '2';
+ case 3:
+ return '3';
+ case 4:
+ return '4';
+ case 5:
+ return '5';
+ case 6:
+ return '6';
+ case 7:
+ return '7';
+ case 8:
+ return '8';
+ case 9:
+ return '9';
+ case 0xa:
+ return 'a';
+ case 0xb:
+ return 'b';
+ case 0xc:
+ return 'c';
+ case 0xd:
+ return 'd';
+ case 0xe:
+ return 'e';
+ case 0xf:
+ return 'f';
+ default:
+ return 0xff;
+ }
+}
+
+void kmsl_genhextable() {
+ int i;
+
+ hextable = malloc(512);
+ for(i = 0; i < 256; i++) {
+ hextable[i * 2] = kmsl_nybble_char(i >> 4);
+ hextable[i * 2 + 1] = kmsl_nybble_char(i & 0xf);
+ }
+}
+
+unsigned char *kmsl_byte_str(unsigned char c) {
+ if(!hextable)
+ kmsl_genhextable();
+ return hextable + 2 * c;
+}
+
+void agent_write_mpi(MPI m) {
+ int len, j, textlen;
+ unsigned char *text, *buf = mpi_get_buffer(m, &len, NULL);
+
+ agent_write("0x", 2);
+ textlen = len * 2;
+ text = alloca(textlen);
+ for(j = 0; j < len; j++)
+ memcpy(text + j * 2, kmsl_byte_str(buf[j]), 2);
+ agent_write(text, textlen);
+ free(buf);
+}
+
+int agent_process(int algo, MPI *ret, MPI data, MPI *skey) {
+ char *end, buf[2000], *alg = pubkey_algo_to_string(algo);
+ int i, r;
+
+ agent_write("PROCESS ", 8);
+ agent_write(alg, strlen(alg));
+ agent_write(" ", 1);
+ for(i = 0; i < pubkey_get_npkey(algo); i++) {
+ agent_write_mpi(skey[i]);
+ agent_write(" ", 1);
+ }
+ agent_write_mpi(data);
+ agent_write("\r\n", 2);
+ r = agent_read(buf, 2000);
+ end = memchr(buf, '\r', r - 1);
+ if(*(end + 1) != '\n')
+ return G10ERR_NETWORK; /* laziness */
+ *end = 0;
+ r -= 2;
+ if(!r)
+ return G10ERR_UNEXPECTED;
+ *ret = mpi_alloc(0);
+ mpi_fromstr(*ret, buf);
+ return 0;
+}
diff --exclude *.orig --exclude TAGS --exclude *.in --exclude *~ -Nru gnupg-1.0.1-orig/g10/agent.h gnupg-work/g10/agent.h
--- gnupg-1.0.1-orig/g10/agent.h Thu Jan 1 10:00:00 1970
+++ gnupg-work/g10/agent.h Tue May 16 17:35:37 2000
@@ -0,0 +1,11 @@
+#ifdef WITH_AGENT
+
+#include "keydb.h"
+
+int agent_connect(char *);
+int agent_read(void *, int);
+int agent_write(void *, int);
+int agent_enum(KBPOS *, KBNODE *);
+int agent_process(int, MPI *, MPI, MPI *);
+
+#endif /* WITH_AGENT */
diff --exclude *.orig --exclude TAGS --exclude *.in --exclude *~ -Nru gnupg-1.0.1-orig/g10/keydb.h gnupg-work/g10/keydb.h
--- gnupg-1.0.1-orig/g10/keydb.h Fri Nov 12 23:49:28 1999
+++ gnupg-work/g10/keydb.h Fri May 12 14:18:09 2000
@@ -58,7 +58,10 @@
enum resource_type {
rt_UNKNOWN = 0,
rt_RING = 1,
- rt_GDBM = 2
+ rt_GDBM = 2,
+#ifdef WITH_AGENT
+ rt_AGENT = 3,
+#endif
};
diff --exclude *.orig --exclude TAGS --exclude *.in --exclude *~ -Nru gnupg-1.0.1-orig/g10/ringedit.c gnupg-work/g10/ringedit.c
--- gnupg-1.0.1-orig/g10/ringedit.c Fri Dec 3 03:30:31 1999
+++ gnupg-work/g10/ringedit.c Tue May 16 16:04:41 2000
@@ -61,7 +61,7 @@
#include "options.h"
#include "main.h"
#include "i18n.h"
-
+#include "agent.h"
@@ -102,7 +102,6 @@
static int do_gdbm_enum( KBPOS *kbpos, KBNODE *ret_root );
#endif
-
static RESTBL *
check_pos( KBPOS *kbpos )
{
@@ -215,6 +214,12 @@
rt = rt_GDBM;
resname += 11;
}
+#ifdef WITH_AGENT
+ else if(strlen(resname) > 12 && !strncmp(resname, "gnupg-agent:", 12)) {
+ rt = rt_AGENT;
+ resname += 12;
+ }
+#endif /* WITH_AGENT */
#ifndef HAVE_DRIVE_LETTERS
else if( strchr( resname, ':' ) ) {
log_error("%s: invalid URL\n", url );
@@ -343,6 +348,23 @@
break;
#endif
+#ifdef WITH_AGENT
+ case rt_AGENT:
+ {
+ if(strlen(resname) == 4 && !strncmp(resname, "$ENV", 4)) {
+ if(!getenv("GNUPG_AGENT")) {
+ rc = G10ERR_GENERAL; /* how do I make this a silent error? */
+ goto leave;
+ }
+ rc = agent_connect(getenv("GNUPG_AGENT"));
+ } else {
+ rc = agent_connect(filename);
+ }
+ if(rc)
+ goto leave;
+ }
+ break;
+#endif /* WITH_AGENT */
default:
log_error("%s: unsupported resource type\n", url );
rc = G10ERR_GENERAL;
@@ -760,6 +782,11 @@
kbpos->offset = 0;
break;
#endif
+#ifdef WITH_AGENT
+ case rt_AGENT:
+ kbpos->offset = 0;
+ break;
+#endif
default: BUG();
}
kbpos->pkt = NULL;
@@ -779,6 +806,11 @@
rc = do_gdbm_enum( kbpos, ret_root );
break;
#endif
+#ifdef WITH_AGENT
+ case rt_AGENT:
+ rc = agent_enum(kbpos, ret_root);
+ break;
+#endif
default: BUG();
}
@@ -803,6 +835,9 @@
kbpos->fp = NULL;
}
break;
+#ifdef WITH_AGENT
+ case rt_AGENT:
+#endif
case rt_GDBM:
break;
case rt_UNKNOWN:
@@ -1826,3 +1861,4 @@
}
#endif /*HAVE_LIBGDBM*/
+
diff --exclude *.orig --exclude TAGS --exclude *.in --exclude *~ -Nru gnupg-1.0.1-orig/g10/seckey-cert.c gnupg-work/g10/seckey-cert.c
--- gnupg-1.0.1-orig/g10/seckey-cert.c Mon Jul 12 22:57:49 1999
+++ gnupg-work/g10/seckey-cert.c Tue May 16 19:01:01 2000
@@ -43,6 +43,8 @@
int i, res;
unsigned nbytes;
+ if(sk->is_protected == 23)
+ return 0;
if( sk->is_protected ) { /* remove the protection */
DEK *dek = NULL;
u32 keyid[4]; /* 4! because we need two of them */
More information about the Gnupg-devel
mailing list