/[winpt]/trunk/Src/wptPassphraseCB.cpp
ViewVC logotype

Diff of /trunk/Src/wptPassphraseCB.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 4 by twoaday, Sun Feb 6 11:11:40 2005 UTC revision 24 by twoaday, Sat Oct 8 10:43:08 2005 UTC
# Line 1  Line 1 
1  /* wptPassphraseCB.cpp - GPGME Passphrase Callback  /* wptPassphraseCB.cpp - GPGME Passphrase Callback
2   *      Copyright (C) 2001, 2002, 2003 Timo Schulz   *      Copyright (C) 2001, 2002, 2003, 2005 Timo Schulz
3     *      Copyright (C) 2005 g10 Code GmbH
4   *   *
5   * This file is part of WinPT.   * This file is part of WinPT.
6   *   *
# Line 32  Line 33 
33  #include "wptUTF8.h"  #include "wptUTF8.h"
34  #include "wptErrors.h"  #include "wptErrors.h"
35  #include "wptTypes.h"  #include "wptTypes.h"
36    #include "wptKeyList.h"
37  #include "wptAgent.h"  #include "wptAgent.h"
38  #include "wptRegistry.h"  #include "wptRegistry.h"
39    
# Line 39  Line 41 
41  #define item_ctrl_id( cmd ) \  #define item_ctrl_id( cmd ) \
42      ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_PWD : IDC_DECRYPT_SIGN_PWD)      ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_PWD : IDC_DECRYPT_SIGN_PWD)
43    
44    #define item_ctrl_id2(cmd) \
45        ((cmd) == GPG_CMD_DECRYPT? IDC_DECRYPT_HIDE : IDC_DECRYPT_SIGN_HIDE)
46    
47  BOOL CALLBACK  
48    /* Dialog procedure for the passphrase callback. */
49    static BOOL CALLBACK
50  passphrase_callback_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)  passphrase_callback_proc (HWND dlg, UINT msg, WPARAM wparam, LPARAM lparam)
51  {      {    
52      static passphrase_cb_s * c;      static passphrase_cb_s * c;
53      static int hide = 1;      gpgme_decrypt_result_t res;
54        gpgme_sign_result_t res_sig;
55      gpgme_key_t key;      gpgme_key_t key;
56      const char * s, * id;      const char *id;
57      char info[768] = {0};      char *info;
58      void * ctx = NULL, * item;      void *ctx = NULL, *item;
59      unsigned int pkalgo;      int n;
60    
61      switch( msg )  {      switch (msg) {
62      case WM_INITDIALOG:      case WM_INITDIALOG:
         hide = 1;  
63          c = (passphrase_cb_s *)lparam;          c = (passphrase_cb_s *)lparam;
64          if (!c)          if (!c)
65              BUG (0);              BUG (0);
# Line 64  passphrase_callback_proc (HWND dlg, UINT Line 70  passphrase_callback_proc (HWND dlg, UINT
70              CheckDlgButton( dlg, IDC_DECRYPT_HIDE, BST_CHECKED );              CheckDlgButton( dlg, IDC_DECRYPT_HIDE, BST_CHECKED );
71          }          }
72          else if( c->gpg_cmd == GPG_CMD_SIGN )          else if( c->gpg_cmd == GPG_CMD_SIGN )
73              CheckDlgButton( dlg, IDC_DECRYPT_SIGN_HIDE, BST_CHECKED );              CheckDlgButton (dlg, IDC_DECRYPT_SIGN_HIDE, BST_CHECKED);
74          if( c->enc_to && c->gpg_cmd == GPG_CMD_DECRYPT ) {          res = gpgme_op_decrypt_result (c->gpg);
75              gpgme_recipients_enum_open( c->enc_to, &ctx );          if (res != NULL && c->gpg_cmd == GPG_CMD_DECRYPT) {
76              while ( (s = gpgme_recipients_enum_read( c->enc_to, &ctx )) ) {              gpgme_recipient_t r;
77                  pkalgo = *s; s++;  
78                  get_pubkey( s, &key );              for (r = res->recipients; r; r = r->next) {
79                  if( key ) {                  get_pubkey (r->keyid, &key);
80                      char * uid = NULL;                  if (key) {
81                      id = gpgme_key_get_string_attr( key, GPGME_ATTR_USERID, NULL, 0 );                      char *uid;
82                      if( !id )                      id = key->uids->name;
83                        if (!id)
84                          id = _("Invalid User ID");                          id = _("Invalid User ID");
85                      uid = utf8_to_wincp (id, strlen (id));                                      uid = utf8_to_wincp (id, strlen (id));
86                      _snprintf( info, sizeof info - 1, "%s (%s, 0x%s)", uid,                      info = new char [16+strlen (uid) + 4 + strlen (r->keyid) + strlen (key->uids->email) +  3];
87                                  gpgme_key_expand_attr( GPGME_ATTR_ALGO, pkalgo ), s+8 );                      if (!info)
88                      free( uid );                          BUG (NULL);
89                        sprintf (info, "%s <%s> (%s, 0x%s)", uid, key->uids->email,
90                                 get_key_pubalgo (r->pubkey_algo), r->keyid+8);
91                        free (uid);
92                        
93                    }
94                    else {
95                        info = new char [32 + strlen (r->keyid) + 2];
96                        if (!info)
97                            BUG (NULL);
98                        sprintf (info, _("Unknown (key ID 0x%s)"),
99                                 r->keyid? r->keyid+8 : "????????");
100                  }                  }
101                  else                  listbox_add_string (GetDlgItem (dlg, IDC_DECRYPT_LIST), info);
102                      _snprintf( info, sizeof info - 1, _("Unknown (key ID 0x%s)"),                  free (info);
                                s? s + 8 : "DEADBEEF" );  
                 listbox_add_string( GetDlgItem( dlg, IDC_DECRYPT_LIST ), info );  
103              }              }
             gpgme_recipients_enum_close( c->enc_to, &ctx );  
104          }          }
105            else if (c->gpg_cmd == GPG_CMD_DECRYPT)
106                EnableWindow (GetDlgItem (dlg, IDC_DECRYPT_LIST), FALSE);
107          SetDlgItemText( dlg, c->gpg_cmd == GPG_CMD_DECRYPT?          SetDlgItemText( dlg, c->gpg_cmd == GPG_CMD_DECRYPT?
108                          IDC_DECRYPT_PWDINFO : IDC_DECRYPT_SIGN_PWDINFO,                          IDC_DECRYPT_PWDINFO : IDC_DECRYPT_SIGN_PWDINFO,
109                          _("Please enter your passphrase") );                          _("Please enter your passphrase") );
110          if( c->gpg_cmd == GPG_CMD_DECRYPT ) {          if (c->gpg_cmd == GPG_CMD_DECRYPT) {
111              SetFocus( GetDlgItem( dlg, IDC_DECRYPT_PWD ) );              SetFocus (GetDlgItem (dlg, IDC_DECRYPT_PWD));
112              SetDlgItemText( dlg, IDC_DECRYPT_MSG, c->info );              if (res && !res->recipients)
113                    SetDlgItemText (dlg, IDC_DECRYPT_MSG, _("Symmetric encryption.\n"));                                                    
114                else
115                    SetDlgItemText (dlg, IDC_DECRYPT_MSG, c->info);
116          }          }
117          else {          else {
118              SetFocus( GetDlgItem( dlg, IDC_DECRYPT_SIGN_PWD ) );              SetFocus( GetDlgItem (dlg, IDC_DECRYPT_SIGN_PWD));
119              SetDlgItemText( dlg, IDC_DECRYPT_SIGN_MSG, c->info );              SetDlgItemText (dlg, IDC_DECRYPT_SIGN_MSG, c->info);
120          }          }
121          center_window( dlg );          center_window (dlg, NULL);
122          SetForegroundWindow( dlg );          SetForegroundWindow (dlg);
123          set_active_window( dlg );          set_active_window (dlg);
124          return FALSE;          return FALSE;
125    
126          case WM_SYSCOMMAND:          case WM_SYSCOMMAND:
# Line 109  passphrase_callback_proc (HWND dlg, UINT Line 129  passphrase_callback_proc (HWND dlg, UINT
129                  c->cancel = 1;                  c->cancel = 1;
130                  EndDialog( dlg, TRUE );                  EndDialog( dlg, TRUE );
131              }              }
132              return FALSE;              break;
133    
134          case WM_COMMAND:          case WM_COMMAND:
135              switch( HIWORD( wparam ) ) {              switch( HIWORD( wparam ) ) {
# Line 117  passphrase_callback_proc (HWND dlg, UINT Line 137  passphrase_callback_proc (HWND dlg, UINT
137                  if ( LOWORD( wparam ) == IDC_DECRYPT_HIDE                  if ( LOWORD( wparam ) == IDC_DECRYPT_HIDE
138                      || LOWORD( wparam ) == IDC_DECRYPT_SIGN_HIDE ) {                      || LOWORD( wparam ) == IDC_DECRYPT_SIGN_HIDE ) {
139                      HWND hwnd;                      HWND hwnd;
140                      hide ^= 1;                      int hide = IsDlgButtonChecked (dlg, item_ctrl_id2 (c->gpg_cmd));
141                      hwnd = GetDlgItem( dlg, item_ctrl_id( c->gpg_cmd ) );                      hwnd = GetDlgItem (dlg, item_ctrl_id (c->gpg_cmd));
142                      SendMessage( hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0 );                      SendMessage( hwnd, EM_SETPASSWORDCHAR, hide? '*' : 0, 0 );
143                      SetFocus( hwnd );                      SetFocus (hwnd);
144                  }                  }
145              }              }
146    
# Line 129  passphrase_callback_proc (HWND dlg, UINT Line 149  passphrase_callback_proc (HWND dlg, UINT
149                  /* fixme: the item is even cached when the passphrase is not                  /* fixme: the item is even cached when the passphrase is not
150                            correct, which means that the user needs to delete all                            correct, which means that the user needs to delete all
151                            cached entries to continue. */                            cached entries to continue. */
152                  GetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), c->pwd, sizeof (c->pwd) -1);                  if (c->pwd) {
153                  if (reg_prefs.cache_time > 0 && !c->is_card && !strstr (c->keyid, "missing")) {                      delete []c->pwd;
154                        c->pwd = NULL;
155                    }
156                    n = item_get_text_length (dlg, item_ctrl_id (c->gpg_cmd));
157                    if (!n) {
158                        c->pwd = new char[2];
159                        strcpy (c->pwd, "");
160                    }
161                    else {
162                        c->pwd = new char[n+2];
163                        if (!c->pwd)
164                            BUG (NULL);
165                        GetDlgItemText (dlg, item_ctrl_id (c->gpg_cmd), c->pwd, n+1);
166                    }
167                    res = gpgme_op_decrypt_result (c->gpg);
168                    if (!res)
169                        res_sig = gpgme_op_sign_result (c->gpg);
170                    if (reg_prefs.cache_time > 0 && !c->is_card &&
171                        ((res && res->recipients) || (res_sig && res_sig->signatures))) {
172                      if (agent_get_cache (c->keyid, &item))                      if (agent_get_cache (c->keyid, &item))
173                          agent_unlock_cache_entry (&item);                          agent_unlock_cache_entry (&item);
174                      else                      else
# Line 149  passphrase_callback_proc (HWND dlg, UINT Line 187  passphrase_callback_proc (HWND dlg, UINT
187      }      }
188            
189      return FALSE;      return FALSE;
190  } /* passphrase_callback_proc */  }
191    
192    
193  static const char *  /* Extract the main keyid from @pass_info.
194  parse_gpg_keyid( const char * desc )     Return value: long main keyid or NULL for an error. */
195    static const char*
196    parse_gpg_keyid (const char *pass_info)
197  {  {
198      static char keyid[16+1];      static char keyid[16+1];
     char * p;  
199            
200      p = strrchr( desc, '\n' );      if (strlen (pass_info) < 16)
     if( !p )  
201          return NULL;          return NULL;
202      /* the format of the desc buffer looks like this:      /* the format of the desc buffer looks like this:
203         request_keyid[16] main_keyid[16] keytype[1] keylength[4]         request_keyid[16] main_keyid[16] keytype[1] keylength[4]
204         we use the main keyid to use only one cache entry. */         we use the main keyid to use only one cache entry. */
205      strncpy( keyid, desc+(p-desc+1+17), 16 );      strncpy (keyid, pass_info+17, 16);
206        keyid[16] = 0;
207      return keyid;      return keyid;
208  } /* parse_gpg_keyid */  }
209    
210    
211    /* Parse the information in @uid_hint and @pass_info to generate
212       a input message for the user in @desc. */
213  static void  static void
214  parse_gpg_description( char * desc, int size )  parse_gpg_description (const char *uid_hint, const char *pass_info,
215                           char *desc, int size)
216  {  {
217      char * buffer = NULL, ch, uid[128] = {0}, * uid2 = NULL;      gpgme_pubkey_algo_t algo;
218      char usedkey[16+1] = {0}, mainkey[16+1] = {0};      char usedkey[16+1], mainkey[16+1];
219      const char * buf;      char *uid, *p;
220      int i, algo, try_again = 0;      int n=0;
221    
222      if( stristr( desc, "[User ID hint missing]" )      while (p = strsep ((char**)&pass_info, " ")) {
223          || stristr( desc, "[passphrase info missing]" ) ) {          switch (n++) {
224          _snprintf( desc, size-1,          case 0: strncpy (mainkey, p, 16); mainkey[16] = 0; break;
225                     _("You need a passphrase to unlock the secret key for\n"          case 1: strncpy (usedkey, p, 16); usedkey[16] = 0; break;
226                       "user: [UserID hint missing]\n"          case 2: algo = (gpgme_pubkey_algo_t)atol (p); break;
                      "      [passphrase info missing]\n") );  
         return;  
     }  
   
     buffer = new char[size+1];  
     if( !buffer )  
         BUG( NULL );  
     strcpy( buffer, desc );  
     buf = buffer;  
     if( strstr( buf, "TRY_AGAIN" ) ) {  
         buf += strlen( "TRY_AGAIN\n" );  
         try_again = 1;  
     }  
     else if( strstr( buf, "ENTER_PASSPHRASE" ) )  
         buf += strlen( "ENTER_PASSPHRASE\n" );  
     else  
         BUG( NULL );  
     buf += 17;  
     for( i = 0; i < sizeof uid-1; i++ ) {  
         ch = *buf++;  
         if( ch == '\n' ) {  
             uid[i] = '\0';  
             break;  
227          }          }
         uid[i] = ch;  
228      }      }
229      memcpy( usedkey, buf, 16 );      uid_hint += 16; /* skip keyid */
230      usedkey[16] = '\0';      uid_hint += 1;  /* space */
     buf += 17;  
     memcpy( mainkey, buf, 16 );  
     mainkey[16] = '\0';  
     buf += 17;  
     if( !buf )  
         BUG( NULL );  
     algo = atol( buf );  
     free_if_alloc( buffer );  
231    
232      uid2 = utf8_to_wincp (uid, strlen (uid));      uid = utf8_to_wincp (uid_hint, strlen (uid_hint));
233    
234      if( strcmp( usedkey, mainkey ) )      if (strcmp (usedkey, mainkey))
235          _snprintf( desc, size-1,          _snprintf (desc, size-1,
236                     _("You need a passphrase to unlock the secret key for\n"                     _("You need a passphrase to unlock the secret key for\n"
237                       "user: \"%s\"\n"                       "user: \"%s\"\n"
238                       "%s key, ID %s (main key ID %s)\n"),                       "%s key, ID %s (main key ID %s)\n"),
239                     uid2, gpgme_key_expand_attr( GPGME_ATTR_ALGO, algo ),                     uid, get_key_pubalgo (algo), usedkey+8, mainkey+8);
240                     usedkey+8, mainkey+8 );      else if (!strcmp (usedkey, mainkey))
241      else if( !strcmp( usedkey, mainkey ) )          _snprintf (desc, size-1,
         _snprintf( desc, size-1,  
242                     _("You need a passphrase to unlock the secret key for\n"                     _("You need a passphrase to unlock the secret key for\n"
243                       "user: \"%s\"\n"                       "user: \"%s\"\n"
244                       "%s key, ID %s\n"),                       "%s key, ID %s\n"),
245                       uid2, gpgme_key_expand_attr( GPGME_ATTR_ALGO, algo ),                       uid, get_key_pubalgo (algo), usedkey+8);
246                       usedkey+8 );      free (uid);
247      free( uid2 );  }
 } /* parse_gpg_describtion */  
