From 4a73d94757f61e4aa2d1841535409622c2c473e3 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 2 Dec 2004 07:48:09 +0000 Subject: [PATCH] First take on a W32 port --- ChangeLog | 6 + agent/gpg-agent.c | 12 +- common/ChangeLog | 9 + common/Makefile.am | 2 + common/fseeko.c | 1 + common/ftello.c | 1 + common/simple-gettext.c | 437 +++++++++++++++++++++++++ common/simple-pwquery.c | 8 + common/strsep.c | 73 +++++ common/util.h | 4 +- common/w32reg.c | 172 ++++++++++ configure.ac | 18 +- jnlib/ChangeLog | 4 + jnlib/logging.c | 4 +- jnlib/types.h | 4 + kbx/ChangeLog | 6 + kbx/Makefile.am | 7 +- kbx/keybox-defs.h | 5 +- kbx/keybox-update.c | 2 +- scd/app-p15.c | 691 ++++++++++++++++++++++++++++++++++++++++ sm/ChangeLog | 7 + sm/gpgsm.c | 44 +-- 22 files changed, 1476 insertions(+), 41 deletions(-) create mode 100644 common/simple-gettext.c create mode 100644 common/strsep.c create mode 100644 common/w32reg.c create mode 100644 scd/app-p15.c diff --git a/ChangeLog b/ChangeLog index 4751d4dca..c95cd9a10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2004-11-26 Werner Koch + + * configure.ac: Replace strsep. Replaced use of "target" by + "host". + + 2004-10-22 Werner Koch Released 1.9.12. diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c index d3d628766..92af49b7a 100644 --- a/agent/gpg-agent.c +++ b/agent/gpg-agent.c @@ -244,12 +244,12 @@ my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr) } -/* Setup the debugging. With a LEVEL of NULL only the active debug - flags are propagated to the subsystems. With LEVEL set, a specific - set of debug flags is set; thus overriding all flags already - set. Note that we don't fail here, because it is important to keep - gpg-agent running even after re-reading the options due to a - SIGHUP. */ +/* Setup the debugging. With the global variable DEBUG_LEVEL set to NULL + only the active debug flags are propagated to the subsystems. With + DEBUG_LEVEL set, a specific set of debug flags is set; thus overriding + all flags already set. Note that we don't fail here, because it is + important to keep gpg-agent running even after re-reading the + options due to a SIGHUP. */ static void set_debug (void) { diff --git a/common/ChangeLog b/common/ChangeLog index d5ded50c9..9224055df 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,12 @@ +2004-11-26 Werner Koch + + * simple-gettext.c: New taken from gnupg 1.3.x + + * simple-pwquery.c [_WIN32]: Include winsock2.h. + (agent_open): Disable it until we have our AF_UNIX implementation + ready. + * fseeko.c, ftello.c: Include sys/types for the sake of W32. + 2004-11-23 Werner Koch * b64enc.c: Include stdio.h and string.h diff --git a/common/Makefile.am b/common/Makefile.am index 64b565cd2..12fdf7b5e 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -41,6 +41,8 @@ libcommon_a_SOURCES = \ iobuf.c iobuf.h \ ttyio.c ttyio.h \ asshelp.c asshelp.h \ + simple-gettext.c \ + w32reg.c \ signal.c \ dynload.h diff --git a/common/fseeko.c b/common/fseeko.c index f151b09ec..06838e4c4 100644 --- a/common/fseeko.c +++ b/common/fseeko.c @@ -22,6 +22,7 @@ #include #endif #include +#include /* Defines off_t under W32. */ int fseeko (FILE *stream, off_t off, int whence) diff --git a/common/ftello.c b/common/ftello.c index e3141900d..6837be959 100644 --- a/common/ftello.c +++ b/common/ftello.c @@ -22,6 +22,7 @@ #include #endif #include +#include /* Defines off_t under W32. */ off_t ftello (FILE *stream) diff --git a/common/simple-gettext.c b/common/simple-gettext.c new file mode 100644 index 000000000..4287606e3 --- /dev/null +++ b/common/simple-gettext.c @@ -0,0 +1,437 @@ +/* simple-gettext.c - a simplified version of gettext. + * Copyright (C) 1995, 1996, 1997, 1999 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +/* This is a simplified version of gettext written by Ulrich Drepper. + * It is used for the Win32 version of GnuPG beucase all the overhead + * of gettext is not needed and we have to do some special Win32 stuff. + * I decided that this is far easier than to tweak gettext for the special + * cases (I tried it but it is a lot of code). wk 15.09.99 + */ + +#include +#ifdef USE_SIMPLE_GETTEXT +#if !defined (_WIN32) && !defined (__CYGWIN32__) +#error This file can only be used under Windows or Cygwin32 +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "util.h" + + +/* The magic number of the GNU message catalog format. */ +#define MAGIC 0x950412de +#define MAGIC_SWAPPED 0xde120495 + +/* Revision number of the currently used .mo (binary) file format. */ +#define MO_REVISION_NUMBER 0 + + +/* Header for binary .mo file format. */ +struct mo_file_header +{ + /* The magic number. */ + u32 magic; + /* The revision number of the file format. */ + u32 revision; + /* The number of strings pairs. */ + u32 nstrings; + /* Offset of table with start offsets of original strings. */ + u32 orig_tab_offset; + /* Offset of table with start offsets of translation strings. */ + u32 trans_tab_offset; + /* Size of hashing table. */ + u32 hash_tab_size; + /* Offset of first hashing entry. */ + u32 hash_tab_offset; +}; + +struct string_desc +{ + /* Length of addressed string. */ + u32 length; + /* Offset of string in file. */ + u32 offset; +}; + + +struct overflow_space_s +{ + struct overflow_space_s *next; + u32 idx; + char d[1]; +}; + +struct loaded_domain +{ + char *data; + int must_swap; + u32 nstrings; + char *mapped; /* 0 = not yet mapped, 1 = mapped, + 2 = mapped to + overflow space */ + struct overflow_space_s *overflow_space; + struct string_desc *orig_tab; + struct string_desc *trans_tab; + u32 hash_size; + u32 *hash_tab; +}; + + +static struct loaded_domain *the_domain; + +static __inline__ u32 +do_swap_u32( u32 i ) +{ + return (i << 24) | ((i & 0xff00) << 8) | ((i >> 8) & 0xff00) | (i >> 24); +} + +#define SWAPIT(flag, data) ((flag) ? do_swap_u32(data) : (data) ) + + +/* We assume to have `unsigned long int' value with at least 32 bits. */ +#define HASHWORDBITS 32 + +/* The so called `hashpjw' function by P.J. Weinberger + [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools, + 1986, 1987 Bell Telephone Laboratories, Inc.] */ + +static __inline__ ulong +hash_string( const char *str_param ) +{ + unsigned long int hval, g; + const char *str = str_param; + + hval = 0; + while (*str != '\0') + { + hval <<= 4; + hval += (unsigned long int) *str++; + g = hval & ((unsigned long int) 0xf << (HASHWORDBITS - 4)); + if (g != 0) + { + hval ^= g >> (HASHWORDBITS - 8); + hval ^= g; + } + } + return hval; +} + + +static struct loaded_domain * +load_domain( const char *filename ) +{ + FILE *fp; + size_t size; + struct stat st; + struct mo_file_header *data = NULL; + struct loaded_domain *domain = NULL; + size_t to_read; + char *read_ptr; + + fp = fopen( filename, "rb" ); + if( !fp ) + return NULL; /* can't open the file */ + /* we must know about the size of the file */ + if( fstat( fileno(fp ), &st ) + || (size = (size_t)st.st_size) != st.st_size + || size < sizeof (struct mo_file_header) ) { + fclose( fp ); + return NULL; + } + + data = malloc( size ); + if( !data ) { + fclose( fp ); + return NULL; /* out of memory */ + } + + to_read = size; + read_ptr = (char *) data; + do { + long int nb = fread( read_ptr, 1, to_read, fp ); + if( nb < to_read ) { + fclose (fp); + free(data); + return NULL; /* read error */ + } + read_ptr += nb; + to_read -= nb; + } while( to_read > 0 ); + fclose (fp); + + /* Using the magic number we can test whether it really is a message + * catalog file. */ + if( data->magic != MAGIC && data->magic != MAGIC_SWAPPED ) { + /* The magic number is wrong: not a message catalog file. */ + free( data ); + return NULL; + } + + domain = calloc( 1, sizeof *domain ); + if( !domain ) { + free( data ); + return NULL; + } + domain->data = (char *) data; + domain->must_swap = data->magic != MAGIC; + + /* Fill in the information about the available tables. */ + switch( SWAPIT(domain->must_swap, data->revision) ) { + case 0: + domain->nstrings = SWAPIT(domain->must_swap, data->nstrings); + domain->orig_tab = (struct string_desc *) + ((char *) data + SWAPIT(domain->must_swap, data->orig_tab_offset)); + domain->trans_tab = (struct string_desc *) + ((char *) data + SWAPIT(domain->must_swap, data->trans_tab_offset)); + domain->hash_size = SWAPIT(domain->must_swap, data->hash_tab_size); + domain->hash_tab = (u32 *) + ((char *) data + SWAPIT(domain->must_swap, data->hash_tab_offset)); + break; + + default: /* This is an invalid revision. */ + free( data ); + free( domain ); + return NULL; + } + + /* Allocate an array to keep track of code page mappings. */ + domain->mapped = calloc( 1, domain->nstrings ); + if( !domain->mapped ) { + free( data ); + free( domain ); + return NULL; + } + + return domain; +} + + +/**************** + * Set the file used for translations. Pass a NULL to disable + * translation. A new filename may be set at anytime. + * WARNING: After changing the filename you should not access any data + * retrieved by gettext(). + */ +int +set_gettext_file( const char *filename ) +{ + struct loaded_domain *domain = NULL; + + if( filename && *filename ) { + if( filename[0] == '/' +#ifdef HAVE_DRIVE_LETTERS + || ( isalpha(filename[0]) + && filename[1] == ':' + && (filename[2] == '/' || filename[2] == '\\') ) +#endif + ) { + /* absolute path - use it as is */ + domain = load_domain( filename ); + } + else { /* relative path - append ".mo" and get dir from the environment */ + char *buf = NULL; + char *dir; + char *p; + + dir = read_w32_registry_string( NULL, + "Control Panel\\Mingw32\\NLS", + "MODir" ); + if( dir && (buf=malloc(strlen(dir)+strlen(filename)+1+3+1)) ) { + strcpy(stpcpy(stpcpy(stpcpy( buf, dir),"\\"), filename),".mo"); + /* Better make sure that we don't mix forward and + backward slashes. It seems that some Windoze + versions don't accept this. */ + for (p=buf; *p; p++) + { + if (*p == '/') + *p = '\\'; + } + domain = load_domain( buf ); + free(buf); + } + free(dir); + } + if( !domain ) + return -1; + } + + if( the_domain ) { + struct overflow_space_s *os, *os2; + free( the_domain->data ); + free( the_domain->mapped ); + for (os=the_domain->overflow_space; os; os = os2) { + os2 = os->next; + free (os); + } + free( the_domain ); + the_domain = NULL; + } + the_domain = domain; + return 0; +} + + +static const char* +get_string( struct loaded_domain *domain, u32 idx ) +{ + struct overflow_space_s *os; + char *p; + + p = domain->data + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset); + if (!domain->mapped[idx]) + { + size_t plen, buflen; + char *buf; + + domain->mapped[idx] = 1; + + plen = strlen (p); + buf = utf8_to_native (p, plen, -1); + buflen = strlen (buf); + if (buflen <= plen) + strcpy (p, buf); + else + { + /* There is not enough space for the translation - store it + in the overflow_space else and mark that in the mapped + array. Because we expect that this won't happen too + often, we use a simple linked list. */ + os = malloc (sizeof *os + buflen); + if (os) + { + os->idx = idx; + strcpy (os->d, buf); + os->next = domain->overflow_space; + domain->overflow_space = os; + p = os->d; + } + else + p = "ERROR in GETTEXT MALLOC"; + } + xfree (buf); + } + else if (domain->mapped[idx] == 2) + { /* We need to get the string from the overflow_space. */ + for (os=domain->overflow_space; os; os = os->next) + if (os->idx == idx) + return (const char*)os->d; + p = "ERROR in GETTEXT\n"; + } + return (const char*)p; +} + + + +const char * +gettext( const char *msgid ) +{ + struct loaded_domain *domain; + size_t act = 0; + size_t top, bottom; + + if( !(domain = the_domain) ) + goto not_found; + + /* Locate the MSGID and its translation. */ + if( domain->hash_size > 2 && domain->hash_tab ) { + /* Use the hashing table. */ + u32 len = strlen (msgid); + u32 hash_val = hash_string (msgid); + u32 idx = hash_val % domain->hash_size; + u32 incr = 1 + (hash_val % (domain->hash_size - 2)); + u32 nstr = SWAPIT (domain->must_swap, domain->hash_tab[idx]); + + if ( !nstr ) /* Hash table entry is empty. */ + goto not_found; + + if( SWAPIT(domain->must_swap, + domain->orig_tab[nstr - 1].length) == len + && !strcmp( msgid, + domain->data + SWAPIT(domain->must_swap, + domain->orig_tab[nstr - 1].offset)) ) + return get_string( domain, nstr - 1 ); + + for(;;) { + if (idx >= domain->hash_size - incr) + idx -= domain->hash_size - incr; + else + idx += incr; + + nstr = SWAPIT(domain->must_swap, domain->hash_tab[idx]); + if( !nstr ) + goto not_found; /* Hash table entry is empty. */ + + if ( SWAPIT(domain->must_swap, + domain->orig_tab[nstr - 1].length) == len + && !strcmp (msgid, + domain->data + SWAPIT(domain->must_swap, + domain->orig_tab[nstr - 1].offset))) + return get_string( domain, nstr-1 ); + } + /* NOTREACHED */ + } + + /* Now we try the default method: binary search in the sorted + array of messages. */ + bottom = 0; + top = domain->nstrings; + while( bottom < top ) { + int cmp_val; + + act = (bottom + top) / 2; + cmp_val = strcmp(msgid, domain->data + + SWAPIT(domain->must_swap, + domain->orig_tab[act].offset)); + if (cmp_val < 0) + top = act; + else if (cmp_val > 0) + bottom = act + 1; + else + return get_string( domain, act ); + } + + not_found: + return msgid; +} + +#if 0 + unsigned int cp1, cp2; + + cp1 = GetConsoleCP(); + cp2 = GetConsoleOutputCP(); + + log_info("InputCP=%u OutputCP=%u\n", cp1, cp2 ); + + if( !SetConsoleOutputCP( 1252 ) ) + log_info("SetConsoleOutputCP failed: %s\n", w32_strerror (0)); + + cp1 = GetConsoleCP(); + cp2 = GetConsoleOutputCP(); + log_info("InputCP=%u OutputCP=%u after switch1\n", cp1, cp2 ); +#endif + +#endif /* USE_SIMPLE_GETTEXT */ diff --git a/common/simple-pwquery.c b/common/simple-pwquery.c index 0bc8128e1..fab6306fa 100644 --- a/common/simple-pwquery.c +++ b/common/simple-pwquery.c @@ -31,8 +31,12 @@ #include #include #include +#ifdef _WIN32 +#include +#else #include #include +#endif #ifdef HAVE_LOCALE_H #include #endif @@ -255,6 +259,9 @@ agent_send_all_options (int fd) static int agent_open (int *rfd) { +#ifdef _WIN32 + return SPWQ_NO_AGENT; /* FIXME */ +#else int rc; int fd; char *infostr, *p; @@ -346,6 +353,7 @@ agent_open (int *rfd) *rfd = fd; return 0; +#endif } diff --git a/common/strsep.c b/common/strsep.c new file mode 100644 index 000000000..af3f02e07 --- /dev/null +++ b/common/strsep.c @@ -0,0 +1,73 @@ +/* strsep.c - Replacement for strsep(). + * Copyright (C) 2002 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include + +/* Code taken from glibc-2.2.1/sysdeps/generic/strsep.c */ +#warning need to get the correct copyright years from glibc +char * +strsep (char **stringp, const char *delim) +{ + char *begin, *end; + + begin = *stringp; + if (begin == NULL) + return NULL; + + /* A frequent case is when the delimiter string contains only one + character. Here we don't need to call the expensive `strpbrk' + function and instead work using `strchr'. */ + if (delim[0] == '\0' || delim[1] == '\0') + { + char ch = delim[0]; + + if (ch == '\0') + end = NULL; + else + { + if (*begin == ch) + end = begin; + else if (*begin == '\0') + end = NULL; + else + end = strchr (begin + 1, ch); + } + } + else + /* Find the end of the token. */ + end = strpbrk (begin, delim); + + if (end) + { + /* Terminate the token and set *STRINGP past NUL character. */ + *end++ = '\0'; + *stringp = end; + } + else + /* No more delimiters; this is the last token. */ + *stringp = NULL; + + return begin; +} + diff --git a/common/util.h b/common/util.h index b9ffe6562..fad7d38cc 100644 --- a/common/util.h +++ b/common/util.h @@ -144,7 +144,9 @@ int is_file_compressed (const char *s, int *ret_rc); int vasprintf (char **result, const char *format, va_list args); int asprintf (char **result, const char *format, ...) JNLIB_GCC_A_PRINTF(2,3); #endif - +#ifndef HAVE_STRSEP +char *strsep (char **stringp, const char *delim); +#endif /*-- some macros to replace ctype ones and avoid locale problems --*/ diff --git a/common/w32reg.c b/common/w32reg.c new file mode 100644 index 000000000..19fb613e7 --- /dev/null +++ b/common/w32reg.c @@ -0,0 +1,172 @@ +/* w32reg.c - MS-Windows Registry access + * Copyright (C) 1999, 2002 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#if defined (_WIN32) || defined (__CYGWIN32__) + /* This module is only used in this environment */ + +#include +#include +#include +#include +#include + +#include "util.h" + +static HKEY +get_root_key(const char *root) +{ + HKEY root_key; + + if( !root ) + root_key = HKEY_CURRENT_USER; + else if( !strcmp( root, "HKEY_CLASSES_ROOT" ) ) + root_key = HKEY_CLASSES_ROOT; + else if( !strcmp( root, "HKEY_CURRENT_USER" ) ) + root_key = HKEY_CURRENT_USER; + else if( !strcmp( root, "HKEY_LOCAL_MACHINE" ) ) + root_key = HKEY_LOCAL_MACHINE; + else if( !strcmp( root, "HKEY_USERS" ) ) + root_key = HKEY_USERS; + else if( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) ) + root_key = HKEY_PERFORMANCE_DATA; + else if( !strcmp( root, "HKEY_CURRENT_CONFIG" ) ) + root_key = HKEY_CURRENT_CONFIG; + else + return NULL; + + return root_key; +} + + +/**************** + * Return a string from the Win32 Registry or NULL in case of + * error. Caller must release the return value. A NULL for root + * is an alias for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. + * NOTE: The value is allocated with a plain malloc() - use free() and not + * the usual m_free()!!! + */ +char * +read_w32_registry_string( const char *root, const char *dir, const char *name ) +{ + HKEY root_key, key_handle; + DWORD n1, nbytes, type; + char *result = NULL; + + if ( !(root_key = get_root_key(root) ) ) + return NULL; + + if( RegOpenKeyEx( root_key, dir, 0, KEY_READ, &key_handle ) ) + { + if (root) + return NULL; /* no need for a RegClose, so return direct */ + /* It seems to be common practise to fall back to HLM. */ + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) ) + return NULL; /* still no need for a RegClose, so return direct */ + } + + nbytes = 1; + if( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) + goto leave; + result = malloc( (n1=nbytes+1) ); + if( !result ) + goto leave; + if( RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ) ) { + free(result); result = NULL; + goto leave; + } + result[nbytes] = 0; /* make sure it is really a string */ + if (type == REG_EXPAND_SZ && strchr (result, '%')) { + char *tmp; + + n1 += 1000; + tmp = malloc (n1+1); + if (!tmp) + goto leave; + nbytes = ExpandEnvironmentStrings (result, tmp, n1); + if (nbytes && nbytes > n1) { + free (tmp); + n1 = nbytes; + tmp = malloc (n1 + 1); + if (!tmp) + goto leave; + nbytes = ExpandEnvironmentStrings (result, tmp, n1); + if (nbytes && nbytes > n1) { + free (tmp); /* oops - truncated, better don't expand at all */ + goto leave; + } + tmp[nbytes] = 0; + free (result); + result = tmp; + } + else if (nbytes) { /* okay, reduce the length */ + tmp[nbytes] = 0; + free (result); + result = malloc (strlen (tmp)+1); + if (!result) + result = tmp; + else { + strcpy (result, tmp); + free (tmp); + } + } + else { /* error - don't expand */ + free (tmp); + } + } + + leave: + RegCloseKey( key_handle ); + return result; +} + + +int +write_w32_registry_string(const char *root, const char *dir, + const char *name, const char *value) +{ + HKEY root_key, reg_key; + + if ( !(root_key = get_root_key(root) ) ) + return -1; + + if ( RegOpenKeyEx( root_key, dir, 0, KEY_WRITE, ®_key ) + != ERROR_SUCCESS ) + return -1; + + if ( RegSetValueEx( reg_key, name, 0, REG_SZ, (BYTE *)value, + strlen( value ) ) != ERROR_SUCCESS ) { + if ( RegCreateKey( root_key, name, ®_key ) != ERROR_SUCCESS ) { + RegCloseKey(reg_key); + return -1; + } + if ( RegSetValueEx( reg_key, name, 0, REG_SZ, (BYTE *)value, + strlen( value ) ) != ERROR_SUCCESS ) { + RegCloseKey(reg_key); + return -1; + } + } + + RegCloseKey( reg_key ); + + return 0; +} + +#endif /* __MINGW32__ || __CYGWIN32__ */ diff --git a/configure.ac b/configure.ac index b0affbbeb..8b6bc4d73 100644 --- a/configure.ac +++ b/configure.ac @@ -343,7 +343,7 @@ GNUPG_CHECK_DOCBOOK_TO_TEXI try_gettext=yes have_dosish_system=no -case "${target}" in +case "${host}" in *-*-mingw32*) # special stuff for Windoze NT ac_cv_have_dev_random=no @@ -660,7 +660,7 @@ fi AC_SUBST(GPGKEYS_MAILTO) -case "${target}" in +case "${host}" in *-*-mingw32*) PRINTABLE_OS_NAME="MingW32" ;; @@ -782,7 +782,7 @@ AC_REPLACE_FUNCS(mkdtemp) AC_REPLACE_FUNCS(fseeko ftello) AC_REPLACE_FUNCS(isascii) AC_REPLACE_FUNCS(putc_unlocked) - +AC_REPLACE_FUNCS(strsep) @@ -970,7 +970,7 @@ GNUPG_CHECK_GNUMAKE # add some extra libs here so that previous tests don't fail for # mysterious reasons - the final link step should bail out. -case "${target}" in +case "${host}" in *-*-mingw32*) W32LIBS="-lwsock32" ;; @@ -1038,6 +1038,14 @@ if test "$build_agent_only" = "yes" ; then build_scdaemon=no fi +# We don't yet want to build some parts for W32 +case "${host}" in + *-mingw32*) + build_gpg=no + ;; +esac + + AM_CONDITIONAL(BUILD_GPG, test "$build_gpg" = "yes") AM_CONDITIONAL(BUILD_GPGSM, test "$build_gpgsm" = "yes") AM_CONDITIONAL(BUILD_AGENT, test "$build_agent" = "yes") @@ -1140,7 +1148,7 @@ AC_OUTPUT echo " GnuPG v${VERSION} has been configured as follows: - Platform: $PRINTABLE_OS_NAME ($target) + Platform: $PRINTABLE_OS_NAME ($host) OpenPGP: $build_gpg S/MIME: $build_gpgsm diff --git a/jnlib/ChangeLog b/jnlib/ChangeLog index 4c52590f5..5ca33d5fb 100644 --- a/jnlib/ChangeLog +++ b/jnlib/ChangeLog @@ -1,3 +1,7 @@ +2004-11-26 Werner Koch + + * logging.c [_WIN32]: Don't include socket headers. + 2004-11-30 Timo Schulz * w32-afunix.c: New. AF_UNIX emulation for W32. diff --git a/jnlib/logging.c b/jnlib/logging.c index 5397a1184..960d816eb 100644 --- a/jnlib/logging.c +++ b/jnlib/logging.c @@ -34,9 +34,11 @@ #include #include #include -#include #include +#ifndef _WIN32 +#include #include +#endif #include #include #include diff --git a/jnlib/types.h b/jnlib/types.h index 230d1502f..934b7a6ee 100644 --- a/jnlib/types.h +++ b/jnlib/types.h @@ -42,7 +42,11 @@ #ifndef HAVE_BYTE_TYPEDEF #undef byte /* maybe there is a macro with this name */ +/* Windows typedefs byte in the rpc headers. Avoid warning about + double definition. */ +#if !(defined(_WIN32) && defined(cbNDRContext)) typedef unsigned char byte; +#endif #define HAVE_BYTE_TYPEDEF #endif diff --git a/kbx/ChangeLog b/kbx/ChangeLog index c10ea126a..ea5b9dbd1 100644 --- a/kbx/ChangeLog +++ b/kbx/ChangeLog @@ -1,3 +1,9 @@ +2004-11-26 Werner Koch + + * Makefile.am (kbxutil_LDADD): Add ../common/libcommon.a + + * keybox-defs.h: Include stringhelp.h. + 2004-09-30 Werner Koch * kbxutil.c (i18n_init): Always use LC_ALL. diff --git a/kbx/Makefile.am b/kbx/Makefile.am index 0b35587cb..ea8436d72 100644 --- a/kbx/Makefile.am +++ b/kbx/Makefile.am @@ -43,11 +43,8 @@ common_sources = \ libkeybox_a_SOURCES = $(common_sources) +# Note that libcommon is only required to resolve the LIBOBJS. kbxutil_SOURCES = kbxutil.c $(common_sources) kbxutil_LDADD = ../jnlib/libjnlib.a $(KSBA_LIBS) $(LIBGCRYPT_LIBS) \ - -lgpg-error @LIBINTL@ - - - - + -lgpg-error $(LIBINTL) ../common/libcommon.a diff --git a/kbx/keybox-defs.h b/kbx/keybox-defs.h index 4906a386e..5724b85a0 100644 --- a/kbx/keybox-defs.h +++ b/kbx/keybox-defs.h @@ -31,8 +31,11 @@ /* We include the type defintions from jnlib instead of defining our owns here. This will not allow us build KBX in a standalone way - but tehre is currently no need for it anyway. */ + but there is currently no need for it anyway. Same goes for + stringhelp.h which for example provides a replacement for stpcpy - + fixme: Better the LIBOBJ mechnism. */ #include "../jnlib/types.h" +#include "../jnlib/stringhelp.h" #include "keybox.h" diff --git a/kbx/keybox-update.c b/kbx/keybox-update.c index 16955502f..eabaa1db2 100644 --- a/kbx/keybox-update.c +++ b/kbx/keybox-update.c @@ -66,7 +66,7 @@ create_tmp_file (const char *template, strcpy (tmpfname + strlen (template)-4, EXTSEP_S "tmp"); } else - { /* file does not end with kbx; hmmm */ + { /* File does not end with kbx; hmmm. */ bakfname = xtrymalloc ( strlen (template) + 5); if (!bakfname) return gpg_error (gpg_err_code_from_errno (errno)); diff --git a/scd/app-p15.c b/scd/app-p15.c new file mode 100644 index 000000000..af2eed465 --- /dev/null +++ b/scd/app-p15.c @@ -0,0 +1,691 @@ +/* app-p15.c - The pkcs#15 card application. + * Copyright (C) 2004 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * GnuPG is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "scdaemon.h" + +#include "iso7816.h" +#include "app-common.h" +#include "tlv.h" + + +/* Context local to this application. */ +struct app_local_s +{ + unsigned short home_df; /* The home DF. Note, that we don't yet + support a multilevel hierachy. Thus we + assume this is directly below the MF. */ + struct + { + unsigned short private_keys; + unsigned short public_keys; + unsigned short trusted_public_keys; + unsigned short secret_keys; + unsigned short certificates; + unsigned short trusted_certificates; + unsigned short useful_certificates; + unsigned short data_objects; + unsigned short auth_objects; + } odf; + + +}; + + + + +/* Do a select and a read for the file with EFID. EFID is a + desctription of the EF to be used with error messages. On success + BUFFER and BUFLEN contain the entire content of the EF. The caller + must free BUFFER but only on success. */ +static gpg_error_t +select_and_read_binary (int slot, unsigned short efid, const char *efid_desc, + unsigned char **buffer, size_t *buflen) +{ + gpg_error_t err; + + err = iso7816_select_file (slot, efid, 0, NULL, NULL); + if (err) + { + log_error ("error selecting %s (0x%04X): %s\n", + efid_desc, efid, gpg_strerror (err)); + return err; + } + err = iso7816_read_binary (slot, 0, 0, buffer, buflen); + if (err) + { + log_error ("error reading %s (0x%04X): %s\n", + efid_desc, efid, gpg_strerror (err)); + return err; + } + return 0; +} + + + + +/* Read and parse the Object Directory File and store away the + pointers. + + Example of such a file: + + A0 06 30 04 04 02 60 34 = Private Keys + A4 06 30 04 04 02 60 35 = Certificates + A5 06 30 04 04 02 60 36 = TrustedCertificates + A7 06 30 04 04 02 60 37 = DataObjects + A8 06 30 04 04 02 60 38 = AuthObjects + + These are all PathOrObjects using the path CHOICE. The paths are + octet strings of length 2. Using this Path CHOICE is recommended, + so we only implement that for now. +*/ +static gpg_error_t +read_ef_odf (app_t app) +{ + gpg_error_t err; + unsigned char *buffer, *p; + size_t buflen; + unsigned short value; + + err = select_and_read_binary (app->slot, 0x5031, "ODF", &buffer, &buflen); + if (err) + return err; + + if (len < 8) + { + log_error ("error: ODF too short\n"); + xfree (buffer); + return gpg_error (GPG_ERR_INV_OBJ); + } + for (p=buffer; buflen >= 8; p += 8, buflen -= 8) + { + if ( (p[0] & 0xf0) != 0xA0 + || memcmp (p+1, "\x06\x30\x04\x04\x02", 5) ) + { + log_error ("ODF format is not supported by us\n"); + xfree (buffer); + return gpg_error (GPG_ERR_INV_OBJ); + } + switch ((p[0] & 0x0f)) + { + case 0: value = app->app_local->odf.private_keys; break; + case 1: value = app->app_local->odf.public_keys; break; + case 2: value = app->app_local->odf.trusted_public_keys; break; + case 3: value = app->app_local->odf.secret_keys; break; + case 4: value = app->app_local->odf.certificates; break; + case 5: value = app->app_local->odf.trusted_certificates; break; + case 6: value = app->app_local->odf.useful_certificates; break; + case 7: value = app->app_local->odf.data_objects; break; + case 8: value = app->app_local->odf.auth_objects; break; + default: value = 0; break; + } + if (value) + { + log_error ("duplicate object type %d in ODF ignored\n",(p[0)&0x0f)); + continue; + } + value = ((p[6] << 8) | p[7]); + switch ((p[0] & 0x0f)) + { + case 0: app->app_local->odf.private_keys = value; break; + case 1: app->app_local->odf.public_keys = value; break; + case 2: app->app_local->odf.trusted_public_keys = value; break; + case 3: app->app_local->odf.secret_keys = value; break; + case 4: app->app_local->odf.certificates = value; break; + case 5: app->app_local->odf.trusted_certificates = value; break; + case 6: app->app_local->odf.useful_certificates = value; break; + case 7: app->app_local->odf.data_objects = value; break; + case 8: app->app_local->odf.auth_objects = value; break; + default: + log_error ("unknown object type %d in ODF ignored\n", (p[0)&0x0f)); + } + } + + if (buflen) + log_info ("warning: %u bytes of garbage detected at end of ODF\n", buflen); + + xfree (buffer); + return 0; +} + + + +/* Read and parse the Private Key Directory Files. */ +/* + 6034 (privatekeys) + +30 33 30 11 0C 08 53 4B 2E 43 48 2E 44 53 03 02 030...SK.CH.DS.. +06 80 04 01 07 30 0C 04 01 01 03 03 06 00 40 02 .....0........@. +02 00 50 A1 10 30 0E 30 08 04 06 3F 00 40 16 00 ..P..0.0...?.@.. +50 02 02 04 00 30 33 30 11 0C 08 53 4B 2E 43 48 P....030...SK.CH +2E 4B 45 03 02 06 80 04 01 0A 30 0C 04 01 0C 03 .KE.......0..... +03 06 44 00 02 02 00 52 A1 10 30 0E 30 08 04 06 ..D....R..0.0... +3F 00 40 16 00 52 02 02 04 00 30 34 30 12 0C 09 ?.@..R....040... +53 4B 2E 43 48 2E 41 55 54 03 02 06 80 04 01 0A SK.CH.AUT....... +30 0C 04 01 0D 03 03 06 20 00 02 02 00 51 A1 10 0....... ....Q.. +30 0E 30 08 04 06 3F 00 40 16 00 51 02 02 04 00 0.0...?.@..Q.... +30 37 30 15 0C 0C 53 4B 2E 43 48 2E 44 53 2D 53 070...SK.CH.DS-S +50 58 03 02 06 80 04 01 0A 30 0C 04 01 02 03 03 PX.......0...... +06 20 00 02 02 00 53 A1 10 30 0E 30 08 04 06 3F . ....S..0.0...? +00 40 16 00 53 02 02 04 00 00 00 00 00 00 00 00 .@..S........... +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + +*/ +static gpg_error_t +read_ef_prkdf (app_t app) +{ + + +} + +/* Read and parse the Public Key Directory Files. */ +static gpg_error_t +read_ef_pukdf (app_t app) +{ + + +} + + +/* Read and parse the Certificate Directory Files. */ +/* + +6035 (certificates) + +30 2A 30 15 0C 0C 43 5F 58 35 30 39 2E 43 48 2E 0*0...C_X509.CH. +44 53 03 02 06 40 04 01 0A 30 03 04 01 01 A1 0C DS...@...0...... +30 0A 30 08 04 06 3F 00 40 16 C0 00 30 2A 30 15 0.0...?.@...0*0. +0C 0C 43 5F 58 35 30 39 2E 43 48 2E 4B 45 03 02 ..C_X509.CH.KE.. +06 40 04 01 0A 30 03 04 01 0C A1 0C 30 0A 30 08 .@...0......0.0. +04 06 3F 00 40 16 C2 00 30 2B 30 16 0C 0D 43 5F ..?.@...0+0...C_ +58 35 30 39 2E 43 48 2E 41 55 54 03 02 06 40 04 X509.CH.AUT...@. +01 0A 30 03 04 01 0D A1 0C 30 0A 30 08 04 06 3F ..0......0.0...? +00 40 16 C5 00 30 2E 30 19 0C 10 43 5F 58 35 30 .@...0.0...C_X50 +39 2E 43 48 2E 44 53 2D 53 50 58 03 02 06 40 04 9.CH.DS-SPX...@. +01 0A 30 03 04 01 02 A1 0C 30 0A 30 08 04 06 3F ..0......0.0...? +00 40 16 C1 20 00 00 00 00 00 00 00 00 00 00 00 .@.. ........... +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + + 0 42: SEQUENCE { + 2 21: SEQUENCE { -- commonObjectAttributes + 4 12: UTF8String 'C_X509.CH.DS' + 18 2: BIT STRING 6 unused bits + : '10'B (bit 1) + 22 1: OCTET STRING 0A + : } + 25 3: SEQUENCE { -- commonCertificateAttributes + 27 1: OCTET STRING 01 + : } + 30 12: [1] { -- certAttributes + 32 10: SEQUENCE { + 34 8: SEQUENCE { + 36 6: OCTET STRING 3F 00 40 16 C0 00 + : } + : } + : } + : } + + + +6036 (trustedcertificates) + +30 35 30 06 03 02 00 00 04 00 30 16 04 14 2D 36 050.......0...-6 +33 39 33 33 39 34 30 33 39 37 37 36 34 30 31 32 3933940397764012 +31 36 A1 13 30 11 30 0F 04 06 3F 00 40 16 C7 08 16..0.0...?.@... +02 01 00 80 02 02 29 30 35 30 06 03 02 00 00 04 ......)050...... +00 30 16 04 14 2D 34 30 31 39 30 35 32 37 32 36 .0...-4019052726 +38 30 31 36 39 33 34 39 32 A1 13 30 11 30 0F 04 801693492..0.0.. +06 3F 00 40 16 C7 0E 02 01 00 80 02 04 12 30 34 .?.@..........04 +30 06 03 02 00 00 04 00 30 15 04 13 37 39 36 33 0.......0...7963 +32 38 33 36 35 30 37 36 36 34 38 32 39 36 30 A1 283650766482960. +13 30 11 30 0F 04 06 3F 00 40 16 C0 08 02 01 00 .0.0...?.@...... +80 02 04 11 00 00 00 00 00 00 00 00 00 00 00 00 ................ +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + + 0 53: SEQUENCE { + 2 6: SEQUENCE { + 4 2: BIT STRING + : '00000000'B + : Error: Spurious zero bits in bitstring. + 8 0: OCTET STRING + : Error: Object has zero length. + : } + 10 22: SEQUENCE { + 12 20: OCTET STRING '-6393394039776401216' + : } + 34 19: [1] { + 36 17: SEQUENCE { + 38 15: SEQUENCE { + 40 6: OCTET STRING 3F 00 40 16 C7 08 + 48 1: INTEGER 0 -- index + 51 2: [0] 02 29 -- length + : } + : } + : } + : } + + +*/ +static gpg_error_t +read_ef_cdf (app_t app) +{ + gpg_error_t err; + unsigned char *buffer = NULL; + size_t buflen; + unsigned short value; + unsigned short fid; + const unsigned char *p; + size_t n, objlen, hdrlen; + int class, tag, constructed, ndef; + + fid = app->app_local->odf.certificates; + if (!fid) + return 0; /* No certificates. */ + + err = select_and_read_binary (app->slot, fid, "CDF", &buffer, &buflen); + if (err) + return err; + + p = buffer; + n = buflen; + + /* Loop over the records. We stop as soon as we detect a new record + starting with 0x00 or 0xff as these values are commonly used to pad + the the read datablocks and are no valid ASN.1 encoding. */ + while (n && *p && *p == 0xff) + { + const unsigned char *pp; + size_t nn; + + err = parse_ber_header (&p, &n, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (!err && (objlen > n || tag != TAG_SEQUENCE)) + err = gpg_error (GPG_ERR_INV_OBJ); + if (err) + { + log_error ("error parsing CDF record: %s\n", gpg_strerror (err)); + goto leave; + } + pp = p; + nn = objlen; + p += objlen; + n -= objlen; + + /* Skip the commonObjectAttributes. */ + err = parse_ber_header (&pp, &nn, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (!err && (objlen > nn || tag != TAG_SEQUENCE)) + err = gpg_error (GPG_ERR_INV_OBJ); + if (err) + { + log_error ("error parsing CDF record: %s - skipped\n", + gpg_strerror (err)); + continue; + } + pp += objlen; + nn -= objlen; + + /* Skip the commonCertificateAttributes. */ + err = parse_ber_header (&pp, &nn, &class, &tag, &constructed, + &ndef, &objlen, &hdrlen); + if (!err && (objlen > nn || tag != TAG_SEQUENCE)) + err = gpg_error (GPG_ERR_INV_OBJ); + if (err) + { + log_error ("error parsing CDF record: %s - skipped\n", + gpg_strerror (err)); + continue; + } + pp += objlen; + nn -= objlen; + + /* FIXME: Check that this is a reference to a certificate. */ + + + } + + + leave: + xfree (buffer); + return err; +} + +/* Read and parse Authentication Object Directory Files. */ +static gpg_error_t +read_ef_aodf (app_t app) +{ + +} + + +/* 6037 (dataobjects) + +30 1E 30 0B 0C 06 45 46 2E 47 44 4F 04 01 0A 30 0.0...EF.GDO...0 +02 0C 00 A1 0B 30 09 04 04 3F 00 2F 02 80 01 0E .....0...?./.... +30 30 30 18 0C 0F 64 69 73 70 6C 61 79 20 6D 65 000...display me +73 73 61 67 65 03 02 06 C0 04 01 0A 30 05 0C 03 ssage.......0... +42 53 53 A1 0D 30 0B 04 06 3F 00 40 16 D0 00 80 BSS..0...?.@.... +01 20 30 2B 30 0C 0C 03 53 53 4F 03 02 06 C0 04 . 0+0...SSO..... +01 0A 30 0B 0C 09 53 61 66 65 47 75 61 72 64 A1 ..0...SafeGuard. +0E 30 0C 04 06 3F 00 0F FF 30 02 80 02 03 00 30 .0...?...0.....0 +30 30 11 0C 08 53 47 41 53 64 61 74 61 03 02 06 00...SGASdata... +C0 04 01 0A 30 0B 0C 09 53 61 66 65 47 75 61 72 ....0...SafeGuar +64 A1 0E 30 0C 04 06 3F 00 0F FF 40 01 80 02 00 d..0...?...@.... +80 30 30 30 11 0C 08 55 73 65 72 64 61 74 61 03 .000...Userdata. +02 06 40 04 01 0A 30 0B 0C 09 53 61 66 65 47 75 ..@...0...SafeGu +61 72 64 A1 0E 30 0C 04 06 3F 00 0F FF 30 01 80 ard..0...?...0.. +02 01 00 30 2C 30 13 0C 0A 62 61 73 69 63 20 64 ...0,0...basic d +61 74 61 03 02 06 C0 04 01 0A 30 05 0C 03 49 44 ata.......0...ID +44 A1 0E 30 0C 04 06 3F 00 40 17 D0 01 80 02 02 D..0...?.@...... +00 30 2F 30 16 0C 0D 65 78 74 65 6E 64 65 64 20 .0/0...extended +64 61 74 61 03 02 06 C0 04 01 0A 30 05 0C 03 49 data.......0...I +44 44 A1 0E 30 0C 04 06 3F 00 40 17 D0 02 80 02 DD..0...?.@..... +08 00 30 34 30 1B 0C 12 73 70 65 63 69 61 6C 20 ..040...special +70 72 69 76 69 6C 65 67 65 73 03 02 06 C0 04 01 privileges...... +0A 30 05 0C 03 49 44 44 A1 0E 30 0C 04 06 3F 00 .0...IDD..0...?. +40 17 D0 03 80 02 04 00 @....... + + 0 30: SEQUENCE { + 2 11: SEQUENCE { + 4 6: UTF8String 'EF.GDO' + 12 1: OCTET STRING 0A + : } + 15 2: SEQUENCE { + 17 0: UTF8String + : Error: Object has zero length. + : } + 19 11: [1] { + 21 9: SEQUENCE { + 23 4: OCTET STRING 3F 00 2F 02 + 29 1: [0] 0E + : } + : } + : } + + + +6038 (authobjects) + +30 2A 30 0B 0C 05 62 61 73 69 63 03 02 00 C0 30 0*0...basic....0 +03 04 01 0A A1 16 30 14 03 03 00 0C 10 0A 01 01 ......0......... +02 01 06 02 01 06 02 01 08 80 01 01 30 51 30 19 ............0Q0. +0C 13 73 70 65 63 69 66 69 63 20 50 49 4E 20 66 ..specific PIN f +6F 72 20 44 53 03 02 00 C0 30 03 04 01 07 A1 2F or DS....0...../ +30 2D 03 03 00 4C 10 0A 01 01 02 01 06 02 01 06 0-...L.......... +02 01 08 80 01 02 18 0F 32 30 30 32 30 34 31 39 ........20020419 +31 32 31 33 34 31 5A 30 06 04 04 3F 00 40 16 121341Z0...?.@. + + 0 42: SEQUENCE { + 2 11: SEQUENCE { + 4 5: UTF8String 'basic' + 11 2: BIT STRING + : '00000011'B + : Error: Spurious zero bits in bitstring. + : } + 15 3: SEQUENCE { + 17 1: OCTET STRING 0A + : } + 20 22: [1] { + 22 20: SEQUENCE { + 24 3: BIT STRING + : '0000100000110000'B + : Error: Spurious zero bits in bitstring. + 29 1: ENUMERATED 1 + 32 1: INTEGER 6 + 35 1: INTEGER 6 + 38 1: INTEGER 8 + 41 1: [0] 01 + : } + : } + : } + + + +*/ + + +/* Read and parse the EF(TokenInfo). + +TokenInfo ::= SEQUENCE { + version INTEGER {v1(0)} (v1,...), + serialNumber OCTET STRING, + manufacturerID Label OPTIONAL, + label [0] Label OPTIONAL, + tokenflags TokenFlags, + seInfo SEQUENCE OF SecurityEnvironmentInfo OPTIONAL, + recordInfo [1] RecordInfo OPTIONAL, + supportedAlgorithms [2] SEQUENCE OF AlgorithmInfo OPTIONAL, + ..., + issuerId [3] Label OPTIONAL, + holderId [4] Label OPTIONAL, + lastUpdate [5] LastUpdate OPTIONAL, + preferredLanguage PrintableString OPTIONAL -- In accordance with + -- IETF RFC 1766 +} (CONSTRAINED BY { -- Each AlgorithmInfo.reference value must be unique --}) + +TokenFlags ::= BIT STRING { + readonly (0), + loginRequired (1), + prnGeneration (2), + eidCompliant (3) +} + + + 5032: + +30 31 02 01 00 04 04 05 45 36 9F 0C 0C 44 2D 54 01......E6...D-T +72 75 73 74 20 47 6D 62 48 80 14 4F 66 66 69 63 rust GmbH..Offic +65 20 69 64 65 6E 74 69 74 79 20 63 61 72 64 03 e identity card. +02 00 40 20 63 61 72 64 03 02 00 40 00 00 00 00 ..@ card...@.... +00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ + + 0 49: SEQUENCE { + 2 1: INTEGER 0 + 5 4: OCTET STRING 05 45 36 9F + 11 12: UTF8String 'D-Trust GmbH' + 25 20: [0] 'Office identity card' + 47 2: BIT STRING + : '00000010'B (bit 1) + : Error: Spurious zero bits in bitstring. + : } + + + + + */ +static gpg_error_t +read_ef_tokeninfo (app_t app) +{ + unsigned short efid = 0x5032; + +} + + +/* Get all the basic information from the pkcs#15 card, check the + structure and init our context. This is used once at application + initialization. */ +static gpg_error_t +read_p15_info (app_t app) +{ + gpg_error_t err; + + err = read_ed_odf (app); + if (err) + return err; + +} + + +static int +do_learn_status (APP app, CTRL ctrl) +{ + gpg_error_t err; + char ct_buf[100], id_buf[100]; + int i; + + /* Output information about all useful objects. */ + for (i=0; objlist[i].fid; i++) + { + if (filelist[i].certtype) + { + size_t len; + + len = app_help_read_length_of_cert (app->slot, + filelist[i].fid, NULL); + if (len) + { + /* FIXME: We should store the length in the application's + context so that a following readcert does only need to + read that many bytes. */ + sprintf (ct_buf, "%d", filelist[i].certtype); + sprintf (id_buf, "P15-DF01.%04X", filelist[i].fid); + send_status_info (ctrl, "CERTINFO", + ct_buf, strlen (ct_buf), + id_buf, strlen (id_buf), + NULL, (size_t)0); + } + } + else if (filelist[i].iskeypair) + { + char gripstr[40+1]; + + err = keygripstr_from_pk_file (app->slot, filelist[i].fid, gripstr); + if (err) + log_error ("can't get keygrip from FID 0x%04X: %s\n", + filelist[i].fid, gpg_strerror (err)); + else + { + sprintf (id_buf, "P15-DF01.%04X", filelist[i].fid); + send_status_info (ctrl, "KEYPAIRINFO", + gripstr, 40, + id_buf, strlen (id_buf), + NULL, (size_t)0); + } + } + } + + return 0; +} + + + + +/* Release all resources. */ +static void +do_deinit (app_t app) +{ + if (app && app->app_local) + { + xfree (app->app_local); + app->app_local = NULL; + } +} + + +/* Select the PKCS#15 application on the card in SLOT. */ +int +app_select_p15 (APP app) +{ + static char const aid[] = { 0xA0, 0, 0, 0, 0x63, + 0x50, 0x4B, 0x43, 0x53, 0x2D, 0x31, 0x35 }; + int slot = app->slot; + int rc; + + rc = iso7816_select_application (slot, aid, sizeof aid); + if (!rc) + { + app->apptype = "P15"; + + app->app_local = xtrycalloc (1, sizeof *app->app_local); + if (!app->app_local) + { + rc = gpg_error_from_errno (errno); + goto leave; + } + + /* Read basic information and check whether this is a real + card. */ + rc = read_p15_info (app); + + /* Special serial number munging. We need to do one case here + because we need to access the EF(TokenInfo). */ + if (app->serialnolen == 12 + && !memcmp (app->serial, "\xD2\x76\0\0\0\0\0\0\0\0\0\0", 12)) + { + /* This is a German card with a silly serial number. Try to get + the serial number from the EF(TokenInfo). We indicate such a + serial number by the using the prefix: "FF0100". */ + const char *efser = card->p15card->serial_number; + char *p; + + if (!efser) + efser = ""; + + xfree (*serial); + *serial = NULL; + p = xtrymalloc (strlen (efser) + 7); + if (!p) + rc = gpg_error (gpg_err_code_from_errno (errno)); + else + { + strcpy (p, "FF0100"); + strcpy (p+6, efser); + *serial = p; + } + } + else + rc = app_munge_serialno (app); + + app->fnc.deinit = do_deinit; + app->fnc.learn_status = do_learn_status; + app->fnc.readcert = do_readcert; + app->fnc.getattr = NULL; + app->fnc.setattr = NULL; + app->fnc.genkey = NULL; + app->fnc.sign = do_sign; + app->fnc.auth = NULL; + app->fnc.decipher = do_decipher; + app->fnc.change_pin = NULL; + app->fnc.check_pin = NULL; + + leave: + if (rc) + { + xfree (app->app_local); + app->app_local = NULL; + } + + } + + return rc; +} + + diff --git a/sm/ChangeLog b/sm/ChangeLog index acfa7f3bd..5f35e4858 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,10 @@ +2004-11-29 Werner Koch + + * gpgsm.c (set_debug): Changed to use a globals DEBUG_LEVEL and + DEBUG_VALUE. + (main): Made DEBUG_LEVEL global and introduced DEBUG_VALUE. This + now allows to add debug flags on top of a debug-level setting. + 2004-11-23 Werner Koch * gpgsm.c: New option --prefer-system-dirmngr. diff --git a/sm/gpgsm.c b/sm/gpgsm.c index c9ce8fd9f..c96683a46 100644 --- a/sm/gpgsm.c +++ b/sm/gpgsm.c @@ -438,6 +438,10 @@ int gpgsm_errors_seen = 0; /* It is possible that we are currentlu running under setuid permissions */ static int maybe_setuid = 1; +/* Helper to implement --debug-level and --debug*/ +static const char *debug_level; +static unsigned int debug_value; + /* Option --enable-special-filenames */ static int allow_special_filenames; @@ -580,45 +584,44 @@ wrong_args (const char *text) } -/* Setup the debugging. With a LEVEL of NULL only the active debug - flags are propagated to the subsystems. With LEVEL set, a specific - set of debug flags is set; thus overriding all flags already - set. */ +/* Setup the debugging. With a DEBUG_LEVEL of NULL only the active + debug flags are propagated to the subsystems. With DEBUG_LEVEL + set, a specific set of debug flags is set; and individual debugging + flags will be added on top. */ static void -set_debug (const char *level) +set_debug (void) { - if (!level) + if (!debug_level) ; - else if (!strcmp (level, "none")) + else if (!strcmp (debug_level, "none")) opt.debug = 0; - else if (!strcmp (level, "basic")) + else if (!strcmp (debug_level, "basic")) opt.debug = DBG_ASSUAN_VALUE; - else if (!strcmp (level, "advanced")) + else if (!strcmp (debug_level, "advanced")) opt.debug = DBG_ASSUAN_VALUE|DBG_X509_VALUE; - else if (!strcmp (level, "expert")) + else if (!strcmp (debug_level, "expert")) opt.debug = (DBG_ASSUAN_VALUE|DBG_X509_VALUE |DBG_CACHE_VALUE|DBG_CRYPTO_VALUE); - else if (!strcmp (level, "guru")) + else if (!strcmp (debug_level, "guru")) opt.debug = ~0; else { - log_error (_("invalid debug-level `%s' given\n"), level); + log_error (_("invalid debug-level `%s' given\n"), debug_level); gpgsm_exit(2); } + opt.debug |= debug_value; if (opt.debug && !opt.verbose) - { - opt.verbose = 1; - gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose); - } - if (opt.debug && opt.quiet) + opt.verbose = 1; + if (opt.debug) opt.quiet = 0; if (opt.debug & DBG_MPI_VALUE) gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 2); if (opt.debug & DBG_CRYPTO_VALUE ) gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1); + gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose); } @@ -695,7 +698,6 @@ main ( int argc, char **argv) int greeting = 0; int nogreeting = 0; int debug_wait = 0; - const char *debug_level = NULL; int use_random_seed = 1; int with_fpr = 0; char *def_digest_string = NULL; @@ -1010,8 +1012,8 @@ main ( int argc, char **argv) case oKeyring: append_to_strlist (&nrings, pargs.r.ret_str); break; - case oDebug: opt.debug |= pargs.r.ret_ulong; break; - case oDebugAll: opt.debug = ~0; break; + case oDebug: debug_value |= pargs.r.ret_ulong; break; + case oDebugAll: debug_value = ~0; break; case oDebugLevel: debug_level = pargs.r.ret_str; break; case oDebugWait: debug_wait = pargs.r.ret_int; break; case oDebugAllowCoreDump: @@ -1201,7 +1203,7 @@ main ( int argc, char **argv) gcry_control (GCRYCTL_RESUME_SECMEM_WARN); - set_debug (debug_level); + set_debug (); /* Although we alwasy use gpgsm_exit, we better install a regualr exit handler so that at least the secure memory gets wiped