// 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) }
// VerifyCertificate ensures that the certificate passed in hasn't // expired and checks the CRL for the server. func VerifyCertificate(cert *x509.Certificate) (revoked, ok bool) { if !time.Now().Before(cert.NotAfter) { log.Infof("Certificate expired %s\n", cert.NotAfter) return true, true } else if !time.Now().After(cert.NotBefore) { log.Infof("Certificate isn't valid until %s\n", cert.NotBefore) return true, true } return revCheck(cert) }
func initializeServer() *server.Server { var hosts string fmt.Print("Keyserver Hostnames/IPs (comma-seperated): ") fmt.Scanln(&hosts) hostnames := strings.Split(hosts, ",") csr, key, err := csr.ParseRequest(&csr.CertificateRequest{ CN: "Keyless Server Authentication Certificate", Hosts: hostnames, KeyRequest: &csr.BasicKeyRequest{ A: "ecdsa", S: 384, }, }) if err != nil { log.Fatal(err) } if err := ioutil.WriteFile(keyFile, key, 0400); err != nil { log.Fatal(err) } log.Infof("Key generated and saved to %s\n", keyFile) log.Info("Server entering initialization state") s, err := server.NewServerFromFile(initCertFile, initKeyFile, caFile, net.JoinHostPort("", port), net.JoinHostPort("", metricsPort)) if err != nil { log.Fatal(err) } s.ActivationToken = []byte(initToken) go func() { log.Fatal(s.ListenAndServe()) }() cert, err := initAPICall(hostnames, string(csr)) if err != nil { log.Fatal(err) } if err := ioutil.WriteFile(certFile, cert, 0644); err != nil { log.Fatal(err) } log.Infof("Cert saved to %s\n", certFile) // Remove server from activation state and initialize issued certificate. s.ActivationToken = s.ActivationToken[:0] tlsCert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { log.Fatal(err) } s.Config.Certificates = []tls.Certificate{tlsCert} return s }
// SignerFromConfigAndDB takes the Config and creates the appropriate // signer.Signer object with a specified db func SignerFromConfigAndDB(c cli.Config, db *sqlx.DB) (signer.Signer, error) { // If there is a config, use its signing policy. Otherwise create a default policy. var policy *config.Signing if c.CFG != nil { policy = c.CFG.Signing } else { policy = &config.Signing{ Profiles: map[string]*config.SigningProfile{}, Default: config.DefaultConfig(), } } // Make sure the policy reflects the new remote if c.Remote != "" { err := policy.OverrideRemotes(c.Remote) if err != nil { log.Infof("Invalid remote %v, reverting to configuration default", c.Remote) return nil, err } } if c.MutualTLSCertFile != "" && c.MutualTLSKeyFile != "" { err := policy.SetClientCertKeyPairFromFile(c.MutualTLSCertFile, c.MutualTLSKeyFile) if err != nil { log.Infof("Invalid mutual-tls-cert: %s or mutual-tls-key: %s, defaulting to no client auth", c.MutualTLSCertFile, c.MutualTLSKeyFile) return nil, err } log.Infof("Using client auth with mutual-tls-cert: %s and mutual-tls-key: %s", c.MutualTLSCertFile, c.MutualTLSKeyFile) } if c.TLSRemoteCAs != "" { err := policy.SetRemoteCAsFromFile(c.TLSRemoteCAs) if err != nil { log.Infof("Invalid tls-remote-ca: %s, defaulting to system trust store", c.TLSRemoteCAs) return nil, err } log.Infof("Using trusted CA from tls-remote-ca: %s", c.TLSRemoteCAs) } s, err := universal.NewSigner(cli.RootFromConfig(&c), policy) if err != nil { return nil, err } if db != nil { dbAccessor := certsql.NewAccessor(db) s.SetDBAccessor(dbAccessor) } return s, nil }
// worker does all the parsing and validation of the certificate(s) // contained in a single file. It first reads all the data in the // file, then begins parsing certificates in the file. Those // certificates are then checked for revocation. func worker(paths chan string, bundler chan *x509.Certificate, pool *sync.WaitGroup) { defer (*pool).Done() for { path, ok := <-paths if !ok { return } log.Infof("Loading %s", path) fileData, err := ioutil.ReadFile(path) if err != nil { log.Warningf("%v", err) continue } for { var block *pem.Block if len(fileData) == 0 { break } block, fileData = pem.Decode(fileData) if block == nil { log.Warningf("%s: no PEM data found", path) break } else if block.Type != "CERTIFICATE" { log.Info("Skipping non-certificate") continue } cert, err := x509.ParseCertificate(block.Bytes) if err != nil { log.Warningf("Invalid certificate: %v", err) continue } log.Infof("Validating %+v", cert.Subject) revoked, ok := revoke.VerifyCertificate(cert) if !ok { log.Warning("Failed to verify certificate.") } else if !revoked { bundler <- cert } else { log.Info("Skipping revoked certificate") } } } }
// 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) }
// 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 }
// revCheck should check the certificate for any revocations. It // returns a pair of booleans: the first indicates whether the certificate // is revoked, the second indicates whether the revocations were // successfully checked.. This leads to the following combinations: // // false, false: an error was encountered while checking revocations. // // false, true: the certificate was checked successfully and // it is not revoked. // // true, true: the certificate was checked successfully and // it is revoked. // // true, false: failure to check revocation status causes // verification to fail func revCheck(cert *x509.Certificate) (revoked, ok bool) { for _, url := range cert.CRLDistributionPoints { if ldapURL(url) { log.Infof("skipping LDAP CRL: %s", url) continue } if revoked, ok := certIsRevokedCRL(cert, url); !ok { log.Warning("error checking revocation via CRL") if HardFail { return true, false } return false, false } else if revoked { log.Info("certificate is revoked via CRL") return true, true } if revoked, ok := certIsRevokedOCSP(cert, HardFail); !ok { log.Warning("error checking revocation via OCSP") if HardFail { return true, false } return false, false } else if revoked { log.Info("certificate is revoked via OCSP") return true, true } } return false, true }
// 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) } } }
// LoadPlatforms reads the file content as a json object array and convert it // to Platforms. func LoadPlatforms(filename string) error { relativePath := filepath.Dir(filename) // Attempt to load root certificate metadata log.Debug("Loading platform metadata: ", filename) bytes, err := ioutil.ReadFile(filename) if err != nil { return fmt.Errorf("platform metadata failed to load: %v", err) } var rawPlatforms []Platform if bytes != nil { err = json.Unmarshal(bytes, &rawPlatforms) if err != nil { return fmt.Errorf("platform metadata failed to parse: %v", err) } } for _, platform := range rawPlatforms { if platform.KeyStoreFile != "" { platform.KeyStoreFile = path.Join(relativePath, platform.KeyStoreFile) } ok := platform.ParseAndLoad() if !ok { // erase all loaded platforms Platforms = nil return fmt.Errorf("fail to finalize the parsing of platform metadata: %v", platform) } log.Infof("Platform metadata is loaded: %v %v", platform.Name, len(platform.KeyStore)) Platforms = append(Platforms, platform) } return nil }
// 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 }
// SignerFromConfigAndDB takes the Config and creates the appropriate // signer.Signer object with a specified db func SignerFromConfigAndDB(c cli.Config, db *sql.DB) (signer.Signer, error) { // If there is a config, use its signing policy. Otherwise create a default policy. var policy *config.Signing if c.CFG != nil { policy = c.CFG.Signing } else { policy = &config.Signing{ Profiles: map[string]*config.SigningProfile{}, Default: config.DefaultConfig(), } } // Make sure the policy reflects the new remote if c.Remote != "" { err := policy.OverrideRemotes(c.Remote) if err != nil { log.Infof("Invalid remote %v, reverting to configuration default", c.Remote) return nil, err } } s, err := universal.NewSigner(cli.RootFromConfig(&c), policy) if err != nil { return nil, err } s.SetDB(db) return s, nil }
// Handle accepts client information requests, and uses the label to // look up the signer whose public certificate should be retrieved. If // the label is empty, the default label is used. func (h *MultiHandler) Handle(w http.ResponseWriter, r *http.Request) error { req := new(info.Req) body, err := ioutil.ReadAll(r.Body) if err != nil { log.Warningf("failed to read request body: %v", err) return errors.NewBadRequest(err) } err = json.Unmarshal(body, req) if err != nil { log.Warningf("failed to unmarshal request: %v", err) return errors.NewBadRequest(err) } log.Debug("checking label") if req.Label == "" { req.Label = h.defaultLabel } if _, ok := h.signers[req.Label]; !ok { log.Warningf("request for invalid endpoint") return errors.NewBadRequestString("bad label") } log.Debug("getting info") resp, err := h.signers[req.Label].Info(*req) if err != nil { log.Infof("error getting certificate: %v", err) return err } response := api.NewSuccessResponse(resp) w.Header().Set("Content-Type", "application/json") enc := json.NewEncoder(w) return enc.Encode(response) }
// Scan performs the scan to be performed on the given host and stores its result. func (s *Scanner) Scan(host string) (Grade, Output, error) { grade, output, err := s.scan(host) if err != nil { log.Infof("scan: %v", err) return grade, output, err } return grade, output, err }
func (stats *statistics) ListenAndServe(addr string) { http.HandleFunc("/metrics", stats.serveJSON) http.HandleFunc("/metrics.js", stats.serveJSON) http.HandleFunc("/metrics.json", stats.serveJSON) log.Infof("Serving metrics endpoint at %s/metrics\n", addr) log.Critical(http.ListenAndServe(addr, nil)) }
// 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) }
// Handle implements an http.Handler interface for the bundle handler. func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error { blob, matched, err := api.ProcessRequestFirstMatchOf(r, [][]string{ {"certificate"}, {"domain"}, }) if err != nil { log.Warningf("invalid request: %v", err) return err } flavor := blob["flavor"] bf := bundler.Ubiquitous if flavor != "" { bf = bundler.BundleFlavor(flavor) } log.Infof("request for flavor %v", bf) var result *bundler.Bundle switch matched[0] { case "domain": bundle, err := h.bundler.BundleFromRemote(blob["domain"], blob["ip"], bf) if err != nil { log.Warningf("couldn't bundle from remote: %v", err) return err } result = bundle case "certificate": bundle, err := h.bundler.BundleFromPEMorDER([]byte(blob["certificate"]), []byte(blob["private_key"]), bf, "") if err != nil { log.Warning("bad PEM certifcate or private key") return err } serverName := blob["domain"] ip := blob["ip"] if serverName != "" { err := bundle.Cert.VerifyHostname(serverName) if err != nil { return errors.Wrap(errors.CertificateError, errors.VerifyFailed, err) } } if ip != "" { err := bundle.Cert.VerifyHostname(ip) if err != nil { return errors.Wrap(errors.CertificateError, errors.VerifyFailed, err) } } result = bundle } log.Info("wrote response") return api.SendResponse(w, result) }
func (g *group) Dial(c *Client) (conn *gokeyless.Conn, err error) { g.Lock() defer g.Unlock() if g.Len() == 0 { err = errors.New("remote group empty") return } var i *item var popped []*item for g.Len() > 0 { i = heap.Pop(g).(*item) popped = append(popped, i) if conn, err = i.Dial(c); err == nil { break } i.p = 0 i.errs = append(i.errs, err) } for _, f := range popped { heap.Push(g, f) } if err != nil { return } go func() { defer conn.Close() for { start := time.Now() err := conn.Ping(nil) duration := time.Since(start) g.Lock() if err != nil { i.p = 0 i.errs = append(i.errs, err) } else { i.p.Update(1 / float64(duration)) } heap.Fix(g, i.index) g.Unlock() if err != nil { log.Infof("Ping failed: %v", err) return } time.Sleep(time.Minute) } }() return }
// ListenAndServe listens on the TCP network address s.Addr and then // calls Serve to handle requests on incoming keyless connections. func (s *Server) ListenAndServe() error { l, err := net.Listen("tcp", s.Addr) if err != nil { return err } log.Infof("Listenting at %s\n", l.Addr()) return s.Serve(l) }
// ServeHTTP encapsulates the call to underlying Handler to handle the request // and return the response with proper HTTP status code func (h HttpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error // Throw 405 when requested with an unsupported verb. if r.Method != h.Method { err = errors.NewMethodNotAllowed(r.Method) } else { err = h.Handle(w, r) } status := handleError(w, err) log.Infof("%s - \"%s %s\" %d", r.RemoteAddr, r.Method, r.URL, status) }
// registerHandlers instantiates various handlers and associate them to corresponding endpoints. func registerHandlers() { for path, getHandler := range v1Endpoints { path = "/api/v1/cfssl/" + path log.Infof("Setting up '%s' endpoint", path) if handler, err := getHandler(); err != nil { log.Warningf("endpoint '%s' is disabled: %v", path, err) } else { http.Handle(path, handler) } } for path, getHandler := range staticEndpoints { log.Infof("Setting up '%s' endpoint", path) if handler, err := getHandler(); err != nil { log.Warningf("endpoint '%s' is disabled: %v", path, err) } else { http.Handle(path, handler) } } log.Info("Handler set up complete.") }
// RunServerTests load tests a server with a given number of workers and ammount of time. func RunServerTests(testLen time.Duration, workers int, c *client.Client, server string, privkeys []*client.PrivateKey) { log.Infof("Testing %s and %d keys for %v with %d workers...", server, len(privkeys), testLen, workers) running := make(chan bool, workers) errs := make(chan error) for i := 0; i < workers; i++ { running <- true go func() { for range running { errs <- testConnect(c, server) for _, priv := range privkeys { errs <- testKey(priv) } running <- true } }() } timeout := time.After(testLen) var testCount, errCount int for { select { case err := <-errs: testCount++ fmt.Print(".") if err != nil { log.Error(err) errCount++ } case <-timeout: close(running) log.Infof("Completed with %d errors / %d tests", errCount, testCount) return } } }
// registerHandlers instantiates various handlers and associate them to corresponding endpoints. func registerHandlers() { for path, getHandler := range endpoints { path = v1APIPath(path) log.Infof("Setting up '%s' endpoint", path) if handler, err := getHandler(); err != nil { log.Warningf("endpoint '%s' is disabled: %v", path, err) } else { http.Handle(path, handler) } } log.Info("Handler set up complete.") }
func (keys *defaultKeystore) Get(op *gokeyless.Operation) (priv crypto.Signer, ok bool) { keys.RLock() defer keys.RUnlock() ski := op.SKI if ski.Valid() { priv, ok = keys.skis[ski] } else { if !ok { log.Debug("Couldn't look up key based on SKI, trying Digest.") if ski, ok = keys.digests[op.Digest]; ok { priv, ok = keys.skis[ski] } } if !ok { log.Debug("Couldn't look up key based on Digest, trying SNI.") if ski, ok = keys.snis[op.SNI]; ok { priv, ok = keys.skis[ski] } } if !ok { if op.ServerIP != nil { log.Debug("Couldn't look up key based on SNI, trying Server IP.") if ski, ok = keys.serverIPs[op.ServerIP.String()]; ok { priv, ok = keys.skis[ski] } } } if !ok { if op.ClientIP != nil { log.Debug("Couldn't look up key based on Server IP, trying Client IP.") if ski, ok = keys.clientIPs[op.ClientIP.String()]; ok { priv, ok = keys.skis[ski] } } } } if !ok { log.Infof("Couldn't look up key for %s.", op) } else if len(keys.validAKIs[ski]) > 0 && !keys.validAKIs[ski].Contains(op.AKI) { log.Warningf("Attempt to access key with invalid AKI: %s", op.AKI) return nil, false } return }
// registerHandlers instantiates various handlers and associate them to corresponding endpoints. func registerHandlers() { for path, getHandler := range endpoints { log.Debugf("getHandler for %s", path) if handler, err := getHandler(); err != nil { log.Warningf("endpoint '%s' is disabled: %v", path, err) } else { if path, handler, err = wrapHandler(path, handler, err); err != nil { log.Warningf("endpoint '%s' is disabled by wrapper: %v", path, err) } else { log.Infof("endpoint '%s' is enabled", path) http.Handle(path, handler) } } } log.Info("Handler set up complete.") }
// ServeHTTP encapsulates the call to underlying Handler to handle the request // and return the response with proper HTTP status code func (h HTTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var err error var match bool // Throw 405 when requested with an unsupported verb. for _, m := range h.Methods { if m == r.Method { match = true } } if match { err = h.Handle(w, r) } else { err = errors.NewMethodNotAllowed(r.Method) } status := HandleError(w, err) log.Infof("%s - \"%s %s\" %d", r.RemoteAddr, r.Method, r.URL, status) }
// 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 }
// 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 }
// RegisterDir reads all .pubkey and .crt files from a directory and returns associated PublicKey structs. func (c *Client) RegisterDir(server, dir string, LoadPubKey func([]byte) (crypto.PublicKey, error)) (privkeys []*PrivateKey, err error) { err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err != nil { return err } isPubKey := pubkeyExt.MatchString(info.Name()) isCert := crtExt.MatchString(info.Name()) if !info.IsDir() && (isPubKey || isCert) { log.Infof("Loading %s...\n", path) var in []byte if in, err = ioutil.ReadFile(path); err != nil { return err } var priv *PrivateKey if isPubKey { var pub crypto.PublicKey if pub, err = LoadPubKey(in); err != nil { return err } if priv, err = c.RegisterPublicKey(server, pub); err != nil { return err } } else { var cert *x509.Certificate if cert, err = helpers.ParseCertificatePEM(in); err != nil { return err } if priv, err = c.RegisterCert(server, cert); err != nil { return err } } privkeys = append(privkeys, priv) } return nil }) return }
// scanFiles walks the files listed in the arguments. These files may // be either certificate files or directories containing certificates. func scanFiles(paths chan string) { walker := func(path string, info os.FileInfo, err error) error { log.Infof("Found %s", path) if err != nil { return err } if info.Mode().IsRegular() { paths <- path } return nil } for _, path := range flag.Args() { err := filepath.Walk(path, walker) if err != nil { log.Errorf("Walk failed: %v", err) } } close(paths) }