Repository: pion/dtls
Pull request #240 (2020-03-30 09:13:09)

Move ExportKeyingMaterial to State
Move `ExportKeyingMaterial` from `Conn` to `State`.


codecov[bot]: # [Codecov](https://codecov.io/gh/pion/dtls/pull/240?src=pr&el=h1) Report
> Merging [#240](https://codecov.io/gh/pion/dtls/pull/240?src=pr&el=desc) into [master](https://codecov.io/gh/pion/dtls/commit/e1af363f7ba5d5de1f134f19e2987447007097a5&el=desc) will **decrease** coverage by `0.13%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/pion/dtls/pull/240/graphs/tree.svg?width=650&height=150&src=pr&token=bcCB2jB88I)](https://codecov.io/gh/pion/dtls/pull/240?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #240      +/-   ##
==========================================
- Coverage   77.81%   77.68%   -0.14%     
==========================================
  Files          76       76              
  Lines        4039     4037       -2     
==========================================
- Hits         3143     3136       -7     
- Misses        619      622       +3     
- Partials      277      279       +2     
```

| Flag | Coverage Δ | |
|---|---|---|
| #go | `77.67% <100.00%> (-0.07%)` | :arrow_down: |
| #wasm | `72.67% <100.00%> (-0.14%)` | :arrow_down: |

| [Impacted Files](https://codecov.io/gh/pion/dtls/pull/240?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [conn.go](https://codecov.io/gh/pion/dtls/pull/240/diff?src=pr&el=tree#diff-Y29ubi5nbw==) | `84.17% <ø> (-0.47%)` | :arrow_down: |
| [state.go](https://codecov.io/gh/pion/dtls/pull/240/diff?src=pr&el=tree#diff-c3RhdGUuZ28=) | `90.24% <100.00%> (+2.18%)` | :arrow_up: |
| [internal/net/connctx/connctx.go](https://codecov.io/gh/pion/dtls/pull/240/diff?src=pr&el=tree#diff-aW50ZXJuYWwvbmV0L2Nvbm5jdHgvY29ubmN0eC5nbw==) | `82.71% <0.00%> (-6.18%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/pion/dtls/pull/240?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/pion/dtls/pull/240?src=pr&el=footer). Last update [e1af363...320c13e](https://codecov.io/gh/pion/dtls/pull/240?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/conn.go b/conn.go
index bf503b9..30f6fd9 100644
--- a/conn.go
+++ b/conn.go
@@ -355,33 +355,6 @@ func (c *Conn) SelectedSRTPProtectionProfile() (SRTPProtectionProfile, bool) {
 	return c.state.srtpProtectionProfile, true
 }
 
-// ExportKeyingMaterial from https://tools.ietf.org/html/rfc5705
-// This allows protocols to use DTLS for key establishment, but
-// then use some of the keying material for their own purposes
-func (c *Conn) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
-	c.lock.Lock()
-	defer c.lock.Unlock()
-
-	if c.getLocalEpoch() == 0 {
-		return nil, errHandshakeInProgress
-	} else if len(context) != 0 {
-		return nil, errContextUnsupported
-	} else if _, ok := invalidKeyingLabels[label]; ok {
-		return nil, errReservedExportKeyingMaterial
-	}
-
-	localRandom := c.state.localRandom.marshalFixed()
-	remoteRandom := c.state.remoteRandom.marshalFixed()
-
-	seed := []byte(label)
-	if c.state.isClient {
-		seed = append(append(seed, localRandom[:]...), remoteRandom[:]...)
-	} else {
-		seed = append(append(seed, remoteRandom[:]...), localRandom[:]...)
-	}
-	return prfPHash(c.state.masterSecret, seed, length, c.state.cipherSuite.hashFunc())
-}
-
 func (c *Conn) writePackets(ctx context.Context, pkts []*packet) error {
 	c.lock.Lock()
 	defer c.lock.Unlock()
diff --git a/state.go b/state.go
index 0c7abb0..7c15dcc 100644
--- a/state.go
+++ b/state.go
@@ -160,3 +160,28 @@ func (s *State) UnmarshalBinary(data []byte) error {
 	}
 	return nil
 }
+
+// ExportKeyingMaterial returns length bytes of exported key material in a new
+// slice as defined in RFC 5705.
+// This allows protocols to use DTLS for key establishment, but
+// then use some of the keying material for their own purposes
+func (s *State) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
+	if s.localEpoch.Load().(uint16) == 0 {
+		return nil, errHandshakeInProgress
+	} else if len(context) != 0 {
+		return nil, errContextUnsupported
+	} else if _, ok := invalidKeyingLabels[label]; ok {
+		return nil, errReservedExportKeyingMaterial
+	}
+
+	localRandom := s.localRandom.marshalFixed()
+	remoteRandom := s.remoteRandom.marshalFixed()
+
+	seed := []byte(label)
+	if s.isClient {
+		seed = append(append(seed, localRandom[:]...), remoteRandom[:]...)
+	} else {
+		seed = append(append(seed, remoteRandom[:]...), localRandom[:]...)
+	}
+	return prfPHash(s.masterSecret, seed, length, s.cipherSuite.hashFunc())
+}


