bundler.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. // Package bundler implements certificate bundling functionality for
  2. // CFSSL.
  3. package bundler
  4. import (
  5. "bytes"
  6. "crypto"
  7. "crypto/ecdsa"
  8. "crypto/rsa"
  9. "crypto/tls"
  10. "crypto/x509"
  11. "encoding/pem"
  12. goerr "errors"
  13. "fmt"
  14. "io/ioutil"
  15. "net"
  16. "net/http"
  17. "os"
  18. "path/filepath"
  19. "strconv"
  20. "strings"
  21. "time"
  22. "github.com/cloudflare/cfssl/errors"
  23. "github.com/cloudflare/cfssl/helpers"
  24. "github.com/cloudflare/cfssl/log"
  25. "github.com/cloudflare/cfssl/ubiquity"
  26. )
  27. // IntermediateStash contains the path to the directory where
  28. // downloaded intermediates should be saved.
  29. // When unspecified, downloaded intermediates are not saved.
  30. var IntermediateStash string
  31. // HTTPClient is an instance of http.Client that will be used for all HTTP requests.
  32. var HTTPClient = http.DefaultClient
  33. // BundleFlavor is named optimization strategy on certificate chain selection when bundling.
  34. type BundleFlavor string
  35. const (
  36. // Optimal means the shortest chain with newest intermediates and
  37. // the most advanced crypto.
  38. Optimal BundleFlavor = "optimal"
  39. // Ubiquitous is aimed to provide the chain which is accepted
  40. // by the most platforms.
  41. Ubiquitous BundleFlavor = "ubiquitous"
  42. // Force means the bundler only verifies the input as a valid bundle, not optimization is done.
  43. Force BundleFlavor = "force"
  44. )
  45. const (
  46. sha2Warning = "The bundle contains certificates signed with advanced hash functions such as SHA2, which are problematic for certain operating systems, e.g. Windows XP SP2."
  47. ecdsaWarning = "The bundle contains ECDSA signatures, which are problematic for certain operating systems, e.g. Windows XP, Android 2.2 and Android 2.3."
  48. expiringWarningStub = "The bundle is expiring within 30 days."
  49. untrustedWarningStub = "The bundle may not be trusted by the following platform(s):"
  50. ubiquityWarning = "Unable to measure bundle ubiquity: No platform metadata present."
  51. )
  52. // A Bundler contains the certificate pools for producing certificate
  53. // bundles. It contains any intermediates and root certificates that
  54. // should be used.
  55. type Bundler struct {
  56. RootPool *x509.CertPool
  57. IntermediatePool *x509.CertPool
  58. KnownIssuers map[string]bool
  59. opts options
  60. }
  61. type options struct {
  62. keyUsages []x509.ExtKeyUsage
  63. }
  64. var defaultOptions = options{
  65. keyUsages: []x509.ExtKeyUsage{
  66. x509.ExtKeyUsageAny,
  67. },
  68. }
  69. // An Option sets options such as allowed key usages, etc.
  70. type Option func(*options)
  71. // WithKeyUsages lets you set which Extended Key Usage values are acceptable. By
  72. // default x509.ExtKeyUsageAny will be used.
  73. func WithKeyUsages(usages ...x509.ExtKeyUsage) Option {
  74. return func(o *options) {
  75. o.keyUsages = usages
  76. }
  77. }
  78. // NewBundler creates a new Bundler from the files passed in; these
  79. // files should contain a list of valid root certificates and a list
  80. // of valid intermediate certificates, respectively.
  81. func NewBundler(caBundleFile, intBundleFile string, opt ...Option) (*Bundler, error) {
  82. var caBundle, intBundle []byte
  83. var err error
  84. if caBundleFile != "" {
  85. log.Debug("Loading CA bundle: ", caBundleFile)
  86. caBundle, err = ioutil.ReadFile(caBundleFile)
  87. if err != nil {
  88. log.Errorf("root bundle failed to load: %v", err)
  89. return nil, errors.Wrap(errors.RootError, errors.ReadFailed, err)
  90. }
  91. }
  92. if intBundleFile != "" {
  93. log.Debug("Loading Intermediate bundle: ", intBundleFile)
  94. intBundle, err = ioutil.ReadFile(intBundleFile)
  95. if err != nil {
  96. log.Errorf("intermediate bundle failed to load: %v", err)
  97. return nil, errors.Wrap(errors.IntermediatesError, errors.ReadFailed, err)
  98. }
  99. }
  100. if IntermediateStash != "" {
  101. if _, err = os.Stat(IntermediateStash); err != nil && os.IsNotExist(err) {
  102. log.Infof("intermediate stash directory %s doesn't exist, creating", IntermediateStash)
  103. err = os.MkdirAll(IntermediateStash, 0755)
  104. if err != nil {
  105. log.Errorf("failed to create intermediate stash directory %s: %v",
  106. IntermediateStash, err)
  107. return nil, err
  108. }
  109. log.Infof("intermediate stash directory %s created", IntermediateStash)
  110. }
  111. }
  112. return NewBundlerFromPEM(caBundle, intBundle, opt...)
  113. }
  114. // NewBundlerFromPEM creates a new Bundler from PEM-encoded root certificates and
  115. // intermediate certificates.
  116. // If caBundlePEM is nil, the resulting Bundler can only do "Force" bundle.
  117. func NewBundlerFromPEM(caBundlePEM, intBundlePEM []byte, opt ...Option) (*Bundler, error) {
  118. opts := defaultOptions
  119. for _, o := range opt {
  120. o(&opts)
  121. }
  122. log.Debug("parsing root certificates from PEM")
  123. roots, err := helpers.ParseCertificatesPEM(caBundlePEM)
  124. if err != nil {
  125. log.Errorf("failed to parse root bundle: %v", err)
  126. return nil, errors.New(errors.RootError, errors.ParseFailed)
  127. }
  128. log.Debug("parse intermediate certificates from PEM")
  129. intermediates, err := helpers.ParseCertificatesPEM(intBundlePEM)
  130. if err != nil {
  131. log.Errorf("failed to parse intermediate bundle: %v", err)
  132. return nil, errors.New(errors.IntermediatesError, errors.ParseFailed)
  133. }
  134. b := &Bundler{
  135. KnownIssuers: map[string]bool{},
  136. IntermediatePool: x509.NewCertPool(),
  137. opts: opts,
  138. }
  139. log.Debug("building certificate pools")
  140. // RootPool will be nil if caBundlePEM is nil, also
  141. // that translates to caBundleFile is "".
  142. // Systems root store will be used.
  143. if caBundlePEM != nil {
  144. b.RootPool = x509.NewCertPool()
  145. }
  146. for _, c := range roots {
  147. b.RootPool.AddCert(c)
  148. b.KnownIssuers[string(c.Signature)] = true
  149. }
  150. for _, c := range intermediates {
  151. b.IntermediatePool.AddCert(c)
  152. b.KnownIssuers[string(c.Signature)] = true
  153. }
  154. log.Debug("bundler set up")
  155. return b, nil
  156. }
  157. // VerifyOptions generates an x509 VerifyOptions structure that can be
  158. // used for verifying certificates.
  159. func (b *Bundler) VerifyOptions() x509.VerifyOptions {
  160. return x509.VerifyOptions{
  161. Roots: b.RootPool,
  162. Intermediates: b.IntermediatePool,
  163. KeyUsages: b.opts.keyUsages,
  164. }
  165. }
  166. // BundleFromFile takes a set of files containing the PEM-encoded leaf certificate
  167. // (optionally along with some intermediate certs), the PEM-encoded private key
  168. // and returns the bundle built from that key and the certificate(s).
  169. func (b *Bundler) BundleFromFile(bundleFile, keyFile string, flavor BundleFlavor, password string) (*Bundle, error) {
  170. log.Debug("Loading Certificate: ", bundleFile)
  171. certsRaw, err := ioutil.ReadFile(bundleFile)
  172. if err != nil {
  173. return nil, errors.Wrap(errors.CertificateError, errors.ReadFailed, err)
  174. }
  175. var keyPEM []byte
  176. // Load private key PEM only if a file is given
  177. if keyFile != "" {
  178. log.Debug("Loading private key: ", keyFile)
  179. keyPEM, err = ioutil.ReadFile(keyFile)
  180. if err != nil {
  181. log.Debugf("failed to read private key: ", err)
  182. return nil, errors.Wrap(errors.PrivateKeyError, errors.ReadFailed, err)
  183. }
  184. if len(keyPEM) == 0 {
  185. log.Debug("key is empty")
  186. return nil, errors.Wrap(errors.PrivateKeyError, errors.DecodeFailed, err)
  187. }
  188. }
  189. return b.BundleFromPEMorDER(certsRaw, keyPEM, flavor, password)
  190. }
  191. // BundleFromPEMorDER builds a certificate bundle from the set of byte
  192. // slices containing the PEM or DER-encoded certificate(s), private key.
  193. func (b *Bundler) BundleFromPEMorDER(certsRaw, keyPEM []byte, flavor BundleFlavor, password string) (*Bundle, error) {
  194. log.Debug("bundling from PEM files")
  195. var key crypto.Signer
  196. var err error
  197. if len(keyPEM) != 0 {
  198. key, err = helpers.ParsePrivateKeyPEM(keyPEM)
  199. if err != nil {
  200. log.Debugf("failed to parse private key: %v", err)
  201. return nil, err
  202. }
  203. }
  204. certs, err := helpers.ParseCertificatesPEM(certsRaw)
  205. if err != nil {
  206. // If PEM doesn't work try DER
  207. var keyDER crypto.Signer
  208. var errDER error
  209. certs, keyDER, errDER = helpers.ParseCertificatesDER(certsRaw, password)
  210. // Only use DER key if no key read from file
  211. if key == nil && keyDER != nil {
  212. key = keyDER
  213. }
  214. if errDER != nil {
  215. log.Debugf("failed to parse certificates: %v", err)
  216. // If neither parser works pass along PEM error
  217. return nil, err
  218. }
  219. }
  220. if len(certs) == 0 {
  221. log.Debugf("no certificates found")
  222. return nil, errors.New(errors.CertificateError, errors.DecodeFailed)
  223. }
  224. log.Debugf("bundle ready")
  225. return b.Bundle(certs, key, flavor)
  226. }
  227. // BundleFromRemote fetches the certificate served by the server at
  228. // serverName (or ip, if the ip argument is not the empty string). It
  229. // is expected that the method will be able to make a connection at
  230. // port 443. The certificate used by the server in this connection is
  231. // used to build the bundle, which will necessarily be keyless.
  232. func (b *Bundler) BundleFromRemote(serverName, ip string, flavor BundleFlavor) (*Bundle, error) {
  233. config := &tls.Config{
  234. RootCAs: b.RootPool,
  235. ServerName: serverName,
  236. }
  237. // Dial by IP if present
  238. var dialName string
  239. if ip != "" {
  240. dialName = ip + ":443"
  241. } else {
  242. dialName = serverName + ":443"
  243. }
  244. log.Debugf("bundling from remote %s", dialName)
  245. dialer := &net.Dialer{Timeout: time.Duration(5) * time.Second}
  246. conn, err := tls.DialWithDialer(dialer, "tcp", dialName, config)
  247. var dialError string
  248. // If there's an error in tls.Dial, try again with
  249. // InsecureSkipVerify to fetch the remote bundle to (re-)bundle
  250. // with. If the bundle is indeed not usable (expired, mismatched
  251. // hostnames, etc.), report the error. Otherwise, create a
  252. // working bundle and insert the tls error in the bundle.Status.
  253. if err != nil {
  254. log.Debugf("dial failed: %v", err)
  255. // record the error msg
  256. dialError = fmt.Sprintf("Failed rigid TLS handshake with %s: %v", dialName, err)
  257. // dial again with InsecureSkipVerify
  258. log.Debugf("try again with InsecureSkipVerify.")
  259. config.InsecureSkipVerify = true
  260. conn, err = tls.DialWithDialer(dialer, "tcp", dialName, config)
  261. if err != nil {
  262. log.Debugf("dial with InsecureSkipVerify failed: %v", err)
  263. return nil, errors.Wrap(errors.DialError, errors.Unknown, err)
  264. }
  265. }
  266. connState := conn.ConnectionState()
  267. certs := connState.PeerCertificates
  268. err = conn.VerifyHostname(serverName)
  269. if err != nil {
  270. log.Debugf("failed to verify hostname: %v", err)
  271. return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
  272. }
  273. // Bundle with remote certs. Inject the initial dial error, if any, to the status reporting.
  274. bundle, err := b.Bundle(certs, nil, flavor)
  275. if err != nil {
  276. return nil, err
  277. } else if dialError != "" {
  278. bundle.Status.Messages = append(bundle.Status.Messages, dialError)
  279. }
  280. return bundle, err
  281. }
  282. type fetchedIntermediate struct {
  283. Cert *x509.Certificate
  284. Name string
  285. }
  286. // fetchRemoteCertificate retrieves a single URL pointing to a certificate
  287. // and attempts to first parse it as a DER-encoded certificate; if
  288. // this fails, it attempts to decode it as a PEM-encoded certificate.
  289. func fetchRemoteCertificate(certURL string) (fi *fetchedIntermediate, err error) {
  290. log.Debugf("fetching remote certificate: %s", certURL)
  291. var resp *http.Response
  292. resp, err = HTTPClient.Get(certURL)
  293. if err != nil {
  294. log.Debugf("failed HTTP get: %v", err)
  295. return
  296. }
  297. defer resp.Body.Close()
  298. var certData []byte
  299. certData, err = ioutil.ReadAll(resp.Body)
  300. if err != nil {
  301. log.Debugf("failed to read response body: %v", err)
  302. return
  303. }
  304. log.Debugf("attempting to parse certificate as DER")
  305. crt, err := x509.ParseCertificate(certData)
  306. if err != nil {
  307. log.Debugf("attempting to parse certificate as PEM")
  308. crt, err = helpers.ParseCertificatePEM(certData)
  309. if err != nil {
  310. log.Debugf("failed to parse certificate: %v", err)
  311. return
  312. }
  313. }
  314. log.Debugf("certificate fetch succeeds")
  315. fi = &fetchedIntermediate{Cert: crt, Name: constructCertFileName(crt)}
  316. return
  317. }
  318. func reverse(certs []*x509.Certificate) []*x509.Certificate {
  319. n := len(certs)
  320. if n == 0 {
  321. return certs
  322. }
  323. rcerts := []*x509.Certificate{}
  324. for i := n - 1; i >= 0; i-- {
  325. rcerts = append(rcerts, certs[i])
  326. }
  327. return rcerts
  328. }
  329. // Check if the certs form a partial cert chain: every cert verifies
  330. // the signature of the one in front of it.
  331. func partialVerify(certs []*x509.Certificate) bool {
  332. n := len(certs)
  333. if n == 0 {
  334. return false
  335. }
  336. for i := 0; i < n-1; i++ {
  337. if certs[i].CheckSignatureFrom(certs[i+1]) != nil {
  338. return false
  339. }
  340. }
  341. return true
  342. }
  343. func isSelfSigned(cert *x509.Certificate) bool {
  344. return cert.CheckSignatureFrom(cert) == nil
  345. }
  346. func isChainRootNode(cert *x509.Certificate) bool {
  347. if isSelfSigned(cert) {
  348. return true
  349. }
  350. return false
  351. }
  352. func (b *Bundler) verifyChain(chain []*fetchedIntermediate) bool {
  353. // This process will verify if the root of the (partial) chain is in our root pool,
  354. // and will fail otherwise.
  355. log.Debugf("verifying chain")
  356. for vchain := chain[:]; len(vchain) > 0; vchain = vchain[1:] {
  357. cert := vchain[0]
  358. // If this is a certificate in one of the pools, skip it.
  359. if b.KnownIssuers[string(cert.Cert.Signature)] {
  360. log.Debugf("certificate is known")
  361. continue
  362. }
  363. _, err := cert.Cert.Verify(b.VerifyOptions())
  364. if err != nil {
  365. log.Debugf("certificate failed verification: %v", err)
  366. return false
  367. } else if len(chain) == len(vchain) && isChainRootNode(cert.Cert) {
  368. // The first certificate in the chain is a root; it shouldn't be stored.
  369. log.Debug("looking at root certificate, will not store")
  370. continue
  371. }
  372. // leaf cert has an empty name, don't store leaf cert.
  373. if cert.Name == "" {
  374. continue
  375. }
  376. log.Debug("add certificate to intermediate pool:", cert.Name)
  377. b.IntermediatePool.AddCert(cert.Cert)
  378. b.KnownIssuers[string(cert.Cert.Signature)] = true
  379. if IntermediateStash != "" {
  380. fileName := filepath.Join(IntermediateStash, cert.Name)
  381. var block = pem.Block{Type: "CERTIFICATE", Bytes: cert.Cert.Raw}
  382. log.Debugf("write intermediate to stash directory: %s", fileName)
  383. // If the write fails, verification should not fail.
  384. err = ioutil.WriteFile(fileName, pem.EncodeToMemory(&block), 0644)
  385. if err != nil {
  386. log.Errorf("failed to write new intermediate: %v", err)
  387. } else {
  388. log.Info("stashed new intermediate ", cert.Name)
  389. }
  390. }
  391. }
  392. return true
  393. }
  394. // constructCertFileName returns a uniquely identifying file name for a certificate
  395. func constructCertFileName(cert *x509.Certificate) string {
  396. // construct the filename as the CN with no period and space
  397. name := strings.Replace(cert.Subject.CommonName, ".", "", -1)
  398. name = strings.Replace(name, " ", "", -1)
  399. // add SKI and serial number as extra identifier
  400. name += fmt.Sprintf("_%x", cert.SubjectKeyId)
  401. name += fmt.Sprintf("_%x", cert.SerialNumber.Bytes())
  402. name += ".crt"
  403. return name
  404. }
  405. // fetchIntermediates goes through each of the URLs in the AIA "Issuing
  406. // CA" extensions and fetches those certificates. If those
  407. // certificates are not present in either the root pool or
  408. // intermediate pool, the certificate is saved to file and added to
  409. // the list of intermediates to be used for verification. This will
  410. // not add any new certificates to the root pool; if the ultimate
  411. // issuer is not trusted, fetching the certificate here will not change
  412. // that.
  413. func (b *Bundler) fetchIntermediates(certs []*x509.Certificate) (err error) {
  414. if IntermediateStash != "" {
  415. log.Debugf("searching intermediates")
  416. if _, err := os.Stat(IntermediateStash); err != nil && os.IsNotExist(err) {
  417. log.Infof("intermediate stash directory %s doesn't exist, creating", IntermediateStash)
  418. err = os.MkdirAll(IntermediateStash, 0755)
  419. if err != nil {
  420. log.Errorf("failed to create intermediate stash directory %s: %v", IntermediateStash, err)
  421. return err
  422. }
  423. log.Infof("intermediate stash directory %s created", IntermediateStash)
  424. }
  425. }
  426. // stores URLs and certificate signatures that have been seen
  427. seen := map[string]bool{}
  428. var foundChains int
  429. // Construct a verify chain as a reversed partial bundle,
  430. // such that the certs are ordered by promxity to the root CAs.
  431. var chain []*fetchedIntermediate
  432. for i, cert := range certs {
  433. var name string
  434. // Only construct filenames for non-leaf intermediate certs
  435. // so they will be saved to disk if necessary.
  436. // Leaf cert gets a empty name and will be skipped.
  437. if i > 0 {
  438. name = constructCertFileName(cert)
  439. }
  440. chain = append([]*fetchedIntermediate{{cert, name}}, chain...)
  441. seen[string(cert.Signature)] = true
  442. }
  443. // Verify the chain and store valid intermediates in the chain.
  444. // If it doesn't verify, fetch the intermediates and extend the chain
  445. // in a DFS manner and verify each time we hit a root.
  446. for {
  447. if len(chain) == 0 {
  448. log.Debugf("search complete")
  449. if foundChains == 0 {
  450. return x509.UnknownAuthorityError{}
  451. }
  452. return nil
  453. }
  454. current := chain[0]
  455. var advanced bool
  456. if b.verifyChain(chain) {
  457. foundChains++
  458. }
  459. log.Debugf("walk AIA issuers")
  460. for _, url := range current.Cert.IssuingCertificateURL {
  461. if seen[url] {
  462. log.Debugf("url %s has been seen", url)
  463. continue
  464. }
  465. crt, err := fetchRemoteCertificate(url)
  466. if err != nil {
  467. continue
  468. } else if seen[string(crt.Cert.Signature)] {
  469. log.Debugf("fetched certificate is known")
  470. continue
  471. }
  472. seen[url] = true
  473. seen[string(crt.Cert.Signature)] = true
  474. chain = append([]*fetchedIntermediate{crt}, chain...)
  475. advanced = true
  476. break
  477. }
  478. if !advanced {
  479. log.Debugf("didn't advance, stepping back")
  480. chain = chain[1:]
  481. }
  482. }
  483. }
  484. // Bundle takes an X509 certificate (already in the
  485. // Certificate structure), a private key as crypto.Signer in one of the appropriate
  486. // formats (i.e. *rsa.PrivateKey or *ecdsa.PrivateKey, or even a opaque key), using them to
  487. // build a certificate bundle.
  488. func (b *Bundler) Bundle(certs []*x509.Certificate, key crypto.Signer, flavor BundleFlavor) (*Bundle, error) {
  489. log.Infof("bundling certificate for %+v", certs[0].Subject)
  490. if len(certs) == 0 {
  491. return nil, nil
  492. }
  493. // Detect reverse ordering of the cert chain.
  494. if len(certs) > 1 && !partialVerify(certs) {
  495. rcerts := reverse(certs)
  496. if partialVerify(rcerts) {
  497. certs = rcerts
  498. }
  499. }
  500. var ok bool
  501. cert := certs[0]
  502. if key != nil {
  503. switch {
  504. case cert.PublicKeyAlgorithm == x509.RSA:
  505. var rsaPublicKey *rsa.PublicKey
  506. if rsaPublicKey, ok = key.Public().(*rsa.PublicKey); !ok {
  507. return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch)
  508. }
  509. if cert.PublicKey.(*rsa.PublicKey).N.Cmp(rsaPublicKey.N) != 0 {
  510. return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch)
  511. }
  512. case cert.PublicKeyAlgorithm == x509.ECDSA:
  513. var ecdsaPublicKey *ecdsa.PublicKey
  514. if ecdsaPublicKey, ok = key.Public().(*ecdsa.PublicKey); !ok {
  515. return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch)
  516. }
  517. if cert.PublicKey.(*ecdsa.PublicKey).X.Cmp(ecdsaPublicKey.X) != 0 {
  518. return nil, errors.New(errors.PrivateKeyError, errors.KeyMismatch)
  519. }
  520. default:
  521. return nil, errors.New(errors.PrivateKeyError, errors.NotRSAOrECC)
  522. }
  523. } else {
  524. switch {
  525. case cert.PublicKeyAlgorithm == x509.RSA:
  526. case cert.PublicKeyAlgorithm == x509.ECDSA:
  527. default:
  528. return nil, errors.New(errors.PrivateKeyError, errors.NotRSAOrECC)
  529. }
  530. }
  531. bundle := new(Bundle)
  532. bundle.Cert = cert
  533. bundle.Key = key
  534. bundle.Issuer = &cert.Issuer
  535. bundle.Subject = &cert.Subject
  536. bundle.buildHostnames()
  537. if flavor == Force {
  538. // force bundle checks the certificates
  539. // forms a verification chain.
  540. if !partialVerify(certs) {
  541. return nil,
  542. errors.Wrap(errors.CertificateError, errors.VerifyFailed,
  543. goerr.New("Unable to verify the certificate chain"))
  544. }
  545. bundle.Chain = certs
  546. } else {
  547. // disallow self-signed cert
  548. if cert.CheckSignatureFrom(cert) == nil {
  549. return nil, errors.New(errors.CertificateError, errors.SelfSigned)
  550. }
  551. chains, err := cert.Verify(b.VerifyOptions())
  552. if err != nil {
  553. log.Debugf("verification failed: %v", err)
  554. // If the error was an unknown authority, try to fetch
  555. // the intermediate specified in the AIA and add it to
  556. // the intermediates bundle.
  557. if _, ok := err.(x509.UnknownAuthorityError); !ok {
  558. return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
  559. }
  560. log.Debugf("searching for intermediates via AIA issuer")
  561. searchErr := b.fetchIntermediates(certs)
  562. if searchErr != nil {
  563. log.Debugf("search failed: %v", searchErr)
  564. return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
  565. }
  566. log.Debugf("verifying new chain")
  567. chains, err = cert.Verify(b.VerifyOptions())
  568. if err != nil {
  569. log.Debugf("failed to verify chain: %v", err)
  570. return nil, errors.Wrap(errors.CertificateError, errors.VerifyFailed, err)
  571. }
  572. log.Debugf("verify ok")
  573. }
  574. var matchingChains [][]*x509.Certificate
  575. switch flavor {
  576. case Optimal:
  577. matchingChains = optimalChains(chains)
  578. case Ubiquitous:
  579. if len(ubiquity.Platforms) == 0 {
  580. log.Warning("No metadata, Ubiquitous falls back to Optimal.")
  581. }
  582. matchingChains = ubiquitousChains(chains)
  583. default:
  584. matchingChains = ubiquitousChains(chains)
  585. }
  586. bundle.Chain = matchingChains[0]
  587. }
  588. statusCode := int(errors.Success)
  589. var messages []string
  590. // Check if bundle is expiring.
  591. expiringCerts := checkExpiringCerts(bundle.Chain)
  592. if len(expiringCerts) > 0 {
  593. statusCode |= errors.BundleExpiringBit
  594. messages = append(messages, expirationWarning(expiringCerts))
  595. }
  596. // Check if bundle contains SHA2 certs.
  597. if ubiquity.ChainHashUbiquity(bundle.Chain) <= ubiquity.SHA2Ubiquity {
  598. statusCode |= errors.BundleNotUbiquitousBit
  599. messages = append(messages, sha2Warning)
  600. }
  601. // Check if bundle contains ECDSA signatures.
  602. if ubiquity.ChainKeyAlgoUbiquity(bundle.Chain) <= ubiquity.ECDSA256Ubiquity {
  603. statusCode |= errors.BundleNotUbiquitousBit
  604. messages = append(messages, ecdsaWarning)
  605. }
  606. // when forcing a bundle, bundle ubiquity doesn't matter
  607. // also we don't retrieve the anchoring root of the bundle
  608. var untrusted []string
  609. if flavor != Force {
  610. // Add root store presence info
  611. root := bundle.Chain[len(bundle.Chain)-1]
  612. bundle.Root = root
  613. log.Infof("the anchoring root is %v", root.Subject)
  614. // Check if there is any platform that doesn't trust the chain.
  615. // Also, an warning will be generated if ubiquity.Platforms is nil,
  616. untrusted = ubiquity.UntrustedPlatforms(root)
  617. untrustedMsg := untrustedPlatformsWarning(untrusted)
  618. if len(untrustedMsg) > 0 {
  619. log.Debug("Populate untrusted platform warning.")
  620. statusCode |= errors.BundleNotUbiquitousBit
  621. messages = append(messages, untrustedMsg)
  622. }
  623. }
  624. // Check if there is any platform that rejects the chain because of SHA1 deprecation.
  625. sha1Msgs := ubiquity.SHA1DeprecationMessages(bundle.Chain)
  626. if len(sha1Msgs) > 0 {
  627. log.Debug("Populate SHA1 deprecation warning.")
  628. statusCode |= errors.BundleNotUbiquitousBit
  629. messages = append(messages, sha1Msgs...)
  630. }
  631. bundle.Status = &BundleStatus{ExpiringSKIs: getSKIs(bundle.Chain, expiringCerts), Code: statusCode, Messages: messages, Untrusted: untrusted}
  632. // attempt to not to include the root certificate for optimization
  633. if flavor != Force {
  634. // Include at least one intermediate if the leaf has enabled OCSP and is not CA.
  635. if bundle.Cert.OCSPServer != nil && !bundle.Cert.IsCA && len(bundle.Chain) <= 2 {
  636. // No op. Return one intermediate if there is one.
  637. } else {
  638. // do not include the root.
  639. bundle.Chain = bundle.Chain[:len(bundle.Chain)-1]
  640. }
  641. }
  642. bundle.Status.IsRebundled = diff(bundle.Chain, certs)
  643. bundle.Expires = helpers.ExpiryTime(bundle.Chain)
  644. bundle.LeafExpires = bundle.Chain[0].NotAfter
  645. log.Debugf("bundle complete")
  646. return bundle, nil
  647. }
  648. // checkExpiringCerts returns indices of certs that are expiring within 30 days.
  649. func checkExpiringCerts(chain []*x509.Certificate) (expiringIntermediates []int) {
  650. now := time.Now()
  651. for i, cert := range chain {
  652. if cert.NotAfter.Sub(now).Hours() < 720 {
  653. expiringIntermediates = append(expiringIntermediates, i)
  654. }
  655. }
  656. return
  657. }
  658. // getSKIs returns a list of cert subject key id in the bundle chain with matched indices.
  659. func getSKIs(chain []*x509.Certificate, indices []int) (skis []string) {
  660. for _, index := range indices {
  661. ski := fmt.Sprintf("%X", chain[index].SubjectKeyId)
  662. skis = append(skis, ski)
  663. }
  664. return
  665. }
  666. // expirationWarning generates a warning message with expiring certs.
  667. func expirationWarning(expiringIntermediates []int) (ret string) {
  668. if len(expiringIntermediates) == 0 {
  669. return
  670. }
  671. ret = expiringWarningStub
  672. if len(expiringIntermediates) > 1 {
  673. ret = ret + "The expiring certs are"
  674. } else {
  675. ret = ret + "The expiring cert is"
  676. }
  677. for _, index := range expiringIntermediates {
  678. ret = ret + " #" + strconv.Itoa(index+1)
  679. }
  680. ret = ret + " in the chain."
  681. return
  682. }
  683. // untrustedPlatformsWarning generates a warning message with untrusted platform names.
  684. func untrustedPlatformsWarning(platforms []string) string {
  685. if len(ubiquity.Platforms) == 0 {
  686. return ubiquityWarning
  687. }
  688. if len(platforms) == 0 {
  689. return ""
  690. }
  691. msg := untrustedWarningStub
  692. for i, platform := range platforms {
  693. if i > 0 {
  694. msg += ","
  695. }
  696. msg += " " + platform
  697. }
  698. msg += "."
  699. return msg
  700. }
  701. // Optimal chains are the shortest chains, with newest intermediates and most advanced crypto suite being the tie breaker.
  702. func optimalChains(chains [][]*x509.Certificate) [][]*x509.Certificate {
  703. // Find shortest chains
  704. chains = ubiquity.Filter(chains, ubiquity.CompareChainLength)
  705. // Find the chains with longest expiry.
  706. chains = ubiquity.Filter(chains, ubiquity.CompareChainExpiry)
  707. // Find the chains with more advanced crypto suite
  708. chains = ubiquity.Filter(chains, ubiquity.CompareChainCryptoSuite)
  709. return chains
  710. }
  711. // Ubiquitous chains are the chains with highest platform coverage and break ties with the optimal strategy.
  712. func ubiquitousChains(chains [][]*x509.Certificate) [][]*x509.Certificate {
  713. // Filter out chains with highest cross platform ubiquity.
  714. chains = ubiquity.Filter(chains, ubiquity.ComparePlatformUbiquity)
  715. // Prefer that all intermediates are SHA-2 certs if the leaf is a SHA-2 cert, in order to improve ubiquity.
  716. chains = ubiquity.Filter(chains, ubiquity.CompareSHA2Homogeneity)
  717. // Filter shortest chains
  718. chains = ubiquity.Filter(chains, ubiquity.CompareChainLength)
  719. // Filter chains with highest signature hash ubiquity.
  720. chains = ubiquity.Filter(chains, ubiquity.CompareChainHashUbiquity)
  721. // Filter chains with highest keyAlgo ubiquity.
  722. chains = ubiquity.Filter(chains, ubiquity.CompareChainKeyAlgoUbiquity)
  723. // Filter chains with intermediates that last longer.
  724. chains = ubiquity.Filter(chains, ubiquity.CompareExpiryUbiquity)
  725. // Use the optimal strategy as final tie breaker.
  726. return optimalChains(chains)
  727. }
  728. // diff checkes if two input cert chains are not identical
  729. func diff(chain1, chain2 []*x509.Certificate) bool {
  730. // Check if bundled one is different from the input.
  731. diff := false
  732. if len(chain1) != len(chain2) {
  733. diff = true
  734. } else {
  735. for i := 0; i < len(chain1); i++ {
  736. cert1 := chain1[i]
  737. cert2 := chain2[i]
  738. // Use signature to differentiate.
  739. if !bytes.Equal(cert1.Signature, cert2.Signature) {
  740. diff = true
  741. break
  742. }
  743. }
  744. }
  745. return diff
  746. }