Peter Kurfer
a720b0ee41
* supports HTTP * support TLS interception e.g. for HTTPS * support CA generation via cli * first draft of plugin API * support commands from plugins * includes Dockerfile * includes basic configuration
106 lines
2.8 KiB
Go
106 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/ecdsa"
|
|
"crypto/ed25519"
|
|
"crypto/elliptic"
|
|
"crypto/rand"
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"encoding/pem"
|
|
"math/big"
|
|
"os"
|
|
)
|
|
|
|
type curveType string
|
|
|
|
const (
|
|
certificateBlockType = "CERTIFICATE"
|
|
privateKeyBlockType = "PRIVATE KEY"
|
|
|
|
curveTypeP224 curveType = "P224"
|
|
curveTypeP256 curveType = "P256"
|
|
curveTypeP384 curveType = "P384"
|
|
curveTypeP521 curveType = "P521"
|
|
curveTypeED25519 curveType = "ED25519"
|
|
)
|
|
|
|
func loadPEMCert(certPEMBytes []byte, keyPEMBytes []byte) (*tls.Certificate, error) {
|
|
cert, err := tls.X509KeyPair(certPEMBytes, keyPEMBytes)
|
|
return &cert, err
|
|
}
|
|
|
|
func parseCert(derBytes []byte, privateKeyBytes []byte) (*tls.Certificate, error) {
|
|
pemEncodedPublicKey := pem.EncodeToMemory(&pem.Block{Type: certificateBlockType, Bytes: derBytes})
|
|
pemEncodedPrivateKey := pem.EncodeToMemory(&pem.Block{Type: privateKeyBlockType, Bytes: privateKeyBytes})
|
|
cert, err := tls.X509KeyPair(pemEncodedPublicKey, pemEncodedPrivateKey)
|
|
return &cert, err
|
|
}
|
|
|
|
func writePublicKey(crtOutPath string, derBytes []byte) (err error) {
|
|
var certOut *os.File
|
|
if certOut, err = os.Create(crtOutPath); err != nil {
|
|
return
|
|
}
|
|
if err = pem.Encode(certOut, &pem.Block{Type: certificateBlockType, Bytes: derBytes}); err != nil {
|
|
return
|
|
}
|
|
err = certOut.Close()
|
|
return
|
|
}
|
|
|
|
func writePrivateKey(keyOutPath string, privateKeyBytes []byte) (err error) {
|
|
var keyOut *os.File
|
|
if keyOut, err = os.OpenFile(keyOutPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600); err != nil {
|
|
return
|
|
}
|
|
|
|
if err = pem.Encode(keyOut, &pem.Block{Type: privateKeyBlockType, Bytes: privateKeyBytes}); err != nil {
|
|
return
|
|
}
|
|
|
|
err = keyOut.Close()
|
|
return
|
|
}
|
|
|
|
func certShouldBeRenewed(timeSource timeSource, cert *x509.Certificate) bool {
|
|
lifetime := cert.NotAfter.Sub(cert.NotBefore)
|
|
// if the cert is closer to the end of the lifetime than lifetime/2 it should be renewed
|
|
if cert.NotAfter.Sub(timeSource.UTCNow()) < lifetime/4 {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func generateSerialNumber() (*big.Int, error) {
|
|
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
|
return rand.Int(rand.Reader, serialNumberLimit)
|
|
}
|
|
|
|
func privateKeyForCurve(options *tlsOptions) (privateKey interface{}, err error) {
|
|
switch options.ecdsaCurve {
|
|
case "P224":
|
|
privateKey, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
|
|
case "P256":
|
|
privateKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
|
case "P384":
|
|
privateKey, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
|
case "P521":
|
|
privateKey, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
|
default:
|
|
_, privateKey, err = ed25519.GenerateKey(rand.Reader)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func publicKey(privateKey interface{}) interface{} {
|
|
switch k := privateKey.(type) {
|
|
case *ecdsa.PrivateKey:
|
|
return &k.PublicKey
|
|
case ed25519.PrivateKey:
|
|
return k.Public().(ed25519.PublicKey)
|
|
default:
|
|
return nil
|
|
}
|
|
}
|