Last active
December 17, 2019 18:17
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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