diff --git a/certgen/certgen.go b/certgen/certgen.go new file mode 100644 index 0000000..f1e9d61 --- /dev/null +++ b/certgen/certgen.go @@ -0,0 +1,115 @@ +package certgen + +import ( + "bytes" + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "encoding/json" + "encoding/pem" + "fmt" + "math/big" + "os" + "time" + + "github.com/lestrrat-go/jwx/jwk" +) + +func ExtractPublicKey(priv interface{}) interface{} { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &k.PublicKey + case *ecdsa.PrivateKey: + return &k.PublicKey + default: + return nil + } +} + +func PublicKeyToJWKJson(pub interface{}) ([]byte, error) { + jk, err := jwk.New(pub) + + if err != nil { + return nil, err + } + + return json.Marshal(jk) +} + +func StringToJWK(in string) (jwk.Key, error) { + set, err := jwk.ParseString(in) + + if err != nil { + return nil, err + } + + k, ok := set.Get(0) + + if !ok { + return nil, fmt.Errorf("No key found") + } + + return k, nil +} + +func PublicKeyToJWK(pub interface{}) (jwk.Key, error) { + return jwk.New(pub) +} + +func pemBlockForKey(priv interface{}) *pem.Block { + switch k := priv.(type) { + case *rsa.PrivateKey: + return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} + case *ecdsa.PrivateKey: + b, err := x509.MarshalECPrivateKey(k) + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err) + os.Exit(2) + } + return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} + default: + return nil + } +} + +func GenCert(org, cn string) (priv *ecdsa.PrivateKey, cert *x509.Certificate, certPem string, keyPem string, err error) { + priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + return nil, nil, "", "", fmt.Errorf("Failed to create key: %s", err) + } + + template := x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{org}, + CommonName: cn, + }, + NotBefore: time.Now(), + NotAfter: time.Now().Add(time.Hour * 24 * 180), + + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, ExtractPublicKey(priv), priv) + + if err != nil { + return nil, nil, "", "", fmt.Errorf("Failed to create certificate: %s", err) + } + + out := &bytes.Buffer{} + pem.Encode(out, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) + certPem = out.String() + out.Reset() + + pem.Encode(out, pemBlockForKey(priv)) + keyPem = out.String() + + cert, err = x509.ParseCertificate(derBytes) + + return priv, cert, certPem, keyPem, err +}