Skip to content

Instantly share code, notes, and snippets.

@gotwarlost
Last active December 17, 2019 18:17
Show Gist options
  • Save gotwarlost/5587dfc74c5ab3c472842b67ddf3c37a to your computer and use it in GitHub Desktop.
Save gotwarlost/5587dfc74c5ab3c472842b67ddf3c37a to your computer and use it in GitHub Desktop.
program that shows the new CA cert with the same key is not valid for old clients when the subject of the cert is differen
package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"io"
"log"
"math/big"
"net"
"net/http"
"net/http/httptest"
"time"
)
func makePrivateKey(bits int) (key *rsa.PrivateKey, keyPEM []byte, err error) {
key, err = rsa.GenerateKey(rand.Reader, bits)
if err != nil {
return nil, nil, err
}
return key, pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(key),
}), nil
}
const mungeOValue = false
func makeCACert(priv *rsa.PrivateKey, years int) (cert []byte, pemFormatted []byte, err error) {
o := "root.ca"
if mungeOValue {
log.Println("munge O value for different CAs")
o = fmt.Sprintf("root.ca.%d", years)
} else {
log.Println("using static O value")
}
ca := &x509.Certificate{
SerialNumber: big.NewInt(int64(years)),
Subject: pkix.Name{
Organization: []string{o},
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(years, 0, 0),
IsCA: true,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
BasicConstraintsValid: true,
}
caBytes, err := x509.CreateCertificate(rand.Reader, ca, ca, &priv.PublicKey, priv)
if err != nil {
return nil, nil, err
}
return caBytes, pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: caBytes,
}), nil
}
func runClient(uri string, pool *x509.CertPool) error {
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: pool,
},
},
}
res, err := client.Get(uri)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode != 200 {
panic("unexpected status code: " + res.Status)
}
return nil
}
func main() {
handle := func(err error) {
if err != nil {
panic(err)
}
}
// make the CA private key
caPrivKey, _, err := makePrivateKey(2048)
handle(err)
// create old and new CA Certs using the same private key but with different lifetimes
oldCertBytes, oldCACertPEM, err := makeCACert(caPrivKey, 1)
handle(err)
oldCACert, err := x509.ParseCertificate(oldCertBytes)
_ = oldCACert
handle(err)
newCertBytes, newCACertPEM, err := makeCACert(caPrivKey, 10)
handle(err)
newCACert, err := x509.ParseCertificate(newCertBytes)
handle(err)
_ = newCACert
serverKey, serverKeyPEM, err := makePrivateKey(1024)
handle(err)
serverCert := &x509.Certificate{
SerialNumber: big.NewInt(1000),
Subject: pkix.Name{
CommonName: "server.cert",
},
DNSNames: []string{"localhost"},
IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1), net.IPv6loopback},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(0, 1, 0),
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature,
}
// create cert using newCACert as parent
certBytes, err := x509.CreateCertificate(rand.Reader, serverCert, newCACert, &serverKey.PublicKey, caPrivKey)
if err != nil {
log.Fatalln("x509.CreateCertificate", err)
}
serverCertPEM := pem.EncodeToMemory(&pem.Block{
Type: "CERTIFICATE",
Bytes: certBytes,
})
serverCertPair, err := tls.X509KeyPair(serverCertPEM, serverKeyPEM)
handle(err)
oldPool := x509.NewCertPool()
oldPool.AppendCertsFromPEM(oldCACertPEM)
newPool := x509.NewCertPool()
newPool.AppendCertsFromPEM(newCACertPEM)
bothPool := x509.NewCertPool()
bothPool.AppendCertsFromPEM(oldCACertPEM)
bothPool.AppendCertsFromPEM(newCACertPEM)
okHandler := func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "OK\n") }
server := httptest.NewUnstartedServer(http.HandlerFunc(okHandler))
server.TLS = &tls.Config{
Certificates: []tls.Certificate{serverCertPair},
}
server.StartTLS()
defer server.Close()
log.Println("server running at:", server.URL)
err = runClient(server.URL, oldPool)
log.Println("Old pool, err:", err)
err = runClient(server.URL, newPool)
log.Println("New pool, err:", err)
err = runClient(server.URL, bothPool)
log.Println("Both pool, err:", err)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment