/* Copyright © 2021 Arsen Musayelyan This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package cmd import ( "crypto/ed25519" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "math/big" "net" "os" "time" "github.com/rs/zerolog/log" "github.com/spf13/cobra" ) // gencertCmd represents the gencert command var gencertCmd = &cobra.Command{ Use: "gencert ", Short: "Generate self-signed TLS certificate for master server", Run: func(cmd *cobra.Command, args []string) { if len(args) < 2 { cmd.Usage() os.Exit(1) } // Generate an ed25519 key from rand reader pub, priv, _ := ed25519.GenerateKey(rand.Reader) // Get current time to use for cert creation time notBefore := time.Now() // Get expiration time 10 years from now notAfter := notBefore.Add(time.Hour * 24 * 365 * 10) // Set limit for serial number serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) // Create random serial number serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) if err != nil { log.Fatal().Err(err).Msg("Failed to generate serial number") } // Get local IP ip, err := localIP() if err != nil { log.Fatal().Err(err).Msg("Error getting local IP") } // Create x509 certificate template template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"Lasso"}, }, NotBefore: notBefore, NotAfter: notAfter, KeyUsage: x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, IPAddresses: []net.IP{net.ParseIP(ip)}, } // Create certificate derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, pub, priv) if err != nil { log.Fatal().Err(err).Msg("Failed to create certificate") } // Create certificate output file certOut, err := os.Create(args[0]) if err != nil { log.Fatal().Err(err).Msg("Failed to open cert file for writing") } // Enode certificate as PEM file if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { log.Fatal().Err(err).Msg("Failed to write data to cert file") } // Close certificate file certOut.Close() log.Info().Str("path", args[0]).Msg("Wrote cert file") // Create key output file keyOut, err := os.OpenFile(args[1], os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) if err != nil { log.Fatal().Err(err).Msg("Failed to open key file for writing") return } // Encode private key as PKCS8 privBytes, err := x509.MarshalPKCS8PrivateKey(priv) if err != nil { log.Fatal().Err(err).Msg("Unable to marshal private key file") } // Encode private key as PEM if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil { log.Fatal().Err(err).Msg("Failed to write data to key file") } // Close key file keyOut.Close() log.Info().Str("path", args[1]).Msg("Wrote key file") }, } func init() { rootCmd.AddCommand(gencertCmd) }