예제 #1
0
파일: remote.go 프로젝트: kisom/cfssl
// Helper function to perform a remote sign or info request.
func (s *Signer) remoteOp(req interface{}, profile, target string) (resp interface{}, err error) {
	jsonData, err := json.Marshal(req)
	if err != nil {
		return nil, cferr.Wrap(cferr.APIClientError, cferr.JSONError, err)
	}

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

	server := client.NewServer(p.RemoteServer)
	if server == nil {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest,
			errors.New("failed to connect to remote"))
	}

	// There's no auth provider for the "info" method
	if target == "info" {
		resp, err = server.Info(jsonData)
	} else if p.RemoteProvider != nil {
		resp, err = server.AuthSign(jsonData, nil, p.RemoteProvider)
	} else {
		resp, err = server.Sign(jsonData)
	}

	if err != nil {
		return nil, err
	}

	return
}
예제 #2
0
파일: config.go 프로젝트: kisom/cfssl
// LoadConfig attempts to load the configuration from a byte slice.
// On error, it returns nil.
func LoadConfig(config []byte) (*Config, error) {
	var cfg = &Config{}
	err := json.Unmarshal(config, &cfg)
	if err != nil {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
			errors.New("failed to unmarshal configuration: "+err.Error()))
	}

	if cfg.Signing == nil {
		return nil, errors.New("No \"signing\" field present")
	}

	if cfg.Signing.Default == nil {
		log.Debugf("no default given: using default config")
		cfg.Signing.Default = DefaultConfig()
	} else {
		if err := cfg.Signing.Default.populate(cfg); err != nil {
			return nil, err
		}
	}

	for k := range cfg.Signing.Profiles {
		if err := cfg.Signing.Profiles[k].populate(cfg); err != nil {
			return nil, err
		}
	}

	if !cfg.Valid() {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid configuration"))
	}

	log.Debugf("configuration ok")
	return cfg, nil
}
예제 #3
0
파일: db_config.go 프로젝트: kisom/cfssl
// LoadFile attempts to load the db configuration file stored at the path
// and returns the configuration. On error, it returns nil.
func LoadFile(path string) (cfg *DBConfig, err error) {
	log.Debugf("loading db configuration file from %s", path)
	if path == "" {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid path"))
	}

	var body []byte
	body, err = ioutil.ReadFile(path)
	if err != nil {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("could not read configuration file"))
	}

	cfg = &DBConfig{}
	err = json.Unmarshal(body, &cfg)
	if err != nil {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy,
			errors.New("failed to unmarshal configuration: "+err.Error()))
	}

	if cfg.DataSourceName == "" || cfg.DriverName == "" {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid db configuration"))
	}

	return
}
예제 #4
0
파일: client.go 프로젝트: kisom/cfssl
// 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)
	resp, err := http.Post(url, "application/json", buf)
	if err != nil {
		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 {
		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
}
예제 #5
0
파일: bundler.go 프로젝트: kisom/cfssl
// BundleFromRemote fetches the certificate served by the server at
// serverName (or ip, if the ip argument is not the empty string). It
// is expected that the method will be able to make a connection at
// port 443. The certificate used by the server in this connection is
// used to build the bundle, which will necessarily be keyless.
func (b *Bundler) BundleFromRemote(serverName, ip string, flavor BundleFlavor) (*Bundle, error) {
	config := &tls.Config{
		RootCAs:    b.RootPool,
		ServerName: serverName,
	}

	// Dial by IP if present
	var dialName string
	if ip != "" {
		dialName = ip + ":443"
	} else {
		dialName = serverName + ":443"
	}

	log.Debugf("bundling from remote %s", dialName)

	dialer := &net.Dialer{Timeout: time.Duration(5) * time.Second}
	conn, err := tls.DialWithDialer(dialer, "tcp", dialName, config)
	var dialError string
	// If there's an error in tls.Dial, try again with
	// InsecureSkipVerify to fetch the remote bundle to (re-)bundle
	// with. If the bundle is indeed not usable (expired, mismatched
	// hostnames, etc.), report the error.  Otherwise, create a
	// working bundle and insert the tls error in the bundle.Status.
	if err != nil {
		log.Debugf("dial failed: %v", err)
		// record the error msg
		dialError = fmt.Sprintf("Failed rigid TLS handshake with %s: %v", dialName, err)
		// dial again with InsecureSkipVerify
		log.Debugf("try again with InsecureSkipVerify.")
		config.InsecureSkipVerify = true
		conn, err = tls.DialWithDialer(dialer, "tcp", dialName, config)
		if err != nil {
			log.Debugf("dial with InsecureSkipVerify failed: %v", err)
			return nil, errors.Wrap(errors.DialError, errors.Unknown, err)
		}
	}

	connState := conn.ConnectionState()

	certs := connState.PeerCertificates

	err = conn.VerifyHostname(serverName)
	if err != nil {
		log.Debugf("failed to verify hostname: %v", err)
		return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
	}

	// Bundle with remote certs. Inject the initial dial error, if any, to the status reporting.
	bundle, err := b.Bundle(certs, nil, flavor)
	if err != nil {
		return nil, err
	} else if dialError != "" {
		bundle.Status.Messages = append(bundle.Status.Messages, dialError)
	}
	return bundle, err
}
예제 #6
0
파일: bundle.go 프로젝트: kisom/cfssl
// 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{
			[]string{"certificate"},
			[]string{"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)
}
예제 #7
0
파일: config.go 프로젝트: kisom/cfssl
// LoadFile attempts to load the configuration file stored at the path
// and returns the configuration. On error, it returns nil.
func LoadFile(path string) (*Config, error) {
	log.Debugf("loading configuration file from %s", path)
	if path == "" {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("invalid path"))
	}

	body, err := ioutil.ReadFile(path)
	if err != nil {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("could not read configuration file"))
	}

	return LoadConfig(body)
}
예제 #8
0
파일: pkcs7.go 프로젝트: kisom/cfssl
// ParsePKCS7 attempts to parse the DER encoded bytes of a
// PKCS7 structure
func ParsePKCS7(raw []byte) (msg *PKCS7, err error) {

	var pkcs7 initPKCS7
	_, err = asn1.Unmarshal(raw, &pkcs7)
	if err != nil {
		return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
	}

	msg = new(PKCS7)
	msg.Raw = pkcs7.Raw
	msg.ContentInfo = pkcs7.ContentType.String()
	switch {
	case msg.ContentInfo == ObjIDData:
		msg.ContentInfo = "Data"
		_, err = asn1.Unmarshal(pkcs7.Content.Bytes, &msg.Content.Data)
		if err != nil {
			return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
		}
	case msg.ContentInfo == ObjIDSignedData:
		msg.ContentInfo = "SignedData"
		var signedData signedData
		_, err = asn1.Unmarshal(pkcs7.Content.Bytes, &signedData)
		if err != nil {
			return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
		}
		if len(signedData.Certificates.Bytes) != 0 {
			msg.Content.SignedData.Certificates, err = x509.ParseCertificates(signedData.Certificates.Bytes)
			if err != nil {
				return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
			}
		}
		if len(signedData.Crls.Bytes) != 0 {
			msg.Content.SignedData.Crl, err = x509.ParseDERCRL(signedData.Crls.Bytes)
			if err != nil {
				return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
			}
		}
		msg.Content.SignedData.Version = signedData.Version
		msg.Content.SignedData.Raw = pkcs7.Content.Bytes
	case msg.ContentInfo == ObjIDEncryptedData:
		msg.ContentInfo = "EncryptedData"
		var encryptedData EncryptedData
		_, err = asn1.Unmarshal(pkcs7.Content.Bytes, &encryptedData)
		if err != nil {
			return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
		}
		if encryptedData.Version != 0 {
			return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("Only support for PKCS #7 encryptedData version 0"))
		}
		msg.Content.EncryptedData = encryptedData

	default:
		return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("Attempt to parse PKCS# 7 Content not of type data, signed data or encrypted data"))
	}

	return msg, nil

}
예제 #9
0
파일: csr.go 프로젝트: kisom/cfssl
// 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
}
예제 #10
0
파일: helpers.go 프로젝트: kisom/cfssl
// ParseCertificatePEM parses and returns a PEM-encoded certificate,
// can handle PEM encoded PKCS #7 structures.
func ParseCertificatePEM(certPEM []byte) (*x509.Certificate, error) {
	certPEM = bytes.TrimSpace(certPEM)
	cert, rest, err := ParseOneCertificateFromPEM(certPEM)
	if err != nil {
		// Log the actual parsing error but throw a default parse error message.
		log.Debugf("Certificate parsing error: %v", err)
		return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed)
	} else if cert == nil {
		return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
	} else if len(rest) > 0 {
		return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("the PEM file should contain only one object"))
	} else if len(cert) > 1 {
		return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("the PKCS7 object in the PEM file should contain only one certificate"))
	}
	return cert[0], nil
}
예제 #11
0
파일: helpers.go 프로젝트: kisom/cfssl
// ParseCertificatesDER parses a DER encoding of a certificate object and possibly private key,
// either PKCS #7, PKCS #12, or raw x509.
func ParseCertificatesDER(certsDER []byte, password string) (certs []*x509.Certificate, key crypto.Signer, err error) {
	certsDER = bytes.TrimSpace(certsDER)
	pkcs7data, err := pkcs7.ParsePKCS7(certsDER)
	if err != nil {
		var pkcs12data interface{}
		certs = make([]*x509.Certificate, 1)
		pkcs12data, certs[0], err = pkcs12.Decode(certsDER, password)
		if err != nil {
			certs, err = x509.ParseCertificates(certsDER)
			if err != nil {
				return nil, nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
			}
		} else {
			key = pkcs12data.(crypto.Signer)
		}
	} else {
		if pkcs7data.ContentInfo != "SignedData" {
			return nil, nil, cferr.Wrap(cferr.CertificateError, cferr.DecodeFailed, errors.New("can only extract certificates from signed data content info"))
		}
		certs = pkcs7data.Content.SignedData.Certificates
	}
	if certs == nil {
		return nil, key, cferr.New(cferr.CertificateError, cferr.DecodeFailed)
	}
	return certs, key, nil
}
예제 #12
0
파일: ocsp.go 프로젝트: kisom/cfssl
// NewSignerFromFile reads the issuer cert, the responder cert and the responder key
// from PEM files, and takes an interval in seconds
func NewSignerFromFile(issuerFile, responderFile, keyFile string, interval time.Duration) (Signer, error) {
	log.Debug("Loading issuer cert: ", issuerFile)
	issuerBytes, err := ioutil.ReadFile(issuerFile)
	if err != nil {
		return nil, err
	}
	log.Debug("Loading responder cert: ", responderFile)
	responderBytes, err := ioutil.ReadFile(responderFile)
	if err != nil {
		return nil, err
	}
	log.Debug("Loading responder key: ", keyFile)
	keyBytes, err := ioutil.ReadFile(keyFile)
	if err != nil {
		return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err)
	}

	issuerCert, err := helpers.ParseCertificatePEM(issuerBytes)
	if err != nil {
		return nil, err
	}

	responderCert, err := helpers.ParseCertificatePEM(responderBytes)
	if err != nil {
		return nil, err
	}

	key, err := helpers.ParsePrivateKeyPEM(keyBytes)
	if err != nil {
		log.Debug("Malformed private key %v", err)
		return nil, err
	}

	return NewSigner(issuerCert, responderCert, key, interval)
}
예제 #13
0
파일: initca.go 프로젝트: kisom/cfssl
// signWithCSR creates a new root certificate from signing a X509.CertificateRequest
// by a crypto.Signer.
func signWithCSR(tpl *x509.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) {
	csrPEM, err = x509.CreateCertificateRequest(rand.Reader, tpl, priv)
	if err != nil {
		log.Errorf("failed to generate a CSR: %v", err)
		// The use of CertificateError was a matter of some
		// debate; it is the one edge case in which a new
		// error category specifically for CSRs might be
		// useful, but it was deemed that one edge case did
		// not a new category justify.
		err = cferr.Wrap(cferr.CertificateError, cferr.BadRequest, err)
		return
	}

	p := &pem.Block{
		Type:  "CERTIFICATE REQUEST",
		Bytes: csrPEM,
	}
	csrPEM = pem.EncodeToMemory(p)

	s, err := local.NewSigner(priv, nil, signer.DefaultSigAlgo(priv), nil)
	if err != nil {
		log.Errorf("failed to create signer: %v", err)
		return
	}
	s.SetPolicy(CAPolicy)

	signReq := signer.SignRequest{Request: string(csrPEM)}
	cert, err = s.Sign(signReq)
	return
}
예제 #14
0
파일: local.go 프로젝트: kisom/cfssl
// NewSignerFromFile generates a new local signer from a caFile
// and a caKey file, both PEM encoded.
func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signer, error) {
	log.Debug("Loading CA: ", caFile)
	ca, err := ioutil.ReadFile(caFile)
	if err != nil {
		return nil, err
	}
	log.Debug("Loading CA key: ", caKeyFile)
	cakey, err := ioutil.ReadFile(caKeyFile)
	if err != nil {
		return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err)
	}

	parsedCa, err := helpers.ParseCertificatePEM(ca)
	if err != nil {
		return nil, err
	}

	priv, err := helpers.ParsePrivateKeyPEM(cakey)
	if err != nil {
		log.Debug("Malformed private key %v", err)
		return nil, err
	}

	return NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy)
}
예제 #15
0
파일: certdb.go 프로젝트: kisom/cfssl
// InsertCertificate puts a CertificateRecord into db.
func InsertCertificate(db *sql.DB, cr *CertificateRecord) error {
	res, err := db.Exec(
		insertSQL,
		cr.Serial,
		cr.CALabel,
		cr.Status,
		cr.Reason,
		cr.Expiry.UTC(),
		cr.RevokedAt,
		cr.PEM,
	)
	if err != nil {
		return wrapCertStoreError(err)
	}

	numRowsAffected, _ := res.RowsAffected()

	if numRowsAffected == 0 {
		return cferr.Wrap(cferr.CertStoreError, cferr.InsertionFailed, fmt.Errorf("failed to insert the certificate record"))
	}

	if numRowsAffected != 1 {
		return wrapCertStoreError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected))
	}

	return nil
}
예제 #16
0
파일: initca.go 프로젝트: kisom/cfssl
// validator contains the default validation logic for certificate
// authority certificates. The only requirement here is that the
// certificate have a non-empty subject field.
func validator(req *csr.CertificateRequest) error {
	if req.CN != "" {
		return nil
	}

	if len(req.Names) == 0 {
		return cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("missing subject information"))
	}

	for i := range req.Names {
		if csr.IsNameEmpty(req.Names[i]) {
			return cferr.Wrap(cferr.PolicyError, cferr.InvalidRequest, errors.New("missing subject information"))
		}
	}

	return nil
}
예제 #17
0
파일: helpers.go 프로젝트: kisom/cfssl
// ParseSelfSignedCertificatePEM parses a PEM-encoded certificate and check if it is self-signed.
func ParseSelfSignedCertificatePEM(certPEM []byte) (*x509.Certificate, error) {
	cert, err := ParseCertificatePEM(certPEM)
	if err != nil {
		return nil, err
	}

	if err := cert.CheckSignature(cert.SignatureAlgorithm, cert.RawTBSCertificate, cert.Signature); err != nil {
		return nil, cferr.Wrap(cferr.CertificateError, cferr.VerifyFailed, err)
	}
	return cert, nil
}
예제 #18
0
파일: client.go 프로젝트: kisom/cfssl
// request performs the common logic for Sign and Info, performing the actual
// request and returning the resultant certificate.
func (srv *server) request(jsonData []byte, target string) ([]byte, error) {
	result, err := srv.getResultMap(jsonData, target)
	if err != nil {
		return nil, err
	}
	cert := result["certificate"].(string)
	if cert != "" {
		return []byte(cert), nil
	}

	return nil, errors.Wrap(errors.APIClientError, errors.ClientHTTPError, stderr.New("response doesn't contain certificate."))
}
예제 #19
0
파일: client.go 프로젝트: kisom/cfssl
func (srv *server) getResultMap(jsonData []byte, target string) (result map[string]interface{}, err error) {
	url := srv.getURL(target)
	response, err := srv.post(url, jsonData)
	if err != nil {
		return
	}
	result, ok := response.Result.(map[string]interface{})
	if !ok {
		err = errors.Wrap(errors.APIClientError, errors.ClientHTTPError, stderr.New("response is formatted improperly"))
		return
	}
	return
}
예제 #20
0
파일: bundler.go 프로젝트: kisom/cfssl
// 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) {
	var caBundle, intBundle []byte
	var err error

	if caBundleFile != "" {
		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)
		}
	}

	if intBundleFile != "" {
		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 IntermediateStash != "" {
		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)

}
예제 #21
0
파일: selfsign.go 프로젝트: kisom/cfssl
// parseCertificateRequest takes an incoming certificate request and
// builds a certificate template from it.
func parseCertificateRequest(priv crypto.Signer, csrBytes []byte) (template *x509.Certificate, err error) {

	csr, err := x509.ParseCertificateRequest(csrBytes)
	if err != nil {
		err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
		return
	}

	err = helpers.CheckSignature(csr, csr.SignatureAlgorithm, csr.RawTBSCertificateRequest, csr.Signature)
	if err != nil {
		err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err)
		return
	}

	template = &x509.Certificate{
		Subject:            csr.Subject,
		PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
		PublicKey:          csr.PublicKey,
		SignatureAlgorithm: signer.DefaultSigAlgo(priv),
	}

	return
}
예제 #22
0
파일: client.go 프로젝트: kisom/cfssl
// authReq is the common logic for AuthSign and AuthInfo -- perform the given
// request, and return the resultant certificate.
// The target is either 'sign' or 'info'.
func (srv *server) authReq(req, ID []byte, provider auth.Provider, target string) ([]byte, error) {
	url := srv.getURL("auth" + target)

	token, err := provider.Token(req)
	if err != nil {
		return nil, errors.Wrap(errors.APIClientError, errors.AuthenticationFailure, err)
	}

	aReq := &auth.AuthenticatedRequest{
		Timestamp:     time.Now().Unix(),
		RemoteAddress: ID,
		Token:         token,
		Request:       req,
	}

	jsonData, err := json.Marshal(aReq)
	if err != nil {
		return nil, errors.Wrap(errors.APIClientError, errors.JSONError, err)
	}

	response, err := srv.post(url, jsonData)
	if err != nil {
		return nil, err
	}

	result, ok := response.Result.(map[string]interface{})
	if !ok {
		return nil, errors.New(errors.APIClientError, errors.JSONError)
	}

	cert, ok := result["certificate"].(string)
	if !ok {
		return nil, errors.New(errors.APIClientError, errors.JSONError)
	}

	return []byte(cert), nil
}
예제 #23
0
파일: signer.go 프로젝트: kisom/cfssl
// ParseCertificateRequest takes an incoming certificate request and
// builds a certificate template from it.
func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certificate, err error) {
	csr, err := x509.ParseCertificateRequest(csrBytes)
	if err != nil {
		err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
		return
	}

	err = helpers.CheckSignature(csr, csr.SignatureAlgorithm, csr.RawTBSCertificateRequest, csr.Signature)
	if err != nil {
		err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err)
		return
	}

	template = &x509.Certificate{
		Subject:            csr.Subject,
		PublicKeyAlgorithm: csr.PublicKeyAlgorithm,
		PublicKey:          csr.PublicKey,
		SignatureAlgorithm: s.SigAlgo(),
		DNSNames:           csr.DNSNames,
		IPAddresses:        csr.IPAddresses,
	}

	return
}
예제 #24
0
파일: bundler.go 프로젝트: kisom/cfssl
// BundleFromFile takes a set of files containing the PEM-encoded leaf certificate
// (optionally along with some intermediate certs), the PEM-encoded private key
// and returns the bundle built from that key and the certificate(s).
func (b *Bundler) BundleFromFile(bundleFile, keyFile string, flavor BundleFlavor, password string) (*Bundle, error) {
	log.Debug("Loading Certificate: ", bundleFile)
	certsRaw, err := ioutil.ReadFile(bundleFile)
	if err != nil {
		return nil, errors.Wrap(errors.CertificateError, errors.ReadFailed, err)
	}

	var keyPEM []byte
	// Load private key PEM only if a file is given
	if keyFile != "" {
		log.Debug("Loading private key: ", keyFile)
		keyPEM, err = ioutil.ReadFile(keyFile)
		if err != nil {
			log.Debugf("failed to read private key: ", err)
			return nil, errors.Wrap(errors.PrivateKeyError, errors.ReadFailed, err)
		}
		if len(keyPEM) == 0 {
			log.Debug("key is empty")
			return nil, errors.Wrap(errors.PrivateKeyError, errors.DecodeFailed, err)
		}
	}

	return b.BundleFromPEMorDER(certsRaw, keyPEM, flavor, password)
}
예제 #25
0
파일: local.go 프로젝트: kisom/cfssl
func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile) (cert []byte, err error) {
	err = signer.FillTemplate(template, s.policy.Default, profile)
	if err != nil {
		return
	}

	var initRoot bool
	if s.ca == nil {
		if !template.IsCA {
			err = cferr.New(cferr.PolicyError, cferr.InvalidRequest)
			return
		}
		template.DNSNames = nil
		s.ca = template
		initRoot = true
		template.MaxPathLen = signer.MaxPathLen
	} else if template.IsCA {
		template.MaxPathLen = 1
		template.DNSNames = nil
	}

	derBytes, err := x509.CreateCertificate(rand.Reader, template, s.ca, template.PublicKey, s.priv)
	if err != nil {
		return nil, cferr.Wrap(cferr.CertificateError, cferr.Unknown, err)
	}
	if initRoot {
		s.ca, err = x509.ParseCertificate(derBytes)
		if err != nil {
			return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
		}
	}

	cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
	log.Infof("signed certificate with serial number %d", template.SerialNumber)
	return
}
예제 #26
0
파일: signer.go 프로젝트: kisom/cfssl
// Profile gets the specific profile from the signer
func Profile(s Signer, profile string) (*config.SigningProfile, error) {
	var p *config.SigningProfile
	policy := s.Policy()
	if policy != nil && policy.Profiles != nil && profile != "" {
		p = policy.Profiles[profile]
	}

	if p == nil && policy != nil {
		p = policy.Default
	}

	if p == nil {
		return nil, cferr.Wrap(cferr.APIClientError, cferr.ClientHTTPError, errors.New("profile must not be nil"))
	}
	return p, nil
}
예제 #27
0
파일: certdb.go 프로젝트: kisom/cfssl
// RevokeCertificate updates a certificate with a given serial number and marks it revoked.
func RevokeCertificate(db *sql.DB, serial string, reasonCode int) error {
	result, err := db.Exec(updateRevokeSQL, reasonCode, serial)

	if err != nil {
		return wrapCertStoreError(err)
	}

	numRowsAffected, _ := result.RowsAffected()

	if numRowsAffected == 0 {
		return cferr.Wrap(cferr.CertStoreError, cferr.RecordNotFound, fmt.Errorf("failed to revoke the certificate: certificate not found"))
	}

	if numRowsAffected != 1 {
		return wrapCertStoreError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected))
	}

	return nil
}
예제 #28
0
파일: certdb.go 프로젝트: kisom/cfssl
// UpdateOCSP updates a ocsp response record with a given serial number.
func UpdateOCSP(db *sql.DB, serial, body string, expiry time.Time) (err error) {
	var result sql.Result
	result, err = db.Exec(updateOCSPSQL, serial, body, expiry)

	if err != nil {
		return wrapCertStoreError(err)
	}

	var numRowsAffected int64
	numRowsAffected, err = result.RowsAffected()

	if numRowsAffected == 0 {
		return cferr.Wrap(cferr.CertStoreError, cferr.RecordNotFound, fmt.Errorf("failed to update the OCSP record"))
	}

	if numRowsAffected != 1 {
		return wrapCertStoreError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected))
	}
	return
}
예제 #29
0
파일: certdb.go 프로젝트: kisom/cfssl
// InsertOCSP puts a new OCSPRecord into the db.
func InsertOCSP(db *sql.DB, rr *OCSPRecord) error {
	res, err := db.Exec(
		insertOCSPSQL,
		rr.Serial,
		rr.Body,
		rr.Expiry.UTC(),
	)
	if err != nil {
		return wrapCertStoreError(err)
	}

	numRowsAffected, _ := res.RowsAffected()

	if numRowsAffected == 0 {
		return cferr.Wrap(cferr.CertStoreError, cferr.InsertionFailed, fmt.Errorf("failed to insert the OCSP record"))
	}

	if numRowsAffected != 1 {
		return wrapCertStoreError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected))
	}

	return nil
}
예제 #30
0
파일: selfsign.go 프로젝트: kisom/cfssl
// Sign creates a new self-signed certificate.
func Sign(priv crypto.Signer, csrPEM []byte, profile *config.SigningProfile) ([]byte, error) {
	if profile == nil {
		return nil, cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, errors.New("no profile for self-signing"))
	}

	p, _ := pem.Decode(csrPEM)
	if p == nil || p.Type != "CERTIFICATE REQUEST" {
		return nil, cferr.New(cferr.CSRError, cferr.BadRequest)
	}

	template, err := parseCertificateRequest(priv, p.Bytes)
	if err != nil {
		return nil, err
	}

	pub := template.PublicKey
	encodedpub, err := x509.MarshalPKIXPublicKey(pub)
	if err != nil {
		return nil, err
	}
	var subPKI subjectPublicKeyInfo
	_, err = asn1.Unmarshal(encodedpub, &subPKI)
	if err != nil {
		return nil, err
	}

	pubhash := sha1.New()
	pubhash.Write(subPKI.SubjectPublicKey.Bytes)

	var (
		eku             []x509.ExtKeyUsage
		ku              x509.KeyUsage
		expiry          time.Duration
		crlURL, ocspURL string
	)

	// The third value returned from Usages is a list of unknown key usages.
	// This should be used when validating the profile at load, and isn't used
	// here.
	ku, eku, _ = profile.Usages()
	expiry = profile.Expiry

	if ku == 0 && len(eku) == 0 {
		err = cferr.New(cferr.PolicyError, cferr.NoKeyUsages)
		return nil, err
	}

	if expiry == 0 {
		expiry = threeMonths
	}

	now := time.Now()
	serialNumber, err := rand.Int(rand.Reader, new(big.Int).SetInt64(math.MaxInt64))
	if err != nil {
		err = cferr.Wrap(cferr.CSRError, cferr.Unknown, err)
		return nil, err
	}

	template.SerialNumber = serialNumber
	template.NotBefore = now.Add(-5 * time.Minute).UTC()
	template.NotAfter = now.Add(expiry).UTC()
	template.KeyUsage = ku
	template.ExtKeyUsage = eku
	template.BasicConstraintsValid = true
	template.IsCA = profile.CA
	template.SubjectKeyId = pubhash.Sum(nil)

	if ocspURL != "" {
		template.OCSPServer = []string{ocspURL}
	}
	if crlURL != "" {
		template.CRLDistributionPoints = []string{crlURL}
	}

	if len(profile.IssuerURL) != 0 {
		template.IssuingCertificateURL = profile.IssuerURL
	}

	cert, err := x509.CreateCertificate(rand.Reader, template, template, pub, priv)
	if err != nil {
		return nil, err
	}

	cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert})
	return cert, nil
}