[Bps-public-commit] GnuPG-Interface branch, master, updated. 0.42-29-g3b5e1b3

Jesse Vincent jesse at bestpractical.com
Mon May 10 10:55:27 EDT 2010


The branch, master has been updated
       via  3b5e1b390bbbb9e67003b0a9a11bbfb416a1911e (commit)
       via  fa67e5adc6f8751030aadc9d3dcf871d501b341f (commit)
       via  a59a8afb44bea625fdf9b3e98badd6128b540c32 (commit)
       via  bd6059c8023b4f5e60d5dd8b647617bbea49dcb2 (commit)
       via  ea2e002c8e5b56f9d04ad42c6b326ced65cabbba (commit)
       via  47d5decb67b15a5a5b266c38d4a6cfeb0b94dc17 (commit)
       via  d528164d135c535720d1650eb2d44c429d4cbb02 (commit)
       via  01eab141d58d4b46ed6d6fc84695285ff832a361 (commit)
       via  a60f36f53c84d898c0411ad644e31836b0c465e6 (commit)
       via  0d83fa8ea2f31287a5c91203736e1441ace7d90b (commit)
       via  c18b29501c3e3f82eddc622f3db90aa37d42e8d5 (commit)
       via  9662af5bce7155b727bdd548b186d2cd2c361a12 (commit)
       via  ae0cb7df26398366dd6b1e9c7b7aa89ff6671b2b (commit)
       via  6a50ef51f1d1d2f560a41c3103d87dd96fe33c00 (commit)
       via  9c4287529265571db959080d527f67cf30b229c6 (commit)
       via  6007358acd4d21c5fc1ce9c0df36dee9c663c506 (commit)
       via  8cfccc75841d0c457258fd8885828c9c8e18ff81 (commit)
      from  8d4cb81eef38638a12136eaf55df0a0966a9688e (commit)

Summary of changes:
 ChangeLog                        |   32 ++++++++
 MANIFEST                         |    5 +-
 lib/GnuPG/Fingerprint.pm         |   11 +++
 lib/GnuPG/Interface.pm           |   93 ++++++++++++++++------
 lib/GnuPG/Key.pm                 |   55 +++++++++++++
 lib/GnuPG/PrimaryKey.pm          |    6 +-
 lib/GnuPG/Revoker.pm             |  159 ++++++++++++++++++++++++++++++++++++++
 lib/GnuPG/Signature.pm           |   78 ++++++++++++++++++-
 lib/GnuPG/SubKey.pm              |   31 +++++++-
 lib/GnuPG/UserAttribute.pm       |  119 ++++++++++++++++++++++++++++
 lib/GnuPG/UserId.pm              |   16 ++++
 t/GnuPG/ComparableFingerprint.pm |   29 -------
 t/GnuPG/ComparableKey.pm         |   20 ++++-
 t/GnuPG/ComparableSignature.pm   |   41 ----------
 t/GnuPG/ComparableSubKey.pm      |    9 +--
 t/GnuPG/ComparableUserId.pm      |   12 ++-
 t/get_public_keys.t              |   39 ++++++++--
 test/pubring.gpg                 |  Bin 3315 -> 3418 bytes
 test/secring.gpg                 |  Bin 1138 -> 1241 bytes
 19 files changed, 633 insertions(+), 122 deletions(-)
 create mode 100644 lib/GnuPG/Revoker.pm
 create mode 100644 lib/GnuPG/UserAttribute.pm
 delete mode 100644 t/GnuPG/ComparableFingerprint.pm
 delete mode 100644 t/GnuPG/ComparableSignature.pm

- Log -----------------------------------------------------------------
commit 8cfccc75841d0c457258fd8885828c9c8e18ff81
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Sun May 2 02:33:52 2010 -0400

    support more than 1 signature over each subkey

diff --git a/lib/GnuPG/Interface.pm b/lib/GnuPG/Interface.pm
index 5d25c61..8ffd66c 100644
--- a/lib/GnuPG/Interface.pm
+++ b/lib/GnuPG/Interface.pm
@@ -488,12 +488,10 @@ sub get_keys {
                 user_id_string => unescape_string($user_id_string),
             );
 
-            if ( $current_signed_item->isa('GnuPG::UserId') ) {
+            if ( $current_signed_item->isa('GnuPG::UserId') ||
+                 $current_signed_item->isa('GnuPG::SubKey') ) {
                 $current_signed_item->push_signatures($signature);
             }
-            elsif ( $current_signed_item->isa('GnuPG::SubKey') ) {
-                $current_signed_item->signature($signature);
-            }
             else {
                 warn "do not know how to handle signature line: $line\n";
             }
diff --git a/lib/GnuPG/SubKey.pm b/lib/GnuPG/SubKey.pm
index 4866b1d..b4743f3 100644
--- a/lib/GnuPG/SubKey.pm
+++ b/lib/GnuPG/SubKey.pm
@@ -15,13 +15,46 @@
 
 package GnuPG::SubKey;
 use Any::Moose;
+use Carp;
 BEGIN { extends qw( GnuPG::Key ) }
 
-has [qw( validity   owner_trust  local_id  signature )] => (
+has [qw( validity   owner_trust  local_id  )] => (
     isa => 'Any',
     is  => 'rw',
 );
 
+has signatures => (
+    isa       => 'ArrayRef',
+    is        => 'rw',
+    default   => sub { [] },
+);
+
+sub push_signatures {
+    my $self = shift;
+    push @{ $self->signatures }, @_;
+}
+
+# DEPRECATED!
+# return the last signature, if present.  Or push in a new signature,
+# if one is supplied.
+sub signature {
+  my $self = shift;
+  my $argcount = @_;
+
+  if ($argcount) {
+    carp("Please do not use GnuPG::SubKey::signature().  Use GnuPG::SubKey::push_signatures() instead, since subkeys can have more than one signature.");
+    $self->push_signatures(@_);
+  } else {
+    carp("Please do not use GnuPG::SubKey::signature.  Use GnuPG::SubKey::signatures instead, since subkeys can have more than one signature.");
+    my $sigcount = @{$self->signatures};
+    if ($sigcount) {
+      return $self->signatures->[$sigcount-1];
+    } else {
+      return undef;
+    }
+  }
+}
+
 __PACKAGE__->meta->make_immutable;
 
 1;
@@ -70,8 +103,17 @@ See GnuPG's DETAILS file for details.
 
 =item signature
 
-A GnuPG::Signature object holding the representation of the
-signature on this key.
+* DEPRECATED*
+
+A GnuPG::Signature object holding the representation of the signature
+on this key.  Please use signatures (see below) instead of signature.
+Using signature, you will get an arbitrary signature from the set of
+available signatures.
+
+=item signatures
+
+A list of GnuPG::Signature objects embodying the binding signatures on
+this subkey.
 
 =back
 
diff --git a/t/GnuPG/ComparableSignature.pm b/t/GnuPG/ComparableSignature.pm
index 0b3b21e..908a6a7 100644
--- a/t/GnuPG/ComparableSignature.pm
+++ b/t/GnuPG/ComparableSignature.pm
@@ -29,7 +29,6 @@ sub compare
     {
 	my $f1 = $self->$field();
 	my $f2 = $other->$field();
-	
 	# don't test for definedness because
 	# all fields should be defined
 	return 0 unless $self->$field() eq $other->$field();
diff --git a/t/GnuPG/ComparableSubKey.pm b/t/GnuPG/ComparableSubKey.pm
index c6a6ef2..f7e6df4 100644
--- a/t/GnuPG/ComparableSubKey.pm
+++ b/t/GnuPG/ComparableSubKey.pm
@@ -27,12 +27,24 @@ sub compare
     
     if ( $deep )
     {
-	bless $self->signature, 'GnuPG::ComparableSignature'
-	  if $self->signature();
+
+      my @self_signatures  = @{$self->signatures()};
+      my @other_signatures = @{$other->signatures()};
+
+      return 0 unless @self_signatures == @other_signatures;
+
+      my $num_sigs = @self_signatures;
+
+      for ( my $i = 0; $i < $num_sigs; $i++ )
+        {
+          return 0
+            unless $self_signatures[$i]->compare( $other_signatures[$i], 1 );
+        }
+
 	bless $self->fingerprint, 'GnuPG::ComparableFingerprint'
 	  if $self->fingerprint();
 	
-	foreach my $field ( qw( signature fingerprint ) )
+	foreach my $field ( qw( fingerprint ) )
 	{
 	    my $f1 = $self->$field();
 	    my $f2 = $other->$field();
diff --git a/t/get_public_keys.t b/t/get_public_keys.t
index 6ccb360..d89f190 100644
--- a/t/get_public_keys.t
+++ b/t/get_public_keys.t
@@ -42,11 +42,12 @@ TEST
 			       )
       );
     
-    my $initial_self_signature = GnuPG::Signature->new
+    my $subkey_signature = GnuPG::ComparableSignature->new
       ( algo_num       => 17,
 	hex_id         => '53AE596EF950DA9C',
-        date           => 949813093,
-	date_string    => '2000-02-06',
+        date           => 1177086380,
+	date_string    => '2007-04-20',
+        user_id_string => 'GnuPG test key (for testing purposes only)',
       );
     
     my $uid2_signature = GnuPG::Signature->new
@@ -80,7 +81,7 @@ TEST
 			       )
       );
     
-    $subkey->signature( $initial_self_signature );
+    $subkey->push_signatures( $subkey_signature );
     
     $handmade_key->push_subkeys( $subkey );
     

commit 6007358acd4d21c5fc1ce9c0df36dee9c663c506
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Sun May 9 17:29:28 2010 -0400

    adopt suggestions from Jesse Vincent: do not carp on use of the deprecated G:SubKey->signature(), and default behavor when G:SubKey-signature() is called with an argument is to clear the signatures list before pushing to it

diff --git a/lib/GnuPG/SubKey.pm b/lib/GnuPG/SubKey.pm
index b4743f3..568aaad 100644
--- a/lib/GnuPG/SubKey.pm
+++ b/lib/GnuPG/SubKey.pm
@@ -42,10 +42,9 @@ sub signature {
   my $argcount = @_;
 
   if ($argcount) {
-    carp("Please do not use GnuPG::SubKey::signature().  Use GnuPG::SubKey::push_signatures() instead, since subkeys can have more than one signature.");
+    @{$self->signatures} = ();
     $self->push_signatures(@_);
   } else {
-    carp("Please do not use GnuPG::SubKey::signature.  Use GnuPG::SubKey::signatures instead, since subkeys can have more than one signature.");
     my $sigcount = @{$self->signatures};
     if ($sigcount) {
       return $self->signatures->[$sigcount-1];

commit 9c4287529265571db959080d527f67cf30b229c6
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Sun May 2 02:35:10 2010 -0400

    actually check validity of signatures and report them

diff --git a/lib/GnuPG/Interface.pm b/lib/GnuPG/Interface.pm
index 8ffd66c..90a2145 100644
--- a/lib/GnuPG/Interface.pm
+++ b/lib/GnuPG/Interface.pm
@@ -365,7 +365,7 @@ sub get_public_keys_with_sigs ( $@ ) {
     my ( $self, @key_ids ) = @_;
 
     return $self->get_keys(
-        commands     => ['--list-sigs'],
+        commands     => ['--check-sigs'],
         command_args => [@key_ids],
     );
 }
@@ -464,11 +464,12 @@ sub get_keys {
         }
         elsif ( $record_type eq 'sig' ) {
             my (
+                $validity,
                 $algo_num,              $hex_key_id,
                 $signature_date,
                 $expiration_date,
                 $user_id_string
-            ) = @fields[ 3 .. 6, 9 ];
+            ) = @fields[ 1, 3 .. 6, 9 ];
 
             my $expiration_date_string;
             if ($expiration_date eq '') {
@@ -479,6 +480,7 @@ sub get_keys {
             my $signature_date_string = $self->_downrez_date($signature_date);
 
             my $signature = GnuPG::Signature->new(
+                validity       => $validity,
                 algo_num       => $algo_num,
                 hex_id         => $hex_key_id,
                 date           => $signature_date,
diff --git a/lib/GnuPG/Signature.pm b/lib/GnuPG/Signature.pm
index f0e200d..0cf00b4 100644
--- a/lib/GnuPG/Signature.pm
+++ b/lib/GnuPG/Signature.pm
@@ -16,11 +16,23 @@
 package GnuPG::Signature;
 use Any::Moose;
 
-has [qw( algo_num hex_id user_id_string date date_string expiration_date expiration_date_string )] => (
+has [qw( validity
+         algo_num
+         hex_id
+         user_id_string
+         date
+         date_string
+         expiration_date
+         expiration_date_string )] => (
     isa => 'Any',
     is  => 'rw',
 );
 
+sub is_valid {
+    my $self = shift;
+    return $self->validity eq '!';
+}
+
 __PACKAGE__->meta->make_immutable;
 
 1;
@@ -51,12 +63,26 @@ They embody various aspects of a GnuPG signature on a key.
 This methods creates a new object.  The optional arguments are
 initialization of data members.
 
+=item is_valid()
+
+Returns 1 if GnuPG was able to cryptographically verify the signature,
+otherwise 0.
+
 =back
 
 =head1 OBJECT DATA MEMBERS
 
 =over 4
 
+=item validity
+
+A character indicating the cryptographic validity of the key.  GnuPG
+uses at least the following characters: "!" means valid, "-" means not
+valid, "?" means unknown (e.g. if the supposed signing key is not
+present in the local keyring), and "%" means an error occurred (e.g. a
+non-supported algorithm).  See the documentation for --check-sigs in
+gpg(1).
+
 =item algo_num
 
 The number of the algorithm used for the signature.
diff --git a/t/GnuPG/ComparableSignature.pm b/t/GnuPG/ComparableSignature.pm
index 908a6a7..6a16bbf 100644
--- a/t/GnuPG/ComparableSignature.pm
+++ b/t/GnuPG/ComparableSignature.pm
@@ -23,7 +23,7 @@ sub compare
 {
     my ( $self, $other ) = @_;
     
-    my @compared_fields = qw( algo_num hex_id date date_string );
+    my @compared_fields = qw( validity algo_num hex_id date date_string );
     
     foreach my $field ( @compared_fields )
     {
diff --git a/t/get_public_keys.t b/t/get_public_keys.t
index d89f190..60b76a5 100644
--- a/t/get_public_keys.t
+++ b/t/get_public_keys.t
@@ -43,7 +43,8 @@ TEST
       );
     
     my $subkey_signature = GnuPG::ComparableSignature->new
-      ( algo_num       => 17,
+      ( validity       => '!',
+        algo_num       => 17,
 	hex_id         => '53AE596EF950DA9C',
         date           => 1177086380,
 	date_string    => '2007-04-20',
@@ -51,14 +52,16 @@ TEST
       );
     
     my $uid2_signature = GnuPG::Signature->new
-      ( algo_num       => 17,
+      ( validity       => '!',
+        algo_num       => 17,
         hex_id         => '53AE596EF950DA9C',
         date           => 953179891,
         date_string    => '2000-03-16',
       );
     
     my $ftobin_signature = GnuPG::Signature->new
-      ( algo_num       => 17,
+      ( validity       => '!',
+        algo_num       => 17,
 	hex_id         => '56FFD10A260C4FA3',
         date           => 953180097,
 	date_string    => '2000-03-16',

commit 6a50ef51f1d1d2f560a41c3103d87dd96fe33c00
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Sun May 2 02:35:55 2010 -0400

    introducing GnuPG::UserAttribute to handle uat packets

diff --git a/MANIFEST b/MANIFEST
index da702f9..12ea121 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -20,6 +20,7 @@ lib/GnuPG/SecretKey.pm
 lib/GnuPG/Signature.pm
 lib/GnuPG/SubKey.pm
 lib/GnuPG/UserId.pm
+lib/GnuPG/UserAttribute.pm
 Makefile.PL
 MANIFEST			This list of files
 MANIFEST.SKIP
diff --git a/lib/GnuPG/Interface.pm b/lib/GnuPG/Interface.pm
index 90a2145..0761b04 100644
--- a/lib/GnuPG/Interface.pm
+++ b/lib/GnuPG/Interface.pm
@@ -406,6 +406,7 @@ sub get_keys {
     require GnuPG::SubKey;
     require GnuPG::Fingerprint;
     require GnuPG::UserId;
+    require GnuPG::UserAttribute;
     require GnuPG::Signature;
 
     while (<$stdout>) {
@@ -491,6 +492,7 @@ sub get_keys {
             );
 
             if ( $current_signed_item->isa('GnuPG::UserId') ||
+                 $current_signed_item->isa('GnuPG::UserAttribute') ||
                  $current_signed_item->isa('GnuPG::SubKey') ) {
                 $current_signed_item->push_signatures($signature);
             }
@@ -508,6 +510,19 @@ sub get_keys {
 
             $current_key->push_user_ids($current_signed_item);
         }
+        elsif ( $record_type eq 'uat' ) {
+            my ( $validity, $subpacket ) = @fields[ 1, 9 ];
+
+            my ( $subpacket_count, $subpacket_total_size ) = split(/ /,$subpacket);
+
+            $current_signed_item = GnuPG::UserAttribute->new(
+                validity  => $validity,
+                subpacket_count => $subpacket_count,
+                subpacket_total_size => $subpacket_total_size,
+            );
+
+            $current_key->push_user_attributes($current_signed_item);
+        }
         elsif ( $record_type eq 'sub' or $record_type eq 'ssb' ) {
             my (
                 $validity, $key_length, $algo_num, $hex_id,
diff --git a/lib/GnuPG/PrimaryKey.pm b/lib/GnuPG/PrimaryKey.pm
index d84bfa7..1c61d2c 100644
--- a/lib/GnuPG/PrimaryKey.pm
+++ b/lib/GnuPG/PrimaryKey.pm
@@ -18,7 +18,7 @@ use Any::Moose;
 
 BEGIN { extends qw( GnuPG::Key ) }
 
-for my $list (qw(user_ids subkeys)) {
+for my $list (qw(user_ids subkeys user_attributes)) {
     has $list => (
         isa        => 'ArrayRef',
         is         => 'rw',
@@ -78,6 +78,10 @@ in L<GnuPG::Key>.
 
 A list of GnuPG::UserId objects associated with this key.
 
+=item user_attributes
+
+A list of GnuPG::UserAttribute objects associated with this key.
+
 =item subkeys
 
 A list of GnuPG::SubKey objects associated with this key.
diff --git a/lib/GnuPG/UserAttribute.pm b/lib/GnuPG/UserAttribute.pm
new file mode 100644
index 0000000..d834312
--- /dev/null
+++ b/lib/GnuPG/UserAttribute.pm
@@ -0,0 +1,104 @@
+#  UserAttribute.pm
+#    - providing an object-oriented approach to GnuPG user attributes
+#
+#  Copyright (C) 2010 Daniel Kahn Gillmor <dkg at fifthhorseman.net>
+#  (derived from UserId.pm, Copyright (C) 2000 Frank J. Tobin <ftobin at cpan.org>)
+#
+#  This module is free software; you can redistribute it and/or modify it
+#  under the same terms as Perl itself.
+#
+#  This program 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.
+#
+#  $Id: UserId.pm,v 1.7 2001/08/21 13:31:50 ftobin Exp $
+#
+
+package GnuPG::UserAttribute;
+use Any::Moose;
+
+has [qw( validity subpacket_count subpacket_total_size )] => (
+    isa => 'Any',
+    is  => 'rw',
+);
+
+has signatures => (
+    isa       => 'ArrayRef',
+    is        => 'rw',
+    default   => sub { [] },
+);
+
+sub push_signatures {
+    my $self = shift;
+    push @{ $self->signatures }, @_;
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
+
+__END__
+
+=head1 NAME
+
+GnuPG::UserAttribute - GnuPG User Attribute Objects
+
+=head1 SYNOPSIS
+
+  # assumes a GnuPG::PublicKey object in $publickey
+  my $jpgs_size = $publickey->user_attributes->[0]->subpacket_total_size();
+
+=head1 DESCRIPTION
+
+GnuPG::UserAttribute objects are generally not instantiated on their
+own, but rather as part of GnuPG::PublicKey or GnuPG::SecretKey
+objects.
+
+=head1 OBJECT METHODS
+
+=over 4
+
+=item new( I<%initialization_args> )
+
+This methods creates a new object.  The optional arguments are
+initialization of data members;
+
+=back
+
+=head1 OBJECT DATA MEMBERS
+
+=over 4
+
+=item validity
+
+A scalar holding the value GnuPG reports for the calculated validity
+of the binding between this User Attribute packet and its associated
+primary key.  See GnuPG's DETAILS file for details.
+
+=item subpacket_count
+
+A scalar holding the number of attribute subpackets.  This is usually
+1, as most UATs seen in the wild contain a single image in JPEG
+format.
+
+=item subpacket_total_size
+
+A scalar holding the total byte count of all attribute subpackets.
+
+=item signatures
+
+A list of GnuPG::Signature objects embodying the signatures
+on this user attribute.
+
+=back
+
+=head1 BUGS
+
+No useful information about the embedded attributes is provided yet.
+It would be nice to be able to get ahold of the raw JPEG material.
+
+=head1 SEE ALSO
+
+L<GnuPG::Signature>,
+
+=cut

commit ae0cb7df26398366dd6b1e9c7b7aa89ff6671b2b
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Tue May 4 17:56:10 2010 -0400

    add signature class and exportability to GnuPG::Signature

diff --git a/lib/GnuPG/Interface.pm b/lib/GnuPG/Interface.pm
index 0761b04..b01c985 100644
--- a/lib/GnuPG/Interface.pm
+++ b/lib/GnuPG/Interface.pm
@@ -469,8 +469,9 @@ sub get_keys {
                 $algo_num,              $hex_key_id,
                 $signature_date,
                 $expiration_date,
-                $user_id_string
-            ) = @fields[ 1, 3 .. 6, 9 ];
+                $user_id_string,
+                $sig_type,
+            ) = @fields[ 1, 3 .. 6, 9, 10 ];
 
             my $expiration_date_string;
             if ($expiration_date eq '') {
@@ -480,6 +481,12 @@ sub get_keys {
             }
             my $signature_date_string = $self->_downrez_date($signature_date);
 
+            my ($sig_class, $is_exportable);
+            if ($sig_type =~ /^([[:xdigit:]]{2})([xl])$/ ) {
+              $sig_class = hex($1);
+              $is_exportable = ('x' eq $2);
+            }
+
             my $signature = GnuPG::Signature->new(
                 validity       => $validity,
                 algo_num       => $algo_num,
@@ -489,6 +496,8 @@ sub get_keys {
                 expiration_date => $expiration_date,
                 expiration_date_string => $expiration_date_string,
                 user_id_string => unescape_string($user_id_string),
+                sig_class      => $sig_class,
+                is_exportable  => $is_exportable,
             );
 
             if ( $current_signed_item->isa('GnuPG::UserId') ||
diff --git a/lib/GnuPG/Signature.pm b/lib/GnuPG/Signature.pm
index 0cf00b4..f2ae5d6 100644
--- a/lib/GnuPG/Signature.pm
+++ b/lib/GnuPG/Signature.pm
@@ -16,14 +16,18 @@
 package GnuPG::Signature;
 use Any::Moose;
 
-has [qw( validity
+has [qw(
+         validity
          algo_num
          hex_id
          user_id_string
          date
          date_string
          expiration_date
-         expiration_date_string )] => (
+         expiration_date_string
+         sig_class
+         is_exportable
+      )] => (
     isa => 'Any',
     is  => 'rw',
 );
@@ -96,6 +100,18 @@ The hex id of the signing key.
 The first user id string on the key that made the signature.
 This may not be defined if the signing key is not on the local keyring.
 
+=item sig_class
+
+Signature class.  This is the numeric value of the class of signature.
+
+A table of possible classes of signatures and their numeric types can
+be found at http://tools.ietf.org/html/rfc4880#section-5.2.1
+
+=item is_exportable
+
+returns 0 for local-only signatures, non-zero for exportable
+signatures.
+
 =item date_string
 
 The formatted date the signature was performed on.
diff --git a/t/GnuPG/ComparableSignature.pm b/t/GnuPG/ComparableSignature.pm
index 6a16bbf..b70304c 100644
--- a/t/GnuPG/ComparableSignature.pm
+++ b/t/GnuPG/ComparableSignature.pm
@@ -23,7 +23,7 @@ sub compare
 {
     my ( $self, $other ) = @_;
     
-    my @compared_fields = qw( validity algo_num hex_id date date_string );
+    my @compared_fields = qw( validity algo_num hex_id date date_string is_exportable sig_class );
     
     foreach my $field ( @compared_fields )
     {
diff --git a/t/get_public_keys.t b/t/get_public_keys.t
index 60b76a5..7f67320 100644
--- a/t/get_public_keys.t
+++ b/t/get_public_keys.t
@@ -49,6 +49,8 @@ TEST
         date           => 1177086380,
 	date_string    => '2007-04-20',
         user_id_string => 'GnuPG test key (for testing purposes only)',
+        sig_class      => 0x18,
+        is_exportable  => 1,
       );
     
     my $uid2_signature = GnuPG::Signature->new

commit 9662af5bce7155b727bdd548b186d2cd2c361a12
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Tue May 4 18:48:10 2010 -0400

    add revocations to keys and user ids and user attributes

diff --git a/lib/GnuPG/Interface.pm b/lib/GnuPG/Interface.pm
index b01c985..2bb45d9 100644
--- a/lib/GnuPG/Interface.pm
+++ b/lib/GnuPG/Interface.pm
@@ -463,7 +463,9 @@ sub get_keys {
             my $f = GnuPG::Fingerprint->new( as_hex_string => $hex );
             $current_fingerprinted_key->fingerprint($f);
         }
-        elsif ( $record_type eq 'sig' ) {
+        elsif ( $record_type eq 'sig' or
+                $record_type eq 'rev'
+              ) {
             my (
                 $validity,
                 $algo_num,              $hex_key_id,
@@ -500,12 +502,19 @@ sub get_keys {
                 is_exportable  => $is_exportable,
             );
 
-            if ( $current_signed_item->isa('GnuPG::UserId') ||
-                 $current_signed_item->isa('GnuPG::UserAttribute') ||
-                 $current_signed_item->isa('GnuPG::SubKey') ) {
+            if ($record_type eq 'sig') {
+              if ( $current_signed_item->isa('GnuPG::UserId') ||
+                   $current_signed_item->isa('GnuPG::UserAttribute') ||
+                   $current_signed_item->isa('GnuPG::SubKey') ) {
                 $current_signed_item->push_signatures($signature);
-            }
-            else {
+              }
+            } elsif ($record_type eq 'rev') {
+              if ( $current_signed_item->isa('GnuPG::Key') ||
+                   $current_signed_item->isa('GnuPG::UserId') ||
+                   $current_signed_item->isa('GnuPG::UserAttribute')) {
+                $current_signed_item->push_revocations($signature);
+              }
+            } else {
                 warn "do not know how to handle signature line: $line\n";
             }
         }
diff --git a/lib/GnuPG/Key.pm b/lib/GnuPG/Key.pm
index bd27611..6586ada 100644
--- a/lib/GnuPG/Key.pm
+++ b/lib/GnuPG/Key.pm
@@ -34,6 +34,17 @@ has [
     is  => 'rw',
     );
 
+has revocations => (
+    isa       => 'ArrayRef',
+    is        => 'rw',
+    default   => sub { [] },
+);
+
+sub push_revocations {
+    my $self = shift;
+    push @{ $self->revocations }, @_;
+}
+
 sub short_hex_id {
     my ($self) = @_;
     return substr $self->hex_id(), -8;
@@ -137,6 +148,13 @@ expiration_date will return undef.
 
 A GnuPG::Fingerprint object.
 
+=item revocations
+
+A list of revocations associated with this key, stored as
+GnuPG::Signature objects (since revocations are a type of
+certification as well).  Note that a revocation of a primary key has a
+different semantic meaning than a revocation associated with a subkey.
+
 =back
 
 =head1 SEE ALSO
diff --git a/lib/GnuPG/UserAttribute.pm b/lib/GnuPG/UserAttribute.pm
index d834312..22ffbd1 100644
--- a/lib/GnuPG/UserAttribute.pm
+++ b/lib/GnuPG/UserAttribute.pm
@@ -27,11 +27,20 @@ has signatures => (
     is        => 'rw',
     default   => sub { [] },
 );
+has revocations => (
+    isa       => 'ArrayRef',
+    is        => 'rw',
+    default   => sub { [] },
+);
 
 sub push_signatures {
     my $self = shift;
     push @{ $self->signatures }, @_;
 }
+sub push_revocations {
+    my $self = shift;
+    push @{ $self->revocations }, @_;
+}
 
 __PACKAGE__->meta->make_immutable;
 
@@ -90,6 +99,12 @@ A scalar holding the total byte count of all attribute subpackets.
 A list of GnuPG::Signature objects embodying the signatures
 on this user attribute.
 
+=item revocations
+
+A list of revocations associated with this User Attribute, stored as
+GnuPG::Signature objects (since revocations are a type of
+certification as well).
+
 =back
 
 =head1 BUGS
diff --git a/lib/GnuPG/UserId.pm b/lib/GnuPG/UserId.pm
index ad37ea5..d75b273 100644
--- a/lib/GnuPG/UserId.pm
+++ b/lib/GnuPG/UserId.pm
@@ -26,11 +26,21 @@ has signatures => (
     is        => 'rw',
     default   => sub { [] },
 );
+has revocations => (
+    isa       => 'ArrayRef',
+    is        => 'rw',
+    default   => sub { [] },
+);
 
 sub push_signatures {
     my $self = shift;
     push @{ $self->signatures }, @_;
 }
+sub push_revocations {
+    my $self = shift;
+    push @{ $self->revocations }, @_;
+}
+
 
 # DEPRECATED
 sub user_id_string {
@@ -90,6 +100,12 @@ See GnuPG's DETAILS file for details.
 A list of GnuPG::Signature objects embodying the signatures
 on this user id.
 
+=item revocations
+
+A list of revocations associated with this User ID, stored as
+GnuPG::Signature objects (since revocations are a type of
+certification as well).
+
 =back
 
 =head1 SEE ALSO
diff --git a/t/GnuPG/ComparableKey.pm b/t/GnuPG/ComparableKey.pm
index db28d1a..df6d5ec 100644
--- a/t/GnuPG/ComparableKey.pm
+++ b/t/GnuPG/ComparableKey.pm
@@ -48,8 +48,14 @@ sub compare
 sub _deeply_compare
 {
     my ( $self, $other ) = @_;
+    my $i;
+
+    for ( $i = 0; $i < scalar(@{$self->revocations}); $i++ ) {
+      return 0
+        unless $self->revocations->[$i]->compare($other->revocations->[$i], 1);
+    }
+
     bless $self->fingerprint(), 'GnuPG::ComparableFingerprint';
-    
     return ( $self->fingerprint->compare( $other->fingerprint() ) );
 }
 
diff --git a/t/GnuPG/ComparableUserId.pm b/t/GnuPG/ComparableUserId.pm
index 11efc40..ff9fb02 100644
--- a/t/GnuPG/ComparableUserId.pm
+++ b/t/GnuPG/ComparableUserId.pm
@@ -42,14 +42,20 @@ sub _deeply_compare
     return 0 unless @self_signatures == @other_signatures;
     
     my $num_sigs = @self_signatures;
+    my $i;
     
-    for ( my $i = 0; $i < $num_sigs; $i++ )
+    for ( $i = 0; $i < $num_sigs; $i++ )
     {
-	
 	return 0
 	  unless $self_signatures[$i]->compare( $other_signatures[$i], 1 );
     }
-    
+
+    # FIXME: what if the other item has revocations that we don't have?
+    for ( $i = 0; $i < scalar(@{$self->revocations}); $i++ ) {
+      return 0
+        unless $self->revocations()->[$i]->compare($other->revocations()->[$i], 1);
+    }
+
     return 1;
 }
 

commit c18b29501c3e3f82eddc622f3db90aa37d42e8d5
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Thu May 6 23:31:50 2010 -0400

    allow for primary key to have per-key (useful for signatures of class 0x1f, see http://tools.ietf.org/html/rfc4880#section-5.2.1)

diff --git a/lib/GnuPG/Interface.pm b/lib/GnuPG/Interface.pm
index 2bb45d9..890a699 100644
--- a/lib/GnuPG/Interface.pm
+++ b/lib/GnuPG/Interface.pm
@@ -457,6 +457,7 @@ sub get_keys {
                 usage_flags            => $usage_flags,
             );
 
+            $current_signed_item = $current_key;
         }
         elsif ( $record_type eq 'fpr' ) {
             my $hex = $fields[9];
@@ -502,20 +503,16 @@ sub get_keys {
                 is_exportable  => $is_exportable,
             );
 
-            if ($record_type eq 'sig') {
-              if ( $current_signed_item->isa('GnuPG::UserId') ||
-                   $current_signed_item->isa('GnuPG::UserAttribute') ||
-                   $current_signed_item->isa('GnuPG::SubKey') ) {
+            if ( $current_signed_item->isa('GnuPG::Key') ||
+                 $current_signed_item->isa('GnuPG::UserId') ||
+                 $current_signed_item->isa('GnuPG::UserAttribute')) {
+              if ($record_type eq 'sig') {
                 $current_signed_item->push_signatures($signature);
-              }
-            } elsif ($record_type eq 'rev') {
-              if ( $current_signed_item->isa('GnuPG::Key') ||
-                   $current_signed_item->isa('GnuPG::UserId') ||
-                   $current_signed_item->isa('GnuPG::UserAttribute')) {
+              } elsif ($record_type eq 'rev') {
                 $current_signed_item->push_revocations($signature);
               }
             } else {
-                warn "do not know how to handle signature line: $line\n";
+              warn "do not know how to handle signature line: $line\n";
             }
         }
         elsif ( $record_type eq 'uid' ) {
diff --git a/lib/GnuPG/Key.pm b/lib/GnuPG/Key.pm
index 6586ada..1b0ee1a 100644
--- a/lib/GnuPG/Key.pm
+++ b/lib/GnuPG/Key.pm
@@ -34,6 +34,17 @@ has [
     is  => 'rw',
     );
 
+has signatures => (
+    isa       => 'ArrayRef',
+    is        => 'rw',
+    default   => sub { [] },
+);
+
+sub push_signatures {
+    my $self = shift;
+    push @{ $self->signatures }, @_;
+}
+
 has revocations => (
     isa       => 'ArrayRef',
     is        => 'rw',
@@ -148,6 +159,13 @@ expiration_date will return undef.
 
 A GnuPG::Fingerprint object.
 
+=item signatures
+
+A list of GnuPG::Signature objects embodying the signatures on this
+key.  For subkeys, the signatures are usually subkey-binding
+signatures.  For primary keys, the signatures are statements about the
+key itself.
+
 =item revocations
 
 A list of revocations associated with this key, stored as
diff --git a/lib/GnuPG/SubKey.pm b/lib/GnuPG/SubKey.pm
index 568aaad..1e5f606 100644
--- a/lib/GnuPG/SubKey.pm
+++ b/lib/GnuPG/SubKey.pm
@@ -23,17 +23,6 @@ has [qw( validity   owner_trust  local_id  )] => (
     is  => 'rw',
 );
 
-has signatures => (
-    isa       => 'ArrayRef',
-    is        => 'rw',
-    default   => sub { [] },
-);
-
-sub push_signatures {
-    my $self = shift;
-    push @{ $self->signatures }, @_;
-}
-
 # DEPRECATED!
 # return the last signature, if present.  Or push in a new signature,
 # if one is supplied.
@@ -105,14 +94,9 @@ See GnuPG's DETAILS file for details.
 * DEPRECATED*
 
 A GnuPG::Signature object holding the representation of the signature
-on this key.  Please use signatures (see below) instead of signature.
-Using signature, you will get an arbitrary signature from the set of
-available signatures.
-
-=item signatures
-
-A list of GnuPG::Signature objects embodying the binding signatures on
-this subkey.
+on this key.  Please use signatures (see L<GnuPG::Key>) instead of
+signature.  Using signature, you will get an arbitrary signature from
+the set of available signatures.
 
 =back
 

commit 0d83fa8ea2f31287a5c91203736e1441ace7d90b
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Thu May 6 23:54:51 2010 -0400

    fixed synopsis example in GnuPG::Signature pod

diff --git a/lib/GnuPG/Signature.pm b/lib/GnuPG/Signature.pm
index f2ae5d6..4172c7c 100644
--- a/lib/GnuPG/Signature.pm
+++ b/lib/GnuPG/Signature.pm
@@ -49,8 +49,8 @@ GnuPG::Signature - GnuPG Key Signature Objects
 
 =head1 SYNOPSIS
 
-  # assumes a GnuPG::SubKey object in $key
-  my $signing_id = $key->signature->hex_id();
+  # assumes a GnuPG::Key or GnuPG::UserID or GnuPG::UserAttribute object in $signed
+  my $signing_id = $signed->signatures->[0]->hex_id();
 
 =head1 DESCRIPTION
 

commit a60f36f53c84d898c0411ad644e31836b0c465e6
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Fri May 7 01:14:58 2010 -0400

    change around some variable names for consistency's sake:
    
      $current_key becomes $current_primary_key
      $current_fingerprinted_key becomes $current_key
    
    This is because keys (both primary and sub) can have more than just
    fingerprints following them.  The parser might want to know what was
    the last key seen (either primary or sub) *and* it might want to know
    the last primary key seen, since this will be associated with the sub
    keys.

diff --git a/lib/GnuPG/Interface.pm b/lib/GnuPG/Interface.pm
index 890a699..75b5ae1 100644
--- a/lib/GnuPG/Interface.pm
+++ b/lib/GnuPG/Interface.pm
@@ -397,9 +397,9 @@ sub get_keys {
     );
 
     my @returned_keys;
-    my $current_key;
+    my $current_primary_key;
     my $current_signed_item;
-    my $current_fingerprinted_key;
+    my $current_key;
 
     require GnuPG::PublicKey;
     require GnuPG::SecretKey;
@@ -418,8 +418,8 @@ sub get_keys {
         my $record_type = $fields[0];
 
         if ( $record_type eq 'pub' or $record_type eq 'sec' ) {
-            push @returned_keys, $current_key
-                if $current_key;
+            push @returned_keys, $current_primary_key
+                if $current_primary_key;
 
             my (
                 $user_id_validity, $key_length, $algo_num, $hex_key_id,
@@ -439,12 +439,12 @@ sub get_keys {
             }
             my $creation_date_string = $self->_downrez_date($creation_date);
 
-            $current_key = $current_fingerprinted_key
+            $current_primary_key = $current_key
                 = $record_type eq 'pub'
                 ? GnuPG::PublicKey->new()
                 : GnuPG::SecretKey->new();
 
-            $current_key->hash_init(
+            $current_primary_key->hash_init(
                 length                 => $key_length,
                 algo_num               => $algo_num,
                 hex_id                 => $hex_key_id,
@@ -457,12 +457,12 @@ sub get_keys {
                 usage_flags            => $usage_flags,
             );
 
-            $current_signed_item = $current_key;
+            $current_signed_item = $current_primary_key;
         }
         elsif ( $record_type eq 'fpr' ) {
             my $hex = $fields[9];
             my $f = GnuPG::Fingerprint->new( as_hex_string => $hex );
-            $current_fingerprinted_key->fingerprint($f);
+            $current_key->fingerprint($f);
         }
         elsif ( $record_type eq 'sig' or
                 $record_type eq 'rev'
@@ -523,7 +523,7 @@ sub get_keys {
                 as_string => unescape_string($user_id_string),
             );
 
-            $current_key->push_user_ids($current_signed_item);
+            $current_primary_key->push_user_ids($current_signed_item);
         }
         elsif ( $record_type eq 'uat' ) {
             my ( $validity, $subpacket ) = @fields[ 1, 9 ];
@@ -536,7 +536,7 @@ sub get_keys {
                 subpacket_total_size => $subpacket_total_size,
             );
 
-            $current_key->push_user_attributes($current_signed_item);
+            $current_primary_key->push_user_attributes($current_signed_item);
         }
         elsif ( $record_type eq 'sub' or $record_type eq 'ssb' ) {
             my (
@@ -555,7 +555,7 @@ sub get_keys {
             }
             my $creation_date_string = $self->_downrez_date($creation_date);
 
-            $current_signed_item = $current_fingerprinted_key
+            $current_signed_item = $current_key
                 = GnuPG::SubKey->new(
                 validity               => $validity,
                 length                 => $key_length,
@@ -569,7 +569,7 @@ sub get_keys {
                 usage_flags            => $usage_flags,
                 );
 
-            $current_key->push_subkeys($current_signed_item);
+            $current_primary_key->push_subkeys($current_signed_item);
         }
         elsif ( $record_type ne 'tru' ) {
             warn "unknown record type $record_type";
@@ -578,8 +578,8 @@ sub get_keys {
 
     waitpid $pid, 0;
 
-    push @returned_keys, $current_key
-        if $current_key;
+    push @returned_keys, $current_primary_key
+        if $current_primary_key;
 
     $self->options($saved_options);
 

commit 01eab141d58d4b46ed6d6fc84695285ff832a361
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Sun May 9 19:59:53 2010 -0400

    move fingerprint comparison directly into GnuPG::Fingerprint

diff --git a/lib/GnuPG/Fingerprint.pm b/lib/GnuPG/Fingerprint.pm
index 1335d30..871e02a 100644
--- a/lib/GnuPG/Fingerprint.pm
+++ b/lib/GnuPG/Fingerprint.pm
@@ -22,6 +22,12 @@ has as_hex_string => (
     is  => 'rw',        
 );
 
+sub compare {
+  my ($self, $other) = @_;
+  return 0 unless $other->isa('GnuPG::Fingerprint');
+  return $self->as_hex_string() eq $other->as_hex_string();
+}
+
 # DEPRECATED
 sub hex_data
 {
@@ -63,6 +69,11 @@ initialization of data members.
 
 =item hash_init( I<%args> ).
 
+=item compare( I<$other> )
+
+Returns non-zero only when this fingerprint is identical to the other
+GnuPG::Fingerprint.
+
 =back
 
 =head1 OBJECT DATA MEMBERS
diff --git a/t/GnuPG/ComparableFingerprint.pm b/t/GnuPG/ComparableFingerprint.pm
deleted file mode 100644
index 6a0632a..0000000
--- a/t/GnuPG/ComparableFingerprint.pm
+++ /dev/null
@@ -1,29 +0,0 @@
-#  ComparableFingerprint.pm
-#    - comparable GnuPG::Fingerprint
-#
-#  Copyright (C) 2000 Frank J. Tobin <ftobin at cpan.org>
-#
-#  This module is free software; you can redistribute it and/or modify it
-#  under the same terms as Perl itself.
-#
-#  This program 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.
-#
-#  $Id: ComparableFingerprint.pm,v 1.4 2001/09/14 12:34:36 ftobin Exp $
-#
-
-package GnuPG::ComparableFingerprint;
-
-use strict;
-
-use base qw(GnuPG::Fingerprint );
-
-sub compare
-{
-    my ( $self, $other ) = @_;
-    
-    return $self->as_hex_string() eq $other->as_hex_string();
-}
-
-1;
diff --git a/t/GnuPG/ComparableKey.pm b/t/GnuPG/ComparableKey.pm
index df6d5ec..afa1a23 100644
--- a/t/GnuPG/ComparableKey.pm
+++ b/t/GnuPG/ComparableKey.pm
@@ -55,7 +55,7 @@ sub _deeply_compare
         unless $self->revocations->[$i]->compare($other->revocations->[$i], 1);
     }
 
-    bless $self->fingerprint(), 'GnuPG::ComparableFingerprint';
+    bless $self->fingerprint(), 'GnuPG::Fingerprint';
     return ( $self->fingerprint->compare( $other->fingerprint() ) );
 }
 
diff --git a/t/GnuPG/ComparableSubKey.pm b/t/GnuPG/ComparableSubKey.pm
index f7e6df4..ffef567 100644
--- a/t/GnuPG/ComparableSubKey.pm
+++ b/t/GnuPG/ComparableSubKey.pm
@@ -17,7 +17,7 @@ package GnuPG::ComparableSubKey;
 
 use strict;
 use GnuPG::ComparableSignature;
-use GnuPG::ComparableFingerprint;
+use GnuPG::Fingerprint;
 
 use base qw( GnuPG::SubKey GnuPG::ComparableKey );
 
@@ -41,7 +41,7 @@ sub compare
             unless $self_signatures[$i]->compare( $other_signatures[$i], 1 );
         }
 
-	bless $self->fingerprint, 'GnuPG::ComparableFingerprint'
+	bless $self->fingerprint, 'GnuPG::Fingerprint'
 	  if $self->fingerprint();
 	
 	foreach my $field ( qw( fingerprint ) )

commit d528164d135c535720d1650eb2d44c429d4cbb02
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Sun May 9 20:20:16 2010 -0400

    move signature comparison into ComparableKey.pm instead of ComparableSubKey.pm

diff --git a/t/GnuPG/ComparableKey.pm b/t/GnuPG/ComparableKey.pm
index afa1a23..46749c8 100644
--- a/t/GnuPG/ComparableKey.pm
+++ b/t/GnuPG/ComparableKey.pm
@@ -50,6 +50,11 @@ sub _deeply_compare
     my ( $self, $other ) = @_;
     my $i;
 
+    for ( $i = 0; $i < scalar(@{$self->signatures}); $i++ ) {
+      return 0
+        unless $self->signatures->[$i]->compare($other->signatures->[$i], 1);
+    }
+
     for ( $i = 0; $i < scalar(@{$self->revocations}); $i++ ) {
       return 0
         unless $self->revocations->[$i]->compare($other->revocations->[$i], 1);
diff --git a/t/GnuPG/ComparableSubKey.pm b/t/GnuPG/ComparableSubKey.pm
index ffef567..5049771 100644
--- a/t/GnuPG/ComparableSubKey.pm
+++ b/t/GnuPG/ComparableSubKey.pm
@@ -27,20 +27,6 @@ sub compare
     
     if ( $deep )
     {
-
-      my @self_signatures  = @{$self->signatures()};
-      my @other_signatures = @{$other->signatures()};
-
-      return 0 unless @self_signatures == @other_signatures;
-
-      my $num_sigs = @self_signatures;
-
-      for ( my $i = 0; $i < $num_sigs; $i++ )
-        {
-          return 0
-            unless $self_signatures[$i]->compare( $other_signatures[$i], 1 );
-        }
-
 	bless $self->fingerprint, 'GnuPG::Fingerprint'
 	  if $self->fingerprint();
 	

commit 47d5decb67b15a5a5b266c38d4a6cfeb0b94dc17
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Sun May 9 20:46:06 2010 -0400

    move compare() into GnuPG::Signature, got rid of t/GnuPG/ComparableSignaturepm

diff --git a/lib/GnuPG/Signature.pm b/lib/GnuPG/Signature.pm
index 4172c7c..c2ba189 100644
--- a/lib/GnuPG/Signature.pm
+++ b/lib/GnuPG/Signature.pm
@@ -37,6 +37,31 @@ sub is_valid {
     return $self->validity eq '!';
 }
 
+sub compare {
+  my ($self, $other) = @_;
+
+  my @compared_fields = qw(
+                            validity
+                            algo_num
+                            hex_id
+                            date
+                            date_string
+                            sig_class
+                            is_exportable
+                         );
+
+  foreach my $field ( @compared_fields ) {
+    return 0 unless $self->$field eq $other->$field;
+  }
+  # check for expiration if present?
+  return 0 unless (defined $self->expiration_date) == (defined $other->expiration_date);
+  if (defined $self->expiration_date) {
+    return 0 unless (($self->expiration_date == $other->expiration_date) ||
+      ($self->expiration_date_string eq $other->expiration_date_string));
+  }
+  return 1;
+}
+
 __PACKAGE__->meta->make_immutable;
 
 1;
@@ -72,6 +97,11 @@ initialization of data members.
 Returns 1 if GnuPG was able to cryptographically verify the signature,
 otherwise 0.
 
+=item compare( I<$other> )
+
+Returns non-zero only when this Signature is identical to the other
+GnuPG::Signature.
+
 =back
 
 =head1 OBJECT DATA MEMBERS
diff --git a/t/GnuPG/ComparableSignature.pm b/t/GnuPG/ComparableSignature.pm
deleted file mode 100644
index b70304c..0000000
--- a/t/GnuPG/ComparableSignature.pm
+++ /dev/null
@@ -1,40 +0,0 @@
-#  ComparableSignature.pm
-#    - comparable GnuPG::Signature
-#
-#  Copyright (C) 2000 Frank J. Tobin <ftobin at cpan.org>
-#
-#  This module is free software; you can redistribute it and/or modify it
-#  under the same terms as Perl itself.
-#
-#  This program 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.
-#
-#  $Id: ComparableSignature.pm,v 1.4 2001/09/14 12:34:36 ftobin Exp $
-#
-
-package GnuPG::ComparableSignature;
-
-use strict;
-
-use base qw( GnuPG::Signature );
-
-sub compare
-{
-    my ( $self, $other ) = @_;
-    
-    my @compared_fields = qw( validity algo_num hex_id date date_string is_exportable sig_class );
-    
-    foreach my $field ( @compared_fields )
-    {
-	my $f1 = $self->$field();
-	my $f2 = $other->$field();
-	# don't test for definedness because
-	# all fields should be defined
-	return 0 unless $self->$field() eq $other->$field();
-    }
-    
-    return 1;
-}
-
-1;
diff --git a/t/GnuPG/ComparableSubKey.pm b/t/GnuPG/ComparableSubKey.pm
index 5049771..ef537f8 100644
--- a/t/GnuPG/ComparableSubKey.pm
+++ b/t/GnuPG/ComparableSubKey.pm
@@ -16,7 +16,6 @@
 package GnuPG::ComparableSubKey;
 
 use strict;
-use GnuPG::ComparableSignature;
 use GnuPG::Fingerprint;
 
 use base qw( GnuPG::SubKey GnuPG::ComparableKey );
diff --git a/t/get_public_keys.t b/t/get_public_keys.t
index 7f67320..ddd1562 100644
--- a/t/get_public_keys.t
+++ b/t/get_public_keys.t
@@ -42,7 +42,7 @@ TEST
 			       )
       );
     
-    my $subkey_signature = GnuPG::ComparableSignature->new
+    my $subkey_signature = GnuPG::Signature->new
       ( validity       => '!',
         algo_num       => 17,
 	hex_id         => '53AE596EF950DA9C',

commit ea2e002c8e5b56f9d04ad42c6b326ced65cabbba
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Fri May 7 01:23:47 2010 -0400

    handle revoker packets (rvk)

diff --git a/MANIFEST b/MANIFEST
index 12ea121..c49859d 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -21,6 +21,7 @@ lib/GnuPG/Signature.pm
 lib/GnuPG/SubKey.pm
 lib/GnuPG/UserId.pm
 lib/GnuPG/UserAttribute.pm
+lib/GnuPG/Revoker.pm
 Makefile.PL
 MANIFEST			This list of files
 MANIFEST.SKIP
diff --git a/lib/GnuPG/Interface.pm b/lib/GnuPG/Interface.pm
index 75b5ae1..b7e82c3 100644
--- a/lib/GnuPG/Interface.pm
+++ b/lib/GnuPG/Interface.pm
@@ -408,6 +408,7 @@ sub get_keys {
     require GnuPG::UserId;
     require GnuPG::UserAttribute;
     require GnuPG::Signature;
+    require GnuPG::Revoker;
 
     while (<$stdout>) {
         my $line = $_;
@@ -505,6 +506,7 @@ sub get_keys {
 
             if ( $current_signed_item->isa('GnuPG::Key') ||
                  $current_signed_item->isa('GnuPG::UserId') ||
+                 $current_signed_item->isa('GnuPG::Revoker') ||
                  $current_signed_item->isa('GnuPG::UserAttribute')) {
               if ($record_type eq 'sig') {
                 $current_signed_item->push_signatures($signature);
@@ -571,6 +573,19 @@ sub get_keys {
 
             $current_primary_key->push_subkeys($current_signed_item);
         }
+        elsif ($record_type eq 'rvk') {
+          my ($algo_num, $fpr, $class) = @fields[ 3,9,10 ];
+          my $rvk = GnuPG::Revoker->new(
+           fingerprint => GnuPG::Fingerprint->new( as_hex_string => $fpr ),
+           algo_num    => ($algo_num + 0),
+           class       => hex($class),
+          );
+          # pushing to either primary key or subkey, to handle
+          # designated revokers to the subkeys too:
+          $current_key->push_revokers($rvk);
+          # revokers should be bound to the key with signatures:
+          $current_signed_item = $rvk;
+        }
         elsif ( $record_type ne 'tru' ) {
             warn "unknown record type $record_type";
         }
diff --git a/lib/GnuPG/Key.pm b/lib/GnuPG/Key.pm
index 1b0ee1a..cfe9fb8 100644
--- a/lib/GnuPG/Key.pm
+++ b/lib/GnuPG/Key.pm
@@ -56,6 +56,17 @@ sub push_revocations {
     push @{ $self->revocations }, @_;
 }
 
+has revokers => (
+    isa       => 'ArrayRef',
+    is        => 'rw',
+    default   => sub { [] },
+);
+
+sub push_revokers {
+    my $self = shift;
+    push @{ $self->revokers }, @_;
+}
+
 sub short_hex_id {
     my ($self) = @_;
     return substr $self->hex_id(), -8;
@@ -173,10 +184,18 @@ GnuPG::Signature objects (since revocations are a type of
 certification as well).  Note that a revocation of a primary key has a
 different semantic meaning than a revocation associated with a subkey.
 
+=item revokers
+
+A list of GnuPG::Revoker objects associated with this key, indicating
+other keys which are allowed to revoke certifications made by this
+key.
+
 =back
 
 =head1 SEE ALSO
 
 L<GnuPG::Fingerprint>,
+L<GnuPG::Signature>,
+L<GnuPG::Revoker>,
 
 =cut
diff --git a/lib/GnuPG/Revoker.pm b/lib/GnuPG/Revoker.pm
new file mode 100644
index 0000000..e688d3e
--- /dev/null
+++ b/lib/GnuPG/Revoker.pm
@@ -0,0 +1,145 @@
+#  Revoker.pm
+#    - providing an object-oriented approach to GnuPG key revokers
+#
+#  Copyright (C) 2010 Daniel Kahn Gillmor <dkg at fifthhorseman.net>
+#  (derived from Signature.pm, Copyright (C) 2000 Frank J. Tobin <ftobin at cpan.org>)
+#
+#  This module is free software; you can redistribute it and/or modify it
+#  under the same terms as Perl itself.
+#
+#  This program 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.
+#
+#  $Id: Signature.pm,v 1.4 2001/08/21 13:31:50 ftobin Exp $
+#
+
+package GnuPG::Revoker;
+use Any::Moose;
+
+has [qw(
+         algo_num
+         class
+      )] => (
+    isa => 'Int',
+    is  => 'rw',
+);
+
+has fingerprint => (
+                    isa => 'GnuPG::Fingerprint',
+                    is => 'rw',
+                    );
+
+has signatures => (
+    isa       => 'ArrayRef',
+    is        => 'rw',
+    default   => sub { [] },
+);
+
+sub push_signatures {
+    my $self = shift;
+    push @{ $self->signatures }, @_;
+}
+
+sub is_sensitive {
+    my $self = shift;
+    return $self->class & 0x40;
+}
+
+sub compare {
+  my ( $self, $other, $deep ) = @_;
+
+  my @comparison_ints = qw( class algo_num );
+
+  foreach my $field ( @comparison_ints ) {
+    return 0 unless $self->$field() == $other->$field();
+  }
+
+  return 0 unless $self->fingerprint->compare($other->fingerprint);
+
+  if ($deep) {
+    for ( my $i = 0; $i < scalar(@{$self->signatures}); $i++ ) {
+      return 0
+        unless $self->signatures->[$i]->compare($other->signatures->[$i], 1);
+    }
+  }
+
+  return 1;
+}
+
+__PACKAGE__->meta->make_immutable;
+
+1;
+
+__END__
+
+=head1 NAME
+
+GnuPG::Revoker - GnuPG Key Revoker Objects
+
+=head1 SYNOPSIS
+
+  # assumes a GnuPG::PrimaryKey object in $key
+  my $revokerfpr = $key->revokers->[0]->fingerprint();
+
+=head1 DESCRIPTION
+
+GnuPG::Revoker objects are generally not instantiated on their own,
+but rather as part of GnuPG::Key objects.  They represent a statement
+that another key is designated to revoke certifications made by the
+key in question.
+
+=head1 OBJECT METHODS
+
+=over 4
+
+=item new( I<%initialization_args> )
+
+This methods creates a new object.  The optional arguments are
+initialization of data members.
+
+=item is_sensitive()
+
+Returns 0 if the revoker information can be freely distributed.
+If this is non-zero, the information should be treated as "sensitive".
+
+Please see http://tools.ietf.org/html/rfc4880#section-5.2.3.15 for
+more explanation.
+
+=back
+
+=head1 OBJECT DATA MEMBERS
+
+=over 4
+
+=item fingerprint
+
+A GnuPG::Fingerprint object indicating the fingerprint of the
+specified revoking key.  (Note that this is *not* the fingerprint of
+the key whose signatures can be revoked by this revoker).
+
+=item algo_num
+
+The numeric identifier of the algorithm of the revoker's key.
+
+=item signatures
+
+A list of GnuPG::Signature objects which cryptographically bind the
+designated revoker to the primary key.  A valid revoker designation
+should always have a valid signature associated with it from the
+relevant key doing the designation (not from the revoker's key).
+
+Note that designated revoker certifications are themselves
+irrevocable, so there is no analogous list of revocations in a
+GnuPG::Revoker object.
+
+=back
+
+=head1 SEE ALSO
+
+L<GnuPG::Fingerprint>,
+L<GnuPG::Key>,
+L<GnuPG::Signature>,
+L<http://tools.ietf.org/html/rfc4880#section-5.2.3.15>
+
+=cut
diff --git a/t/GnuPG/ComparableKey.pm b/t/GnuPG/ComparableKey.pm
index 46749c8..61f9d53 100644
--- a/t/GnuPG/ComparableKey.pm
+++ b/t/GnuPG/ComparableKey.pm
@@ -60,6 +60,11 @@ sub _deeply_compare
         unless $self->revocations->[$i]->compare($other->revocations->[$i], 1);
     }
 
+    for ( $i = 0; $i < scalar(@{$self->revokers}); $i++ ) {
+      return 0
+        unless $self->revokers->[$i]->compare($other->revokers->[$i], 1);
+    }
+
     bless $self->fingerprint(), 'GnuPG::Fingerprint';
     return ( $self->fingerprint->compare( $other->fingerprint() ) );
 }
diff --git a/t/get_public_keys.t b/t/get_public_keys.t
index ddd1562..3dffe8c 100644
--- a/t/get_public_keys.t
+++ b/t/get_public_keys.t
@@ -69,6 +69,24 @@ TEST
 	date_string    => '2000-03-16',
 	);
     
+    my $designated_revoker_sig = GnuPG::Signature->new
+      ( validity       => '!',
+        algo_num       => 17,
+	hex_id         => '53AE596EF950DA9C',
+        date           => 978325209,
+	date_string    => '2001-01-01',
+        sig_class      => 0x1f,
+        is_exportable  => 1
+	);
+
+    my $revoker = GnuPG::Revoker->new
+      ( algo_num       => 17,
+        class          => 0x80,
+	fingerprint    => GnuPG::Fingerprint->new( as_hex_string =>
+                                                   '4F863BBBA8166F0A340F600356FFD10A260C4FA3'),
+	);
+    $revoker->push_signatures($designated_revoker_sig);
+    
     my $subkey = GnuPG::SubKey->new
       ( validity                 => 'u',
 	length                   => 768,
@@ -89,6 +107,7 @@ TEST
     $subkey->push_signatures( $subkey_signature );
     
     $handmade_key->push_subkeys( $subkey );
+    $handmade_key->push_revokers( $revoker );
     
     $handmade_key->compare( $given_key );
 };
diff --git a/test/pubring.gpg b/test/pubring.gpg
index c6d2276..60b008a 100644
Binary files a/test/pubring.gpg and b/test/pubring.gpg differ
diff --git a/test/secring.gpg b/test/secring.gpg
index 391bd39..aa34674 100644
Binary files a/test/secring.gpg and b/test/secring.gpg differ

commit bd6059c8023b4f5e60d5dd8b647617bbea49dcb2
Author: Daniel Kahn Gillmor <dkg at fifthhorseman.net>
Date:   Sun May 9 23:24:45 2010 -0400

    GnuPG::Revoker: improve docs, compare() should fail if the signature counts differ

diff --git a/lib/GnuPG/Revoker.pm b/lib/GnuPG/Revoker.pm
index e688d3e..e5adc31 100644
--- a/lib/GnuPG/Revoker.pm
+++ b/lib/GnuPG/Revoker.pm
@@ -57,7 +57,11 @@ sub compare {
 
   return 0 unless $self->fingerprint->compare($other->fingerprint);
 
-  if ($deep) {
+  return 0 unless @{$self->signatures} == @{$other->signatures};
+
+  # FIXME: is it actually wrong if the associated signatures come out
+  # in a different order on the two compared designated revokers?
+  if (defined $deep && $deep) {
     for ( my $i = 0; $i < scalar(@{$self->signatures}); $i++ ) {
       return 0
         unless $self->signatures->[$i]->compare($other->signatures->[$i], 1);
@@ -106,6 +110,13 @@ If this is non-zero, the information should be treated as "sensitive".
 Please see http://tools.ietf.org/html/rfc4880#section-5.2.3.15 for
 more explanation.
 
+=item compare( I<$other>, I<$deep> )
+
+Returns non-zero only when this designated revoker is identical to the
+other GnuPG::Revoker.  If $deep is present and non-zero, the revokers'
+signatures will also be compared.
+
+
 =back
 
 =head1 OBJECT DATA MEMBERS
@@ -125,9 +136,11 @@ The numeric identifier of the algorithm of the revoker's key.
 =item signatures
 
 A list of GnuPG::Signature objects which cryptographically bind the
-designated revoker to the primary key.  A valid revoker designation
-should always have a valid signature associated with it from the
-relevant key doing the designation (not from the revoker's key).
+designated revoker to the primary key.  If the material was
+instantiated using the *_with_sigs() functions from GnuPG::Interface,
+then a valid revoker designation should have a valid signature
+associated with it from the relevant key doing the designation (not
+from the revoker's key).
 
 Note that designated revoker certifications are themselves
 irrevocable, so there is no analogous list of revocations in a
@@ -137,6 +150,7 @@ GnuPG::Revoker object.
 
 =head1 SEE ALSO
 
+L<GnuPG::Interface>,
 L<GnuPG::Fingerprint>,
 L<GnuPG::Key>,
 L<GnuPG::Signature>,

commit a59a8afb44bea625fdf9b3e98badd6128b540c32
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Mon May 10 10:45:17 2010 -0400

    MANIFEST updates

diff --git a/MANIFEST b/MANIFEST
index c49859d..4cfbbb8 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -16,12 +16,12 @@ lib/GnuPG/Key.pm
 lib/GnuPG/Options.pm
 lib/GnuPG/PrimaryKey.pm
 lib/GnuPG/PublicKey.pm
+lib/GnuPG/Revoker.pm
 lib/GnuPG/SecretKey.pm
 lib/GnuPG/Signature.pm
 lib/GnuPG/SubKey.pm
-lib/GnuPG/UserId.pm
 lib/GnuPG/UserAttribute.pm
-lib/GnuPG/Revoker.pm
+lib/GnuPG/UserId.pm
 Makefile.PL
 MANIFEST			This list of files
 MANIFEST.SKIP
@@ -38,12 +38,10 @@ t/export_keys.t
 t/Fingerprint.t
 t/get_public_keys.t
 t/get_secret_keys.t
-t/GnuPG/ComparableFingerprint.pm
 t/GnuPG/ComparableKey.pm
 t/GnuPG/ComparablePrimaryKey.pm
 t/GnuPG/ComparablePublicKey.pm
 t/GnuPG/ComparableSecretKey.pm
-t/GnuPG/ComparableSignature.pm
 t/GnuPG/ComparableSubKey.pm
 t/GnuPG/ComparableUserId.pm
 t/import_keys.t
@@ -84,5 +82,4 @@ test/secret-keys/2.out
 test/secring.gpg
 test/signed.1.asc
 test/temp
-test/trustdb.gpg
 THANKS

commit fa67e5adc6f8751030aadc9d3dcf871d501b341f
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Mon May 10 10:50:56 2010 -0400

    Changelog updates for 0.42_01

diff --git a/ChangeLog b/ChangeLog
index 46722fe..30dbf01 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+0.42_01 Mon May 10 10:50:49 EDT 2010
+    GnuPG::Revoker: improve docs, compare() should fail if the signature counts differ - dkg
+    Handle revoker packets (rvk) - dkg
+    Move compare() into GnuPG::Signature, got rid of t/GnuPG/ComparableSignature.pm - dkg
+    Move signature comparison into ComparableKey.pm instead of ComparableSubKey.pm - dkg
+    Move fingerprint comparison directly into GnuPG::Fingerprint - dkg
+    Change around some variable names for consistency's sake:
+      $current_key becomes $current_primary_key
+      $current_fingerprinted_key becomes $current_key  -dkg
+    Fixed synopsis example in GnuPG::Signature pod - dkg
+    Allow for primary key to have per-key (useful for signatures of class 0x1f, see http://tools.ietf.org/html/rfc4880#section-5.2.1) - dkg
+    Add revocations to keys and user ids and user attributes - dkg
+    Add signature class and exportability to GnuPG::Signature - dkg
+    Introduced GnuPG::UserAttribute to handle uat packets - dkg
+    Actually check validity of signatures and report them - dkg
+    Support more than 1 signature over each subkey - dkg
+    Do not bother shipping test/random_seed - dkg
+    Fix copy method of GnuPG::Options.
+     The result of not checking for definedness here is to never copy the
+     meta_immutable value successfully (as that is true by default).  This led
+     to a FTBFS (failure to build from source) when running non-interactively.
+    
+     See also:  http://bugs.debian.org/549743  - Tim Retout
+    Expose signature expiration times - dkg
+    Take advantage of --fixed-list-mode and report timestamps at 1Hz precision instead of daily precision - dkg
+    Always use --fixed-list-mode for consistency and better granularity of data - dkg
+    Unescape strings to handle User IDs with colons in them - dkg
+    Add usage_flags to keys - dkg
+    Several doc patches from Daniel Kahn Gillmor 
+    Fix for documented typos reported by SYSMON Fixes rt.cpan.org#50377 - jesse
+    Fix POD errors - alexmv
+
 0.42 Wed Sep 30 23:20:58 JST 2009
 
 	* Support for GPG2

commit 3b5e1b390bbbb9e67003b0a9a11bbfb416a1911e
Author: Jesse Vincent <jesse at bestpractical.com>
Date:   Mon May 10 10:54:34 2010 -0400

    Checking in changes prior to tagging of version 0.42_01.
    
    Changelog diff is:

diff --git a/lib/GnuPG/Interface.pm b/lib/GnuPG/Interface.pm
index b7e82c3..c874ff1 100644
--- a/lib/GnuPG/Interface.pm
+++ b/lib/GnuPG/Interface.pm
@@ -26,7 +26,7 @@ use IO::Handle;
 use GnuPG::Options;
 use GnuPG::Handles;
 
-$VERSION = '0.42';
+$VERSION = '0.42_01';
 
 has $_ => (
     isa     => 'Any',

-----------------------------------------------------------------------



More information about the Bps-public-commit mailing list