See ChangeLog: Fri Feb 19 15:49:15 CET 1999 Werner Koch
[gnupg.git] / g10 / import.c
index 2fa25c5..640c234 100644 (file)
@@ -51,8 +51,8 @@ static struct {
 } stats;
 
 
-static int read_block( IOBUF a, compress_filter_context_t *cfx,
-                            PACKET **pending_pkt, KBNODE *ret_root );
+static int import( IOBUF inp, int fast, const char* fname );
+static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root );
 static int import_one( const char *fname, KBNODE keyblock, int fast );
 static int import_secret_one( const char *fname, KBNODE keyblock );
 static int import_revoke_cert( const char *fname, KBNODE node );
@@ -106,22 +106,9 @@ static int merge_keysigs( KBNODE dst, KBNODE src, int *n_sigs,
 int
 import_keys( const char *fname, int fast )
 {
-    armor_filter_context_t afx;
-    compress_filter_context_t cfx;
-    PACKET *pending_pkt = NULL;
     IOBUF inp = NULL;
-    KBNODE keyblock;
-    int rc = 0;
-    ulong count=0;
-
-    memset( &afx, 0, sizeof afx);
-    memset( &cfx, 0, sizeof cfx);
-    afx.only_keyblocks = 1;
-
-    /* fixme: don't use static variables */
-    memset( &stats, 0, sizeof( stats ) );
+    int rc;
 
-    /* open file */
     inp = iobuf_open(fname);
     if( !fname )
        fname = "[stdin]";
@@ -130,10 +117,38 @@ import_keys( const char *fname, int fast )
        return G10ERR_OPEN_FILE;
     }
 
-    if( !opt.no_armor ) /* armored reading is not disabled */
-       iobuf_push_filter( inp, armor_filter, &afx );
+    rc = import( inp, fast, fname );
+
+    iobuf_close(inp);
+    return rc;
+}
+
+int
+import_keys_stream( IOBUF inp, int fast )
+{
+    return import( inp, fast, "[stream]" );
+}
+
+static int
+import( IOBUF inp, int fast, const char* fname )
+{
+    PACKET *pending_pkt = NULL;
+    KBNODE keyblock;
+    int rc = 0;
+    ulong count=0;
+
+    /* fixme: don't use static variables */
+    memset( &stats, 0, sizeof( stats ) );
+
+    getkey_disable_caches();
+
+    if( !opt.no_armor ) { /* armored reading is not disabled */
+       armor_filter_context_t *afx = m_alloc_clear( sizeof *afx );
+       afx->only_keyblocks = 1;
+       iobuf_push_filter2( inp, armor_filter, afx, 1 );
+    }
 
-    while( !(rc = read_block( inp, &cfx, &pending_pkt, &keyblock) )) {
+    while( !(rc = read_block( inp, &pending_pkt, &keyblock) )) {
        if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY )
            rc = import_one( fname, keyblock, fast );
        else if( keyblock->pkt->pkttype == PKT_SECRET_KEY )
@@ -182,21 +197,18 @@ import_keys( const char *fname, int fast )
     if( stats.secret_dups )
        log_info(_(" secret keys unchanged: %lu\n"), stats.secret_dups );
 
-
-    iobuf_close(inp);
     return rc;
 }
 
 
 /****************
- * Read the next keyblock from stream A, CFX is used to handle
- * compressed keyblocks. PENDING_PKT should be initialzed to NULL
+ * Read the next keyblock from stream A.
+ * PENDING_PKT should be initialzed to NULL
  * and not chnaged form the caller.
  * Retunr: 0 = okay, -1 no more blocks or another errorcode.
  */
 static int
-read_block( IOBUF a, compress_filter_context_t *cfx,
-           PACKET **pending_pkt, KBNODE *ret_root )
+read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
 {
     int rc;
     PACKET *pkt;
@@ -241,9 +253,12 @@ read_block( IOBUF a, compress_filter_context_t *cfx,
                rc = G10ERR_COMPR_ALGO;
                goto ready;
            }
-           cfx->algo = pkt->pkt.compressed->algorithm;
-           pkt->pkt.compressed->buf = NULL;
-           iobuf_push_filter( a, compress_filter, cfx );
+           {
+               compress_filter_context_t *cfx = m_alloc_clear( sizeof *cfx );
+               cfx->algo = pkt->pkt.compressed->algorithm;
+               pkt->pkt.compressed->buf = NULL;
+               iobuf_push_filter2( a, compress_filter, cfx, 1 );
+           }
            free_packet( pkt );
            init_packet(pkt);
            break;
@@ -356,7 +371,7 @@ import_one( const char *fname, KBNODE keyblock, int fast )
            return G10ERR_GENERAL;
        }
        if( opt.verbose > 1 )
-           log_info_f( fname, _("writing to '%s'\n"),
+           log_info_f( fname, _("writing to `%s'\n"),
                                keyblock_resource_name(&kbpos) );
        if( (rc=lock_keyblock( &kbpos )) )
            log_error_f( keyblock_resource_name(&kbpos),
@@ -658,12 +673,13 @@ import_revoke_cert( const char *fname, KBNODE node )
  * loop over the keyblock and check all self signatures.
  * Mark all user-ids with a self-signature by setting flag bit 0.
  * Mark all user-ids with an invalid self-signature by setting bit 1.
+ * This works allso for subkeys, here the subkey is marked.
  */
 static int
 chk_self_sigs( const char *fname, KBNODE keyblock,
               PKT_public_key *pk, u32 *keyid )
 {
-    KBNODE n, unode;
+    KBNODE n;
     PKT_signature *sig;
     int rc;
 
@@ -672,22 +688,51 @@ chk_self_sigs( const char *fname, KBNODE keyblock,
            continue;
        sig = n->pkt->pkt.signature;
        if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) {
-           unode = find_prev_kbnode( keyblock, n, PKT_USER_ID );
-           if( !unode )  {
-               log_error_f(fname, _("key %08lX: no user-id for signature\n"),
-                                       (ulong)keyid[1]);
-               return -1;  /* the complete keyblock is invalid */
+           if( (sig->sig_class&~3) == 0x10 ) {
+               KBNODE unode = find_prev_kbnode( keyblock, n, PKT_USER_ID );
+               if( !unode )  {
+                   log_error_f(fname,
+                               _("key %08lX: no user-id for signature\n"),
+                                           (ulong)keyid[1]);
+                   return -1;  /* the complete keyblock is invalid */
+               }
+               rc = check_key_signature( keyblock, n, NULL);
+               if( rc ) {
+                   log_error_f( fname,  rc == G10ERR_PUBKEY_ALGO ?
+                        _("key %08lX: unsupported public key algorithm\n"):
+                        _("key %08lX: invalid self-signature\n"),
+                                    (ulong)keyid[1]);
+
+                   unode->flag |= 2; /* mark as invalid */
+               }
+               unode->flag |= 1; /* mark that signature checked */
            }
-           rc = check_key_signature( keyblock, n, NULL);
-           if( rc ) {
-               log_error_f( fname,  rc == G10ERR_PUBKEY_ALGO ?
-                         _("key %08lX: unsupported public key algorithm\n"):
-                         _("key %08lX: invalid self-signature\n"),
-                                (ulong)keyid[1]);
-
-               unode->flag |= 2; /* mark as invalid */
+           else if( sig->sig_class == 0x18 ) {
+               KBNODE knode = find_prev_kbnode( keyblock,
+                                                n, PKT_PUBLIC_SUBKEY );
+               if( !knode )
+                   knode = find_prev_kbnode( keyblock,
+                                                n, PKT_SECRET_SUBKEY );
+
+               if( !knode )  {
+                   log_error_f(fname,
+                             _("key %08lX: no subkey for key binding\n"),
+                                           (ulong)keyid[1]);
+                   n->flag |= 4; /* delete this */
+               }
+               else {
+                   rc = check_key_signature( keyblock, n, NULL);
+                   if( rc ) {
+                       log_error_f( fname,  rc == G10ERR_PUBKEY_ALGO ?
+                          _("key %08lX: unsupported public key algorithm\n"):
+                          _("key %08lX: invalid subkey binding\n"),
+                                        (ulong)keyid[1]);
+
+                       knode->flag |= 2; /* mark as invalid */
+                   }
+                   knode->flag |= 1; /* mark that signature checked */
+               }
            }
-           unode->flag |= 1; /* mark that signature checked */
        }
     }
     return 0;
@@ -727,6 +772,22 @@ delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid )
            else
                nvalid++;
        }
+       else if(    node->pkt->pkttype == PKT_PUBLIC_SUBKEY
+                || node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+           if( (node->flag & 2) || !(node->flag & 1) ) {
+               if( opt.verbose ) {
+                   log_info_f(fname, _("key %08lX: skipped subkey\n"),
+                                                        (ulong)keyid[1]);
+               }
+               delete_kbnode( node ); /* the subkey */
+               /* and all following signature packets */
+               while( node->next
+                      && node->next->pkt->pkttype == PKT_SIGNATURE ) {
+                   delete_kbnode( node->next );
+                   node = node->next;
+               }
+           }
+       }
        else if( node->pkt->pkttype == PKT_SIGNATURE
                 && check_pubkey_algo( node->pkt->pkt.signature->pubkey_algo)
                 && node->pkt->pkt.signature->pubkey_algo != PUBKEY_ALGO_RSA )
@@ -749,6 +810,8 @@ delete_inv_parts( const char *fname, KBNODE keyblock, u32 *keyid )
                }
            }
        }
+       else if( (node->flag & 4) ) /* marked for deletion */
+           delete_kbnode( node );
     }
 
     /* note: because keyblock is the public key, it is never marked
@@ -842,7 +905,7 @@ merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock,
        }
     }
 
-    /* merge subkey certifcates */
+    /* merge subkey certificates */
     for(onode=keyblock_orig->next; onode; onode=onode->next ) {
        if( !(onode->flag & 1)
            &&  (   onode->pkt->pkttype == PKT_PUBLIC_SUBKEY