Beispiel #1
0
func main() {
	cfg := config{
		Years:        10,
		Organization: "gencerts",
	}
	parser := flags.NewParser(&cfg, flags.Default)
	_, err := parser.Parse()
	if err != nil {
		if e, ok := err.(*flags.Error); !ok || e.Type != flags.ErrHelp {
			parser.WriteHelp(os.Stderr)
		}
		return
	}

	if cfg.Directory == "" {
		var err error
		cfg.Directory, err = os.Getwd()
		if err != nil {
			fmt.Fprintf(os.Stderr, "no directory specified and cannot get working directory\n")
			os.Exit(1)
		}
	}
	cfg.Directory = cleanAndExpandPath(cfg.Directory)
	certFile := filepath.Join(cfg.Directory, "rpc.cert")
	keyFile := filepath.Join(cfg.Directory, "rpc.key")

	if !cfg.Force {
		if fileExists(certFile) || fileExists(keyFile) {
			fmt.Fprintf(os.Stderr, "%v: certificate and/or key files exist; use -f to force\n", cfg.Directory)
			os.Exit(1)
		}
	}

	validUntil := time.Now().Add(time.Duration(cfg.Years) * 365 * 24 * time.Hour)
	cert, key, err := btcutil.NewTLSCertPair(cfg.Organization, validUntil, cfg.ExtraHosts)
	if err != nil {
		fmt.Fprintf(os.Stderr, "cannot generate certificate pair: %v\n", err)
		os.Exit(1)
	}

	// Write cert and key files.
	if err = ioutil.WriteFile(certFile, cert, 0666); err != nil {
		fmt.Fprintf(os.Stderr, "cannot write cert: %v\n", err)
		os.Exit(1)
	}
	if err = ioutil.WriteFile(keyFile, key, 0600); err != nil {
		os.Remove(certFile)
		fmt.Fprintf(os.Stderr, "cannot write key: %v\n", err)
		os.Exit(1)
	}
}
Beispiel #2
0
// generateRPCKeyPair generates a new RPC TLS keypair and writes the cert and
// possibly also the key in PEM format to the paths specified by the config.  If
// successful, the new keypair is returned.
func generateRPCKeyPair(writeKey bool) (tls.Certificate, error) {
	log.Infof("Generating TLS certificates...")

	// Create directories for cert and key files if they do not yet exist.
	certDir, _ := filepath.Split(cfg.RPCCert)
	keyDir, _ := filepath.Split(cfg.RPCKey)
	err := os.MkdirAll(certDir, 0700)
	if err != nil {
		return tls.Certificate{}, err
	}
	err = os.MkdirAll(keyDir, 0700)
	if err != nil {
		return tls.Certificate{}, err
	}

	// Generate cert pair.
	org := "btcwallet autogenerated cert"
	validUntil := time.Now().Add(time.Hour * 24 * 365 * 10)
	cert, key, err := btcutil.NewTLSCertPair(org, validUntil, nil)
	if err != nil {
		return tls.Certificate{}, err
	}
	keyPair, err := tls.X509KeyPair(cert, key)
	if err != nil {
		return tls.Certificate{}, err
	}

	// Write cert and (potentially) the key files.
	err = ioutil.WriteFile(cfg.RPCCert, cert, 0600)
	if err != nil {
		return tls.Certificate{}, err
	}
	if writeKey {
		err = ioutil.WriteFile(cfg.RPCKey, key, 0600)
		if err != nil {
			rmErr := os.Remove(cfg.RPCCert)
			if rmErr != nil {
				log.Warnf("Cannot remove written certificates: %v",
					rmErr)
			}
			return tls.Certificate{}, err
		}
	}

	log.Info("Done generating TLS certificates")
	return keyPair, nil
}
Beispiel #3
0
// genCertPair generates a key/cert pair to the paths provided.
func genCertPair(certFile, keyFile string) error {
	org := "btcsim autogenerated cert"
	validUntil := time.Now().Add(10 * 365 * 24 * time.Hour)
	cert, key, err := btcutil.NewTLSCertPair(org, validUntil, nil)
	if err != nil {
		return err
	}

	// Write cert and key files.
	if err = ioutil.WriteFile(certFile, cert, 0666); err != nil {
		return err
	}
	if err = ioutil.WriteFile(keyFile, key, 0600); err != nil {
		os.Remove(certFile)
		return err
	}

	return nil
}
Beispiel #4
0
// TestNewTLSCertPair ensures the NewTLSCertPair function works as expected.
func TestNewTLSCertPair(t *testing.T) {
	// Certs don't support sub-second precision, so truncate it now to
	// ensure the checks later don't fail due to nanosecond precision
	// differences.
	validUntil := time.Unix(time.Now().Add(10*365*24*time.Hour).Unix(), 0)
	org := "test autogenerated cert"
	extraHosts := []string{"testtlscert.bogus", "localhost", "127.0.0.1"}
	cert, key, err := btcutil.NewTLSCertPair(org, validUntil, extraHosts)
	if err != nil {
		t.Fatalf("failed with unexpected error: %v", err)
	}

	// Ensure the PEM-encoded cert that is returned can be decoded.
	pemCert, _ := pem.Decode(cert)
	if pemCert == nil {
		t.Fatalf("pem.Decode was unable to decode the certificate")
	}

	// Ensure the PEM-encoded key that is returned can be decoded.
	pemKey, _ := pem.Decode(key)
	if pemCert == nil {
		t.Fatalf("pem.Decode was unable to decode the key")
	}

	// Ensure the DER-encoded key bytes can be successfully parsed.
	_, err = x509.ParseECPrivateKey(pemKey.Bytes)
	if err != nil {
		t.Fatalf("failed with unexpected error: %v", err)
	}

	// Ensure the DER-encoded cert bytes can be successfully into an X.509
	// certificate.
	x509Cert, err := x509.ParseCertificate(pemCert.Bytes)
	if err != nil {
		t.Fatalf("failed with unexpected error: %v", err)
	}

	// Ensure the specified organization is correct.
	x509Orgs := x509Cert.Subject.Organization
	if len(x509Orgs) == 0 || x509Orgs[0] != org {
		x509Org := "<no organization>"
		if len(x509Orgs) > 0 {
			x509Org = x509Orgs[0]
		}
		t.Fatalf("generated cert organization field mismatch, got "+
			"'%v', want '%v'", x509Org, org)
	}

	// Ensure the specified valid until value is correct.
	if !x509Cert.NotAfter.Equal(validUntil) {
		t.Fatalf("generated cert valid until field mismatch, got %v, "+
			"want %v", x509Cert.NotAfter, validUntil)
	}

	// Ensure the specified extra hosts are present.
	for _, host := range extraHosts {
		if err := x509Cert.VerifyHostname(host); err != nil {
			t.Fatalf("failed to verify extra host '%s'", host)
		}
	}

	// Ensure that the Common Name is also the first SAN DNS name.
	cn := x509Cert.Subject.CommonName
	san0 := x509Cert.DNSNames[0]
	if cn != san0 {
		t.Errorf("common name %s does not match first SAN %s", cn, san0)
	}

	// Ensure there are no duplicate hosts or IPs.
	hostCounts := make(map[string]int)
	for _, host := range x509Cert.DNSNames {
		hostCounts[host]++
	}
	ipCounts := make(map[string]int)
	for _, ip := range x509Cert.IPAddresses {
		ipCounts[string(ip)]++
	}
	for host, count := range hostCounts {
		if count != 1 {
			t.Errorf("host %s appears %d times in certificate", host, count)
		}
	}
	for ipStr, count := range ipCounts {
		if count != 1 {
			t.Errorf("ip %s appears %d times in certificate", net.IP(ipStr), count)
		}
	}

	// Ensure the cert can be use for the intended purposes.
	if !x509Cert.IsCA {
		t.Fatal("generated cert is not a certificate authority")
	}
	if x509Cert.KeyUsage&x509.KeyUsageKeyEncipherment == 0 {
		t.Fatal("generated cert can't be used for key encipherment")
	}
	if x509Cert.KeyUsage&x509.KeyUsageDigitalSignature == 0 {
		t.Fatal("generated cert can't be used for digital signatures")
	}
	if x509Cert.KeyUsage&x509.KeyUsageCertSign == 0 {
		t.Fatal("generated cert can't be used for signing other certs")
	}
	if !x509Cert.BasicConstraintsValid {
		t.Fatal("generated cert does not have valid basic constraints")
	}
}