예제 #1
0
파일: revoke.go 프로젝트: kisom/cfssl
func revokeMain(args []string, c cli.Config) (err error) {
	if len(args) > 0 {
		return errors.New("argument is provided but not defined; please refer to the usage by flag -h")
	}

	if len(c.Serial) == 0 {
		return errors.New("serial number is required but not provided")
	}

	if c.DBConfigFile == "" {
		return errors.New("need DB config file (provide with -db-config)")
	}

	var db *sql.DB
	db, err = certdb.DBFromConfig(c.DBConfigFile)
	if err != nil {
		return err
	}

	var reasonCode int
	reasonCode, err = ocsp.ReasonStringToCode(c.Reason)
	if err != nil {
		log.Error("Invalid reason code: ", err)
		return
	}

	err = certdb.RevokeCertificate(db, c.Serial, reasonCode)

	return
}
예제 #2
0
파일: scan.go 프로젝트: kisom/cfssl
func (ctx *context) runWorker() {
	for host := range ctx.hosts {
		fmt.Printf("Scanning %s...\n", host)
		results, err := scan.Default.RunScans(host, ctx.c.IP, ctx.c.Family, ctx.c.Scanner, ctx.c.Timeout)
		fmt.Printf("=== %s ===\n", host)
		if err != nil {
			log.Error(err)
		} else {
			printJSON(results)
		}
	}
	ctx.Done()
}
예제 #3
0
파일: ocspsign.go 프로젝트: kisom/cfssl
// Handle responds to requests for a ocsp signature. It creates and signs
// a ocsp response for the provided certificate and status. If the status
// is revoked then it also adds reason and revoked_at. The response is
// base64 encoded.
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		return err
	}
	r.Body.Close()

	// Default the status to good so it matches the cli
	req := &jsonSignRequest{
		Status: "good",
	}
	err = json.Unmarshal(body, req)
	if err != nil {
		return errors.NewBadRequestString("Unable to parse sign request")
	}

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

	signReq := ocsp.SignRequest{
		Certificate: cert,
		Status:      req.Status,
	}
	// We need to convert the time from being a string to a time.Time
	if req.Status == "revoked" {
		signReq.Reason = req.Reason
		// "now" is accepted and the default on the cli so default that here
		if req.RevokedAt == "" || req.RevokedAt == "now" {
			signReq.RevokedAt = time.Now()
		} else {
			signReq.RevokedAt, err = time.Parse("2006-01-02", req.RevokedAt)
			if err != nil {
				return errors.NewBadRequestString("Malformed revocation time")
			}
		}
	}

	resp, err := h.signer.Sign(signReq)
	if err != nil {
		return err
	}

	b64Resp := base64.StdEncoding.EncodeToString(resp)
	result := map[string]string{"ocspResponse": b64Resp}
	return api.SendResponse(w, result)
}
예제 #4
0
파일: signhandler.go 프로젝트: kisom/cfssl
// Handle responds to requests for the CA to sign the certificate request
// present in the "certificate_request" parameter for the host named
// in the "hostname" parameter. The certificate should be PEM-encoded. If
// provided, subject information from the "subject" parameter will be used
// in place of the subject information from the CSR.
func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error {
	log.Info("signature request received")

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

	var req jsonSignRequest

	err = json.Unmarshal(body, &req)
	if err != nil {
		return errors.NewBadRequestString("Unable to parse sign request")
	}

	signReq := jsonReqToTrue(req)

	if req.Request == "" {
		return errors.NewBadRequestString("missing parameter 'certificate_request'")
	}

	var cert []byte
	profile, err := signer.Profile(h.signer, req.Profile)
	if err != nil {
		return err
	}

	if profile.Provider != nil {
		log.Error("profile requires authentication")
		return errors.NewBadRequestString("authentication required")
	}

	cert, err = h.signer.Sign(signReq)
	if err != nil {
		log.Warningf("failed to sign request: %v", err)
		return err
	}

	result := map[string]string{"certificate": string(cert)}
	log.Info("wrote response")
	return api.SendResponse(w, result)
}
예제 #5
0
파일: ocspdump.go 프로젝트: kisom/cfssl
// ocspdumpMain is the main CLI of OCSP dump functionality.
func ocspdumpMain(args []string, c cli.Config) (err error) {
	if c.DBConfigFile == "" {
		log.Error("need DB config file (provide with -db-config)")
		return
	}

	var db *sql.DB
	db, err = certdb.DBFromConfig(c.DBConfigFile)
	if err != nil {
		return err
	}

	var records []*certdb.OCSPRecord
	records, err = certdb.GetUnexpiredOCSPs(db)
	if err != nil {
		return err
	}
	for _, certRecord := range records {
		fmt.Printf("%s\n", base64.StdEncoding.EncodeToString([]byte(certRecord.Body)))
	}
	return nil
}
예제 #6
0
// ParseAndLoad converts HashAlgo and KeyAlgo to corresponding ubiquity value and load
// certificates into internal KeyStore from KeyStoreFiles
func (p *Platform) ParseAndLoad() (ok bool) {
	p.HashUbiquity = p.hashUbiquity()
	p.KeyAlgoUbiquity = p.keyAlgoUbiquity()
	p.KeyStore = map[string]bool{}
	if p.KeyStoreFile != "" {
		pemBytes, err := ioutil.ReadFile(p.KeyStoreFile)
		if err != nil {
			log.Error(err)
			return false
		}
		// Best effort parsing the PEMs such that ignore all borken pem,
		// since some of CA certs have negative serial number which trigger errors.
		for len(pemBytes) > 0 {
			var certs []*x509.Certificate
			certs, rest, err := helpers.ParseOneCertificateFromPEM(pemBytes)
			// If one certificate object is parsed, possibly a PKCS#7
			// structure containing multiple certs, record the raw SHA1 hash(es).
			if err == nil && certs != nil {
				for _, cert := range certs {
					p.KeyStore.Add(cert)
				}
			}

			if len(rest) < len(pemBytes) {
				pemBytes = rest
			} else {
				// No progress in bytes parsing, bail out.
				break
			}
		}
	}
	if p.HashUbiquity <= UnknownHashUbiquity ||
		p.KeyAlgoUbiquity <= UnknownAlgoUbiquity {
		return false
	}
	return true
}
예제 #7
0
파일: crl.go 프로젝트: kisom/cfssl
// 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)
}
예제 #8
0
파일: gencert.go 프로젝트: kisom/cfssl
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
		}

		// 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(req.Hosts) == 0 {
			log.Warning(generator.CSRNoHostMessage)
		}

		cli.PrintCert(key, csrBytes, cert)
	}
	return nil
}
예제 #9
0
파일: config.go 프로젝트: kisom/cfssl
// populate is used to fill in the fields that are not in JSON
//
// First, the ExpiryString parameter is needed to parse
// expiration timestamps from JSON. The JSON decoder is not able to
// decode a string time duration to a time.Duration, so this is called
// when loading the configuration to properly parse and fill out the
// Expiry parameter.
// This function is also used to create references to the auth key
// and default remote for the profile.
// It returns true if ExpiryString is a valid representation of a
// time.Duration, and the AuthKeyString and RemoteName point to
// valid objects. It returns false otherwise.
func (p *SigningProfile) populate(cfg *Config) error {
	if p == nil {
		return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("can't parse nil profile"))
	}

	var err error
	if p.RemoteName == "" && p.AuthRemote.RemoteName == "" {
		log.Debugf("parse expiry in profile")
		if p.ExpiryString == "" {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("empty expiry string"))
		}

		dur, err := time.ParseDuration(p.ExpiryString)
		if err != nil {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
		}

		log.Debugf("expiry is valid")
		p.Expiry = dur

		if p.BackdateString != "" {
			dur, err = time.ParseDuration(p.BackdateString)
			if err != nil {
				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
			}

			p.Backdate = dur
		}

		if !p.NotBefore.IsZero() && !p.NotAfter.IsZero() && p.NotAfter.Before(p.NotBefore) {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
		}

		if len(p.Policies) > 0 {
			for _, policy := range p.Policies {
				for _, qualifier := range policy.Qualifiers {
					if qualifier.Type != "" && qualifier.Type != "id-qt-unotice" && qualifier.Type != "id-qt-cps" {
						return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
							errors.New("invalid policy qualifier type"))
					}
				}
			}
		}
	} else if p.RemoteName != "" {
		log.Debug("match remote in profile to remotes section")
		if p.AuthRemote.RemoteName != "" {
			log.Error("profile has both a remote and an auth remote specified")
			return cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
		}
		if remote := cfg.Remotes[p.RemoteName]; remote != "" {
			if err := p.updateRemote(remote); err != nil {
				return err
			}
		} else {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to find remote in remotes section"))
		}
	} else {
		log.Debug("match auth remote in profile to remotes section")
		if remote := cfg.Remotes[p.AuthRemote.RemoteName]; remote != "" {
			if err := p.updateRemote(remote); err != nil {
				return err
			}
		} else {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to find remote in remotes section"))
		}
	}

	if p.AuthKeyName != "" {
		log.Debug("match auth key in profile to auth_keys section")
		if key, ok := cfg.AuthKeys[p.AuthKeyName]; ok == true {
			if key.Type == "standard" {
				p.Provider, err = auth.New(key.Key, nil)
				if err != nil {
					log.Debugf("failed to create new standard auth provider: %v", err)
					return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
						errors.New("failed to create new standard auth provider"))
				}
			} else {
				log.Debugf("unknown authentication type %v", key.Type)
				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
					errors.New("unknown authentication type"))
			}
		} else {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to find auth_key in auth_keys section"))
		}
	}

	if p.AuthRemote.AuthKeyName != "" {
		log.Debug("match auth remote key in profile to auth_keys section")
		if key, ok := cfg.AuthKeys[p.AuthRemote.AuthKeyName]; ok == true {
			if key.Type == "standard" {
				p.RemoteProvider, err = auth.New(key.Key, nil)
				if err != nil {
					log.Debugf("failed to create new standard auth provider: %v", err)
					return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
						errors.New("failed to create new standard auth provider"))
				}
			} else {
				log.Debugf("unknown authentication type %v", key.Type)
				return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
					errors.New("unknown authentication type"))
			}
		} else {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to find auth_remote's auth_key in auth_keys section"))
		}
	}

	if p.NameWhitelistString != "" {
		log.Debug("compiling whitelist regular expression")
		rule, err := regexp.Compile(p.NameWhitelistString)
		if err != nil {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
				errors.New("failed to compile name whitelist section"))
		}
		p.NameWhitelist = rule
	}

	p.ExtensionWhitelist = map[string]bool{}
	for _, oid := range p.AllowedExtensions {
		p.ExtensionWhitelist[asn1.ObjectIdentifier(oid).String()] = true
	}

	return nil
}
예제 #10
0
파일: ocsprefresh.go 프로젝트: kisom/cfssl
// ocsprefreshMain is the main CLI of OCSP refresh functionality.
func ocsprefreshMain(args []string, c cli.Config) (err error) {
	if c.DBConfigFile == "" {
		log.Error("need DB config file (provide with -db-config)")
		return
	}

	if c.ResponderFile == "" {
		log.Error("need responder certificate (provide with -responder)")
		return
	}

	if c.ResponderKeyFile == "" {
		log.Error("need responder key (provide with -responder-key)")
		return
	}

	if c.CAFile == "" {
		log.Error("need CA certificate (provide with -ca)")
		return
	}

	s, err := SignerFromConfig(c)
	if err != nil {
		log.Critical("Unable to create OCSP signer: ", err)
		return err
	}

	var db *sql.DB
	db, err = certdb.DBFromConfig(c.DBConfigFile)
	if err != nil {
		return err
	}

	var certs []*certdb.CertificateRecord
	certs, err = certdb.GetUnexpiredCertificates(db)
	if err != nil {
		return err
	}

	// Set an expiry timestamp for all certificates refreshed in this batch
	ocspExpiry := time.Now().Add(c.Interval)
	for _, certRecord := range certs {
		cert, err := helpers.ParseCertificatePEM([]byte(certRecord.PEM))
		if err != nil {
			log.Critical("Unable to parse certificate: ", err)
			return err
		}

		req := ocsp.SignRequest{
			Certificate: cert,
			Status:      certRecord.Status,
		}

		if certRecord.Status == "revoked" {
			req.Reason = int(certRecord.Reason)
			req.RevokedAt = certRecord.RevokedAt
		}

		resp, err := s.Sign(req)
		if err != nil {
			log.Critical("Unable to sign OCSP response: ", err)
			return err
		}

		err = certdb.UpsertOCSP(db, cert.SerialNumber.String(), string(resp), ocspExpiry)
		if err != nil {
			log.Critical("Unable to save OCSP response: ", err)
			return err
		}
	}

	return nil
}
예제 #11
0
파일: sign.go 프로젝트: kisom/cfssl
// signerMain is the main CLI of signer functionality.
// [TODO: zi] Decide whether to drop the argument list and only use flags to specify all the inputs.
func signerMain(args []string, c cli.Config) (err error) {
	if c.CSRFile == "" {
		c.CSRFile, args, err = cli.PopFirstArgument(args)
		if err != nil {
			return
		}
	}

	var subjectData *signer.Subject
	if len(args) > 0 {
		var subjectFile string
		subjectFile, args, err = cli.PopFirstArgument(args)
		if err != nil {
			return
		}

		var subjectJSON []byte
		subjectJSON, err = ioutil.ReadFile(subjectFile)
		if err != nil {
			return
		}

		subjectData = new(signer.Subject)
		err = json.Unmarshal(subjectJSON, subjectData)
		if err != nil {
			return
		}
	}

	csr, err := cli.ReadStdin(c.CSRFile)
	if err != nil {
		return
	}

	// Remote can be forced on the command line or in the config
	if c.Remote == "" && c.CFG == nil {
		if c.CAFile == "" {
			log.Error("need CA certificate (provide one with -ca)")
			return
		}

		if c.CAKeyFile == "" {
			log.Error("need CA key (provide one with -ca-key)")
			return
		}
	}

	s, err := SignerFromConfig(c)
	if err != nil {
		return
	}

	req := signer.SignRequest{
		Hosts:   signer.SplitHosts(c.Hostname),
		Request: string(csr),
		Subject: subjectData,
		Profile: c.Profile,
		Label:   c.Label,
	}
	cert, err := s.Sign(req)
	if err != nil {
		return
	}
	cli.PrintCert(nil, csr, cert)
	return
}
예제 #12
0
파일: signhandler.go 프로젝트: kisom/cfssl
// Handle receives the incoming request, validates it, and processes it.
func (h *AuthHandler) Handle(w http.ResponseWriter, r *http.Request) error {
	log.Info("signature request received")

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Errorf("failed to read response body: %v", err)
		return err
	}
	r.Body.Close()

	var aReq auth.AuthenticatedRequest
	err = json.Unmarshal(body, &aReq)
	if err != nil {
		log.Errorf("failed to unmarshal authenticated request: %v", err)
		return errors.NewBadRequest(err)
	}

	var req jsonSignRequest
	err = json.Unmarshal(aReq.Request, &req)
	if err != nil {
		log.Errorf("failed to unmarshal request from authenticated request: %v", err)
		return errors.NewBadRequestString("Unable to parse authenticated sign request")
	}

	// Sanity checks to ensure that we have a valid policy. This
	// should have been checked in NewAuthHandler.
	policy := h.signer.Policy()
	if policy == nil {
		log.Critical("signer was initialised without a signing policy")
		return errors.NewBadRequestString("invalid policy")
	}

	profile, err := signer.Profile(h.signer, req.Profile)
	if err != nil {
		return err
	}

	if profile.Provider == nil {
		log.Error("profile has no authentication provider")
		return errors.NewBadRequestString("no authentication provider")
	}

	if !profile.Provider.Verify(&aReq) {
		log.Warning("received authenticated request with invalid token")
		return errors.NewBadRequestString("invalid token")
	}

	signReq := jsonReqToTrue(req)

	if signReq.Request == "" {
		return errors.NewBadRequestString("missing parameter 'certificate_request'")
	}

	cert, err := h.signer.Sign(signReq)
	if err != nil {
		log.Errorf("signature failed: %v", err)
		return err
	}

	result := map[string]string{"certificate": string(cert)}
	log.Info("wrote response")
	return api.SendResponse(w, result)
}