Skip to content

Instantly share code, notes, and snippets.

@fntlnz
Last active October 3, 2023 11:42
Star You must be signed in to star a gist
Embed
What would you like to do?
Self Signed Certificate with Custom Root CA

Create Root CA (Done once)

Create Root Key

Attention: this is the key used to sign the certificate requests, anyone holding this can sign certificates on your behalf. So keep it in a safe place!

openssl genrsa -des3 -out rootCA.key 4096

If you want a non password protected key just remove the -des3 option

Create and self sign the Root Certificate

openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt

Here we used our root key to create the root certificate that needs to be distributed in all the computers that have to trust us.

Create a certificate (Done for each server)

This procedure needs to be followed for each server/appliance that needs a trusted certificate from our CA

Create the certificate key

openssl genrsa -out mydomain.com.key 2048

Create the signing (csr)

The certificate signing request is where you specify the details for the certificate you want to generate. This request will be processed by the owner of the Root key (you in this case since you create it earlier) to generate the certificate.

Important: Please mind that while creating the signign request is important to specify the Common Name providing the IP address or domain name for the service, otherwise the certificate cannot be verified.

I will describe here two ways to gener

Method A (Interactive)

If you generate the csr in this way, openssl will ask you questions about the certificate to generate like the organization details and the Common Name (CN) that is the web address you are creating the certificate for, e.g mydomain.com.

openssl req -new -key mydomain.com.key -out mydomain.com.csr

Method B (One Liner)

This method generates the same output as Method A but it's suitable for use in your automation :) .

openssl req -new -sha256 -key mydomain.com.key -subj "/C=US/ST=CA/O=MyOrg, Inc./CN=mydomain.com" -out mydomain.com.csr

If you need to pass additional config you can use the -config parameter, here for example I want to add alternative names to my certificate.

openssl req -new -sha256 \
    -key mydomain.com.key \
    -subj "/C=US/ST=CA/O=MyOrg, Inc./CN=mydomain.com" \
    -reqexts SAN \
    -config <(cat /etc/ssl/openssl.cnf \
        <(printf "\n[SAN]\nsubjectAltName=DNS:mydomain.com,DNS:www.mydomain.com")) \
    -out mydomain.com.csr

Verify the csr's content

openssl req -in mydomain.com.csr -noout -text

Generate the certificate using the mydomain csr and key along with the CA Root key

openssl x509 -req -in mydomain.com.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out mydomain.com.crt -days 500 -sha256

Verify the certificate's content

openssl x509 -in mydomain.com.crt -text -noout
@minhphungbk03
Copy link

I followed all the steps and configured nginx to use the generated certificate:

    ssl_certificate         /root/mydomain.com.crt;
    ssl_certificate_key     /root/mydomain.com.key;
    ssl_client_certificate  /root/rootCA.crt;

    ssl_verify_client on;
    ssl_verify_depth 2;

however, when trying it with curl it doens't work: curl --cacert rootCA.crt https://localhost:9090

Any idea?

Hi, I face with the same issue. Does anyone has solution yet? Thanks!
https://gist.github.com/fntlnz/cf14feb5a46b2eda428e000157447309#gistcomment-3095363

@EmmanuelKasper
Copy link

@fntlnz
not sure how long you want to maintain this gist, but it lacks the command where the CA is signing a CSR containing at subjectAltName entry. You're documenting how generate a CSR containing a subjectAltName, but not how the CA should sign it :)
It should be
openssl x509 -req -extfile <(printf "subjectAltName=DNS:mydomain.com") -days 120 -in mydomain.com.csr -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out mydomain.com.crt -sha256

as pointed out by @chrismacp

@pplmx
Copy link

pplmx commented Sep 17, 2021

Help: how to create a authentication tls in golang

Could anyone give me some help? Thanks a lot.

Error info

I can create root CA and the server CA successfully.
However, I cannot use localhost.key.pem and localhost.crt.pem to create a TLS connection in golang 1.17.
Client always failed to connect to the server, which threw the following

2021/09/17 14:27:21 x509: certificate signed by unknown authority
exit status 1

Server start

# server can be started normally
go run server.go 12345
# client cannot connect to the server.
go run client.go localhost:12345

CA creation

Here are my reproduced steps:

openssl req -x509 -nodes -sha256 \
	-newkey rsa:4096 \
	-days 10240 \
	-subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg, Inc./OU=Software Dept/CN=localhost" \
	-keyout root.key.pem \
	-out root.crt.pem

# OPENSSL_CONF="/etc/ssl/openssl.cnf"
OPENSSL_CONF="/System/Library/OpenSSL/openssl.cnf"
openssl req -new -nodes \
    -newkey rsa:4096 \
    -subj "/C=CN/ST=Beijing/L=Beijing/O=MyOrg, Inc./OU=Software Dept/CN=localhost" \
	-reqexts SAN \
    -config <(cat "${OPENSSL_CONF}" \
        <(printf "\n[SAN]\nsubjectAltName=DNS:localhost")) \
    -keyout localhost.key.pem \
    -out localhost.csr

openssl x509 -req -sha256 -CAcreateserial -days 365 \
	-CA root.crt.pem \
	-CAkey root.key.pem \
	-extfile <(printf "subjectAltName=DNS:localhost") \
	-in localhost.csr \
	-out localhost.crt.pem

Golang code

Here is my golang code.
Server

package main

import (
    "bufio"
    "crypto/rand"
    "crypto/tls"
    "fmt"
    "log"
    "net"
    "os"
    "strconv"
    "strings"
    "time"
)

var count = 0
var ServerCertFile = "../certificate/localhost.crt.pem"
var ServerKeyFile = "../certificate/localhost.key.pem"

func handleConnection(c net.Conn) {
    fmt.Println("Connection from ", c.RemoteAddr().String())
    for {
        netData, err := bufio.NewReader(c).ReadString('\n')
        if err != nil {
            fmt.Println(err)
            return
        }

        temp := strings.TrimSpace(netData)
        if temp == "STOP" {
            break
        }
        fmt.Println(temp)
        counter := strconv.Itoa(count) + "\n"
        c.Write([]byte(counter))
    }
    defer func(c net.Conn) {
        err := c.Close()
        if err != nil {
            fmt.Println("Failed to Close Connection from ", c.RemoteAddr().String())
        }
    }(c)
}

func main() {

    arguments := os.Args
    if len(arguments) == 1 {
        fmt.Println("Please provide a port number!")
        return
    }
    PORT := ":" + arguments[1]

    // load certificate
    crt, err := tls.LoadX509KeyPair(ServerCertFile, ServerKeyFile)
    if err != nil {
        log.Fatalln(err.Error())
        return
    }
    tlsConfig := &tls.Config{}
    tlsConfig.Certificates = []tls.Certificate{crt}
    tlsConfig.Time = time.Now
    tlsConfig.Rand = rand.Reader

    l, err := tls.Listen("tcp", PORT, tlsConfig)
    if err != nil {
        log.Fatalln(err.Error())
        return
    }
    defer l.Close()

    for {
        conn, err := l.Accept()
        if err != nil {
            fmt.Println(err.Error())
            continue
        }
        go handleConnection(conn)
        count++
    }
}

Client

package main

import (
    "bufio"
    "crypto/tls"
    "fmt"
    "log"
    "os"
    "strings"
)

func main() {
    arguments := os.Args
    if len(arguments) == 1 {
        fmt.Println("Please provide host:port.")
        return
    }

    CONNECT := arguments[1]
    c, err := tls.Dial("tcp", CONNECT, nil)
    if err != nil {
        log.Fatalln(err.Error())
        return
    }

    for {
        reader := bufio.NewReader(os.Stdin)
        fmt.Print(">> ")
        text, _ := reader.ReadString('\n')
        fmt.Fprintf(c, text+"\n")

        message, _ := bufio.NewReader(c).ReadString('\n')
        fmt.Print("->: " + message)
        if strings.TrimSpace(string(text)) == "STOP" {
            fmt.Println("TCP client exiting...")
            return
        }
    }
}

@pplmx
Copy link

pplmx commented Sep 17, 2021

Help: how to create a authentication tls in golang

Fixed it.
FYI.
https://awesomeopensource.com/project/jcbsmpsn/golang-https-example
image

@cspiel1
Copy link

cspiel1 commented Nov 4, 2022

Option -copy_extensions copy is missing for openssl x509 -req command because of the example with the Subject alternative name.

@shreeve
Copy link

shreeve commented Dec 17, 2022

#!/bin/bash

# =============================================================================
# ssl-certs.sh - Self signing SSL certificates
#
# Author: Steve Shreeve <steve.shreeve@gmail.com>
#   Date: Dec 17, 2022
# =============================================================================

# Use https://gist.github.com/shreeve/3358901a26a21d4ddee0e1342be7749d
# See https://gist.github.com/fntlnz/cf14feb5a46b2eda428e000157447309

# variables
name="ACME, Inc."
base="acme.com"
root="root"
myip="$(ifconfig | awk '/inet / { print $2 }' | grep -v -E "^127\." | head -1)"

# create root key and certificate
openssl genrsa -out "${root}.key" 3072
openssl req -x509 -nodes -sha256 -new -key "${root}.key" -out "${root}.crt" -days 731 \
  -subj "/CN=Custom Root" \
  -addext "keyUsage = critical, keyCertSign" \
  -addext "basicConstraints = critical, CA:TRUE, pathlen:0" \
  -addext "subjectKeyIdentifier = hash"

# create our key and certificate signing request
openssl genrsa -out "${base}.key" 2048
openssl req -sha256 -new -key "${base}.key" -out "${base}.csr" \
  -subj "/CN=*.${base}/O=${name}/OU=$(whoami)@$(hostname) ($(/usr/bin/id -F))" \
  -reqexts SAN -config <(echo "[SAN]\nsubjectAltName=DNS:${base},DNS:*.${base},IP:127.0.0.1,IP:${myip}\n")

# create our final certificate and sign it
openssl x509 -req -sha256 -in "${base}.csr" -out "${base}.crt" -days 731 \
  -CAkey "${root}.key" -CA "${root}.crt" -CAcreateserial -extfile <(cat <<END
    subjectAltName = DNS:${base},DNS:*.${base},IP:127.0.0.1,IP:${myip}
    keyUsage = critical, digitalSignature, keyEncipherment
    extendedKeyUsage = serverAuth
    basicConstraints = CA:FALSE
    authorityKeyIdentifier = keyid:always
    subjectKeyIdentifier = none
END
)

# update the macOS trust store (TODO: add other operating systems)
sudo /usr/bin/security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "${root}.crt"

# review files
echo "--"; openssl x509 -in "${root}.crt" -noout -text
echo "--"; openssl req  -in "${base}.csr" -noout -text
echo "--"; openssl x509 -in "${base}.crt" -noout -text
echo "--";

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment