Convert-X509
view release on metacpan or search on metacpan
lib/Convert/X509/minipkcs7.pm view on Meta::CPAN
and correspondent crypto-algorithmes
=head1 SYNOPSYS
use Convert::X509::minipkcs7;
use Data::Dumper;
open(F,'<', $ARGV[0]) or die;
binmode(F);
local $/;
my $data=Convert::X509::minipkcs7->new(<F>);
print Dumper($data->snlist());
=cut
use strict;
use warnings;
use Convert::ASN1;
use MIME::Base64;
my %oid_db=(
'PKCS7' => { 'asn'=>'ContentInfo' },
'1.2.840.113549.1.7.1' => { 'asn'=>'Data' },
'1.2.840.113549.1.7.2' => { 'asn'=>'SignedData' },
'1.2.840.113549.1.7.3' => { 'asn'=>'EnvelopedData' },
'1.2.840.113549.1.7.4' => { 'asn'=>'SignedAndEnvelopedData' },
'1.2.840.113549.1.7.5' => { 'asn'=>'DigestedData' },
'1.2.840.113549.1.7.6' => { 'asn'=>'EncryptedData' },
);
my $asn;
sub _prepare {
my ($pdata) = @_;
warn ('Parameter must be a scalar ref') && return undef unless ref($pdata) eq 'SCALAR';
# first bytes for ASN.1 SEQUENCE are 3080 or 3082
unless (unpack('H3',$$pdata) eq '308'){
$$pdata = decode_base64(
join("\n",
$$pdata =~ m!^([A-Za-z01-9+/]{1,})[-=]*$!gm
)
);
}
}
sub _int2hexstr {
my $res='';
my $m=$_[0];
while ($m){
$res = unpack('H2',pack('C', $m & 255 )) . $res;
$m >>= 8;
}
return $res;
}
sub _decode {
warn ("Error\n",$asn->error,"\nin ASN.1 code\n") && return undef if $asn->error;
my $type = shift;
my $node= $asn->find( $oid_db{uc($type)}->{'asn'} || 'Any' );
warn ('Error finding ',$type,'-', $oid_db{uc($type)}->{'asn'}, ' in module',"\n") && return undef unless $node;
my @decoded = map {$node->decode($_)} @_;
return ( @_ > 1 ? [@decoded] : $decoded[0] )
}
sub snlist {
my ($self) = @_;
my $res = { }; # {'recipients'=>[],'signers'=>[]};
if (exists $self->{'content'}{'signerInfos'}){
@{ $res->{'signers'} } =
map{
{_int2hexstr( $_->{'issuerAndSerialNumber'}{'serialNumber'} ) =>
$_->{'digestAlgorithm'}{'algorithm'} }
}
@{ $self->{'content'}{'signerInfos'} }
;
# for (@{ $self->{'content'}{'signerInfos'} }) {
# push @{ $res->{'signers'} },
# _int2hexstr( $_->{'issuerAndSerialNumber'}{'serialNumber'} );
}
if (exists $self->{'content'}{'recipientInfos'}){
for (@{ $self->{'content'}{'recipientInfos'}{'riSet'} }) {
my ($kkey) = keys %$_; # RecipientInfo is "CHOICE", so there is only one key
my $k = $_->{$kkey}{'self'} || $_->{$kkey};
# damn Signalcom again...
my $e;
# known cases
# case one - keyAgreementRecipientInfo
$e = (exists $k->{'recipientEncryptedKeys'} ?
_int2hexstr(
$k->{'recipientEncryptedKeys'}[0]{'recipientIdentifier'}
{'issuerAndSerialNumber'}{'serialNumber'}
# I don't have any reason to "foreach" in two those lists ([0] and [0] above)
) : undef
);
push @{ $res->{'recipients'} },
{$e=>$k->{'keyEncryptionAlgorithm'}{'algorithm'}} if($e);
# case two - keyTransportRecipientInfo
$e = (exists $k->{'rid'} ?
_int2hexstr($k->{'rid'}{'issuerAndSerialNumber'}{'serialNumber'})
: undef);
push @{ $res->{'recipients'} },
{$e=>$k->{'keyEncryptionAlgorithm'}{'algorithm'}} if($e);
}
}
return $res;
}
sub new {
my $self={};
my $class = shift;
my $pdata = (ref($_[0]) ? $_[0] : \$_[0]);
my (undef, $debug) = @_;
_prepare($pdata);
unless (unpack('H3',$$pdata) eq '308'){
warn ('Seems to be not PKCS7 data',"\n") if $debug;
return undef;
}
$self = _decode('pkcs7'=>$$pdata);
unless ($self){
( run in 4.656 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )