-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathCRL.pm
165 lines (140 loc) · 4.79 KB
/
CRL.pm
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
158
159
160
161
162
163
164
165
#
# @(#)$Id$
#
#
package CRL;
use strict;
require OSSL and import OSSL unless defined &OSSL::new;
use vars qw/ $log $cnf /;
# Syntax:
# CRL->new( [name [,data]] );
# CRL->setName( name);
# CRL->setData( datablob ); # load a CRL in PEM format or bails out
# CRL->verify( cafilelist ); # returns path to CA or undef if verify failed
#
#
sub new {
my $obref = {}; bless $obref;
my $self = shift;
$self = $obref;
my $name = shift;
my $data = shift;
$self->{"name"} = "unknown";
$self->setName($name) if $name;
$self->setData($data) if $data;
return $self;
}
sub setName($$) {
my $self = shift or die "Invalid invocation of CRL::setName\n";
my $name = shift;
return 0 unless $name;
$self->{"name"} = $name;
return 1;
}
sub setData($$) {
my $self = shift or die "Invalid invocation of CRL::setData\n";
my $data = shift;
my $pemdata = undef;
my $errormsg;
my $openssl = OSSL->new() or $::log->err("OpenSSL not found") and return 0;
# try to recognise data type and normalise to PEM string
# but extract only the first blob of PEM (so max one CRL per data object)
#
if ( $data =~
/(^-----BEGIN X509 CRL-----\n[^-]+\n-----END X509 CRL-----$)/sm ) {
$pemdata = $1;
} elsif ( substr($data,0,1) eq "0" ) { # looks a bit like an ASN.1 SEQ
($pemdata,$errormsg) =
$openssl->Exec3($data, qw/ crl -inform DER -outform PEM / );
$pemdata or
$::log->warn("Apparent DER data for",$self->{"name"},"not recognised")
and return 0;
} else {
$::log->warn("CRL data for",$self->{"name"},"not recognised");
return 0;
}
# extract other data from the pem blob with openssl
(my $statusdata,$errormsg) =
$openssl->Exec3($pemdata, qw/ crl
-noout -issuer -sha1 -fingerprint -lastupdate -nextupdate -hash/);
defined $statusdata or do {
( my $eline = $errormsg ) =~ s/\n.*//sgm;
$::log->warn("Unable to extract CRL data for",$self->{"name"},$eline);
return 0;
};
$statusdata =~ /(?:^|\n)SHA1 Fingerprint=([^\n]+)\n/ and
$self->{"sha1fp"} = $1;
$statusdata =~ /(?:^|\n)issuer=([^\n]+)\n/ and
$self->{"issuer"} = $1;
$statusdata =~ /(?:^|\n)lastUpdate=([^\n]+)\n/ and
$self->{"lastupdatestr"} = $1;
$statusdata =~ /(?:^|\n)nextUpdate=([^\n]+)\n/ and
$self->{"nextupdatestr"} = $1;
$statusdata =~ /(?:^|\n)([0-9a-f]{8})\n/ and
$self->{"hash"} = $1;
$self->{"nextupdatestr"} and
$self->{"nextupdate"} = $openssl->gms2t($self->{"nextupdatestr"});
$self->{"lastupdatestr"} and
$self->{"lastupdate"} = $openssl->gms2t($self->{"lastupdatestr"});
#$self->{"nextupdate"} = time - 200;
#$self->{"lastupdate"} = time + 200;
$self->{"data"} = $data;
$self->{"pemdata"} = $pemdata;
return 1;
}
sub getLastUpdate($) {
my $self = shift or die "Invalid invocation of CRL::getLastUpdate\n";
return $self->{"lastupdate"} || undef;
}
sub getNextUpdate($) {
my $self = shift or die "Invalid invocation of CRL::getNextUpdate\n";
return $self->{"nextupdate"} || undef;
}
sub getAttribute($$) {
my $self = shift or die "Invalid invocation of CRL::getAttribute\n";
my $key = shift;
return $self->{$key} || undef;
}
sub getPEMdata($) {
my $self = shift or die "Invalid invocation of CRL::getPEMdata\n";
$self->{"pemdata"} or
$::log->err("Attempt to extract PEM data from bad CRL object",
($self->{"name"}||"unknown")) and
return undef;
return $self->{"pemdata"};
}
sub verify($@) {
my $self = shift or die "Invalid invocation of CRL::verify\n";
my $openssl = OSSL->new() or $::log->err("OpenSSL not found") and return 0;
$self->{"pemdata"} or
$::log->err("verify called on empty data blob") and return 0;
my @verifyStatus = ();
# openssl crl verify works against a single CA and does not need a
# full chain to be present. That suits us file (checked with OpenSSL
# 0.9.5a and 1.0.0a)
my $verifyOK;
foreach my $cafile ( @_ ) {
-e $cafile or
$::log->err("CRL::verify called with nonexistent CA file $cafile") and
next;
my ($dataout,$dataerr) =
$openssl->Exec3($self->{"pemdata"}, qw/crl -noout -CAfile/,$cafile);
$dataerr and $dataout .= $dataerr;
$dataout =~ /verify OK/ and $verifyOK = $cafile and last;
}
$verifyOK or push @verifyStatus, "CRL signature failed";
$verifyOK and
$::log->verb(4,"Verified CRL",$self->{"name"},"against $verifyOK");
$self->{"nextupdate"} or
push @verifyStatus, "CRL nextUpdate determination failed";
$self->{"lastupdate"} or
push @verifyStatus, "CRL lastUpdate determination failed";
if ( $self->{"nextupdate"} and $self->{"nextupdate"} < time ) {
push @verifyStatus, "CRL has nextUpdate time in the past";
}
if ( $self->{"lastupdate"} and $self->{"lastupdate"} > time ) {
push @verifyStatus, "CRL has lastUpdate time in the future";
}
return @verifyStatus;
}
1;