func TestCAIssuing(t *testing.T) {
	var caCerts = []string{testCaFile, testECDSACaFile}
	var caKeys = []string{testCaKeyFile, testECDSACaKeyFile}
	var interCSRs = []string{ecdsaInterCSR, rsaInterCSR}
	var interKeys = []string{ecdsaInterKey, rsaInterKey}
	var CAPolicy = &config.Signing{
		Default: &config.SigningProfile{
			Usage:        []string{"cert sign", "crl sign"},
			ExpiryString: "1h",
			Expiry:       1 * time.Hour,
			CA:           true,
		},
	}
	var hostname = "cloudflare-inter.com"
	// Each RSA or ECDSA root CA issues two intermediate CAs (one ECDSA and one RSA).
	// For each intermediate CA, use it to issue additional RSA and ECDSA intermediate CSRs.
	for i, caFile := range caCerts {
		caKeyFile := caKeys[i]
		s := newCustomSigner(t, caFile, caKeyFile)
		s.policy = CAPolicy
		for j, csr := range interCSRs {
			csrBytes, _ := ioutil.ReadFile(csr)
			certBytes, err := s.Sign(signer.SignRequest{Hosts: signer.SplitHosts(hostname), Request: string(csrBytes)})
			if err != nil {
				t.Fatal(err)
			}
			interCert, err := helpers.ParseCertificatePEM(certBytes)
			if err != nil {
				t.Fatal(err)
			}
			keyBytes, _ := ioutil.ReadFile(interKeys[j])
			interKey, _ := helpers.ParsePrivateKeyPEM(keyBytes)
			interSigner := &Signer{
				ca:      interCert,
				priv:    interKey,
				policy:  CAPolicy,
				sigAlgo: signer.DefaultSigAlgo(interKey),
			}
			for _, anotherCSR := range interCSRs {
				anotherCSRBytes, _ := ioutil.ReadFile(anotherCSR)
				bytes, err := interSigner.Sign(
					signer.SignRequest{
						Hosts:   signer.SplitHosts(hostname),
						Request: string(anotherCSRBytes),
					})
				if err != nil {
					t.Fatal(err)
				}
				cert, err := helpers.ParseCertificatePEM(bytes)
				if err != nil {
					t.Fatal(err)
				}
				if cert.SignatureAlgorithm != interSigner.SigAlgo() {
					t.Fatal("Cert Signature Algorithm does not match the issuer.")
				}
			}
		}
	}

}
func makeCASigner(certBytes, keyBytes []byte, sigAlgo x509.SignatureAlgorithm, t *testing.T) signer.Signer {
	cert, err := helpers.ParseCertificatePEM(certBytes)
	if err != nil {
		t.Fatal(err)
	}

	key, err := helpers.ParsePrivateKeyPEM(keyBytes)
	if err != nil {
		t.Fatal(err)
	}

	defaultProfile := &config.SigningProfile{
		Usage:        []string{"cert sign"},
		CAConstraint: config.CAConstraint{IsCA: true},
		Expiry:       time.Hour,
		ExpiryString: "1h",
	}
	policy := &config.Signing{
		Profiles: map[string]*config.SigningProfile{},
		Default:  defaultProfile,
	}
	s, err := local.NewSigner(key, cert, sigAlgo, policy)
	if err != nil {
		t.Fatal(err)
	}

	return s
}
Пример #3
0
func TestReGenerate(t *testing.T) {
	var req = &CertificateRequest{
		Names: []Name{
			{
				C:  "US",
				ST: "California",
				L:  "San Francisco",
				O:  "CloudFlare",
				OU: "Systems Engineering",
			},
		},
		CN:         "cloudflare.com",
		Hosts:      []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1"},
		KeyRequest: &BasicKeyRequest{"ecdsa", 256},
	}

	csr, key, err := ParseRequest(req)
	if err != nil {
		t.Fatalf("%v", err)
	}

	priv, err := helpers.ParsePrivateKeyPEM(key)
	if err != nil {
		t.Fatalf("%v", err)
	}

	csr, err = Generate(priv, req)
	if err != nil {
		t.Fatalf("%v", err)
	}

	if _, _, err = helpers.ParseCSR(csr); err != nil {
		t.Fatalf("%v", err)
	}
}
Пример #4
0
// NewSignerFromFile generates a new local signer from a caFile
// and a caKey file, both PEM encoded.
func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signer, error) {
	log.Debug("Loading CA: ", caFile)
	ca, err := ioutil.ReadFile(caFile)
	if err != nil {
		return nil, err
	}
	log.Debug("Loading CA key: ", caKeyFile)
	cakey, err := ioutil.ReadFile(caKeyFile)
	if err != nil {
		return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err)
	}

	parsedCa, err := helpers.ParseCertificatePEM(ca)
	if err != nil {
		return nil, err
	}

	priv, err := helpers.ParsePrivateKeyPEM(cakey)
	if err != nil {
		log.Debug("Malformed private key %v", err)
		return nil, err
	}

	return NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy)
}
Пример #5
0
// NewSignerFromFile reads the issuer cert, the responder cert and the responder key
// from PEM files, and takes an interval in seconds
func NewSignerFromFile(issuerFile, responderFile, keyFile string, interval time.Duration) (Signer, error) {
	log.Debug("Loading issuer cert: ", issuerFile)
	issuerBytes, err := ioutil.ReadFile(issuerFile)
	if err != nil {
		return nil, err
	}
	log.Debug("Loading responder cert: ", responderFile)
	responderBytes, err := ioutil.ReadFile(responderFile)
	if err != nil {
		return nil, err
	}
	log.Debug("Loading responder key: ", keyFile)
	keyBytes, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err)
	}

	issuerCert, err := helpers.ParseCertificatePEM(issuerBytes)
	if err != nil {
		return nil, err
	}

	responderCert, err := helpers.ParseCertificatePEM(responderBytes)
	if err != nil {
		return nil, err
	}

	key, err := helpers.ParsePrivateKeyPEM(keyBytes)
	if err != nil {
		log.Debug("Malformed private key %v", err)
		return nil, err
	}

	return NewSigner(issuerCert, responderCert, key, interval)
}
Пример #6
0
// LoadKey attempts to load a private key from PEM or DER.
func LoadKey(in []byte) (priv crypto.Signer, err error) {
	priv, err = helpers.ParsePrivateKeyPEM(in)
	if err == nil {
		return priv, nil
	}

	return derhelpers.ParsePrivateKeyDER(in)
}
Пример #7
0
// createAndWriteca.RootCA creates a Certificate authority for a new Swarm Cluster.
// We're copying CreateAndWriteca.RootCA, so we can have smaller key-sizes for tests
func createAndWriteRootCA(rootCN string, paths ca.CertPaths, expiry time.Duration) (ca.RootCA, error) {
	// Create a simple CSR for the CA using the default CA validator and policy
	req := cfcsr.CertificateRequest{
		CN:         rootCN,
		KeyRequest: cfcsr.NewBasicKeyRequest(),
		CA:         &cfcsr.CAConfig{Expiry: ca.RootCAExpiration},
	}

	// Generate the CA and get the certificate and private key
	cert, _, key, err := initca.New(&req)
	if err != nil {
		return ca.RootCA{}, err
	}

	// Convert the key given by initca to an object to create a ca.RootCA
	parsedKey, err := helpers.ParsePrivateKeyPEM(key)
	if err != nil {
		log.Errorf("failed to parse private key: %v", err)
		return ca.RootCA{}, err
	}

	// Convert the certificate into an object to create a ca.RootCA
	parsedCert, err := helpers.ParseCertificatePEM(cert)
	if err != nil {
		return ca.RootCA{}, err
	}

	// Create a Signer out of the private key
	signer, err := local.NewSigner(parsedKey, parsedCert, cfsigner.DefaultSigAlgo(parsedKey), ca.SigningPolicy(expiry))
	if err != nil {
		log.Errorf("failed to create signer: %v", err)
		return ca.RootCA{}, err
	}

	// Ensure directory exists
	err = os.MkdirAll(filepath.Dir(paths.Cert), 0755)
	if err != nil {
		return ca.RootCA{}, err
	}

	// Write the Private Key and Certificate to disk, using decent permissions
	if err := ioutils.AtomicWriteFile(paths.Cert, cert, 0644); err != nil {
		return ca.RootCA{}, err
	}
	if err := ioutils.AtomicWriteFile(paths.Key, key, 0600); err != nil {
		return ca.RootCA{}, err
	}

	// Create a Pool with our Root CA Certificate
	pool := x509.NewCertPool()
	if !pool.AppendCertsFromPEM(cert) {
		return ca.RootCA{}, fmt.Errorf("failed to append certificate to cert pool")
	}

	return ca.RootCA{Signer: signer, Key: key, Cert: cert, Pool: pool}, nil
}
Пример #8
0
// createAndWriteRootCA creates a Certificate authority for a new Swarm Cluster.
// We're copying ca.CreateRootCA, so we can have smaller key-sizes for tests
func createAndWriteRootCA(rootCN string, paths ca.CertPaths, expiry time.Duration) (ca.RootCA, error) {
	cert, key, err := CreateRootCertAndKey(rootCN)
	if err != nil {
		return ca.RootCA{}, err
	}

	// Convert the key given by initca to an object to create a ca.RootCA
	parsedKey, err := helpers.ParsePrivateKeyPEM(key)
	if err != nil {
		log.Errorf("failed to parse private key: %v", err)
		return ca.RootCA{}, err
	}

	// Convert the certificate into an object to create a ca.RootCA
	parsedCert, err := helpers.ParseCertificatePEM(cert)
	if err != nil {
		return ca.RootCA{}, err
	}

	// Create a Signer out of the private key
	signer, err := local.NewSigner(parsedKey, parsedCert, cfsigner.DefaultSigAlgo(parsedKey), ca.SigningPolicy(expiry))
	if err != nil {
		log.Errorf("failed to create signer: %v", err)
		return ca.RootCA{}, err
	}

	// Ensure directory exists
	err = os.MkdirAll(filepath.Dir(paths.Cert), 0755)
	if err != nil {
		return ca.RootCA{}, err
	}

	// Write the Private Key and Certificate to disk, using decent permissions
	if err := ioutils.AtomicWriteFile(paths.Cert, cert, 0644); err != nil {
		return ca.RootCA{}, err
	}
	if err := ioutils.AtomicWriteFile(paths.Key, key, 0600); err != nil {
		return ca.RootCA{}, err
	}

	// Create a Pool with our Root CA Certificate
	pool := x509.NewCertPool()
	if !pool.AppendCertsFromPEM(cert) {
		return ca.RootCA{}, errors.New("failed to append certificate to cert pool")
	}

	return ca.RootCA{
		Signer: signer,
		Key:    key,
		Cert:   cert,
		Pool:   pool,
		Digest: digest.FromBytes(cert),
	}, nil
}
Пример #9
0
func init() {
	var err error
	caKey, err = helpers.ParsePrivateKeyPEM(mustRead(caKeyFile))
	if err != nil {
		panic(fmt.Sprintf("Unable to parse %s: %s", caKeyFile, err))
	}
	caCert, err = core.LoadCert(caCertFile)
	if err != nil {
		panic(fmt.Sprintf("Unable to parse %s: %s", caCertFile, err))
	}
}
Пример #10
0
// NewFromPEM creates a new root certificate from the key file passed in.
func NewFromPEM(req *csr.CertificateRequest, keyFile string) (cert, csrPEM []byte, err error) {
	privData, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return nil, nil, err
	}

	priv, err := helpers.ParsePrivateKeyPEM(privData)
	if err != nil {
		return nil, nil, err
	}

	return NewFromSigner(req, priv)
}
Пример #11
0
// NewCRLFromFile takes in a list of serial numbers, one per line, as well as the issuing certificate
// of the CRL, and the private key. This function is then used to parse the list and generate a CRL
func NewCRLFromFile(serialList, issuerFile, keyFile []byte, expiryTime string) ([]byte, error) {

	var revokedCerts []pkix.RevokedCertificate
	var oneWeek = time.Duration(604800) * time.Second

	expiryInt, err := strconv.ParseInt(expiryTime, 0, 32)
	if err != nil {
		return nil, err
	}
	newDurationFromInt := time.Duration(expiryInt) * time.Second
	newExpiryTime := time.Now().Add(newDurationFromInt)
	if expiryInt == 0 {
		newExpiryTime = time.Now().Add(oneWeek)
	}

	// Parse the PEM encoded certificate
	issuerCert, err := helpers.ParseCertificatePEM(issuerFile)
	if err != nil {
		return nil, err
	}

	// Split input file by new lines
	individualCerts := strings.Split(string(serialList), "\n")

	// For every new line, create a new revokedCertificate and add it to slice
	for _, value := range individualCerts {
		if len(strings.TrimSpace(value)) == 0 {
			continue
		}

		tempBigInt := new(big.Int)
		tempBigInt.SetString(value, 10)
		tempCert := pkix.RevokedCertificate{
			SerialNumber:   tempBigInt,
			RevocationTime: time.Now(),
		}
		revokedCerts = append(revokedCerts, tempCert)
	}

	// Parse the key given
	key, err := helpers.ParsePrivateKeyPEM(keyFile)
	if err != nil {
		log.Debug("Malformed private key %v", err)
		return nil, err
	}

	return CreateGenericCRL(revokedCerts, key, issuerCert, newExpiryTime)
}
Пример #12
0
// TestBadReGenerator ensures that a request that fails the ParseCSR is
// not processed.
func TestBadReGenerate(t *testing.T) {
	var req = &CertificateRequest{
		Names: []Name{
			{
				C:  "US",
				ST: "California",
				L:  "San Francisco",
				O:  "CloudFlare",
				OU: "Systems Engineering",
			},
		},
		CN:         "cloudflare.com",
		Hosts:      []string{"cloudflare.com", "www.cloudflare.com", "192.168.0.1"},
		KeyRequest: &BasicKeyRequest{"ecdsa", 256},
	}

	csr, key, err := ParseRequest(req)
	if err != nil {
		t.Fatalf("%v", err)
	}

	priv, err := helpers.ParsePrivateKeyPEM(key)
	if err != nil {
		t.Fatalf("%v", err)
	}

	csr, err = Generate(priv, req)
	if err != nil {
		t.Fatalf("%v", err)
	}

	block := pem.Block{
		Type: "CERTIFICATE REQUEST",
		Headers: map[string]string{
			"Location": "UCSD",
		},
		Bytes: csr,
	}

	csr = pem.EncodeToMemory(&block)

	_, err = Regenerate(priv, csr)
	if err == nil {
		t.Fatalf("%v", err)
	}
}
func testGenerateKeypair(req *csr.CertificateRequest) (keyFile, certFile string, err error) {
	fail := func(err error) (string, string, error) {
		if keyFile != "" {
			os.Remove(keyFile)
		}
		if certFile != "" {
			os.Remove(certFile)
		}
		return "", "", err
	}

	keyFile, err = tempName()
	if err != nil {
		return fail(err)
	}

	certFile, err = tempName()
	if err != nil {
		return fail(err)
	}

	csrPEM, keyPEM, err := csr.ParseRequest(req)
	if err != nil {
		return fail(err)
	}

	if err = ioutil.WriteFile(keyFile, keyPEM, 0644); err != nil {
		return fail(err)
	}

	priv, err := helpers.ParsePrivateKeyPEM(keyPEM)
	if err != nil {
		return fail(err)
	}

	cert, err := selfsign.Sign(priv, csrPEM, config.DefaultConfig())
	if err != nil {
		return fail(err)
	}

	if err = ioutil.WriteFile(certFile, cert, 0644); err != nil {
		return fail(err)
	}

	return
}
Пример #14
0
// New creates a new root certificate from the certificate request.
func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
	policy := CAPolicy()
	if req.CA != nil {
		if req.CA.Expiry != "" {
			policy.Default.ExpiryString = req.CA.Expiry
			policy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
			if err != nil {
				return
			}
		}

		policy.Default.CAConstraint.MaxPathLen = req.CA.PathLength
		if req.CA.PathLength != 0 && req.CA.PathLenZero == true {
			log.Infof("ignore invalid 'pathlenzero' value")
		} else {
			policy.Default.CAConstraint.MaxPathLenZero = req.CA.PathLenZero
		}
	}

	g := &csr.Generator{Validator: validator}
	csrPEM, key, err = g.ProcessRequest(req)
	if err != nil {
		log.Errorf("failed to process request: %v", err)
		key = nil
		return
	}

	priv, err := helpers.ParsePrivateKeyPEM(key)
	if err != nil {
		log.Errorf("failed to parse private key: %v", err)
		return
	}

	s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), policy)
	if err != nil {
		log.Errorf("failed to create signer: %v", err)
		return
	}

	signReq := signer.SignRequest{Hosts: req.Hosts, Request: string(csrPEM)}
	cert, err = s.Sign(signReq)

	return

}
Пример #15
0
func loadSigner(issuerConfig cmd.IssuerConfig) (crypto.Signer, error) {
	if issuerConfig.File != "" {
		keyBytes, err := ioutil.ReadFile(issuerConfig.File)
		if err != nil {
			return nil, fmt.Errorf("Could not read key file %s", issuerConfig.File)
		}

		signer, err := helpers.ParsePrivateKeyPEM(keyBytes)
		if err != nil {
			return nil, err
		}
		return signer, nil
	}

	var pkcs11Config *pkcs11key.Config
	if issuerConfig.ConfigFile != "" {
		contents, err := ioutil.ReadFile(issuerConfig.ConfigFile)
		if err != nil {
			return nil, err
		}
		pkcs11Config = new(pkcs11key.Config)
		err = json.Unmarshal(contents, pkcs11Config)
		if err != nil {
			return nil, err
		}
	} else {
		pkcs11Config = issuerConfig.PKCS11
	}
	if pkcs11Config.Module == "" ||
		pkcs11Config.TokenLabel == "" ||
		pkcs11Config.PIN == "" ||
		pkcs11Config.PrivateKeyLabel == "" {
		return nil, fmt.Errorf("Missing a field in pkcs11Config %#v", pkcs11Config)
	}
	numSessions := issuerConfig.NumSessions
	if numSessions <= 0 {
		numSessions = 1
	}
	return pkcs11key.NewPool(numSessions, pkcs11Config.Module,
		pkcs11Config.TokenLabel, pkcs11Config.PIN, pkcs11Config.PrivateKeyLabel)
}
Пример #16
0
// New creates a new root certificate from the certificate request.
func New(req *csr.CertificateRequest) (cert, csrPEM, key []byte, err error) {
	if req.CA != nil {
		if req.CA.Expiry != "" {
			CAPolicy.Default.ExpiryString = req.CA.Expiry
			CAPolicy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
		}

		if req.CA.PathLength != 0 {
			signer.MaxPathLen = req.CA.PathLength
		}
	}

	g := &csr.Generator{Validator: validator}
	csrPEM, key, err = g.ProcessRequest(req)
	if err != nil {
		log.Errorf("failed to process request: %v", err)
		key = nil
		return
	}

	priv, err := helpers.ParsePrivateKeyPEM(key)
	if err != nil {
		log.Errorf("failed to parse private key: %v", err)
		return
	}

	s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), nil)
	if err != nil {
		log.Errorf("failed to create signer: %v", err)
		return
	}
	s.SetPolicy(CAPolicy)

	signReq := signer.SignRequest{Hosts: req.Hosts, Request: string(csrPEM)}
	cert, err = s.Sign(signReq)

	return

}
Пример #17
0
// New generates a new CA from a certificate request and signing profile.
func New(req *csr.CertificateRequest, profiles *config.Signing) (*CA, error) {
	certPEM, _, keyPEM, err := initca.New(req)
	if err != nil {
		return nil, err
	}

	// If initca returns successfully, the following (which are
	// all CFSSL internal functions) should not return an
	// error. If they do, we should abort --- something about
	// CFSSL has become inconsistent, and it can't be trusted.

	priv, err := helpers.ParsePrivateKeyPEM(keyPEM)
	assert.NoError(err, "CFSSL-generated private key can't be parsed")

	cert, err := helpers.ParseCertificatePEM(certPEM)
	assert.NoError(err, "CFSSL-generated certificate can't be parsed")

	s, err := local.NewSigner(priv, cert, helpers.SignerAlgo(priv), profiles)
	assert.NoError(err, "a signer could not be constructed")

	return NewFromSigner(s), nil
}
Пример #18
0
func TestDefaultSign(t *testing.T) {
	csrBytes, err := ioutil.ReadFile(csrFile)
	if err != nil {
		t.Fatal(err)
	}
	keyBytes, err := ioutil.ReadFile(keyFile)
	if err != nil {
		t.Fatal(err)
	}

	priv, err := helpers.ParsePrivateKeyPEM(keyBytes)
	if err != nil {
		t.Fatal(err)
	}

	profile := config.DefaultConfig()
	profile.Expiry = 10 * time.Hour

	_, err = Sign(priv, csrBytes, profile)
	if err != nil {
		t.Fatal(err)
	}
}
Пример #19
0
// BundleFromPEMorDER builds a certificate bundle from the set of byte
// slices containing the PEM or DER-encoded certificate(s), private key.
func (b *Bundler) BundleFromPEMorDER(certsRaw, keyPEM []byte, flavor BundleFlavor, password string) (*Bundle, error) {
	log.Debug("bundling from PEM files")
	var key crypto.Signer
	var err error
	if len(keyPEM) != 0 {
		key, err = helpers.ParsePrivateKeyPEM(keyPEM)
		if err != nil {
			log.Debugf("failed to parse private key: %v", err)
			return nil, err
		}
	}

	certs, err := helpers.ParseCertificatesPEM(certsRaw)
	if err != nil {
		// If PEM doesn't work try DER
		var keyDER crypto.Signer
		var errDER error
		certs, keyDER, errDER = helpers.ParseCertificatesDER(certsRaw, password)
		// Only use DER key if no key read from file
		if key == nil && keyDER != nil {
			key = keyDER
		}
		if errDER != nil {
			log.Debugf("failed to parse certificates: %v", err)
			// If neither parser works pass along PEM error
			return nil, err
		}

	}
	if len(certs) == 0 {
		log.Debugf("no certificates found")
		return nil, errors.New(errors.CertificateError, errors.DecodeFailed)
	}

	log.Debugf("bundle ready")
	return b.Bundle(certs, key, flavor)
}
Пример #20
0
// New creates a new root certificate from the certificate request.
func New(req *csr.CertificateRequest) (cert, key []byte, err error) {
	log.Infof("creating root certificate from CSR")
	g := &csr.Generator{validator}
	csr, key, err := g.ProcessRequest(req)
	if err != nil {
		log.Errorf("failed to process request: %v", err)
		key = nil
		return
	}

	priv, err := helpers.ParsePrivateKeyPEM(key)
	if err != nil {
		log.Errorf("failed to parse private key: %v", err)
		return
	}

	s := &signer.Signer{
		Priv:   priv,
		Policy: CAPolicy,
	}

	cert, err = s.Sign("", csr, "")
	return
}
Пример #21
0
// NewFromPEM creates a new root certificate from the key file passed in.
func NewFromPEM(req *csr.CertificateRequest, keyFile string) (cert, csrPEM []byte, err error) {
	if req.CA != nil {
		if req.CA.Expiry != "" {
			CAPolicy.Default.ExpiryString = req.CA.Expiry
			CAPolicy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
		}

		if req.CA.PathLength != 0 {
			signer.MaxPathLen = req.CA.PathLength
		}
	}

	privData, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return nil, nil, err
	}

	priv, err := helpers.ParsePrivateKeyPEM(privData)
	if err != nil {
		return nil, nil, err
	}

	return NewFromSigner(req, priv)
}
Пример #22
0
// NewSigner generates a new certificate signer using the certificate
// authority certificate and private key and Signing config for signing. caFile should
// contain the CA's certificate, and the cakeyFile should contain the
// private key. Both must be PEM-encoded.
func NewSigner(caFile, cakeyFile string, policy *config.Signing) (*Signer, error) {
	if policy == nil {
		policy = &config.Signing{
			Profiles: map[string]*config.SigningProfile{},
			Default:  config.DefaultConfig(),
		}
	}

	if !policy.Valid() {
		return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid policy"))
	}

	log.Debug("Loading CA: ", caFile)
	ca, err := ioutil.ReadFile(caFile)
	if err != nil {
		return nil, err
	}
	log.Debug("Loading CA key: ", cakeyFile)
	cakey, err := ioutil.ReadFile(cakeyFile)
	if err != nil {
		return nil, err
	}

	parsedCa, err := helpers.ParseCertificatePEM(ca)
	if err != nil {
		return nil, err
	}

	priv, err := helpers.ParsePrivateKeyPEM(cakey)
	if err != nil {

		return nil, err
	}

	return &Signer{parsedCa, priv, policy, DefaultSigAlgo(priv)}, nil
}
Пример #23
0
// BundleFromPEM builds a certificate bundle from the set of byte
// slices containing the PEM-encoded certificate(s), private key.
func (b *Bundler) BundleFromPEM(certsPEM, keyPEM []byte, flavor BundleFlavor) (*Bundle, error) {
	log.Debug("bundling from PEM files")
	var key interface{}
	var err error
	if len(keyPEM) != 0 {
		key, err = helpers.ParsePrivateKeyPEM(keyPEM)
		log.Debugf("failed to parse private key: %v", err)
		if err != nil {
			return nil, err
		}
	}

	certs, err := helpers.ParseCertificatesPEM(certsPEM)
	if err != nil {
		log.Debugf("failed to parse certificates: %v", err)
		return nil, err
	} else if len(certs) == 0 {
		log.Debugf("no certificates found")
		return nil, errors.New(errors.CertificateError, errors.DecodeFailed, nil)
	}

	log.Debugf("bundle ready")
	return b.Bundle(certs, key, flavor)
}
Пример #24
0
// RenewFromPEM re-creates a root certificate from the CA cert and key
// files. The resulting root certificate will have the input CA certificate
// as the template and have the same expiry length. E.g. the exsiting CA
// is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate
// will be valid from now and expire in one year as well.
func RenewFromPEM(caFile, keyFile string) ([]byte, error) {
	caBytes, err := ioutil.ReadFile(caFile)
	if err != nil {
		return nil, err
	}

	ca, err := helpers.ParseCertificatePEM(caBytes)
	if err != nil {
		return nil, err
	}

	keyBytes, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return nil, err
	}

	key, err := helpers.ParsePrivateKeyPEM(keyBytes)
	if err != nil {
		return nil, err
	}

	return RenewFromSigner(ca, key)

}
Пример #25
0
// NewFromPEM creates a new root certificate from the key file passed in.
func NewFromPEM(req *csr.CertificateRequest, keyFile string) (cert, csrPEM []byte, err error) {
	if req.CA != nil {
		if req.CA.Expiry != "" {
			CAPolicy.Default.ExpiryString = req.CA.Expiry
			CAPolicy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry)
		}

		if req.CA.PathLength != 0 {
			signer.MaxPathLen = req.CA.PathLength
		}
	}

	privData, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return nil, nil, err
	}

	priv, err := helpers.ParsePrivateKeyPEM(privData)
	if err != nil {
		return nil, nil, err
	}

	var sigAlgo x509.SignatureAlgorithm
	switch priv := priv.(type) {
	case *rsa.PrivateKey:
		bitLength := priv.PublicKey.N.BitLen()
		switch {
		case bitLength >= 4096:
			sigAlgo = x509.SHA512WithRSA
		case bitLength >= 3072:
			sigAlgo = x509.SHA384WithRSA
		case bitLength >= 2048:
			sigAlgo = x509.SHA256WithRSA
		default:
			sigAlgo = x509.SHA1WithRSA
		}
	case *ecdsa.PrivateKey:
		switch priv.Curve {
		case elliptic.P521():
			sigAlgo = x509.ECDSAWithSHA512
		case elliptic.P384():
			sigAlgo = x509.ECDSAWithSHA384
		case elliptic.P256():
			sigAlgo = x509.ECDSAWithSHA256
		default:
			sigAlgo = x509.ECDSAWithSHA1
		}
	default:
		sigAlgo = x509.UnknownSignatureAlgorithm
	}

	var tpl = x509.CertificateRequest{
		Subject:            req.Name(),
		SignatureAlgorithm: sigAlgo,
		DNSNames:           req.Hosts,
	}

	csrPEM, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv)
	if err != nil {
		log.Errorf("failed to generate a CSR: %v", err)
		// The use of CertificateError was a matter of some
		// debate; it is the one edge case in which a new
		// error category specifically for CSRs might be
		// useful, but it was deemed that one edge case did
		// not a new category justify.
		err = cferr.Wrap(cferr.CertificateError, cferr.BadRequest, err)
		return
	}

	p := &pem.Block{
		Type:  "CERTIFICATE REQUEST",
		Bytes: csrPEM,
	}
	csrPEM = pem.EncodeToMemory(p)

	s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), nil)
	if err != nil {
		log.Errorf("failed to create signer: %v", err)
		return
	}
	s.SetPolicy(CAPolicy)

	signReq := signer.SignRequest{Request: string(csrPEM)}
	cert, err = s.Sign(signReq)
	return
}
Пример #26
0
func selfSignMain(args []string, c cli.Config) (err error) {
	if c.Hostname == "" && !c.IsCA {
		c.Hostname, args, err = cli.PopFirstArgument(args)
		if err != nil {
			return
		}
	}

	csrFile, args, err := cli.PopFirstArgument(args)
	if err != nil {
		return
	}

	csrFileBytes, err := cli.ReadStdin(csrFile)
	if err != nil {
		return
	}

	var req = csr.New()
	err = json.Unmarshal(csrFileBytes, req)
	if err != nil {
		return
	}

	var key, csrPEM []byte
	g := &csr.Generator{Validator: genkey.Validator}
	csrPEM, key, err = g.ProcessRequest(req)
	if err != nil {
		key = nil
		return
	}

	priv, err := helpers.ParsePrivateKeyPEM(key)
	if err != nil {
		key = nil
		return
	}

	var profile *config.SigningProfile

	// If there is a config, use its signing policy. Otherwise, leave policy == nil
	// and NewSigner will use DefaultConfig().
	if c.CFG != nil {
		if c.Profile != "" && c.CFG.Signing.Profiles != nil {
			profile = c.CFG.Signing.Profiles[c.Profile]
		}
	}

	if profile == nil {
		profile = config.DefaultConfig()
		profile.Expiry = 2190 * time.Hour
	}

	cert, err := selfsign.Sign(priv, csrPEM, profile)
	if err != nil {
		key = nil
		priv = nil
		return
	}

	fmt.Fprintf(os.Stderr, `*** WARNING ***

Self-signed certificates are dangerous. Use this self-signed
certificate at your own risk.

It is strongly recommended that these certificates NOT be used
in production.

*** WARNING ***

`)
	cli.PrintCert(key, csrPEM, cert)
	return
}
Пример #27
0
// Handle responds to requests for crl generation. It creates this crl
// based off of the given certificate, serial numbers, and private key
func crlHandler(w http.ResponseWriter, r *http.Request) error {

	var revokedCerts []pkix.RevokedCertificate
	var oneWeek = time.Duration(604800) * time.Second
	var newExpiryTime = time.Now()

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	r.Body.Close()

	req := &jsonCRLRequest{}

	err = json.Unmarshal(body, req)
	if err != nil {
		log.Error(err)
	}

	if req.ExpiryTime != "" {
		expiryTime := strings.TrimSpace(req.ExpiryTime)
		expiryInt, err := strconv.ParseInt(expiryTime, 0, 32)
		if err != nil {
			return err
		}

		newExpiryTime = time.Now().Add((time.Duration(expiryInt) * time.Second))
	}

	if req.ExpiryTime == "" {
		newExpiryTime = time.Now().Add(oneWeek)
	}

	if err != nil {
		return err
	}

	cert, err := helpers.ParseCertificatePEM([]byte(req.Certificate))
	if err != nil {
		log.Error("Error from ParseCertificatePEM", err)
		return errors.NewBadRequestString("Malformed certificate")
	}

	for _, value := range req.SerialNumber {
		tempBigInt := new(big.Int)
		tempBigInt.SetString(value, 10)
		tempCert := pkix.RevokedCertificate{
			SerialNumber:   tempBigInt,
			RevocationTime: time.Now(),
		}
		revokedCerts = append(revokedCerts, tempCert)
	}

	key, err := helpers.ParsePrivateKeyPEM([]byte(req.PrivateKey))
	if err != nil {
		log.Debug("Malformed private key %v", err)
		return errors.NewBadRequestString("Malformed Private Key")
	}

	result, err := cert.CreateCRL(rand.Reader, key, revokedCerts, time.Now(), newExpiryTime)

	return api.SendResponse(w, result)
}
Пример #28
0
func parsePrivateKeySpec(spec string, cfg map[string]string) (crypto.Signer, error) {
	specURL, err := url.Parse(spec)
	if err != nil {
		return nil, err
	}

	var priv crypto.Signer
	switch specURL.Scheme {
	case "file":
		// A file spec will be parsed such that the root
		// directory of a relative path will be stored as the
		// hostname, and the remainder of the file's path is
		// stored in the Path field.
		log.Debug("loading private key file", specURL.Path)
		path := filepath.Join(specURL.Host, specURL.Path)
		in, err := ioutil.ReadFile(path)
		if err != nil {
			return nil, err
		}

		log.Debug("attempting to load PEM-encoded private key")
		priv, err = helpers.ParsePrivateKeyPEM(in)
		if err != nil {
			log.Debug("file is not a PEM-encoded private key")
			log.Debug("attempting to load DER-encoded private key")
			priv, err = derhelpers.ParsePrivateKeyDER(in)
			if err != nil {
				return nil, err
			}
		}
		log.Debug("loaded private key")
		return priv, nil
	case "rofile":
		log.Warning("Red October support is currently experimental")
		path := filepath.Join(specURL.Host, specURL.Path)
		in, err := ioutil.ReadFile(path)
		if err != nil {
			return nil, err
		}

		roServer := cfg["ro_server"]
		if roServer == "" {
			return nil, errors.New("config: no RedOctober server available")
		}

		// roCAPath can be empty; if it is, the client uses
		// the system default CA roots.
		roCAPath := cfg["ro_ca"]

		roUser := cfg["ro_user"]
		if roUser == "" {
			return nil, errors.New("config: no RedOctober user available")
		}

		roPass := cfg["ro_pass"]
		if roPass == "" {
			return nil, errors.New("config: no RedOctober passphrase available")
		}

		log.Debug("decrypting key via RedOctober Server")
		roClient, err := client.NewRemoteServer(roServer, roCAPath)
		if err != nil {
			return nil, err
		}

		req := core.DecryptRequest{
			Name:     roUser,
			Password: roPass,
			Data:     in,
		}
		in, err = roClient.DecryptIntoData(req)
		if err != nil {
			return nil, err
		}

		return priv, nil
	default:
		return nil, ErrUnsupportedScheme
	}
}
Пример #29
0
func TestInitCA(t *testing.T) {
	var req *csr.CertificateRequest
	hostname := "cloudflare.com"
	for _, param := range validKeyParams {
		req = &csr.CertificateRequest{
			Names: []csr.Name{
				{
					C:  "US",
					ST: "California",
					L:  "San Francisco",
					O:  "CloudFlare",
					OU: "Systems Engineering",
				},
			},
			CN:    hostname,
			Hosts: []string{hostname, "www." + hostname},
			KeyRequest: &csr.KeyRequest{
				Algo: param.keyAlgo,
				Size: param.keyLen,
			},
		}
		certBytes, keyBytes, err := New(req)
		if err != nil {
			t.Fatal("InitCA failed:", err)
		}
		key, err := helpers.ParsePrivateKeyPEM(keyBytes)
		if err != nil {
			t.Fatal("InitCA private key parsing failed:", err)
		}
		cert, err := helpers.ParseCertificatePEM(certBytes)
		if err != nil {
			t.Fatal("InitCA cert parsing failed:", err)
		}

		// Verify key parameters.
		switch req.KeyRequest.Algo {
		case "rsa":
			if cert.PublicKey.(*rsa.PublicKey).N.BitLen() != param.keyLen {
				t.Fatal("Cert key length mismatch.")
			}
			if key.(*rsa.PrivateKey).N.BitLen() != param.keyLen {
				t.Fatal("Private key length mismatch.")
			}
		case "ecdsa":
			if cert.PublicKey.(*ecdsa.PublicKey).Curve.Params().BitSize != param.keyLen {
				t.Fatal("Cert key length mismatch.")
			}
			if key.(*ecdsa.PrivateKey).Curve.Params().BitSize != param.keyLen {
				t.Fatal("Private key length mismatch.")
			}
		}

		// Start a signer
		var CAPolicy = &config.Signing{
			Default: &config.SigningProfile{
				Usage:        []string{"cert sign", "crl sign"},
				ExpiryString: "300s",
				Expiry:       300 * time.Second,
				CA:           true,
			},
		}
		s := &signer.Signer{cert, key, CAPolicy, signer.DefaultSigAlgo(key)}

		// Sign RSA and ECDSA customer CSRs.
		for _, csrFile := range csrFiles {
			csrBytes, err := ioutil.ReadFile(csrFile)
			if err != nil {
				t.Fatal("CSR loading error:", err)
			}
			bytes, err := s.Sign(hostname, csrBytes, "")
			if err != nil {
				t.Fatal(err)
			}
			customerCert, _ := helpers.ParseCertificatePEM(bytes)
			if customerCert.SignatureAlgorithm != s.SigAlgo {
				t.Fatal("Signature Algorithm mismatch")
			}
			err = customerCert.CheckSignatureFrom(cert)
			if err != nil {
				t.Fatal("Signing CSR failed.", err)
			}
		}

	}
}
Пример #30
0
func TestInitCA(t *testing.T) {
	var req *csr.CertificateRequest
	hostname := "cloudflare.com"
	for _, param := range validKeyParams {
		for _, caconfig := range validCAConfigs {
			req = &csr.CertificateRequest{
				Names: []csr.Name{
					{
						C:  "US",
						ST: "California",
						L:  "San Francisco",
						O:  "CloudFlare",
						OU: "Systems Engineering",
					},
				},
				CN:         hostname,
				Hosts:      []string{hostname, "www." + hostname},
				KeyRequest: &param,
				CA:         &caconfig,
			}
			certBytes, _, keyBytes, err := New(req)
			if err != nil {
				t.Fatal("InitCA failed:", err)
			}
			key, err := helpers.ParsePrivateKeyPEM(keyBytes)
			if err != nil {
				t.Fatal("InitCA private key parsing failed:", err)
			}
			cert, err := helpers.ParseCertificatePEM(certBytes)
			if err != nil {
				t.Fatal("InitCA cert parsing failed:", err)
			}

			// Verify key parameters.
			switch req.KeyRequest.Algo() {
			case "rsa":
				if cert.PublicKey.(*rsa.PublicKey).N.BitLen() != param.Size() {
					t.Fatal("Cert key length mismatch.")
				}
				if key.(*rsa.PrivateKey).N.BitLen() != param.Size() {
					t.Fatal("Private key length mismatch.")
				}
			case "ecdsa":
				if cert.PublicKey.(*ecdsa.PublicKey).Curve.Params().BitSize != param.Size() {
					t.Fatal("Cert key length mismatch.")
				}
				if key.(*ecdsa.PrivateKey).Curve.Params().BitSize != param.Size() {
					t.Fatal("Private key length mismatch.")
				}
			}

			// Verify CA MaxPathLen
			if caconfig.PathLength == 0 && cert.MaxPathLenZero != caconfig.PathLenZero {
				t.Fatalf("fail to init a CA cert with specified CA pathlen zero: expect %v, got %v", caconfig.PathLenZero, cert.MaxPathLenZero)
			}

			if caconfig.PathLength != 0 {
				if cert.MaxPathLen != caconfig.PathLength {
					t.Fatalf("fail to init a CA cert with specified CA pathlen: expect %d, got %d", caconfig.PathLength, cert.MaxPathLen)
				}
				if cert.MaxPathLenZero != false {
					t.Fatalf("fail to init a CA cert with specified CA pathlen zero: expect false, got %t", cert.MaxPathLenZero)
				}
			}

			// Replace the default CAPolicy with a test (short expiry) version.
			CAPolicy = func() *config.Signing {
				return &config.Signing{
					Default: &config.SigningProfile{
						Usage:        []string{"cert sign", "crl sign"},
						ExpiryString: "300s",
						Expiry:       300 * time.Second,
						CAConstraint: config.CAConstraint{IsCA: true},
					},
				}
			}

			// Start a signer
			s, err := local.NewSigner(key, cert, signer.DefaultSigAlgo(key), nil)
			if err != nil {
				t.Fatal("Signer Creation error:", err)
			}
			s.SetPolicy(CAPolicy())

			// Sign RSA and ECDSA customer CSRs.
			for _, csrFile := range csrFiles {
				csrBytes, err := ioutil.ReadFile(csrFile)
				if err != nil {
					t.Fatal("CSR loading error:", err)
				}
				req := signer.SignRequest{
					Request: string(csrBytes),
					Hosts:   signer.SplitHosts(hostname),
					Profile: "",
					Label:   "",
				}

				bytes, err := s.Sign(req)
				if err != nil {
					t.Fatal(err)
				}
				customerCert, _ := helpers.ParseCertificatePEM(bytes)
				if customerCert.SignatureAlgorithm != s.SigAlgo() {
					t.Fatal("Signature Algorithm mismatch")
				}
				err = customerCert.CheckSignatureFrom(cert)
				if err != nil {
					t.Fatal("Signing CSR failed.", err)
				}
			}
		}
	}
}