1 // Package local implements certificate signature functionality for CFSSL.
22 "github.com/cloudflare/cfssl/certdb"
23 "github.com/cloudflare/cfssl/config"
24 cferr "github.com/cloudflare/cfssl/errors"
25 "github.com/cloudflare/cfssl/helpers"
26 "github.com/cloudflare/cfssl/info"
27 "github.com/cloudflare/cfssl/log"
28 "github.com/cloudflare/cfssl/signer"
29 "github.com/google/certificate-transparency/go"
30 "github.com/google/certificate-transparency/go/client"
33 // Signer contains a signer that uses the standard library to
34 // support both ECDSA and RSA CA keys.
38 policy *config.Signing
39 sigAlgo x509.SignatureAlgorithm
40 dbAccessor certdb.Accessor
43 // NewSigner creates a new Signer directly from a
44 // private key and certificate, with optional policy.
45 func NewSigner(priv crypto.Signer, cert *x509.Certificate, sigAlgo x509.SignatureAlgorithm, policy *config.Signing) (*Signer, error) {
47 policy = &config.Signing{
48 Profiles: map[string]*config.SigningProfile{},
49 Default: config.DefaultConfig()}
53 return nil, cferr.New(cferr.PolicyError, cferr.InvalidPolicy)
64 // NewSignerFromFile generates a new local signer from a caFile
65 // and a caKey file, both PEM encoded.
66 func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signer, error) {
67 log.Debug("Loading CA: ", caFile)
68 ca, err := ioutil.ReadFile(caFile)
72 log.Debug("Loading CA key: ", caKeyFile)
73 cakey, err := ioutil.ReadFile(caKeyFile)
75 return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err)
78 parsedCa, err := helpers.ParseCertificatePEM(ca)
83 strPassword := os.Getenv("CFSSL_CA_PK_PASSWORD")
84 password := []byte(strPassword)
85 if strPassword == "" {
89 priv, err := helpers.ParsePrivateKeyPEMWithPassword(cakey, password)
91 log.Debug("Malformed private key %v", err)
95 return NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy)
98 func (s *Signer) sign(template *x509.Certificate, profile *config.SigningProfile) (cert []byte, err error) {
99 var distPoints = template.CRLDistributionPoints
100 err = signer.FillTemplate(template, s.policy.Default, profile)
101 if distPoints != nil && len(distPoints) > 0 {
102 template.CRLDistributionPoints = distPoints
111 err = cferr.New(cferr.PolicyError, cferr.InvalidRequest)
114 template.DNSNames = nil
115 template.EmailAddresses = nil
120 derBytes, err := x509.CreateCertificate(rand.Reader, template, s.ca, template.PublicKey, s.priv)
122 return nil, cferr.Wrap(cferr.CertificateError, cferr.Unknown, err)
125 s.ca, err = x509.ParseCertificate(derBytes)
127 return nil, cferr.Wrap(cferr.CertificateError, cferr.ParseFailed, err)
131 cert = pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
132 log.Infof("signed certificate with serial number %d", template.SerialNumber)
136 // replaceSliceIfEmpty replaces the contents of replaced with newContents if
137 // the slice referenced by replaced is empty
138 func replaceSliceIfEmpty(replaced, newContents *[]string) {
139 if len(*replaced) == 0 {
140 *replaced = *newContents
144 // PopulateSubjectFromCSR has functionality similar to Name, except
145 // it fills the fields of the resulting pkix.Name with req's if the
146 // subject's corresponding fields are empty
147 func PopulateSubjectFromCSR(s *signer.Subject, req pkix.Name) pkix.Name {
148 // if no subject, use req
155 if name.CommonName == "" {
156 name.CommonName = req.CommonName
159 replaceSliceIfEmpty(&name.Country, &req.Country)
160 replaceSliceIfEmpty(&name.Province, &req.Province)
161 replaceSliceIfEmpty(&name.Locality, &req.Locality)
162 replaceSliceIfEmpty(&name.Organization, &req.Organization)
163 replaceSliceIfEmpty(&name.OrganizationalUnit, &req.OrganizationalUnit)
164 if name.SerialNumber == "" {
165 name.SerialNumber = req.SerialNumber
170 // OverrideHosts fills template's IPAddresses, EmailAddresses, and DNSNames with the
171 // content of hosts, if it is not nil.
172 func OverrideHosts(template *x509.Certificate, hosts []string) {
174 template.IPAddresses = []net.IP{}
175 template.EmailAddresses = []string{}
176 template.DNSNames = []string{}
179 for i := range hosts {
180 if ip := net.ParseIP(hosts[i]); ip != nil {
181 template.IPAddresses = append(template.IPAddresses, ip)
182 } else if email, err := mail.ParseAddress(hosts[i]); err == nil && email != nil {
183 template.EmailAddresses = append(template.EmailAddresses, email.Address)
185 template.DNSNames = append(template.DNSNames, hosts[i])
191 // Sign signs a new certificate based on the PEM-encoded client
192 // certificate or certificate request with the signing profile,
193 // specified by profileName.
194 func (s *Signer) Sign(req signer.SignRequest) (cert []byte, err error) {
195 profile, err := signer.Profile(s, req.Profile)
200 block, _ := pem.Decode([]byte(req.Request))
202 return nil, cferr.New(cferr.CSRError, cferr.DecodeFailed)
205 if block.Type != "NEW CERTIFICATE REQUEST" && block.Type != "CERTIFICATE REQUEST" {
206 return nil, cferr.Wrap(cferr.CSRError,
207 cferr.BadRequest, errors.New("not a certificate or csr"))
210 csrTemplate, err := signer.ParseCertificateRequest(s, block.Bytes)
215 // Copy out only the fields from the CSR authorized by policy.
216 safeTemplate := x509.Certificate{}
217 // If the profile contains no explicit whitelist, assume that all fields
218 // should be copied from the CSR.
219 if profile.CSRWhitelist == nil {
220 safeTemplate = *csrTemplate
222 if profile.CSRWhitelist.Subject {
223 safeTemplate.Subject = csrTemplate.Subject
225 if profile.CSRWhitelist.PublicKeyAlgorithm {
226 safeTemplate.PublicKeyAlgorithm = csrTemplate.PublicKeyAlgorithm
228 if profile.CSRWhitelist.PublicKey {
229 safeTemplate.PublicKey = csrTemplate.PublicKey
231 if profile.CSRWhitelist.SignatureAlgorithm {
232 safeTemplate.SignatureAlgorithm = csrTemplate.SignatureAlgorithm
234 if profile.CSRWhitelist.DNSNames {
235 safeTemplate.DNSNames = csrTemplate.DNSNames
237 if profile.CSRWhitelist.IPAddresses {
238 safeTemplate.IPAddresses = csrTemplate.IPAddresses
240 if profile.CSRWhitelist.EmailAddresses {
241 safeTemplate.EmailAddresses = csrTemplate.EmailAddresses
245 if req.CRLOverride != "" {
246 safeTemplate.CRLDistributionPoints = []string{req.CRLOverride}
249 if safeTemplate.IsCA {
250 if !profile.CAConstraint.IsCA {
251 log.Error("local signer policy disallows issuing CA certificate")
252 return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest)
255 if s.ca != nil && s.ca.MaxPathLen > 0 {
256 if safeTemplate.MaxPathLen >= s.ca.MaxPathLen {
257 log.Error("local signer certificate disallows CA MaxPathLen extending")
258 // do not sign a cert with pathlen > current
259 return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest)
261 } else if s.ca != nil && s.ca.MaxPathLen == 0 && s.ca.MaxPathLenZero {
262 log.Error("local signer certificate disallows issuing CA certificate")
263 // signer has pathlen of 0, do not sign more intermediate CAs
264 return nil, cferr.New(cferr.PolicyError, cferr.InvalidRequest)
268 OverrideHosts(&safeTemplate, req.Hosts)
269 safeTemplate.Subject = PopulateSubjectFromCSR(req.Subject, safeTemplate.Subject)
271 // If there is a whitelist, ensure that both the Common Name and SAN DNSNames match
272 if profile.NameWhitelist != nil {
273 if safeTemplate.Subject.CommonName != "" {
274 if profile.NameWhitelist.Find([]byte(safeTemplate.Subject.CommonName)) == nil {
275 return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
278 for _, name := range safeTemplate.DNSNames {
279 if profile.NameWhitelist.Find([]byte(name)) == nil {
280 return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
283 for _, name := range safeTemplate.EmailAddresses {
284 if profile.NameWhitelist.Find([]byte(name)) == nil {
285 return nil, cferr.New(cferr.PolicyError, cferr.UnmatchedWhitelist)
290 if profile.ClientProvidesSerialNumbers {
291 if req.Serial == nil {
292 return nil, cferr.New(cferr.CertificateError, cferr.MissingSerial)
294 safeTemplate.SerialNumber = req.Serial
297 // Certificate users MUST be able to handle serialNumber
298 // values up to 20 octets. Conforming CAs MUST NOT use
299 // serialNumber values longer than 20 octets.
301 // If CFSSL is providing the serial numbers, it makes
302 // sense to use the max supported size.
303 serialNumber := make([]byte, 20)
304 _, err = io.ReadFull(rand.Reader, serialNumber)
306 return nil, cferr.Wrap(cferr.CertificateError, cferr.Unknown, err)
309 // SetBytes interprets buf as the bytes of a big-endian
310 // unsigned integer. The leading byte should be masked
311 // off to ensure it isn't negative.
312 serialNumber[0] &= 0x7F
314 safeTemplate.SerialNumber = new(big.Int).SetBytes(serialNumber)
317 if len(req.Extensions) > 0 {
318 for _, ext := range req.Extensions {
319 oid := asn1.ObjectIdentifier(ext.ID)
320 if !profile.ExtensionWhitelist[oid.String()] {
321 return nil, cferr.New(cferr.CertificateError, cferr.InvalidRequest)
324 rawValue, err := hex.DecodeString(ext.Value)
326 return nil, cferr.Wrap(cferr.CertificateError, cferr.InvalidRequest, err)
329 safeTemplate.ExtraExtensions = append(safeTemplate.ExtraExtensions, pkix.Extension{
331 Critical: ext.Critical,
337 var certTBS = safeTemplate
339 if len(profile.CTLogServers) > 0 {
340 // Add a poison extension which prevents validation
341 var poisonExtension = pkix.Extension{Id: signer.CTPoisonOID, Critical: true, Value: []byte{0x05, 0x00}}
342 var poisonedPreCert = certTBS
343 poisonedPreCert.ExtraExtensions = append(safeTemplate.ExtraExtensions, poisonExtension)
344 cert, err = s.sign(&poisonedPreCert, profile)
349 derCert, _ := pem.Decode(cert)
350 prechain := []ct.ASN1Cert{derCert.Bytes, s.ca.Raw}
351 var sctList []ct.SignedCertificateTimestamp
353 for _, server := range profile.CTLogServers {
354 log.Infof("submitting poisoned precertificate to %s", server)
355 var ctclient = client.New(server, nil)
356 var resp *ct.SignedCertificateTimestamp
357 resp, err = ctclient.AddPreChain(prechain)
359 return nil, cferr.Wrap(cferr.CTError, cferr.PrecertSubmissionFailed, err)
361 sctList = append(sctList, *resp)
364 var serializedSCTList []byte
365 serializedSCTList, err = serializeSCTList(sctList)
367 return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
370 // Serialize again as an octet string before embedding
371 serializedSCTList, err = asn1.Marshal(serializedSCTList)
373 return nil, cferr.Wrap(cferr.CTError, cferr.Unknown, err)
376 var SCTListExtension = pkix.Extension{Id: signer.SCTListOID, Critical: false, Value: serializedSCTList}
377 certTBS.ExtraExtensions = append(certTBS.ExtraExtensions, SCTListExtension)
379 var signedCert []byte
380 signedCert, err = s.sign(&certTBS, profile)
385 if s.dbAccessor != nil {
386 var certRecord = certdb.CertificateRecord{
387 Serial: certTBS.SerialNumber.String(),
388 // this relies on the specific behavior of x509.CreateCertificate
389 // which updates certTBS AuthorityKeyId from the signer's SubjectKeyId
390 AKI: hex.EncodeToString(certTBS.AuthorityKeyId),
393 Expiry: certTBS.NotAfter,
394 PEM: string(signedCert),
397 err = s.dbAccessor.InsertCertificate(certRecord)
401 log.Debug("saved certificate with serial number ", certTBS.SerialNumber)
404 return signedCert, nil
407 func serializeSCTList(sctList []ct.SignedCertificateTimestamp) ([]byte, error) {
409 for _, sct := range sctList {
410 sct, err := ct.SerializeSCT(sct)
414 binary.Write(&buf, binary.BigEndian, uint16(len(sct)))
418 var sctListLengthField = make([]byte, 2)
419 binary.BigEndian.PutUint16(sctListLengthField, uint16(buf.Len()))
420 return bytes.Join([][]byte{sctListLengthField, buf.Bytes()}, nil), nil
423 // Info return a populated info.Resp struct or an error.
424 func (s *Signer) Info(req info.Req) (resp *info.Resp, err error) {
425 cert, err := s.Certificate(req.Label, req.Profile)
430 profile, err := signer.Profile(s, req.Profile)
435 resp = new(info.Resp)
437 resp.Certificate = string(bytes.TrimSpace(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})))
439 resp.Usage = profile.Usage
440 resp.ExpiryString = profile.ExpiryString
445 // SigAlgo returns the RSA signer's signature algorithm.
446 func (s *Signer) SigAlgo() x509.SignatureAlgorithm {
450 // Certificate returns the signer's certificate.
451 func (s *Signer) Certificate(label, profile string) (*x509.Certificate, error) {
456 // SetPolicy sets the signer's signature policy.
457 func (s *Signer) SetPolicy(policy *config.Signing) {
461 // SetDBAccessor sets the signers' cert db accessor
462 func (s *Signer) SetDBAccessor(dba certdb.Accessor) {
466 // Policy returns the signer's policy.
467 func (s *Signer) Policy() *config.Signing {