github.com/hoffie/larasync@v0.0.0-20151025221940-0384d2bddcef/helpers/x509/generate.go (about)

     1  package x509
     2  
     3  import (
     4  	"crypto/ecdsa"
     5  	"crypto/elliptic"
     6  	"crypto/rand"
     7  	"crypto/x509"
     8  	"crypto/x509/pkix"
     9  	"encoding/pem"
    10  	"io"
    11  	"math/big"
    12  	"os"
    13  	"time"
    14  )
    15  
    16  const (
    17  	certFileName = "lara-server.crt"
    18  	keyFileName  = "lara-server.key"
    19  )
    20  
    21  // GenerateServerCert generates a new server certificate, writing the resulting
    22  // keys and certificates to the provided writers.
    23  func GenerateServerCert(keyOut, certOut io.Writer) error {
    24  	// inspired by crypto/tls/generate_cert.go
    25  	priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
    26  	if err != nil {
    27  		return err
    28  	}
    29  	serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
    30  	serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
    31  	if err != nil {
    32  		return err
    33  	}
    34  	notBefore := time.Now()
    35  	notAfter := notBefore.Add(128 * 365 * 24 * time.Hour)
    36  
    37  	template := x509.Certificate{
    38  		SerialNumber: serialNumber,
    39  		Subject: pkix.Name{
    40  			Organization: []string{"larasync server certificate"},
    41  		},
    42  		NotBefore: notBefore,
    43  		NotAfter:  notAfter,
    44  
    45  		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
    46  		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
    47  		BasicConstraintsValid: true,
    48  	}
    49  
    50  	derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template,
    51  		&priv.PublicKey, priv)
    52  	if err != nil {
    53  		return err
    54  	}
    55  
    56  	pemBlock, err := pemBlockForKey(priv)
    57  	if err != nil {
    58  		return err
    59  	}
    60  	err = pem.Encode(keyOut, pemBlock)
    61  	if err != nil {
    62  		return err
    63  	}
    64  
    65  	err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
    66  	if err != nil {
    67  		return err
    68  	}
    69  
    70  	return nil
    71  }
    72  
    73  // pemBlockForKey returns a pem block containing the given private key.
    74  func pemBlockForKey(k *ecdsa.PrivateKey) (*pem.Block, error) {
    75  	b, err := x509.MarshalECPrivateKey(k)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}, nil
    80  }
    81  
    82  // GenerateServerCertFiles creates a certificate and a key file at the given
    83  // locations.
    84  func GenerateServerCertFiles(certFile, keyFile string) error {
    85  	certOut, err := os.OpenFile(certFile, os.O_CREATE|os.O_WRONLY, 0600)
    86  	if err != nil {
    87  		return err
    88  	}
    89  	defer certOut.Close()
    90  
    91  	keyOut, err := os.OpenFile(keyFile, os.O_CREATE|os.O_WRONLY, 0600)
    92  	if err != nil {
    93  		return err
    94  	}
    95  	defer keyOut.Close()
    96  
    97  	return GenerateServerCert(keyOut, certOut)
    98  }