bundler.go 27 KB

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