Skip to content

Instantly share code, notes, and snippets.

@jhseodev
Last active June 21, 2021 22:20
Show Gist options
  • Save jhseodev/d17c371c95c7ab4a65c58edc0c31cbf6 to your computer and use it in GitHub Desktop.
Save jhseodev/d17c371c95c7ab4a65c58edc0c31cbf6 to your computer and use it in GitHub Desktop.
nginx test

Test nginx SSL directive

1. proxy_ssl_verify_depth (ssl_verify_depth)

description

Syntax:	 proxy_ssl_verify_depth number;
Default: proxy_ssl_verify_depth 1;
Context: http, server, location
This directive appeared in version 1.7.0.

Sets the verification depth in the proxied HTTPS server certificates chain.

1-1. Preparation

a. Root CA certificate

a-1. Root CA openssl config file
# openssl_root.conf
[ ca ]
default_ca = CA_default

[ CA_default ]
dir               = .

# Mandatory option
new_certs_dir     = $dir/newcerts                           # new certificates
database          = $dir/index.txt                          # index file
serial            = $dir/serial                             # serial number file
private_key       = $dir/private/ca.www.root_ca.com.key     # CA private key
certificate       = $dir/certs/ca.www.root_ca.com.crt       # CA cert
default_md        = sha512
policy            = policy_loose

[ policy_loose ]
# "match" then the field value must match the same field in the CA certificate.
# "supplied" then it must be present.
# "optional" then it may be present.
countryName             = optional
stateOrProvinceName     = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ req ]
distinguished_name  = req_distinguished_name
x509_extensions     = v3_ca

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
stateOrProvinceName             = State or Province Name
localityName                    = Locality Name
0.organizationName              = Organization Name
organizationalUnitName          = Organizational Unit Name
commonName                      = Common Name
emailAddress                    = Email Address

[ v3_ca ]
basicConstraints = critical, CA:true   # This cert is CA certificate.

[ v3_intermediate_ca ]
basicConstraints = critical, CA:true   # This intermediate cert is CA certificate.

[ server_cert ]
basicConstraints = CA:FALSE
a-2. make directory and locate file
mkdir certs private newcerts
touch index.txt
touch index.txt.attr
echo 1000 > serial
a-3. create private key
openssl genrsa -out private/ca.www.root_ca.com.key 2048
a-4. create certificate request and self signing
openssl req -config openssl_root.conf \
    -new -x509 -extensions v3_ca \
    -key private/ca.www.root_ca.com.key \
    -out certs/ca.www.root_ca.com.crt \
    -days 3650 \
    -set_serial 0

b. Intermediate CA certificate

b-1. Intermediate CA openssl config file
# openssl_intermediate_ca.conf
[ ca ]
default_ca = CA_default

[ CA_default ]
dir               = ./intermediate

# Mandatory option
new_certs_dir     = $dir/newcerts                           # new certificates
database          = $dir/index.txt                          # index file
serial            = $dir/serial                             # serial number file
private_key       = $dir/private/int.www.intermediate_ca.com.key     # CA private key
certificate       = $dir/certs/int.www.intermediate_ca.com.crt       # CA cert
default_md        = sha512
policy            = policy_loose

[ policy_loose ]
# "match" then the field value must match the same field in the CA certificate.
# "supplied" then it must be present.
# "optional" then it may be present.
countryName             = optional
stateOrProvinceName     = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ req ]
distinguished_name  = req_distinguished_name
x509_extensions     = v3_ca

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
stateOrProvinceName             = State or Province Name
localityName                    = Locality Name
0.organizationName              = Organization Name
organizationalUnitName          = Organizational Unit Name
commonName                      = Common Name
emailAddress                    = Email Address

[ v3_ca ]
basicConstraints = critical, CA:true   # This cert is CA certificate.

[ v3_intermediate_ca ]
basicConstraints = critical, CA:true   # This intermediate cert is CA certificate.

[ server_cert ]
basicConstraints = CA:FALSE
b-2. make directory
mkdir intermediate
cd intermediate
mkdir newcerts certs private csr
touch index.txt
touch index.txt.attr
echo 2000 > serial
b-3. create private key
openssl genrsa -out intermediate/private/int.www.intermediate_ca.com.key 2048
b-4. create certificate request
openssl req -config intermediate/openssl_intermediate_ca.conf \
    -new -key intermediate/private/int.www.intermediate_ca.com.key \
    -out intermediate/csr/int.www.intermediate_ca.com.csr
