See ChangeLog: Fri Nov 27 15:30:24 CET 1998 Werner Koch
[gnupg.git] / g10 / parse-packet.c
index 20afd41..2d82308 100644 (file)
@@ -33,6 +33,7 @@
 #include "filter.h"
 #include "options.h"
 #include "main.h"
+#include "i18n.h"
 
 static int mpi_print_mode = 0;
 static int list_mode = 0;
@@ -105,7 +106,7 @@ unknown_pubkey_warning( int algo )
     algo &= 0xff;
     if( !unknown_pubkey_algos[algo] ) {
        if( opt.verbose )
-           log_info("can't handle public key algorithm %d\n", algo );
+           log_info(_("can't handle public key algorithm %d\n"), algo );
        unknown_pubkey_algos[algo] = 1;
     }
 }
@@ -203,7 +204,7 @@ static int
 parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
        int *skip, IOBUF out, int do_skip )
 {
-    int rc, c, ctb, pkttype, lenbytes;
+    int rc=0, c, ctb, pkttype, lenbytes;
     unsigned long pktlen;
     byte hdr[8];
     int hdrlen;
@@ -213,13 +214,16 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
     assert( !pkt->pkt.generic );
     if( retpos )
        *retpos = iobuf_tell(inp);
-    if( (ctb = iobuf_get(inp)) == -1 )
-       return -1;
+    if( (ctb = iobuf_get(inp)) == -1 ) {
+       rc = -1;
+       goto leave;
+    }
     hdrlen=0;
     hdr[hdrlen++] = ctb;
     if( !(ctb & 0x80) ) {
        log_error("%s: invalid packet (ctb=%02x)\n", iobuf_where(inp), ctb );
-       return G10ERR_INVALID_PACKET;
+       rc = G10ERR_INVALID_PACKET;
+       goto leave;
     }
     pktlen = 0;
     new_ctb = !!(ctb & 0x40);
@@ -227,7 +231,8 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
        pkttype =  ctb & 0x3f;
        if( (c = iobuf_get(inp)) == -1 ) {
            log_error("%s: 1st length byte missing\n", iobuf_where(inp) );
-           return G10ERR_INVALID_PACKET;
+           rc = G10ERR_INVALID_PACKET;
+           goto leave;
        }
        hdr[hdrlen++] = c;
        if( c < 192 )
@@ -236,7 +241,8 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
            pktlen = (c - 192) * 256;
            if( (c = iobuf_get(inp)) == -1 ) {
                log_error("%s: 2nd length byte missing\n", iobuf_where(inp) );
-               return G10ERR_INVALID_PACKET;
+               rc = G10ERR_INVALID_PACKET;
+               goto leave;
            }
            hdr[hdrlen++] = c;
            pktlen += c + 192;
@@ -247,7 +253,8 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
            pktlen |= (hdr[hdrlen++] = iobuf_get_noeof(inp)) << 8;
            if( (c = iobuf_get(inp)) == -1 ) {
                log_error("%s: 4 byte length invalid\n", iobuf_where(inp) );
-               return G10ERR_INVALID_PACKET;
+               rc = G10ERR_INVALID_PACKET;
+               goto leave;
            }
            pktlen |= (hdr[hdrlen++] = c );
        }
@@ -277,13 +284,14 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
            rc = G10ERR_WRITE_FILE;
        else
            rc = copy_packet(inp, out, pkttype, pktlen );
-       return rc;
+       goto leave;
     }
 
     if( do_skip || !pkttype || (reqtype && pkttype != reqtype) ) {
-       skip_packet(inp, pkttype, pktlen);
+       skip_rest(inp, pktlen);
        *skip = 1;
-       return 0;
+       rc = 0;
+       goto leave;
     }
 
     if( DBG_PACKET )
@@ -341,6 +349,9 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
        break;
     }
 
+  leave:
+    if( !rc && iobuf_error(inp) )
+       rc = G10ERR_INV_KEYRING;
     return rc;
 }
 
@@ -396,10 +407,14 @@ static void
 skip_packet( IOBUF inp, int pkttype, unsigned long pktlen )
 {
     if( list_mode ) {
-       printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen );
+       if( pkttype == PKT_MARKER )
+           fputs(":marker packet:\n", stdout );
+       else
+           printf(":unknown packet: type %2d, length %lu\n", pkttype, pktlen);
        if( pkttype ) {
            int c, i=0 ;
-           printf("dump:");
+           if( pkttype != PKT_MARKER )
+               fputs("dump:", stdout );
            if( iobuf_in_block_mode(inp) ) {
                while( (c=iobuf_get(inp)) != -1 )
                    dump_hex_line(c, &i);
@@ -424,7 +439,8 @@ skip_rest( IOBUF inp, unsigned long pktlen )
     }
     else {
        for( ; pktlen; pktlen-- )
-           iobuf_get(inp);
+           if( iobuf_get(inp) == -1 )
+               break;
     }
 }
 
@@ -450,6 +466,25 @@ read_rest( IOBUF inp, ulong *r_pktlen )
     return p;
 }
 
+static void *
+read_rest2( IOBUF inp, size_t pktlen )
+{
+    byte *p;
+    int i;
+
+    if( iobuf_in_block_mode(inp) ) {
+       log_error("read_rest: can't store stream data\n");
+       p = NULL;
+    }
+    else {
+       p = m_alloc( pktlen );
+       for(i=0; pktlen; pktlen--, i++ )
+           p[i] = iobuf_get(inp);
+    }
+    return p;
+}
+
+
 
 static int
 parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
@@ -480,8 +515,8 @@ parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
       case 1:  /* salted s2k */
        minlen = 8;
        break;
-      case 4:  /* iterated+salted s2k */
-       minlen = 12;
+      case 3:  /* iterated+salted s2k */
+       minlen = 9;
        break;
       default:
        log_error("unknown S2K %d\n", s2kmode );
@@ -498,12 +533,12 @@ parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
     k->cipher_algo = cipher_algo;
     k->s2k.mode = s2kmode;
     k->s2k.hash_algo = hash_algo;
-    if( s2kmode == 1 || s2kmode == 4 ) {
+    if( s2kmode == 1 || s2kmode == 3 ) {
        for(i=0; i < 8 && pktlen; i++, pktlen-- )
            k->s2k.salt[i] = iobuf_get_noeof(inp);
     }
-    if( s2kmode == 4 ) {
-       k->s2k.count = read_32(inp); pktlen -= 4;
+    if( s2kmode == 3 ) {
+       k->s2k.count = iobuf_get(inp); pktlen--;
     }
     k->seskeylen = seskeylen;
     for(i=0; i < seskeylen && pktlen; i++, pktlen-- )
@@ -513,11 +548,11 @@ parse_symkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
     if( list_mode ) {
        printf(":symkey enc packet: version %d, cipher %d, s2k %d, hash %d\n",
                            version, cipher_algo, s2kmode, hash_algo);
-       if( s2kmode == 1  || s2kmode == 4 ) {
+       if( s2kmode == 1 || s2kmode == 3 ) {
            printf("\tsalt ");
            for(i=0; i < 8; i++ )
                printf("%02x", k->s2k.salt[i]);
-           if( s2kmode == 4 )
+           if( s2kmode == 3 )
                printf(", count %lu\n", (ulong)k->s2k.count );
            printf("\n");
        }
@@ -548,6 +583,7 @@ parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
     k->keyid[0] = read_32(inp); pktlen -= 4;
     k->keyid[1] = read_32(inp); pktlen -= 4;
     k->pubkey_algo = iobuf_get_noeof(inp); pktlen--;
+    k->throw_keyid = 0; /* only used as flag for build_packet */
     if( list_mode )
        printf(":pubkey enc packet: version %d, algo %d, keyid %08lX%08lX\n",
          k->version, k->pubkey_algo, (ulong)k->keyid[0], (ulong)k->keyid[1]);
@@ -577,6 +613,107 @@ parse_pubkeyenc( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
 }
 
 
+static void
+dump_sig_subpkt( int hashed, int type, int critical,
+                const byte *buffer, size_t buflen, size_t length )
+{
+    const char *p=NULL;
+    int i;
+
+    printf("\t%s%ssubpkt %d len %u (", /*)*/
+             critical ? "critical ":"",
+             hashed ? "hashed ":"", type, (unsigned)length );
+    buffer++;
+    length--;
+    if( length > buflen ) {
+       printf("too short: buffer is only %u)\n", (unsigned)buflen );
+       return;
+    }
+    switch( type ) {
+      case SIGSUBPKT_SIG_CREATED:
+       if( length >= 4 )
+           printf("sig created %s", strtimestamp( buffer_to_u32(buffer) ) );
+       break;
+      case SIGSUBPKT_SIG_EXPIRE:
+       if( length >= 4 )
+           printf("sig expires after %s",
+                                    strtimevalue( buffer_to_u32(buffer) ) );
+       break;
+      case SIGSUBPKT_EXPORTABLE:
+       if( length )
+           printf("%sexportable", *buffer? "":"not ");
+       break;
+      case SIGSUBPKT_TRUST:
+       p = "trust signature";
+       break;
+      case SIGSUBPKT_REGEXP:
+       p = "regular expression";
+       break;
+      case SIGSUBPKT_REVOCABLE:
+       p = "revocable";
+       break;
+      case SIGSUBPKT_KEY_EXPIRE:
+       if( length >= 4 )
+           printf("key expires after %s",
+                                   strtimevalue( buffer_to_u32(buffer) ) );
+       break;
+      case SIGSUBPKT_ARR:
+       p = "additional recipient request";
+       break;
+      case SIGSUBPKT_PREF_SYM:
+       fputs("pref-sym-algos:", stdout );
+       for( i=0; i < length; i++ )
+           printf(" %d", buffer[i] );
+       break;
+      case SIGSUBPKT_REV_KEY:
+       p = "revocation key";
+       break;
+      case SIGSUBPKT_ISSUER:
+       if( length >= 8 )
+           printf("issuer key ID %08lX%08lX",
+                     (ulong)buffer_to_u32(buffer),
+                     (ulong)buffer_to_u32(buffer+4) );
+       break;
+      case SIGSUBPKT_NOTATION:
+       p = "notation data";
+       break;
+      case SIGSUBPKT_PREF_HASH:
+       fputs("pref-hash-algos:", stdout );
+       for( i=0; i < length; i++ )
+           printf(" %d", buffer[i] );
+       break;
+      case SIGSUBPKT_PREF_COMPR:
+       fputs("pref-zip-algos:", stdout );
+       for( i=0; i < length; i++ )
+           printf(" %d", buffer[i] );
+       break;
+      case SIGSUBPKT_KS_FLAGS:
+       p = "key server preferences";
+       break;
+      case SIGSUBPKT_PREF_KS:
+       p = "preferred key server";
+       break;
+      case SIGSUBPKT_PRIMARY_UID:
+       p = "primary user id";
+       break;
+      case SIGSUBPKT_POLICY:
+       p = "policy URL";
+       break;
+      case SIGSUBPKT_KEY_FLAGS:
+       p = "key flags";
+       break;
+      case SIGSUBPKT_SIGNERS_UID:
+       p = "signer's user id";
+       break;
+      case SIGSUBPKT_PRIV_ADD_SIG:
+       p = "signs additional user id";
+       break;
+      default: p = "?"; break;
+    }
+
+    printf("%s)\n", p? p: "");
+}
+
 const byte *
 parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n )
 {
@@ -617,32 +754,9 @@ parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n )
        }
        else
            critical = 0;
-       if( reqtype < 0 ) { /* list packets */
-           printf("\t%ssubpacket %d of length %u (%s)\n",
-           reqtype == SIGSUBPKT_LIST_HASHED ? "hashed ":"", type, (unsigned)n,
-            type == SIGSUBPKT_SIG_CREATED ? "signature creation time"
-          : type == SIGSUBPKT_SIG_EXPIRE  ? "signature expiration time"
-          : type == SIGSUBPKT_EXPORTABLE  ? "exportable"
-          : type == SIGSUBPKT_TRUST       ? "trust signature"
-          : type == SIGSUBPKT_REGEXP      ? "regular expression"
-          : type == SIGSUBPKT_REVOCABLE   ? "revocable"
-          : type == SIGSUBPKT_KEY_EXPIRE  ? "key expiration time"
-          : type == SIGSUBPKT_ARR         ? "additional recipient request"
-          : type == SIGSUBPKT_PREF_SYM    ? "preferred symmetric algorithms"
-          : type == SIGSUBPKT_REV_KEY     ? "revocation key"
-          : type == SIGSUBPKT_ISSUER      ? "issuer key ID"
-          : type == SIGSUBPKT_NOTATION    ? "notation data"
-          : type == SIGSUBPKT_PREF_HASH   ? "preferred hash algorithms"
-          : type == SIGSUBPKT_PREF_COMPR  ? "preferred compression algorithms"
-          : type == SIGSUBPKT_KS_FLAGS    ? "key server preferences"
-          : type == SIGSUBPKT_PREF_KS     ? "preferred key server"
-          : type == SIGSUBPKT_PRIMARY_UID ? "primary user id"
-          : type == SIGSUBPKT_POLICY      ? "policy URL"
-          : type == SIGSUBPKT_KEY_FLAGS   ? "key flags"
-          : type == SIGSUBPKT_SIGNERS_UID ? "signer's user id"
-          : type == SIGSUBPKT_PRIV_ADD_SIG? "signs additional user id"
-                             : "?");
-       }
+       if( reqtype < 0 ) /* list packets */
+           dump_sig_subpkt( reqtype == SIGSUBPKT_LIST_HASHED,
+                                   type, critical, buffer, buflen, n );
        else if( type == reqtype )
            break; /* found */
        buffer += n; buflen -=n;
@@ -660,10 +774,18 @@ parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n )
        if( n < 4 )
            break;
        return buffer;
+      case SIGSUBPKT_EXPORTABLE:
+       if( !n )
+           break;
+       return buffer;
       case SIGSUBPKT_ISSUER:/* issuer key ID */
        if( n < 8 )
            break;
        return buffer;
+      case SIGSUBPKT_PREF_SYM:
+      case SIGSUBPKT_PREF_HASH:
+      case SIGSUBPKT_PREF_COMPR:
+       return buffer;
       case SIGSUBPKT_PRIV_ADD_SIG:
        /* because we use private data, we check the GNUPG marker */
        if( n < 24 )
@@ -682,6 +804,19 @@ parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n )
 }
 
 
