package NGCP::Panel::Model::CA; use Sipwise::Base; use MIME::Base64 qw(decode_base64); use Time::HiRes qw(); use Path::Tiny qw(); use Sys::Hostname qw(hostname); use parent 'Catalyst::Component'; sub client_signing_template { my ($self, $serial) = @_; return <<"TEMPLATE_END"; cn = "Sipwise NGCP API client certificate" expiration_days = 3650 serial = $serial tls_www_client signing_key encryption_key TEMPLATE_END } sub COMPONENT { my ($class, $app, $args) = @_; $args = $class->merge_config_hashes($class->config, $args); my $self = $class->new($app, $args); return $self; } sub make_client { my ($self, $c, $serial) = @_; my $client_key = Path::Tiny->tempfile; my($command,$stdout); if($self->check_ca_errors($c)){ die [$c->loc('Cannot use the configured certificate for signing client certificates'), "showdetails"]; } $command = sprintf 'certtool -p --bits 3248 --outfile %s 1>&- 2>&-', $client_key->stringify; $c->log->debug($command); system $command; my $client_signing_template = Path::Tiny->tempfile; my $tmpl = $self->client_signing_template($serial); $c->log->debug($tmpl); $client_signing_template->spew($tmpl); my $client_cert = Path::Tiny->tempfile; $command = sprintf 'certtool -c --load-privkey %s --outfile %s --load-ca-certificate %s --load-ca-privkey %s --template %s', $client_key->stringify, $client_cert->stringify, ($c->config->{ssl}->{rest_api_certfile} || $c->config->{ssl}->{certfile}), ($c->config->{ssl}->{rest_api_keyfile} || $c->config->{ssl}->{keyfile}), $client_signing_template->stringify; $c->log->debug($command); $stdout = `$command 2>&1`; $c->log->debug($stdout) if $stdout; my $cert = $client_cert->slurp . $client_key->slurp =~ s/.*(?=-----BEGIN RSA PRIVATE KEY-----)//mrs; $client_cert->remove; $client_key->remove; return $cert; } sub check_ca_errors { my ($self, $c) = @_; my($command,$stdout,$error); $command = 'openssl x509 -noout -purpose -in ' . $c->config->{ssl}->{rest_api_certfile}; $c->log->debug($command); $stdout = `$command 2>&1` // ""; unless ($stdout =~ m/SSL (client|server) CA : Yes/) { $error = "Failed to check CA certificate: $stdout"; } $command = 'openssl verify ' . $c->config->{ssl}->{rest_api_certfile}; #$command = 'openssl verify /etc/ngcp-config/shared-files/ssl/client-auth-ca.crt'; $c->log->debug($command); $stdout = `$command 2>&1` // ""; if ($stdout =~ m/certificate has expired/) { $error = "Failed to check CA certificate: expired: $stdout"; } if($error){ $c->log->error($error); return $error; } return 0; } sub make_pkcs12 { my ($self, $c, $serial, $cert, $pass) = @_; my $cert_file = Path::Tiny->tempfile; $cert_file->spew($cert); my $p12_file = Path::Tiny->tempfile; my $command = sprintf 'openssl pkcs12 -export -in %s -inkey %s -out %s -password pass:%s -name "NGCP API Client Certificate %d"', $cert_file->stringify, $cert_file->stringify, $p12_file->stringify, $pass, $serial; $c->log->debug($command); system $command; my $p12 = $p12_file->slurp({binmode => ":raw"}); $cert_file->remove; $p12_file->remove; return $p12; } sub get_server_cert { my ($self, $c) = @_; my $cert_file = Path::Tiny->new($c->config->{ssl}->{server_certfile}); return $cert_file->slurp; } sub get_server_ca_cert { my ($self, $c) = @_; my $cert_file = Path::Tiny->new($c->config->{ssl}->{server_cacertfile}); return $cert_file->slurp; } sub get_provisioning_server_cert { my ($self, $c) = @_; my $cert_file = Path::Tiny->new($c->config->{deviceprovisioning}->{server_certfile}); return $cert_file->slurp; } sub get_provisioning_ca_cert { my ($self, $c) = @_; my $cert_file = Path::Tiny->new($c->config->{deviceprovisioning}->{ca_certfile}); return $cert_file->slurp; } sub get_provisioning_root_ca_cert { my ($self, $c) = @_; my $content = $self->get_provisioning_ca_cert($c); $content =~ s/\r?\n//gm; $content =~ s/^.*?BEGIN CERTIFICATE\-+(.*?)\-+END CERTIFICATE.*$/$1/; return $content; } 1; # vim: set tabstop=4 expandtab