signer.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. // Package signer implements certificate signature functionality for CFSSL.
  2. package signer
  3. import (
  4. "crypto"
  5. "crypto/ecdsa"
  6. "crypto/elliptic"
  7. "crypto/rsa"
  8. "crypto/sha1"
  9. "crypto/x509"
  10. "crypto/x509/pkix"
  11. "encoding/asn1"
  12. "errors"
  13. "math/big"
  14. "net/http"
  15. "strings"
  16. "time"
  17. "github.com/cloudflare/cfssl/certdb"
  18. "github.com/cloudflare/cfssl/config"
  19. "github.com/cloudflare/cfssl/csr"
  20. cferr "github.com/cloudflare/cfssl/errors"
  21. "github.com/cloudflare/cfssl/info"
  22. )
  23. // Subject contains the information that should be used to override the
  24. // subject information when signing a certificate.
  25. type Subject struct {
  26. CN string
  27. Names []csr.Name `json:"names"`
  28. SerialNumber string
  29. }
  30. // Extension represents a raw extension to be included in the certificate. The
  31. // "value" field must be hex encoded.
  32. type Extension struct {
  33. ID config.OID `json:"id"`
  34. Critical bool `json:"critical"`
  35. Value string `json:"value"`
  36. }
  37. // SignRequest stores a signature request, which contains the hostname,
  38. // the CSR, optional subject information, and the signature profile.
  39. //
  40. // Extensions provided in the signRequest are copied into the certificate, as
  41. // long as they are in the ExtensionWhitelist for the signer's policy.
  42. // Extensions requested in the CSR are ignored, except for those processed by
  43. // ParseCertificateRequest (mainly subjectAltName).
  44. type SignRequest struct {
  45. Hosts []string `json:"hosts"`
  46. Request string `json:"certificate_request"`
  47. Subject *Subject `json:"subject,omitempty"`
  48. Profile string `json:"profile"`
  49. CRLOverride string `json:"crl_override"`
  50. Label string `json:"label"`
  51. Serial *big.Int `json:"serial,omitempty"`
  52. Extensions []Extension `json:"extensions,omitempty"`
  53. // If provided, NotBefore will be used without modification (except
  54. // for canonicalization) as the value of the notBefore field of the
  55. // certificate. In particular no backdating adjustment will be made
  56. // when NotBefore is provided.
  57. NotBefore time.Time
  58. // If provided, NotAfter will be used without modification (except
  59. // for canonicalization) as the value of the notAfter field of the
  60. // certificate.
  61. NotAfter time.Time
  62. }
  63. // appendIf appends to a if s is not an empty string.
  64. func appendIf(s string, a *[]string) {
  65. if s != "" {
  66. *a = append(*a, s)
  67. }
  68. }
  69. // Name returns the PKIX name for the subject.
  70. func (s *Subject) Name() pkix.Name {
  71. var name pkix.Name
  72. name.CommonName = s.CN
  73. for _, n := range s.Names {
  74. appendIf(n.C, &name.Country)
  75. appendIf(n.ST, &name.Province)
  76. appendIf(n.L, &name.Locality)
  77. appendIf(n.O, &name.Organization)
  78. appendIf(n.OU, &name.OrganizationalUnit)
  79. }
  80. name.SerialNumber = s.SerialNumber
  81. return name
  82. }
  83. // SplitHosts takes a comma-spearated list of hosts and returns a slice
  84. // with the hosts split
  85. func SplitHosts(hostList string) []string {
  86. if hostList == "" {
  87. return nil
  88. }
  89. return strings.Split(hostList, ",")
  90. }
  91. // A Signer contains a CA's certificate and private key for signing
  92. // certificates, a Signing policy to refer to and a SignatureAlgorithm.
  93. type Signer interface {
  94. Info(info.Req) (*info.Resp, error)
  95. Policy() *config.Signing
  96. SetDBAccessor(certdb.Accessor)
  97. GetDBAccessor() certdb.Accessor
  98. SetPolicy(*config.Signing)
  99. SigAlgo() x509.SignatureAlgorithm
  100. Sign(req SignRequest) (cert []byte, err error)
  101. SetReqModifier(func(*http.Request, []byte))
  102. }
  103. // Profile gets the specific profile from the signer
  104. func Profile(s Signer, profile string) (*config.SigningProfile, error) {
  105. var p *config.SigningProfile
  106. policy := s.Policy()
  107. if policy != nil && policy.Profiles != nil && profile != "" {
  108. p = policy.Profiles[profile]
  109. }
  110. if p == nil && policy != nil {
  111. p = policy.Default
  112. }
  113. if p == nil {
  114. return nil, cferr.Wrap(cferr.APIClientError, cferr.ClientHTTPError, errors.New("profile must not be nil"))
  115. }
  116. return p, nil
  117. }
  118. // DefaultSigAlgo returns an appropriate X.509 signature algorithm given
  119. // the CA's private key.
  120. func DefaultSigAlgo(priv crypto.Signer) x509.SignatureAlgorithm {
  121. pub := priv.Public()
  122. switch pub := pub.(type) {
  123. case *rsa.PublicKey:
  124. keySize := pub.N.BitLen()
  125. switch {
  126. case keySize >= 4096:
  127. return x509.SHA512WithRSA
  128. case keySize >= 3072:
  129. return x509.SHA384WithRSA
  130. case keySize >= 2048:
  131. return x509.SHA256WithRSA
  132. default:
  133. return x509.SHA1WithRSA
  134. }
  135. case *ecdsa.PublicKey:
  136. switch pub.Curve {
  137. case elliptic.P256():
  138. return x509.ECDSAWithSHA256
  139. case elliptic.P384():
  140. return x509.ECDSAWithSHA384
  141. case elliptic.P521():
  142. return x509.ECDSAWithSHA512
  143. default:
  144. return x509.ECDSAWithSHA1
  145. }
  146. default:
  147. return x509.UnknownSignatureAlgorithm
  148. }
  149. }
  150. // ParseCertificateRequest takes an incoming certificate request and
  151. // builds a certificate template from it.
  152. func ParseCertificateRequest(s Signer, csrBytes []byte) (template *x509.Certificate, err error) {
  153. csrv, err := x509.ParseCertificateRequest(csrBytes)
  154. if err != nil {
  155. err = cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
  156. return
  157. }
  158. err = csrv.CheckSignature()
  159. if err != nil {
  160. err = cferr.Wrap(cferr.CSRError, cferr.KeyMismatch, err)
  161. return
  162. }
  163. template = &x509.Certificate{
  164. Subject: csrv.Subject,
  165. PublicKeyAlgorithm: csrv.PublicKeyAlgorithm,
  166. PublicKey: csrv.PublicKey,
  167. SignatureAlgorithm: s.SigAlgo(),
  168. DNSNames: csrv.DNSNames,
  169. IPAddresses: csrv.IPAddresses,
  170. EmailAddresses: csrv.EmailAddresses,
  171. }
  172. for _, val := range csrv.Extensions {
  173. // Check the CSR for the X.509 BasicConstraints (RFC 5280, 4.2.1.9)
  174. // extension and append to template if necessary
  175. if val.Id.Equal(asn1.ObjectIdentifier{2, 5, 29, 19}) {
  176. var constraints csr.BasicConstraints
  177. var rest []byte
  178. if rest, err = asn1.Unmarshal(val.Value, &constraints); err != nil {
  179. return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, err)
  180. } else if len(rest) != 0 {
  181. return nil, cferr.Wrap(cferr.CSRError, cferr.ParseFailed, errors.New("x509: trailing data after X.509 BasicConstraints"))
  182. }
  183. template.BasicConstraintsValid = true
  184. template.IsCA = constraints.IsCA
  185. template.MaxPathLen = constraints.MaxPathLen
  186. template.MaxPathLenZero = template.MaxPathLen == 0
  187. }
  188. }
  189. return
  190. }
  191. type subjectPublicKeyInfo struct {
  192. Algorithm pkix.AlgorithmIdentifier
  193. SubjectPublicKey asn1.BitString
  194. }
  195. // ComputeSKI derives an SKI from the certificate's public key in a
  196. // standard manner. This is done by computing the SHA-1 digest of the
  197. // SubjectPublicKeyInfo component of the certificate.
  198. func ComputeSKI(template *x509.Certificate) ([]byte, error) {
  199. pub := template.PublicKey
  200. encodedPub, err := x509.MarshalPKIXPublicKey(pub)
  201. if err != nil {
  202. return nil, err
  203. }
  204. var subPKI subjectPublicKeyInfo
  205. _, err = asn1.Unmarshal(encodedPub, &subPKI)
  206. if err != nil {
  207. return nil, err
  208. }
  209. pubHash := sha1.Sum(subPKI.SubjectPublicKey.Bytes)
  210. return pubHash[:], nil
  211. }
  212. // FillTemplate is a utility function that tries to load as much of
  213. // the certificate template as possible from the profiles and current
  214. // template. It fills in the key uses, expiration, revocation URLs
  215. // and SKI.
  216. func FillTemplate(template *x509.Certificate, defaultProfile, profile *config.SigningProfile, notBefore time.Time, notAfter time.Time) error {
  217. ski, err := ComputeSKI(template)
  218. if err != nil {
  219. return err
  220. }
  221. var (
  222. eku []x509.ExtKeyUsage
  223. ku x509.KeyUsage
  224. backdate time.Duration
  225. expiry time.Duration
  226. crlURL, ocspURL string
  227. issuerURL = profile.IssuerURL
  228. )
  229. // The third value returned from Usages is a list of unknown key usages.
  230. // This should be used when validating the profile at load, and isn't used
  231. // here.
  232. ku, eku, _ = profile.Usages()
  233. if profile.IssuerURL == nil {
  234. issuerURL = defaultProfile.IssuerURL
  235. }
  236. if ku == 0 && len(eku) == 0 {
  237. return cferr.New(cferr.PolicyError, cferr.NoKeyUsages)
  238. }
  239. if expiry = profile.Expiry; expiry == 0 {
  240. expiry = defaultProfile.Expiry
  241. }
  242. if crlURL = profile.CRL; crlURL == "" {
  243. crlURL = defaultProfile.CRL
  244. }
  245. if ocspURL = profile.OCSP; ocspURL == "" {
  246. ocspURL = defaultProfile.OCSP
  247. }
  248. if notBefore.IsZero() {
  249. if !profile.NotBefore.IsZero() {
  250. notBefore = profile.NotBefore
  251. } else {
  252. if backdate = profile.Backdate; backdate == 0 {
  253. backdate = -5 * time.Minute
  254. } else {
  255. backdate = -1 * profile.Backdate
  256. }
  257. notBefore = time.Now().Round(time.Minute).Add(backdate)
  258. }
  259. }
  260. notBefore = notBefore.UTC()
  261. if notAfter.IsZero() {
  262. if !profile.NotAfter.IsZero() {
  263. notAfter = profile.NotAfter
  264. } else {
  265. notAfter = notBefore.Add(expiry)
  266. }
  267. }
  268. notAfter = notAfter.UTC()
  269. template.NotBefore = notBefore
  270. template.NotAfter = notAfter
  271. template.KeyUsage = ku
  272. template.ExtKeyUsage = eku
  273. template.BasicConstraintsValid = true
  274. template.IsCA = profile.CAConstraint.IsCA
  275. if template.IsCA {
  276. template.MaxPathLen = profile.CAConstraint.MaxPathLen
  277. if template.MaxPathLen == 0 {
  278. template.MaxPathLenZero = profile.CAConstraint.MaxPathLenZero
  279. }
  280. template.DNSNames = nil
  281. template.EmailAddresses = nil
  282. }
  283. template.SubjectKeyId = ski
  284. if ocspURL != "" {
  285. template.OCSPServer = []string{ocspURL}
  286. }
  287. if crlURL != "" {
  288. template.CRLDistributionPoints = []string{crlURL}
  289. }
  290. if len(issuerURL) != 0 {
  291. template.IssuingCertificateURL = issuerURL
  292. }
  293. if len(profile.Policies) != 0 {
  294. err = addPolicies(template, profile.Policies)
  295. if err != nil {
  296. return cferr.Wrap(cferr.PolicyError, cferr.InvalidPolicy, err)
  297. }
  298. }
  299. if profile.OCSPNoCheck {
  300. ocspNoCheckExtension := pkix.Extension{
  301. Id: asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1, 5},
  302. Critical: false,
  303. Value: []byte{0x05, 0x00},
  304. }
  305. template.ExtraExtensions = append(template.ExtraExtensions, ocspNoCheckExtension)
  306. }
  307. return nil
  308. }
  309. type policyInformation struct {
  310. PolicyIdentifier asn1.ObjectIdentifier
  311. Qualifiers []interface{} `asn1:"tag:optional,omitempty"`
  312. }
  313. type cpsPolicyQualifier struct {
  314. PolicyQualifierID asn1.ObjectIdentifier
  315. Qualifier string `asn1:"tag:optional,ia5"`
  316. }
  317. type userNotice struct {
  318. ExplicitText string `asn1:"tag:optional,utf8"`
  319. }
  320. type userNoticePolicyQualifier struct {
  321. PolicyQualifierID asn1.ObjectIdentifier
  322. Qualifier userNotice
  323. }
  324. var (
  325. // Per https://tools.ietf.org/html/rfc3280.html#page-106, this represents:
  326. // iso(1) identified-organization(3) dod(6) internet(1) security(5)
  327. // mechanisms(5) pkix(7) id-qt(2) id-qt-cps(1)
  328. iDQTCertificationPracticeStatement = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 2, 1}
  329. // iso(1) identified-organization(3) dod(6) internet(1) security(5)
  330. // mechanisms(5) pkix(7) id-qt(2) id-qt-unotice(2)
  331. iDQTUserNotice = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 2, 2}
  332. // CTPoisonOID is the object ID of the critical poison extension for precertificates
  333. // https://tools.ietf.org/html/rfc6962#page-9
  334. CTPoisonOID = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3}
  335. // SCTListOID is the object ID for the Signed Certificate Timestamp certificate extension
  336. // https://tools.ietf.org/html/rfc6962#page-14
  337. SCTListOID = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 2}
  338. )
  339. // addPolicies adds Certificate Policies and optional Policy Qualifiers to a
  340. // certificate, based on the input config. Go's x509 library allows setting
  341. // Certificate Policies easily, but does not support nested Policy Qualifiers
  342. // under those policies. So we need to construct the ASN.1 structure ourselves.
  343. func addPolicies(template *x509.Certificate, policies []config.CertificatePolicy) error {
  344. asn1PolicyList := []policyInformation{}
  345. for _, policy := range policies {
  346. pi := policyInformation{
  347. // The PolicyIdentifier is an OID assigned to a given issuer.
  348. PolicyIdentifier: asn1.ObjectIdentifier(policy.ID),
  349. }
  350. for _, qualifier := range policy.Qualifiers {
  351. switch qualifier.Type {
  352. case "id-qt-unotice":
  353. pi.Qualifiers = append(pi.Qualifiers,
  354. userNoticePolicyQualifier{
  355. PolicyQualifierID: iDQTUserNotice,
  356. Qualifier: userNotice{
  357. ExplicitText: qualifier.Value,
  358. },
  359. })
  360. case "id-qt-cps":
  361. pi.Qualifiers = append(pi.Qualifiers,
  362. cpsPolicyQualifier{
  363. PolicyQualifierID: iDQTCertificationPracticeStatement,
  364. Qualifier: qualifier.Value,
  365. })
  366. default:
  367. return errors.New("Invalid qualifier type in Policies " + qualifier.Type)
  368. }
  369. }
  370. asn1PolicyList = append(asn1PolicyList, pi)
  371. }
  372. asn1Bytes, err := asn1.Marshal(asn1PolicyList)
  373. if err != nil {
  374. return err
  375. }
  376. template.ExtraExtensions = append(template.ExtraExtensions, pkix.Extension{
  377. Id: asn1.ObjectIdentifier{2, 5, 29, 32},
  378. Critical: false,
  379. Value: asn1Bytes,
  380. })
  381. return nil
  382. }