api/pkg/plugins/tls_interceptor/certs.go
Peter Kurfer a720b0ee41
Initial working version
* 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
2020-04-01 04:08:21 +02:00

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
}
}