// ParsePrivateKeyDER parses a PKCS #1, PKCS #8, or elliptic curve // DER-encoded private key. The key must not be in PEM format. func ParsePrivateKeyDER(keyDER []byte) (key crypto.Signer, err error) { generalKey, err := x509.ParsePKCS8PrivateKey(keyDER) if err != nil { generalKey, err = x509.ParsePKCS1PrivateKey(keyDER) if err != nil { generalKey, err = x509.ParseECPrivateKey(keyDER) if err != nil { // We don't include the actual error into // the final error. The reason might be // we don't want to leak any info about // the private key. return nil, cferr.New(cferr.PrivateKeyError, cferr.ParseFailed) } } } switch generalKey.(type) { case *rsa.PrivateKey: return generalKey.(*rsa.PrivateKey), nil case *ecdsa.PrivateKey: return generalKey.(*ecdsa.PrivateKey), nil } // should never reach here return nil, cferr.New(cferr.PrivateKeyError, cferr.ParseFailed) }
// NewAuthHandlerFromSigner creates a new AuthHandler from the signer // that is passed in. func NewAuthHandlerFromSigner(signer signer.Signer) (http.Handler, error) { policy := signer.Policy() if policy == nil { return nil, errors.New(errors.PolicyError, errors.InvalidPolicy) } if policy.Default == nil && policy.Profiles == nil { return nil, errors.New(errors.PolicyError, errors.InvalidPolicy) } // AuthSign will not respond for profiles that have no auth provider. // So if there are no profiles with auth providers in this policy, // we return an error. haveAuth := (policy.Default.Provider != nil) for _, profile := range policy.Profiles { if haveAuth { break } haveAuth = (profile.Provider != nil) } if !haveAuth { return nil, errors.New(errors.PolicyError, errors.InvalidPolicy) } return &api.HTTPHandler{ Handler: &AuthHandler{ signer: signer, }, Methods: []string{"POST"}, }, nil }
// NewHandlerFromSigner generates a new Handler directly from // an existing signer. func NewHandlerFromSigner(signer signer.Signer) (h *api.HTTPHandler, err error) { policy := signer.Policy() if policy == nil { err = errors.New(errors.PolicyError, errors.InvalidPolicy) return } // Sign will only respond for profiles that have no auth provider. // So if all of the profiles require authentication, we return an error. haveUnauth := (policy.Default.Provider == nil) for _, profile := range policy.Profiles { haveUnauth = haveUnauth || (profile.Provider == nil) } if !haveUnauth { err = errors.New(errors.PolicyError, errors.InvalidPolicy) return } return &api.HTTPHandler{ Handler: &Handler{ signer: signer, }, Methods: []string{"POST"}, }, 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) (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 }
// NewSigner creates a new remote Signer directly from a // signing policy. func NewSigner(policy *config.Signing) (*Signer, error) { if policy != nil { if !policy.Valid() { return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy) } return &Signer{policy: policy}, nil } return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy) }
// GetKeyDERFromPEM parses a PEM-encoded private key and returns DER-format key bytes. func GetKeyDERFromPEM(in []byte) ([]byte, error) { keyDER, _ := pem.Decode(in) if keyDER != nil { if procType, ok := keyDER.Headers["Proc-Type"]; ok { if strings.Contains(procType, "ENCRYPTED") { return nil, cferr.New(cferr.PrivateKeyError, cferr.Encrypted) } } return keyDER.Bytes, nil } return nil, cferr.New(cferr.PrivateKeyError, cferr.DecodeFailed) }
// 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 }
func newLocalSigner(root Root, policy *config.Signing) (s signer.Signer, err error) { // shouldProvide indicates whether the // function *should* have produced a key. If // it's true, we should use the signer and // error returned. Otherwise, keep looking for // signers. var shouldProvide bool // localSignerList is defined in the // universal_signers*.go files. These activate // and deactivate signers based on build // flags; for example, // universal_signers_pkcs11.go contains a list // of valid signers when PKCS #11 is turned // on. for _, possibleSigner := range localSignerList { s, shouldProvide, err = possibleSigner(&root, policy) if shouldProvide { break } } if s == nil { err = cferr.New(cferr.PrivateKeyError, cferr.Unknown) } return s, err }
// pkcs11Signer looks for token, module, slot, and PIN configuration // options in the root. func pkcs11Signer(root *Root, policy *config.Signing) (signer.Signer, bool, error) { module := root.Config["pkcs11-module"] tokenLabel := root.Config["pkcs11-token-label"] privateKeyLabel := root.Config["pkcs11-private-key-label"] userPIN := root.Config["pkcs11-user-pin"] certFile := root.Config["cert-file"] if module == "" && tokenLabel == "" && privateKeyLabel == "" && userPIN == "" { return nil, false, nil } if !pkcs11.Enabled { return nil, true, cferr.New(cferr.PrivateKeyError, cferr.Unavailable) } conf := pkcs11.Config{ Module: module, Token: tokenLabel, Label: privateKeyLabel, PIN: userPIN, } s, err := pkcs11.New(certFile, policy, &conf) return s, true, err }
// NewSigner generates a new certificate signer from a Root structure. // This is one of two standard signers: local or remote. If the root // structure specifies a force remote, then a remote signer is created, // otherwise either a remote or local signer is generated based on the // policy. For a local signer, the CertFile and KeyFile need to be // defined in Root. func NewSigner(root Root, policy *config.Signing) (signer.Signer, error) { if policy == nil { policy = &config.Signing{ Profiles: map[string]*config.SigningProfile{}, Default: config.DefaultConfig(), } } if !policy.Valid() { return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy) } var s signer.Signer var err error if root.ForceRemote { s, err = remote.NewSigner(policy) } else { if policy.NeedsLocalSigner() && policy.NeedsRemoteSigner() { s, err = newUniversalSigner(root, policy) } else { if policy.NeedsLocalSigner() { s, err = newLocalSigner(root, policy) } if policy.NeedsRemoteSigner() { s, err = remote.NewSigner(policy) } } } return s, err }
// post connects to the remote server and returns a Response struct func (srv *server) post(url string, jsonData []byte) (*api.Response, error) { buf := bytes.NewBuffer(jsonData) 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 }
// 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 }
// Sign is used with an OCSP signer to request the issuance of // an OCSP response. func (s StandardSigner) Sign(req SignRequest) ([]byte, error) { if req.Certificate == nil { return nil, cferr.New(cferr.OCSPError, cferr.ReadFailed) } // Verify that req.Certificate is issued under s.issuer if bytes.Compare(req.Certificate.RawIssuer, s.issuer.RawSubject) != 0 { return nil, cferr.New(cferr.OCSPError, cferr.IssuerMismatch) } if req.Certificate.CheckSignatureFrom(s.issuer) != nil { return nil, cferr.New(cferr.OCSPError, cferr.IssuerMismatch) } // Round thisUpdate times down to the nearest hour thisUpdate := time.Now().Truncate(time.Hour) nextUpdate := thisUpdate.Add(s.interval) status, ok := StatusCode[req.Status] if !ok { return nil, cferr.New(cferr.OCSPError, cferr.InvalidStatus) } // If the OCSP responder is the same as the issuer, there is no need to // include any certificate in the OCSP response, which decreases the byte size // of OCSP responses dramatically. certificate := s.responder if s.issuer == s.responder || bytes.Equal(s.issuer.Raw, s.responder.Raw) { certificate = nil } template := ocsp.Response{ Status: status, SerialNumber: req.Certificate.SerialNumber, ThisUpdate: thisUpdate, NextUpdate: nextUpdate, Certificate: certificate, ExtraExtensions: req.Extensions, } if status == ocsp.Revoked { template.RevokedAt = req.RevokedAt template.RevocationReason = req.Reason } return ocsp.CreateResponse(s.issuer, s.responder, template, s.key) }
// NewBundlerFromPEM creates a new Bundler from PEM-encoded root certificates and // intermediate certificates. // If caBundlePEM is nil, the resulting Bundler can only do "Force" bundle. func NewBundlerFromPEM(caBundlePEM, intBundlePEM []byte) (*Bundler, error) { log.Debug("parsing root certificates from PEM") roots, err := helpers.ParseCertificatesPEM(caBundlePEM) if err != nil { log.Errorf("failed to parse root bundle: %v", err) return nil, errors.New(errors.RootError, errors.ParseFailed) } log.Debug("parse intermediate certificates from PEM") intermediates, err := helpers.ParseCertificatesPEM(intBundlePEM) if err != nil { log.Errorf("failed to parse intermediate bundle: %v", err) return nil, errors.New(errors.IntermediatesError, errors.ParseFailed) } b := &Bundler{ KnownIssuers: map[string]bool{}, IntermediatePool: x509.NewCertPool(), } log.Debug("building certificate pools") // RootPool will be nil if caBundlePEM is nil, also // that translates to caBundleFile is "". // Systems root store will be used. if caBundlePEM != nil { b.RootPool = x509.NewCertPool() } for _, c := range roots { b.RootPool.AddCert(c) b.KnownIssuers[string(c.Signature)] = true } for _, c := range intermediates { b.IntermediatePool.AddCert(c) b.KnownIssuers[string(c.Signature)] = true } log.Debug("bundler set up") return b, nil }
// ParseCertificatesPEM parses a sequence of PEM-encoded certificate and returns them, // can handle PEM encoded PKCS #7 structures. func ParseCertificatesPEM(certsPEM []byte) ([]*x509.Certificate, error) { var certs []*x509.Certificate var err error certsPEM = bytes.TrimSpace(certsPEM) for len(certsPEM) > 0 { var cert []*x509.Certificate cert, certsPEM, err = ParseOneCertificateFromPEM(certsPEM) if err != nil { return nil, cferr.New(cferr.CertificateError, cferr.ParseFailed) } else if cert == nil { break } certs = append(certs, cert...) } if len(certsPEM) > 0 { return nil, cferr.New(cferr.CertificateError, cferr.DecodeFailed) } return certs, nil }
// getMatchingProfile returns the SigningProfile that matches the profile passed. // if an empty profile string is passed it returns the default profile. func (s *Signer) getMatchingProfile(profile string) (*config.SigningProfile, error) { if profile == "" { return s.policy.Default, nil } for p, signingProfile := range s.policy.Profiles { if p == profile { return signingProfile, nil } } return nil, cferr.New(cferr.PolicyError, cferr.UnknownProfile) }
// 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 }
// New returns a new PKCS #11 signer. func New(caCertFile string, policy *config.Signing, cfg *Config) (signer.Signer, error) { if cfg == nil { return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed) } log.Debugf("Loading PKCS #11 module %s", cfg.Module) certData, err := ioutil.ReadFile(caCertFile) if err != nil { return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed) } cert, err := helpers.ParseCertificatePEM(certData) if err != nil { return nil, err } priv, err := pkcs11key.New(cfg.Module, cfg.Token, cfg.PIN, cfg.Label) if err != nil { return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed) } sigAlgo := signer.DefaultSigAlgo(priv) return local.NewSigner(priv, cert, sigAlgo, policy) }
// NewPKCS11Signer returns a new PKCS #11 signer. func NewPKCS11Signer(cfg ocspConfig.Config) (ocsp.Signer, error) { log.Debugf("Loading PKCS #11 module %s", cfg.PKCS11.Module) certData, err := ioutil.ReadFile(cfg.CACertFile) if err != nil { return nil, errors.New(errors.CertificateError, errors.ReadFailed) } cert, err := helpers.ParseCertificatePEM(certData) if err != nil { return nil, err } PKCS11 := cfg.PKCS11 priv, err := pkcs11key.New( PKCS11.Module, PKCS11.TokenLabel, PKCS11.PIN, PKCS11.PrivateKeyLabel) if err != nil { return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed) } return ocsp.NewSigner(cert, cert, priv, cfg.Interval) }
// RenewFromSigner re-creates a root certificate from the CA cert and crypto.Signer. // The resulting root certificate will have ca certificate // as the template and have the same expiry length. E.g. the exsiting CA // is valid for a year from Jan 01 2015 to Jan 01 2016, the renewed certificate // will be valid from now and expire in one year as well. func RenewFromSigner(ca *x509.Certificate, priv crypto.Signer) ([]byte, error) { if !ca.IsCA { return nil, errors.New("input certificate is not a CA cert") } // matching certificate public key vs private key switch { case ca.PublicKeyAlgorithm == x509.RSA: var rsaPublicKey *rsa.PublicKey var ok bool if rsaPublicKey, ok = priv.Public().(*rsa.PublicKey); !ok { return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch) } if ca.PublicKey.(*rsa.PublicKey).N.Cmp(rsaPublicKey.N) != 0 { return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch) } case ca.PublicKeyAlgorithm == x509.ECDSA: var ecdsaPublicKey *ecdsa.PublicKey var ok bool if ecdsaPublicKey, ok = priv.Public().(*ecdsa.PublicKey); !ok { return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch) } if ca.PublicKey.(*ecdsa.PublicKey).X.Cmp(ecdsaPublicKey.X) != 0 { return nil, cferr.New(cferr.PrivateKeyError, cferr.KeyMismatch) } default: return nil, cferr.New(cferr.PrivateKeyError, cferr.NotRSAOrECC) } req := csr.ExtractCertificateRequest(ca) cert, _, err := NewFromSigner(req, priv) return cert, err }
// NewSigner creates a new Signer directly from a // private key and certificate, with optional policy. func NewSigner(priv crypto.Signer, cert *x509.Certificate, sigAlgo x509.SignatureAlgorithm, policy *config.Signing) (*Signer, error) { if policy == nil { policy = &config.Signing{ Profiles: map[string]*config.SigningProfile{}, Default: config.DefaultConfig()} } if !policy.Valid() { return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy) } return &Signer{ ca: cert, priv: priv, sigAlgo: sigAlgo, policy: policy, db: nil, }, nil }
// ReasonStringToCode tries to convert a reason string to an integer code func ReasonStringToCode(reason string) (reasonCode int, err error) { // default to 0 if reason == "" { return 0, nil } reasonCode, present := revocationReasonCodes[strings.ToLower(reason)] if !present { reasonCode, err = strconv.Atoi(reason) if err != nil { return } if reasonCode >= ocsp.AACompromise || reasonCode <= ocsp.Unspecified { return 0, cferr.New(cferr.OCSPError, cferr.InvalidStatus) } } return }
// BundleFromPEMorDER builds a certificate bundle from the set of byte // slices containing the PEM or DER-encoded certificate(s), private key. func (b *Bundler) BundleFromPEMorDER(certsRaw, keyPEM []byte, flavor BundleFlavor, password string) (*Bundle, error) { log.Debug("bundling from PEM files") var key crypto.Signer var err error if len(keyPEM) != 0 { key, err = helpers.ParsePrivateKeyPEM(keyPEM) if err != nil { log.Debugf("failed to parse private key: %v", err) return nil, err } } certs, err := helpers.ParseCertificatesPEM(certsRaw) if err != nil { // If PEM doesn't work try DER var keyDER crypto.Signer var errDER error certs, keyDER, errDER = helpers.ParseCertificatesDER(certsRaw, password) // Only use DER key if no key read from file if key == nil && keyDER != nil { key = keyDER } if errDER != nil { log.Debugf("failed to parse certificates: %v", err) // If neither parser works pass along PEM error return nil, err } } if len(certs) == 0 { log.Debugf("no certificates found") return nil, errors.New(errors.CertificateError, errors.DecodeFailed) } log.Debugf("bundle ready") return b.Bundle(certs, key, flavor) }
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 }
// ParseCSR parses a PEM- or DER-encoded PKCS #10 certificate signing request. func ParseCSR(in []byte) (csr *x509.CertificateRequest, rest []byte, err error) { in = bytes.TrimSpace(in) p, rest := pem.Decode(in) if p != nil { if p.Type != "CERTIFICATE REQUEST" { return nil, rest, cferr.New(cferr.CSRError, cferr.BadRequest) } csr, err = x509.ParseCertificateRequest(p.Bytes) } else { csr, err = x509.ParseCertificateRequest(in) } if err != nil { return nil, rest, err } err = CheckSignature(csr, csr.SignatureAlgorithm, csr.RawTBSCertificateRequest, csr.Signature) if err != nil { return nil, rest, err } return csr, rest, nil }
"net/url" "strings" "github.com/kisom/cfssl/crypto/pkcs11key" "github.com/kisom/cfssl/errors" ) func setIfPresent(val url.Values, k string, target *string) { sv := val.Get(k) if sv != "" { *target = sv } } // ErrInvalidURI is returned if the PKCS #11 URI is invalid. var ErrInvalidURI = errors.New(errors.PrivateKeyError, errors.ParseFailed) // Parse parses a PKCS #11 URI into a PKCS #11 configuration. Note that // the module path will override the module name if present. func Parse(uri string) (*pkcs11key.Config, error) { u, err := url.Parse(uri) if err != nil || u.Scheme != "pkcs11" { return nil, ErrInvalidURI } c := new(pkcs11key.Config) pk11PAttr, err := url.ParseQuery(u.Opaque) if err != nil { return nil, ErrInvalidURI }
// 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 }
// 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 } 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) // If there is a whitelist, ensure that both the Common Name and SAN DNSNames match if profile.NameWhitelist != nil { if safeTemplate.Subject.CommonName != "" { if profile.NameWhitelist.Find([]byte(safeTemplate.Subject.CommonName)) == nil { return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy) } } for _, name := range safeTemplate.DNSNames { if profile.NameWhitelist.Find([]byte(name)) == nil { return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy) } } } if profile.ClientProvidesSerialNumbers { if req.Serial == nil { fmt.Printf("xx %#v\n", profile) return nil, cferr.New(cferr.CertificateError, cferr.MissingSerial) } safeTemplate.SerialNumber = req.Serial } else { // RFC 5280 4.1.2.2: // Certificate users MUST be able to handle serialNumber // values up to 20 octets. Conforming CAs MUST NOT use // serialNumber values longer than 20 octets. // // If CFSSL is providing the serial numbers, it makes // sense to use the max supported size. serialNumber := make([]byte, 20) _, err = io.ReadFull(rand.Reader, serialNumber) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.Unknown, err) } // SetBytes interprets buf as the bytes of a big-endian // unsigned integer. The leading byte should be masked // off to ensure it isn't negative. serialNumber[0] &= 0x7F safeTemplate.SerialNumber = new(big.Int).SetBytes(serialNumber) } if len(req.Extensions) > 0 { for _, ext := range req.Extensions { oid := asn1.ObjectIdentifier(ext.ID) if !profile.ExtensionWhitelist[oid.String()] { return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest) } rawValue, err := hex.DecodeString(ext.Value) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.InvalidRequest, err) } safeTemplate.ExtraExtensions = append(safeTemplate.ExtraExtensions, pkix.Extension{ Id: oid, Critical: ext.Critical, Value: rawValue, }) } } var certTBS = safeTemplate if len(profile.CTLogServers) > 0 { // Add a poison extension which prevents validation var poisonExtension = pkix.Extension{Id: signer.CTPoisonOID, Critical: true, Value: []byte{0x05, 0x00}} var poisonedPreCert = certTBS poisonedPreCert.ExtraExtensions = append(safeTemplate.ExtraExtensions, poisonExtension) cert, err = s.sign(&poisonedPreCert, profile) if err != nil { return } derCert, _ := pem.Decode(cert) prechain := []ct.ASN1Cert{derCert.Bytes, s.ca.Raw} var sctList []ct.SignedCertificateTimestamp for _, server := range profile.CTLogServers { log.Infof("submitting poisoned precertificate to %s", server) var ctclient = client.New(server) var resp *ct.SignedCertificateTimestamp resp, err = ctclient.AddPreChain(prechain) if err != nil { return nil, cferr.Wrap(cferr.CTError, cferr.PrecertSubmissionFailed, err) } sctList = append(sctList, *resp) } var serializedSCTList []byte serializedSCTList, err = serializeSCTList(sctList) if err != nil { return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err) } // Serialize again as an octet string before embedding serializedSCTList, err = asn1.Marshal(serializedSCTList) if err != nil { return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err) } var SCTListExtension = pkix.Extension{Id: signer.SCTListOID, Critical: false, Value: serializedSCTList} certTBS.ExtraExtensions = append(certTBS.ExtraExtensions, SCTListExtension) } var signedCert []byte signedCert, err = s.sign(&certTBS, profile) if err != nil { return nil, err } if s.db != nil { var certRecord = &certdb.CertificateRecord{ Serial: certTBS.SerialNumber.String(), CALabel: req.Label, Status: "good", Expiry: certTBS.NotAfter, PEM: string(signedCert), } err = certdb.InsertCertificate(s.db, certRecord) if err != nil { return nil, err } log.Debug("saved certificate with serial number ", certTBS.SerialNumber) } return signedCert, nil }
// FillTemplate is a utility function that tries to load as much of // the certificate template as possible from the profiles and current // template. It fills in the key uses, expiration, revocation URLs // and SKI. func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.SigningProfile) error { ski, err := ComputeSKI(template) var ( eku []x509.ExtKeyUsage ku x509.KeyUsage backdate time.Duration expiry time.Duration notBefore time.Time notAfter time.Time 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() if profile.IssuerURL == nil { profile.IssuerURL = defaultProfile.IssuerURL } if ku == 0 && len(eku) == 0 { return cferr.New(cferr.PolicyError, cferr.NoKeyUsages) } if expiry = profile.Expiry; expiry == 0 { expiry = defaultProfile.Expiry } if crlURL = profile.CRL; crlURL == "" { crlURL = defaultProfile.CRL } if ocspURL = profile.OCSP; ocspURL == "" { ocspURL = defaultProfile.OCSP } if backdate = profile.Backdate; backdate == 0 { backdate = -5 * time.Minute } else { backdate = -1 * profile.Backdate } if !profile.NotBefore.IsZero() { notBefore = profile.NotBefore.UTC() } else { notBefore = time.Now().Round(time.Minute).Add(backdate).UTC() } if !profile.NotAfter.IsZero() { notAfter = profile.NotAfter.UTC() } else { notAfter = notBefore.Add(expiry).UTC() } template.NotBefore = notBefore template.NotAfter = notAfter template.KeyUsage = ku template.ExtKeyUsage = eku template.BasicConstraintsValid = true template.IsCA = profile.CA template.SubjectKeyId = ski if ocspURL != "" { template.OCSPServer = []string{ocspURL} } if crlURL != "" { template.CRLDistributionPoints = []string{crlURL} } if len(profile.IssuerURL) != 0 { template.IssuingCertificateURL = profile.IssuerURL } if len(profile.Policies) != 0 { err = addPolicies(template, profile.Policies) if err != nil { return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err) } } if profile.OCSPNoCheck { ocspNoCheckExtension := pkix.Extension{ Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1, 5}, Critical: false, Value: []byte{0x05, 0x00}, } template.ExtraExtensions = append(template.ExtraExtensions, ocspNoCheckExtension) } return nil }
// 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 }