From 7bf018748f8fb2fa3eeb78ca5879fd8c7b6ba70a Mon Sep 17 00:00:00 2001 From: kyoshiro Date: Fri, 2 Feb 2007 22:45:51 +0000 Subject: [PATCH] bip configuration+make cert script (perl) --- scripts/genconfig | 688 ++++++++++++++++++++++++++++++++++++++++++ scripts/make_cert.cnf | 17 -- scripts/make_cert.sh | 8 - 3 files changed, 688 insertions(+), 25 deletions(-) create mode 100755 scripts/genconfig delete mode 100644 scripts/make_cert.cnf delete mode 100755 scripts/make_cert.sh diff --git a/scripts/genconfig b/scripts/genconfig new file mode 100755 index 0000000..e0d366d --- /dev/null +++ b/scripts/genconfig @@ -0,0 +1,688 @@ +#!/usr/bin/env perl + +use strict; +#use serialize; +use IO::File; +use POSIX; +use Data::Dumper; + +my $CFILE = $ENV{'HOME'} . '/.bip/bip.conf.autogen'; +my $CONFIG = ".config"; +my %cf; +my $global_done = 0; +my $cert_done = 0; +my $mode = 'normal'; +# maximum level of blocks { { { } } } +my $maxlevel = 5; +my $bipmkpw; +my $tmpcrt = "/tmp/bip-cert.cnf"; +my $certout = $ENV{'HOME'} . '/.bip/bip.pem.autogen'; +my %optdesc = ( + 'global' => { + 'ip' => { 'type' => 's', 'adv' => 1, 'default' => '0.0.0.0', + 'optional' => 1, + 'desc' => 'What IP address/hostname do you want bip to listen on ?' }, + 'port' => { 'type' => 'i', 'adv' => 1, 'default' => '7778', + 'optional' => 1, + 'desc' => 'What port do you want bip to listen on ?' }, + 'client_side_ssl' => { 'type' => 'b', 'adv' => 1, 'default' => 'true', + 'optional' => 1, + 'desc' => 'Do you want to enable client side SSL ?' }, + 'pid_file' => { 'type' => 's', 'adv' => 1, 'optional' => 1, + 'default' => $ENV{'HOME'} . '/.bip/bip.pid', + 'desc' => 'Where do you want the pidfile to be stored ?' }, + 'log' => { 'type' => 'b', 'adv' => 0, 'default' => 'true', + 'optional' => 1, + 'desc' => 'Do you want to enable the logging system ?' }, + 'log_sync_interval' => { 'type' => 'i', 'adv' => 1, + 'optional' => 1, + 'default' => '5', 'depends' => 'log', 'depval' => 'true', + 'desc' => 'At which interval do you want bip to force logs to be written {seconds} ?' }, + 'log_level' => { 'type' => 'i', 'adv' => 1, 'default' => '3', + 'optional' => 1, + 'depends' => 'log', 'depval' => 'true', + 'desc' => 'Define bip\'s system logs verbosity level {less 0 - 7 tremendous}:' }, + 'log_root' => { 'type' => 's', 'adv' => 0, + 'optional' => 1, + 'default' => $ENV{'HOME'} . '/.bip/logs', + 'depends' => 'log', 'depval' => 'true', + 'desc' => 'In which directory do you want logs to be stored ?' }, + 'log_format' => { 'type' => 's', 'adv' => 1, 'default' => '%n/%Y-%m/%c.%d.log', + 'optional' => 1, + 'depends' => 'log', 'depval' => 'true', + 'desc' => 'Define the channel/private log format {see strftime, limited}:' }, + 'backlog' => { 'type' => 'b', 'adv' => 0, 'default' => 'true', + 'optional' => 1, + 'depends' => 'log', 'depval' => 'true', + 'desc' => 'Do you want to activate backlog {play back logs} system ?' }, + 'backlog_lines' => { 'type' => 'i', 'adv' => 0, 'default' => '10', + 'optional' => 1, + 'depends' => 'backlog', 'depval' => 'true', + 'desc' => 'How much line do you want bip to play back upon client connect' . + "\n {0 => replay everything since backlog's last reset} ?" }, + 'backlog_no_timestamp' => { 'type' => 'b', 'adv' => 0, + 'optional' => 1, + 'default' => 'false', 'depends' => 'backlog', 'depval' => 'true', + 'desc' => 'Disable timestamp in backlog ?' }, + 'bl_msg_only' => { 'type' => 'b', 'adv' => 0, + 'optional' => 1, + 'default' => 'false', 'depends' => 'backlog', 'depval' => 'true', + 'desc' => 'Only playback users messages {chan/priv}, no nick/join/... ?' }, + 'always_backlog' => { 'type' => 'b', 'adv' => 0, + 'optional' => 1, + 'default' => 'false', 'depends' => 'backlog', 'depval' => 'true', + 'desc' => 'Always backlog {false means backlog pointers are reset after each backlog} ?' }, + 'blreset_on_talk' => { 'type' => 'b', 'adv' => 0, + 'optional' => 1, + 'default' => 'false', 'depends' => 'backlog', 'depval' => 'true', + 'desc' => 'Reset backlog when an attached client sends is talking ?' }, + }, + + 'network' => { + 'name' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 0, + 'desc' => 'Network\'s name' }, + 'ssl' => { 'type' => 'b', 'adv' => 0, 'default' => '', + 'optional' => 1, + 'desc' => 'Enable SSL for this network ?' }, + 'server' => { 'type' => 'e' }, + }, + + 'user' => { + 'name' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 0, + 'desc' => 'User\'s internal name ?' }, + 'password' => { 'type' => 'p', 'adv' => 0, 'default' => '', + 'optional' => 0, + 'desc' => 'Set a password for his bip account:' }, + 'ssl_check_mode' => { 'type' => 's', 'adv' => 1, + 'optional' => 1, 'default' => 'none', + 'desc' => 'Type of SSL servers certificate\'s checks' }, + 'ssl_check_store' => { 'type' => 's', 'adv' => 1, + 'optional' => 1, 'default' => '', + 'desc' => 'Path to SSL servers\'s data storage' }, + 'default_nick' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 0, + 'desc' => 'User\'s default IRC nickname' }, + 'default_user' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 0, + 'desc' => 'User\'s default IRC username' }, + 'default_realname' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 0, + 'desc' => 'User\'s default IRC realname' }, + 'connection' => { 'type' => 'e' }, + }, + + 'connection' => { + 'name' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 0, + 'desc' => 'Connection name (used by bip only)' }, + 'network' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 0, 'postdepends' => 'networks.$value', + 'desc' => 'Network to connect to' }, + 'nick' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 1, + 'desc' => 'IRC nickname on this connection ?' }, + 'user' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 1, + 'desc' => 'IRC username on this connection ?' }, + 'realname' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 1, + 'desc' => 'IRC realname on this connection ?' }, + 'password' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 1, + 'desc' => 'IRC server\'s password ?' }, + 'vhost' => { 'type' => 's', 'adv' => 1, 'default' => '', + 'optional' => 1, + 'desc' => 'Connect to IRC server from this specific IP address:' }, + 'source_port' => { 'type' => 'i', 'adv' => 0, 'default' => '', + 'optional' => 1, + 'desc' => 'Connect to IRC server from this specific port:' }, + 'follow_nick' => { 'type' => 'b', 'adv' => 0, 'default' => 'true', + 'optional' => 1, + 'desc' => 'Follow (and store) nicknames changes from clients to use upon reconnection (if false, bip\'ll use config nickname)' }, + 'ignore_first_nick' => { 'type' => 'b', 'adv' => 0, 'default' => 'true', + 'optional' => 1, + 'desc' => 'Ignore nickname change sent by a client (first one only, upon client attach)' }, + 'away_nick' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 1, + 'desc' => 'Set nickname to this value when there\'s no more client attached:' }, + 'no_client_away_msg' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 1, + 'desc' => 'Set this away message when there\'s no more client attached:' }, + 'on_connect_send' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 1, + 'desc' => 'Send this raw message upon connection to IRC server' }, + 'channel' => { 'type' => 'e' }, + }, + + 'channel' => { + 'name' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 0, + 'desc' => 'Channel name' }, + 'key' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 1, + 'desc' => 'Channel key (optional)' }, + }, + + 'server' => { + 'host' => { 'type' => 's', 'adv' => 0, 'default' => '', + 'optional' => 0, + 'desc' => 'IRC server\'s IP address/hostname' }, + 'port' => { 'type' => 'i', 'adv' => 0, 'default' => '6667', + 'optional' => 0, + 'desc' => 'IRC server\'s port' }, + } +); +my %optorder = ( + 'global' => [ + 'ip' , + 'port' , + 'client_side_ssl' , + 'pid_file' , + 'log' , + 'log_sync_interval' , + 'log_level' , + 'log_root' , + 'log_format' , + 'backlog' , + 'backlog_lines' , + 'backlog_no_timestamp' , + 'bl_msg_only' , + 'always_backlog' , + 'blreset_on_talk' , + ], + + 'network' => [ + 'name' , + 'ssl' , + 'server' , + ], + + 'user' => [ + 'name' , + 'password' , + 'ssl_check_mode' , + 'ssl_check_store' , + 'default_nick' , + 'default_user' , + 'default_realname' , + 'connection' , + ], + + 'connection' => [ + 'name' , + 'network' , + 'nick' , + 'user' , + 'realname' , + 'password' , + 'vhost' , + 'source_port' , + 'follow_nick' , + 'ignore_first_nick' , + 'away_nick' , + 'no_client_away_msg' , + 'on_connect_send' , + 'channel' , + ], + + 'channel' => [ + 'name' , + 'key' , + ], + + 'server' => [ + 'host' , + 'port' , + ] +); + +my $clear_string = `clear`; + +sub myexit { + warn("Error: $1"); + warn("Saving configuration..."); + save_config(); + warn("Don't worry, your configuration has been saved ;)"); + exit(1); +} + +sub askOpt { + my ($e, $curval) = @_; + my ($o, $sel); + + $sel = (($curval ne undef) ? $curval : $e->{'default'}); + return $sel if ($mode eq 'normal' && $e->{'adv'} eq 1); + + while (1) { + if ($e->{'type'} eq 'b') { + $o = askbool($e->{'desc'}, $sel); + } else { + $o = askval($e->{'desc'}, $sel); + } + if ($o eq undef && $e->{'optional'} eq 0) { + print("This value is mandatory, please enter a value\n"); + next; + } + if ($e->{'type'} eq 'i' && $o !~ /^\d*$/) { + print("We want a number here, please enter one\n"); + next; + } + last; + } + return $o; +} + +sub askbool { + my ($text, $default) = @_; + + if ($default eq "true") { + print "$text [Y/n] "; + } else { + $default = "false"; + print "$text [y/N] "; + } + + while (my $l = ) { + chomp($l); + if ($default eq "true" && $l =~ /^n$/i) { + return "false"; + } elsif ($default eq "false" && $l =~ /^y$/i) { + return "true"; + } elsif (!$default && $l eq '') { + return undef; + } else { + return $default; + } + } +} + +sub askPass { + my ($text) = @_; + + while (!$bipmkpw && ! -x $bipmkpw) { + if ($bipmkpw ne '' && ! -x $bipmkpw) { + print("No exec permission: $bipmkpw\n"); + } + $bipmkpw = askval("Please enter the full path to bipmkpw binary :"); + } + print("$text ? "); + my $pass = `$bipmkpw`; + chomp($pass); + $pass =~ s/^Password:\s*\n?//si; + chomp($pass); + return $pass; +} + +sub askval { + my ($text, $default, $skipblank) = @_; + + $text .= " "; + $text .= "[$default] " if ($default ne undef); + print($text); + while (my $l = ) { + chomp($l); + if ($default eq undef && !$skipblank && $l eq '') { + my $q = askbool("You've entered a blank value, do you want this field to be unset\n (if not, it'll be set to the empty string) ?", "true"); + return undef if ($q eq 'true'); + } + return ($l ne '' ? $l : $default); + } +} + +sub checkDepends { + my ($n, $v) = @_; + return if (!exists($v->{'depends'})); + + my $d = $v->{'depends'}; + if (!exists($cf{'global'}->{$d})) { + return "You cannot define `$n' since `$d' isn't defined"; + } + if (exists($v->{'depval'}) && + $cf{'global'}->{$d} ne $v->{'depval'}) { + return "You cannot define `$n' since `$d' isn't set to " . + $v->{'depval'}; + } +} + +sub loadConfig { + -e "$CONFIG" || return "There's no saved configuration at the moment"; + my $data; + my $fh = new IO::File; + $fh->open($CONFIG) || return "Unable to open $CONFIG"; + while ($data .= <$fh>) {}; + %cf = unserialize($data) || return "Invalid format in $CONFIG"; + return "Config loaded from $CONFIG"; +} + +sub resetConfig { + my $r = askbool("Do you want to reset current loaded configuration options, networks, users... ?", 'false'); + $r eq 'false' && return "Reset config aborted"; + + %cf = (); + -e "$CONFIG" || return "Configuration cleared"; + my $r = askbool("Do you want to delete saved configuration file $CONFIG too ?", 'false'); + if ($r eq 'true') { + unlink($CONFIG) || return "Unable to remove file $CONFIG, current config has been cleared"; + return "Configuration cleared, saved-configuration file removed"; + } + return "Configuration cleared"; +} + +sub setOptions { + foreach my $n (@{$optorder{'global'}}) { + my $e = $optdesc{'global'}->{$n}; + my $r = checkDepends($n, $e); + if ($r) { + print("$r\n"); + $cf{'global'}->{$n} = undef; + next; + } + $cf{'global'}->{$n} = askOpt($e, $cf{'global'}->{$n}); + } + $global_done = 1; + pause(); + return "Options have been set"; +} + +sub printOptions { + my $cnt = 1; + foreach my $n (@{$optorder{'global'}}) { + my $e = $optdesc{'global'}->{$n}; + my $r = checkDepends($n, $e); + if ($r) { + printf('%02d.(%s - unset, missing dependency)'."\n", $cnt, $n); + } elsif (exists($cf{'global'}->{$n})) { + printf('%02d. %s = %s'."\n", $cnt, $n, $cf{'global'}->{$n}); + } else { + printf('%02d. %s - unset'."\n", $cnt, $n); + } + $cnt++; + } + pause(); + return; +} + +sub makeCert { + my ($fh, $c, $o, $ou, $cn); + $fh = new IO::File; + $c = askval("SSL cert country :"); + $o = askval("SSL cert organisation :", "Sexy boys"); + $ou = askval("SSL cert organisational unit :", "Bip"); + $cn = askval("SSL cert common name :", "Bip"); + + $fh->open("> $tmpcrt"); + return "Unable to write to $tmpcrt\n" if (!$fh); + print $fh "HOME = . + +[ req ] +distinguished_name = dn +x509_extensions = v3_bip +default_md = sha1 +prompt = no + +[ dn ] +C=$c +O=$o +OU=$ou +CN=$cn + +[ v3_bip ] +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid:always"; + +# if (-e $certout) { +# my @t = localtime(time); +# my $ts = sprintf("%04d-%02d-%02d.%02d:%02d:%02d", 1900+$t[5], 1+$t[4], $t[3], $t[2], $t[1], $t[0]); +# rename($certout, "$certout.$ts"); +# print "Existing $certout found, renamed to $certout.$ts\n"; +# } + + `openssl req -new -x509 -days 365 -nodes -config "$tmpcrt" -out "$certout" -keyout "$certout"`; + # TODO check command status + `openssl x509 -subject -dates -fingerprint -noout -in "$certout"`; + # TODO check command status + $cert_done = 1; + print "Certificate/key pair has been generated in $certout\n"; + unlink("$tmpcrt"); + pause(); + return "Certificate/key pair has been generated in $certout"; +} + +sub writeConfig { + my ($f) = @_; + my ($fh, $ts); + + $ts = POSIX::strftime('%a, %d %b %Y %H:%M:%S %z', localtime(time)); + $fh = new IO::File; + $fh->open('> ' . $f) || return "Unable to open $f for writing"; + print $fh "# vim:ft=bip:ts=2\n"; + print $fh "# Auto-generated BIP IRC Proxy configuration $ts \n"; + print $fh "#\n"; + print $fh "### Global options\n"; + foreach my $k (keys(%{$cf{'global'}})) { + next if ($cf{'global'}->{$k} eq undef); + my $t = $optdesc{'global'}->{$k}->{'type'}; + if ($t eq 's' || $t eq 'b') { + print $fh "$k = \"" . $cf{'global'}->{$k} . "\";\n"; + } else { + print $fh "$k = " . $cf{'global'}->{$k} . ";\n"; + } + } + print $fh "\n"; + print $fh "### Networks\n"; + foreach my $e (@{$cf{'networks'}}) { + my $out = printBlock("", 'network', $e, 1); + print $fh $out; + } + print $fh "\n"; + print $fh "### Users\n"; + foreach my $e (@{$cf{'users'}}) { + my $out = printBlock("", 'user', $e, 1); + print $fh $out; + } + print $fh "\n"; + $fh->close; + print("Configuration saved in $f\n"); + return; +} + +sub printBlock { + my ($prefix, $name, $e, $level) = @_; + my $out = ''; + + fatal("Too much recursion levels ($level)") if ($level ge $maxlevel); + + $out .= $prefix . $name . " {\n"; + foreach my $k (keys(%{$e})) { + next if ($e->{$k} eq undef); + my $t = $optdesc{$k}->{'type'}; + if ($t eq 's' || $t eq 'b') { + $out .= $prefix . "\t$k = \"" . $e->{$k} . "\";\n"; + } elsif (ref($e->{$k}) eq 'ARRAY') { + foreach my $e2 (@{$e->{$k}}) { + $out .= printBlock($prefix . "\t", $k, $e2, $level+1); + } + } else { + $out .= $prefix . "\t$k = " . $e->{$k} . ";\n"; + } + } + $out .= $prefix . "}\n\n"; + return $out; +} + +sub addEntry { + my ($section, $nopause) = @_; + my ($e, $opts); + + $opts = $optdesc{$section}; + + foreach my $n (@{$optorder{$section}}) { + my $v = $optdesc{$section}->{$n}; + my $r = checkDepends($n, $v); + if ($r) { + $e->{$n} = undef; + print("$r\n"); + next; + } + if ($v->{'type'} eq 'e') { + my $first = 1; + do { + if ($v->{'optional'} eq 1 || !$first) { + my $a = askbool("Do you want to add a new $n ?", 'true'); + last if ($a eq 'false'); + } + print("\nAdding a new $n :\n"); + my $e2 = addEntry($n, 1); + if (ref($e->{$n}) eq 'ARRAY') { + push(@{$e->{$n}}, $e2); + } else { + $e->{$n} = [ $e2 ]; + } + $first = 0; + } while (1); + } elsif ($v->{'type'} eq 'p') { + $e->{$n} = askPass($v->{'desc'}); + } else { + $e->{$n} = askOpt($v); + } + } + pause() if (!$nopause); + return $e; +} + +sub pause { + my ($txt) = @_; + + $txt = "Press any key to continue" if (!$txt); + print("\n" . $txt . "\n"); + ; +} + +sub printMenu { + my ($mhead, $mopts, $mfoot, $mask) = @_; + + print($clear_string); + print(join("\n", @{$mhead})); + print("\n"); + print("\n"); + foreach my $n (sort {$a <=> $b} keys(%{$mopts})) { + if ($mopts->{$n} eq undef) { + print("\n"); + next; + } + printf(' %2d. %s%s', $n, $mopts->{$n}, "\n"); + } + print("\n"); + print(join("\n", @{$mfoot})); + print("\n"); + print("\n"); + return askval($mask, undef, 1); +} + +sub main_menu { + my ($txt) = @_; + my ($act, $out, $warn, $mopts, $mhead, $mfoot); + my ($mhead, $mask); + + $mopts = { + 1 => 'Set global options', + 2 => 'Add a new network', + 3 => 'Add a new user', + 4 => 'View/Edit/Unset global options', + 5 => 'View/Edit/Delete networks (todo)', + 6 => 'View/Edit/Delete users (todo)', + 7 => 'Generate a server certificate/key pair', + 8 => 'Load saved config (todo)', + 9 => 'Parse and load current config (todo)', + 10 => 'Reset config options', + 11 => 'Switch to ' . invMode($mode) . ' mode', + 12 => undef, + 90 => 'Save and exit', + 91 => 'Debug (will be exit)', + }; + if ($mode eq 'normal') { + $warn = "# WARNING: non-advanced mode, some 'expert' options'll be hidden !"; + } else { + $warn = "# "; + } + $mhead = [ + "########################################################################", + "# Welcome to bip configuration program.", + "# This script will help you build a configuration file", + "# ", + $warn, + "# Please note this script not finalized, and that you'll only be able to", + "# generate a config at once, no modifications will be possible without", + "# resetting all config options. Feature is coming soon !", + "# ", + ]; + $mfoot = [ $txt ]; + $mask = "What do you want to do ?"; + + $act = printMenu($mhead, $mopts, $mfoot, $mask); + print($clear_string); + if ($act eq 8) { + $out = loadConfig(); + } elsif ($act eq 10) { + $out = resetConfig(); + } elsif ($act eq 4) { + $out = printOptions(); + } elsif ($act eq 1) { + $out = setOptions(); + } elsif ($act eq 6) { +# $out = printUsers(); + } elsif ($act eq 3) { + $out = addEntry('user'); + if ($out) { + push(@{$cf{'users'}}, $out); + $out = "New user added"; + } else { + $out = "User add failed"; + } + } elsif ($act eq 5) { +# $out = printNetworks(); + } elsif ($act eq 2) { + $out = addEntry('network'); + if ($out) { + push(@{$cf{'networks'}}, $out); + $out = "New network added"; + } else { + $out = "Network add failed"; + } + } elsif ($act eq 7) { + $out = makeCert(); + } elsif ($act eq 11) { + $mode = invMode(); + $out = "Ok, configuration mode set to $mode"; + } elsif ($act eq 90) { + $out = writeConfig($CFILE); + if (!$out) { + my $u = (exists($cf{'users'}) ? scalar @{$cf{'users'}} + : 0); + my $n = (exists($cf{'networks'}) ? scalar @{$cf{'networks'}} + : 0); + print "You haven't set global options\n" if (!$global_done); + print "$u users defined, $n networks defined\n"; + print "The certificate/key pair is in $certout\n" + if ($cert_done eq 1); + print "Configuration has been generated in $CFILE\n"; + print "You have to rename all generated files to use them\n"; + exit(0); + } + } elsif ($act eq 91) { + print Dumper(\%cf); + pause(); +# exit(0); + } + main_menu($out); +} + +sub invMode { + return ($mode eq 'advanced' ? 'normal' : 'advanced'); +} + +main_menu(); +#sets config backlog +#different user/nick/real ? diff --git a/scripts/make_cert.cnf b/scripts/make_cert.cnf deleted file mode 100644 index 21d2b5a..0000000 --- a/scripts/make_cert.cnf +++ /dev/null @@ -1,17 +0,0 @@ -HOME = . - -[ req ] -distinguished_name = dn -x509_extensions = v3_bip -default_md = sha1 -prompt = no - -[ dn ] -C=FR -O=Sexy boys -OU=Bip -CN=Bip - -[ v3_bip ] -subjectKeyIdentifier=hash -authorityKeyIdentifier=keyid:always diff --git a/scripts/make_cert.sh b/scripts/make_cert.sh deleted file mode 100755 index 8e368fe..0000000 --- a/scripts/make_cert.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/sh - -openssl req -new -x509 -days 365 -nodes \ - -config make_cert.cnf -out bip.pem -keyout bip.pem -#RANDOM_FILE=/dev/urandom -#openssl gendh -rand $(RANDOM_FILE) 512 >> bip.pem -#openssl gendh 512 >> bip.pem -openssl x509 -subject -dates -fingerprint -noout -in bip.pem