line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package VOMS::Lite::X509; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
1241
|
use 5.004; |
|
1
|
|
|
|
|
5
|
|
|
1
|
|
|
|
|
51
|
|
4
|
1
|
|
|
1
|
|
6
|
use strict; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
63
|
|
5
|
1
|
|
|
1
|
|
974
|
use VOMS::Lite::ASN1Helper qw(ASN1OIDtoOID ASN1Index ASN1Wrap ASN1Unwrap ASN1UnwrapHex DecToHex Hex ASN1BitStr OIDtoASN1OID); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
125
|
|
6
|
1
|
|
|
1
|
|
958
|
use VOMS::Lite::KEY; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
47
|
|
7
|
1
|
|
|
1
|
|
844
|
use Digest::SHA1 qw(sha1_hex); |
|
1
|
|
|
|
|
979
|
|
|
1
|
|
|
|
|
74
|
|
8
|
1
|
|
|
1
|
|
8
|
use Digest::MD5 qw(md5); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
58
|
|
9
|
1
|
|
|
1
|
|
1077
|
use Time::Local qw(timegm); |
|
1
|
|
|
|
|
2505
|
|
|
1
|
|
|
|
|
73
|
|
10
|
1
|
|
|
1
|
|
1190
|
use VOMS::Lite::RSAKey; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
100
|
|
11
|
1
|
|
|
1
|
|
1093
|
use VOMS::Lite::CertKeyHelper; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
69
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
require Exporter; |
14
|
1
|
|
|
1
|
|
8
|
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
8959
|
|
15
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
$VERSION = '0.20'; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
sub Examine { |
20
|
10
|
|
|
10
|
1
|
44
|
my ($decoded,$dataref)=@_; |
21
|
10
|
|
|
|
|
72
|
my %Values=%$dataref; |
22
|
10
|
|
|
|
|
59
|
my @ASN1Index=ASN1Index($decoded); |
23
|
|
|
|
|
|
|
|
24
|
10
|
50
|
|
|
|
54
|
return ( {Errors=>["Unable to parse certificate"]} ) if (@ASN1Index==0); |
25
|
|
|
|
|
|
|
|
26
|
10
|
|
|
|
|
169
|
my ($index,$ignoreuntil)=(0,0); |
27
|
10
|
|
|
|
|
32
|
my ($X509TBSCert,$X509version,$X509serial,$X509signature,$X509issuer,$X509validity,$X509subject, |
28
|
|
|
|
|
|
|
$X509subjectPublicKeyInfo,$X509issuerUniqueID,$X509subjectUniqueID,$X509extensions, |
29
|
|
|
|
|
|
|
$X509SignatureAlgorithm,$X509SignatureValue); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
# Drill down into the certificate |
32
|
10
|
|
|
|
|
16
|
shift @ASN1Index; # skip the wrapping of the certificate sequence |
33
|
10
|
|
|
|
|
31
|
my $TBSCertRef=shift @ASN1Index; #CertificateTBS Sequence |
34
|
10
|
100
|
|
|
|
67
|
if (defined $Values{X509TBSCert}) { |
35
|
2
|
|
|
|
|
11
|
my ($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN) = @$TBSCertRef; |
36
|
2
|
|
|
|
|
22
|
$Values{X509TBSCert}=substr($decoded,$HEADSTART,($HEADLEN+$CHUNKLEN)); |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# Extract the main components of the certificate |
40
|
10
|
|
|
|
|
29
|
foreach (@ASN1Index) { |
41
|
615
|
|
|
|
|
927
|
my ($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN) = @$_; |
42
|
615
|
100
|
|
|
|
780
|
if ( $HEADSTART < $ignoreuntil ) { next; } |
|
515
|
|
|
|
|
597
|
|
43
|
|
|
|
|
|
|
else { |
44
|
100
|
100
|
66
|
|
|
2861
|
if ($index==0 && $CLASS==2 && $TAG==0) {$X509version = substr($decoded,$HEADSTART,($HEADLEN+$CHUNKLEN));$index++;} |
|
10
|
100
|
66
|
|
|
27
|
|
|
10
|
100
|
66
|
|
|
13
|
|
|
10
|
100
|
66
|
|
|
18
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
50
|
66
|
|
|
|
|
|
|
50
|
100
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
50
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
33
|
|
|
|
|
45
|
10
|
|
|
|
|
16
|
elsif ($index==1 && $TAG==2) {$X509serial = substr($decoded,$HEADSTART,($HEADLEN+$CHUNKLEN));$index++;} |
|
10
|
|
|
|
|
23
|
|
46
|
10
|
|
|
|
|
15
|
elsif ($index==2 && $TAG==16) {$X509signature = substr($decoded,$HEADSTART,($HEADLEN+$CHUNKLEN));$index++;} |
|
10
|
|
|
|
|
25
|
|
47
|
10
|
|
|
|
|
14
|
elsif ($index==3 && $TAG==16) {$X509issuer = substr($decoded,$HEADSTART,($HEADLEN+$CHUNKLEN));$index++;} |
|
10
|
|
|
|
|
23
|
|
48
|
10
|
|
|
|
|
15
|
elsif ($index==4 && $TAG==16) {$X509validity = substr($decoded,$HEADSTART,($HEADLEN+$CHUNKLEN));$index++;} |
|
10
|
|
|
|
|
44
|
|
49
|
10
|
|
|
|
|
11
|
elsif ($index==5 && $TAG==16) {$X509subject = substr($decoded,$HEADSTART,($HEADLEN+$CHUNKLEN));$index++;} |
|
10
|
|
|
|
|
25
|
|
50
|
10
|
|
|
|
|
13
|
elsif ($index==6 && $TAG==16) {$X509subjectPublicKeyInfo = substr($decoded,$HEADSTART,($HEADLEN+$CHUNKLEN));$index++;} |
|
0
|
|
|
|
|
0
|
|
51
|
0
|
|
|
|
|
0
|
elsif ($index==7 && $CLASS==2 && $TAG==1) {$X509issuerUniqueID = substr($decoded,$HEADSTART,($HEADLEN+$CHUNKLEN));} |
52
|
10
|
|
|
|
|
31
|
elsif ($index==7 && $CLASS==2 && $TAG==2) {$X509subjectUniqueID = substr($decoded,$HEADSTART,($HEADLEN+$CHUNKLEN));} |
53
|
10
|
|
|
|
|
24
|
elsif ($index==7 && $CLASS==2 && $TAG==3) {$X509extensions = substr($decoded,$HEADSTART,($HEADLEN+$CHUNKLEN));} |
54
|
10
|
|
|
|
|
13
|
elsif ($index==7 && $TAG==16) {$X509SignatureAlgorithm = substr($decoded,$HEADSTART,($HEADLEN+$CHUNKLEN));$index++;} |
|
10
|
|
|
|
|
25
|
|
55
|
|
|
|
|
|
|
elsif ($index==8 && $TAG==3) {$X509SignatureValue = substr($decoded,$HEADSTART,($HEADLEN+$CHUNKLEN));} |
56
|
100
|
|
|
|
|
163
|
$ignoreuntil=$HEADSTART+$HEADLEN+$CHUNKLEN; |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
} |
59
|
10
|
50
|
|
|
|
30
|
if ($index != 8) {return undef;} #Failed to read certificate |
|
0
|
|
|
|
|
0
|
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
#Standard |
62
|
10
|
50
|
|
|
|
44
|
if (defined $Values{X509version}) {$Values{X509version}=$X509version;} |
|
0
|
|
|
|
|
0
|
|
63
|
10
|
100
|
|
|
|
26
|
if (defined $Values{X509serial}) {$Values{X509serial}=$X509serial;} |
|
4
|
|
|
|
|
9
|
|
64
|
10
|
50
|
|
|
|
35
|
if (defined $Values{X509signature}) {$Values{X509signature}=$X509signature;} |
|
0
|
|
|
|
|
0
|
|
65
|
10
|
100
|
|
|
|
37
|
if (defined $Values{X509issuer}) {$Values{X509issuer}=$X509issuer;} |
|
4
|
|
|
|
|
7
|
|
66
|
10
|
50
|
|
|
|
27
|
if (defined $Values{X509validity}) {$Values{X509validity}=$X509validity;} |
|
0
|
|
|
|
|
0
|
|
67
|
10
|
100
|
|
|
|
28
|
if (defined $Values{X509subject}) {$Values{X509subject}=$X509subject;} |
|
5
|
|
|
|
|
13
|
|
68
|
10
|
50
|
|
|
|
33
|
if (defined $Values{X509subjectPublicKeyInfo}) {$Values{X509subjectPublicKeyInfo}=$X509subjectPublicKeyInfo;} |
|
0
|
|
|
|
|
0
|
|
69
|
10
|
50
|
|
|
|
22
|
if (defined $Values{X509issuerUniqueID}) {$Values{X509issuerUniqueID}=$X509issuerUniqueID;} |
|
0
|
|
|
|
|
0
|
|
70
|
10
|
50
|
|
|
|
22
|
if (defined $Values{X509subjectUniqueID}) {$Values{X509subjectUniqueID}=$X509subjectUniqueID;} |
|
0
|
|
|
|
|
0
|
|
71
|
10
|
50
|
|
|
|
22
|
if (defined $Values{X509extensions}) {$Values{X509extensions}=$X509extensions;} |
|
0
|
|
|
|
|
0
|
|
72
|
10
|
50
|
|
|
|
31
|
if (defined $Values{X509SignatureValue}) {$Values{X509SignatureValue}=$X509SignatureValue;} |
|
0
|
|
|
|
|
0
|
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
################## |
75
|
|
|
|
|
|
|
# Helpers -- Deeper parsing of certificate |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# Values of Start and End Time Seconds since Epoch |
78
|
10
|
100
|
100
|
|
|
64
|
if (defined $Values{Start} || defined $Values{End}) { |
79
|
5
|
|
|
|
|
20
|
my @validity=ASN1Unwrap($X509validity); |
80
|
5
|
|
|
|
|
20
|
my @st=ASN1Unwrap($validity[5]); |
81
|
5
|
|
|
|
|
24
|
my @et=ASN1Unwrap(substr($validity[5],$st[0]+$st[1])); |
82
|
5
|
50
|
33
|
|
|
68
|
if ( $st[4] eq "23" && $st[5]=~ /^(..)(..)(..)(..)(..)(..)Z$/ ) { $Values{Start} = timegm($6,$5,$4,$3,($2-1),$1); } |
|
5
|
0
|
0
|
|
|
50
|
|
83
|
0
|
|
|
|
|
0
|
elsif ( $st[4] eq "24" && $st[5]=~ /^(....)(..)(..)(..)(..)(..)Z$/ ) { $Values{Start} = timegm($6,$5,$4,$3,($2-1),$1); } |
84
|
5
|
50
|
33
|
|
|
263
|
if ( $et[4] eq "23" && $et[5]=~ /^(..)(..)(..)(..)(..)(..)Z$/ ) { $Values{End} = timegm($6,$5,$4,$3,($2-1),$1); } |
|
5
|
0
|
0
|
|
|
29
|
|
85
|
0
|
|
|
|
|
0
|
elsif ( $et[4] eq "24" && $et[5]=~ /^(....)(..)(..)(..)(..)(..)Z$/ ) { $Values{End} = timegm($6,$5,$4,$3,($2-1),$1); } |
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# The String Repersentation of the subject and issuer DNs |
89
|
10
|
100
|
66
|
|
|
203
|
if (defined $Values{SubjectDN} || defined $Values{Proxy}) { |
90
|
5
|
|
|
|
|
29
|
my @ASN1SubjectDNIndex=ASN1Index($X509subject); |
91
|
5
|
|
|
|
|
13
|
shift @ASN1SubjectDNIndex; |
92
|
5
|
|
|
|
|
16
|
$Values{SubjectDN}=""; |
93
|
5
|
|
|
|
|
18
|
while (@ASN1SubjectDNIndex) { |
94
|
15
|
|
|
|
|
35
|
my ($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN)=(0,0,0,0,0); |
95
|
15
|
|
|
|
|
38
|
until ($TAG == 6 ) { ($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN) = @{shift @ASN1SubjectDNIndex}; } |
|
45
|
|
|
|
|
45
|
|
|
45
|
|
|
|
|
248
|
|
96
|
15
|
|
|
|
|
34
|
my $OID=substr($X509subject,($HEADSTART+$HEADLEN),$CHUNKLEN); |
97
|
15
|
|
|
|
|
16
|
($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN) = @{shift @ASN1SubjectDNIndex}; |
|
15
|
|
|
|
|
35
|
|
98
|
15
|
|
|
|
|
38
|
my $Value=substr($X509subject,($HEADSTART+$HEADLEN),$CHUNKLEN); |
99
|
15
|
|
|
|
|
58
|
$Values{SubjectDN}.="/".VOMS::Lite::CertKeyHelper::OIDtoDNattrib(ASN1OIDtoOID($OID))."=$Value"; |
100
|
|
|
|
|
|
|
} |
101
|
|
|
|
|
|
|
} |
102
|
10
|
100
|
66
|
|
|
48
|
if (defined $Values{IssuerDN} || defined $Values{Proxy}) { |
103
|
5
|
|
|
|
|
23
|
my @ASN1IssuerDNIndex=ASN1Index($X509issuer); |
104
|
5
|
|
|
|
|
13
|
shift @ASN1IssuerDNIndex; |
105
|
5
|
|
|
|
|
16
|
$Values{IssuerDN}=""; |
106
|
5
|
|
|
|
|
19
|
while (@ASN1IssuerDNIndex) { |
107
|
15
|
|
|
|
|
30
|
my ($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN)=(0,0,0,0,0); |
108
|
15
|
|
|
|
|
34
|
until ($TAG == 6 ) { ($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN) = @{shift @ASN1IssuerDNIndex}; } |
|
45
|
|
|
|
|
51
|
|
|
45
|
|
|
|
|
181
|
|
109
|
15
|
|
|
|
|
28
|
my $OID=substr($X509issuer,($HEADSTART+$HEADLEN),$CHUNKLEN); |
110
|
15
|
|
|
|
|
19
|
($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN) = @{shift @ASN1IssuerDNIndex}; |
|
15
|
|
|
|
|
40
|
|
111
|
15
|
|
|
|
|
36
|
my $Value=substr($X509issuer,($HEADSTART+$HEADLEN),$CHUNKLEN); |
112
|
15
|
|
|
|
|
48
|
$Values{IssuerDN}.="/".VOMS::Lite::CertKeyHelper::OIDtoDNattrib(ASN1OIDtoOID($OID))."=$Value"; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
# Public key and Modulus |
117
|
10
|
100
|
66
|
|
|
68
|
if ( defined $Values{KeypublicExponent} || defined $Values{Keymodulus} ) { |
118
|
2
|
|
|
|
|
4
|
my ($OID,$modexpbitstr); |
119
|
2
|
|
|
|
|
10
|
my @KeyIndex=ASN1Index($X509subjectPublicKeyInfo); |
120
|
2
|
|
|
|
|
6
|
foreach (@KeyIndex) { |
121
|
10
|
|
|
|
|
45
|
my ($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN) = @$_; |
122
|
10
|
100
|
|
|
|
26
|
if ( ! $CONSTRUCTED ) { |
123
|
6
|
100
|
|
|
|
25
|
$OID=Hex(substr($X509subjectPublicKeyInfo,($HEADSTART+$HEADLEN),$CHUNKLEN)) if ( $TAG == 6 ); |
124
|
6
|
100
|
|
|
|
22
|
$modexpbitstr=substr($X509subjectPublicKeyInfo,($HEADSTART+$HEADLEN),$CHUNKLEN) if ( $TAG == 3 ); |
125
|
|
|
|
|
|
|
} |
126
|
|
|
|
|
|
|
} |
127
|
2
|
50
|
|
|
|
9
|
if ( $OID eq "2a864886f70d010101" ) { |
128
|
2
|
|
|
|
|
17
|
$modexpbitstr=~ s/.//; # BS always encoding 8 bit bytes |
129
|
2
|
|
|
|
|
7
|
my @KeyIndex2=ASN1Index($modexpbitstr); |
130
|
2
|
|
|
|
|
6
|
shift @KeyIndex2; |
131
|
2
|
|
|
|
|
4
|
my ($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN) = @{shift @KeyIndex2}; |
|
2
|
|
|
|
|
6
|
|
132
|
2
|
|
|
|
|
7
|
$Values{Keymodulus}=substr($modexpbitstr,($HEADSTART+$HEADLEN),$CHUNKLEN); |
133
|
2
|
|
|
|
|
4
|
($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN) = @{shift @KeyIndex2}; |
|
2
|
|
|
|
|
6
|
|
134
|
2
|
|
|
|
|
12
|
$Values{KeypublicExponent}=substr($modexpbitstr,($HEADSTART+$HEADLEN),$CHUNKLEN); |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# Issuer and Subject Hashes |
139
|
10
|
100
|
|
|
|
35
|
if (defined $Values{Hash}) { |
140
|
3
|
|
|
|
|
27
|
my $data=md5($X509subject); |
141
|
3
|
|
|
|
|
35
|
$Values{Hash}=Hex( substr($data,3,1).substr($data,2,1).substr($data,1,1).substr($data,0,1) ); |
142
|
|
|
|
|
|
|
} |
143
|
10
|
100
|
|
|
|
30
|
if (defined $Values{IHash}) { |
144
|
3
|
|
|
|
|
12
|
my $data=md5($X509issuer); |
145
|
3
|
|
|
|
|
17
|
$Values{IHash}=Hex( substr($data,3,1).substr($data,2,1).substr($data,1,1).substr($data,0,1) ); |
146
|
|
|
|
|
|
|
} |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# SSLv3 Certificate extensions |
149
|
10
|
|
|
|
|
37
|
my @Exts=(1,1,1,1,1,$X509extensions,1); |
150
|
10
|
|
|
|
|
33
|
my @ExtIndex=ASN1Index($X509extensions); |
151
|
10
|
|
|
|
|
25
|
shift (@ExtIndex) ; shift @ExtIndex; #unwrap twice from tag 3 |
|
10
|
|
|
|
|
25
|
|
152
|
10
|
|
|
|
|
40
|
while (@ExtIndex) { |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
# Get OID |
155
|
45
|
|
|
|
|
85
|
my ($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN)=(0,0,0,0,0); |
156
|
45
|
|
|
|
|
95
|
until ($TAG == 6 ) { ($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN) = @{shift @ExtIndex}; } |
|
90
|
|
|
|
|
89
|
|
|
90
|
|
|
|
|
376
|
|
157
|
45
|
|
|
|
|
83
|
my $OID=substr($X509extensions,($HEADSTART+$HEADLEN),$CHUNKLEN); |
158
|
|
|
|
|
|
|
# Calculate OID string value |
159
|
45
|
|
|
|
|
120
|
my $OIDstr=ASN1OIDtoOID($OID); |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
# Check for Criticality and get data |
162
|
45
|
|
|
|
|
55
|
($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN) = @{shift @ExtIndex}; |
|
45
|
|
|
|
|
112
|
|
163
|
45
|
|
|
|
|
83
|
my $CRITICAL=0; |
164
|
45
|
100
|
|
|
|
146
|
if ($TAG == 1) { # Check Criticality |
165
|
20
|
|
|
|
|
43
|
$CRITICAL=ord(substr($X509extensions,($HEADSTART+$HEADLEN+2),1)); |
166
|
20
|
|
|
|
|
28
|
($CLASS,$CONSTRUCTED,$TAG,$HEADSTART,$HEADLEN,$CHUNKLEN) = @{shift @ExtIndex}; |
|
20
|
|
|
|
|
55
|
|
167
|
|
|
|
|
|
|
} |
168
|
45
|
|
|
|
|
97
|
my $Value=substr($X509extensions,($HEADSTART+$HEADLEN),$CHUNKLEN); |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# Return Extension if requested |
171
|
45
|
50
|
|
|
|
133
|
if (defined $Values{"Extension:$OIDstr"} ) { |
172
|
0
|
|
|
|
|
0
|
$Values{"Extension:$OIDstr"} = $Value; |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
# GSI Proxy (check for Pre-RFC and RFC) |
176
|
45
|
50
|
33
|
|
|
157
|
if (defined $Values{ProxyInfo} && # Has Proxyinfo been requested |
|
|
|
66
|
|
|
|
|
177
|
|
|
|
|
|
|
( $OIDstr eq "1.3.6.1.5.5.7.1.14" || $OIDstr eq "1.3.6.1.4.1.3536.1.222" ) ) { |
178
|
0
|
0
|
|
|
|
0
|
next if ( ! $CRITICAL ); # MUST be critical (if it's not we can ignore it anyhow) |
179
|
0
|
|
|
|
|
0
|
my $ProxyPolicy; |
180
|
0
|
|
|
|
|
0
|
my $PCI = ASN1Unwrap($Value); |
181
|
0
|
0
|
|
|
|
0
|
my $PType = ( $OIDstr eq "1.3.6.1.5.5.7.1.14" ) ? "RFC" : "Pre-RFC"; |
182
|
0
|
0
|
|
|
|
0
|
$Values{"ProxyInfo"} .= ( $Values{"ProxyInfo"} eq "" ) ? "$PType" : ":$PType"; #Could have both ProxyInfo |
183
|
0
|
|
|
|
|
0
|
$Values{"ProxyInfo$PType"} = $PCI; |
184
|
0
|
|
|
|
|
0
|
$Values{"ProxyPolicyOID$PType"} = undef; |
185
|
0
|
|
|
|
|
0
|
$Values{"ProxyPolicy$PType"} = undef; |
186
|
0
|
|
|
|
|
0
|
$Values{"ProxyPathlen$PType"} = undef; |
187
|
0
|
|
|
|
|
0
|
until (length($PCI) == 0) { # Get the first level |
188
|
0
|
|
|
|
|
0
|
my ($headlen,$reallen,$Class,$Constructed,$Tag,$str)=ASN1Unwrap($PCI); |
189
|
0
|
|
|
|
|
0
|
$PCI=substr($PCI,($headlen+$reallen)); |
190
|
0
|
0
|
0
|
|
|
0
|
if ($Tag==16) { $ProxyPolicy=$str; } |
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
|
191
|
0
|
|
|
|
|
0
|
elsif ( $Tag==2 && $PType eq "RFC" ) { $Values{"ProxyPathlen$PType"}=ord($str); } |
192
|
0
|
|
|
|
|
0
|
elsif ( $Tag==1 ) { $Values{"ProxyPathlen$PType"}=ord(ASN1Unwrap($str)); } |
193
|
|
|
|
|
|
|
} |
194
|
0
|
|
|
|
|
0
|
until (length($ProxyPolicy) == 0) { |
195
|
0
|
|
|
|
|
0
|
my ($headlen,$reallen,$Class,$Constructed,$Tag,$str)=ASN1Unwrap($ProxyPolicy); |
196
|
0
|
|
|
|
|
0
|
$ProxyPolicy=substr($ProxyPolicy,($headlen+$reallen)); |
197
|
0
|
0
|
|
|
|
0
|
if ($Tag==6) { $Values{"ProxyPolicyOID$PType"}=$str; } |
|
0
|
0
|
|
|
|
0
|
|
198
|
0
|
|
|
|
|
0
|
elsif ($Tag==4) { $Values{"ProxyPolicy$PType"}=$str; } |
199
|
|
|
|
|
|
|
} |
200
|
0
|
|
|
|
|
0
|
next; |
201
|
|
|
|
|
|
|
} |
202
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
# Subject Alternative Name |
204
|
45
|
50
|
66
|
|
|
143
|
if (defined $Values{subjectAltName} && $OIDstr eq "2.5.29.17" ) { |
205
|
0
|
|
|
|
|
0
|
my $SAN=ASN1Unwrap($Value); |
206
|
0
|
|
|
|
|
0
|
$Values{subjectAltName}=scalar ASN1Unwrap($Value); |
207
|
0
|
|
|
|
|
0
|
my @SAN; |
208
|
0
|
|
|
|
|
0
|
until (length($SAN) == 0) { |
209
|
0
|
|
|
|
|
0
|
my ($headlen,$reallen,$Class,$Constructed,$Tag,$str)=ASN1Unwrap($SAN); |
210
|
0
|
|
|
|
|
0
|
$SAN=substr($SAN,($headlen+$reallen)); |
211
|
0
|
0
|
|
|
|
0
|
if ($Tag==0) {push @SAN,"otherName=$str"} |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
212
|
0
|
|
|
|
|
0
|
elsif ($Tag==1) {push @SAN,"rfc822Name=$str";} |
213
|
0
|
|
|
|
|
0
|
elsif ($Tag==2) {push @SAN,"dNSName=$str";} |
214
|
0
|
|
|
|
|
0
|
elsif ($Tag==3) {push @SAN,"x400Address=$str";} |
215
|
0
|
|
|
|
|
0
|
elsif ($Tag==4) {push @SAN,"directoryName=$str";} |
216
|
0
|
|
|
|
|
0
|
elsif ($Tag==5) {push @SAN,"ediPartyName=$str";} |
217
|
0
|
|
|
|
|
0
|
elsif ($Tag==6) {push @SAN,"uniformResourceIdentifier=$str";} |
218
|
0
|
|
|
|
|
0
|
elsif ($Tag==7) {push @SAN,"IPAddress=$str";} |
219
|
|
|
|
|
|
|
elsif ($Tag==8) {push @SAN,"registeredID=$str";} |
220
|
|
|
|
|
|
|
} |
221
|
0
|
|
|
|
|
0
|
$Values{subjectAltNameArray}=\@SAN; |
222
|
0
|
|
|
|
|
0
|
next; |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
# Issuer Alternative Name |
226
|
45
|
50
|
33
|
|
|
125
|
if (defined $Values{issuerAltName} && $OIDstr eq "2.5.29.18" ) { |
227
|
0
|
|
|
|
|
0
|
my $IAN=ASN1Unwrap($Value); |
228
|
0
|
|
|
|
|
0
|
$Values{issuerAltName}=scalar ASN1Unwrap($Value); |
229
|
0
|
|
|
|
|
0
|
my @IAN; |
230
|
0
|
|
|
|
|
0
|
until (length($IAN) == 0) { |
231
|
0
|
|
|
|
|
0
|
my ($headlen,$reallen,$Class,$Constructed,$Tag,$str)=ASN1Unwrap($IAN); |
232
|
0
|
|
|
|
|
0
|
$IAN=substr($IAN,($headlen+$reallen)); |
233
|
0
|
0
|
|
|
|
0
|
if ($Tag==0) {push @IAN,"otherName=$str"} |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
0
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
234
|
0
|
|
|
|
|
0
|
elsif ($Tag==1) {push @IAN,"rfc822Name=$str";} |
235
|
0
|
|
|
|
|
0
|
elsif ($Tag==2) {push @IAN,"dNSName=$str";} |
236
|
0
|
|
|
|
|
0
|
elsif ($Tag==3) {push @IAN,"x400Address=$str";} |
237
|
0
|
|
|
|
|
0
|
elsif ($Tag==4) {push @IAN,"directoryName=$str";} |
238
|
0
|
|
|
|
|
0
|
elsif ($Tag==5) {push @IAN,"ediPartyName=$str";} |
239
|
0
|
|
|
|
|
0
|
elsif ($Tag==6) {push @IAN,"uniformResourceIdentifier=$str";} |
240
|
0
|
|
|
|
|
0
|
elsif ($Tag==7) {push @IAN,"IPAddress=$str";} |
241
|
|
|
|
|
|
|
elsif ($Tag==8) {push @IAN,"registeredID=$str";} |
242
|
|
|
|
|
|
|
} |
243
|
0
|
|
|
|
|
0
|
$Values{issuerAltNameArray}=\@IAN; |
244
|
0
|
|
|
|
|
0
|
next; |
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
# Subject Key Identifier |
248
|
45
|
100
|
100
|
|
|
519
|
if (defined $Values{subjectKeyIdentifier} && $OIDstr eq "2.5.29.14" ) { |
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
|
|
100
|
100
|
|
|
|
|
249
|
8
|
|
|
|
|
29
|
my $SKI=ASN1Unwrap($Value); |
250
|
8
|
|
|
|
|
33
|
$Values{subjectKeyIdentifier}=scalar ASN1Unwrap($Value); |
251
|
8
|
|
|
|
|
24
|
next; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
# Authority key identifier |
254
|
|
|
|
|
|
|
elsif (defined $Values{authorityKeyIdentifier} && $OIDstr eq "2.5.29.35" ) { |
255
|
5
|
|
|
|
|
25
|
my $AKI=ASN1Unwrap($Value); |
256
|
5
|
|
|
|
|
11
|
$Values{authorityKeyIdentifier}=$AKI; |
257
|
5
|
|
|
|
|
16
|
$Values{authorityKeyIdentifierSkid} = undef; #explicitly undefine these incase they were set in the call! |
258
|
5
|
|
|
|
|
19
|
$Values{authorityKeyIdentifierIssuer} = undef; # |
259
|
5
|
|
|
|
|
11
|
$Values{authorityKeyIdentifierSerial} = undef; # |
260
|
5
|
|
|
|
|
20
|
until (length($AKI) == 0) { |
261
|
15
|
|
|
|
|
42
|
my ($headlen,$reallen,$Class,$Constructed,$Tag,$str)=ASN1Unwrap($AKI); |
262
|
15
|
|
|
|
|
38
|
$AKI=substr($AKI,($headlen+$reallen)); |
263
|
15
|
100
|
|
|
|
165
|
if ($Tag==0) {$Values{authorityKeyIdentifierSkid}=$str;} |
|
5
|
100
|
|
|
|
20
|
|
|
5
|
50
|
|
|
|
20
|
|
264
|
5
|
|
|
|
|
22
|
elsif ($Tag==1) {$Values{authorityKeyIdentifierIssuer}=$str;} |
265
|
|
|
|
|
|
|
elsif ($Tag==2) {$Values{authorityKeyIdentifierSerial}=Hex($str);} |
266
|
|
|
|
|
|
|
} |
267
|
5
|
|
|
|
|
16
|
next; |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
# Key Usage |
270
|
|
|
|
|
|
|
elsif (defined $Values{keyUsage} && $OIDstr eq "2.5.29.15" ) { |
271
|
5
|
|
|
|
|
14
|
my $KU=ASN1Unwrap($Value); |
272
|
5
|
|
|
|
|
9
|
my $ignore; |
273
|
5
|
50
|
|
|
|
45
|
if ($KU =~ s/^(.)//) { $ignore = ord($1); } |
|
5
|
|
|
|
|
16
|
|
274
|
5
|
|
|
|
|
9
|
my @B; |
275
|
5
|
|
|
|
|
32
|
$KU =~ s|(.)|push @B,split(//, unpack("B*", $&))|ge; |
|
5
|
|
|
|
|
58
|
|
276
|
5
|
|
|
|
|
23
|
splice @B,-$ignore; |
277
|
5
|
|
|
|
|
31
|
$Values{keyUsage}=unpack("N", pack("B32",substr("0" x 32 . join("",@B), -32 ))); |
278
|
5
|
50
|
|
|
|
30
|
$Values{keyUsageDigitalSignature} = (defined $B[0])?$B[0]:0; |
279
|
5
|
50
|
|
|
|
24
|
$Values{keyUsageNonRepudiation} = (defined $B[1])?$B[1]:0; |
280
|
5
|
50
|
|
|
|
19
|
$Values{keyUsageKeyEncipherment} = (defined $B[2])?$B[2]:0; |
281
|
5
|
50
|
|
|
|
23
|
$Values{keyUsageDataEncipherment} = (defined $B[3])?$B[3]:0; |
282
|
5
|
50
|
|
|
|
21
|
$Values{keyUsageKeyAgreement} = (defined $B[4])?$B[4]:0; |
283
|
5
|
100
|
|
|
|
19
|
$Values{keyUsageKeyCertSign} = (defined $B[5])?$B[5]:0; |
284
|
5
|
100
|
|
|
|
16
|
$Values{keyUsageCRLSign} = (defined $B[6])?$B[6]:0; |
285
|
5
|
50
|
|
|
|
16
|
$Values{keyUsageEncipherOnly} = (defined $B[7])?$B[7]:0; |
286
|
5
|
50
|
|
|
|
15
|
$Values{keyUsageDecipherOnly} = (defined $B[8])?$B[8]:0; |
287
|
5
|
|
|
|
|
21
|
next; |
288
|
|
|
|
|
|
|
} |
289
|
|
|
|
|
|
|
# Basic Constraints |
290
|
|
|
|
|
|
|
elsif (defined $Values{basicConstraints} && $OIDstr eq "2.5.29.19" ) { |
291
|
5
|
|
|
|
|
16
|
my $BC=ASN1Unwrap($Value); |
292
|
5
|
|
|
|
|
13
|
$Values{basicConstraints} = $BC; |
293
|
5
|
|
|
|
|
15
|
$Values{basicConstraintsCA} = 0; #explicitly undefine these incase they were set in the call! |
294
|
5
|
|
|
|
|
11
|
$Values{basicConstraintsPathLen} = undef; |
295
|
5
|
100
|
|
|
|
33
|
if ($BC =~ /\x01\x01(.)(.*)/) { |
296
|
3
|
|
|
|
|
9
|
$Values{basicConstraintsCA} = ord($1); |
297
|
3
|
50
|
|
|
|
15
|
if ($2 =~ /(.+)/) { $Values{basicConstraintsPathLen} = unpack("N",ASN1Unwrap($1));} |
|
0
|
|
|
|
|
0
|
|
298
|
|
|
|
|
|
|
} |
299
|
5
|
|
|
|
|
22
|
next; |
300
|
|
|
|
|
|
|
} |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
# Signature Value |
304
|
10
|
100
|
66
|
|
|
59
|
if (defined $Values{SignatureValue} || defined $Values{SignatureType}) { |
305
|
2
|
|
|
|
|
8
|
$Values{SignatureValue}=substr(ASN1Unwrap($X509SignatureValue),1); |
306
|
2
|
|
|
|
|
9
|
my $HexX509signature=Hex($X509signature); |
307
|
2
|
50
|
|
|
|
14
|
if ( $HexX509signature eq "300d06092a864886f70d0101040500" ) { $Values{SignatureType}="md5WithRSA"; } |
|
0
|
50
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
308
|
2
|
|
|
|
|
5
|
elsif ( $HexX509signature eq "300d06092a864886f70d0101050500" ) { $Values{SignatureType}="sha1WithRSA"; } |
309
|
0
|
|
|
|
|
0
|
elsif ( $HexX509signature eq "300d06092a864886f70d0101030500" ) { $Values{SignatureType}="md4WithRSA"; } |
310
|
0
|
|
|
|
|
0
|
elsif ( $HexX509signature eq "300d06092a864886f70d0101020500" ) { $Values{SignatureType}="md2WithRSA"; } |
311
|
0
|
|
|
|
|
0
|
else { $Values{SignatureType}="unrecognised"; } |
312
|
|
|
|
|
|
|
} |
313
|
10
|
|
|
|
|
428
|
return (\%Values); |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
######################################################### |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
sub Create { |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
# Load in Context |
321
|
3
|
|
|
3
|
1
|
613
|
my %context = %{ shift() }; |
|
3
|
|
|
|
|
23
|
|
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
# Create error and warning arrays |
324
|
3
|
|
|
|
|
8
|
my @Errors; my @Warnings; |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
# Get request time; |
327
|
3
|
|
|
|
|
15
|
my $now=time(); |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
# Check for required input values |
330
|
3
|
50
|
|
|
|
14
|
if ( ! defined $context{'DN'} ) { push @Errors, "X509: Distinguished Name not supplied"; } |
|
0
|
|
|
|
|
0
|
|
331
|
3
|
50
|
|
|
|
11
|
if ( ! defined $context{'Serial'} ) { push @Errors, "X509: Serial number not supplied"; } |
|
0
|
|
|
|
|
0
|
|
332
|
3
|
50
|
66
|
|
|
21
|
if ( ! defined $context{'CACert'} && defined $context{'CAKey'} ) { push @Errors, "X509: Issuer key supplied but certificate not supplied"; } |
|
0
|
|
|
|
|
0
|
|
333
|
3
|
50
|
66
|
|
|
15
|
if ( ! defined $context{'CAKey'} && defined $context{'CACert'} ) { push @Errors, "X509: Issuer certificate supplied but key not supplied"; } |
|
0
|
|
|
|
|
0
|
|
334
|
3
|
50
|
66
|
|
|
15
|
if ( ! defined $context{'CACert'} && ! defined $context{'CAKey'} ) { push @Warnings, "X509: Issuer not supplied creating Self signed certificate"; } |
|
1
|
|
|
|
|
3
|
|
335
|
3
|
50
|
66
|
|
|
14
|
if ( ! defined $context{'CACert'} && ! defined $context{'CA'} ) { push @Warnings, "X509: CA Assuming this is a CA"; $context{'CA'}="True"; } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
336
|
3
|
50
|
33
|
|
|
13
|
if ( ! defined $context{'CA'} && defined $context{'CACert'} ) { push @Warnings, "X509: CA Assuming this is not a CA"; $context{'CA'}="False"; } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
# Bail if there isn't enough information |
339
|
3
|
50
|
|
|
|
11
|
if ( @Errors > 0 ) { return { Errors => \@Errors} ; } |
|
0
|
|
|
|
|
0
|
|
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
# Check input values |
342
|
3
|
50
|
|
|
|
14
|
if (ref($context{'DN'}) ne "ARRAY" ) { push @Errors, "X509: DN Must be a reference to an array of distinguished name component strings."; } |
|
0
|
|
|
|
|
0
|
|
343
|
3
|
50
|
33
|
|
|
16
|
if ( defined ($context{'Extensions'}) && |
344
|
0
|
|
|
|
|
0
|
ref($context{'Extensions'}) ne "ARRAY" ) { push @Errors, "X509: Extensions must be passed by reference to an array of DER encoded extensions."; } |
345
|
3
|
50
|
|
|
|
24
|
if ( $context{'Serial'} !~ /^([0-9]+)$/ ) { push @Errors, "X509: Serial number was not a positive integer"; } |
|
0
|
|
|
|
|
0
|
|
346
|
3
|
50
|
|
|
|
20
|
if ( $context{'CA'} !~ /^(False|True)$/ ) { push @Errors, "X509: CA valus can be only \"True\" or \"False\""; } |
|
0
|
|
|
|
|
0
|
|
347
|
3
|
50
|
33
|
|
|
28
|
if ( defined $context{'Lifetime'} && |
348
|
0
|
|
|
|
|
0
|
$context{'Lifetime'} !~ /^[0-9]+$/) { push @Errors, "X509: Invalid Lifetime $context{'Lifetime'}. Must be a +ve int."; } |
349
|
3
|
50
|
33
|
|
|
27
|
if ( defined $context{'Bits'} && |
350
|
0
|
|
|
|
|
0
|
$context{'Bits'} !~ /^(512|1024|2048|4096)$/ ) { push @Errors, "X509: Key size can only be 512, 1024, 2048 or 4096."; } |
351
|
3
|
50
|
33
|
|
|
14
|
if ( defined $context{'SubjectAltName'} && |
352
|
0
|
|
|
|
|
0
|
ref($context{'SubjectAltName'}) ne "ARRAY" ) { push @Errors, "X509: Extensions must be passed by reference to an array of generalnames."; } |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
# Bail if inputs are not the right format |
355
|
3
|
50
|
|
|
|
10
|
if ( @Errors > 0 ) { return { Errors => \@Errors} ; } |
|
0
|
|
|
|
|
0
|
|
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
# Load input data into local variables |
358
|
3
|
|
|
|
|
8
|
my ($CertInfoRef,$KeyInfoRef)=(undef,undef); |
359
|
3
|
|
|
|
|
4
|
my %CI; |
360
|
|
|
|
|
|
|
my %KI; |
361
|
3
|
100
|
|
|
|
12
|
if ( defined $context{'CACert'} ) { |
362
|
2
|
50
|
|
|
|
31
|
$CertInfoRef = (($context{'CACert'} =~ /^(\060.+)$/s) ? Examine($&, {X509issuer=>"", X509subject=>"", End=>"", subjectKeyIdentifier=>"", X509serial=>"", subjectAltName=>""}) : undef); |
363
|
2
|
50
|
|
|
|
29
|
$KeyInfoRef = (($context{'CAKey'} =~ /^(\060.+)$/s) ? VOMS::Lite::KEY::Examine($&, {Keymodulus=>"", KeyprivateExponent=>""}) : undef); |
364
|
2
|
50
|
|
|
|
7
|
if ( defined $CertInfoRef ) { %CI=%$CertInfoRef; } else { push @Errors, "X509: Unable to parse CA certificate."; } |
|
2
|
|
|
|
|
13
|
|
|
0
|
|
|
|
|
0
|
|
365
|
2
|
50
|
33
|
|
|
19
|
if ( %CI && defined $CI{'Errors'} ) { push @Errors, "X509: Unable to parse CA certificate errors: ".join ('; ',@{ $CI{'Errors'}}); } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
366
|
2
|
50
|
|
|
|
5
|
if ( defined $KeyInfoRef ) { %KI=%$KeyInfoRef; } else { push @Errors, "X509: Unable to parse CA key."; } |
|
2
|
|
|
|
|
6
|
|
|
0
|
|
|
|
|
0
|
|
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
# Bail if there is a certificate Parse error |
370
|
3
|
50
|
|
|
|
9
|
if ( @Errors > 0 ) { return { Errors => \@Errors} ; } |
|
0
|
|
|
|
|
0
|
|
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
# Check for unknown options |
373
|
3
|
50
|
|
|
|
11
|
foreach (keys %context) { if ( ! /^(DN|subjectAltName|Quiet|Serial|CACert|CAKey|CA|Bits|Lifetime)$/ ) {push @Errors, "X509: $_ is an invalid option.";}} |
|
21
|
|
|
|
|
70
|
|
|
0
|
|
|
|
|
0
|
|
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
# Bail if any recognised options are invalid |
376
|
3
|
50
|
|
|
|
11
|
if ( @Errors > 0 ) { return { Errors => \@Errors} ; } |
|
0
|
|
|
|
|
0
|
|
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
# Warn if there is something queer |
379
|
3
|
50
|
|
|
|
9
|
if ( ! defined $context{'Lifetime'} ) { $context{'Lifetime'} = 43200; push @Warnings, "X509: Undefined lifetime. Defaulting to $context{'Lifetime'} seconds."; } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
380
|
3
|
50
|
|
|
|
42
|
if ( ! defined $context{'Bits'} ) { $context{'Bits'} = 1024; push @Warnings, "X509: Undefined key size. Defaulting to $context{'Bits'} b."; } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
381
|
3
|
100
|
|
|
|
9
|
if ( defined $context{'CACert'} ) { |
382
|
2
|
50
|
|
|
|
10
|
if ( ( $context{'Lifetime'} ) > ( $CI{'End'} - $now ) ) { push @Warnings, "X509: Requested lifetime exceeds lifetime of issuer."; } |
|
0
|
|
|
|
|
0
|
|
383
|
2
|
50
|
|
|
|
5
|
if ( ( $CI{'End'} - $now ) < 604800 ) { push @Warnings, "X509: Issuer certificate will expire in less than 1 week."; } |
|
2
|
|
|
|
|
4
|
|
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
#Get times. Now and Now + $lifetime |
387
|
3
|
|
|
|
|
20
|
my @NOW=gmtime($now); |
388
|
3
|
|
|
|
|
13
|
my @FUT=gmtime($now+$context{'Lifetime'}); |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
# UTCTIME (so two digit years, OK for the next 40 or so years!) |
391
|
3
|
|
|
|
|
26
|
my $beforeDate=sprintf("%02i%02i%02i%02i%02i%02iZ",($NOW[5] % 100),($NOW[4]+1),$NOW[3],$NOW[2],$NOW[1],$NOW[0]); |
392
|
3
|
|
|
|
|
12
|
my $afterDate=sprintf("%02i%02i%02i%02i%02i%02iZ",($FUT[5] % 100),($FUT[4]+1),$FUT[3],$FUT[2],$FUT[1],$FUT[0]); |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
# Check and parse the DN array referenced |
395
|
3
|
|
|
|
|
7
|
my $ASN1DN=""; |
396
|
3
|
|
|
|
|
5
|
foreach (@{ $context{'DN'} }) { |
|
3
|
|
|
|
|
9
|
|
397
|
9
|
|
|
|
|
25
|
my ($attrib,$value)=split(/=/,$_,2); # Splits attribute and value |
398
|
9
|
|
|
|
|
31
|
my $OID = VOMS::Lite::CertKeyHelper::DNattribToOID($attrib); # Convert Attribute to dot representation e.g. CN -> 2.5.4.3 |
399
|
9
|
50
|
|
|
|
19
|
if ( defined $OID ) { |
400
|
9
|
|
|
|
|
7
|
my $STRtype; |
401
|
9
|
50
|
|
|
|
30
|
if ( $value =~ /^[a-zA-Z0-9 \x22()+,.\/:?-]*$/ ) { $STRtype="13"; } # Printable String |
|
9
|
0
|
|
|
|
13
|
|
402
|
0
|
|
|
|
|
0
|
elsif ( $value =~ /^[\x00\x07-\x0f\x11-\x14\x18-\x1b\x20-\x23\x25-\x7d\x7f]*$/ ) { $STRtype="16"; } #IA5 String |
403
|
0
|
|
|
|
|
0
|
else { push @Errors, "X509: Can't find an apropriate encoding for $attrib+$value."; } |
404
|
9
|
50
|
|
|
|
18
|
if ( defined $STRtype ) { $ASN1DN .= ASN1Wrap("31",ASN1Wrap("30",ASN1Wrap("06",Hex(OIDtoASN1OID($OID))).ASN1Wrap($STRtype,Hex($value)))) }; |
|
9
|
|
|
|
|
25
|
|
405
|
|
|
|
|
|
|
} |
406
|
0
|
|
|
|
|
0
|
else { push @Errors, "X509: unknown Attribute: $attrib"; } |
407
|
|
|
|
|
|
|
} |
408
|
3
|
50
|
|
|
|
10
|
if ( $ASN1DN eq "" ) { push @Errors, "X509: No Attributes in Distunguished Name"; } ; |
|
0
|
|
|
|
|
0
|
|
409
|
3
|
|
|
|
|
8
|
$ASN1DN=ASN1Wrap("30",$ASN1DN); # The DN in an apropriate X.509 ASN1 structure. |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
# Make hash name |
412
|
3
|
|
|
|
|
7
|
my $Hash=$ASN1DN; |
413
|
3
|
|
|
|
|
17
|
$Hash =~ s/(..)/pack("C",hex($&))/ge; |
|
200
|
|
|
|
|
477
|
|
414
|
3
|
|
|
|
|
26
|
$Hash = md5($Hash); |
415
|
3
|
|
|
|
|
16
|
$Hash = Hex( substr($Hash,3,1).substr($Hash,2,1).substr($Hash,1,1).substr($Hash,0,1) ); |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
# Check and parse the SubjectAltName array referenced |
418
|
3
|
|
|
|
|
7
|
my $SubjectAltName=""; |
419
|
3
|
100
|
|
|
|
8
|
if ( defined $context{'subjectAltName'} ) { |
420
|
2
|
|
|
|
|
11
|
foreach (@{ $context{'subjectAltName'} }) { |
|
2
|
|
|
|
|
5
|
|
421
|
2
|
50
|
|
|
|
16
|
if ( /^otherName=/ ) { push @Errors, "X509: otherName not supported"; } |
|
0
|
100
|
|
|
|
0
|
|
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
422
|
|
|
|
|
|
|
# elsif ( /^rfc822Name=([\x00\x07-\x0f\x11-\x14\x18-\x1b\x20-\x23\x25-\x7d\x7f]*)$/ ) |
423
|
|
|
|
|
|
|
elsif ( /^rfc822Name=([\x00-\x7f]*)$/ ) #IA5String -- Misconception that DNS is only [a-zA-Z0-9.-]* |
424
|
1
|
|
|
|
|
4
|
{ $SubjectAltName.=ASN1Wrap("81",Hex($1)); } |
425
|
|
|
|
|
|
|
# elsif ( /^dNSName=([\x00\x07-\x0f\x11-\x14\x18-\x1b\x20-\x23\x25-\x7d\x7f]*)$/ ) |
426
|
|
|
|
|
|
|
elsif ( /^dNSName=([\x00-\x7f]*)$/ ) #IA5String -- Misconception that DNS is only [a-zA-Z0-9.-]* |
427
|
1
|
|
|
|
|
3
|
{ $SubjectAltName.=ASN1Wrap("82",Hex($1)); } |
428
|
0
|
|
|
|
|
0
|
elsif ( /^x400Address=/ ) { push @Errors, "X509: x400Address not supported"; } |
429
|
0
|
|
|
|
|
0
|
elsif ( /^directoryName=(30[0-9a-f]*)$/ ) { $SubjectAltName.=ASN1Wrap("84",$1); } |
430
|
0
|
|
|
|
|
0
|
elsif ( /^directoryName=(\060.*)$/ ) { $SubjectAltName.=ASN1Wrap("84",Hex($1)); } |
431
|
0
|
|
|
|
|
0
|
elsif ( /^ediPartyName=/ ) { push @Errors, "X509: ediPartyName not supported"; } |
432
|
|
|
|
|
|
|
elsif ( /^uniformResourceIdentifier=([\x00\x07-\x0f\x11-\x14\x18-\x1b\x20-\x23\x25-\x7d\x7f]*)$/ ) |
433
|
0
|
|
|
|
|
0
|
{ $SubjectAltName.=ASN1Wrap("86",Hex($1)); } |
434
|
0
|
|
|
|
|
0
|
elsif ( /^IPAddress=(.{4})$/ ) { $SubjectAltName.=ASN1Wrap("87",$1."ffffffff"); |
435
|
0
|
|
|
|
|
0
|
push @Warnings, "X509: Assuming IPv4Address has /32 Mask"; } |
436
|
|
|
|
|
|
|
elsif ( /^IPAddress=([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/ ) |
437
|
0
|
|
|
|
|
0
|
{ $SubjectAltName.=ASN1Wrap("87",Hex(chr($1).chr($2).chr($3).chr($4))."ffffffff"); |
438
|
0
|
|
|
|
|
0
|
push @Warnings, "X509: Assuming IPv4Address has /32 Mask";} |
439
|
|
|
|
|
|
|
elsif ( /^IPAddress=([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)\/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/ ) |
440
|
0
|
|
|
|
|
0
|
{ $SubjectAltName.=ASN1Wrap("87",Hex(chr($1).chr($2).chr($3).chr($4).chr($5).chr($6).chr($7).chr($8)));} |
441
|
0
|
|
|
|
|
0
|
elsif ( /^IPAddress=(.{8})$/ ) { $SubjectAltName.=ASN1Wrap("87",Hex($1)); } |
442
|
0
|
|
|
|
|
0
|
elsif ( /^IPAddress=(.{16})$/ ) { $SubjectAltName.=ASN1Wrap("87",Hex($1).("\xff" x 16)); |
443
|
0
|
|
|
|
|
0
|
push @Warnings, "X509: Assuming IPv6Address has /128 Mask"; } |
444
|
0
|
|
|
|
|
0
|
elsif ( /^registeredID=/ ) { push @Errors, "X509: registeredID not supported"; } |
445
|
|
|
|
|
|
|
elsif ( /^(rfc822Name|dNSName|directoryName|uniformResourceIdentifier|IPAddress)=/ ) |
446
|
0
|
|
|
|
|
0
|
{ push @Errors, "X509: Bad data for $1 subjectAlternitiveName"; } |
447
|
0
|
|
|
|
|
0
|
elsif ( /^([^=]+)=/ ) { push @Errors, "X509: unknown generalName $1 for subjectAlternitiveName"; } |
448
|
0
|
|
|
|
|
0
|
else { push @Errors, "X509: malformed SubjectAltName entry"; } |
449
|
|
|
|
|
|
|
} |
450
|
2
|
|
|
|
|
7
|
$SubjectAltName=ASN1Wrap("04",ASN1Wrap("30",$SubjectAltName)); |
451
|
|
|
|
|
|
|
} |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
# Get Set issuerAltName |
454
|
3
|
|
|
|
|
5
|
my $IssuerAltName=""; |
455
|
3
|
50
|
66
|
|
|
29
|
if ( defined $context{'CACert'} && $CI{subjectAltName} ne "" ) { $IssuerAltName=ASN1Wrap("04",ASN1Wrap("30",Hex($CI{subjectAltName}))); } |
|
0
|
50
|
66
|
|
|
0
|
|
456
|
0
|
|
|
|
|
0
|
elsif ( ! defined $context{'CACert'} && $SubjectAltName ne "" ) { $IssuerAltName=$SubjectAltName; } |
457
|
|
|
|
|
|
|
|
458
|
|
|
|
|
|
|
# Get Extensions |
459
|
3
|
|
|
|
|
5
|
my $ExtraExts=""; |
460
|
3
|
|
|
|
|
6
|
foreach ( @{ $context{'Extensions'} } ) { |
|
3
|
|
|
|
|
9
|
|
461
|
0
|
0
|
|
|
|
0
|
if ( /^\060/ ) { $ExtraExts.=Hex($_); } |
|
0
|
0
|
|
|
|
0
|
|
462
|
0
|
|
|
|
|
0
|
elsif ( /^30[0-9a-f]*$/ ) { $ExtraExts.=$_; } |
463
|
0
|
|
|
|
|
0
|
else { push @Errors,"X509: The format of an extension was not understood."; } |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
# Bail if DN is bad or extension was not DER or hex DER |
467
|
3
|
50
|
|
|
|
8
|
if ( @Errors > 0 ) { return { Errors => \@Errors} ; } |
|
0
|
|
|
|
|
0
|
|
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
# Generate Key Pair |
470
|
3
|
50
|
|
|
|
26
|
my $keyref = VOMS::Lite::RSAKey::Create( { Bits => $context{'Bits'}, Verbose => (defined $context{'Quiet'})?undef:"y" } ); |
471
|
3
|
50
|
|
|
|
19
|
if ( ! defined $keyref ) { return { Errors => [ "X509: Key Generation Failure" ] } ; } |
|
0
|
|
|
|
|
0
|
|
472
|
3
|
|
|
|
|
6
|
my %key = %{ $keyref }; |
|
3
|
|
|
|
|
29
|
|
473
|
3
|
50
|
|
|
|
17
|
if ( defined $key{'Error'} ) { return { Errors => [ "X509: Error in Key Generation ".$key{'Error'} ] } ; } |
|
0
|
|
|
|
|
0
|
|
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
############################### |
477
|
|
|
|
|
|
|
#OK Let's create an X509 Cred!# |
478
|
|
|
|
|
|
|
############################### |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
### Create Key Pair ###################################################### |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
# Keyversion Keymodulus KeypublicExponent KeyprivateExponent |
483
|
|
|
|
|
|
|
# Keyprime1 Keyprime2 Keyexponent1 Keyexponent2 Keycoefficient |
484
|
3
|
|
|
|
|
8
|
my $Keyversion = "020100"; |
485
|
3
|
|
|
|
|
21
|
my $Keymodulus = ASN1Wrap("02",DecToHex($key{Modulus})); |
486
|
3
|
|
|
|
|
16
|
my $KeypublicExponent = ASN1Wrap("02",DecToHex($key{PublicExponent})); |
487
|
3
|
|
|
|
|
15
|
my $KeyprivateExponent = ASN1Wrap("02",DecToHex($key{PrivateExponent})); |
488
|
3
|
|
|
|
|
16
|
my $Keyprime1 = ASN1Wrap("02",DecToHex($key{Prime1})); |
489
|
3
|
|
|
|
|
13
|
my $Keyprime2 = ASN1Wrap("02",DecToHex($key{Prime2})); |
490
|
3
|
|
|
|
|
12
|
my $Keyexponent1 = ASN1Wrap("02",DecToHex($key{Exponent1})); |
491
|
3
|
|
|
|
|
16
|
my $Keyexponent2 = ASN1Wrap("02",DecToHex($key{Exponent2})); |
492
|
3
|
|
|
|
|
17
|
my $Keycoefficient = ASN1Wrap("02",DecToHex($key{Iqmp})); |
493
|
|
|
|
|
|
|
|
494
|
3
|
|
|
|
|
24
|
my $Privatekey=ASN1Wrap("30",$Keyversion.$Keymodulus.$KeypublicExponent.$KeyprivateExponent. |
495
|
|
|
|
|
|
|
$Keyprime1.$Keyprime2.$Keyexponent1.$Keyexponent2.$Keycoefficient); |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
# If this is to be selfsigned, set the CA's private key and modulus |
498
|
3
|
100
|
|
|
|
17
|
if ( ! defined $context{'CACert'} ) { |
499
|
1
|
|
|
|
|
4
|
$KI{Keymodulus}=DecToHex($key{Modulus}); |
500
|
1
|
|
|
|
|
15
|
$KI{KeyprivateExponent}=DecToHex($key{PrivateExponent}); |
501
|
1
|
|
|
|
|
7
|
$KI{Keymodulus} =~ s/(..)/pack("C",hex($&))/ge; |
|
65
|
|
|
|
|
115
|
|
502
|
1
|
|
|
|
|
4
|
$KI{KeyprivateExponent} =~ s/(..)/pack("C",hex($&))/ge; |
|
65
|
|
|
|
|
137
|
|
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
### Create Certificate Data ############################################## |
506
|
|
|
|
|
|
|
# TBSCertificate: X509version X509serial X509signature X509issuer X509validity X509subject X509subjectPublicKeyInfo (X509issuerUniqueID) (X509subjectUniqueID) X509extensions |
507
|
|
|
|
|
|
|
|
508
|
|
|
|
|
|
|
#### Certificate Version #### (x509 v3) |
509
|
3
|
|
|
|
|
6
|
my $X509version = "a003020102"; |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
#### Serial Number #### |
512
|
3
|
|
|
|
|
14
|
my $X509serial=ASN1Wrap("02",DecToHex($context{'Serial'})); |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
#### Type of Signature #### Use SHA1 and RSA |
515
|
3
|
|
|
|
|
7
|
my $X509signature="300d06092a864886f70d0101050500"; #SEQ(OID:SHA1WithSHA1Encryption NULL) |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
#### Issuer (straight from certificate) |
518
|
3
|
100
|
|
|
|
23
|
my $X509issuer=( defined $CI{X509subject} ) ? Hex($CI{X509subject}) : $ASN1DN; |
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
#### Validity #### |
521
|
3
|
|
|
|
|
43
|
my $X509Validity=ASN1Wrap("30",ASN1Wrap("17",Hex($beforeDate)).ASN1Wrap("17",Hex($afterDate))); |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
#### Subject #### |
524
|
3
|
|
|
|
|
9
|
my $X509subject=$ASN1DN; |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
#### Public Key (RSA) #### |
527
|
3
|
|
|
|
|
14
|
my $PubKeyChunk=ASN1Wrap("30",$Keymodulus.$KeypublicExponent); |
528
|
3
|
|
|
|
|
13
|
my $X509subjectPublicKeyInfo=ASN1Wrap("30",ASN1Wrap("30","06092a864886f70d0101010500").ASN1Wrap("03",ASN1BitStr($PubKeyChunk))); |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
#### Extensions #### |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
#KeyUsage; Critical:Certificate Sign, CRL Sign -OR- Critical:Dig sign & Key encypher & Key Agree |
533
|
3
|
100
|
|
|
|
24
|
my $keyusage=ASN1Wrap("30","0603551d0f"."0101ff".(($context{'CA'} eq "True")?"040403020106":"0404030203a8")); |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
#BasicConstraints; Critical:CA=True & Pathlen undefiend -OR- Critical:CA=False & Pathlen undefiend |
536
|
3
|
100
|
|
|
|
18
|
my $basicconstraints=ASN1Wrap("30","0603551d13"."0101ff".(($context{'CA'} eq "True")?"040530030101ff":"04023000")); # why 04023000 not 04053003010100 (DER). |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
#SKID |
539
|
|
|
|
|
|
|
# my $PubKeyDigest=sha1_hex($PubKeyChunk); oops |
540
|
3
|
|
|
|
|
7
|
my $digestable=$PubKeyChunk; |
541
|
3
|
|
|
|
|
17
|
$digestable=~s/(..)/pack('C',hex($&))/ge; |
|
222
|
|
|
|
|
497
|
|
542
|
3
|
|
|
|
|
42
|
my $PubKeyDigest=sha1_hex($digestable); |
543
|
3
|
|
|
|
|
11
|
my $SKID=ASN1Wrap("30","0603551d0e".ASN1Wrap("04",ASN1Wrap("04",$PubKeyDigest))); |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
#AKID |
546
|
3
|
|
|
|
|
8
|
my $AKID; |
547
|
3
|
100
|
|
|
|
10
|
if ( ! defined $context{'CACert'} ) { |
548
|
1
|
|
|
|
|
3
|
$CI{subjectKeyIdentifier} = $PubKeyDigest; |
549
|
1
|
|
|
|
|
2
|
$CI{X509issuer} = $X509issuer; |
550
|
1
|
|
|
|
|
4
|
$CI{X509serial} = $X509serial; |
551
|
1
|
|
|
|
|
90
|
$CI{subjectKeyIdentifier} =~ s/(..)/pack("C",hex($&))/ge; |
|
20
|
|
|
|
|
38
|
|
552
|
1
|
|
|
|
|
3
|
$CI{X509issuer} =~ s/(..)/pack("C",hex($&))/ge; |
|
67
|
|
|
|
|
139
|
|
553
|
1
|
|
|
|
|
4
|
$CI{X509serial} =~ s/(..)/pack("C",hex($&))/ge; |
|
3
|
|
|
|
|
6
|
|
554
|
|
|
|
|
|
|
} |
555
|
|
|
|
|
|
|
|
556
|
3
|
|
|
|
|
16
|
$AKID=ASN1Wrap("30", "0603551d23".ASN1Wrap("04",ASN1Wrap("30",ASN1Wrap("80",Hex($CI{subjectKeyIdentifier})) |
557
|
|
|
|
|
|
|
.ASN1Wrap("a1",ASN1Wrap("a4",Hex($CI{X509issuer}))) |
558
|
|
|
|
|
|
|
.ASN1Wrap("82",Hex(scalar ASN1Unwrap($CI{X509serial}))) ))); |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
#Alternative names |
561
|
3
|
100
|
|
|
|
26
|
if ( $SubjectAltName ne "" ) { $SubjectAltName = ASN1Wrap("30","0603551d11".$SubjectAltName) } |
|
2
|
|
|
|
|
12
|
|
562
|
3
|
50
|
|
|
|
9
|
if ( $IssuerAltName ne "" ) { $IssuerAltName = ASN1Wrap("30","0603551d12".$IssuerAltName) } |
|
0
|
|
|
|
|
0
|
|
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
#Concat and wrap the Extensions |
565
|
3
|
|
|
|
|
24
|
my $X509extensions=ASN1Wrap("a3",ASN1Wrap("30",$SKID.$AKID.$keyusage.$basicconstraints.$SubjectAltName.$IssuerAltName.$ExtraExts)); |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
#### The whole chunck of certificate to be signed #### |
568
|
3
|
|
|
|
|
21
|
my $TBSCertificate=ASN1Wrap("30",$X509version.$X509serial.$X509signature.$X509issuer.$X509Validity. |
569
|
|
|
|
|
|
|
$X509subject.$X509subjectPublicKeyInfo.$X509extensions); |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
### Create Signature ################################################# |
572
|
|
|
|
|
|
|
# X509signatureAlgorithm X509signature |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
# Make MD5 Checksum and RSA sign it |
575
|
3
|
|
|
|
|
6
|
my $BinaryTBSCertificate = $TBSCertificate; |
576
|
3
|
|
|
|
|
13
|
$BinaryTBSCertificate =~ s/(..)/pack('C',hex($&))/ge; |
|
1464
|
|
|
|
|
2925
|
|
577
|
3
|
|
|
|
|
16
|
my $RSAsignedDigest = VOMS::Lite::CertKeyHelper::digestSign("sha1WithRSA",$BinaryTBSCertificate,Hex($KI{KeyprivateExponent}),Hex($KI{Keymodulus})); |
578
|
3
|
|
|
|
|
21
|
my $Signature = ASN1Wrap("03",ASN1BitStr($RSAsignedDigest)); #(Always n*8 bits for MDnRSA and SHA1RSA) |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
### Wrap Certificate up with Signature ################################ |
581
|
|
|
|
|
|
|
# TBSCertificate X509signatureAlgorithm X509signature |
582
|
|
|
|
|
|
|
|
583
|
3
|
|
|
|
|
40
|
my $Certificate = ASN1Wrap("30",$TBSCertificate.$X509signature.$Signature); |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
### Pack and return Certificate and Key in DER format ################# |
586
|
|
|
|
|
|
|
|
587
|
3
|
|
|
|
|
27
|
$Certificate=~s/(..)/pack('C',hex($&))/ge; |
|
1722
|
|
|
|
|
3216
|
|
588
|
3
|
|
|
|
|
16
|
$Privatekey=~s/(..)/pack('C',hex($&))/ge; |
|
959
|
|
|
|
|
10737
|
|
589
|
|
|
|
|
|
|
|
590
|
3
|
|
|
|
|
255
|
return { Cert=>$Certificate, Key=>$Privatekey, Warnings=>\@Warnings, Hash=>$Hash }; |
591
|
|
|
|
|
|
|
} |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
1; |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
__END__ |