1
0

connection_manager_test.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. package nebula
  2. import (
  3. "crypto/ed25519"
  4. "crypto/rand"
  5. "net/netip"
  6. "testing"
  7. "time"
  8. "github.com/rcrowley/go-metrics"
  9. "github.com/slackhq/nebula/cert"
  10. "github.com/slackhq/nebula/config"
  11. "github.com/slackhq/nebula/overlay/overlaytest"
  12. "github.com/slackhq/nebula/test"
  13. "github.com/slackhq/nebula/udp"
  14. "github.com/stretchr/testify/assert"
  15. "github.com/stretchr/testify/require"
  16. )
  17. func newTestLighthouse() *LightHouse {
  18. lh := &LightHouse{
  19. l: test.NewLogger(),
  20. addrMap: map[netip.Addr]*RemoteList{},
  21. queryChan: make(chan netip.Addr, 10),
  22. // Nothing drains queryChan here, so an 11th query is dropped.
  23. queryDropped: metrics.NilCounter{},
  24. }
  25. lighthouses := []netip.Addr{}
  26. staticList := map[netip.Addr]struct{}{}
  27. lh.localAddrsFn = func(*LocalAllowList) []netip.Addr { return nil }
  28. lh.lighthouses.Store(&lighthouses)
  29. lh.staticList.Store(&staticList)
  30. return lh
  31. }
  32. func Test_NewConnectionManagerTest(t *testing.T) {
  33. l := test.NewLogger()
  34. //_, tuncidr, _ := net.ParseCIDR("1.1.1.1/24")
  35. localrange := netip.MustParsePrefix("10.1.1.1/24")
  36. vpnIp := netip.MustParseAddr("172.1.1.2")
  37. preferredRanges := []netip.Prefix{localrange}
  38. // Very incomplete mock objects
  39. hostMap := newHostMap(l)
  40. hostMap.preferredRanges.Store(&preferredRanges)
  41. cs := &CertState{
  42. initiatingVersion: cert.Version1,
  43. privateKey: []byte{},
  44. v1Cert: &dummyCert{version: cert.Version1},
  45. v1Credential: nil,
  46. }
  47. lh := newTestLighthouse()
  48. ifce := &Interface{
  49. hostMap: hostMap,
  50. inside: &overlaytest.NoopTun{},
  51. outside: &udp.NoopConn{},
  52. firewall: &Firewall{},
  53. lightHouse: lh,
  54. pki: &PKI{},
  55. handshakeManager: NewHandshakeManager(l, hostMap, lh, &udp.NoopConn{}, defaultHandshakeConfig),
  56. l: l,
  57. }
  58. ifce.pki.cs.Store(cs)
  59. // Create manager
  60. conf := config.NewC(test.NewLogger())
  61. punchy := NewPunchyFromConfig(test.NewLogger(), conf, nil)
  62. nc := newConnectionManagerFromConfig(test.NewLogger(), conf, hostMap, punchy)
  63. nc.intf = ifce
  64. p := []byte("")
  65. nb := make([]byte, 12, 12)
  66. out := make([]byte, mtu)
  67. // Add an ip we have established a connection w/ to hostmap
  68. hostinfo := &HostInfo{
  69. vpnAddrs: []netip.Addr{vpnIp},
  70. localIndexId: 1099,
  71. remoteIndexId: 9901,
  72. }
  73. hostinfo.ConnectionState = &ConnectionState{
  74. myCert: &dummyCert{version: cert.Version1},
  75. }
  76. nc.hostMap.unlockedAddHostInfo(hostinfo, ifce)
  77. // We saw traffic out to vpnIp
  78. nc.Out(hostinfo)
  79. nc.In(hostinfo)
  80. assert.False(t, hostinfo.isPendingDeletion())
  81. assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnAddrs[0])
  82. assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId)
  83. assert.True(t, hostinfo.sentSinceCheck())
  84. assert.True(t, (hostinfo.state.Load()&stateIn != 0))
  85. // Do a traffic check tick, should not be pending deletion but should not have any in/out packets recorded
  86. nc.doTrafficCheck(hostinfo.localIndexId, p, nb, out, time.Now())
  87. assert.False(t, hostinfo.isPendingDeletion())
  88. assert.False(t, hostinfo.sentSinceCheck())
  89. assert.False(t, (hostinfo.state.Load()&stateIn != 0))
  90. // Do another traffic check tick, this host should be pending deletion now
  91. nc.Out(hostinfo)
  92. assert.True(t, hostinfo.sentSinceCheck())
  93. nc.doTrafficCheck(hostinfo.localIndexId, p, nb, out, time.Now())
  94. assert.True(t, hostinfo.isPendingDeletion())
  95. assert.False(t, hostinfo.sentSinceCheck())
  96. assert.False(t, (hostinfo.state.Load()&stateIn != 0))
  97. assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId)
  98. assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnAddrs[0])
  99. // Do a final traffic check tick, the host should now be removed
  100. nc.doTrafficCheck(hostinfo.localIndexId, p, nb, out, time.Now())
  101. assert.NotContains(t, nc.hostMap.Hosts, hostinfo.vpnAddrs)
  102. assert.NotContains(t, nc.hostMap.Indexes, hostinfo.localIndexId)
  103. }
  104. func Test_NewConnectionManagerTest2(t *testing.T) {
  105. l := test.NewLogger()
  106. //_, tuncidr, _ := net.ParseCIDR("1.1.1.1/24")
  107. localrange := netip.MustParsePrefix("10.1.1.1/24")
  108. vpnIp := netip.MustParseAddr("172.1.1.2")
  109. preferredRanges := []netip.Prefix{localrange}
  110. // Very incomplete mock objects
  111. hostMap := newHostMap(l)
  112. hostMap.preferredRanges.Store(&preferredRanges)
  113. cs := &CertState{
  114. initiatingVersion: cert.Version1,
  115. privateKey: []byte{},
  116. v1Cert: &dummyCert{version: cert.Version1},
  117. v1Credential: nil,
  118. }
  119. lh := newTestLighthouse()
  120. ifce := &Interface{
  121. hostMap: hostMap,
  122. inside: &overlaytest.NoopTun{},
  123. outside: &udp.NoopConn{},
  124. firewall: &Firewall{},
  125. lightHouse: lh,
  126. pki: &PKI{},
  127. handshakeManager: NewHandshakeManager(l, hostMap, lh, &udp.NoopConn{}, defaultHandshakeConfig),
  128. l: l,
  129. }
  130. ifce.pki.cs.Store(cs)
  131. // Create manager
  132. conf := config.NewC(test.NewLogger())
  133. punchy := NewPunchyFromConfig(test.NewLogger(), conf, nil)
  134. nc := newConnectionManagerFromConfig(test.NewLogger(), conf, hostMap, punchy)
  135. nc.intf = ifce
  136. p := []byte("")
  137. nb := make([]byte, 12, 12)
  138. out := make([]byte, mtu)
  139. // Add an ip we have established a connection w/ to hostmap
  140. hostinfo := &HostInfo{
  141. vpnAddrs: []netip.Addr{vpnIp},
  142. localIndexId: 1099,
  143. remoteIndexId: 9901,
  144. }
  145. hostinfo.ConnectionState = &ConnectionState{
  146. myCert: &dummyCert{version: cert.Version1},
  147. }
  148. nc.hostMap.unlockedAddHostInfo(hostinfo, ifce)
  149. // We saw traffic out to vpnIp
  150. nc.Out(hostinfo)
  151. nc.In(hostinfo)
  152. assert.True(t, (hostinfo.state.Load()&stateIn != 0))
  153. assert.True(t, hostinfo.sentSinceCheck())
  154. assert.False(t, hostinfo.isPendingDeletion())
  155. assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnAddrs[0])
  156. assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId)
  157. // Do a traffic check tick, should not be pending deletion but should not have any in/out packets recorded
  158. nc.doTrafficCheck(hostinfo.localIndexId, p, nb, out, time.Now())
  159. assert.False(t, hostinfo.isPendingDeletion())
  160. assert.False(t, hostinfo.sentSinceCheck())
  161. assert.False(t, (hostinfo.state.Load()&stateIn != 0))
  162. // Do another traffic check tick, this host should be pending deletion now
  163. nc.Out(hostinfo)
  164. nc.doTrafficCheck(hostinfo.localIndexId, p, nb, out, time.Now())
  165. assert.True(t, hostinfo.isPendingDeletion())
  166. assert.False(t, hostinfo.sentSinceCheck())
  167. assert.False(t, (hostinfo.state.Load()&stateIn != 0))
  168. assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId)
  169. assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnAddrs[0])
  170. // We saw traffic, should no longer be pending deletion
  171. nc.In(hostinfo)
  172. nc.doTrafficCheck(hostinfo.localIndexId, p, nb, out, time.Now())
  173. assert.False(t, hostinfo.isPendingDeletion())
  174. assert.False(t, hostinfo.sentSinceCheck())
  175. assert.False(t, (hostinfo.state.Load()&stateIn != 0))
  176. assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId)
  177. assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnAddrs[0])
  178. }
  179. func Test_NewConnectionManager_CounterLimits(t *testing.T) {
  180. l := test.NewLogger()
  181. localrange := netip.MustParsePrefix("10.1.1.1/24")
  182. vpnIp := netip.MustParseAddr("172.1.1.2")
  183. preferredRanges := []netip.Prefix{localrange}
  184. // Very incomplete mock objects
  185. hostMap := newHostMap(l)
  186. hostMap.preferredRanges.Store(&preferredRanges)
  187. cs := &CertState{
  188. initiatingVersion: cert.Version1,
  189. privateKey: []byte{},
  190. v1Cert: &dummyCert{version: cert.Version1},
  191. v1Credential: nil,
  192. }
  193. lh := newTestLighthouse()
  194. ifce := &Interface{
  195. hostMap: hostMap,
  196. inside: &overlaytest.NoopTun{},
  197. outside: &udp.NoopConn{},
  198. firewall: &Firewall{},
  199. lightHouse: lh,
  200. pki: &PKI{},
  201. myVpnAddrs: []netip.Addr{netip.MustParseAddr("172.1.1.1")}, // sorts below vpnIp so shouldSwapPrimary can proceed
  202. handshakeManager: NewHandshakeManager(l, hostMap, lh, &udp.NoopConn{}, defaultHandshakeConfig),
  203. l: l,
  204. }
  205. ifce.pki.cs.Store(cs)
  206. conf := config.NewC(test.NewLogger())
  207. punchy := NewPunchyFromConfig(test.NewLogger(), conf, nil)
  208. nc := newConnectionManagerFromConfig(test.NewLogger(), conf, hostMap, punchy)
  209. nc.intf = ifce
  210. hostinfo := &HostInfo{
  211. vpnAddrs: []netip.Addr{vpnIp},
  212. localIndexId: 1099,
  213. remoteIndexId: 9901,
  214. }
  215. hostinfo.ConnectionState = &ConnectionState{
  216. myCert: &dummyCert{version: cert.Version1},
  217. }
  218. nc.hostMap.unlockedAddHostInfo(hostinfo, ifce)
  219. // Below the rehandshake threshold, no handshake is started
  220. hostinfo.ConnectionState.messageCounter.Store(RehandshakeAfterMessages - 1)
  221. nc.tryRehandshake(hostinfo)
  222. assert.Nil(t, ifce.handshakeManager.QueryVpnAddr(vpnIp))
  223. // A tunnel on its current cert would normally swap to primary
  224. assert.True(t, nc.shouldSwapPrimary(hostinfo))
  225. // At the rehandshake threshold, a new handshake is started
  226. hostinfo.ConnectionState.messageCounter.Store(RehandshakeAfterMessages)
  227. nc.tryRehandshake(hostinfo)
  228. assert.NotNil(t, ifce.handshakeManager.QueryVpnAddr(vpnIp))
  229. // An exhausted tunnel being rolled must never swap back to primary onto its spent key
  230. assert.False(t, nc.shouldSwapPrimary(hostinfo))
  231. // Still below the reject limit, the tunnel stays up
  232. nc.In(hostinfo)
  233. decision, _, _ := nc.makeTrafficDecision(hostinfo.localIndexId, time.Now())
  234. assert.Equal(t, tryRehandshake, decision)
  235. // At the reject limit, the tunnel is deleted locally without a doomed CloseTunnel notify
  236. hostinfo.ConnectionState.messageCounter.Store(RejectAfterMessages)
  237. decision, _, _ = nc.makeTrafficDecision(hostinfo.localIndexId, time.Now())
  238. assert.Equal(t, deleteTunnel, decision)
  239. }
  240. func Test_NewConnectionManager_DisconnectInactive(t *testing.T) {
  241. l := test.NewLogger()
  242. localrange := netip.MustParsePrefix("10.1.1.1/24")
  243. vpnAddrs := []netip.Addr{netip.MustParseAddr("172.1.1.2")}
  244. preferredRanges := []netip.Prefix{localrange}
  245. // Very incomplete mock objects
  246. hostMap := newHostMap(l)
  247. hostMap.preferredRanges.Store(&preferredRanges)
  248. cs := &CertState{
  249. initiatingVersion: cert.Version1,
  250. privateKey: []byte{},
  251. v1Cert: &dummyCert{version: cert.Version1},
  252. v1Credential: nil,
  253. }
  254. lh := newTestLighthouse()
  255. ifce := &Interface{
  256. hostMap: hostMap,
  257. inside: &overlaytest.NoopTun{},
  258. outside: &udp.NoopConn{},
  259. firewall: &Firewall{},
  260. lightHouse: lh,
  261. pki: &PKI{},
  262. handshakeManager: NewHandshakeManager(l, hostMap, lh, &udp.NoopConn{}, defaultHandshakeConfig),
  263. l: l,
  264. }
  265. ifce.pki.cs.Store(cs)
  266. // Create manager
  267. conf := config.NewC(test.NewLogger())
  268. conf.Settings["tunnels"] = map[string]any{
  269. "drop_inactive": true,
  270. }
  271. punchy := NewPunchyFromConfig(test.NewLogger(), conf, nil)
  272. nc := newConnectionManagerFromConfig(test.NewLogger(), conf, hostMap, punchy)
  273. assert.True(t, nc.dropInactive.Load())
  274. nc.intf = ifce
  275. // Add an ip we have established a connection w/ to hostmap
  276. hostinfo := &HostInfo{
  277. vpnAddrs: vpnAddrs,
  278. localIndexId: 1099,
  279. remoteIndexId: 9901,
  280. }
  281. hostinfo.ConnectionState = &ConnectionState{
  282. myCert: &dummyCert{version: cert.Version1},
  283. }
  284. nc.hostMap.unlockedAddHostInfo(hostinfo, ifce)
  285. // Do a traffic check tick, in and out should be cleared but should not be pending deletion
  286. nc.Out(hostinfo)
  287. nc.In(hostinfo)
  288. assert.True(t, hostinfo.sentSinceCheck())
  289. assert.True(t, (hostinfo.state.Load()&stateIn != 0))
  290. now := time.Now()
  291. decision, _, _ := nc.makeTrafficDecision(hostinfo.localIndexId, now)
  292. assert.Equal(t, tryRehandshake, decision)
  293. assert.Equal(t, now, hostinfo.lastUsed)
  294. assert.False(t, hostinfo.isPendingDeletion())
  295. assert.False(t, hostinfo.sentSinceCheck())
  296. assert.False(t, (hostinfo.state.Load()&stateIn != 0))
  297. decision, _, _ = nc.makeTrafficDecision(hostinfo.localIndexId, now.Add(time.Second*5))
  298. assert.Equal(t, doNothing, decision)
  299. assert.Equal(t, now, hostinfo.lastUsed)
  300. assert.False(t, hostinfo.isPendingDeletion())
  301. assert.False(t, hostinfo.sentSinceCheck())
  302. assert.False(t, (hostinfo.state.Load()&stateIn != 0))
  303. // Do another traffic check tick, should still not be pending deletion
  304. decision, _, _ = nc.makeTrafficDecision(hostinfo.localIndexId, now.Add(time.Second*10))
  305. assert.Equal(t, doNothing, decision)
  306. assert.Equal(t, now, hostinfo.lastUsed)
  307. assert.False(t, hostinfo.isPendingDeletion())
  308. assert.False(t, hostinfo.sentSinceCheck())
  309. assert.False(t, (hostinfo.state.Load()&stateIn != 0))
  310. assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId)
  311. assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnAddrs[0])
  312. // Finally advance beyond the inactivity timeout
  313. decision, _, _ = nc.makeTrafficDecision(hostinfo.localIndexId, now.Add(time.Minute*10))
  314. assert.Equal(t, closeTunnel, decision)
  315. assert.Equal(t, now, hostinfo.lastUsed)
  316. assert.False(t, hostinfo.isPendingDeletion())
  317. assert.False(t, hostinfo.sentSinceCheck())
  318. assert.False(t, (hostinfo.state.Load()&stateIn != 0))
  319. assert.Contains(t, nc.hostMap.Indexes, hostinfo.localIndexId)
  320. assert.Contains(t, nc.hostMap.Hosts, hostinfo.vpnAddrs[0])
  321. }
  322. // Check if we can disconnect the peer.
  323. // Validate if the peer's certificate is invalid (expired, etc.)
  324. // Disconnect only if disconnectInvalid: true is set.
  325. func Test_NewConnectionManagerTest_DisconnectInvalid(t *testing.T) {
  326. now := time.Now()
  327. l := test.NewLogger()
  328. vpncidr := netip.MustParsePrefix("172.1.1.1/24")
  329. localrange := netip.MustParsePrefix("10.1.1.1/24")
  330. vpnIp := netip.MustParseAddr("172.1.1.2")
  331. preferredRanges := []netip.Prefix{localrange}
  332. hostMap := newHostMap(l)
  333. hostMap.preferredRanges.Store(&preferredRanges)
  334. // Generate keys for CA and peer's cert.
  335. pubCA, privCA, _ := ed25519.GenerateKey(rand.Reader)
  336. tbs := &cert.TBSCertificate{
  337. Version: 1,
  338. Name: "ca",
  339. IsCA: true,
  340. NotBefore: now,
  341. NotAfter: now.Add(1 * time.Hour),
  342. PublicKey: pubCA,
  343. }
  344. caCert, err := tbs.Sign(nil, cert.Curve_CURVE25519, privCA)
  345. require.NoError(t, err)
  346. ncp := cert.NewCAPool()
  347. require.NoError(t, ncp.AddCA(caCert))
  348. pubCrt, _, _ := ed25519.GenerateKey(rand.Reader)
  349. tbs = &cert.TBSCertificate{
  350. Version: 1,
  351. Name: "host",
  352. Networks: []netip.Prefix{vpncidr},
  353. NotBefore: now,
  354. NotAfter: now.Add(60 * time.Second),
  355. PublicKey: pubCrt,
  356. }
  357. peerCert, err := tbs.Sign(caCert, cert.Curve_CURVE25519, privCA)
  358. require.NoError(t, err)
  359. cachedPeerCert, err := ncp.VerifyCertificate(now.Add(time.Second), peerCert)
  360. cs := &CertState{
  361. privateKey: []byte{},
  362. v1Cert: &dummyCert{},
  363. v1Credential: nil,
  364. }
  365. lh := newTestLighthouse()
  366. ifce := &Interface{
  367. hostMap: hostMap,
  368. inside: &overlaytest.NoopTun{},
  369. outside: &udp.NoopConn{},
  370. firewall: &Firewall{},
  371. lightHouse: lh,
  372. handshakeManager: NewHandshakeManager(l, hostMap, lh, &udp.NoopConn{}, defaultHandshakeConfig),
  373. l: l,
  374. pki: &PKI{},
  375. }
  376. ifce.pki.cs.Store(cs)
  377. ifce.pki.caPool.Store(ncp)
  378. ifce.disconnectInvalid.Store(true)
  379. // Create manager
  380. conf := config.NewC(test.NewLogger())
  381. punchy := NewPunchyFromConfig(test.NewLogger(), conf, nil)
  382. nc := newConnectionManagerFromConfig(test.NewLogger(), conf, hostMap, punchy)
  383. nc.intf = ifce
  384. ifce.connectionManager = nc
  385. hostinfo := &HostInfo{
  386. vpnAddrs: []netip.Addr{vpnIp},
  387. ConnectionState: &ConnectionState{
  388. myCert: &dummyCert{},
  389. peerCert: cachedPeerCert,
  390. },
  391. }
  392. nc.hostMap.unlockedAddHostInfo(hostinfo, ifce)
  393. // Move ahead 45s.
  394. // Check if to disconnect with invalid certificate.
  395. // Should be alive.
  396. nextTick := now.Add(45 * time.Second)
  397. invalid := nc.isInvalidCertificate(nextTick, hostinfo)
  398. assert.False(t, invalid)
  399. // Move ahead 61s.
  400. // Check if to disconnect with invalid certificate.
  401. // Should be disconnected.
  402. nextTick = now.Add(61 * time.Second)
  403. invalid = nc.isInvalidCertificate(nextTick, hostinfo)
  404. assert.True(t, invalid)
  405. }
  406. type dummyCert struct {
  407. version cert.Version
  408. curve cert.Curve
  409. groups []string
  410. isCa bool
  411. issuer string
  412. name string
  413. networks []netip.Prefix
  414. notAfter time.Time
  415. notBefore time.Time
  416. publicKey []byte
  417. signature []byte
  418. unsafeNetworks []netip.Prefix
  419. }
  420. func (d *dummyCert) Version() cert.Version {
  421. return d.version
  422. }
  423. func (d *dummyCert) Curve() cert.Curve {
  424. return d.curve
  425. }
  426. func (d *dummyCert) Groups() []string {
  427. return d.groups
  428. }
  429. func (d *dummyCert) IsCA() bool {
  430. return d.isCa
  431. }
  432. func (d *dummyCert) Issuer() string {
  433. return d.issuer
  434. }
  435. func (d *dummyCert) Name() string {
  436. return d.name
  437. }
  438. func (d *dummyCert) Networks() []netip.Prefix {
  439. return d.networks
  440. }
  441. func (d *dummyCert) NotAfter() time.Time {
  442. return d.notAfter
  443. }
  444. func (d *dummyCert) NotBefore() time.Time {
  445. return d.notBefore
  446. }
  447. func (d *dummyCert) PublicKey() []byte {
  448. return d.publicKey
  449. }
  450. func (d *dummyCert) MarshalPublicKeyPEM() []byte {
  451. return cert.MarshalPublicKeyToPEM(d.curve, d.publicKey)
  452. }
  453. func (d *dummyCert) Signature() []byte {
  454. return d.signature
  455. }
  456. func (d *dummyCert) UnsafeNetworks() []netip.Prefix {
  457. return d.unsafeNetworks
  458. }
  459. func (d *dummyCert) MarshalForHandshakes() ([]byte, error) {
  460. return nil, nil
  461. }
  462. func (d *dummyCert) Sign(curve cert.Curve, key []byte) error {
  463. return nil
  464. }
  465. func (d *dummyCert) CheckSignature(key []byte) bool {
  466. return true
  467. }
  468. func (d *dummyCert) Expired(t time.Time) bool {
  469. return false
  470. }
  471. func (d *dummyCert) CheckRootConstraints(signer cert.Certificate) error {
  472. return nil
  473. }
  474. func (d *dummyCert) VerifyPrivateKey(curve cert.Curve, key []byte) error {
  475. return nil
  476. }
  477. func (d *dummyCert) String() string {
  478. return ""
  479. }
  480. func (d *dummyCert) Marshal() ([]byte, error) {
  481. return nil, nil
  482. }
  483. func (d *dummyCert) MarshalPEM() ([]byte, error) {
  484. return nil, nil
  485. }
  486. func (d *dummyCert) Fingerprint() (string, error) {
  487. return "", nil
  488. }
  489. func (d *dummyCert) MarshalJSON() ([]byte, error) {
  490. return nil, nil
  491. }
  492. func (d *dummyCert) Copy() cert.Certificate {
  493. return d
  494. }