b-5. signing
openssl ca -config openssl_root.conf \
    -extensions v3_intermediate_ca \
    -days 3650 \
    -notext \
    -in intermediate/csr/int.www.intermediate_ca.com.csr \
    -out intermediate/certs/int.www.intermediate_ca.com.crt

c. Next intermediate CA certificate

c-1. Intermediate CA openssl config file
# openssl_next_intermediate_ca.conf
[ ca ]
default_ca = CA_default

[ CA_default ]
dir               = ./next_intermediate

# Mandatory option
new_certs_dir     = $dir/newcerts                           # new certificates
database          = $dir/index.txt                          # index file
serial            = $dir/serial                             # serial number file
private_key       = $dir/private/int.www.next_intermediate_ca.com.key     # CA private key
certificate       = $dir/certs/int.www.next_intermediate_ca.com.crt       # CA cert
default_md        = sha512
policy            = policy_loose

[ policy_loose ]
# "match" then the field value must match the same field in the CA certificate.
# "supplied" then it must be present.
# "optional" then it may be present.
countryName             = optional
stateOrProvinceName     = optional
organizationName        = optional
organizationalUnitName  = optional
commonName              = supplied
emailAddress            = optional

[ req ]
distinguished_name  = req_distinguished_name
x509_extensions     = v3_ca

[ req_distinguished_name ]
countryName                     = Country Name (2 letter code)
stateOrProvinceName             = State or Province Name
localityName                    = Locality Name
0.organizationName              = Organization Name
organizationalUnitName          = Organizational Unit Name
commonName                      = Common Name
emailAddress                    = Email Address

[ v3_ca ]
basicConstraints = critical, CA:true   # This cert is CA certificate.

[ v3_intermediate_ca ]
basicConstraints = critical, CA:true   # This intermediate cert is CA certificate.

[ server_cert ]
basicConstraints = CA:FALSE
c-2. make directory
mkdir intermediate/next_intermediate
cd intermediate/next_intermediate
mkdir newcerts certs private csr
touch index.txt
touch index.txt.attr
echo 3000 > serial
c-3. create private key
openssl genrsa -out next_intermediate/private/int.www.next_intermediate_ca.com.key 2048
c-4. create certificate request
openssl req -config next_intermediate/openssl_next_intermediate_ca.conf \
    -new -key next_intermediate/private/int.www.next_intermediate_ca.com.key \
    -out next_intermediate/csr/int.www.next_intermediate_ca.com.csr
c-5. signing
openssl ca -config openssl_intermediate_ca.conf \
    -extensions v3_intermediate_ca \
    -days 3650 \
    -notext \
    -in next_intermediate/csr/int.www.next_intermediate_ca.com.csr \
    -out next_intermediate/certs/int.www.next_intermediate_ca.com.crt

d. server certificate

d-1. Server openssl config file
# openssl_server.conf
[ req ]
default_bits       = 2048
distinguished_name = req_distinguished_name
req_extensions     = req_ext

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

[ req_ext ]
subjectAltName = @alt_names

[alt_names]
DNS.1   = *.my_server.org
DNS.2   = *.my_server.net
d-2. create private key
openssl genrsa -out private/srv.www.my_server.com.key 2048
d-3. create certificate request
openssl req -config openssl_server.conf \
    -new -key private/srv.www.my_server.com.key \
    -out next_intermediate/csr/srv.www.my_server.com.csr
d-4. signing
openssl ca -config openssl_next_intermediate_ca.conf \
    -extensions v3_intermediate_ca \
    -days 3650 \
    -notext \
    -in next_intermediate/csr/srv.www.my_server.com.csr \
    -out next_intermediate/certs/srv.www.my_server.com.crt

1-2. Test based openssl verify command

root_ca / intermediate_ca

$ openssl verify -CAfile certs/ca.www.root_ca.com.crt intermediate/certs/int.www.intermediate_ca.com.crt
intermediate/certs/int.www.intermediate_ca.com.crt: OK
$

intermediate_ca / next_intermediate_ca

