github.com/turingchain2020/turingchain@v1.1.21/system/dapp/commands/cert.go (about) 1 package commands 2 3 import ( 4 "crypto/ecdsa" 5 "crypto/elliptic" 6 "crypto/rand" 7 "crypto/rsa" 8 "crypto/x509" 9 "crypto/x509/pkix" 10 "encoding/pem" 11 "fmt" 12 "math/big" 13 "net" 14 "os" 15 "strings" 16 "time" 17 18 "github.com/spf13/cobra" 19 ) 20 21 //CertCmd generate cert 22 func CertCmd() *cobra.Command { 23 cmd := &cobra.Command{ 24 Use: "cert", 25 Short: "generate cert", 26 Run: func(cmd *cobra.Command, args []string) { 27 host, _ := cmd.Flags().GetString("host") 28 validFrom, _ := cmd.Flags().GetString("start-date") 29 ecdsaCurve, _ := cmd.Flags().GetString("ecdsa-curve") 30 rsaBits, _ := cmd.Flags().GetInt("rsa-bits") 31 isCA, _ := cmd.Flags().GetBool("ca") 32 validFor, _ := cmd.Flags().GetDuration("duration") 33 certGenerate(host, validFrom, ecdsaCurve, rsaBits, isCA, validFor) 34 }, 35 } 36 addCertFlags(cmd) 37 return cmd 38 } 39 40 func addCertFlags(cmd *cobra.Command) { 41 cmd.Flags().StringP("host", "", "", "Comma-separated hostnames and IPs to generate a certificate for") 42 cmd.Flags().StringP("start-date", "", "", "Creation date formatted as Jan 1 15:04:05 2011") 43 cmd.Flags().StringP("ecdsa-curve", "", "", "ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521") 44 cmd.Flags().IntP("rsa-bits", "", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set") 45 cmd.Flags().Bool("ca", false, "whether this cert should be its own Certificate Authority") 46 cmd.Flags().Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for") 47 cmd.MarkFlagRequired("host") 48 } 49 50 func publicKey(priv interface{}) interface{} { 51 switch k := priv.(type) { 52 case *rsa.PrivateKey: 53 return &k.PublicKey 54 case *ecdsa.PrivateKey: 55 return &k.PublicKey 56 default: 57 return nil 58 } 59 } 60 61 func pemBlockForKey(priv interface{}) *pem.Block { 62 switch k := priv.(type) { 63 case *rsa.PrivateKey: 64 return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(k)} 65 case *ecdsa.PrivateKey: 66 b, err := x509.MarshalECPrivateKey(k) 67 if err != nil { 68 fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err) 69 os.Exit(2) 70 } 71 return &pem.Block{Type: "EC PRIVATE KEY", Bytes: b} 72 default: 73 return nil 74 } 75 } 76 77 func certGenerate(host, validFrom, ecdsaCurve string, rsaBits int, isCA bool, validFor time.Duration) { 78 var priv interface{} 79 var err error 80 switch ecdsaCurve { 81 case "": 82 priv, err = rsa.GenerateKey(rand.Reader, rsaBits) 83 case "P224": 84 priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader) 85 case "P256": 86 priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) 87 case "P384": 88 priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader) 89 case "P521": 90 priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader) 91 default: 92 fmt.Fprintf(os.Stderr, "Unrecognized elliptic curve: %q", ecdsaCurve) 93 os.Exit(1) 94 } 95 if err != nil { 96 fmt.Fprintf(os.Stderr, "failed to generate private key: %s\n", err) 97 os.Exit(1) 98 } 99 100 var notBefore time.Time 101 if len(validFrom) == 0 { 102 notBefore = time.Now() 103 } else { 104 notBefore, err = time.Parse("Jan 2 15:04:05 2006", validFrom) 105 if err != nil { 106 fmt.Fprintf(os.Stderr, "Failed to parse creation date: %s\n", err) 107 os.Exit(1) 108 } 109 } 110 111 notAfter := notBefore.Add(validFor) 112 113 serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) 114 serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) 115 if err != nil { 116 fmt.Fprintf(os.Stderr, "failed to generate serial number: %s", err) 117 os.Exit(1) 118 } 119 120 template := x509.Certificate{ 121 SerialNumber: serialNumber, 122 Subject: pkix.Name{ 123 Organization: []string{"Acme Co"}, 124 }, 125 NotBefore: notBefore, 126 NotAfter: notAfter, 127 128 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 129 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, 130 BasicConstraintsValid: true, 131 } 132 133 hosts := strings.Split(host, ",") 134 for _, h := range hosts { 135 if ip := net.ParseIP(h); ip != nil { 136 template.IPAddresses = append(template.IPAddresses, ip) 137 } else { 138 template.DNSNames = append(template.DNSNames, h) 139 } 140 } 141 142 if isCA { 143 template.IsCA = true 144 template.KeyUsage |= x509.KeyUsageCertSign 145 } 146 147 derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv) 148 if err != nil { 149 fmt.Fprintf(os.Stderr, "Failed to create certificate: %s", err) 150 os.Exit(1) 151 } 152 153 certOut, err := os.Create("cert.pem") 154 if err != nil { 155 fmt.Fprintf(os.Stderr, "failed to open cert.pem for writing: %s", err) 156 os.Exit(1) 157 } 158 if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { 159 fmt.Fprintf(os.Stderr, "failed to write data to cert.pem: %s", err) 160 os.Exit(1) 161 } 162 if err := certOut.Close(); err != nil { 163 fmt.Fprintf(os.Stderr, "error closing cert.pem: %s", err) 164 os.Exit(1) 165 } 166 fmt.Print("wrote cert.pem\n") 167 168 keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) 169 if err != nil { 170 fmt.Fprintf(os.Stderr, "failed to open key.pem for writing: %s", err) 171 os.Exit(1) 172 } 173 if err := pem.Encode(keyOut, pemBlockForKey(priv)); err != nil { 174 fmt.Fprintf(os.Stderr, "failed to write data to key.pem: %s", err) 175 os.Exit(1) 176 } 177 if err := keyOut.Close(); err != nil { 178 fmt.Fprintf(os.Stderr, "error closing key.pem: %s", err) 179 os.Exit(1) 180 } 181 fmt.Print("wrote key.pem\n") 182 }