Test patch:
diff --git a/conn_test.go b/conn_test.go
index b764500..791bc63 100644
--- a/conn_test.go
+++ b/conn_test.go
@@ -357,32 +357,38 @@ func TestExportKeyingMaterial(t *testing.T) {
 
 	c := &Conn{
 		state: State{
-			localRandom:  handshakeRandom{time.Unix(500, 0), rand},
-			remoteRandom: handshakeRandom{time.Unix(1000, 0), rand},
-			cipherSuite:  &cipherSuiteTLSEcdheEcdsaWithAes128GcmSha256{},
+			localRandom:         handshakeRandom{time.Unix(500, 0), rand},
+			remoteRandom:        handshakeRandom{time.Unix(1000, 0), rand},
+			localSequenceNumber: []uint64{0, 0},
+			cipherSuite:         &cipherSuiteTLSEcdheEcdsaWithAes128GcmSha256{},
 		},
 	}
 	c.setLocalEpoch(0)
+	c.setRemoteEpoch(0)
 
-	_, err := c.ExportKeyingMaterial(exportLabel, nil, 0)
+	state := c.ConnectionState()
+	_, err := state.ExportKeyingMaterial(exportLabel, nil, 0)
 	if err != errHandshakeInProgress {
 		t.Errorf("ExportKeyingMaterial when epoch == 0: expected '%s' actual '%s'", errHandshakeInProgress, err)
 	}
 
 	c.setLocalEpoch(1)
-	_, err = c.ExportKeyingMaterial(exportLabel, []byte{0x00}, 0)
+	state = c.ConnectionState()
+	_, err = state.ExportKeyingMaterial(exportLabel, []byte{0x00}, 0)
 	if err != errContextUnsupported {
 		t.Errorf("ExportKeyingMaterial with context: expected '%s' actual '%s'", errContextUnsupported, err)
 	}
 
 	for k := range invalidKeyingLabels {
-		_, err = c.ExportKeyingMaterial(k, nil, 0)
+		state = c.ConnectionState()
+		_, err = state.ExportKeyingMaterial(k, nil, 0)
 		if err != errReservedExportKeyingMaterial {
 			t.Errorf("ExportKeyingMaterial reserved label: expected '%s' actual '%s'", errReservedExportKeyingMaterial, err)
 		}
 	}
 
-	keyingMaterial, err := c.ExportKeyingMaterial(exportLabel, nil, 10)
+	state = c.ConnectionState()
+	keyingMaterial, err := state.ExportKeyingMaterial(exportLabel, nil, 10)
 	if err != nil {
 		t.Errorf("ExportKeyingMaterial as server: unexpected error '%s'", err)
 	} else if !bytes.Equal(keyingMaterial, expectedServerKey) {
@@ -390,7 +396,8 @@ func TestExportKeyingMaterial(t *testing.T) {
 	}
 
 	c.state.isClient = true
-	keyingMaterial, err = c.ExportKeyingMaterial(exportLabel, nil, 10)
+	state = c.ConnectionState()
+	keyingMaterial, err = state.ExportKeyingMaterial(exportLabel, nil, 10)
 	if err != nil {
 		t.Errorf("ExportKeyingMaterial as server: unexpected error '%s'", err)
 	} else if !bytes.Equal(keyingMaterial, expectedClientKey) {