$ openssl verify -CAfile intermediate/certs/int.www.intermediate_ca.com.crt intermediate/next_intermediate/certs/int.www.next_intermediate_ca.com.crt
error 2 at 1 depth lookup: unable to get issuer certificate
error intermediate/next_intermediate/certs/int.www.next_intermediate_ca.com.crt: verification failed
$
Firstly a certificate chain is built up starting from the supplied certificate and ending in the root CA.

root_ca ~ next_intermediate_ca

$ openssl verify -CAfile certs/ca.www.root_ca.com.crt \
> -untrusted intermediate/certs/int.www.intermediate_ca.com.crt \
> intermediate/next_intermediate/certs/int.www.next_intermediate_ca.com.crt
intermediate/next_intermediate/certs/int.www.next_intermediate_ca.com.crt: OK
$

root_ca / server

$ openssl verify -CAfile certs/ca.www.root_ca.com.crt \
> -untrusted intermediate/certs/int.www.intermediate_ca.com.crt \
> -untrusted intermediate/certs/int.www.next_intermediate_ca.com.crt \
> intermediate/next_intermediate/certs/srv.www.my_server.com.crt
intermediate/next_intermediate/certs/srv.www.my_server.com.crt: OK
$

ca chain / server

$ cat intermediate/next_intermediate/certs/int.www.next_intermediate_ca.com.crt \
> intermediate/certs/int.www.intermediate_ca.com.crt \
> certs/ca.www.root_ca.com.crt > ca_chain.crt
$ openssl verify -CAfile ca_chain.crt \
> intermediate/next_intermediate/certs/srv.www.my_server.com.crt
intermediate/next_intermediate/certs/srv.www.my_server.com.crt: OK
$

1-3. Test based nginx

proxy settings

http {
  error_log /usr/local/nginx/logs/error_log;

  ...

  upstream {
    server my_server_ip_addr:443;  
  }

  server {
    listen proxy_ip_addr;

    ...

    location ~ '' {
      proxy_pass https://my_server;

      ...

      proxy_ssl_verify_depth 1;
      proxy_ssl_verify on;
      proxy_ssl_trusted_certificate ca_chain.crt;
      proxy_ssl_name $host;

      ...
    }
  }
}

server settings

server {                                                                  
    listen       443 ssl;                                                 
    server_name  localhost;                                               
                                                                          
    ssl_certificate      srv.www.my_server.com.crt
    ssl_certificate_key  srv.www.my_server.com.key
    ssl_session_cache    shared:SSL:1m;                                   
    ssl_session_timeout  5m;                                              
                                                                          
    ssl_ciphers  HIGH:RSA:!MD5;  #HIGH:!aNULL:!MD5;                       
    ssl_prefer_server_ciphers  on;                                        
                                                                          
    location / {                                                          
        root   html;                                                      
        index  index.html index.htm;                                      
    }                                                                     
}                                                                         

test result

$ curl proxy_domain_name
<html>                                     
<head><title>502 Bad Gateway</title></head>
<body bgcolor="white">                     
<center><h1>502 Bad Gateway</h1></center>  
</body>                                    
</html>                                    
$ tail /usr/local/nginx/logs/error.log
upstream SSL certificate verify error: (22:certificate chain too long) while SSL handshaking to upstream, client: xxx.xxx.xxx.xxx, server: , request: "GET / HTTP/1.1", upstream: "https://my_server_ip_addr:443/", host: "proxy_domain_name"
$

change verify_depth 1 to 2

http {
  error_log /usr/local/nginx/logs/error_log;

  ...

  upstream {
    server my_server_ip_addr:443;  
  }

  server {
    listen proxy_ip_addr;

    ...

    location ~ '' {
      proxy_pass https://my_server;

      ...

      proxy_ssl_verify_depth 2;
      proxy_ssl_verify on;
      proxy_ssl_trusted_certificate ca_chain.crt;
      proxy_ssl_name $host;

      ...
    }
  }
}

test result after change verify depth

$ curl proxy_domain_name
<!DOCTYPE html>
<html>                                                         
<head>                
<title>Welcome to nginx!</title>                             
<style>
    body {
        width: 35em;
        margin: 0 auto;
        font-family: Tahoma, Verdana, Arial, sans-serif;
    }              
</style>           
</head>            
<body>             
<h1>Welcome to nginx!</h1>              
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>                
                      
<p>For online documentation and support please refer to      
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
      
<p><em>Thank you for using nginx.</em></p>                     
</body>               
</html>                                                      
$ 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment