bundler.go 26 KB

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