line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package VOMS::Lite::ASN1Helper; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
19
|
use 5.004; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
49
|
|
4
|
1
|
|
|
1
|
|
5
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
31
|
|
5
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
49
|
|
6
|
1
|
|
|
1
|
|
1809
|
use Math::BigInt lib => 'GMP'; |
|
1
|
|
|
|
|
25973
|
|
|
1
|
|
|
|
|
7
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
require Exporter; |
9
|
1
|
|
|
1
|
|
28520
|
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
1976
|
|
10
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
11
|
|
|
|
|
|
|
%EXPORT_TAGS = ( ); |
12
|
|
|
|
|
|
|
@EXPORT_OK = qw( Hex DecToHex ASN1BitStr ASN1Wrap ASN1UnwrapHex ASNLenStr ASN1Index ASN1Unwrap ASN1OIDtoOID OIDtoASN1OID); |
13
|
|
|
|
|
|
|
@EXPORT = ( ); |
14
|
|
|
|
|
|
|
$VERSION = '0.20'; |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
################################################## |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub Hex { #Converts a binary string to a padded string of hex values |
19
|
89
|
|
|
89
|
0
|
164
|
my $data=shift; |
20
|
89
|
50
|
|
|
|
169
|
return undef if ( ! defined $data ); |
21
|
89
|
|
|
|
|
231
|
my $str=unpack('H*',$data); |
22
|
89
|
50
|
|
|
|
431
|
return ((length($str) & 1)?"0":"").$str; |
23
|
|
|
|
|
|
|
} |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
################################################## |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
sub DecToHex { #Converts an 'integer' to a padded string of hex values |
28
|
39
|
|
|
39
|
0
|
70
|
my $data=shift; |
29
|
39
|
50
|
|
|
|
105
|
return undef if ( ! defined $data ); |
30
|
39
|
50
|
|
|
|
203
|
return "NaN" if ( $data !~ /^-?[0-9]+$/ ); |
31
|
39
|
|
|
|
|
1456
|
my $num=Math::BigInt->new("$data"); |
32
|
39
|
50
|
|
|
|
2576
|
$num->binc() if ( $data =~ /^-/ ); |
33
|
39
|
|
|
|
|
1137
|
my $str=$num->as_hex(); |
34
|
39
|
|
|
|
|
30011
|
$str =~ s/^-?0x//; # strip 0x and negative sign |
35
|
39
|
|
|
|
|
241
|
$str =~ s/^.(..)*$/0$&/; # even up str |
36
|
39
|
|
|
|
|
178
|
$str =~ s/^[89a-f]/00$&/; # convert to 2's complement as if positive |
37
|
39
|
50
|
|
|
|
129
|
$str =~ y/0-9a-f/fedcba9876543210/ if ( $data =~ /^-/ ); # if negative, negate |
38
|
39
|
|
|
|
|
1468
|
return $str; |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
################################################## |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub ASN1OIDtoOID { |
44
|
75
|
|
|
75
|
0
|
124
|
my ($val,$OIDstr)=(0,""); |
45
|
75
|
|
|
|
|
215
|
foreach (split(//,shift)) { # Tackle OID one byte at a time |
46
|
225
|
|
|
|
|
311
|
$val=($val*128)+ord($_&"\x7f"); # effectively shift $val 7 bits left add last 7 bits of $_ |
47
|
225
|
50
|
|
|
|
440
|
if (($_&"\x80") ne "\x80") { # If bit 8 is 0 then write append the value to the oid string |
48
|
225
|
100
|
|
|
|
523
|
$OIDstr .= ( ( length($OIDstr) ) ? ".$val" : (int($val/40).".".$val%40) ); |
49
|
225
|
|
|
|
|
360
|
$val=0; |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
} |
52
|
75
|
|
|
|
|
267
|
return $OIDstr; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub OIDtoASN1OID { |
56
|
9
|
50
|
|
9
|
0
|
43
|
if ( $_[0] !~ /^[0-9]+(?:\.[0-9]+)*$/ ) { return undef; } |
|
0
|
|
|
|
|
0
|
|
57
|
9
|
|
|
|
|
30
|
my @nums=split /\./,$_[0]; |
58
|
9
|
|
|
|
|
24
|
unshift(@nums,shift(@nums)*40+shift(@nums)); |
59
|
9
|
|
|
|
|
14
|
my $OIDASN1str=""; |
60
|
9
|
|
|
|
|
15
|
foreach (@nums) { |
61
|
27
|
|
|
|
|
31
|
my $str=""; |
62
|
27
|
|
|
|
|
49
|
while ( $_ > 0 ) { |
63
|
27
|
|
|
|
|
29
|
my $m = $_ % 128; |
64
|
27
|
|
|
|
|
26
|
$_ -= $m; |
65
|
27
|
50
|
|
|
|
44
|
$m += 128 if ($str ne ""); |
66
|
27
|
|
|
|
|
46
|
$str = pack('C',$m).$str; |
67
|
27
|
|
|
|
|
64
|
$_/=128; |
68
|
|
|
|
|
|
|
} |
69
|
27
|
|
|
|
|
41
|
$OIDASN1str .= $str; |
70
|
|
|
|
|
|
|
} |
71
|
9
|
|
|
|
|
30
|
return $OIDASN1str; |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
################################################## |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub ASN1BitStr { #Converts a hex representation of a bit string to an ASN1 bitstring primitive |
77
|
9
|
|
|
9
|
0
|
26
|
my ($data,$length)=@_; |
78
|
9
|
50
|
|
|
|
38
|
return undef if ( ! defined $data ); |
79
|
9
|
50
|
|
|
|
27
|
if ( defined $length ) { |
80
|
0
|
|
|
|
|
0
|
my $wholebytes = int($length/8); |
81
|
0
|
|
|
|
|
0
|
my $mask = Hex(pack('C',(2**((8-$length)%8)-1))); |
82
|
0
|
|
|
|
|
0
|
return $mask.substr($data,0,$wholebytes*2); |
83
|
|
|
|
|
|
|
} |
84
|
9
|
|
|
|
|
56
|
return "00".$data; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
################################################## |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub ASN1Wrap { #wraps an ASN1 structure with its ASN1 headers |
90
|
220
|
|
|
220
|
0
|
293
|
my $Header=shift; |
91
|
220
|
|
|
|
|
294
|
my $Data=shift; |
92
|
220
|
50
|
33
|
|
|
783
|
return undef if (! defined $Header || ! defined $Data); |
93
|
220
|
|
|
|
|
379
|
return $Header.ASNLenStr($Data).$Data; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
################################################## |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
sub ASN1UnwrapHex { |
99
|
0
|
|
|
0
|
0
|
0
|
my $data=shift; |
100
|
0
|
0
|
|
|
|
0
|
return undef if ( ! defined $data ); |
101
|
0
|
|
|
|
|
0
|
$data=~ s/(..)/pack("C",hex($&))/ge; |
|
0
|
|
|
|
|
0
|
|
102
|
0
|
|
|
|
|
0
|
return Hex(scalar ASN1Unwrap($data)); |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub ASN1Unwrap { |
106
|
1109
|
|
|
1109
|
0
|
2251
|
my $BER=shift; |
107
|
1109
|
0
|
|
|
|
2019
|
return (wantarray ? (0,0,undef,undef,undef,"") : "") if (! defined $BER ); |
|
|
50
|
|
|
|
|
|
108
|
1109
|
|
|
|
|
1117
|
my $inheader=1; |
109
|
1109
|
|
|
|
|
1302
|
my ($Class,$Constructed,$Tag)=(0,0,0); |
110
|
1109
|
|
|
|
|
1160
|
my ($headlen,$reallen,$lenlen)=(0,0,0); |
111
|
|
|
|
|
|
|
# my $i; |
112
|
1109
|
|
|
|
|
2381
|
for ( my $i = 0 ; $i <= length($BER) ; $i++ ) { |
113
|
3453
|
|
|
|
|
4709
|
my $C=substr $BER,$i,1; |
114
|
3453
|
|
|
|
|
14071
|
my @B=split(//, unpack("B*", $C)); |
115
|
3453
|
100
|
|
|
|
10631
|
if ( $inheader==1 ) { # ID First Byte |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
116
|
1109
|
|
|
|
|
1439
|
$headlen=1; |
117
|
1109
|
|
|
|
|
2278
|
$Class= (shift @B)*2 + shift @B; |
118
|
1109
|
|
|
|
|
1550
|
$Constructed=shift @B; |
119
|
1109
|
|
|
|
|
3585
|
$Tag=unpack("N", pack("B32",substr("0" x 32 . join("",@B), -32 ))); |
120
|
1109
|
50
|
|
|
|
2499
|
if ($Tag==31) { $inheader=2; $Tag=0; } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
121
|
1109
|
|
|
|
|
3553
|
else { $inheader=3; } |
122
|
|
|
|
|
|
|
} elsif ( $inheader==2 ) { # ID Subsequent Bytes |
123
|
0
|
|
|
|
|
0
|
$headlen++; |
124
|
0
|
|
|
|
|
0
|
$inheader+=shift @B; |
125
|
0
|
|
|
|
|
0
|
$Tag <<= 7; |
126
|
0
|
|
|
|
|
0
|
$Tag=unpack("N", pack("B32",substr("0" x 32 . join("",@B), -32 ))); |
127
|
|
|
|
|
|
|
} elsif ( $inheader==3 ) { # Length First Byte |
128
|
1109
|
|
|
|
|
1095
|
$headlen++; |
129
|
1109
|
100
|
|
|
|
1682
|
if ( shift @B ) { $inheader=4; $reallen=0; $lenlen = unpack("N", pack("B32",substr("0" x 32 . join("",@B), -32 )));} |
|
88
|
|
|
|
|
102
|
|
|
88
|
|
|
|
|
85
|
|
|
88
|
|
|
|
|
457
|
|
130
|
1021
|
|
|
|
|
1046
|
else { $inheader=-1; $lenlen=0; $reallen = unpack("N", pack("B32",substr("0" x 32 . join("",@B), -32 )));} |
|
1021
|
|
|
|
|
1064
|
|
|
1021
|
|
|
|
|
5498
|
|
131
|
|
|
|
|
|
|
} elsif ( $inheader==4 ) { # Length Subsequent Bytes |
132
|
126
|
|
|
|
|
127
|
$headlen++; $lenlen--; |
|
126
|
|
|
|
|
135
|
|
133
|
126
|
|
|
|
|
624
|
$reallen+=(unpack("N", pack("B32",substr("0" x 32 . join("",@B), -32 ))))*(256**$lenlen); |
134
|
126
|
100
|
|
|
|
339
|
if ( $lenlen == 0 ) { $inheader=-1;} |
|
88
|
|
|
|
|
277
|
|
135
|
|
|
|
|
|
|
} else { #What's left: Primative or Construction |
136
|
1109
|
100
|
|
|
|
6073
|
return wantarray ? ($headlen,$reallen,$Class,$Constructed,$Tag,substr($BER,$i,$reallen)) : substr($BER,$i,$reallen); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
} |
139
|
0
|
0
|
|
|
|
0
|
return wantarray ? (0,0,undef,undef,undef,"") : ""; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
################################################## |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
sub ASNLenStr { #expects Hex String returns ASN1 length header |
145
|
220
|
|
|
220
|
0
|
242
|
my $data=shift; |
146
|
220
|
50
|
|
|
|
357
|
return undef if ( ! defined $data ); |
147
|
|
|
|
|
|
|
|
148
|
220
|
|
|
|
|
271
|
my $len=length($data)/2; |
149
|
220
|
100
|
|
|
|
381
|
if ($len <= 127) { |
150
|
195
|
|
|
|
|
1085
|
return unpack("H2",pack("i",$len)); |
151
|
|
|
|
|
|
|
} else { |
152
|
25
|
|
|
|
|
98
|
my $lenlen=sprintf "%0x",$len; |
153
|
25
|
100
|
|
|
|
72
|
if ( length($lenlen) & 1 ) { $lenlen='0'.$lenlen; } |
|
19
|
|
|
|
|
35
|
|
154
|
25
|
|
|
|
|
246
|
return sprintf("%0x%s",((length($lenlen)/2)+128),$lenlen); |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
} |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
################################################## |
159
|
|
|
|
|
|
|
# Subroutine to find structure of DER ASN.1 |
160
|
|
|
|
|
|
|
################################################## |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub ASN1Index { |
163
|
38
|
|
|
38
|
0
|
61
|
my $data=shift; |
164
|
38
|
50
|
|
|
|
84
|
return () if ( ! defined $data ); |
165
|
|
|
|
|
|
|
|
166
|
38
|
|
|
|
|
72
|
my @ContentStart=(0); |
167
|
38
|
|
|
|
|
51
|
my $datalength=length($data); |
168
|
38
|
|
|
|
|
79
|
my @ContentStop=($datalength); |
169
|
38
|
|
|
|
|
46
|
my $pointer=0; |
170
|
|
|
|
|
|
|
|
171
|
38
|
|
|
|
|
130
|
my @total=ASN1Unwrap(substr($data,$pointer,($ContentStop[-1]-$ContentStart[-1]))); |
172
|
38
|
50
|
|
|
|
128
|
if ( $total[0]+$total[1] != $datalength ) { return (); } |
|
0
|
|
|
|
|
0
|
|
173
|
|
|
|
|
|
|
|
174
|
38
|
|
|
|
|
46
|
my @data; |
175
|
38
|
|
66
|
|
|
233
|
while ( defined $ContentStop[-1] && $pointer < $ContentStop[0] ) { |
176
|
|
|
|
|
|
|
|
177
|
996
|
|
|
|
|
2621
|
my ($headlen,$reallen,$Class,$Constructed,$Tag,$Data) = ASN1Unwrap(substr($data,$pointer,($ContentStop[-1]-$ContentStart[-1]))); |
178
|
|
|
|
|
|
|
|
179
|
996
|
50
|
|
|
|
2831
|
if ( ! defined $Class ) { return (); } |
|
0
|
|
|
|
|
0
|
|
180
|
996
|
|
|
|
|
1483
|
push @ContentStart,($pointer+$headlen); |
181
|
996
|
|
|
|
|
1522
|
push @ContentStop,($pointer+$headlen+$reallen); |
182
|
|
|
|
|
|
|
|
183
|
996
|
|
|
|
|
2205
|
push @data, [$Class,$Constructed,$Tag,$pointer,$headlen,$reallen]; |
184
|
|
|
|
|
|
|
|
185
|
996
|
|
|
|
|
1159
|
$pointer+=$headlen; |
186
|
996
|
100
|
|
|
|
2163
|
$pointer+=$reallen if ($Constructed==0); |
187
|
996
|
|
100
|
|
|
5098
|
while ( defined $ContentStop[-1] && $pointer == $ContentStop[-1] ) { |
188
|
1034
|
50
|
|
|
|
1915
|
if ( ! defined pop @ContentStop) { return (); } |
|
0
|
|
|
|
|
0
|
|
189
|
1034
|
50
|
|
|
|
5838
|
if ( ! defined pop @ContentStart) { return (); } |
|
0
|
|
|
|
|
0
|
|
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
} |
192
|
38
|
|
|
|
|
403
|
return @data; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
1; |
196
|
|
|
|
|
|
|
__END__ |