#!/usr/bin/perl # # --- BEGIN COPYRIGHT BLOCK --- # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; # version 2.1 of the License. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, # Boston, MA 02110-1301 USA # # Copyright (C) 2007 Red Hat, Inc. # All rights reserved. # --- END COPYRIGHT BLOCK --- # package PKI::TPS::Modutil; sub new { my $class = shift; my ($dir) = @_; if (! $dir) { die "no module directory provided\n"; } my $self = {}; $self->{dir} = $dir; $self->{modules} = makemodules($self); bless $self, $class; return $self; } sub exists { my $self = shift; return -e "$self->{dir}/secmod.db"; } sub create { my $self = shift; my $mods = `modutil -force -dbdir '$self->{dir}' -nocertdb -create`; return $mods; } use Data::Dumper; sub makemodules { my $self = shift; my $modules = {}; my $mods = `modutil -force -dbdir '$self->{dir}' -nocertdb -list`; #my $mods = join "",<::DATA>; #print "raw mods = $mods"; my (@modules) = ( $mods =~ / ^ #beginning of a line \s+ #some spaces \d+\.\s* #some digits (.*?) #lots of text ((?=^\s*\d+)|(?=------)) #if we would next match some spaces and digits /msxg ); @modules = grep /.+/ms, @modules; foreach $module (@modules) { #print "Module #$i:$module --\n"; $module = "modulename:$module"; my ($moduleheader, $rest) = ( $module =~ / (.*status: .*?\n) # moduleheader (\s*slot:.*) # slot (?=\n(\n|$)) #empty line /msxg ); #print "moduleheader: $moduleheader\n"; my $m = makehash($moduleheader); $modules->{$m->{modulename}} = $m; $m->{tokens} = {}; my @tokens = split "\n\n", $rest; # get summary slot info with: -list foreach my $token (@tokens) { #print "slottext: $slot\n"; my $slh = makehash($token); $m->{tokens}->{$slh->{token}} = $slh; } # get detailed slot info with: -list "modulename" my $moduledetail = `modutil -force -dbdir '$self->{dir}' -nocertdb -list "$m->{modulename}" 2> /dev/null`; my @details= split "\n\n", $moduledetail; while ($details[0] !~ /.*Name:.*/) { shift @details; }; $m->{detail} = makehash(shift @details); foreach $d (@details) { my $sdh = makehash($d); my $tokenname = $sdh->{"Token Name"}; $tokenname =~ s/\s+$//; # remove trailing spaces if ($tokenname) { $m->{tokens}->{$tokenname}->{detail} = $sdh; } } $i++; } return $modules; } # input: a multi-list string with nv/pairs # return a hashtable reference sub makehash { my $str = shift; my $ht = { }; my @lines = split "\n", $str; my $line; LINE: foreach $line (@lines) { if ($line =~ /Using database directory/) { next LINE; } if ($line =~ /--------------/) { next LINE; } my ($name, $value) = ($line =~ /^\s*(.*?):\s*(.*?)\s*$/); if ($name) { #print "name:$name\n"; #print "value:$value\n"; $ht->{$name} = $value; } } return $ht; } sub getmodules { my $self = shift; #print "modules: ".$self->{modules}. "\n"; #print "keys: ".(join ",",keys %{$self->{modules}})."\n"; return keys %{$self->{modules}}; } sub getmodule { my $self = shift; my $modulename = shift; #print Dumper($self->{modules}); return $self->{modules}->{$modulename}; } sub gettokens { my $self = shift; my $module = shift; return keys %{$module->{tokens}}; } sub gettoken { my $self = shift; my $token= shift; foreach my $m (values %{$self->{modules}}) { foreach $t (values %{$m->{tokens}}) { #print join ",", keys %{$t}; #print Dumper($t->{detail}); if ($t->{detail}->{"Token Name"} eq $token) { return $t; } } } } package main; sub ::test { # initialize my $modutil = new PKI::TPS::Modutil("."); #make database if it doesn't exist if (! $modutil->exists()) { $modutil->create(); } #get an array of module names my @mods = $modutil->getmodules(); print "Found ".@mods." pkcs#11 modules\n"; #for each module... foreach my $modname (@mods) { my $module = $modutil->getmodule($modname); print "Module: $modname\n"; print "Library: ".$module->{detail}->{"Library file"}."\n"; print "Other keys: ".(join ",", keys %{$module->{detail}})."\n"; #find all the tokens in a module, e.g. each partition for a lunasa foreach my $tokenname ($modutil->gettokens($module)) { print " token: $tokenname\n"; my $token = $modutil->gettoken($tokenname); #dump out the information we have on the token foreach my $key (keys %{$token}) { print " token keys/values: $key: ".$token->{$key}."\n"; } my @detailkeys = (keys %{$token->{detail}}) ; print " token detail keys:". (join ",", @detailkeys)."\n"; print " token detail Manufacturer:". $token->{detail}->{Manufacturer}."\n"; print "\n"; } print "\n"; } } # this is where 'main' starts if ($ARGV[0] eq "--test") { ::test(); } 1; __DATA__ Listing of PKCS #11 Modules ----------------------------------------------------------- 1. NSS Internal PKCS #11 Module slots: 2 slots attached status: loaded slot: NSS Internal Cryptographic Services token: NSS Generic Crypto Services slot: NSS User Private Key and Certificate Services token: NSS Certificate DB 2. lunasa library name: /usr/lunasa/lib/libCryptoki2.so slots: 2 slots attached status: loaded slot: LunaNet Slot token: lunasa1-ca slot: LunaNet Slot token: lunasa2-ca -----------------------------------------------------------