+const byte *
+parse_sig_subpkt2( PKT_signature *sig, sigsubpkttype_t reqtype, size_t *ret_n )
+{
+    const byte *p;
+
+    p = parse_sig_subpkt( sig->hashed_data, reqtype, ret_n );
+    if( !p )
+       p = parse_sig_subpkt( sig->unhashed_data, reqtype, ret_n );
+    return p;
+}
+
+
+
 static int
 parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
                                          PKT_signature *sig )
@@ -763,12 +898,17 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen,
 
     if( is_v4 ) { /*extract required information */
        const byte *p;
+
+       /* FIXME: set sig->flags.unknown_critical is there is a
+        * critical bit set for packets which are not understood
+        * It does only make sense for hashed data.
+        */
        p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_SIG_CREATED, NULL );
        if( !p )
            log_error("signature packet without timestamp\n");
        else
            sig->timestamp = buffer_to_u32(p);
-       p = parse_sig_subpkt( sig->unhashed_data, SIGSUBPKT_ISSUER, NULL );
+       p = parse_sig_subpkt2( sig, SIGSUBPKT_ISSUER, NULL );
        if( !p )
            log_error("signature packet without keyid\n");
        else {
@@ -864,8 +1004,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
 {
     int i, version, algorithm;
     unsigned n;
-    unsigned long timestamp;
-    unsigned short valid_period;
+    unsigned long timestamp, expiredate;
     int npkey, nskey;
     int is_v4=0;
     int rc=0;
@@ -903,37 +1042,46 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
 
     timestamp = read_32(inp); pktlen -= 4;
     if( is_v4 )
-       valid_period = 0;
+       expiredate = 0; /* have to get it from the selfsignature */
     else {
-       valid_period = read_16(inp); pktlen -= 2;
+       unsigned short ndays;
+       ndays = read_16(inp); pktlen -= 2;
+       if( ndays )
+           expiredate = timestamp + ndays * 86400L;
+       else
+           expiredate = 0;
     }
     algorithm = iobuf_get_noeof(inp); pktlen--;
     if( list_mode )
        printf(":%s key packet:\n"
-              "\tversion %d, algo %d, created %lu, valid for %hu days\n",
+              "\tversion %d, algo %d, created %lu, expires %lu\n",
                pkttype == PKT_PUBLIC_KEY? "public" :
                pkttype == PKT_SECRET_KEY? "secret" :
                pkttype == PKT_PUBLIC_SUBKEY? "public sub" :
                pkttype == PKT_SECRET_SUBKEY? "secret sub" : "??",
-               version, algorithm, timestamp, valid_period );
+               version, algorithm, timestamp, expiredate );
 
     if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY )  {
        PKT_secret_key *sk = pkt->pkt.secret_key;
 
        sk->timestamp = timestamp;
-       sk->valid_days = valid_period;
+       sk->expiredate = expiredate;
        sk->hdrbytes = hdrlen;
        sk->version = version;
        sk->pubkey_algo = algorithm;
+       sk->pubkey_usage = 0; /* not yet used */
     }
     else {
        PKT_public_key *pk = pkt->pkt.public_key;
 
        pk->timestamp = timestamp;
-       pk->valid_days = valid_period;
+       pk->expiredate = expiredate;
        pk->hdrbytes    = hdrlen;
        pk->version     = version;
        pk->pubkey_algo = algorithm;
+       pk->pubkey_usage = 0; /* not yet used */
+       pk->keyid[0] = 0;
+       pk->keyid[1] = 0;
     }
     nskey = pubkey_get_nskey( algorithm );
     npkey = pubkey_get_npkey( algorithm );
