File Coverage

blib/lib/IO/Socket/SSL/Utils.pm
Criterion Covered Total %
statement 97 222 43.6
branch 29 118 24.5
condition 20 68 29.4
subroutine 11 22 50.0
pod 15 15 100.0
total 172 445 38.6


line stmt bran cond sub pod time code
1              
2             package IO::Socket::SSL::Utils;
3 14     14   7224 use strict;
  14         32  
  14         433  
4 14     14   79 use warnings;
  14         40  
  14         438  
5 14     14   69 use Carp 'croak';
  14         27  
  14         638  
6 14     14   79 use Net::SSLeay;
  14         24  
  14         4564  
7              
8             # old versions of Exporter do not export 'import' yet
9             require Exporter;
10             *import = \&Exporter::import;
11              
12             our $VERSION = '2.015';
13             our @EXPORT = qw(
14             PEM_file2cert PEM_file2certs PEM_string2cert PEM_cert2file PEM_certs2file PEM_cert2string
15             PEM_file2key PEM_string2key PEM_key2file PEM_key2string
16             KEY_free CERT_free
17             KEY_create_rsa CERT_asHash CERT_create
18             );
19              
20             sub PEM_file2cert {
21 10     10 1 396 my $file = shift;
22 10 50       343 my $bio = Net::SSLeay::BIO_new_file($file,'r') or
23             croak "cannot read $file: $!";
24 10         876 my $cert = Net::SSLeay::PEM_read_bio_X509($bio);
25 10         151 Net::SSLeay::BIO_free($bio);
26 10 50       35 $cert or croak "cannot parse $file as PEM X509 cert: ".
27             Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error());
28 10         38 return $cert;
29             }
30              
31             sub PEM_cert2file {
32 0     0 1 0 my ($cert,$file) = @_;
33 0 0       0 my $string = Net::SSLeay::PEM_get_string_X509($cert)
34             or croak("cannot get string from cert");
35 0 0       0 open( my $fh,'>',$file ) or croak("cannot write $file: $!");
36 0         0 print $fh $string;
37             }
38              
39 14     14   113 use constant PEM_R_NO_START_LINE => 108;
  14         37  
  14         53856  
