blib/lib/OpenCA/X509.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 9 | 270 | 3.3 |
branch | 0 | 106 | 0.0 |
condition | 0 | 30 | 0.0 |
subroutine | 3 | 19 | 15.7 |
pod | 0 | 16 | 0.0 |
total | 12 | 441 | 2.7 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | ## OpenCA::X509 | ||||||
2 | ## | ||||||
3 | ## Copyright (C) 1998-1999 Massimiliano Pala (madwolf@openca.org) | ||||||
4 | ## All rights reserved. | ||||||
5 | ## | ||||||
6 | ## This library is free for commercial and non-commercial use as long as | ||||||
7 | ## the following conditions are aheared to. The following conditions | ||||||
8 | ## apply to all code found in this distribution, be it the RC4, RSA, | ||||||
9 | ## lhash, DES, etc., code; not just the SSL code. The documentation | ||||||
10 | ## included with this distribution is covered by the same copyright terms | ||||||
11 | ## | ||||||
12 | ## Copyright remains Massimiliano Pala's, and as such any Copyright notices | ||||||
13 | ## in the code are not to be removed. | ||||||
14 | ## If this package is used in a product, Massimiliano Pala should be given | ||||||
15 | ## attribution as the author of the parts of the library used. | ||||||
16 | ## This can be in the form of a textual message at program startup or | ||||||
17 | ## in documentation (online or textual) provided with the package. | ||||||
18 | ## | ||||||
19 | ## Redistribution and use in source and binary forms, with or without | ||||||
20 | ## modification, are permitted provided that the following conditions | ||||||
21 | ## are met: | ||||||
22 | ## 1. Redistributions of source code must retain the copyright | ||||||
23 | ## notice, this list of conditions and the following disclaimer. | ||||||
24 | ## 2. Redistributions in binary form must reproduce the above copyright | ||||||
25 | ## notice, this list of conditions and the following disclaimer in the | ||||||
26 | ## documentation and/or other materials provided with the distribution. | ||||||
27 | ## 3. All advertising materials mentioning features or use of this software | ||||||
28 | ## must display the following acknowledgement: | ||||||
29 | ## "This product includes OpenCA software written by Massimiliano Pala | ||||||
30 | ## (madwolf@openca.org) and the OpenCA Group (www.openca.org)" | ||||||
31 | ## 4. If you include any Windows specific code (or a derivative thereof) from | ||||||
32 | ## some directory (application code) you must include an acknowledgement: | ||||||
33 | ## "This product includes OpenCA software (www.openca.org)" | ||||||
34 | ## | ||||||
35 | ## THIS SOFTWARE IS PROVIDED BY OPENCA DEVELOPERS ``AS IS'' AND | ||||||
36 | ## ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||||
37 | ## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||||
38 | ## ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | ||||||
39 | ## FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||||
40 | ## DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||||||
41 | ## OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||||
42 | ## HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||||
43 | ## LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||||||
44 | ## OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||||
45 | ## SUCH DAMAGE. | ||||||
46 | ## | ||||||
47 | ## The licence and distribution terms for any publically available version or | ||||||
48 | ## derivative of this code cannot be changed. i.e. this code cannot simply be | ||||||
49 | ## copied and put under another distribution licence | ||||||
50 | ## [including the GNU Public Licence.] | ||||||
51 | ## | ||||||
52 | |||||||
53 | ## the module's errorcode is 74 | ||||||
54 | ## | ||||||
55 | ## functions | ||||||
56 | ## | ||||||
57 | ## new 11 | ||||||
58 | ## init 12 | ||||||
59 | ## getHeader 21 | ||||||
60 | ## getKey 22 | ||||||
61 | ## getBody 23 | ||||||
62 | ## getParsed 31 | ||||||
63 | ## parseCert 13 | ||||||
64 | ## getPEM 41 | ||||||
65 | ## getPEMHeader 42 | ||||||
66 | ## getDER 43 | ||||||
67 | ## getTXT 44 | ||||||
68 | ## setHeaderAttribute 51 | ||||||
69 | ## getItem 61 | ||||||
70 | ## getSerial 62 | ||||||
71 | ## setParams 71 | ||||||
72 | |||||||
73 | 1 | 1 | 1212 | use strict; | |||
1 | 2 | ||||||
1 | 40 | ||||||
74 | 1 | 1 | 5 | use Digest::MD5; | |||
1 | 1 | ||||||
1 | 37 | ||||||
75 | 1 | 1 | 784 | use X500::DN; | |||
1 | 241046 | ||||||
1 | 6143 | ||||||
76 | |||||||
77 | package OpenCA::X509; | ||||||
78 | |||||||
79 | our ($errno, $errval); | ||||||
80 | |||||||
81 | ($OpenCA::X509::VERSION = '$Revision: 1.47 $' )=~ s/(?:^.*: (\d+))|(?:\s+\$$)/defined $1?"0\.9":""/eg; | ||||||
82 | |||||||
83 | my %params = ( | ||||||
84 | cert => undef, | ||||||
85 | item => undef, | ||||||
86 | pemCert => undef, | ||||||
87 | pemHeader => undef, | ||||||
88 | derCert => undef, | ||||||
89 | txtCert => undef, | ||||||
90 | backend => undef, | ||||||
91 | parsedItem => undef, | ||||||
92 | beginCert => undef, | ||||||
93 | endCert => undef, | ||||||
94 | beginHeader => undef, | ||||||
95 | endHeader => undef, | ||||||
96 | beginKey => undef, | ||||||
97 | endKey => undef, | ||||||
98 | beginAttribute => undef, | ||||||
99 | endAttribute => undef, | ||||||
100 | certFormat => undef, | ||||||
101 | ); | ||||||
102 | |||||||
103 | sub setError { | ||||||
104 | 0 | 0 | 0 | my $self = shift; | |||
105 | |||||||
106 | 0 | 0 | if (scalar (@_) == 4) { | ||||
107 | 0 | my $keys = { @_ }; | |||||
108 | 0 | $errval = $keys->{ERRVAL}; | |||||
109 | 0 | $errno = $keys->{ERRNO}; | |||||
110 | } else { | ||||||
111 | 0 | $errno = $_[0]; | |||||
112 | 0 | $errval = $_[1]; | |||||
113 | } | ||||||
114 | |||||||
115 | ## support for: return $self->setError (1234, "Something fails.") if (not $xyz); | ||||||
116 | 0 | return undef; | |||||
117 | } | ||||||
118 | |||||||
119 | ## Create an instance of the Class | ||||||
120 | sub new { | ||||||
121 | 0 | 0 | 0 | my $that = shift; | |||
122 | 0 | 0 | my $class = ref($that) || $that; | ||||
123 | |||||||
124 | 0 | my $self = { | |||||
125 | %params, | ||||||
126 | }; | ||||||
127 | |||||||
128 | 0 | bless $self, $class; | |||||
129 | |||||||
130 | 0 | my $keys = { @_ }; | |||||
131 | 0 | my ( $infile, $tmp ); | |||||
132 | |||||||
133 | 0 | $self->{item} = $keys->{DATA}; | |||||
134 | 0 | 0 | $self->{certFormat} = ( $keys->{FORMAT} or $keys->{INFORM} or "PEM" ); | ||||
135 | 0 | $infile = $keys->{INFILE}; | |||||
136 | |||||||
137 | 0 | $self->{backend} = $keys->{SHELL}; | |||||
138 | |||||||
139 | 0 | $self->{beginCert} = "-----BEGIN CERTIFICATE-----"; | |||||
140 | 0 | $self->{endCert} = "-----END CERTIFICATE-----"; | |||||
141 | 0 | $self->{beginHeader} = "-----BEGIN HEADER-----"; | |||||
142 | 0 | $self->{endHeader} = "-----END HEADER-----"; | |||||
143 | 0 | $self->{beginAttribute} = "-----BEGIN ATTRIBUTE-----"; | |||||
144 | 0 | $self->{endAttribute} = "-----END ATTRIBUTE-----"; | |||||
145 | 0 | $self->{beginKey} = "-----BEGIN ENCRYPTED PRIVATE KEY-----"; | |||||
146 | 0 | $self->{endKey} = "-----END ENCRYPTED PRIVATE KEY-----"; | |||||
147 | |||||||
148 | 0 | 0 | if( $infile ) { | ||||
149 | 0 | $self->{item} = ""; | |||||
150 | |||||||
151 | 0 | 0 | open( FD, "<$infile" ) | ||||
152 | or return $self->setError (7411011, "OpenCA::X509->new: Cannot open infile $infile for reading."); | ||||||
153 | 0 | while ( $tmp = |
|||||
154 | 0 | $self->{item} .= $tmp; | |||||
155 | } | ||||||
156 | 0 | close( FD ); | |||||
157 | } | ||||||
158 | |||||||
159 | 0 | 0 | 0 | if ( defined($self->{item}) and $self->{item} ne "" ) { | |||
160 | 0 | $self->{cert} = $self->getBody( ITEM=>$self->{item} ); | |||||
161 | |||||||
162 | 0 | 0 | if ( not $self->init() ) { | ||||
163 | 0 | return $self->setError (7411021, "OpenCA::X509->new: Cannot initialize certificate ". | |||||
164 | "($errno)\n$errval"); | ||||||
165 | } | ||||||
166 | |||||||
167 | } | ||||||
168 | |||||||
169 | 0 | return $self; | |||||
170 | } | ||||||
171 | |||||||
172 | sub init { | ||||||
173 | 0 | 0 | 0 | my $self = shift; | |||
174 | |||||||
175 | 0 | 0 | return $self->setError (7412011, "OpenCA::X509->init: No certificate present.") | ||||
176 | if (not $self->{cert}); | ||||||
177 | |||||||
178 | 0 | $self->{pemCert} = ""; | |||||
179 | |||||||
180 | 0 | $self->{derCert} = ""; | |||||
181 | |||||||
182 | 0 | $self->{txtCert} = ""; | |||||
183 | |||||||
184 | 0 | $self->{parsedItem} = $self->parseCert(); | |||||
185 | 0 | 0 | return $self->setError (7412031, "OpenCA::X509->init: Cannot parse certificate ($errno).\n$errval") | ||||
186 | if (not $self->{parsedItem}); | ||||||
187 | |||||||
188 | ## build pem-header | ||||||
189 | 0 | $self->{pemHeader} = $self->{beginHeader}; | |||||
190 | 0 | for my $h (keys %{$self->{parsedItem}->{HEADER}}) { | |||||
0 | |||||||
191 | 0 | $self->{pemHeader} .= "\n".$h."="; | |||||
192 | 0 | 0 | if ( $self->{parsedItem}->{HEADER}->{$h} =~ /\n/ ) { | ||||
193 | ## multirow attribute | ||||||
194 | 0 | $self->{pemHeader} .= "\n".$self->{beginAttribute}. | |||||
195 | "\n".$self->{parsedItem}->{HEADER}->{$h}. | ||||||
196 | "\n".$self->{endAttribute}; | ||||||
197 | } else { | ||||||
198 | 0 | $self->{pemHeader} .= $self->{parsedItem}->{HEADER}->{$h}; | |||||
199 | } | ||||||
200 | } | ||||||
201 | 0 | $self->{pemHeader} .= "\n".$self->{endHeader}."\n"; | |||||
202 | |||||||
203 | 0 | return 1; | |||||
204 | } | ||||||
205 | |||||||
206 | ## modified by michael bell to support multirow-values | ||||||
207 | sub getHeader { | ||||||
208 | 0 | 0 | 0 | my $self = shift; | |||
209 | 0 | my $keys = { @_ }; | |||||
210 | 0 | my $req = $keys->{ITEM}; | |||||
211 | |||||||
212 | 0 | my ( $txt, $ret, $i, $key, $val ); | |||||
213 | |||||||
214 | 0 | my $beginHeader = $self->{beginHeader}; | |||||
215 | 0 | my $endHeader = $self->{endHeader}; | |||||
216 | 0 | my $beginAttribute = $self->{beginAttribute}; | |||||
217 | 0 | my $endAttribute = $self->{endAttribute}; | |||||
218 | |||||||
219 | 0 | 0 | if( ($txt) = ( $req =~ /$beginHeader\n([\S\s\n]+)\n$endHeader/m) ) { | ||||
220 | 0 | my $active_multirow = 0; | |||||
221 | 0 | foreach $i ( split ( /\n/, $txt ) ) { | |||||
222 | 0 | 0 | if ($active_multirow) { | ||||
0 | |||||||
223 | ## multirow | ||||||
224 | 0 | 0 | if ($i =~ /^$endAttribute$/) { | ||||
225 | ## end of multirow | ||||||
226 | 0 | $active_multirow = 0; | |||||
227 | } else { | ||||||
228 | 0 | 0 | $ret->{$key} .= "\n" if ($ret->{$key}); | ||||
229 | ## additional data | ||||||
230 | 0 | $ret->{$key} .= $i; | |||||
231 | } | ||||||
232 | } elsif ($i =~ /^$beginAttribute$/) { | ||||||
233 | ## begin of multirow | ||||||
234 | 0 | $active_multirow = 1; | |||||
235 | } else { | ||||||
236 | ## no multirow | ||||||
237 | ## if multirow then $ret->{key} is initially empty) | ||||||
238 | 0 | $i =~ s/\s*=\s*/=/; | |||||
239 | 0 | ( $key, $val ) = ( $i =~ /(.*)\s*=\s*(.*)\s*/ ); | |||||
240 | 0 | $ret->{$key} = $val; | |||||
241 | } | ||||||
242 | } | ||||||
243 | } | ||||||
244 | |||||||
245 | 0 | 0 | if (not defined $ret->{CSR_SERIAL}) | ||||
246 | { | ||||||
247 | 0 | $ret->{CSR_SERIAL} = -1; | |||||
248 | } | ||||||
249 | |||||||
250 | 0 | return $ret; | |||||
251 | } | ||||||
252 | |||||||
253 | sub getKey { | ||||||
254 | 0 | 0 | 0 | my $self = shift; | |||
255 | 0 | my $keys = { @_ }; | |||||
256 | 0 | my $req = $keys->{ITEM}; | |||||
257 | |||||||
258 | 0 | my $beginKey = $self->{beginKey}; | |||||
259 | 0 | my $endKey = $self->{endKey}; | |||||
260 | |||||||
261 | 0 | my ( $ret ) = ( $req =~ /($beginKey[\S\s\n]+$endKey)/ ); | |||||
262 | 0 | return $ret; | |||||
263 | } | ||||||
264 | |||||||
265 | sub getBody { | ||||||
266 | 0 | 0 | 0 | my $self = shift; | |||
267 | 0 | my $keys = { @_ }; | |||||
268 | 0 | my $req = $keys->{ITEM}; | |||||
269 | |||||||
270 | 0 | my $beginCert = $self->{beginCert}; | |||||
271 | 0 | my $endCert = $self->{endCert}; | |||||
272 | |||||||
273 | 0 | my ( $ret ) = ( $req =~ /($beginCert[\S\s\n]+$endCert)/ ); | |||||
274 | 0 | return $ret; | |||||
275 | } | ||||||
276 | |||||||
277 | sub getParsed { | ||||||
278 | 0 | 0 | 0 | my $self = shift; | |||
279 | |||||||
280 | 0 | 0 | return $self->setError (7431011, "OpenCA::X509->getParsed: The certificate was not parsed.") | ||||
281 | if ( not $self->{parsedItem} ); | ||||||
282 | 0 | return $self->{parsedItem}; | |||||
283 | } | ||||||
284 | |||||||
285 | sub parseCert { | ||||||
286 | |||||||
287 | 0 | 0 | 0 | my $self = shift; | |||
288 | 0 | my $keys = { @_ }; | |||||
289 | |||||||
290 | 0 | my ( @ouList, @exts, $ret, $k, $v, $tmp, $md5 ); | |||||
291 | |||||||
292 | 0 | my @attList = ( "SERIAL", "DN", "ISSUER", "NOTBEFORE", "NOTAFTER", | |||||
293 | "ALIAS", "MODULUS", "PUBKEY", "FINGERPRINT", "HASH", "EMAILADDRESS", | ||||||
294 | "VERSION", "PUBKEY_ALGORITHM", "SIGNATURE_ALGORITHM", "EXPONENT", | ||||||
295 | "KEYSIZE", "EXTENSIONS" ); | ||||||
296 | 0 | 0 | if ($self->{certFormat} eq "DER") | ||||
297 | { | ||||||
298 | 0 | $ret = $self->{backend}->getCertAttribute( | |||||
299 | ATTRIBUTE_LIST => \@attList, | ||||||
300 | DATA => $self->getDER(), | ||||||
301 | INFORM => "DER"); | ||||||
302 | } else { | ||||||
303 | 0 | $ret = $self->{backend}->getCertAttribute( | |||||
304 | ATTRIBUTE_LIST => \@attList, | ||||||
305 | DATA => $self->getPEM(), | ||||||
306 | INFORM => "PEM"); | ||||||
307 | } | ||||||
308 | |||||||
309 | 0 | 0 | print "OpenCA::X509->parseCert: DN: ".$ret->{SUBJECT}." \n" if ($self->{DEBUG}); |
||||
310 | |||||||
311 | 0 | $ret->{DN} =~ s/(^\/|\/$)//g; | |||||
312 | 0 | $ret->{DN} =~ s/\/([A-Za-z0-9\-]+)=/, $1=/g; | |||||
313 | |||||||
314 | 0 | $ret->{ISSUER} =~ s/(^\/|\/$)//g; | |||||
315 | 0 | $ret->{ISSUER} =~ s/\/([A-Za-z0-9\-]+)=/, $1=/g; | |||||
316 | |||||||
317 | ## OpenSSL includes a bug in -nameopt RFC2253 | ||||||
318 | ## = signs are not escaped if they are normal values | ||||||
319 | 0 | my $i = 0; | |||||
320 | 0 | my $now = "name"; | |||||
321 | 0 | while ($i < length ($ret->{DN})) | |||||
322 | { | ||||||
323 | 0 | 0 | if (substr ($ret->{DN}, $i, 1) =~ /\\/) | ||||
0 | |||||||
0 | |||||||
324 | { | ||||||
325 | 0 | $i++; | |||||
326 | } elsif (substr ($ret->{DN}, $i, 1) =~ /=/) { | ||||||
327 | 0 | 0 | if ($now =~ /value/) | ||||
328 | { | ||||||
329 | ## OpenSSL forgets to escape = | ||||||
330 | 0 | $ret->{DN} = substr ($ret->{DN}, 0, $i)."\\".substr ($ret->{DN}, $i); | |||||
331 | 0 | $i++; | |||||
332 | } else { | ||||||
333 | 0 | $now = "value"; | |||||
334 | } | ||||||
335 | } elsif (substr ($ret->{DN}, $i, 1) =~ /[,+]/) { | ||||||
336 | 0 | $now = "name"; | |||||
337 | } | ||||||
338 | 0 | $i++; | |||||
339 | } | ||||||
340 | |||||||
341 | ## load the differnt parts of the DN into DN_HASH | ||||||
342 | 0 | 0 | print "OpenCA::X509->parseCert: DN: ".$ret->{DN}." \n" if ($self->{DEBUG}); |
||||
343 | 0 | 0 | if ($ret->{DN} =~ /\\/) { | ||||
344 | 0 | my $x500_dn = X500::DN->ParseRFC2253 ($ret->{DN}); | |||||
345 | 0 | 0 | if (not $x500_dn) { | ||||
346 | 0 | 0 | print "OpenCA::X509->parseCert: X500::DN failed \n" if ($self->{DEBUG}); |
||||
347 | 0 | return $self->setError (7413031, "OpenCA::X509->parseCert: X500::DN failed."); | |||||
348 | 0 | return undef; | |||||
349 | } | ||||||
350 | 0 | my $rdn; | |||||
351 | 0 | foreach $rdn ($x500_dn->getRDNs()) { | |||||
352 | 0 | 0 | next if ($rdn->isMultivalued()); | ||||
353 | 0 | my @attr_types = $rdn->getAttributeTypes(); | |||||
354 | 0 | my $type = $attr_types[0]; | |||||
355 | 0 | my $value = $rdn->getAttributeValue ($type); | |||||
356 | 0 | push (@{$ret->{DN_HASH}->{uc($type)}}, $value); | |||||
0 | |||||||
357 | 0 | 0 | print "OpenCA::X509->parseCert: DN_HASH: $type=$value \n" if ($self->{DEBUG}); |
||||
358 | } | ||||||
359 | } else { | ||||||
360 | 0 | my @rdns = split /,/, $ret->{DN}; | |||||
361 | 0 | foreach my $rdn (@rdns) { | |||||
362 | 0 | my ($type, $value) = split /=/, $rdn; | |||||
363 | 0 | $type =~ s/^\s*//; | |||||
364 | 0 | $type =~ s/\s*$//; | |||||
365 | 0 | $value =~ s/^\s*//; | |||||
366 | 0 | $value =~ s/\s*$//; | |||||
367 | 0 | push (@{$ret->{DN_HASH}->{uc($type)}}, $value); | |||||
0 | |||||||
368 | 0 | 0 | print "OpenCA::REQ->parseReq: DN_HASH: $type=$value \n" if ($self->{DEBUG}); |
||||
369 | } | ||||||
370 | } | ||||||
371 | |||||||
372 | 0 | 0 | if( exists $ret->{PUBKEY} ) { | ||||
373 | 0 | $md5 = new Digest::MD5; | |||||
374 | 0 | $md5->add( $ret->{PUBKEY} ); | |||||
375 | 0 | $ret->{KEY_DIGEST} = $md5->hexdigest(); | |||||
376 | } | ||||||
377 | |||||||
378 | ## Check if Email field is only present in subjectAltName | ||||||
379 | 0 | 0 | 0 | if (not $ret->{EMAILADDRESS} and | |||
0 | |||||||
380 | exists $ret->{DN_HASH}->{EMAILADDRESS} and | ||||||
381 | $ret->{DN_HASH}->{EMAILADDRESS}[0]) { | ||||||
382 | 0 | $ret->{EMAILADDRESS} = $ret->{DN_HASH}->{EMAILADDRESS}[0]; | |||||
383 | } | ||||||
384 | |||||||
385 | 0 | $ret->{SIG_ALGORITHM} = $ret->{SIGNATURE_ALGORITHM}; | |||||
386 | 0 | $ret->{PK_ALGORITHM} = $ret->{PUBKEY_ALGORITHM}; | |||||
387 | |||||||
388 | ## load all extensions | ||||||
389 | 0 | $ret->{PLAIN_EXTENSIONS} = $ret->{EXTENSIONS}; | |||||
390 | 0 | delete $ret->{EXTENSIONS}; | |||||
391 | 0 | $ret->{OPENSSL_EXTENSIONS} = {}; | |||||
392 | |||||||
393 | 0 | my ($c, $val, $key); | |||||
394 | 0 | my @lines = split(/\n/, $ret->{PLAIN_EXTENSIONS}); | |||||
395 | |||||||
396 | 0 | $i = 0; | |||||
397 | 0 | while($i < @lines) { | |||||
398 | 0 | 0 | if($lines[$i] =~ /^[\s\t]*[^:]+:\s*(critical|)\s*$/i) { | ||||
399 | 0 | $key = $lines[$i]; | |||||
400 | 0 | $key =~ s/[\s\t]*:.*$//g; | |||||
401 | 0 | $key =~ s/^[\s\t]*//g; | |||||
402 | 0 | $ret->{OPENSSL_EXTENSIONS}->{$key} = []; | |||||
403 | 0 | $i++; | |||||
404 | 0 | 0 | while($lines[$i] !~ /^[\s\t].+:\s*$/ && $i < @lines) { | ||||
405 | 0 | $val = $lines[$i]; | |||||
406 | 0 | $val =~ s/^[\s]+//g; | |||||
407 | 0 | $val =~ s/[\s]+$//g; | |||||
408 | 0 | $i++; | |||||
409 | 0 | 0 | next if $val =~ /^$/; | ||||
410 | 0 | push(@{$ret->{OPENSSL_EXTENSIONS}->{$key}}, $val); | |||||
0 | |||||||
411 | } | ||||||
412 | } else { | ||||||
413 | ## FIXME: can this every happen? | ||||||
414 | 0 | $i++; | |||||
415 | } | ||||||
416 | } | ||||||
417 | |||||||
418 | 0 | 0 | if ($self->{DEBUG}) { | ||||
419 | 0 | print "OpenCA::X509->parseCert: show all extensions and their values \n"; |
|||||
420 | 0 | while(($key, $val) = each(%{$ret->{OPENSSL_EXTENSIONS}})) { | |||||
0 | |||||||
421 | 0 | print "OpenCA::X509->parseCert: found extension: $key \n"; |
|||||
422 | 0 | print "OpenCA::X509->parseCert: with value(s): $_ \n" foreach(@{$val}); |
|||||
0 | |||||||
423 | } | ||||||
424 | } | ||||||
425 | |||||||
426 | ## load special extensions | ||||||
427 | 0 | my $h = $ret->{OPENSSL_EXTENSIONS}->{"X509v3 Basic Constraints"}[0]; | |||||
428 | 0 | 0 | $h ||= ""; | ||||
429 | 0 | $h =~ s/\s//g; | |||||
430 | 0 | 0 | if ($h =~ /CA:TRUE/i) { | ||||
431 | 0 | $ret->{IS_CA} = 1; | |||||
432 | 0 | $ret->{EXTENSIONS}->{BASIC_CONSTRAINTS}->{CA} = 1; | |||||
433 | } else { | ||||||
434 | 0 | $ret->{IS_CA} = 0; | |||||
435 | 0 | $ret->{EXTENSIONS}->{BASIC_CONSTRAINTS}->{CA} = 0; | |||||
436 | } | ||||||
437 | |||||||
438 | 0 | $ret->{BODY} = $self->getBody (ITEM => $self->{item}); | |||||
439 | 0 | $ret->{HEADER} = $self->getHeader (ITEM => $self->{item}); | |||||
440 | 0 | $ret->{KEY} = $self->getKey (ITEM => $self->{item}); | |||||
441 | 0 | $ret->{ITEM} = $ret->{BODY}; | |||||
442 | 0 | $ret->{FLAG_EXPORT_STATE} = 0; | |||||
443 | |||||||
444 | ## if email was not set then we check the subject alternative name | ||||||
445 | 0 | 0 | if (not $ret->{EMAILADDRESS}) { | ||||
446 | 0 | my $h = $ret->{OPENSSL_EXTENSIONS}->{"X509v3 Subject Alternative Name"}[0]; | |||||
447 | 0 | 0 | 0 | if ($h && $h =~ /^(.*,|)\s*email:/i) { | |||
448 | ## email steckt im subjectAltName | ||||||
449 | 0 | $h =~ s/^(.*,|)\s*email:\s*//ig; | |||||
450 | 0 | $h =~ s/\s*$//g; | |||||
451 | 0 | $h =~ s/,.*$//g; | |||||
452 | 0 | $ret->{EMAILADDRESS} = $h; | |||||
453 | } | ||||||
454 | } | ||||||
455 | |||||||
456 | 0 | return $ret; | |||||
457 | } | ||||||
458 | |||||||
459 | sub getPEM { | ||||||
460 | 0 | 0 | 0 | my $self = shift; | |||
461 | |||||||
462 | 0 | 0 | if ( $self->{certFormat} eq 'PEM' ) { | ||||
463 | 0 | $self->{cert} =~ s/^\n*//; | |||||
464 | 0 | $self->{cert} =~ s/\n*$/\n/; | |||||
465 | 0 | return $self->{cert}; | |||||
466 | } | ||||||
467 | 0 | 0 | if (not $self->{pemCert}) { | ||||
468 | 0 | $self->{pemCert} = $self->{backend}->dataConvert( DATA=>$self->{cert}, | |||||
469 | DATATYPE=>"CERTIFICATE", | ||||||
470 | INFORM=>$self->{certFormat}, | ||||||
471 | OUTFORM=>"PEM" ); | ||||||
472 | 0 | 0 | return $self->setError (7441005, "OpenCA::X509->getPEM: Cannot convert request to PEM-format ". | ||||
473 | "(".$OpenCA::OpenSSL::errno.")\n".$OpenCA::OpenSSL::errval) | ||||||
474 | if (not $self->{pemCert}); | ||||||
475 | } | ||||||
476 | |||||||
477 | ## return $self->setError (7441011, "OpenCA::X509->getPEM: The certificate is not available in PEM-format.") | ||||||
478 | ## if (not $self->{pemCert}); | ||||||
479 | 0 | return $self->{pemCert}; | |||||
480 | } | ||||||
481 | |||||||
482 | sub getPEMHeader { | ||||||
483 | 0 | 0 | 0 | my $self = shift; | |||
484 | |||||||
485 | 0 | 0 | return $self->setError (7442011, "OpenCA::X509->getPEMHeader: There is no PEM-header available.") | ||||
486 | if (not $self->{pemHeader}); | ||||||
487 | 0 | return $self->{pemHeader}; | |||||
488 | } | ||||||
489 | |||||||
490 | sub getDER { | ||||||
491 | 0 | 0 | 0 | my $self = shift; | |||
492 | |||||||
493 | 0 | 0 | if ( $self->{certFormat} eq 'DER' ) { | ||||
494 | 0 | return $self->{cert}; | |||||
495 | } | ||||||
496 | 0 | 0 | if (not $self->{derCert}) { | ||||
497 | 0 | $self->{derCert} = $self->{backend}->dataConvert( DATA=>$self->{cert}, | |||||
498 | DATATYPE=>"CERTIFICATE", | ||||||
499 | INFORM=>$self->{certFormat}, | ||||||
500 | OUTFORM=>"DER" ); | ||||||
501 | 0 | 0 | return $self->setError (7443005, "OpenCA::X509->getDER: Cannot convert request to DER-format ". | ||||
502 | "(".$OpenCA::OpenSSL::errno.")\n".$OpenCA::OpenSSL::errval) | ||||||
503 | if (not $self->{derCert}); | ||||||
504 | } | ||||||
505 | |||||||
506 | ## return $self->setError (7443011, "OpenCA::X509->getDER: The certificate is not available in DER-format.") | ||||||
507 | ## if( not $self->{derCert} ); | ||||||
508 | 0 | return $self->{derCert}; | |||||
509 | } | ||||||
510 | |||||||
511 | sub getTXT { | ||||||
512 | 0 | 0 | 0 | my $self = shift; | |||
513 | |||||||
514 | 0 | 0 | if (not $self->{txtCert}) { | ||||
515 | 0 | $self->{txtCert} = $self->{backend}->dataConvert( DATA=>$self->{cert}, | |||||
516 | DATATYPE=>"CERTIFICATE", | ||||||
517 | INFORM=>$self->{certFormat}, | ||||||
518 | OUTFORM=>"TXT" ); | ||||||
519 | 0 | 0 | return $self->setError (7444005, "OpenCA::X509->init: Cannot convert request to TXT-format ". | ||||
520 | "(".$OpenCA::OpenSSL::errno.")\n".$OpenCA::OpenSSL::errval) | ||||||
521 | if (not $self->{txtCert}); | ||||||
522 | } | ||||||
523 | |||||||
524 | ## return $self->setError (7444011, "OpenCA::X509->getTXT: The certificate is not available in TXT-format.") | ||||||
525 | ## if( not $self->{txtCert} ); | ||||||
526 | 0 | return $self->{txtCert}; | |||||
527 | } | ||||||
528 | |||||||
529 | ## by michael bell to support signature in the header | ||||||
530 | ## 1) works actually only with PEM because automatical | ||||||
531 | ## transformation to DER etc. is a high risc | ||||||
532 | ## for a failure | ||||||
533 | ## 2) please submit only one attribute | ||||||
534 | sub setHeaderAttribute { | ||||||
535 | |||||||
536 | 0 | 0 | 0 | my $self = shift; | |||
537 | 0 | my $keys = { @_ }; | |||||
538 | |||||||
539 | 0 | my $beginHeader = $self->{beginHeader}; | |||||
540 | 0 | my $endHeader = $self->{endHeader}; | |||||
541 | 0 | my $beginAttribute = $self->{beginAttribute}; | |||||
542 | 0 | my $endAttribute = $self->{endAttribute}; | |||||
543 | |||||||
544 | ## check certFormat to be PEM | ||||||
545 | 0 | 0 | return $self->setError (7451011, "OpenCA::X509->setHeaderAttribute: The request is not in PEM-format.") | ||||
546 | if ($self->{certFormat} !~ /^PEM$/i); | ||||||
547 | 0 | 0 | print "X509->setHeaderAttribute: correct format - PEM \n" if ($self->{DEBUG}); |
||||
548 | |||||||
549 | ## check for header | ||||||
550 | 0 | 0 | if ($self->{item} !~ /$beginHeader/) { | ||||
551 | ## create header | ||||||
552 | 0 | $self->{item} = $beginHeader."\n".$endHeader."\n".$self->{item}; | |||||
553 | } | ||||||
554 | |||||||
555 | 0 | for my $attribute (keys %{$keys}) { | |||||
0 | |||||||
556 | |||||||
557 | 0 | 0 | print "X509->setHeaderAttribute: $attribute:=".$keys->{$attribute}." \n" if ($self->{DEBUG}); |
||||
558 | |||||||
559 | ## insert into item | ||||||
560 | ## find last position in header | ||||||
561 | ## enter attributename | ||||||
562 | ## check fo multirow | ||||||
563 | 0 | 0 | if ($keys->{$attribute} =~ /\n/) { | ||||
564 | ## multirow | ||||||
565 | 0 | $self->{item} =~ s/${endHeader}/${attribute}=\n${beginAttribute}\n$keys->{$attribute}\n${endAttribute}\n${endHeader}/; | |||||
566 | } else { | ||||||
567 | ## single row | ||||||
568 | 0 | $self->{item} =~ s/${endHeader}/${attribute}=$keys->{$attribute}\n${endHeader}/; | |||||
569 | } | ||||||
570 | |||||||
571 | } | ||||||
572 | |||||||
573 | ## if you call init then all information is lost !!! | ||||||
574 | 0 | 0 | return $self->setError (7451021, "OpenCA::X509->setHeaderAttribute: Cannot re-initialize the certificate ". | ||||
575 | "($errno)\n$errval") | ||||||
576 | if (not $self->init ( CERTIFICATE => $self->{item}, | ||||||
577 | FORMAT => "PEM")); | ||||||
578 | |||||||
579 | 0 | return 1; | |||||
580 | } | ||||||
581 | |||||||
582 | sub getItem { | ||||||
583 | 0 | 0 | 0 | my $self = shift; | |||
584 | 0 | my $txtItem = ""; | |||||
585 | 0 | my $bH = $self->{beginHeader}; | |||||
586 | 0 | my $eH = $self->{endHeader}; | |||||
587 | |||||||
588 | ## remove empty header | ||||||
589 | 0 | 0 | if ($self->getPEMHeader() !~ /^\n*$bH\n*$eH\n*$/) { | ||||
590 | 0 | $txtItem .= $self->getPEMHeader ()."\n"; | |||||
591 | } | ||||||
592 | 0 | $txtItem .= $self->getPEM(); | |||||
593 | 0 | 0 | $txtItem .= $self->getParsed()->{KEY} || ""; | ||||
594 | |||||||
595 | 0 | return $txtItem; | |||||
596 | } | ||||||
597 | |||||||
598 | sub getSerial { | ||||||
599 | 0 | 0 | 0 | my $self = shift; | |||
600 | |||||||
601 | 0 | 0 | 0 | if (defined $_[0] and ( ($_[0] =~ /^CA/i) or ($_[0] =~ /CA_/i)) ) { | |||
0 | |||||||
602 | 0 | return $self->{backend}->getDigest ( DATA => $self->getPEM() ); | |||||
603 | } else { | ||||||
604 | 0 | return $self->getParsed()->{SERIAL}; | |||||
605 | } | ||||||
606 | } | ||||||
607 | |||||||
608 | sub setParams { | ||||||
609 | |||||||
610 | 0 | 0 | 0 | my $self = shift; | |||
611 | 0 | my $params = { @_ }; | |||||
612 | 0 | my $key; | |||||
613 | |||||||
614 | 0 | foreach $key ( keys %{$params} ) { | |||||
0 | |||||||
615 | ## we should place the parameters here | ||||||
616 | } | ||||||
617 | |||||||
618 | 0 | return 1; | |||||
619 | } | ||||||
620 | |||||||
621 | # Autoload methods go after =cut, and are processed by the autosplit program. | ||||||
622 | |||||||
623 | 1; |