summaryrefslogtreecommitdiff
path: root/Master/tlpkg/tlperl0/lib/Crypt/OpenPGP/Message.pm
blob: fcf606f509d9e4be4c2ab6ed6ff760158c2650ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package Crypt::OpenPGP::Message;
use strict;

use Crypt::OpenPGP::Buffer;
use Crypt::OpenPGP::PacketFactory;
use Crypt::OpenPGP::ErrorHandler;
use base qw( Crypt::OpenPGP::ErrorHandler );

sub new {
    my $class = shift;
    my $msg = bless { }, $class;
    $msg->init(@_);
}

sub init {
    my $msg = shift;
    my %param = @_;
    $msg->{is_packet_stream} = delete $param{IsPacketStream};
    $msg->{pieces} = [];
    $msg->{_data} = $param{Data} || '';
    if (!$msg->{_data} && (my $file = $param{Filename})) {
        local *FH;
        open FH, $file or
            return (ref $msg)->error("Can't open message $file: $!");
        binmode FH;
        { local $/; $msg->{_data} = <FH> }
        close FH;
    }
    $msg->read or return;
    $msg;
}

sub read {
    my $msg = shift;
    my $data = $msg->{_data} or
        return $msg->error("Message contains no data");
    my $pt;
    if (!$msg->{is_packet_stream} &&
        $data =~ /-----BEGIN PGP SIGNED MESSAGE/) {
        require Crypt::OpenPGP::Armour;
        require Crypt::OpenPGP::Util;
        require Crypt::OpenPGP::Plaintext;
        my($head, $text, $sig) = $data =~
            m!-----BEGIN PGP SIGNED MESSAGE-----(.*?\r?\n\r?\n)?(.+?)(-----BEGIN PGP SIGNATURE.*?END PGP SIGNATURE-----)!s;
        ## In clear-signed messages, the line ending before the signature
        ## is not considered part of the signed text.
        $text =~ s!\r?\n$!!;
        $pt = Crypt::OpenPGP::Plaintext->new(
                              Data => Crypt::OpenPGP::Util::dash_unescape($text),
                              Mode => 't',
                    );
        $data = $sig;
    }

    if (!$msg->{is_packet_stream} && $data =~ /^-----BEGIN PGP/m) {
        require Crypt::OpenPGP::Armour;
        my $rec = Crypt::OpenPGP::Armour->unarmour($data) or
            return $msg->error("Unarmour failed: " .
                Crypt::OpenPGP::Armour->errstr);
        $data = $rec->{Data};
    }
    my $buf = Crypt::OpenPGP::Buffer->new;
    $buf->append($data);
    $msg->restore($buf);
    push @{ $msg->{pieces} }, $pt if $pt;
    1;
}

sub restore {
    my $msg = shift;
    my($buf) = @_;
    while (my $packet = Crypt::OpenPGP::PacketFactory->parse($buf)) {
        push @{ $msg->{pieces} }, $packet;
    }
}

sub pieces { @{ $_[0]->{pieces} } }

1;
__END__

=head1 NAME

Crypt::OpenPGP::Message - Sequence of PGP packets

=head1 SYNOPSIS

    use Crypt::OpenPGP::Message;

    my $data; $data .= $_ while <STDIN>;
    my $msg = Crypt::OpenPGP::Message->new( Data => $data );
    my @pieces = $msg->pieces;

=head1 DESCRIPTION

I<Crypt::OpenPGP::Message> provides a container for a sequence of PGP
packets. It transparently handles ASCII-armoured messages, as well as
cleartext signatures.

=head1 USAGE

=head2 Crypt::OpenPGP::Message->new( %arg )

Constructs a new I<Crypt::OpenPGP::Message> object, presumably to be
filled with some data, where the data is a serialized stream of PGP
packets.

Reads the packets into in-memory packet objects.

Returns the new I<Message> object on success, C<undef> on failure.

I<%arg> can contain:

=over 4

=item * Data

A scalar string containing the serialized packets.

This argument is optional, but either this argument or I<Filename> must
be provided.

=item * Filename

The path to a file that contains a serialized stream of packets.

This argument is optional, but either this argument or I<Data> must be
provided.

=item * IsPacketStream

By default I<Crypt::OpenPGP::Message> will attempt to unarmour ASCII-armoured
text. Since the armoured text can actually appear anywhere in a string, as
long as it starts at the beginning of a line, this can cause problems when a
stream of packets happens to include armoured text. At those times you want
the packets to be treated as a stream, not as a string that happens to contain
armoured text.

In this case, set I<IsPacketStream> to a true value, and the ASCII armour
detection will be skipped.

=back

=head2 $msg->pieces

Returns an array containing packet objects. For example, if the packet
stream contains a public key packet, a user ID packet, and a signature
packet, the array will contain three objects: a
I<Crypt::OpenPGP::Certificate> object; a I<Crypt::OpenPGP::UserID>
object; and a I<Crypt::OpenPGP::Signature> object, in that order.

=head1 AUTHOR & COPYRIGHTS

Please see the Crypt::OpenPGP manpage for author, copyright, and
license information.

=cut