Created
July 22, 2018 21:44
-
-
Save mdelillo/09a5332faf4371f38f920cc758eef72c to your computer and use it in GitHub Desktop.
Create a self-signed CA and use it to create a signed certificate
This file contains hidden or 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 ( | |
"bytes" | |
"crypto/rand" | |
"crypto/rsa" | |
"crypto/tls" | |
"crypto/x509" | |
"crypto/x509/pkix" | |
"encoding/pem" | |
"fmt" | |
"io/ioutil" | |
"log" | |
"math/big" | |
"time" | |
) | |
func main() { | |
caCertBytes, caKeyBytes, err := generateSelfSignedCA() | |
if err != nil { | |
log.Fatalf("Failed to generate CA: %s", err.Error()) | |
} | |
if err := ioutil.WriteFile("caCert.pem", caCertBytes, 0644); err != nil { | |
log.Fatalf("Failed to write caCert.pem: %s", err.Error()) | |
} | |
if err := ioutil.WriteFile("caKey.pem", caKeyBytes, 0600); err != nil { | |
log.Fatalf("Failed to write caKey.pem: %s", err.Error()) | |
} | |
certBytes, keyBytes, err := generateSignedCert(caCertBytes, caKeyBytes) | |
if err != nil { | |
log.Fatalf("Failed to generate signed certificate: %s", err.Error()) | |
} | |
if err := ioutil.WriteFile("cert.pem", certBytes, 0644); err != nil { | |
log.Fatalf("Failed to write cert.pem: %s", err.Error()) | |
} | |
if err := ioutil.WriteFile("key.pem", keyBytes, 0600); err != nil { | |
log.Fatalf("Failed to write key.pem: %s", err.Error()) | |
} | |
block, _ := pem.Decode(certBytes) | |
if block == nil { | |
log.Fatal("Failed to decode certificate") | |
} | |
cert, err := x509.ParseCertificate(block.Bytes) | |
if err != nil { | |
log.Fatalf("Failed to parse certificate: %s", err.Error()) | |
} | |
roots := x509.NewCertPool() | |
roots.AppendCertsFromPEM(caCertBytes) | |
if _, err := cert.Verify(x509.VerifyOptions{Roots: roots}); err != nil { | |
log.Fatalf("Verification failed: %s", err.Error()) | |
} | |
fmt.Println("Verification succeeded") | |
} | |
func generateSelfSignedCA() ([]byte, []byte, error) { | |
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 256) | |
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) | |
if err != nil { | |
return nil, nil, fmt.Errorf("failed to generate serial number: %s", err) | |
} | |
template := &x509.Certificate{ | |
SerialNumber: serialNumber, | |
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, | |
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, | |
NotBefore: time.Now(), | |
NotAfter: time.Now().Add(time.Hour * 24 * 30), | |
Subject: pkix.Name{CommonName: "my-ca"}, | |
IsCA: true, | |
MaxPathLenZero: true, | |
BasicConstraintsValid: true, | |
} | |
key, err := rsa.GenerateKey(rand.Reader, 4096) | |
if err != nil { | |
return nil, nil, fmt.Errorf("failed to generate key: %s", err) | |
} | |
derBytes, err := x509.CreateCertificate(rand.Reader, template, template, &key.PublicKey, key) | |
if err != nil { | |
return nil, nil, fmt.Errorf("failed to create certificate: %s", err) | |
} | |
var certPem, keyPem bytes.Buffer | |
if err := pem.Encode(&certPem, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { | |
return nil, nil, fmt.Errorf("failed to encode certificate: %s", err) | |
} | |
if err := pem.Encode(&keyPem, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}); err != nil { | |
return nil, nil, fmt.Errorf("failed to encode key: %s", err) | |
} | |
return certPem.Bytes(), keyPem.Bytes(), nil | |
} | |
func generateSignedCert(caCertBytes, caKeyBytes []byte) ([]byte, []byte, error) { | |
key, err := rsa.GenerateKey(rand.Reader, 4096) | |
if err != nil { | |
return nil, nil, fmt.Errorf("failed to generate key: %s", err) | |
} | |
csrDerBytes, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{}, key) | |
if err != nil { | |
return nil, nil, fmt.Errorf("failed to generate csr: %s", err.Error()) | |
} | |
csr, err := x509.ParseCertificateRequest(csrDerBytes) | |
if err != nil { | |
return nil, nil, fmt.Errorf("failed to parse csr: %s", err.Error()) | |
} | |
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 256) | |
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) | |
if err != nil { | |
return nil, nil, fmt.Errorf("failed to generate serial number: %s", err) | |
} | |
template := &x509.Certificate{ | |
SerialNumber: serialNumber, | |
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, | |
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, | |
NotBefore: time.Now(), | |
NotAfter: time.Now().Add(time.Hour * 24 * 30), | |
Subject: pkix.Name{CommonName: "my-cert"}, | |
} | |
caTLS, err := tls.X509KeyPair(caCertBytes, caKeyBytes) | |
if err != nil { | |
return nil, nil, fmt.Errorf("failed to load CA key pair: %s", err) | |
} | |
ca, err := x509.ParseCertificate(caTLS.Certificate[0]) | |
if err != nil { | |
return nil, nil, fmt.Errorf("failed to parse CA certificate: %s", err) | |
} | |
derBytes, err := x509.CreateCertificate(rand.Reader, template, ca, csr.PublicKey, caTLS.PrivateKey) | |
if err != nil { | |
return nil, nil, fmt.Errorf("failed to create certificate: %s", err) | |
} | |
var certPem, keyPem bytes.Buffer | |
if err := pem.Encode(&certPem, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { | |
return nil, nil, fmt.Errorf("failed to encode certificate: %s", err) | |
} | |
if err := pem.Encode(&keyPem, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}); err != nil { | |
return nil, nil, fmt.Errorf("failed to encode key: %s", err) | |
} | |
return certPem.Bytes(), keyPem.Bytes(), nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment