// NewBundler creates a new Bundler from the files passed in; these // files should contain a list of valid root certificates and a list // of valid intermediate certificates, respectively. func NewBundler(caBundleFile, intBundleFile string) (*Bundler, error) { log.Debug("Loading CA bundle: ", caBundleFile) caBundle, err := ioutil.ReadFile(caBundleFile) if err != nil { log.Errorf("root bundle failed to load: %v", err) return nil, errors.Wrap(errors.RootError, errors.ReadFailed, err) } log.Debug("Loading Intermediate bundle: ", intBundleFile) intBundle, err := ioutil.ReadFile(intBundleFile) if err != nil { log.Errorf("intermediate bundle failed to load: %v", err) return nil, errors.Wrap(errors.IntermediatesError, errors.ReadFailed, err) } if _, err := os.Stat(IntermediateStash); err != nil && os.IsNotExist(err) { log.Infof("intermediate stash directory %s doesn't exist, creating", IntermediateStash) err = os.MkdirAll(IntermediateStash, 0755) if err != nil { log.Errorf("failed to create intermediate stash directory %s: %v", IntermediateStash, err) return nil, err } log.Infof("intermediate stash directory %s created", IntermediateStash) } return NewBundlerFromPEM(caBundle, intBundle) }
// signWithCSR creates a new root certificate from signing a X509.CertificateRequest // by a crypto.Signer. func signWithCSR(tpl *x509.CertificateRequest, priv crypto.Signer, policy *config.Signing) (cert, csrPEM []byte, err error) { if policy == nil { policy = CAPolicy() } 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(policy) signReq := signer.SignRequest{Request: string(csrPEM)} cert, err = s.Sign(signReq) return }
// NewBundlerFromPEM creates a new Bundler from PEM-encoded root certificates and // intermediate certificates. func NewBundlerFromPEM(caBundlePEM, intBundlePEM []byte) (*Bundler, error) { b := &Bundler{ RootPool: x509.NewCertPool(), IntermediatePool: x509.NewCertPool(), KnownIssuers: map[string]bool{}, } log.Debug("parsing root certificates from PEM") roots, err := helpers.ParseCertificatesPEM(caBundlePEM) if err != nil { log.Errorf("failed to parse root bundle: %v", err) return nil, errors.New(errors.RootError, errors.ParseFailed) } log.Debug("parse intermediate certificates from PEM") var intermediates []*x509.Certificate if intermediates, err = helpers.ParseCertificatesPEM(intBundlePEM); err != nil { log.Errorf("failed to parse intermediate bundle: %v", err) return nil, errors.New(errors.IntermediatesError, errors.ParseFailed) } log.Debug("building certificate pools") for _, c := range roots { b.RootPool.AddCert(c) b.KnownIssuers[string(c.Signature)] = true } for _, c := range intermediates { b.IntermediatePool.AddCert(c) b.KnownIssuers[string(c.Signature)] = true } log.Debug("bundler set up") return b, nil }
// makeBundle opens the file for writing, and listens for incoming // certificates. These are PEM-encoded and written to file. func makeBundle(filename string, bundler chan *x509.Certificate) { file, err := os.Create(filename) if err != nil { log.Errorf("%v", err) return } defer file.Close() var total int for { cert, ok := <-bundler if !ok { break } block := &pem.Block{ Type: "CERTIFICATE", Bytes: cert.Raw, } err = pem.Encode(file, block) if err != nil { log.Errorf("Failed to write PEM block: %v", err) break } total++ } log.Infof("Wrote %d certificates.", total) }
// NewSourceFromFile reads the named file into an InMemorySource. // The file read by this function must contain whitespace-separated OCSP // responses. Each OCSP response must be in base64-encoded DER form (i.e., // PEM without headers or whitespace). Invalid responses are ignored. // This function pulls the entire file into an InMemorySource. func NewSourceFromFile(responseFile string) (Source, error) { fileContents, err := ioutil.ReadFile(responseFile) if err != nil { return nil, err } responsesB64 := regexp.MustCompile("\\s").Split(string(fileContents), -1) src := InMemorySource{} for _, b64 := range responsesB64 { // if the line/space is empty just skip if b64 == "" { continue } der, tmpErr := base64.StdEncoding.DecodeString(b64) if tmpErr != nil { log.Errorf("Base64 decode error on: %s", b64) continue } response, tmpErr := ocsp.ParseResponse(der, nil) if tmpErr != nil { log.Errorf("OCSP decode error on: %s", b64) continue } src[response.SerialNumber.String()] = der } log.Infof("Read %d OCSP responses", len(src)) return src, nil }
// LoadPlatforms reads the file content as a json object array and convert it // to Platforms. func LoadPlatforms(filename string) { // Attempt to load root certificate metadata log.Debug("Loading platform metadata: ", filename) bytes, err := ioutil.ReadFile(filename) if err != nil { log.Errorf("platform metadata failed to load: %v", err) } var rawPlatforms []Platform if bytes != nil { err = json.Unmarshal(bytes, &rawPlatforms) if err != nil { log.Errorf("platform metadata failed to parse: %v", err) } } for _, platform := range rawPlatforms { ok := platform.ParseAndLoad() if !ok { log.Errorf("fail to finalize the parsing of platform metadata:", err) } else { log.Infof("Platform metadata is loaded: %v %v", platform.Name, len(platform.KeyStore)) Platforms = append(Platforms, platform) } } }
// A Responder can process both GET and POST requests. The mapping // from an OCSP request to an OCSP response is done by the Source; // the Responder simply decodes the request, and passes back whatever // response is provided by the source. func (rs Responder) ServeHTTP(response http.ResponseWriter, request *http.Request) { // Read response from request var requestBody []byte var err error switch request.Method { case "GET": re := regexp.MustCompile("^.*/") base64Request := re.ReplaceAllString(request.RequestURI, "") base64Request, err = url.QueryUnescape(base64Request) if err != nil { return } requestBody, err = base64.StdEncoding.DecodeString(base64Request) if err != nil { return } case "POST": requestBody, err = ioutil.ReadAll(request.Body) if err != nil { response.WriteHeader(http.StatusBadRequest) return } default: response.WriteHeader(http.StatusMethodNotAllowed) return } // TODO log request b64Body := base64.StdEncoding.EncodeToString(requestBody) log.Infof("Received OCSP request: %s", b64Body) // All responses after this point will be OCSP. // We could check for the content type of the request, but that // seems unnecessariliy restrictive. response.Header().Add("Content-Type", "application/ocsp-response") // Parse response as an OCSP request // XXX: This fails if the request contains the nonce extension. // We don't intend to support nonces anyway, but maybe we // should return unauthorizedRequest instead of malformed. ocspRequest, err := ocsp.ParseRequest(requestBody) if err != nil { log.Errorf("Error decoding request body: %s", b64Body) response.Write(malformedRequestErrorResponse) return } // Look up OCSP response from source ocspResponse, found := rs.Source.Response(ocspRequest) if !found { log.Errorf("No response found for request: %s", b64Body) response.Write(unauthorizedErrorResponse) return } // Write OCSP response to response response.WriteHeader(http.StatusOK) response.Write(ocspResponse) }
// 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 }
// registerHandlers instantiates various handlers and assoicate them to corresponding endpoints. func registerHandlers() error { log.Info("Setting up signer endpoint") signHandler, err := api.NewSignHandler(Config.caFile, Config.caKeyFile) if err != nil { log.Warningf("endpoint '/api/v1/cfssl/sign' is disabled: %v", err) } else { http.Handle("/api/v1/cfssl/sign", signHandler) } log.Info("Setting up bundler endpoint") bundleHandler, err := api.NewBundleHandler(Config.caBundleFile, Config.intBundleFile) if err != nil { log.Warningf("endpoint '/api/v1/cfssl/bundle' is disabled: %v", err) } else { http.Handle("/api/v1/cfssl/bundle", bundleHandler) } log.Info("Setting up CSR endpoint") generatorHandler, err := api.NewGeneratorHandler(api.CSRValidate) if err != nil { log.Errorf("Failed to set up CSR endpoint: %v", err) return err } http.Handle("/api/v1/cfssl/newkey", generatorHandler) log.Info("Setting up new cert endpoint") newCertGenerator, err := api.NewCertGeneratorHandler(api.CSRValidate, Config.caFile, Config.caKeyFile) if err != nil { log.Errorf("endpoint '/api/v1/cfssl/newcert' is disabled") } else { http.Handle("/api/v1/cfssl/newcert", newCertGenerator) } log.Info("Setting up initial CA endpoint") http.Handle("/api/v1/cfssl/init_ca", api.NewInitCAHandler()) if Config.remote != "" { log.Info("Remote CFSSL endpoint given, setting up remote certificate generator") if rcg, err := api.NewRemoteCertGenerator(api.CSRValidate, Config.remote); err != nil { log.Errorf("Failed to set up remote certificate generator: %v", err) return err } else { http.Handle("/api/v1/cfssl/remotecert", rcg) } } log.Info("Handler set up complete.") return nil }
// HandleError is the centralised error handling and reporting. func HandleError(w http.ResponseWriter, err error) (code int) { if err == nil { return http.StatusOK } msg := err.Error() httpCode := http.StatusInternalServerError // If it is recognized as HttpError emitted from cfssl, // we rewrite the status code accordingly. If it is a // cfssl error, set the http status to StatusBadRequest switch err := err.(type) { case *errors.HTTPError: httpCode = err.StatusCode code = err.StatusCode case *errors.Error: httpCode = http.StatusBadRequest code = err.ErrorCode msg = err.Message } response := NewErrorResponse(msg, code) jsonMessage, err := json.Marshal(response) if err != nil { log.Errorf("Failed to marshal JSON: %v", err) } else { msg = string(jsonMessage) } http.Error(w, msg, httpCode) return code }
// NewCertGeneratorHandler builds a new handler for generating // certificates directly from certificate requests; the validator covers // the certificate request and the CA's key and certificate are used to // sign the generated request. If remote is not an empty string, the // handler will send signature requests to the CFSSL instance contained // in remote. func NewCertGeneratorHandler(validator Validator, caFile, caKeyFile string, policy *config.Signing) (http.Handler, error) { var err error log.Info("setting up new generator / signer") cg := new(CertGeneratorHandler) if policy == nil { policy = &config.Signing{ Default: config.DefaultConfig(), Profiles: nil, } } root := universal.Root{ Config: map[string]string{ "ca-file": caFile, "ca-key-file": caKeyFile, }, } if cg.signer, err = universal.NewSigner(root, policy); err != nil { log.Errorf("setting up signer failed: %v", err) return nil, err } cg.generator = &csr.Generator{Validator: validator} return api.HTTPHandler{Handler: cg, Methods: []string{"POST"}}, nil }
// NewFromSigner creates a new root certificate from a crypto.Signer. func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPEM []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 nil, nil, err } } signer.MaxPathLen = req.CA.PathLength if req.CA.PathLength != 0 && req.CA.PathLenZero == true { log.Infof("ignore invalid 'pathlenzero' value") } else { signer.MaxPathLenZero = req.CA.PathLenZero } } csrPEM, err = csr.Generate(priv, req) if err != nil { return nil, nil, err } s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), nil) if err != nil { log.Errorf("failed to create signer: %v", err) return } s.SetPolicy(policy) signReq := signer.SignRequest{Request: string(csrPEM)} cert, err = s.Sign(signReq) return }
// Generate creates a new CSR from a CertificateRequest structure and // an existing key. The KeyRequest field is ignored. func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) { sigAlgo := helpers.SignerAlgo(priv, crypto.SHA256) if sigAlgo == x509.UnknownSignatureAlgorithm { return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable) } var tpl = x509.CertificateRequest{ Subject: req.Name(), SignatureAlgorithm: sigAlgo, } for i := range req.Hosts { if ip := net.ParseIP(req.Hosts[i]); ip != nil { tpl.IPAddresses = append(tpl.IPAddresses, ip) } else { tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i]) } } csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv) if err != nil { log.Errorf("failed to generate a CSR: %v", err) err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err) return } block := pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: csr, } log.Info("encoded CSR") csr = pem.EncodeToMemory(&block) 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 }
// NewSignHandler generates a new SignHandler using the certificate // authority private key and certficate to sign certificates. func NewSignHandler(caFile, cakeyFile string) (http.Handler, error) { var err error s := new(SignHandler) // TODO(kyle): add profile loading to API server if s.signer, err = signer.NewSigner(caFile, cakeyFile, nil); err != nil { log.Errorf("setting up signer failed: %v", err) return nil, err } return HttpHandler{s, "POST"}, nil }
// Close marks conn as closed and closed the inner net.Conn. func (c *Conn) Close() { c.Lock() defer c.Unlock() c.users-- if c.users == 0 { if err := c.Conn.Close(); err != nil { log.Errorf("Unable to close connection: %v", err) } } }
// NewBundlerFromPEM creates a new Bundler from PEM-encoded root certificates and // intermediate certificates. // If caBundlePEM is nil, the resulting Bundler can only do "Force" bundle. func NewBundlerFromPEM(caBundlePEM, intBundlePEM []byte) (*Bundler, error) { log.Debug("parsing root certificates from PEM") roots, err := helpers.ParseCertificatesPEM(caBundlePEM) if err != nil { log.Errorf("failed to parse root bundle: %v", err) return nil, errors.New(errors.RootError, errors.ParseFailed) } log.Debug("parse intermediate certificates from PEM") intermediates, err := helpers.ParseCertificatesPEM(intBundlePEM) if err != nil { log.Errorf("failed to parse intermediate bundle: %v", err) return nil, errors.New(errors.IntermediatesError, errors.ParseFailed) } b := &Bundler{ KnownIssuers: map[string]bool{}, IntermediatePool: x509.NewCertPool(), } log.Debug("building certificate pools") // RootPool will be nil if caBundlePEM is nil, also // that translates to caBundleFile is "". // Systems root store will be used. if caBundlePEM != nil { b.RootPool = x509.NewCertPool() } for _, c := range roots { b.RootPool.AddCert(c) b.KnownIssuers[string(c.Signature)] = true } for _, c := range intermediates { b.IntermediatePool.AddCert(c) b.KnownIssuers[string(c.Signature)] = true } log.Debug("bundler set up") return b, nil }
func NewRemoteCertGenerator(validator Validator, remote string) (http.Handler, error) { log.Info("setting up a new remote certificate generator") cg := new(RemoteCertGeneratorHandler) if cg.remote = client.NewServer(remote); cg.remote == nil { log.Errorf("invalid address for remote server") return nil, errors.New(errors.DialError, errors.Unknown, nil) } cg.generator = &csr.Generator{validator} return HttpHandler{cg, "POST"}, nil }
// 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 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 }
// NewHandler generates a new Handler using the certificate // authority private key and certficate to sign certificates. If remote // is not an empty string, the handler will send signature requests to // the CFSSL instance contained in remote by default. func NewHandler(caFile, caKeyFile string, policy *config.Signing) (http.Handler, error) { root := universal.Root{ Config: map[string]string{ "cert-file": caFile, "key-file": caKeyFile, }, } s, err := universal.NewSigner(root, policy) if err != nil { log.Errorf("setting up signer failed: %v", err) return nil, err } return NewHandlerFromSigner(s) }
// post connects to the remote server and returns a Response struct func (srv *server) post(url string, jsonData []byte) (*api.Response, error) { var resp *http.Response var err error client := &http.Client{} if srv.TLSConfig != nil { client.Transport = srv.createTLSTransport() } req, err := http.NewRequest("POST", url, bytes.NewReader(jsonData)) if err != nil { err = fmt.Errorf("failed POST to %s: %v", url, err) return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, err) } req.Header.Set("content-type", "application/json") if srv.reqModifier != nil { srv.reqModifier(req, jsonData) } resp, err = client.Do(req) if err != nil { err = fmt.Errorf("failed POST to %s: %v", url, err) return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, err) } body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, errors.Wrap(errors.APIClientError, errors.IOError, err) } resp.Body.Close() if resp.StatusCode != http.StatusOK { log.Errorf("http error with %s", url) return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, stderr.New(string(body))) } var response api.Response err = json.Unmarshal(body, &response) if err != nil { log.Debug("Unable to parse response body:", string(body)) return nil, errors.Wrap(errors.APIClientError, errors.JSONError, err) } if !response.Success || response.Result == nil { if len(response.Errors) > 0 { return nil, errors.Wrap(errors.APIClientError, errors.ServerRequestFailed, stderr.New(response.Errors[0].Message)) } return nil, errors.New(errors.APIClientError, errors.ServerRequestFailed) } return &response, nil }
func (b *Bundler) verifyChain(chain []*fetchedIntermediate) bool { // This process will verify if the root of the (partial) chain is in our root pool, // and will fail otherwise. log.Debugf("verifying chain") for vchain := chain[:]; len(vchain) > 0; vchain = vchain[1:] { cert := vchain[0] // If this is a certificate in one of the pools, skip it. if b.KnownIssuers[string(cert.Cert.Signature)] { log.Debugf("certificate is known") continue } _, err := cert.Cert.Verify(b.VerifyOptions()) if err != nil { log.Debugf("certificate failed verification: %v", err) return false } else if len(chain) == len(vchain) && isChainRootNode(cert.Cert) { // The first certificate in the chain is a root; it shouldn't be stored. log.Debug("looking at root certificate, will not store") continue } // leaf cert has an empty name, don't store leaf cert. if cert.Name == "" { continue } log.Debug("add certificate to intermediate pool:", cert.Name) b.IntermediatePool.AddCert(cert.Cert) b.KnownIssuers[string(cert.Cert.Signature)] = true if IntermediateStash != "" { fileName := filepath.Join(IntermediateStash, cert.Name) var block = pem.Block{Type: "CERTIFICATE", Bytes: cert.Cert.Raw} log.Debugf("write intermediate to stash directory: %s", fileName) // If the write fails, verification should not fail. err = ioutil.WriteFile(fileName, pem.EncodeToMemory(&block), 0644) if err != nil { log.Errorf("failed to write new intermediate: %v", err) } else { log.Info("stashed new intermediate ", cert.Name) } } } return true }
func main() { var addr, conf string flag.StringVar(&addr, "a", "127.0.0.1:9876", "`address` of server") flag.StringVar(&conf, "f", "server.json", "config `file` to use") flag.Parse() var id = new(core.Identity) data, err := ioutil.ReadFile(conf) if err != nil { exlib.Err(1, err, "reading config file") } err = json.Unmarshal(data, id) if err != nil { exlib.Err(1, err, "parsing config file") } tr, err := transport.New(exlib.Before, id) if err != nil { exlib.Err(1, err, "creating transport") } l, err := transport.Listen(addr, tr) if err != nil { exlib.Err(1, err, "setting up listener") } var errChan = make(chan error, 0) go func(ec <-chan error) { for { err, ok := <-ec if !ok { log.Warning("error channel closed, future errors will not be reported") break } log.Errorf("auto update error: %v", err) } }(errChan) log.Info("setting up auto-update") go l.AutoUpdate(nil, errChan) log.Info("listening on ", addr) exlib.Warn(serve(l), "serving listener") }
func dumpMetrics(w http.ResponseWriter, req *http.Request) { log.Info("whitelisted requested for metrics endpoint") var statsOut = struct { Metrics metrics.Registry `json:"metrics"` Signers []string `json:"signers"` }{stats.Registry, make([]string, 0, len(signers))} for signer := range signers { statsOut.Signers = append(statsOut.Signers, signer) } out, err := json.Marshal(statsOut) if err != nil { log.Errorf("failed to dump metrics: %v", err) } w.Write(out) }
// ParseRequest takes a certificate request and generates a key and // CSR from it. It does no validation -- caveat emptor. It will, // however, fail if the key request is not valid (i.e., an unsupported // curve or RSA key size). The lack of validation was specifically // chosen to allow the end user to define a policy and validate the // request appropriately before calling this function. func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) { log.Info("received CSR") if req.KeyRequest == nil { req.KeyRequest = NewBasicKeyRequest() } log.Infof("generating key: %s-%d", req.KeyRequest.Algo(), req.KeyRequest.Size()) priv, err := req.KeyRequest.Generate() if err != nil { err = cferr.Wrap(cferr.PrivateKeyError, cferr.GenerationFailed, err) return } switch priv := priv.(type) { case *rsa.PrivateKey: key = x509.MarshalPKCS1PrivateKey(priv) block := pem.Block{ Type: "RSA PRIVATE KEY", Bytes: key, } key = pem.EncodeToMemory(&block) case *ecdsa.PrivateKey: key, err = x509.MarshalECPrivateKey(priv) if err != nil { err = cferr.Wrap(cferr.PrivateKeyError, cferr.Unknown, err) return } block := pem.Block{ Type: "EC PRIVATE KEY", Bytes: key, } key = pem.EncodeToMemory(&block) default: panic("Generate should have failed to produce a valid key.") } csr, err = Generate(priv.(crypto.Signer), req) if err != nil { log.Errorf("failed to generate a CSR: %v", err) err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err) } return }
func main() { var s *server.Server if initToken != "" { s = initializeServer() } else { s, err := server.NewServerFromFile(certFile, keyFile, caFile, net.JoinHostPort("", port), net.JoinHostPort("", metricsPort)) if err != nil { log.Warningf("Could not create server. Run with `gokeyless -init-token=XXX` to get %s and %s", keyFile, certFile) log.Fatal(err) } if err := s.LoadKeysFromDir(keyDir, LoadKey); err != nil { log.Fatal(err) } // Start server in background, then listen for SIGHUPs to reload keys. go func() { log.Fatal(s.ListenAndServe()) }() } if pidFile != "" { if f, err := os.Create(pidFile); err != nil { log.Errorf("error creating pid file: %v", err) } else { fmt.Fprintf(f, "%d", os.Getpid()) f.Close() } } c := make(chan os.Signal, 1) signal.Notify(c, syscall.SIGHUP) for { select { case <-c: log.Info("Received SIGHUP, reloading keys...") if err := s.LoadKeysFromDir(keyDir, LoadKey); err != nil { log.Fatal(err) } } } }
// post connects to the remote server and returns a Response struct func (srv *server) post(url string, jsonData []byte) (*api.Response, error) { buf := bytes.NewBuffer(jsonData) var resp *http.Response var err error if srv.TLSConfig != nil { transport := srv.createTransport() client := &http.Client{Transport: transport} resp, err = client.Post(url, "application/json", buf) } else { resp, err = http.Post(url, "application/json", buf) } if err != nil { err = fmt.Errorf("failed POST to %s: %v", url, err) return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, err) } body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, errors.Wrap(errors.APIClientError, errors.IOError, err) } resp.Body.Close() if resp.StatusCode != http.StatusOK { log.Errorf("http error with %s", url) return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, stderr.New(string(body))) } var response api.Response err = json.Unmarshal(body, &response) if err != nil { log.Debug("Unable to parse response body:", string(body)) return nil, errors.Wrap(errors.APIClientError, errors.JSONError, err) } if !response.Success || response.Result == nil { if len(response.Errors) > 0 { return nil, errors.Wrap(errors.APIClientError, errors.ServerRequestFailed, stderr.New(response.Errors[0].Message)) } return nil, errors.New(errors.APIClientError, errors.ServerRequestFailed) } return &response, nil }
func fail(w http.ResponseWriter, req *http.Request, status, code int, msg, ad string) { incErrors() if ad != "" { ad = " (" + ad + ")" } log.Errorf("[HTTP %d] %d - %s%s", status, code, msg, ad) dumpReq, err := httputil.DumpRequest(req, true) if err != nil { fmt.Printf("%v#v\n", req) } else { fmt.Printf("%s\n", dumpReq) } res := api.NewErrorResponse(msg, code) w.WriteHeader(status) jenc := json.NewEncoder(w) jenc.Encode(res) }