// initialCAHandler is an HTTP handler that accepts a JSON blob in the // same format as the CSR endpoint; this blob should contain the // identity information for the CA's root key. This endpoint is not // suitable for creating intermediate certificates. func initialCAHandler(w http.ResponseWriter, r *http.Request) error { log.Info("setting up initial CA handler") body, err := ioutil.ReadAll(r.Body) if err != nil { log.Warningf("failed to read request body: %v", err) return errors.NewBadRequest(err) } r.Body.Close() req := new(csr.CertificateRequest) req.KeyRequest = csr.NewBasicKeyRequest() err = json.Unmarshal(body, req) if err != nil { log.Warningf("failed to unmarshal request: %v", err) return errors.NewBadRequest(err) } cert, _, key, err := initca.New(req) if err != nil { log.Warningf("failed to initialise new CA: %v", err) return err } response := api.NewSuccessResponse(&NewCA{string(key), string(cert)}) enc := json.NewEncoder(w) err = enc.Encode(response) return err }
// 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 }
// GenerateNewCSR returns a newly generated key and CSR signed with said key func GenerateNewCSR() (csr, key []byte, err error) { req := &cfcsr.CertificateRequest{ KeyRequest: cfcsr.NewBasicKeyRequest(), } csr, key, err = cfcsr.ParseRequest(req) if err != nil { return } return }
// CreateRootCertAndKey returns a generated certificate and key for a root CA func CreateRootCertAndKey(rootCN string) ([]byte, []byte, 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) return cert, key, err }
// RefreshKeys will make sure the Transport has loaded keys and has a // valid certificate. It will handle any persistence, check that the // certificate is valid (i.e. that its expiry date is within the // Before date), and handle certificate reissuance as needed. func (tr *Transport) RefreshKeys() (err error) { if !tr.Provider.Ready() { log.Debug("key and certificate aren't ready, loading") err = tr.Provider.Load() if err != nil && err != kp.ErrCertificateUnavailable { log.Debugf("failed to load keypair: %v", err) kr := tr.Identity.Request.KeyRequest if kr == nil { kr = csr.NewBasicKeyRequest() } err = tr.Provider.Generate(kr.Algo(), kr.Size()) if err != nil { log.Debugf("failed to generate key: %v", err) return } } } lifespan := tr.Lifespan() if lifespan < tr.Before { log.Debugf("transport's certificate is out of date (lifespan %s)", lifespan) req, err := tr.Provider.CertificateRequest(tr.Identity.Request) if err != nil { log.Debugf("couldn't get a CSR: %v", err) return err } log.Debug("requesting certificate from CA") cert, err := tr.CA.SignCSR(req) if err != nil { log.Debugf("failed to get the certificate signed: %v", err) return err } log.Debug("giving the certificate to the provider") err = tr.Provider.SetCertificatePEM(cert) if err != nil { log.Debugf("failed to set the provider's certificate: %v", err) return err } log.Debug("storing the certificate") err = tr.Provider.Store() if err != nil { log.Debugf("the provider failed to store the certificate: %v", err) return err } } return nil }
func generateNewCSR() (csr, key []byte, err error) { req := &cfcsr.CertificateRequest{ KeyRequest: cfcsr.NewBasicKeyRequest(), } csr, key, err = cfcsr.ParseRequest(req) if err != nil { log.Debugf(`failed to generate CSR`) return } return }
func genkeyMain(args []string, c cli.Config) (err error) { csrFile, args, err := cli.PopFirstArgument(args) if err != nil { return } csrFileBytes, err := cli.ReadStdin(csrFile) if err != nil { return } req := csr.CertificateRequest{ KeyRequest: csr.NewBasicKeyRequest(), } err = json.Unmarshal(csrFileBytes, &req) if err != nil { return } if c.IsCA { var key, csrPEM, cert []byte cert, csrPEM, key, err = initca.New(&req) if err != nil { return } cli.PrintCert(key, csrPEM, cert) } else { if req.CA != nil { err = errors.New("ca section only permitted in initca") return } var key, csrPEM []byte g := &csr.Generator{Validator: Validator} csrPEM, key, err = g.ProcessRequest(&req) if err != nil { key = nil return } cli.PrintCert(key, csrPEM, nil) } return nil }
// Handle responds to requests for the CA to generate a new private // key and certificate request on behalf of the client. The format for // these requests is documented in the API documentation. func (g *Handler) Handle(w http.ResponseWriter, r *http.Request) error { log.Info("request for CSR") body, err := ioutil.ReadAll(r.Body) if err != nil { log.Warningf("failed to read request body: %v", err) return errors.NewBadRequest(err) } r.Body.Close() req := new(csr.CertificateRequest) req.KeyRequest = csr.NewBasicKeyRequest() err = json.Unmarshal(body, req) if err != nil { log.Warningf("failed to unmarshal request: %v", err) return errors.NewBadRequest(err) } if req.CA != nil { log.Warningf("request received with CA section") return errors.NewBadRequestString("ca section only permitted in initca") } csr, key, err := g.generator.ProcessRequest(req) if err != nil { log.Warningf("failed to process CSR: %v", err) // The validator returns a *cfssl/errors.HttpError return err } sum, err := computeSum(csr) if err != nil { return errors.NewBadRequest(err) } // Both key and csr are returned PEM-encoded. response := api.NewSuccessResponse(&CertRequest{ Key: string(key), CSR: string(csr), Sums: map[string]Sum{"certificate_request": sum}, }) w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) err = enc.Encode(response) return err }
func TestCSRValidate(t *testing.T) { req := &csr.CertificateRequest{ Names: []csr.Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{}, KeyRequest: csr.NewBasicKeyRequest(), } err := CSRValidate(req) if err != nil { t.Fatal("There should be not an error for missing Hosts parameter") } }
func csrData(t *testing.T) *bytes.Reader { req := &csr.CertificateRequest{ Names: []csr.Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: "cloudflare.com", Hosts: []string{"cloudflare.com"}, KeyRequest: csr.NewBasicKeyRequest(), } csrBytes, err := json.Marshal(req) if err != nil { t.Fatal(err) } return bytes.NewReader(csrBytes) }
func createKey(c *cfg) (*string, *string, error) { keypath := path.Join(c.certpath, fmt.Sprintf("%s-key.pem", c.certname)) csrpath := path.Join(c.certpath, fmt.Sprintf("%s.csr", c.certname)) _, keyerr := os.Stat(keypath) _, csrerr := os.Stat(csrpath) if keyerr == nil && csrerr == nil { log.Println("key and csr already exist") return &keypath, &csrpath, nil } bytes, err := ioutil.ReadFile(c.csrfile) if err != nil { return nil, nil, err } req := csr.CertificateRequest{KeyRequest: csr.NewBasicKeyRequest()} if err := json.Unmarshal(bytes, &req); err != nil { return nil, nil, err } var keybytes, csrbytes []byte g := &csr.Generator{Validator: genkey.Validator} csrbytes, keybytes, err = g.ProcessRequest(&req) if err != nil { return nil, nil, err } if err := ioutil.WriteFile(keypath, keybytes, 0600); err != nil { return nil, nil, err } if err := ioutil.WriteFile(csrpath, csrbytes, 0600); err != nil { return nil, nil, err } return &keypath, &csrpath, nil }
func gencertMain(args []string, c cli.Config) error { if c.RenewCA { log.Infof("re-generate a CA certificate from CA cert and key") cert, err := initca.RenewFromPEM(c.CAFile, c.CAKeyFile) if err != nil { log.Errorf("%v\n", err) return err } cli.PrintCert(nil, nil, cert) return nil } csrJSONFile, args, err := cli.PopFirstArgument(args) if err != nil { return err } csrJSONFileBytes, err := cli.ReadStdin(csrJSONFile) if err != nil { return err } req := csr.CertificateRequest{ KeyRequest: csr.NewBasicKeyRequest(), } err = json.Unmarshal(csrJSONFileBytes, &req) if err != nil { return err } switch { case c.IsCA: var key, csrPEM, cert []byte if c.CAKeyFile != "" { log.Infof("re-generate a CA certificate from CSR and CA key") cert, csrPEM, err = initca.NewFromPEM(&req, c.CAKeyFile) if err != nil { log.Errorf("%v\n", err) return err } } else { log.Infof("generating a new CA key and certificate from CSR") cert, csrPEM, key, err = initca.New(&req) if err != nil { return err } } cli.PrintCert(key, csrPEM, cert) default: if req.CA != nil { err = errors.New("ca section only permitted in initca") return err } // Remote can be forced on the command line or in the config if c.Remote == "" && c.CFG == nil { if c.CAFile == "" { log.Error("need a CA certificate (provide one with -ca)") return nil } if c.CAKeyFile == "" { log.Error("need a CA key (provide one with -ca-key)") return nil } } var key, csrBytes []byte g := &csr.Generator{Validator: genkey.Validator} csrBytes, key, err = g.ProcessRequest(&req) if err != nil { key = nil return err } s, err := sign.SignerFromConfig(c) if err != nil { return err } var cert []byte req := signer.SignRequest{ Request: string(csrBytes), Hosts: signer.SplitHosts(c.Hostname), Profile: c.Profile, Label: c.Label, } cert, err = s.Sign(req) if err != nil { return err } cli.PrintCert(key, csrBytes, cert) } return nil }
func genSecurityConfig(s *store.MemoryStore, rootCA ca.RootCA, role, org, tmpDir string, nonSigningRoot bool) (*ca.SecurityConfig, error) { req := &cfcsr.CertificateRequest{ KeyRequest: cfcsr.NewBasicKeyRequest(), } csr, key, err := cfcsr.ParseRequest(req) if err != nil { return nil, err } // Obtain a signed Certificate nodeID := identity.NewID() // All managers get added the subject-alt-name of CA, so they can be used for cert issuance hosts := []string{role} if role == ca.ManagerRole { hosts = append(hosts, ca.CARole) } cert, err := rootCA.Signer.Sign(cfsigner.SignRequest{ Request: string(csr), // OU is used for Authentication of the node type. The CN has the random // node ID. Subject: &cfsigner.Subject{CN: nodeID, Names: []cfcsr.Name{{OU: role, O: org}}}, // Adding ou as DNS alt name, so clients can connect to ManagerRole and CARole Hosts: hosts, }) if err != nil { return nil, err } // Append the root CA Key to the certificate, to create a valid chain certChain := append(cert, rootCA.Cert...) // If we were instructed to persist the files if tmpDir != "" { paths := ca.NewConfigPaths(tmpDir) if err := ioutil.WriteFile(paths.Node.Cert, certChain, 0644); err != nil { return nil, err } if err := ioutil.WriteFile(paths.Node.Key, key, 0600); err != nil { return nil, err } } // Load a valid tls.Certificate from the chain and the key nodeCert, err := tls.X509KeyPair(certChain, key) if err != nil { return nil, err } nodeServerTLSCreds, err := rootCA.NewServerTLSCredentials(&nodeCert) if err != nil { return nil, err } nodeClientTLSCreds, err := rootCA.NewClientTLSCredentials(&nodeCert, ca.ManagerRole) if err != nil { return nil, err } err = createNode(s, nodeID, role, csr, cert) if err != nil { return nil, err } if nonSigningRoot { rootCA = ca.RootCA{ Cert: rootCA.Cert, Digest: rootCA.Digest, Pool: rootCA.Pool, } } return ca.NewSecurityConfig(&rootCA, nodeClientTLSCreds, nodeServerTLSCreds), nil }
func gencertMain(args []string, c cli.Config) error { if c.RenewCA { log.Infof("re-generate a CA certificate from CA cert and key") cert, err := initca.RenewFromPEM(c.CAFile, c.CAKeyFile) if err != nil { log.Errorf("%v\n", err) return err } cli.PrintCert(nil, nil, cert) return nil } csrJSONFile, args, err := cli.PopFirstArgument(args) if err != nil { return err } csrJSONFileBytes, err := cli.ReadStdin(csrJSONFile) if err != nil { return err } req := csr.CertificateRequest{ KeyRequest: csr.NewBasicKeyRequest(), } err = json.Unmarshal(csrJSONFileBytes, &req) if err != nil { return err } if c.CNOverride != "" { req.CN = c.CNOverride } switch { case c.IsCA: var key, csrPEM, cert []byte if c.CAKeyFile != "" { log.Infof("re-generate a CA certificate from CSR and CA key") cert, csrPEM, err = initca.NewFromPEM(&req, c.CAKeyFile) if err != nil { log.Errorf("%v\n", err) return err } } else { log.Infof("generating a new CA key and certificate from CSR") cert, csrPEM, key, err = initca.New(&req) if err != nil { return err } } cli.PrintCert(key, csrPEM, cert) default: if req.CA != nil { err = errors.New("ca section only permitted in initca") return err } if c.Hostname != "" { req.Hosts = signer.SplitHosts(c.Hostname) } // Remote can be forced on the command line or in the config if c.Remote == "" && c.CFG == nil { if c.CAFile == "" { log.Error("need a CA certificate (provide one with -ca)") return nil } if c.CAKeyFile == "" { log.Error("need a CA key (provide one with -ca-key)") return nil } } var key, csrBytes []byte g := &csr.Generator{Validator: genkey.Validator} csrBytes, key, err = g.ProcessRequest(&req) if err != nil { key = nil return err } s, err := sign.SignerFromConfig(c) if err != nil { return err } var cert []byte signReq := signer.SignRequest{ Request: string(csrBytes), Hosts: signer.SplitHosts(c.Hostname), Profile: c.Profile, Label: c.Label, } if c.CRL != "" { signReq.CRLOverride = c.CRL } cert, err = s.Sign(signReq) if err != nil { return err } // This follows the Baseline Requirements for the Issuance and // Management of Publicly-Trusted Certificates, v.1.1.6, from the CA/Browser // Forum (https://cabforum.org). Specifically, section 10.2.3 ("Information // Requirements"), states: // // "Applicant information MUST include, but not be limited to, at least one // Fully-Qualified Domain Name or IP address to be included in the Certificate’s // SubjectAltName extension." if len(signReq.Hosts) == 0 && len(req.Hosts) == 0 { log.Warning(generator.CSRNoHostMessage) } cli.PrintCert(key, csrBytes, cert) } return nil }