40             sub PEM_file2certs {
41 0     0 1 0 my $file = shift;
42 0 0       0 my $bio = Net::SSLeay::BIO_new_file($file,'r') or
43             croak "cannot read $file: $!";
44 0         0 my @certs;
45 0         0 while (1) {
46 0 0       0 if (my $cert = Net::SSLeay::PEM_read_bio_X509($bio)) {
47 0         0 push @certs, $cert;
48             } else {
49 0         0 Net::SSLeay::BIO_free($bio);
50 0         0 my $error = Net::SSLeay::ERR_get_error();
51 0 0 0     0 last if ($error & 0xfff) == PEM_R_NO_START_LINE && @certs;
52 0         0 croak "cannot parse $file as PEM X509 cert: " .
53             Net::SSLeay::ERR_error_string($error);
54             }
55             }
56 0         0 return @certs;
57             }
58              
59             sub PEM_certs2file {
60 0     0 1 0 my $file = shift;
61 0 0       0 open( my $fh,'>',$file ) or croak("cannot write $file: $!");
62 0         0 for my $cert (@_) {
63 0 0       0 my $string = Net::SSLeay::PEM_get_string_X509($cert)
64             or croak("cannot get string from cert");
65 0         0 print $fh $string;
66             }
67             }
68              
69              
70             sub PEM_string2cert {
71 592     592 1 95741 my $string = shift;
72 592         2310 my $bio = Net::SSLeay::BIO_new( Net::SSLeay::BIO_s_mem());
73 592         3027 Net::SSLeay::BIO_write($bio,$string);
74 592         41692 my $cert = Net::SSLeay::PEM_read_bio_X509($bio);
75 592         2442 Net::SSLeay::BIO_free($bio);
76 592 50       1369 $cert or croak "cannot parse string as PEM X509 cert: ".
77             Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error());
78 592         1558 return $cert;
79             }
80              
81             sub PEM_cert2string {
82 0     0 1 0 my $cert = shift;
83 0   0     0 return Net::SSLeay::PEM_get_string_X509($cert)
84             || croak("cannot get string from cert");
85             }
86              
87             sub PEM_file2key {
88 0     0 1 0 my $file = shift;
89 0 0       0 my $bio = Net::SSLeay::BIO_new_file($file,'r') or
90             croak "cannot read $file: $!";
91 0         0 my $key = Net::SSLeay::PEM_read_bio_PrivateKey($bio);
92 0         0 Net::SSLeay::BIO_free($bio);
93 0 0       0 $key or croak "cannot parse $file as PEM private key: ".
94             Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error());
95 0         0 return $key;
96             }
97              
98             sub PEM_key2file {
99 0     0 1 0 my ($key,$file) = @_;
100 0 0       0 my $string = Net::SSLeay::PEM_get_string_PrivateKey($key)
101             or croak("cannot get string from key");
102 0 0       0 open( my $fh,'>',$file ) or croak("cannot write $file: $!");
103 0         0 print $fh $string;
104             }
105              
106             sub PEM_string2key {
107 0     0 1 0 my $string = shift;
108 0         0 my $bio = Net::SSLeay::BIO_new( Net::SSLeay::BIO_s_mem());
109 0         0 Net::SSLeay::BIO_write($bio,$string);
110 0         0 my $key = Net::SSLeay::PEM_read_bio_PrivateKey($bio);
111 0         0 Net::SSLeay::BIO_free($bio);
112 0 0       0 $key or croak "cannot parse string as PEM private key: ".
113             Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error());
114 0         0 return $key;
115             }
116              
117             sub PEM_key2string {
118 0     0 1 0 my $key = shift;
119 0   0     0 return Net::SSLeay::PEM_get_string_PrivateKey($key)
120             || croak("cannot get string from key");
121             }
122              
123             sub CERT_free {
124 78     78 1 26099 Net::SSLeay::X509_free($_) for @_;
125             }
126              
127             sub KEY_free {
128 0     0 1 0 Net::SSLeay::EVP_PKEY_free($_) for @_;
129             }
130              
131             sub KEY_create_rsa {
132 16   50 16 1 66 my $bits = shift || 2048;
133 16         69 my $key = Net::SSLeay::EVP_PKEY_new();
134 16         2546958 my $rsa = Net::SSLeay::RSA_generate_key($bits, 0x10001); # 0x10001 = RSA_F4
135 16         248 Net::SSLeay::EVP_PKEY_assign_RSA($key,$rsa);
136 16         156 return $key;
137             }
138              
139             if (defined &Net::SSLeay::EC_KEY_generate_key) {
140             push @EXPORT,'KEY_create_ec';
141             *KEY_create_ec = sub {
142 0   0 0   0 my $curve = shift || 'prime256v1';
143 0         0 my $key = Net::SSLeay::EVP_PKEY_new();
144 0         0 my $ec = Net::SSLeay::EC_KEY_generate_key($curve);
145 0         0 Net::SSLeay::EVP_PKEY_assign_EC_KEY($key,$ec);
146 0         0 return $key;
147             }
148             }
149              
150             # extract information from cert
151             my %gen2i = qw( OTHERNAME 0 EMAIL 1 DNS 2 X400 3 DIRNAME 4 EDIPARTY 5 URI 6 IP 7 RID 8 );
152             my %i2gen = reverse %gen2i;
153             sub CERT_asHash {
154 0     0 1 0 my $cert = shift;
155 0   0     0 my $digest_name = shift || 'sha256';
156              
157 0         0 my %hash = (
158             version => Net::SSLeay::X509_get_version($cert),
159             not_before => _asn1t2t(Net::SSLeay::X509_get_notBefore($cert)),
160             not_after => _asn1t2t(Net::SSLeay::X509_get_notAfter($cert)),
161             serial => Net::SSLeay::P_ASN1_INTEGER_get_dec(
162             Net::SSLeay::X509_get_serialNumber($cert)),
163             signature_alg => Net::SSLeay::OBJ_obj2txt (
164             Net::SSLeay::P_X509_get_signature_alg($cert)),
165             crl_uri => [ Net::SSLeay::P_X509_get_crl_distribution_points($cert) ],
166             keyusage => [ Net::SSLeay::P_X509_get_key_usage($cert) ],
167             extkeyusage => {
168             oid => [ Net::SSLeay::P_X509_get_ext_key_usage($cert,0) ],
169             nid => [ Net::SSLeay::P_X509_get_ext_key_usage($cert,1) ],
170             sn => [ Net::SSLeay::P_X509_get_ext_key_usage($cert,2) ],
171             ln => [ Net::SSLeay::P_X509_get_ext_key_usage($cert,3) ],
172             },
173             "pubkey_digest_$digest_name" => Net::SSLeay::X509_pubkey_digest(
174             $cert,_digest($digest_name)),
175             "x509_digest_$digest_name" => Net::SSLeay::X509_digest(
176             $cert,_digest($digest_name)),
177             "fingerprint_$digest_name" => Net::SSLeay::X509_get_fingerprint(
178             $cert,$digest_name),
179             );
180              
181 0         0 for([ subject => Net::SSLeay::X509_get_subject_name($cert) ],
182             [ issuer => Net::SSLeay::X509_get_issuer_name($cert) ]) {
183 0         0 my ($what,$subj) = @$_;
184 0         0 my %subj;
185 0         0 for ( 0..Net::SSLeay::X509_NAME_entry_count($subj)-1 ) {
186 0         0 my $e = Net::SSLeay::X509_NAME_get_entry($subj,$_);
187 0         0 my $k = Net::SSLeay::OBJ_obj2txt(
188             Net::SSLeay::X509_NAME_ENTRY_get_object($e));
189 0         0 my $v = Net::SSLeay::P_ASN1_STRING_get(
190             Net::SSLeay::X509_NAME_ENTRY_get_data($e));
191 0 0       0 if (!exists $subj{$k}) {
    0          
192 0         0 $subj{$k} = $v;
193             } elsif (!ref $subj{$k}) {
194 0         0 $subj{$k} = [ $subj{$k}, $v ];
195             } else {
196 0         0 push @{$subj{$k}}, $v;
  0         0  
197             }
198             }
199 0         0 $hash{$what} = \%subj;
200             }
201              
202              
203 0 0       0 if ( my @names = Net::SSLeay::X509_get_subjectAltNames($cert) ) {
204 0         0 my $alt = $hash{subjectAltNames} = [];
205 0         0 while (my ($t,$v) = splice(@names,0,2)) {
206 0   0     0 $t = $i2gen{$t} || die "unknown type $t in subjectAltName";
207 0 0       0 if ( $t eq 'IP' ) {
208 0 0       0 if (length($v) == 4) {
    0          
209 0         0 $v = join('.',unpack("CCCC",$v));
210             } elsif ( length($v) == 16 ) {
211 0         0 my @v = unpack("nnnnnnnn",$v);
212 0         0 my ($best0,$last0);
213 0         0 for(my $i=0;$i<@v;$i++) {
214 0 0       0 if ($v[$i] == 0) {
215 0 0       0 if ($last0) {
216 0         0 $last0->[1] = $i;
217 0         0 $last0->[2]++;
218 0 0       0 $best0 = $last0 if ++$last0->[2]>$best0->[2];
219             } else {
220 0         0 $last0 = [ $i,$i,0 ];
221 0   0     0 $best0 ||= $last0;
222             }
223             } else {
224 0         0 $last0 = undef;
225             }
226             }
227 0 0       0 if ($best0) {
228 0         0 $v = '';
229 0 0       0 $v .= join(':', map { sprintf( "%x",$_) } @v[0..$best0->[0]-1]) if $best0->[0]>0;
  0         0  
230 0         0 $v .= '::';
231 0 0       0 $v .= join(':', map { sprintf( "%x",$_) } @v[$best0->[1]+1..$#v]) if $best0->[1]<$#v;
  0         0  
232             } else {
233 0         0 $v = join(':', map { sprintf( "%x",$_) } @v);
  0         0  
234             }
235             }
236             }
237 0         0 push @$alt,[$t,$v]
238             }
239             }
240              
241 0         0 my @ext;
242 0         0 for( 0..Net::SSLeay::X509_get_ext_count($cert)-1 ) {
243 0         0 my $e = Net::SSLeay::X509_get_ext($cert,$_);
244 0         0 my $o = Net::SSLeay::X509_EXTENSION_get_object($e);
245 0         0 my $nid = Net::SSLeay::OBJ_obj2nid($o);
246 0 0       0 push @ext, {
    0          
247             oid => Net::SSLeay::OBJ_obj2txt($o),
248             nid => ( $nid > 0 ) ? $nid : undef,
249             sn => ( $nid > 0 ) ? Net::SSLeay::OBJ_nid2sn($nid) : undef,
250             critical => Net::SSLeay::X509_EXTENSION_get_critical($e),
251             data => Net::SSLeay::X509V3_EXT_print($e),
252             }
253             }
254 0         0 $hash{ext} = \@ext;
255              
256 0 0       0 if ( defined(&Net::SSLeay::P_X509_get_ocsp_uri)) {
257 0         0 $hash{ocsp_uri} = [ Net::SSLeay::P_X509_get_ocsp_uri($cert) ];
258             } else {
259 0         0 $hash{ocsp_uri} = [];
260 0         0 for( @ext ) {
261 0 0       0 $_->{sn} or next;
262 0 0       0 $_->{sn} eq 'authorityInfoAccess' or next;
263 0         0 push @{ $hash{ocsp_uri}}, $_->{data} =~m{\bOCSP - URI:(\S+)}g;
  0         0  
264             }
265             }
266              
267 0         0 return \%hash;
268             }
269              
270             sub CERT_create {
271 120 50   120 1 45936 my %args = @_%2 ? %{ shift() } : @_;
  0         0  
272              
273 120         1140 my $cert = Net::SSLeay::X509_new();
274 120   50     635 my $digest_name = delete $args{digest} || 'sha256';
275              
276             Net::SSLeay::ASN1_INTEGER_set(
277             Net::SSLeay::X509_get_serialNumber($cert),
278 120   33     963 delete $args{serial} || rand(2**32),
279             );
280              
281             # version default to 2 (V3)
282             Net::SSLeay::X509_set_version($cert,
283 120   50     605 delete $args{version} || 2 );
284              
285             # not_before default to now
286             Net::SSLeay::ASN1_TIME_set(
287             Net::SSLeay::X509_get_notBefore($cert),
288             delete $args{not_before} || time()
289 120   33     1427 );
290              
291             # not_after default to now+365 days
292             Net::SSLeay::ASN1_TIME_set(
293             Net::SSLeay::X509_get_notAfter($cert),
294 120   33     863 delete $args{not_after} || time() + 365*86400
295             );
296              
297             # set subject
298 120         289 my $subj_e = Net::SSLeay::X509_get_subject_name($cert);
299             my $subj = delete $args{subject} || {
300 120   100     357 organizationName => 'IO::Socket::SSL',
301             commonName => 'IO::Socket::SSL Test'
302             };
303              
304 120         607 while ( my ($k,$v) = each %$subj ) {
305             # Not everything we get is nice - try with MBSTRING_UTF8 first and if it
306             # fails try V_ASN1_T61STRING and finally V_ASN1_OCTET_STRING
307 116 50       343 for (ref($v) ? @$v : ($v)) {
308 116 0 33     1894 Net::SSLeay::X509_NAME_add_entry_by_txt($subj_e,$k,0x1000,$_,-1,0)
      33        
309             or Net::SSLeay::X509_NAME_add_entry_by_txt($subj_e,$k,20,$_,-1,0)
310             or Net::SSLeay::X509_NAME_add_entry_by_txt($subj_e,$k,4,$_,-1,0)
311             or croak("failed to add entry for $k - ".
312             Net::SSLeay::ERR_error_string(Net::SSLeay::ERR_get_error()));
313             }
314             }
315              
316 120         3584 my @ext = (
317             &Net::SSLeay::NID_subject_key_identifier => 'hash',
318             &Net::SSLeay::NID_authority_key_identifier => 'keyid',
319             );
320 120 100       4121 if ( my $altsubj = delete $args{subjectAltNames} ) {
321             push @ext,
322             &Net::SSLeay::NID_subject_alt_name =>
323 22         393 join(',', map { "$_->[0]:$_->[1]" } @$altsubj)
  57         699  
324             }
325              
326 120   66     416 my $key = delete $args{key} || KEY_create_rsa();
327 120         1126 Net::SSLeay::X509_set_pubkey($cert,$key);
328              
329 120         240 my $is = delete $args{issuer};
330 120   66     538 my $issuer_cert = delete $args{issuer_cert} || $is && $is->[0] || $cert;
331 120   66     427 my $issuer_key = delete $args{issuer_key} || $is && $is->[1] || $key;
332              
333 120         214 my %purpose;
334 120 100       297 if (my $p = delete $args{purpose}) {
335 2 50       17 if (!ref($p)) {
    50          
336 0 0 0     0 $purpose{lc($2)} = (!$1 || $1 eq '+') ? 1:0
337             while $p =~m{([+-]?)(\w+)}g;
338             } elsif (ref($p) eq 'ARRAY') {
339 0         0 for(@$p) {
340 0 0       0 m{^([+-]?)(\w+)$} or die "invalid entry in purpose: $_";
341 0 0 0     0 $purpose{lc($2)} = (!$1 || $1 eq '+') ? 1:0
342             }
343             } else {
344 2         18 while( my ($k,$v) = each %$p) {
345 2 50 33     24 $purpose{lc($k)} = ($v && $v ne '-')?1:0;
346             }
347             }
348             }
349 120 100       262 if (delete $args{CA}) {
350             # add defaults for CA
351 10         119 %purpose = (
352             ca => 1, sslca => 1, emailca => 1, objca => 1,
353             %purpose
354             );
355             }
356 120 100       270 if (!%purpose) {
357 108         392 %purpose = (server => 1, client => 1);
358             }
359              
360 120         244 my (%key_usage,%ext_key_usage,%cert_type,%basic_constraints);
361              
362 120         317 my %dS = ( digitalSignature => \%key_usage );
363 120         302 my %kE = ( keyEncipherment => \%key_usage );
364 120         488 my %CA = ( 'CA:TRUE' => \%basic_constraints, %dS, keyCertSign => \%key_usage );
365 120         235 my @disable;
366 120         3856 for(
367             [ client => { %dS, %kE, clientAuth => \%ext_key_usage, client => \%cert_type } ],
368             [ server => { %dS, %kE, serverAuth => \%ext_key_usage, server => \%cert_type } ],
369             [ email => { %dS, %kE, emailProtection => \%ext_key_usage, email => \%cert_type } ],
370             [ objsign => { %dS, %kE, codeSigning => \%ext_key_usage, objsign => \%cert_type } ],
371              
372             [ CA => { %CA }],
373             [ sslCA => { %CA, sslCA => \%cert_type }],
374             [ emailCA => { %CA, emailCA => \%cert_type }],
375             [ objCA => { %CA, objCA => \%cert_type }],
376              
377             [ emailProtection => { %dS, %kE, emailProtection => \%ext_key_usage, email => \%cert_type } ],
378             [ codeSigning => { %dS, %kE, codeSigning => \%ext_key_usage, objsign => \%cert_type } ],
379              
380             [ timeStamping => { timeStamping => \%ext_key_usage } ],
381             [ digitalSignature => { digitalSignature => \%key_usage } ],
382             [ nonRepudiation => { nonRepudiation => \%key_usage } ],
383             [ keyEncipherment => { keyEncipherment => \%key_usage } ],
384             [ dataEncipherment => { dataEncipherment => \%key_usage } ],
385             [ keyAgreement => { keyAgreement => \%key_usage } ],
386             [ keyCertSign => { keyCertSign => \%key_usage } ],
387             [ cRLSign => { cRLSign => \%key_usage } ],
388             [ encipherOnly => { encipherOnly => \%key_usage } ],
389             [ decipherOnly => { decipherOnly => \%key_usage } ],
390             [ clientAuth => { clientAuth => \%ext_key_usage } ],
391             [ serverAuth => { serverAuth => \%ext_key_usage } ],
392             ) {
393 2640 100       5176 exists $purpose{lc($_->[0])} or next;
394 258 50       671 if (delete $purpose{lc($_->[0])}) {
395 258         368 while (my($k,$h) = each %{$_->[1]}) {
  1280         3321  
396 1022         1831 $h->{$k} = 1;
397             }
398             } else {
399 0         0 push @disable, $_->[1];
400             }
401             }
402 120 50       1511 die "unknown purpose ".join(",",keys %purpose) if %purpose;
403 120         256 for(@disable) {
404 0         0 while (my($k,$h) = each %$_) {
405 0         0 delete $h->{$k};
406             }
407             }
408              
409 120 100       260 if (%basic_constraints) {
410 10         293 push @ext,&Net::SSLeay::NID_basic_constraints,
411             => join(",",'critical', sort keys %basic_constraints);
412             } else {
413 110         2866 push @ext, &Net::SSLeay::NID_basic_constraints => 'critical,CA:FALSE';
414             }
415 120 50       3792 push @ext,&Net::SSLeay::NID_key_usage
416             => join(",",'critical', sort keys %key_usage) if %key_usage;
417 120 50       3407 push @ext,&Net::SSLeay::NID_netscape_cert_type
418             => join(",",sort keys %cert_type) if %cert_type;
419 120 100       3068 push @ext,&Net::SSLeay::NID_ext_key_usage
420             => join(",",sort keys %ext_key_usage) if %ext_key_usage;
421 120         6948 Net::SSLeay::P_X509_add_extensions($cert, $issuer_cert, @ext);
422              
423 120         284 my %have_ext;
424 120         416 for(my $i=0;$i<@ext;$i+=2) {
425 732         2013 $have_ext{ $ext[$i] }++
426             }
427 120 50       278 for my $ext (@{ delete $args{ext} || [] }) {
  120         1016  
428             my $nid = $ext->{nid}
429             || $ext->{sn} && Net::SSLeay::OBJ_sn2nid($ext->{sn})
430 0   0     0 || croak "cannot determine NID of extension";
431 0 0       0 $have_ext{$nid} and next;
432 0         0 my $val = $ext->{data};
433 0 0       0 if ($nid == 177) {
434             # authorityInfoAccess:
435             # OpenSSL i2v does not output the same way as expected by i2v :(
436 0         0 for (split(/\n/,$val)) {
437 0         0 s{ - }{;}; # "OCSP - URI:..." -> "OCSP;URI:..."
438 0 0       0 $_ = "critical,$_" if $ext->{critical};
439 0         0 Net::SSLeay::P_X509_add_extensions($cert,$issuer_cert,$nid,$_);
440             }
441             } else {
442 0 0       0 $val = "critical,$val" if $ext->{critical};
443 0         0 Net::SSLeay::P_X509_add_extensions($cert, $issuer_cert, $nid, $val);
444             }
445             }
446              
447             die "unknown arguments: ". join(" ", sort keys %args)
448 120 50 33     616 if !delete $args{ignore_invalid_args} && %args;
449              
450 120         2036 Net::SSLeay::X509_set_issuer_name($cert,
451             Net::SSLeay::X509_get_subject_name($issuer_cert));
452 120         351 Net::SSLeay::X509_sign($cert,$issuer_key,_digest($digest_name));
453              
454 120         1462 return ($cert,$key);
455             }
456              
457              
458              
459             if ( defined &Net::SSLeay::ASN1_TIME_timet ) {
460             *_asn1t2t = \&Net::SSLeay::ASN1_TIME_timet
461             } else {
462             require Time::Local;
463             my %mon2i = qw(
464             Jan 0 Feb 1 Mar 2 Apr 3 May 4 Jun 5
465             Jul 6 Aug 7 Sep 8 Oct 9 Nov 10 Dec 11
466             );
467             *_asn1t2t = sub {
468             my $t = Net::SSLeay::P_ASN1_TIME_put2string( shift );
469             my ($mon,$d,$h,$m,$s,$y,$tz) = split(/[\s:]+/,$t);
470             defined( $mon = $mon2i{$mon} ) or die "invalid month in $t";
471             $tz ||= $y =~s{^(\d+)([A-Z]\S*)}{$1} && $2;
472             if ( ! $tz ) {
473             return Time::Local::timelocal($s,$m,$h,$d,$mon,$y)
474             } elsif ( $tz eq 'GMT' ) {
475             return Time::Local::timegm($s,$m,$h,$d,$mon,$y)
476             } else {
477             die "unexpected TZ $tz from ASN1_TIME_print";
478             }
479             }
480             }
481              
482             {
483             my %digest;
484             sub _digest {
485 120     120   226 my $digest_name = shift;
486 120   66     226568 return $digest{$digest_name} ||= do {
487 6         80 Net::SSLeay::SSLeay_add_ssl_algorithms();
488 6 50       16969 Net::SSLeay::EVP_get_digestbyname($digest_name)
489             or die "Digest algorithm $digest_name is not available";
490             };
491             }
492             }
493              
494              
495             1;
496              
497             __END__