@@ -944,7 +1092,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
     }
 
 
-    if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY )  {
+    if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY ) {
        PKT_secret_key *sk = pkt->pkt.secret_key;
        byte temp[8];
 
@@ -975,7 +1123,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
                sk->protect.s2k.hash_algo = iobuf_get_noeof(inp); pktlen--;
                switch( sk->protect.s2k.mode ) {
                  case 1:
-                 case 4:
+                 case 3:
                    for(i=0; i < 8 && pktlen; i++, pktlen-- )
                        temp[i] = iobuf_get_noeof(inp);
                    memcpy(sk->protect.s2k.salt, temp, 8 );
@@ -986,7 +1134,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
                    break;
                  case 1: if( list_mode ) printf(  "\tsalted S2K" );
                    break;
-                 case 4: if( list_mode ) printf(  "\titer+salt S2K" );
+                 case 3: if( list_mode ) printf(  "\titer+salt S2K" );
                    break;
                  default:
                    if( list_mode )
@@ -1001,7 +1149,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
                                     sk->protect.algo,
                                     sk->protect.s2k.hash_algo );
                    if( sk->protect.s2k.mode == 1
-                       || sk->protect.s2k.mode == 4 ) {
+                       || sk->protect.s2k.mode == 3 ) {
                        printf(", salt: ");
                        for(i=0; i < 8; i++ )
                            printf("%02x", sk->protect.s2k.salt[i]);
@@ -1009,23 +1157,25 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
                    putchar('\n');
                }
 
-               if( sk->protect.s2k.mode == 4 ) {
-                   if( pktlen < 4 ) {
+               if( sk->protect.s2k.mode == 3 ) {
+                   if( pktlen < 1 ) {
                        rc = G10ERR_INVALID_PACKET;
                        goto leave;
                    }
-                   sk->protect.s2k.count = read_32(inp);
-                   pktlen -= 4;
+                   sk->protect.s2k.count = iobuf_get(inp);
+                   pktlen--;
+                   if( list_mode )
+                       printf("\tprotect count: %lu\n",
+                                           (ulong)sk->protect.s2k.count);
                }
-
            }
            else { /* old version; no S2K, so we set mode to 0, hash MD5 */
                sk->protect.s2k.mode = 0;
                /* We need a kludge to cope with old GNUPG versions */
                sk->protect.s2k.hash_algo =
-                        ( sk->protect.algo == CIPHER_ALGO_BLOWFISH160
-                          && algorithm == PUBKEY_ALGO_ELGAMAL_E ) ?
-                                 DIGEST_ALGO_RMD160 : DIGEST_ALGO_MD5;
+                            ( sk->protect.algo == CIPHER_ALGO_BLOWFISH160
+                              && algorithm == PUBKEY_ALGO_ELGAMAL_E ) ?
+                                     DIGEST_ALGO_RMD160 : DIGEST_ALGO_MD5;
                if( list_mode )
                    printf(  "\tprotect algo: %d  (hash algo: %d)\n",
                         sk->protect.algo, sk->protect.s2k.hash_algo );
@@ -1034,6 +1184,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
                rc = G10ERR_INVALID_PACKET;
                goto leave;
            }
+           /* fixme: Add support for other blocksizes */
            for(i=0; i < 8 && pktlen; i++, pktlen-- )
                temp[i] = iobuf_get_noeof(inp);
            if( list_mode ) {
@@ -1050,25 +1201,37 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
         * If the user is so careless, not to protect his secret key,
         * we can assume, that he operates an open system :=(.
         * So we put the key into secure memory when we unprotect it. */
-
-       for(i=npkey; i < nskey; i++ ) {
-           n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
-           if( sk->is_protected )
-               mpi_set_protect_flag(sk->skey[i]);
+       if( is_v4 && sk->is_protected ){
+           /* ugly; the length is encrypted too, so we read all
+            * stuff up to the end of the packet into the first
+            * skey element */
+           sk->skey[npkey] = mpi_set_opaque(NULL,
+                                            read_rest2(inp, pktlen), pktlen );
+           pktlen = 0;
            if( list_mode ) {
-               printf(  "\tskey[%d]: ", i);
+               printf("\tencrypted stuff follows\n");
+           }
+       }
+       else { /* v3 method: the mpi length is not encrypted */
+           for(i=npkey; i < nskey; i++ ) {
+               n = pktlen; sk->skey[i] = mpi_read(inp, &n, 0 ); pktlen -=n;
                if( sk->is_protected )
-                   printf(  "[encrypted]\n");
-               else {
-                   mpi_print(stdout, sk->skey[i], mpi_print_mode  );
-                   putchar('\n');
+                   mpi_set_protect_flag(sk->skey[i]);
+               if( list_mode ) {
+                   printf(  "\tskey[%d]: ", i);
+                   if( sk->is_protected )
+                       printf(  "[encrypted]\n");
+                   else {
+                       mpi_print(stdout, sk->skey[i], mpi_print_mode  );
+                       putchar('\n');
+                   }
                }
            }
-       }
 
-       sk->csum = read_16(inp); pktlen -= 2;
-       if( list_mode ) {
-           printf("\tchecksum: %04hx\n", sk->csum);
+           sk->csum = read_16(inp); pktlen -= 2;
+           if( list_mode ) {
+               printf("\tchecksum: %04hx\n", sk->csum);
+           }
        }
     }
     else {