diff options
Diffstat (limited to 'FS/FS/svc_cert.pm')
-rw-r--r-- | FS/FS/svc_cert.pm | 408 |
1 files changed, 0 insertions, 408 deletions
diff --git a/FS/FS/svc_cert.pm b/FS/FS/svc_cert.pm deleted file mode 100644 index 88e4199..0000000 --- a/FS/FS/svc_cert.pm +++ /dev/null @@ -1,408 +0,0 @@ -package FS::svc_cert; - -use strict; -use base qw( FS::svc_Common ); -use Tie::IxHash; -#use FS::Record qw( qsearch qsearchs ); -use FS::cust_svc; - -=head1 NAME - -FS::svc_cert - Object methods for svc_cert records - -=head1 SYNOPSIS - - use FS::svc_cert; - - $record = new FS::svc_cert \%hash; - $record = new FS::svc_cert { 'column' => 'value' }; - - $error = $record->insert; - - $error = $new_record->replace($old_record); - - $error = $record->delete; - - $error = $record->check; - -=head1 DESCRIPTION - -An FS::svc_cert object represents a certificate. FS::svc_cert inherits from -FS::Record. The following fields are currently supported: - -=over 4 - -=item svcnum - -primary key - -=item recnum - -recnum - -=item privatekey - -privatekey - -=item csr - -csr - -=item certificate - -certificate - -=item cacert - -cacert - -=item common_name - -common_name - -=item organization - -organization - -=item organization_unit - -organization_unit - -=item city - -city - -=item state - -state - -=item country - -country - -=item cert_contact - -contact email - - -=back - -=head1 METHODS - -=over 4 - -=item new HASHREF - -Creates a new certificate. To add the certificate to the database, see L<"insert">. - -Note that this stores the hash reference, not a distinct copy of the hash it -points to. You can ask the object for a copy with the I<hash> method. - -=cut - -# the new method can be inherited from FS::Record, if a table method is defined - -sub table { 'svc_cert'; } - -sub table_info { - my %dis = ( disable_default=>1, disable_fixed=>1, disable_inventory=>1, disable_select=>1 ); - { - 'name' => 'Certificate', - 'name_plural' => 'Certificates', - 'longname_plural' => 'Example services', #optional - 'sorts' => 'svcnum', # optional sort field (or arrayref of sort fields, main first) - 'display_weight' => 25, - 'cancel_weight' => 65, - 'fields' => { - #'recnum' => '', - 'privatekey' => { label=>'Private key', %dis, }, - 'csr' => { label=>'Certificate signing request', %dis, }, - 'certificate' => { label=>'Certificate', %dis, }, - 'cacert' => { label=>'Certificate authority chain', %dis, }, - 'common_name' => { label=>'Common name', %dis, }, - 'organization' => { label=>'Organization', %dis, }, - 'organization_unit' => { label=>'Organization Unit', %dis, }, - 'city' => { label=>'City', %dis, }, - 'state' => { label=>'State', %dis, }, - 'country' => { label=>'Country', %dis, }, - 'cert_contact' => { label=>'Contact email', %dis, }, - - #'another_field' => { - # 'label' => 'Description', - # 'def_label' => 'Description for service definitions', - # 'type' => 'text', - # 'disable_default' => 1, #disable switches - # 'disable_fixed' => 1, # - # 'disable_inventory' => 1, # - # }, - #'foreign_key' => { - # 'label' => 'Description', - # 'def_label' => 'Description for service defs', - # 'type' => 'select', - # 'select_table' => 'foreign_table', - # 'select_key' => 'key_field_in_table', - # 'select_label' => 'label_field_in_table', - # }, - - }, - }; -} - -=item label - -Returns a meaningful identifier for this example - -=cut - -sub label { - my $self = shift; -# $self->label_field; #or something more complicated if necessary - # check privatekey, check->privatekey, more? - return 'Certificate'; -} - -=item insert - -Adds this record to the database. If there is an error, returns the error, -otherwise returns false. - -=cut - -# the insert method can be inherited from FS::Record - -=item delete - -Delete this record from the database. - -=cut - -# the delete method can be inherited from FS::Record - -=item replace OLD_RECORD - -Replaces the OLD_RECORD with this one in the database. If there is an error, -returns the error, otherwise returns false. - -=cut - -# the replace method can be inherited from FS::Record - -=item check - -Checks all fields to make sure this is a valid certificate. If there is -an error, returns the error, otherwise returns false. Called by the insert -and replace methods. - -=cut - -# the check method should currently be supplied - FS::Record contains some -# data checking routines - -sub check { - my $self = shift; - - my $error = - $self->ut_numbern('svcnum') - || $self->ut_numbern('recnum') - || $self->ut_anything('privatekey') #XXX - || $self->ut_anything('csr') #XXX - || $self->ut_anything('certificate')#XXX - || $self->ut_anything('cacert') #XXX - || $self->ut_textn('common_name') - || $self->ut_textn('organization') - || $self->ut_textn('organization_unit') - || $self->ut_textn('city') - || $self->ut_textn('state') - || $self->ut_textn('country') #XXX char(2) or NULL - || $self->ut_textn('cert_contact') - ; - return $error if $error; - - $self->SUPER::check; -} - -=item generate_privatekey [ KEYSIZE ] - -=cut - -use IPC::Run qw( run ); -use File::Temp; - -sub generate_privatekey { - my $self = shift; - my $keysize = (@_ && $_[0]) ? shift : 2048; - run( [qw( openssl genrsa ), $keysize], '>pipe'=>\*OUT, '2>'=>'/dev/null' ) - or die "error running openssl: $!"; - #XXX error checking - my $privatekey = join('', <OUT>); - $self->privatekey($privatekey); -} - -=item check_privatekey - -=cut - -sub check_privatekey { - my $self = shift; - my $in = $self->privatekey; - run( [qw( openssl rsa -check -noout)], '<'=>\$in, '>pipe'=>\*OUT, '2>'=>'/dev/null' ) - ;# or die "error running openssl: $!"; - - my $ok = <OUT>; - return ($ok =~ /key ok/); -} - -tie my %subj, 'Tie::IxHash', - 'CN' => 'common_name', - 'O' => 'organization', - 'OU' => 'organization_unit', - 'L' => 'city', - 'ST' => 'state', - 'C' => 'country', -; - -sub subj_col { - \%subj; -} - -sub subj { - my $self = shift; - - '/'. join('/', map { my $v = $self->get($subj{$_}); - $v =~ s/([=\/])/\\$1/; - "$_=$v"; - } - keys %subj - ); -} - -sub _file { - my $self = shift; - my $field = shift; - my $dir = $FS::UID::conf_dir. "/cache.". $FS::UID::datasrc; #XXX actual cache dir - my $fh = new File::Temp( - TEMPLATE => 'cert.'. '.XXXXXXXX', - DIR => $dir, - ) or die "can't open temp file: $!\n"; - print $fh $self->$field; - close $fh; - $fh; -} - -sub generate_csr { - my $self = shift; - - my $fh = $self->_file('privatekey'); - - run( [qw( openssl req -new -key ), $fh->filename, '-subj', $self->subj ], - '>pipe'=>\*OUT, '2>'=>'/dev/null' - ) - or die "error running openssl: $!"; - #XXX error checking - my $csr = join('', <OUT>); - $self->csr($csr); -} - -sub check_csr { - my $self = shift; - - my $in = $self->csr; - - run( [qw( openssl req -subject -noout ), ], - '<'=>\$in, - '>pipe'=>\*OUT, '2>'=>'/dev/null' - ) - ;#or die "error running openssl: $!"; - - #subject=/CN=cn.example.com/ST=AK/O=Tofuy/OU=Soybean dept./C=US/L=Tofutown - my $line = <OUT>; - $line =~ /^subject=\/(.*)$/ or return (); - my $subj = $1; - - map { if ( /^\s*(\w+)=\s*(.*)\s*$/ ) { - ($1=>$2); - } else { - (); - } - } - split('/', $subj); -} - -sub generate_selfsigned { - my $self = shift; - - my $days = 730; - - my $key = $self->_file('privatekey'); - my $csr = $self->_file('csr'); - - run( [qw( openssl req -x509 -nodes ), - '-days' => $days, - '-key' => $key->filename, - '-in' => $csr->filename, - ], - '>pipe'=>\*OUT, '2>'=>'/dev/null' - ) - or die "error running openssl: $!"; - #XXX error checking - my $certificate = join('', <OUT>); - $self->certificate($certificate); -} - -#openssl x509 -in cert -noout -subject -issuer -dates -serial -#subject= /CN=cn.example.com/ST=AK/O=Tofuy/OU=Soybean dept./C=US/L=Tofutown -#issuer= /CN=cn.example.com/ST=AK/O=Tofuy/OU=Soybean dept./C=US/L=Tofutown -#notBefore=Nov 7 05:07:42 2010 GMT -#notAfter=Nov 6 05:07:42 2012 GMT -#serial=B1DBF1A799EF207B - -sub check_certificate { shift->check_x509('certificate'); } -sub check_cacert { shift->check_x509('cacert'); } - -sub check_x509 { - my( $self, $field ) = ( shift, shift ); - - my $in = $self->$field; - run( [qw( openssl x509 -noout -subject -issuer -dates -serial )], - '<'=>\$in, - '>pipe'=>\*OUT, '2>'=>'/dev/null' - ) - or die "error running openssl: $!"; - #XXX error checking - - my %hash = (); - while (<OUT>) { - /^\s*(\w+)=\s*(.*)\s*$/ or next; - $hash{$1} = $2; - } - - for my $f (qw( subject issuer )) { - - $hash{$f} = { map { if ( /^\s*(\w+)=\s*(.*)\s*$/ ) { - ($1=>$2); - } else { - (); - } - } - split('/', $hash{$f}) - }; - - } - - $hash{'selfsigned'} = 1 if $hash{'subject'}->{'O'} eq $hash{'issuer'}->{'O'}; - - %hash; -} - -=back - -=head1 BUGS - -=head1 SEE ALSO - -L<FS::Record>, schema.html from the base documentation. - -=cut - -1; - |