Thursday, April 27, 2017

nginx on Solaris 11.3 SRU 19 with EC crypto and HTTP/2 support

nginx on Solaris 11.3 SRU 19 with EC crypto and HTTP/2 support

Solaris 11.3 SRU 19 came out last week and the Bugs Fixed list had the following highlight.

23058111 Enable Elliptic Curve Cryptography in OpenSSL

Niiiice. Let's build nginx with HTTP/2 support. See How to build software on Solaris 11/SPARC for default compiler flags.

# pkg install --accept --no-backup-be developer/build/gnu-make developer/developerstudio-125/cc system/xopen/xcu6
...
           Packages to install: 15
...
$ wget https://nginx.org/download/nginx-1.13.0.tar.gz
$ gzcat nginx-1.13.0.tar.gz | pax -rf -
$ cd nginx-1.13.0
$ PATH=$(getconf PATH) ./configure \
  --prefix=/opt/local --user=webservd --group=webservd \
  --with-cc-opt="-xO4 -xarch=sparcvis2 -Qoption cg -xregs=no%appl -W2,-xwrap_int -xc99=all -xmemalign=16s -mt \
    -KPIC -DPIC" \
  --with-ld-opt="-zaslr=enable -znxstack=enable -znxheap=enable \
    -M /usr/lib/ld/map.noexstk -M /usr/lib/ld/map.noexbss -M /usr/lib/ld/map.pagealign \
    -Bdirect -zignore -zstrip-class=comment -ztype=pie" \
  --with-cpu-opt=sparc64 --with-threads --with-http_ssl_module --with-http_v2_module
...
Configuration summary
  + using threads
  + using system PCRE library
  + using system OpenSSL library
  + using system zlib library

$ perl -w -pi -e 's/-fast -xipo //; s/-g //' objs/Makefile

$ PATH=$(getconf PATH) gmake
...

# gmake install
...

Make the following changes to /opt/local/conf/nginx.conf.

# cat << 'EOF' > /opt/local/conf/nginx.conf
worker_processes  2;

events {
    worker_connections  1024;
    accept_mutex off;
    #use eventport;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile on;
    tcp_nopush on;
    gzip on;
    gzip_types application/json application/x-javascript application/xml application/xml+rss
               text/css text/javascript text/js text/plain text/xml;
    
    server {
        listen 80 default_server;

        # Redirect all HTTP requests to HTTPS with a 301 Moved Permanently response.
        return 301 https://$host$request_uri;
    }

    server {
        listen 443 ssl http2 reuseport default_server;

        ssl_certificate server.crt;
        ssl_certificate_key server.key;
        ssl_certificate server-ecc.crt;
        ssl_certificate_key server-ecc.key;

        ssl_session_cache shared:SSL:10m;
        ssl_session_timeout 10m;
        ssl_session_tickets off;

        ssl_protocols TLSv1.2;
        ssl_ciphers AESGCM;
        ssl_prefer_server_ciphers on;

        add_header Strict-Transport-Security max-age=15768000;
        add_header X-Frame-Options DENY;

        #ssl_stapling on;
        #ssl_stapling_verify on;
        #ssl_trusted_certificate /etc/certs/ca-certificates.crt;

        location / {
            root   html;
            index  index.html index.htm;
        }
    }
}
EOF

We need a SSL certificate and key as well. See How to create a SSL CA/certificate/key with pktool how to do that. Done? Good.

# cp server.crt /opt/local/conf
# cp server.key /opt/local/conf

Let's create an ECDSA certificate/key as well.

This step here is optional since we already created a CA with pktool. Only do this when you want to go full ECC and don't forget to copy the ECC CA certificate to /etc/certs/CA/ as well!

$ openssl ecparam -genkey -name secp384r1 -out CA.key
$ openssl req -x509 -new -sha256 -nodes -key CA.key -days 3650 -out CA.crt \
  -subj "/C=DE/ST=Berlin/L=Berlin/O=My Company/OU=Unix Dep/CN=Unix Dep CA/emailAddress=unix.dep@mycompany.com"

Decided which CA to use? Good then let's proceed.

$ FQDN=$(perl -mNet::Domain -e 'print Net::Domain::hostfqdn()')
$ HOSTNAME=$(uname -n)
$ cat << EOF > csr.cnf
[req]
req_extensions     = v3_req
distinguished_name = req_distinguished_name

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
stateOrProvinceName             = State or Province Name (full name)
localityName                    = Locality Name (eg, city)
0.organizationName              = Organization Name (eg, company)
organizationalUnitName          = Organizational Unit Name (eg, section)
commonName                      = Common Name (e.g. server FQDN or YOUR name)
emailAddress                    = Email Address

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage         = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName   = @alt_names

[alt_names]
DNS.1 = $FQDN
DNS.2 = $HOSTNAME
EOF

$ openssl ecparam -genkey -name secp384r1 -out server-ecc.key
$ openssl req -new -sha256 -nodes -key server-ecc.key -days 365 -out server-ecc.csr -config csr.cnf \
  -subj "/C=DE/ST=Berlin/L=Berlin/O=My Company/OU=Unix Dep/CN=$FQDN/emailAddress=webservd@$FQDN"
$ openssl x509 -req -sha256 -days 365 -in server-ecc.csr -CA CA.crt -CAkey CA.key -CAcreateserial \
  -out server-ecc.crt -extfile csr.cnf -extensions v3_req

# cp server-ecc.crt /opt/local/conf
# cp server-ecc.key /opt/local/conf

Certificates and keys created? Excellent. Let's start nginx now and try connecting via ECDSA TLS 1.2 and HTTP/2.

# /opt/local/sbin/nginx -t
nginx: the configuration file /opt/local/conf/nginx.conf syntax is ok
nginx: configuration file /opt/local/conf/nginx.conf test is successful

# /opt/local/sbin/nginx

$ openssl s_client -connect $(uname -n):443 -tls1_2 -cipher ECDHE-ECDSA-AES128-GCM-SHA256 < /dev/null
...
Server Temp Key: ECDH, P-256, 256 bits
...
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-ECDSA-AES128-GCM-SHA256
...

And Firefox reports that HTTP/2 is being used as well.

Firefox Web Developer Network Headers

Links

1 comment:

  1. Amazing article, well written and explained! I'll give this a shot for sure on my SPARC SUNfire T2000 which has S11.3 installed along with LDOM functionality:)

    ReplyDelete

389 Directory Server 1.3.x LDAP client authentication

389 Directory Server 1.3.x LDAP client authentication Last time we did a multi-master replication setup, see 389 Directory Server 1.3.x Repl...