Permalink
Browse files

Add gnutls-ca.pl for generating a simple CA chain using certtool

  • Loading branch information...
1 parent 1b3c9b4 commit c08dacb1499202cf0bcb1200429b5eb3e6141750 Daniel De Graaf committed Aug 8, 2010
Showing with 191 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +189 −0 extras/gnutls-ca.pl
View
@@ -6,6 +6,8 @@
/inspircd
/org.inspircd.plist
/run
+/ssl
+/extras/ssl
/include/inspircd_config.h
/include/inspircd_version.h
View
@@ -0,0 +1,189 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+sub gen_key;
+sub gen_ca;
+sub gen_server;
+sub ca_sign;
+sub gen_templates;
+sub key_info;;
+
+mkdir "ssl";
+chdir "ssl" or die $!;
+mkdir "keys" and chmod 0700, "keys";
+mkdir "certs";
+gen_templates;
+
+my $what = shift || '';
+if ($what eq 'sign') {
+ gen_ca;
+ for my $req (@ARGV) {
+ my $out = $req;
+ $out =~ s/request/ca-sign/ or ($out .= '.sign');
+ ca_sign $req, $out;
+ }
+} elsif ($what eq 'server') {
+ gen_ca;
+ gen_server;
+ ca_sign 'server-request.pem', 'server-ca-sign.pem';
+ print <<END;
+SSL certificates have been generated.
+
+It is a good idea to make your SSL certificate match your IRCd's hostname; some
+IRC clients complain about a mismatch here. To do this, edit ssl/server.info
+and rerun this script.
+
+If you just want a simple server certificate, copy ssl/server-key.pem and
+ssl/server-selfsign.pem to conf/key.pem and conf/cert.pem.
+
+If you want a certificate signed by a CA, use ssl/server-key.pem and
+ssl/server-ca-sign.pem. If you have multiple servers, choose one to hold the
+root CA and copy the other server-request.pem files to that system. Then use
+$0 sign <filename> to sign them with the single CA.
+The file ssl/ca.pem can be used by clients to verify your servers.
+END
+} else {
+ print "Use: \n";
+ print " $0 server Generate server certificates for one server\n";
+ print " $0 sign cert Sign another server's request with the local CA\n";
+ exit (@ARGV != 0);
+}
+
+sub gen_key {
+ my $key = shift;
+ return if -e $key;
+ print "[\e[32m*\e[0m] Generating private key $key\n";
+
+ system "certtool --generate-privkey --outfile keys/tmp.pem 2>>log" and die;
+ my $fp;
+ open my $info, '-|', 'certtool --key-info < keys/tmp.pem' or die;
+ while (<$info>) {
+ m#Public Key ID: ([0-9A-F:]+)# and $fp = $1;
+ }
+ $fp or die "Cannot read key ID of the key we just made";
+ $fp =~ s/://g;
+ $fp = lc $fp;
+ rename 'keys/tmp.pem', "keys/$fp.pem";
+ unlink $key;
+ symlink "keys/$fp.pem", $key;
+}
+
+sub gen_ca {
+ gen_key 'ca-key.pem';
+ my @ca = stat 'ca.pem';
+ my @ca_t = stat 'ca.info';
+ if (!@ca || $ca[9] < $ca_t[9]) {
+ print "[\e[32m*\e[0m] Creating certificate authority (ca.pem)\n";
+ system "certtool --generate-self-signed --template ca.info --load-privkey ca-key.pem --outfile tmp.pem 2>>log" and die;
+ my($fn, $certfp, $keyfp) = key_info;
+
+ unlink "ca.pem";
+ symlink $fn, "ca.pem";
+ @ca = stat 'ca.pem';
+ }
+}
+
+sub gen_server {
+ gen_key 'server-key.pem';
+
+ my @server_t = stat 'server.info';
+ my @server_req = stat 'server-request.pem';
+ my @server_ss = stat 'server-selfsign.pem';
+
+ if (!@server_req || $server_req[9] < $server_t[9]) {
+ print "[\e[32m*\e[0m] Creating server certificate request (server-request.pem)\n";
+ system "certtool --generate-request --template server.info --load-privkey server-key.pem --outfile server-request.pem 2>>log" and die;
+ @server_req = stat 'server-request.pem';
+ }
+
+ if (!@server_ss || $server_ss[9] < $server_t[9]) {
+ print "[\e[32m*\e[0m] Creating self-signed server certificate (server-selfsign.pem)\n";
+ system "certtool --generate-self-signed --template server.info --load-privkey server-key.pem --outfile tmp.pem 2>>log" and die;
+ my($fn, $certfp, $keyfp) = key_info;
+
+ unlink "server-selfsign.pem";
+ symlink $fn, "server-selfsign.pem";
+ }
+}
+
+sub ca_sign {
+ my($in, $out) = @_;
+ my @ca = stat 'ca.pem';
+ my @server_req = stat $in;
+ my @server_cs = stat $out;
+ if (!@server_cs || $server_cs[9] < $server_req[9] || $server_cs[9] < $ca[9]) {
+ print "[\e[32m*\e[0m] Signing $in with ca.pem ($out)\n";
+ system "certtool --generate-certificate --load-request '$in' --load-ca-certificate ca.pem --load-ca-privkey ca-key.pem --template ca-signing.info --outfile tmp.pem 2>>log" and die;
+ my($fn, $certfp, $keyfp) = key_info;
+
+ system "cat ca.pem $fn > certs/$certfp-full.pem";
+ unlink $out;
+ symlink "certs/$certfp-full.pem", $out;
+ }
+}
+
+sub gen_templates {
+ if (!-e 'server.info') {
+ open F, '>', 'server.info';
+ print F <<EOF;
+# X.509 Certificate options
+
+# CN (common name) - the name of your server. You want to set this.
+#cn = "irc.example.com"
+
+# How many days, counting from today, will certificate be valid?
+# Default is 1 year
+#expiration_days = 1000
+
+#You can also set other fields, see certtool documentation for the rest
+EOF
+ close F;
+ }
+ if (!-e 'ca.info') {
+ open F, '>', 'ca.info';
+ print F <<EOF;
+# X.509 Certificate options
+# This is for a Certificate Authority
+ca
+
+# CN (common name) - the name of your root.
+# While not strictly required, your IRC network is good to put here
+#cn = "irc.example.com"
+
+# How many days, counting from today, will certificate be valid?
+# Default is 1 year
+#expiration_days = 1000
+
+#You can also set other fields, see certtool documentation for the rest
+EOF
+ close F;
+ }
+ if (!-e 'ca-signing.info') {
+ open F, '>', 'ca-signing.info';
+ print F <<EOF;
+# X.509 Certificate options
+# This is for certificate requests being signed by the CA.
+# Blank to accept all fields from the request.
+EOF
+ close F;
+ }
+}
+
+sub key_info {
+ my($certfp, $keyfp);
+ open my $info, '-|', 'certtool --certificate-info < tmp.pem' or die;
+ while (<$info>) {
+ if (m#SHA-1 fingerprint:#) {
+ $certfp = <$info>;
+ } elsif (m#Public Key Id:#) {
+ $keyfp = <$info>;
+ }
+ }
+ chomp($certfp, $keyfp);
+ $certfp =~ s/^\t+//;
+ $keyfp =~ s/^\t+//;
+ my $fn = "certs/$certfp.pem";
+ rename 'tmp.pem', $fn;
+ return($fn, $certfp, $keyfp);
+}

0 comments on commit c08dacb

Please sign in to comment.