JadKHaddad / rust-mtls-example

An example of how to support mTLS in Rust with both client and server implementation

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Rust mTLS example

This is an example of how to support mTLS (two-way authentication, with client authentication) in Rust.

Implementation is quite short and includes both client and server side.

To run the example:

  1. Generate all required keys and certificates following the instructions below.
  2. Use cd .. to go back to the project root folder.
  3. Start the server by running cargo run -- server (note the white space).
  4. (While the server is running) start another prompt and run cargo run -- client (note the white space).
  5. If you see "Hello, mTLS World!", your configuration is probably correct. Congratulations!

To run the example with rustls-tls instead of native-tls, replace the command in step 2/3 above with:

  • cargo run --no-default-features --features rustls-tls -- server
  • cargo run --no-default-features --features rustls-tls -- client

Requirements:

  • Rust & Cargo
  • openssl (>=2019)
  • (optional) curl (>=2019)

Notes:

  • To successfully run the executable, if you do not need two CAs in your configuration, you should replace all "second_ca" with "ca" in main.rs. The second_ca in the code only targets to demonstrate the option to configure different CAs separately and you can find more information in (13.) below.

  • To use this in a real-world scenario, please replace localhost with a meaningful domain name. Do not forget to also change it in the SAN (subjectAltName). Also do not forget to fill in meaningful information while generating CSRs.

  • To test the mTLS server in your browser (e.g. Chrome), please see this nice post or search "manual install certification {your browser name}". However, please note that

    • To make the https work (make the small lock icon green), the localhost.bundle.crt mentioned below need to be installed in the trusted root certifications category.
    • To make the client authentication work, just import the client's client_0.p12 file mentioned below into Personal category. In the import window, you might need to change the extension name to find the right file.

Setup your own Certificate Authority

CA

  1. Create a folder for all related files

    mkdir ca
    cd ca
  2. Generate a key for the CA

    openssl genrsa -out ca.key 2048
  3. Generate a self signed certificate for the CA

    # enter detailed information when necessary
    openssl req -new -x509 -key ca.key -out ca.crt

Server

  1. Generate an RSA key for the domain (localhost here)

    openssl genrsa -out localhost.key 2048
    # optional: inspect the key
    openssl rsa -in localhost.key -noout -text
    # optional: extract pubkey
    openssl rsa -in localhost.key -pubout -out localhost.pubkey
  2. Generate a Certificate Signing Request (CSR)

    # enter detailed information when necessary (please make sure you enter COMMON NAME)
    openssl req -new -key localhost.key -addext "subjectAltName = DNS:localhost" -out localhost.csr
    # optional: inspect the csr (note: while inspecting, make sure your Signature Algorithm is not MD5 which is not accepted by many sites, upgrade your openssl if necessary)
    openssl req -in localhost.csr -noout -text
  3. Sign the domain certificate

    openssl x509 -req -in localhost.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extfile <(printf "subjectAltName=DNS:localhost") -out localhost.crt
    # optional: to exam the output crt
    openssl x509 -in localhost.crt -noout -text
  4. Create another file that contains the domain certificate and the ca certificate

    cat localhost.crt ca.crt > localhost.bundle.crt

Client

  1. Generate an RSA key for the client

    openssl genrsa -out client_0.key 2048
  2. Generate a Certificate Signing Request (CSR), please note that the SAN extension is NECESSARY

    # enter detailed information when necessary (please make sure you enter COMMON NAME)
    openssl req -new -key client_0.key -addext "subjectAltName = DNS:localhost" -out client_0.csr
  3. Use CA key to sign it

    openssl x509 -req -in client_0.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extfile <(printf "subjectAltName=DNS:localhost") -out client_0.crt
  4. Generate pem file to test with curl & browser

    # generate pem file
    cat client_0.crt client_0.key > client_0.pem
    # optional: test command (after starting the server) using .pem file
    curl -L  https://localhost:3030/ --cacert ca.crt --cert client_0.pem -v
    # generate cert file to use with browser (setting password to be 123456 for example)
    openssl pkcs12 -export -in client_0.pem -out client_0.p12 -name "client_0"
    # optional: test command (after starting the server) using .p12 file
    curl -L  https://localhost:3030/ --cacert ca.crt --cert-type P12 --cert client_0.p12:123456 -v

Optional

  1. Create certificates for more clients

    export CLIENT_NAME=client_1
    openssl genrsa -out ${CLIENT_NAME}.key 2048
    openssl req -new -key ${CLIENT_NAME}.key -addext "subjectAltName = DNS:localhost" -out ${CLIENT_NAME}.csr
    # after answering the prompt above
    openssl x509 -req -in ${CLIENT_NAME}.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extfile <(printf "subjectAltName=DNS:localhost") -out ${CLIENT_NAME}.crt
    cat ${CLIENT_NAME}.crt ${CLIENT_NAME}.key > ${CLIENT_NAME}.pem
    openssl pkcs12 -export -in ${CLIENT_NAME}.pem -out ${CLIENT_NAME}.p12 -name "${CLIENT_NAME}"
    # enter a password (e.g. 123456 (plz don't use weak password in real-world deployment))
  2. Generate multiple CAs

    # generate a second CA
    openssl genrsa -out second_ca.key 2048
    openssl req -new -x509 -key second_ca.key -out second_ca.crt
    # answer the prompt
    
    export CLIENT_NAME=second_client
    openssl genrsa -out ${CLIENT_NAME}.key 2048
    openssl req -new -key ${CLIENT_NAME}.key -addext "subjectAltName = DNS:localhost" -out ${CLIENT_NAME}.csr
    # answer the prompt
    
    openssl x509 -req -in ${CLIENT_NAME}.csr -CA second_ca.crt -CAkey second_ca.key -CAcreateserial -extfile <(printf "subjectAltName=DNS:localhost") -out ${CLIENT_NAME}.crt
    cat ${CLIENT_NAME}.crt ${CLIENT_NAME}.key > ${CLIENT_NAME}.pem
    openssl pkcs12 -export -in ${CLIENT_NAME}.pem -out ${CLIENT_NAME}.p12 -name "${CLIENT_NAME}"
    # enter a password (e.g. 123456 (plz don't use weak password in real-world deployment))

Reference:

Contributing

There is still an unclear issue:

  • Why the certificate for the client must include the extension fields of SAN?

If you know the answers or have better solutions, please feel free to share your thoughts or send issues/PRs. Contributions are greatly appreciated.

About

An example of how to support mTLS in Rust with both client and server implementation

License:Other


Languages

Language:Rust 100.0%