Package: libgnupg-interface-perl
Tags: patch

GnuPG::SubKey currently reports a single signature object.  However, it
should have a list of signatures.  RFC 4880 permits multiple binding
signatures to exist on a subkey.

For example:

 * primary key X has subkey Y, with an initial binding signature A.

 * This bundle is uploaded to the public keyservers.

 * the keyholder then decides to set (or modify) the expiration date for
subkey Y, generating a new subkey binding signature.

 * the new binding signature is uploaded to the keyservers, which now
have two signatures over the subkey.

 * another user downloading the key from the keyservers (or importing it
from a file) will find two 'sig' lines after the 'sub' line.

The attached patch deprecates the signature() function of GnuPG::SubKey
(code that calls this function will carp()) and introduces two
functions: signatures() and push_signatures().

It also updates the test suite and the documentation.

Regards,

        --dkg
--- a/lib/GnuPG/Interface.pm
+++ b/lib/GnuPG/Interface.pm
@@ -488,12 +488,10 @@
                 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";
             }
--- 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 @@
 
 =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
 
--- a/t/GnuPG/ComparableSubKey.pm
+++ b/t/GnuPG/ComparableSubKey.pm
@@ -27,12 +27,24 @@
     
     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();
--- a/t/get_public_keys.t
+++ b/t/get_public_keys.t
@@ -42,11 +42,12 @@
 			       )
       );
     
-    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 @@
 			       )
       );
     
-    $subkey->signature( $initial_self_signature );
+    $subkey->push_signatures( $subkey_signature );
     
     $handmade_key->push_subkeys( $subkey );
     
--- a/t/GnuPG/ComparableSignature.pm
+++ b/t/GnuPG/ComparableSignature.pm
@@ -29,7 +29,6 @@
     {
 	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();

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to