# HG changeset patch # User Heiko Schlittermann # Date 1264544768 -3600 # Node ID 730be7994b86940c70d98235738685c8ed5b8c83 simple functionality now diff -r 000000000000 -r 730be7994b86 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Tue Jan 26 23:26:08 2010 +0100 @@ -0,0 +1,3 @@ +style: glob +var/ +CA/ diff -r 000000000000 -r 730be7994b86 .perltidyrc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.perltidyrc Tue Jan 26 23:26:08 2010 +0100 @@ -0,0 +1,2 @@ +--paren-tightness=2 +--square-bracket-tightness=2 diff -r 000000000000 -r 730be7994b86 bin/ca --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/ca Tue Jan 26 23:26:08 2010 +0100 @@ -0,0 +1,206 @@ +#! /usr/bin/perl +use strict; +use warnings; +use Template; +use IO::File; +use File::Path; +use File::Temp qw(tempdir); +use File::Basename; +use Getopt::Long qw(GetOptionsFromArray); +use Pod::Usage; + +my $CA_CRT = "CA/ca-crt.pem"; +my $CA_KEY = "CA/private/ca-key.pem"; +my $CA_DIR = "./var"; + +my %TEMPLATE = ( + ca => "templates/ca", + req => "templates/req", +); + +my $TMP = tempdir("/tmp/$ENV{USER}.ca.XXXXXX", CLEANUP => 1); + +my $opt_days = undef; # see the templates/ca for a default +my $opt_type = undef; # see the templates/ca for a default +my $opt_policy = "de"; # see the templates/ca for a default +my $opt_outfile = undef; +my $opt_force = undef; + +sub init_ca(); +sub ask_pass($); + +MAIN: { + my $csrfile; + + GetOptions( + "d|days=i" => \$opt_days, + "t|type=s" => \$opt_type, + "p|policy=s" => \$opt_policy, + "o|outfile=s" => \$opt_outfile, + "force" => \$opt_force, + "init" => sub { init_ca(); exit 0; }, + "h|help" => sub { pod2usage(-verbose => 1, -exit => 0) }, + "m|man" => sub { pod2usage(-verbose => 2, -exit => 0) }, + ) or pod2usage; + + pod2usage if @ARGV > 1; + $csrfile = $ARGV[0]; # don't shift, we'll need it later! + + my $csr = new IO::File "$TMP/csr" => "w+" + or die "Can't open +>$TMP/csr: $!\n"; + my $cnf = new IO::File "$TMP/cnf" => "w" + or die "Can't open >$TMP/cnf: $!\n"; + my $crt = new IO::File "$TMP/crt" => "w+" + or die "Can't open +>$TMP/crt: $!\n"; + my $tt2 = new Template or die $Template::ERROR; + + # get a private copy of the request + print { IO::File->new("|openssl req -out $TMP/csr") } <>; + open(STDIN, "process( + $TEMPLATE{ca}, + { + type => $opt_type, + days => $opt_days, + policy => "policy_$opt_policy", + cacrt => $CA_CRT, + cakey => $CA_KEY, + cadir => $CA_DIR, + } => "$TMP/cnf" + ) or die $tt2->error, "\n"; + + system( "openssl ca -config $TMP/cnf -in $TMP/csr -out $TMP/crt" + . " -utf8 \${CA_PASS:+-passin env:CA_PASS}"); + + die "ERR: Cert is zero size\n" if not -s $crt; + + # get the name of the output crt file + my $outfile = $opt_outfile; + if (not defined $outfile and defined($_ = $csrfile)) { + if (/(.*[\W_])(?:req|csr).pem$/) { $outfile = "$1crt.pem" } + elsif (/(.*[\W_])req$/) { $outfile = "$1crt" } + else { $outfile .= ".crt.pem" } + } + + # to be sure not to have an invalid/dangerous file name + fork() or do { + open(STDOUT, ">$outfile") + if defined $outfile + or die "Can't open >$outfile: $!\n"; + exec "openssl x509 -in $TMP/crt"; + die "Can't exec openssl x509: $!\n"; + }; + wait; + exit; +} + +sub verbose($) { + warn $_[0], " \n "; +} + +sub ask_pass($) { + my $prompt = shift; + my @keys = ("x", "y"); + + while (1) { + print $prompt; + my $stty = `stty -g`; + system("stty -echo"); + chomp($keys[0] = IO::File->new("/dev/tty")->getline()); + print "\n"; + system("stty $stty"); + print "please again for verification: "; + system("stty -echo"); + chomp($keys[1] = IO::File->new("/dev/tty")->getline()); + print "\n"; + system("stty $stty"); + return $keys[0] if $keys[0] eq $keys[1]; + print "keys mismatch, again\n"; + } +} + +sub init_ca() { + # initialize the CA directory structure. This should + # correspond to the values found in templates/ca + die "$CA_DIR already exists" if -d $CA_DIR and not $opt_force; + mkpath(map { "$CA_DIR/$_" } qw(newcerts)); + mkpath(map { dirname $_ } $CA_CRT, $CA_KEY); + (new IO::File ">$CA_DIR/index"); + (new IO::File ">$CA_DIR/serial")-> print("01\n"); + + # now + my $tt2 = new Template or die $Template::ERROR; + $tt2->process($TEMPLATE{req}, + { + # not used yet + } => "$TMP/cnf") or die $tt2->error; + + $ENV{CA_PASS} = ask_pass("passphrase for CA key: "); + system("openssl req -config $TMP/cnf -x509 -days 3650 -new -passout env:CA_PASS -keyout $TMP/ca-key.pem -out $TMP/ca-crt.pem") + and exit; + + system("openssl x509 -in $TMP/ca-crt.pem -out $CA_CRT") and exit; + $_ = umask(077); + system("openssl rsa -in $TMP/ca-key.pem -des3 -passin env:CA_PASS -passout env:CA_PASS -out $CA_KEY") and exit; + umask($_); + + +} + +__END__ + +=head1 NAME + + ca - the ultimative CA tool + +=head1 SYNOPSIS + + ca [--force] --init + ca --type=TYPE --days=DAYS [request.pem] + + (not yet: request c=COUNTRY ST=STATE l=LOCATION o=ORGANIZATION OU=ORG-UNIT cn=COMMON-NAME) + +=head1 DESCRIPTION + +This B tool signs the request file. If no file is given, it +expects the request on STDIN + +=head1 OPTIONS + +=over 4 + +=item B<-d>|B<--days> I + +The number of days the certificate should be valid. (default: 365) + +=item B<-h>|B<--help> + +Print the reference help and exit. (default: off) + +=item B<-i>|B<--init> + +Initialize the CA (keys, directories). This may be enforce with +B<--force>. (default: off) + +=item B<-m>|B<--man> + +Open the reference manual and exit. (default: off) + +=item B<-o>|B<--out> I + +The name of the output file. If not set (the default), the output goes +to I if the CSR came from stdin and it goes to a file named +similar to the CSR, if the request came from a file. + +=item B<-t>|B<--type> I + +The (NSCertType) type of the certificate. Should be client or server. +(default: none) + +=back + +=cut +## Please see file perltidy.ERR diff -r 000000000000 -r 730be7994b86 templates/ca --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/ca Tue Jan 26 23:26:08 2010 +0100 @@ -0,0 +1,128 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +#HOME = . +#RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +#oid_section = new_oids + + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +[% IF not cadir %] +[% THROW param "missing ca dir" %] +[% END %] + +dir = [% cadir %] +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +[% IF not cacrt %] +[% THROW param "missing ca crt" %] +[% END %] + +certificate = [% cacrt %] # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL + +[% IF not cakey %] +[% THROW param "missing ca key" %] +[% END %] + +private_key = [% cakey %] # The private key + +RANDFILE = $dir/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +[% DEFAULT days = 365 %] +default_days = [% days %] # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = sha1 # which md to use. +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +[% DEFAULT policy = de %] +policy = [% policy %] + +# For the CA policy +[ policy_de ] +countryName = match +stateOrProvinceName = supplied +organizationName = supplied +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +[% IF type %] +# This is OK for an SSL server. +nsCertType = [% type %] +[% END %] + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +nsCaRevocationUrl = https://ssl.schlittermann.de/ca/ca-crl.pem +nsRevocationUrl = https://ssl.schlittermann.de/ca/crt-crl.pem diff -r 000000000000 -r 730be7994b86 templates/openssl.cnf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/openssl.cnf Tue Jan 26 23:26:08 2010 +0100 @@ -0,0 +1,313 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca' and 'req'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = ./demoCA # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = sha1 # which md to use. +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString. +# utf8only: only UTF8Strings. +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings +# so use this option with caution! +string_mask = nombstr + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = AU +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Some-State + +localityName = Locality Name (eg, city) + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Internet Widgits Pty Ltd + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +#organizationalUnitName_default = + +commonName = Common Name (eg, YOUR name) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer:always + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always,issuer:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer:always + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo diff -r 000000000000 -r 730be7994b86 templates/req --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/templates/req Tue Jan 26 23:26:08 2010 +0100 @@ -0,0 +1,102 @@ +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +#oid_section = new_oids + +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +#attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString. +# utf8only: only UTF8Strings. +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings +# so use this option with caution! +string_mask = nombstr + +# req_extensions = v3_req # The extensions to add to a certificate request + +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = DE +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = Saxony + +localityName = Locality Name (eg, city) +0.organizationName = Organization Name (eg, company) + +organizationalUnitName = Organizational Unit Name (eg, section) + +commonName = Common Name (eg, YOUR name) +commonName_max = 64 + +emailAddress = Email Address +emailAddress_max = 64 + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer:always + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF +