/* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at https://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package extlib import ( "bytes" "errors" "fmt" "strings" "crypto" "crypto/dsa" "crypto/ecdsa" "crypto/rand" "crypto/rsa" "crypto/x509" "encoding/asn1" "encoding/pem" "math/big" "net" ) // that pieces of code were copied from // https://github.com/Masterminds/sprig/blob/868e7517d046cb7540e10345b09c0d70da584c8e/crypto.go#L405 type certificate struct { Cert string Key string } // DSAKeyFormat stores the format for DSA keys. // Used by pemBlockForKey type DSAKeyFormat struct { Version int P, Q, G, Y, X *big.Int } func getCertAndKey( template *x509.Certificate, signeeKey crypto.PrivateKey, parent *x509.Certificate, signingKey crypto.PrivateKey, ) (string, string, error) { signeePubKey, err := getPublicKey(signeeKey) if err != nil { return "", "", fmt.Errorf("error retrieving public key from signee key: %s", err) } derBytes, err := x509.CreateCertificate( rand.Reader, template, parent, signeePubKey, signingKey, ) if err != nil { return "", "", fmt.Errorf("error creating certificate: %s", err) } certBuffer := bytes.Buffer{} if err := pem.Encode( &certBuffer, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}, ); err != nil { return "", "", fmt.Errorf("error pem-encoding certificate: %s", err) } keyBuffer := bytes.Buffer{} if err := pem.Encode( &keyBuffer, pemBlockForKey(signeeKey), ); err != nil { return "", "", fmt.Errorf("error pem-encoding key: %s", err) } return certBuffer.String(), keyBuffer.String(), nil } 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 *dsa.PrivateKey: val := DSAKeyFormat{ P: k.P, Q: k.Q, G: k.G, Y: k.Y, X: k.X, } bytes, err := asn1.Marshal(val) if err != nil { return nil } return &pem.Block{Type: "DSA PRIVATE KEY", Bytes: bytes} case *ecdsa.PrivateKey: b, err := x509.MarshalECPrivateKey(k) if err != nil { return nil } return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} default: // attempt PKCS#8 format for all other keys b, err := x509.MarshalPKCS8PrivateKey(k) if err != nil { return nil } return &pem.Block{Type: "PRIVATE KEY", Bytes: b} } } func parsePrivateKeyPEM(pemBlock string) (crypto.PrivateKey, error) { block, _ := pem.Decode([]byte(pemBlock)) if block == nil { return nil, errors.New("no PEM data in input") } if block.Type == "PRIVATE KEY" { priv, err := x509.ParsePKCS8PrivateKey(block.Bytes) if err != nil { return nil, fmt.Errorf("decoding PEM as PKCS#8: %s", err) } return priv, nil } else if !strings.HasSuffix(block.Type, " PRIVATE KEY") { return nil, fmt.Errorf("no private key data in PEM block of type %s", block.Type) } switch block.Type[:len(block.Type)-12] { // strip " PRIVATE KEY" case "RSA": priv, err := x509.ParsePKCS1PrivateKey(block.Bytes) if err != nil { return nil, fmt.Errorf("parsing RSA private key from PEM: %s", err) } return priv, nil case "EC": priv, err := x509.ParseECPrivateKey(block.Bytes) if err != nil { return nil, fmt.Errorf("parsing EC private key from PEM: %s", err) } return priv, nil case "DSA": var k DSAKeyFormat _, err := asn1.Unmarshal(block.Bytes, &k) if err != nil { return nil, fmt.Errorf("parsing DSA private key from PEM: %s", err) } priv := &dsa.PrivateKey{ PublicKey: dsa.PublicKey{ Parameters: dsa.Parameters{ P: k.P, Q: k.Q, G: k.G, }, Y: k.Y, }, X: k.X, } return priv, nil default: return nil, fmt.Errorf("invalid private key type %s", block.Type) } } func getPublicKey(priv crypto.PrivateKey) (crypto.PublicKey, error) { switch k := priv.(type) { case interface{ Public() crypto.PublicKey }: return k.Public(), nil case *dsa.PrivateKey: return &k.PublicKey, nil default: return nil, fmt.Errorf("unable to get public key for type %T", priv) } } func getNetIPs(ips []interface{}) ([]net.IP, error) { if ips == nil { return []net.IP{}, nil } var ipStr string var ok bool var netIP net.IP netIPs := make([]net.IP, len(ips)) for i, ip := range ips { ipStr, ok = ip.(string) if !ok { return nil, fmt.Errorf("error parsing ip: %v is not a string", ip) } netIP = net.ParseIP(ipStr) if netIP == nil { return nil, fmt.Errorf("error parsing ip: %s", ipStr) } netIPs[i] = netIP } return netIPs, nil } func getAlternateDNSStrs(alternateDNS []interface{}) ([]string, error) { if alternateDNS == nil { return []string{}, nil } var dnsStr string var ok bool alternateDNSStrs := make([]string, len(alternateDNS)) for i, dns := range alternateDNS { dnsStr, ok = dns.(string) if !ok { return nil, fmt.Errorf( "error processing alternate dns name: %v is not a string", dns, ) } alternateDNSStrs[i] = dnsStr } return alternateDNSStrs, nil }