248    
249    
250  static int inline  static int inline
251  is_hexstring( const char * p )  is_hexstring (const char * p)
252  {  {
253      size_t i;      size_t i;
254      for( i=0; i < strlen( p ); i++ ) {  
255          if( !isxdigit( p[i] ) )      for (i=0; i < strlen (p); i++) {
256            if (!isxdigit (p[i]))
257              return -1;              return -1;
258      }      }
259      return 0;      return 0;
260  }  }
261    
262    
263  const char *  /* Passphrase callback with the ability to support caching. */
264  passphrase_cb( void * opaque, const char * desc, void * r_hd )  gpgme_error_t
265  {    passphrase_cb (void *hook, const char *uid_hint,
266      passphrase_cb_s * c = (passphrase_cb_s *)opaque;                 const char *passphrase_info,
267      void * item;                 int prev_was_bad, int fd)
268      const char * pass, * keyid;  {
269      int rc = 0;      passphrase_cb_s *c = (passphrase_cb_s*)hook;
270        HANDLE hd = (HANDLE)fd;
271      if( !c )      void *item;
272          return NULL;      const char *keyid, *pass;
273        DWORD n;
274      if( desc ) {      int rc;
275          keyid = parse_gpg_keyid( desc );  
276          pass = agent_get_cache( keyid, &item );      /* XXX: pubkey_enc cancel does not quit gpg.exe */
277          if( pass ) {      /* XXX: handle prev_was_bad case. */
278              agent_unlock_cache_entry( &item );      if (!c)
279            return gpg_error (GPG_ERR_INV_ARG);
280    
281        if (passphrase_info) {
282            keyid = parse_gpg_keyid (passphrase_info);
283            pass = agent_get_cache (keyid+8, &item);
284            if (pass) {
285                agent_unlock_cache_entry (&item);
286              c->pwd_init = 0;              c->pwd_init = 0;
287              return pass;              if (!WriteFile (hd, pass, strlen (pass), &n, NULL))
288                    log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
289                if (!WriteFile (hd, "\n", 1, &n, NULL))
290                    log_debug ("passphrase_cb: WriteFile() failed ec=%d\n", w32_errno);
291                return 0;
292          }          }
293      }      }
294    
295      if( c->pwd_init ) {      if (c->pwd_init) {
296          c->keyid = keyid;          if (keyid && strlen (keyid) == 16)
297                strcpy (c->keyid, keyid+8);
298    
299          /* if the desc has a length of 32 and only hex digits, we assume a          /* if the desc has a length of 32 and only hex digits, we assume a
300             smart card has been used. */             smart card has been used. */
301          /*log_box( "", 0, "%s %d %d", desc,strlen( desc), is_hexstring( desc ) );*/          if (uid_hint && strlen (uid_hint) == 32 && !is_hexstring (uid_hint)) {
         if( desc && strlen( desc ) == 32 && !is_hexstring( desc ) ) {  
302              char buf[16];              char buf[16];
303              memset( buf, 0, sizeof buf );              memset (buf, 0, sizeof buf);
304              strncpy( buf, desc+20, 8 );              strncpy (buf, uid_hint+20, 8);
305              _snprintf( c->info, sizeof c->info-1,              _snprintf (c->info, sizeof c->info-1,
306                      _("Please enter the PIN to unlock your secret card key\n"                         _("Please enter the PIN to unlock your secret card key\n"
307                        "Card: %s"), buf );                           "Card: %s"), buf);
308              c->is_card = 1;              c->is_card = 1;
309          }          }
310          else if( desc ) {          else if (uid_hint)
311              strcpy( c->info, desc );              parse_gpg_description (uid_hint, passphrase_info,
312              parse_gpg_description( c->info, sizeof c->info - 1 );                                     c->info, sizeof c->info - 1);
313            if (c->gpg_cmd == GPG_CMD_DECRYPT) {
314                rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT,
315                                     (HWND)c->hwnd, passphrase_callback_proc,
316                                     (LPARAM)c);
317          }          }
318          if( c->gpg_cmd == GPG_CMD_DECRYPT ) {          else if (c->gpg_cmd == GPG_CMD_SIGN) {
319              rc = DialogBoxParam( glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT,              rc = DialogBoxParam (glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT_SIGN,
320                                  (HWND)c->hwnd, passphrase_callback_proc,                                   (HWND)c->hwnd, passphrase_callback_proc,
321                                  (LPARAM)c );                                   (LPARAM)c);
322          }          }
323          else if( c->gpg_cmd == GPG_CMD_SIGN ) {          if (rc == -1) {
324              rc = DialogBoxParam( glob_hinst, (LPCSTR)IDD_WINPT_DECRYPT_SIGN,              WriteFile (hd, "\n", 1, &n, NULL);
325                                  (HWND)c->hwnd, passphrase_callback_proc,              return gpg_error (GPG_ERR_EOF);
                                 (LPARAM)c );  
326          }          }
         if( rc == -1 )  
             return NULL;  
327          c->pwd_init = 0;          c->pwd_init = 0;
328      }      }
329        if (c->cancel) {
330            WriteFile (hd, "\n", 1, &n, NULL);
331            return gpg_error (GPG_ERR_EOF);
332        }
333    
334        WriteFile (hd, c->pwd, strlen (c->pwd), &n, NULL);
335        WriteFile (hd, "\n", 1, &n, NULL);
336        return 0;
337    }
338    
     if( c->cancel )  
         return NULL;  
339    
340      return c->pwd;  /* Initialize the given passphrase callback @cb with the
341  } /* passphrase_cb */     used gpgme context @ctx, the command @cmd and a title
342       @title for the dialog. */
343    void
344    set_gpg_passphrase_cb (passphrase_cb_s *cb, gpgme_ctx_t ctx,
345                           int cmd, HWND hwnd, const char *title)
346    {
347        memset (cb, 0, sizeof *cb);
348        cb->gpg_cmd = cmd;
349        cb->is_card = 0;
350        cb->cancel = 0;
351        cb->hwnd = hwnd;
352        cb->pwd_init = 1;
353        free_if_alloc (cb->title);
354        cb->title = m_strdup (title);
355        if (!cb->title)
356            BUG (NULL);
357        gpgme_set_passphrase_cb (ctx, passphrase_cb, cb);
358        cb->gpg = ctx;
359    }
360    
361    
362    /* Release a passphrase callback @ctx. */
363  void  void
364  set_gpg_passphrase_cb( gpgme_ctx_t c, passphrase_cb_s * ctx, int cmd,  release_gpg_passphrase_cb (passphrase_cb_s *ctx)
                        HWND hwnd, const char * title )  
365  {  {
366      ctx->gpg_cmd = cmd;      if (!ctx)
367      ctx->is_card = 0;          return;
368      ctx->cancel = 0;      sfree_if_alloc (ctx->pwd);
369      ctx->hwnd = hwnd;      free_if_alloc (ctx->title);
370      ctx->pwd_init = 1;  }
371      if( strlen( title ) > 256 )  
372          BUG( NULL ); /* check bounds */  /* Simple check to measure passphrase (@pass) quality.
373      strcpy( ctx->title, title );     Return value: 0 on success. */
374      gpgme_set_passphrase_cb( c, passphrase_cb, ctx );  int
375  } /* set_gpg_passphrase_cb */  check_passwd_quality (const char *pass, int strict)
376    {
377        int i, nd=0, nc=0, n;
378    
379        n = strlen (pass);
380        if (n < 8)
381            return -1;
382    
383        for (i=0; i < n; i++) {
384            if (isdigit (pass[i])) nd++;
385            if (isalpha (pass[i])) nc++;
386        }
387    
388        if (nd == n || nc == n)
389            return -1;
390    
391        return 0;
392    }

Legend:
Removed from v.4  
changed lines
  Added in v.24

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26