![]() |
|
| Daemon News Ezine | BSD News | BSD Mall | BSD Support Forum | BSD Advocacy | BSD Updates |
FreeBSD IPSEC: Racoon + X.509 Certificatesby Alex C. Jokela (alex@camulus.com)AbstractThis document provides a simple guide to quickly get racoon using X.509 certificates instead of shared keys. CertificatesCreating a Certificate AuthorityFirst and foremost, you will want to download a couple of files from either my own site or from the author of the originals.
If for some reason or another the links end up being dead, copies of my files can be found at the end of this document in Appendix A. Once you have downloaded Makefile and openssl.cnf, you should probably edit openssl.cnf to suit your situation (i.e. changing the organization and contact names). I would also put the two files in their own directory, ssl, for example. After editing openssl.cnf, type at the command line: make init If you are curious as to what exactly make init is doing, here you go: test ! -f serial mkdir crl newcerts private chmod go-rwx private echo '01' > serial touch index openssl req -nodes -config openssl.cnf -days 1825 -x509 -newkey rsa -out ca-cert.pem -outform PEM Creating X.509 CertificatesNow that we have a CA, we make some certificates, one for each end-host that our tunnel will connect. Hint: Instead of hostX, use the hostname of the machine that the certificate will eventually live on.
If you are curious as to what exactly make sign is doing, here you go: openssl ca -batch -config openssl.cnf -in hostX.csr -out hostX.cert Creating TunnelsFor the following, we will be using the fictitious IP addresses of 3.3.3.3 and 4.4.4.4 for the "real world" IPs. For our tunnel-endpoints, we will be using 10.1.1.1 on the 3.3.3.3 machine, and 10.1.2.1 on the 4.4.4.4 machine. On 3.3.3.3 ifconfig gif0 create ifconfig gif0 tunnel 3.3.3.3 4.4.4.4 ifconfig gif0 inet 10.1.1.1 10.1.2.1 The reverse of this will need to be preformed on 4.4.4.4 Setting up RoutingFor this fictitious network, we have one endpoint of the tunnel being, for example, a secondary DNS server. There are no systems behind it, i.e., it is not performing NAT. The other endpoint, however, is performing NAT, and you would like be able to have the systems behind the endpoint be able to securely contact the other endpoint and vise versa. On 4.4.4.4 (our DNS server mentioned above), run the following command: route add -net 172.16 -interface gif0 assuming you use that network prefix. Most commonly, people with small SOHO networks use something like 192.168.0. We need not put any new static routes in place for the NAT'ing endpoint. That is because this particular machine is already configured (you configured it for NAT, right?) for routing packets from the inside network. Testing Tunnels before using IPSECThe following assumes that you have punched the correct holes into your firewall configuration. You need to allow IP-in-IP packets (in /etc/protocols, it is ipencap for the type). From the DNS server (4.4.4.4) ping 172.16.0.100 We are part way there, now try pinging from 172.16.0.100 ping 10.1.2.1 Both of the above commands should work. If they do not, do not proceed until you have corrected the problem. Things to think over to help diagnose the problem:
IPSECKernel ConfigurationIn order to start encrypting packets, you will need to make sure that your kernel has IPSEC support compiled into it. This is relatively simple. The following will assume that you already have a fresh copy of the FreeBSD source.
Configuring Racoon for X.509 CertificatesFirst, you need to transfer the tuple of certs (ca-cert.pem, hostX.key, hostX.cert) to the system on which they are to reside. The files should be put in a directory like /usr/local/etc/racoon/cert. Add the following to your racoon.conf and make sure to change the IP address of the remote endpoint IP of the tunnel. The following would be used on the NAT machine:
remote 10.1.2.1
{
exchange_mode main,aggressive;
doi ipsec_doi;
situation identity_only;
my_identifier asn1dn;
peers_identifier asn1dn;
verify_identifier on;
certificate_type x509 "hostX.cert" "hostX.key";
nonce_size 16;
lifetime time 1 min; # sec,min,hour
support_mip6 on;
proposal_check strict; # obey, strict or claim
proposal {
encryption_algorithm 3des;
hash_algorithm sha1;
authentication_method rsasig ;
dh_group 2 ;
}
}
Make sure to change your certificate path to match the real location of your certificates. path certificate "/usr/local/etc/racoon/cert"; Finally, we need to tell racoon about our CA certificate, ca-cert.pem. In your certificates directory, run the following: ln -s ca-cert.pem `openssl x509 -noout -hash -in ca-cert.pem`.0 Setting up the necessary SPD EntriesYou now have one last thing to do - setup the IPSEC rules that get fed to the kernel. This, of course, will need to be done on each endpoint system of the tunnel. The following would go into your /etc/ipsec.conf: flush; spdflush; spdadd 10.1.2.1/32 10.1.1.1/32 any -P in ipsec esp/tunnel/10.1.2.1-10.1.1.1/require; spdadd 10.1.1.1/32 10.1.2.1/32 any -P out ipsec esp/tunnel/10.1.1.1-10.1.2.1/require; spdadd 172.16.0.0/16 10.1.2.1/32 any -P out ipsec esp/tunnel/10.1.1.1-10.1.2.1/require; spdadd 10.1.2.1/32 172.16.0.0/16 any -P in ipsec esp/tunnel/10.1.2.1-10.1.1.1/require; Starting your IPSEC in /etc/rc.confcloned_interfaces="gif0" gif_interfaces="gif0" gifconfig_gif0="3.3.3.3 4.4.4.4" ifconfig_gif0="inet 10.1.1.1 10.1.2.1" racoon_enable="YES" racoon_flags="-f /usr/local/etc/racoon/racoon.conf" ipsec_enable="YES" Simply flip the IPs for the other system. References and LinksBibliography
Appendix AMakefile:
requests = *.csr
sign: ${requests}
# remove -batch option if want chance to not certify a particular request
${requests}: FORCE
@openssl ca -batch -config openssl.cnf -in $@ -out ${@:.csr=.cert}
@[ -f ${@:.csr=.cert} ] && rm $@
revoke:
@test $${cert:?"usage: make revoke cert=certificate"}
@openssl ca -config openssl.cnf -revoke $(cert)
@$(MAKE) gencrl
gencrl:
@openssl ca -config openssl.cnf -gencrl -out ca-crl.pem
clean:
-rm ${requests}
# creates required supporting files, CA key and certificate
init:
@test ! -f serial
@mkdir crl newcerts private
@chmod go-rwx private
@echo '01' > serial
@touch index
@openssl req -nodes -config openssl.cnf -days 1825 -x509 -newkey rsa -out ca-cert.pem -outform PEM
# for legacy make support
FORCE:
openssl.cnf HOME = . RANDFILE = $ENV::HOME/.rnd [ ca ] default_ca = CA_default [ CA_default ] dir = . # unset at present, and my limited certs can be kept in current dir #certs = $dir/certs new_certs_dir = $dir/newcerts crl_dir = $dir/crl database = $dir/index certificate = $dir/ca-cert.pem serial = $dir/serial crl = $dir/ca-crl.pem private_key = $dir/private/ca-key.pem RANDFILE = $dir/private/.rand x509_extensions = usr_cert # Comment out the following two lines for the "traditional" # (and highly broken) format. name_opt = ca_default cert_opt = ca_default default_crl_days= 30 default_days = 3650 # if need to be compatible with older software, use weaker md5 default_md = sha1 # MSIE may need following set to yes? preserve = no # 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 = 2048 default_keyfile = ./private/ca-key.pem default_md = sha1 prompt = no distinguished_name = root_ca_distinguished_name x509_extensions = v3_ca # 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 [ root_ca_distinguished_name ] commonName = Camulus.org countryName = US stateOrProvinceName = Minnesota localityName = Proctor 0.organizationName = camulus.org emailAddress = root@camulus.org [ 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 # PKIX recommendations harmless if included in all certificates. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer:always nsCaRevocationUrl = https://secure.camulus.org/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 [ crl_ext ] # CRL extensions. # Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. # issuerAltName=issuer:copy authorityKeyIdentifier=keyid:always,issuer:always |