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 }
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) } }
// 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) }
// 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) }
// 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) }
// 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 }
// 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 }
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)) } }
// 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) }
// 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) }
// 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 }
// 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 }
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) }
// 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 }
// 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 }
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) } }
// 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) }
// 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 }
// 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) }
// 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 }
// 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) }
// 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) }
// 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 }
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 }
// 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) }
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 } }
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) } } } }
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: ¶m, 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) } } } } }