// 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 }
// 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 }
// Given a slice of PKCS #7 content infos containing PKCS #12 Safe Bag Data, // getBags returns those Safe Bags. func getBags(authenticatedSafe []asn1.RawValue, password []byte) (bags []safeBag, err error) { for _, contentInfo := range authenticatedSafe { var safeContents []safeBag bagContainer, err := pkcs7.ParsePKCS7(contentInfo.FullBytes) if err != nil { return nil, err } switch { case bagContainer.ContentInfo == "Data": if _, err = asn1.Unmarshal(bagContainer.Content.Data, &safeContents); err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } case bagContainer.ContentInfo == "EncryptedData": data, err := decrypt(bagContainer.Content.EncryptedData.EncryptedContentInfo.ContentEncryptionAlgorithm, bagContainer.Content.EncryptedData.EncryptedContentInfo.EncryptedContent, password) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } if _, err = asn1.Unmarshal(data, &safeContents); err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err) } default: return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, errors.New("Only support for bags encoded in Data and EncryptedData types")) } bags = append(bags, safeContents...) } return bags, nil }
// 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 }
// 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 }
// 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 }
// 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, EmailAddresses: csr.EmailAddresses, } return }
// 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) }
// 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 }
// 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) }
// 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) }
// 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 }
// 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) ([]*x509.Certificate, crypto.Signer, error) { var certs []*x509.Certificate var key crypto.Signer certsDER = bytes.TrimSpace(certsDER) pkcs7data, err := pkcs7.ParsePKCS7(certsDER) if err != nil { pkcs12data, err := pkcs12.ParsePKCS12(certsDER, []byte(password)) if err != nil { certs, err = x509.ParseCertificates(certsDER) if err != nil { return nil, nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed) } } else { key = pkcs12data.PrivateKey certs = pkcs12data.Certificates } } 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 }
// InsertCertificate puts a certdb.CertificateRecord into db. func (d *Accessor) InsertCertificate(cr certdb.CertificateRecord) error { err := d.checkDB() if err != nil { return err } res, err := d.db.NamedExec(insertSQL, &certdb.CertificateRecord{ Serial: cr.Serial, AKI: cr.AKI, CALabel: cr.CALabel, Status: cr.Status, Reason: cr.Reason, Expiry: cr.Expiry.UTC(), RevokedAt: cr.RevokedAt.UTC(), PEM: cr.PEM, }) if err != nil { return wrapSQLError(err) } numRowsAffected, err := res.RowsAffected() if numRowsAffected == 0 { return cferr.Wrap(cferr.CertStoreError, cferr.InsertionFailed, fmt.Errorf("failed to insert the certificate record")) } if numRowsAffected != 1 { return wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected)) } return err }
// UpdateOCSP updates a ocsp response record with a given serial number. func (d *Accessor) UpdateOCSP(serial, aki, body string, expiry time.Time) error { err := d.checkDB() if err != nil { return err } result, err := d.db.NamedExec(updateOCSPSQL, &certdb.OCSPRecord{ AKI: aki, Body: body, Expiry: expiry.UTC(), Serial: serial, }) if err != nil { return wrapSQLError(err) } 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 wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected)) } return err }
// RevokeCertificate updates a certificate with a given serial number and marks it revoked. func (d *Accessor) RevokeCertificate(serial, aki string, reasonCode int) error { err := d.checkDB() if err != nil { return err } result, err := d.db.NamedExec(updateRevokeSQL, &certdb.CertificateRecord{ AKI: aki, Reason: reasonCode, Serial: serial, }) if err != nil { return wrapSQLError(err) } numRowsAffected, err := 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 wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected)) } return err }
// 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 }
// 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 }
// 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 }
// InsertCertificate puts a certdb.CertificateRecord into db. func (d *Accessor) InsertCertificate(cr *certdb.CertificateRecord) error { err := d.checkDB() if err != nil { return err } res, err := d.db.Exec( insertSQL, cr.Serial, cr.CALabel, cr.Status, cr.Reason, cr.Expiry.UTC(), cr.RevokedAt, cr.PEM, ) if err != nil { return wrapSQLError(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 wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected)) } return nil }
// 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) }
// 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) }
func (d *Accessor) checkDB() error { if d.db == nil { return cferr.Wrap(cferr.CertStoreError, cferr.Unknown, errors.New("unknown db object, please check SetDB method")) } return nil }
// InsertOCSP puts a new certdb.OCSPRecord into the db. func (d *Accessor) InsertOCSP(rr *certdb.OCSPRecord) error { err := d.checkDB() if err != nil { return err } res, err := d.db.Exec( insertOCSPSQL, rr.Serial, rr.Body, rr.Expiry.UTC(), ) if err != nil { return wrapSQLError(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 wrapSQLError(fmt.Errorf("%d rows are affected, should be 1 row", numRowsAffected)) } return nil }
// 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 } strPassword := os.Getenv("CFSSL_CA_PK_PASSWORD") password := []byte(strPassword) if strPassword == "" { password = nil } priv, err := helpers.ParsePrivateKeyPEMWithPassword(cakey, password) if err != nil { log.Debug("Malformed private key %v", err) return nil, err } return NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy) }
// 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 }
// Sign signs a new certificate based on the PEM-encoded client // certificate or certificate request with the signing profile, // specified by profileName. func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) { profile, err := signer.Profile(s, req.Profile) if err != nil { return } serialSeq := "" if profile.UseSerialSeq { serialSeq = req.SerialSeq } block, _ := pem.Decode([]byte(req.Request)) if block == nil { return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed) } if block.Type != "CERTIFICATE REQUEST" { return nil, cferr.Wrap(cferr.CSRError, cferr.BadRequest, errors.New("not a certificate or csr")) } csrTemplate, err := signer.ParseCertificateRequest(s, block.Bytes) if err != nil { return nil, err } // Copy out only the fields from the CSR authorized by policy. safeTemplate := x509.Certificate{} // If the profile contains no explicit whitelist, assume that all fields // should be copied from the CSR. if profile.CSRWhitelist == nil { safeTemplate = *csrTemplate } else { if profile.CSRWhitelist.Subject { safeTemplate.Subject = csrTemplate.Subject } if profile.CSRWhitelist.PublicKeyAlgorithm { safeTemplate.PublicKeyAlgorithm = csrTemplate.PublicKeyAlgorithm } if profile.CSRWhitelist.PublicKey { safeTemplate.PublicKey = csrTemplate.PublicKey } if profile.CSRWhitelist.SignatureAlgorithm { safeTemplate.SignatureAlgorithm = csrTemplate.SignatureAlgorithm } if profile.CSRWhitelist.DNSNames { safeTemplate.DNSNames = csrTemplate.DNSNames } if profile.CSRWhitelist.IPAddresses { safeTemplate.IPAddresses = csrTemplate.IPAddresses } } OverrideHosts(&safeTemplate, req.Hosts) safeTemplate.Subject = PopulateSubjectFromCSR(req.Subject, safeTemplate.Subject) return s.sign(&safeTemplate, profile, serialSeq) }
// ParseCertificateRequest takes an incoming certificate request and // builds a certificate template from it. func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certificate, err error) { csrv, err := x509.ParseCertificateRequest(csrBytes) if err != nil { err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err) return } err = helpers.CheckSignature(csrv, csrv.SignatureAlgorithm, csrv.RawTBSCertificateRequest, csrv.Signature) if err != nil { err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err) return } template = &x509.Certificate{ Subject: csrv.Subject, PublicKeyAlgorithm: csrv.PublicKeyAlgorithm, PublicKey: csrv.PublicKey, SignatureAlgorithm: s.SigAlgo(), DNSNames: csrv.DNSNames, IPAddresses: csrv.IPAddresses, EmailAddresses: csrv.EmailAddresses, } for _, val := range csrv.Extensions { // Check the CSR for the X.509 BasicConstraints (RFC 5280, 4.2.1.9) // extension and append to template if necessary if val.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) { var constraints csr.BasicConstraints var rest []byte if rest, err = asn1.Unmarshal(val.Value, &constraints); err != nil { return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err) } else if len(rest) != 0 { return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, errors.New("x509: trailing data after X.509 BasicConstraints")) } template.BasicConstraintsValid = true template.IsCA = constraints.IsCA template.MaxPathLen = constraints.MaxPathLen template.MaxPathLenZero = template.MaxPathLen == 0 } } 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 }
// 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 }