1

I have been using Crypt::X509 before, but now I porting my code to newer supported library Crypt::OpenSSL::X509. The most important fields in the certificate are CN and SAN, I expect there are a simple call like:

use Crypt::X509;
print $x509->$cert_hr->SubjectAltName;

But instead I have to use cumbersome code:

use Crypt::OpenSSL::X509;
my $ext = $x509->extensions_by_oid();
print ${$ext}{'2.5.29.17'}->value();

But what makes it worse, returned string has parasitic "." inside, and I need to create some smart regular expressions to safely clean it.

I feel I am missing something simple. Is there another function or library?

Edit: Test results: Proposed Timothy solution works as long as you updated to latest version of library. Cannot add comment, neither press 'Accepted answer.' Will re-visit later.

user1281461
  • 45
  • 1
  • 5
  • *"Is there another function or library?"* - have a look at [IO::Socket::SSL::Utils](https://metacpan.org/pod/IO::Socket::SSL::Utils) which contains functions to parse certificate to hash, create new certificates from hash ... It also provides easy access to [subjectAltNames](https://metacpan.org/pod/IO::Socket::SSL::Utils#subjectAltNames) – Steffen Ullrich Nov 30 '21 at 19:34

1 Answers1

1

Here is an example of how to do it using Crypt::OpenSSL::X509 and Convert::ASN1 which I must say took far more time that I expected it to take:

use Crypt::OpenSSL::X509;
use Convert::ASN1;
 
my $x509 = Crypt::OpenSSL::X509->new_from_file('google.pem');
my $ext = $x509->extensions_by_oid();
my $pdu = ${$ext}{'2.5.29.17'}->value();
$pdu =~ s/#//g;

my @san = get_san($pdu);

print "Size: ", scalar @san, "\n";

foreach (@san) {
    print "$_\n";
}

sub get_san {
    my $bin_data = join '', pack 'H*', @_;
    $asn = Convert::ASN1->new();

    my $ok = $asn->prepare(q<
        DNSName ::=  
            [2]
            IA5String
        SubjectAltName ::= SEQUENCE OF
            DNSName
    >);
    die "*** Could not prepare definition: ".$asn->error()
        if !$ok;

    my $top = $asn->find("SubjectAltName")
        or die $asn->error;
    $out = $top->decode($bin_data)
        or die "can't decode SubjectAltName: ".$top->error;

    return @$out;
}

https://github.com/dsully/perl-crypt-openssl-x509/pull/92 implements an expanded form of this which should work for most X509 certificates

Timothy Legge
  • 459
  • 1
  • 4
  • 5
  • Does not work. Added 2 lines for debug, nothing else changed. ` print("Parameters received for get_san: ".join("",@_)."\n"); print "bin_data=<$bin_data>=HEX(".sprintf("%v02X", $bin_data).")\n"; ` Result: ` # openssl x509 -in google.pem -text | grep "v3 Subject A" -A 1 X509v3 Subject Alternative Name: DNS:www.google.com # ./stack_overflow.pl Parameters received for get_san: 0...www.google.com bin_data=<-^->=HEX(0E.EE.00.0E.08.80.5E.EC.86) can't decode Contact: decode error at /usr/share/perl5/vendor_perl/Convert/ASN1/_decode.pm line 64. ` – user1281461 Dec 03 '21 at 19:24
  • I am sorry, dont know how to do formatting in comments. – user1281461 Dec 03 '21 at 19:27
  • weird, I may have an older version. Let me take another look – Timothy Legge Dec 03 '21 at 21:02
  • can you check the module versions perl -MCrypt::OpenSSL::X509 -I blib/lib/ -I blib/arch/ -e 'print $Crypt::OpenSSL::X509::VERSION, "\n";' perl -MConvert::ASN1 -I blib/lib/ -I blib/arch/ -e 'print $Convert::ASN1::VERSION, "\n";' The function expects a long string of hex characters like: 30820935820C.... which will fill the screen. If you use the the certificate from metacpan: Parameters received for get_san: 300E820C6D6574616370616E2E6F7267 bin_data=<0� metacpan.org>=HEX(30.0E.82.0C.6D.65.74.61.63.70.61.6E.2E.6F.72.67) Size: 1 metacpan.org – Timothy Legge Dec 03 '21 at 22:47
  • See also https://github.com/dsully/perl-crypt-openssl-x509/pull/92 it might take a while to get accepted into Crypt::OpenSSL::X509 (if it does) but I expanded it to work for the various SAN types. – Timothy Legge Dec 04 '21 at 18:52