Remediate SAF-01-005 Crypto: Unnecessary Configurability Considered Dangerous (Medium)
This is a rather large commit, as the change from a toolset to the new cipher suite system has a large impact.
This commit is contained in:
parent
7990775cf3
commit
31216b0885
20 changed files with 1117 additions and 389 deletions
4
Gopkg.lock
generated
4
Gopkg.lock
generated
|
@ -104,7 +104,7 @@
|
|||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
digest = "1:23e3d5f66ff9fd60dd264fbf26e71cab6b4a3bd2ef993a1645432d5c4c3b50fc"
|
||||
digest = "1:4df631634d7dc4496e9c51436cc2d3ccd0d0d4734640f63108950fe68b348b7e"
|
||||
name = "golang.org/x/crypto"
|
||||
packages = [
|
||||
"blake2b",
|
||||
|
@ -118,6 +118,7 @@
|
|||
"poly1305",
|
||||
"salsa20",
|
||||
"salsa20/salsa",
|
||||
"scrypt",
|
||||
"sha3",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
|
@ -164,6 +165,7 @@
|
|||
"golang.org/x/crypto/pbkdf2",
|
||||
"golang.org/x/crypto/poly1305",
|
||||
"golang.org/x/crypto/salsa20",
|
||||
"golang.org/x/crypto/scrypt",
|
||||
"golang.org/x/crypto/sha3",
|
||||
]
|
||||
solver-name = "gps-cdcl"
|
||||
|
|
2
SPEC.md
2
SPEC.md
|
@ -1,5 +1,7 @@
|
|||
# Jess Specification
|
||||
|
||||
This document takes a closer look at the inner workings of Jess. It does not, however, define the formats and some other aspects. First, some basics will be covered. Then, the wire protocol is given a closer look.
|
||||
|
||||
## Basics
|
||||
|
||||
The basic building blocks of jess are:
|
||||
|
|
|
@ -11,20 +11,19 @@ import (
|
|||
func TestWire(t *testing.T) {
|
||||
wireReKeyAfterMsgs = 100
|
||||
|
||||
testWireCorrespondence(t, RecommendedNetwork, testData1)
|
||||
testWireCorrespondence(t, RecommendedNetwork, testData2)
|
||||
// current suites recommendation
|
||||
testWireCorrespondence(t, getSuite(t, SuiteWire), testData1)
|
||||
testWireCorrespondence(t, getSuite(t, SuiteWire), testData2)
|
||||
|
||||
testWireCorrespondence(t, []string{"ECDH-P224", "HKDF(SHA2-256)", "CHACHA20-POLY1305"}, testData1)
|
||||
testWireCorrespondence(t, []string{"ECDH-P256", "HKDF(SHA2-256)", "CHACHA20-POLY1305"}, testData1)
|
||||
testWireCorrespondence(t, []string{"ECDH-P384", "HKDF(SHA2-256)", "CHACHA20-POLY1305"}, testData1)
|
||||
testWireCorrespondence(t, []string{"ECDH-P521", "HKDF(SHA2-256)", "CHACHA20-POLY1305"}, testData1)
|
||||
testWireCorrespondence(t, []string{"RSA-OAEP(SHA2-256)", "HKDF(SHA2-256)", "CHACHA20-POLY1305"}, testData1)
|
||||
// older suites
|
||||
// testWireCorrespondence(t, getSuite(t, SuiteWireV1), testData1)
|
||||
// testWireCorrespondence(t, getSuite(t, SuiteWireV1), testData2)
|
||||
}
|
||||
|
||||
func testWireCorrespondence(t *testing.T, toolIDs []string, testData string) {
|
||||
func testWireCorrespondence(t *testing.T, suite *Suite, testData string) {
|
||||
wtr := &wireTestRange{t: t}
|
||||
wtr.init(toolIDs, testData)
|
||||
fmt.Printf("\n\nsimulating %v\n", toolIDs)
|
||||
wtr.init(suite, testData)
|
||||
fmt.Printf("\n\nsimulating %v\n", suite.ID)
|
||||
fmt.Println("two dots are one packet send+recv:")
|
||||
|
||||
fmt.Println("\nclient ->")
|
||||
|
@ -74,7 +73,7 @@ func testWireCorrespondence(t *testing.T, toolIDs []string, testData string) {
|
|||
duration := wtr.endTime.Sub(wtr.startTime)
|
||||
t.Logf(
|
||||
"%v tested: msgsize=%d, rekey every %d msgs, %d msgs, %d bytes, +%f%% overhead, %s, %s per msg, %f Mbit/s",
|
||||
wtr.toolIDs,
|
||||
wtr.suite.ID,
|
||||
len(testData),
|
||||
wireReKeyAfterMsgs,
|
||||
wtr.msgsTransferred,
|
||||
|
@ -92,7 +91,7 @@ func testWireCorrespondence(t *testing.T, toolIDs []string, testData string) {
|
|||
|
||||
type wireTestRange struct {
|
||||
t *testing.T
|
||||
toolIDs []string
|
||||
suite *Suite
|
||||
testData string
|
||||
|
||||
client *Session
|
||||
|
@ -108,12 +107,12 @@ type wireTestRange struct {
|
|||
endTime time.Time
|
||||
}
|
||||
|
||||
func (wtr *wireTestRange) init(toolIDs []string, testData string) (detectedInvalid bool) {
|
||||
wtr.toolIDs = toolIDs
|
||||
func (wtr *wireTestRange) init(suite *Suite, testData string) (detectedInvalid bool) {
|
||||
wtr.suite = suite
|
||||
|
||||
e, err := setupEnvelopeAndTrustStore(wtr.t, wtr.toolIDs)
|
||||
e, err := setupEnvelopeAndTrustStore(wtr.t, wtr.suite)
|
||||
if err != nil {
|
||||
wtr.t.Fatalf("%v failed to setup envelope: %s", wtr.toolIDs, err)
|
||||
wtr.t.Fatalf("%s failed to setup envelope: %s", wtr.suite.ID, err)
|
||||
return false
|
||||
}
|
||||
if e == nil {
|
||||
|
@ -122,7 +121,7 @@ func (wtr *wireTestRange) init(toolIDs []string, testData string) (detectedInval
|
|||
|
||||
wtr.client, err = e.WireCorrespondence(testTrustStore)
|
||||
if err != nil {
|
||||
wtr.t.Fatalf("%v failed to init client session: %s", wtr.toolIDs, err)
|
||||
wtr.t.Fatalf("%s failed to init client session: %s", wtr.suite.ID, err)
|
||||
}
|
||||
|
||||
// setup and reset
|
||||
|
@ -142,18 +141,18 @@ func (wtr *wireTestRange) init(toolIDs []string, testData string) (detectedInval
|
|||
func (wtr *wireTestRange) clientSend() {
|
||||
letter, err := wtr.client.Close([]byte(wtr.testData))
|
||||
if err != nil {
|
||||
wtr.t.Fatalf("%v failed to close: %s", wtr.toolIDs, err)
|
||||
wtr.t.Fatalf("%s failed to close: %s", wtr.suite.ID, err)
|
||||
}
|
||||
|
||||
wireData, err := letter.ToWire()
|
||||
if err != nil {
|
||||
wtr.t.Fatalf("%v failed to serialize to wire: %s", wtr.toolIDs, err)
|
||||
wtr.t.Fatalf("%s failed to serialize to wire: %s", wtr.suite.ID, err)
|
||||
}
|
||||
|
||||
select {
|
||||
case wtr.clientToServer <- wireData:
|
||||
default:
|
||||
wtr.t.Fatalf("%v could not send to server", wtr.toolIDs)
|
||||
wtr.t.Fatalf("%s could not send to server", wtr.suite.ID)
|
||||
}
|
||||
|
||||
fmt.Print(".")
|
||||
|
@ -167,27 +166,27 @@ func (wtr *wireTestRange) serverRecv() {
|
|||
|
||||
letter, err := LetterFromWire(wireData)
|
||||
if err != nil {
|
||||
wtr.t.Fatalf("%v failed to parse initial wired letter: %s", wtr.toolIDs, err)
|
||||
wtr.t.Fatalf("%s failed to parse initial wired letter: %s", wtr.suite.ID, err)
|
||||
}
|
||||
|
||||
if wtr.server == nil {
|
||||
wtr.server, err = letter.WireCorrespondence(testTrustStore)
|
||||
if err != nil {
|
||||
wtr.t.Fatalf("%v failed to init server session: %s", wtr.toolIDs, err)
|
||||
wtr.t.Fatalf("%s failed to init server session: %s", wtr.suite.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
origData, err := wtr.server.Open(letter)
|
||||
if err != nil {
|
||||
wtr.t.Fatalf("%v failed to open: %s", wtr.toolIDs, err)
|
||||
wtr.t.Fatalf("%s failed to open: %s", wtr.suite.ID, err)
|
||||
}
|
||||
wtr.bytesTransferred += len(origData)
|
||||
|
||||
if string(origData) != wtr.testData {
|
||||
wtr.t.Fatalf("%v testdata mismatch", wtr.toolIDs)
|
||||
wtr.t.Fatalf("%s testdata mismatch", wtr.suite.ID)
|
||||
}
|
||||
default:
|
||||
wtr.t.Fatalf("%v could not recv from client", wtr.toolIDs)
|
||||
wtr.t.Fatalf("%s could not recv from client", wtr.suite.ID)
|
||||
}
|
||||
|
||||
fmt.Print(".")
|
||||
|
@ -196,18 +195,18 @@ func (wtr *wireTestRange) serverRecv() {
|
|||
func (wtr *wireTestRange) serverSend() {
|
||||
letter, err := wtr.server.Close([]byte(wtr.testData))
|
||||
if err != nil {
|
||||
wtr.t.Fatalf("%v failed to close: %s", wtr.toolIDs, err)
|
||||
wtr.t.Fatalf("%s failed to close: %s", wtr.suite.ID, err)
|
||||
}
|
||||
|
||||
wireData, err := letter.ToWire()
|
||||
if err != nil {
|
||||
wtr.t.Fatalf("%v failed to serialize to wire: %s", wtr.toolIDs, err)
|
||||
wtr.t.Fatalf("%s failed to serialize to wire: %s", wtr.suite.ID, err)
|
||||
}
|
||||
|
||||
select {
|
||||
case wtr.serverToClient <- wireData:
|
||||
default:
|
||||
wtr.t.Fatalf("%v could not send to client", wtr.toolIDs)
|
||||
wtr.t.Fatalf("%s could not send to client", wtr.suite.ID)
|
||||
}
|
||||
|
||||
fmt.Print(".")
|
||||
|
@ -221,20 +220,20 @@ func (wtr *wireTestRange) clientRecv() {
|
|||
|
||||
letter, err := LetterFromWire(wireData)
|
||||
if err != nil {
|
||||
wtr.t.Fatalf("%v failed to parse initial wired letter: %s", wtr.toolIDs, err)
|
||||
wtr.t.Fatalf("%s failed to parse initial wired letter: %s", wtr.suite.ID, err)
|
||||
}
|
||||
|
||||
origData, err := wtr.client.Open(letter)
|
||||
if err != nil {
|
||||
wtr.t.Fatalf("%v failed to open: %s", wtr.toolIDs, err)
|
||||
wtr.t.Fatalf("%s failed to open: %s", wtr.suite.ID, err)
|
||||
}
|
||||
wtr.bytesTransferred += len(origData)
|
||||
|
||||
if string(origData) != wtr.testData {
|
||||
wtr.t.Fatalf("%v testdata mismatch", wtr.toolIDs)
|
||||
wtr.t.Fatalf("%s testdata mismatch", wtr.suite.ID)
|
||||
}
|
||||
default:
|
||||
wtr.t.Fatalf("%v could not recv from server", wtr.toolIDs)
|
||||
wtr.t.Fatalf("%s could not recv from server", wtr.suite.ID)
|
||||
}
|
||||
|
||||
fmt.Print(".")
|
||||
|
|
77
core.go
77
core.go
|
@ -16,7 +16,7 @@ func (s *Session) Close(data []byte) (*Letter, error) { //nolint:gocognit
|
|||
|
||||
if s.wire == nil || s.wire.msgNo == 0 {
|
||||
letter.Version = 1
|
||||
letter.Tools = s.envelope.Tools
|
||||
letter.SuiteID = s.envelope.SuiteID
|
||||
}
|
||||
|
||||
/////////////////
|
||||
|
@ -314,6 +314,15 @@ func (s *Session) Open(letter *Letter) ([]byte, error) { //nolint:gocognit,gocyc
|
|||
|
||||
// Verify verifies signatures of the given letter.
|
||||
func (s *Session) Verify(letter *Letter) error {
|
||||
|
||||
// debugging:
|
||||
/*
|
||||
fmt.Printf("opening: %+v\n", letter)
|
||||
for _, sig := range letter.Signatures {
|
||||
fmt.Printf("sig: %+v\n", sig)
|
||||
}
|
||||
*/
|
||||
|
||||
var err error
|
||||
if s.wire == nil && letter.Version != 1 {
|
||||
return fmt.Errorf("unsupported letter version: %d", letter.Version)
|
||||
|
@ -323,44 +332,54 @@ func (s *Session) Verify(letter *Letter) error {
|
|||
// verify
|
||||
/////////
|
||||
|
||||
if len(s.signers) == 0 {
|
||||
return errors.New("letter is not signed")
|
||||
}
|
||||
// TODO: signature verification is run before tool setup. Currently, this is ok, but might change in the future. This might break additional signing algorithms that actually need setup.
|
||||
|
||||
data := letter.Data
|
||||
associatedSigningData := letter.compileAssociatedSigningData(nil)
|
||||
|
||||
// run managed signing hashers
|
||||
if s.managedSigningHashers != nil {
|
||||
err = s.feedManagedHashers(s.managedSigningHashers, data, associatedSigningData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer s.resetManagedHashers(s.managedSigningHashers)
|
||||
// build associated data
|
||||
var associatedData []byte
|
||||
if len(s.integratedCiphers) > 0 || len(s.macs) > 0 {
|
||||
associatedData = letter.compileAssociatedData()
|
||||
}
|
||||
|
||||
// run signers
|
||||
if len(s.envelope.Senders) != len(letter.Signatures) {
|
||||
return errors.New("mismatch regarding available signatures and senders")
|
||||
}
|
||||
sigIndex := 0
|
||||
// Signature
|
||||
if len(s.signers) > 0 {
|
||||
associatedSigningData := letter.compileAssociatedSigningData(associatedData)
|
||||
|
||||
for _, tool := range s.signers {
|
||||
//nolint:scopelint // function is executed immediately within loop
|
||||
err = s.envelope.LoopSenders(tool.Info().Name, func(signet *Signet) error {
|
||||
|
||||
err := tool.Verify(data, associatedSigningData, letter.Signatures[sigIndex].Value, signet)
|
||||
// run managed signing hashers
|
||||
if s.managedSigningHashers != nil {
|
||||
err = s.feedManagedHashers(s.managedSigningHashers, data, associatedSigningData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to verify signature (%s) with ID %s: %s", tool.Info().Name, letter.Signatures[sigIndex].ID, err)
|
||||
return err
|
||||
}
|
||||
|
||||
sigIndex++
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
defer s.resetManagedHashers(s.managedSigningHashers)
|
||||
}
|
||||
|
||||
// run signers
|
||||
if len(s.envelope.Senders) != len(letter.Signatures) {
|
||||
return errors.New("mismatch regarding available signatures and senders")
|
||||
}
|
||||
sigIndex := 0
|
||||
|
||||
for _, tool := range s.signers {
|
||||
//nolint:scopelint // function is executed immediately within loop
|
||||
err = s.envelope.LoopSenders(tool.Info().Name, func(signet *Signet) error {
|
||||
|
||||
err := tool.Verify(data, associatedSigningData, letter.Signatures[sigIndex].Value, signet)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to verify signature (%s) with ID %s: %s", tool.Info().Name, letter.Signatures[sigIndex].ID, err)
|
||||
}
|
||||
|
||||
sigIndex++
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return errors.New("no signatures to verify")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
173
core_test.go
173
core_test.go
|
@ -120,16 +120,8 @@ func init() {
|
|||
}
|
||||
|
||||
func TestCoreBasic(t *testing.T) {
|
||||
// toolsets to test
|
||||
toolsets := [][]string{
|
||||
RecommendedStorageKey,
|
||||
RecommendedStoragePassword,
|
||||
{"HKDF(SHA2-256)", "CHACHA20-POLY1305"},
|
||||
{"PBKDF2-SHA2-256", "HKDF(SHA2-256)", "CHACHA20-POLY1305"},
|
||||
}
|
||||
|
||||
for _, toolIDs := range toolsets {
|
||||
testStorage(t, toolIDs)
|
||||
for _, suite := range Suites() {
|
||||
testStorage(t, suite)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,10 +129,12 @@ func TestCoreBasic(t *testing.T) {
|
|||
func TestCoreAllCombinations(t *testing.T) {
|
||||
// This shall test all tools in all combinations and every tool should be tested when placed before and after every other tool.
|
||||
|
||||
// skip in short tests
|
||||
if testing.Short() {
|
||||
// skip in short tests and when not running comprehensive
|
||||
if testing.Short() || !runComprehensiveTestsActive {
|
||||
return
|
||||
}
|
||||
// run this test with
|
||||
// go test -timeout 10m github.com/safing/jess -v -count=1 -ldflags "-X github.com/safing/jess.RunComprehensiveTests=true" -run ^TestCoreAllCombinations$
|
||||
|
||||
// add all tools
|
||||
var all []string
|
||||
|
@ -193,7 +187,7 @@ func TestCoreAllCombinations(t *testing.T) {
|
|||
|
||||
// rotate to test before/after differences
|
||||
for i := 0; i < len(testTools); i++ {
|
||||
detectedInvalid := testStorage(t, testTools)
|
||||
detectedInvalid := testStorage(t, &Suite{Tools: testTools})
|
||||
combinationsTested++
|
||||
if detectedInvalid {
|
||||
combinationsDetectedInvalid++
|
||||
|
@ -207,7 +201,7 @@ func TestCoreAllCombinations(t *testing.T) {
|
|||
}
|
||||
} else {
|
||||
// test this order only
|
||||
detectedInvalid := testStorage(t, testTools)
|
||||
detectedInvalid := testStorage(t, &Suite{Tools: testTools})
|
||||
combinationsTested++
|
||||
if detectedInvalid {
|
||||
combinationsDetectedInvalid++
|
||||
|
@ -226,12 +220,12 @@ func TestCoreAllCombinations(t *testing.T) {
|
|||
t.Logf("of these, %d were successfully detected as invalid", combinationsDetectedInvalid)
|
||||
}
|
||||
|
||||
func testStorage(t *testing.T, toolIDs []string) (detectedInvalid bool) {
|
||||
// t.Logf("testing storage with %v", toolIDs)
|
||||
func testStorage(t *testing.T, suite *Suite) (detectedInvalid bool) {
|
||||
// t.Logf("testing storage with %s", suite.ID)
|
||||
|
||||
e, err := setupEnvelopeAndTrustStore(t, toolIDs)
|
||||
e, err := setupEnvelopeAndTrustStore(t, suite)
|
||||
if err != nil {
|
||||
tErrorf(t, "%v failed: %s", toolIDs, err)
|
||||
tErrorf(t, "%s failed: %s", suite.ID, err)
|
||||
return false
|
||||
}
|
||||
if e == nil {
|
||||
|
@ -242,122 +236,72 @@ func testStorage(t *testing.T, toolIDs []string) (detectedInvalid bool) {
|
|||
|
||||
s, err := e.Correspondence(testTrustStore)
|
||||
if err != nil {
|
||||
tErrorf(t, "%v failed to init session (1): %s", toolIDs, err)
|
||||
tErrorf(t, "%s failed to init session (1): %s", suite.ID, err)
|
||||
return false
|
||||
}
|
||||
|
||||
letter, err := s.Close([]byte(testData1))
|
||||
if err != nil {
|
||||
tErrorf(t, "%v failed to close (1): %s", toolIDs, err)
|
||||
tErrorf(t, "%s failed to close (1): %s", suite.ID, err)
|
||||
return false
|
||||
}
|
||||
|
||||
msg, err := letter.ToJSON()
|
||||
if err != nil {
|
||||
tErrorf(t, "%v failed to json encode (1): %s", toolIDs, err)
|
||||
tErrorf(t, "%s failed to json encode (1): %s", suite.ID, err)
|
||||
return false
|
||||
}
|
||||
|
||||
// test 2: open from session
|
||||
// test 2: open
|
||||
|
||||
letter2, err := LetterFromJSON(msg)
|
||||
if err != nil {
|
||||
tErrorf(t, "%v failed to json decode (2): %s", toolIDs, err)
|
||||
tErrorf(t, "%s failed to json decode (2): %s", suite.ID, err)
|
||||
return false
|
||||
}
|
||||
|
||||
origData2, err := s.Open(letter2)
|
||||
origData2, err := letter2.Open(e.suite.Provides, testTrustStore)
|
||||
if err != nil {
|
||||
tErrorf(t, "%v failed to open (2): %s", toolIDs, err)
|
||||
tErrorf(t, "%s failed to open (2): %s", suite.ID, err)
|
||||
return false
|
||||
}
|
||||
if string(origData2) != testData1 {
|
||||
tErrorf(t, "%v original data mismatch (2): %s", toolIDs, string(origData2))
|
||||
tErrorf(t, "%s original data mismatch (2): %s", suite.ID, string(origData2))
|
||||
return false
|
||||
}
|
||||
|
||||
if len(letter2.Signatures) > 0 {
|
||||
err = s.Verify(letter2)
|
||||
if err != nil {
|
||||
tErrorf(t, "%v failed to verify (2): %s", toolIDs, err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// extended tests
|
||||
// only run for toolsets greater than 3 if we comprehensive testing is on
|
||||
// for these tests, it is enough if every tool is tested once
|
||||
if len(toolIDs) > 3 && RunComprehensiveTests != "true" {
|
||||
return false
|
||||
}
|
||||
|
||||
// test 2.1: open again to check if reset after opening works
|
||||
// test 2.1: verify
|
||||
|
||||
letter21, err := LetterFromJSON(msg)
|
||||
if err != nil {
|
||||
tErrorf(t, "%v failed to json decode (2.1): %s", toolIDs, err)
|
||||
tErrorf(t, "%s failed to json decode (2): %s", suite.ID, err)
|
||||
return false
|
||||
}
|
||||
|
||||
origData21, err := s.Open(letter21)
|
||||
if err != nil {
|
||||
tErrorf(t, "%v failed to open (2.1): %s", toolIDs, err)
|
||||
return false
|
||||
}
|
||||
if string(origData21) != testData1 {
|
||||
tErrorf(t, "%v original data mismatch (2.1): %s", toolIDs, string(origData21))
|
||||
return false
|
||||
}
|
||||
|
||||
// test 2.2: close and open again to check if reset after closing works
|
||||
|
||||
letter22, err := s.Close([]byte(testData1))
|
||||
if err != nil {
|
||||
tErrorf(t, "%v failed to close (2.2): %s", toolIDs, err)
|
||||
return false
|
||||
}
|
||||
|
||||
origData22, err := s.Open(letter22)
|
||||
if err != nil {
|
||||
tErrorf(t, "%v failed to open (2.2): %s", toolIDs, err)
|
||||
return false
|
||||
}
|
||||
if string(origData22) != testData1 {
|
||||
tErrorf(t, "%v original data mismatch (2.2): %s", toolIDs, string(origData22))
|
||||
return false
|
||||
}
|
||||
|
||||
// test 3: open from letter
|
||||
|
||||
// FIXME - other improvements broke these tests, pausing them
|
||||
/*
|
||||
letter3, err := LetterFromJSON(msg)
|
||||
if len(letter21.Signatures) > 0 {
|
||||
err = letter21.Verify(e.suite.Provides, testTrustStore)
|
||||
if err != nil {
|
||||
tErrorf(t, "%v failed to json decode (3): %s", toolIDs, err)
|
||||
tErrorf(t, "%s failed to verify (2): %s", suite.ID, err)
|
||||
return false
|
||||
}
|
||||
|
||||
origData3, err := letter3.Open(nil, testTrustStore)
|
||||
if err != nil {
|
||||
tErrorf(t, "%v failed to open (3): %s", toolIDs, err)
|
||||
return false
|
||||
}
|
||||
if string(origData3) != testData1 {
|
||||
tErrorf(t, "%v original data mismatch (3): %s", toolIDs, string(origData3))
|
||||
return false
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
//nolint:gocognit,gocyclo
|
||||
func setupEnvelopeAndTrustStore(t *testing.T, toolIDs []string) (*Envelope, error) {
|
||||
func setupEnvelopeAndTrustStore(t *testing.T, suite *Suite) (*Envelope, error) {
|
||||
// check if suite is registered
|
||||
if suite.ID == "" {
|
||||
// register as test suite
|
||||
suite.ID = fmt.Sprintf("__unit_test_suite__" + strings.Join(suite.Tools, "__"))
|
||||
registerSuite(suite)
|
||||
}
|
||||
|
||||
// create envelope baseline
|
||||
e := &Envelope{
|
||||
Tools: toolIDs,
|
||||
requirements: newEmptyRequirements(),
|
||||
SuiteID: suite.ID,
|
||||
suite: suite,
|
||||
}
|
||||
|
||||
// check vars
|
||||
|
@ -366,7 +310,7 @@ func setupEnvelopeAndTrustStore(t *testing.T, toolIDs []string) (*Envelope, erro
|
|||
asyncKeyEstablishmentPresent := false
|
||||
|
||||
// process tools and setup envelope
|
||||
for _, toolID := range e.Tools {
|
||||
for _, toolID := range e.suite.Tools {
|
||||
|
||||
// remove hasher argument for now
|
||||
if strings.Contains(toolID, "(") {
|
||||
|
@ -389,7 +333,7 @@ func setupEnvelopeAndTrustStore(t *testing.T, toolIDs []string) (*Envelope, erro
|
|||
e.Secrets = append(e.Secrets, pw)
|
||||
|
||||
// add a second one!
|
||||
if len(toolIDs) <= 2 {
|
||||
if len(suite.Tools) <= 2 {
|
||||
pw1, err := getOrMakeSignet(t, nil, false, "test-pw-2")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -422,66 +366,69 @@ func setupEnvelopeAndTrustStore(t *testing.T, toolIDs []string) (*Envelope, erro
|
|||
passDerPresent = true
|
||||
// add passderivation requirements later, as it is a bit special
|
||||
case tools.PurposeKeyExchange:
|
||||
e.requirements.Add(RecipientAuthentication)
|
||||
e.suite.Provides.Add(RecipientAuthentication)
|
||||
case tools.PurposeKeyEncapsulation:
|
||||
e.requirements.Add(RecipientAuthentication)
|
||||
e.suite.Provides.Add(RecipientAuthentication)
|
||||
case tools.PurposeSigning:
|
||||
e.requirements.Add(SenderAuthentication)
|
||||
e.suite.Provides.Add(SenderAuthentication)
|
||||
case tools.PurposeIntegratedCipher:
|
||||
e.requirements.Add(Confidentiality)
|
||||
e.requirements.Add(Integrity)
|
||||
e.suite.Provides.Add(Confidentiality)
|
||||
e.suite.Provides.Add(Integrity)
|
||||
case tools.PurposeCipher:
|
||||
e.requirements.Add(Confidentiality)
|
||||
e.suite.Provides.Add(Confidentiality)
|
||||
case tools.PurposeMAC:
|
||||
e.requirements.Add(Integrity)
|
||||
e.suite.Provides.Add(Integrity)
|
||||
}
|
||||
}
|
||||
|
||||
// if invalid: test if toolset is recognized as invalid
|
||||
|
||||
// no requirements -> only "meta" tools (kdf, pass derivation)
|
||||
if e.requirements.Empty() {
|
||||
if e.suite.Provides.Empty() {
|
||||
return nil, testInvalidToolset(e, "there are only meta tools in toolset")
|
||||
}
|
||||
|
||||
// recipient auth, but no confidentiality? nope.
|
||||
if e.requirements.Has(RecipientAuthentication) &&
|
||||
!e.requirements.Has(Confidentiality) {
|
||||
if e.suite.Provides.Has(RecipientAuthentication) &&
|
||||
!e.suite.Provides.Has(Confidentiality) {
|
||||
return nil, testInvalidToolset(e, "authenticating the recipient without using confidentiality does not make sense")
|
||||
}
|
||||
|
||||
// check if we are missing key derivation - this is only ok if we are merely signing
|
||||
if !keyDerPresent &&
|
||||
(len(e.requirements.all) != 1 ||
|
||||
!e.requirements.Has(SenderAuthentication)) {
|
||||
(len(e.suite.Provides.all) != 1 ||
|
||||
!e.suite.Provides.Has(SenderAuthentication)) {
|
||||
return nil, testInvalidToolset(e, "omitting a key derivation tool is only allowed when merely signing")
|
||||
}
|
||||
|
||||
// check if we have key derivation, but not need it
|
||||
if keyDerPresent &&
|
||||
(!e.requirements.Has(Confidentiality) &&
|
||||
!e.requirements.Has(Integrity)) {
|
||||
(!e.suite.Provides.Has(Confidentiality) &&
|
||||
!e.suite.Provides.Has(Integrity)) {
|
||||
return nil, testInvalidToolset(e, "a key derivation tool was specified, albeit none is needed")
|
||||
}
|
||||
|
||||
// add passderivation here, as to easier handle the other cases
|
||||
if passDerPresent {
|
||||
e.requirements.Add(SenderAuthentication)
|
||||
e.requirements.Add(RecipientAuthentication)
|
||||
e.suite.Provides.Add(SenderAuthentication)
|
||||
e.suite.Provides.Add(RecipientAuthentication)
|
||||
|
||||
// need Confidentiality for this to make sense
|
||||
if !e.requirements.Has(Confidentiality) {
|
||||
if !e.suite.Provides.Has(Confidentiality) {
|
||||
return nil, testInvalidToolset(e, "using a password without confidentiality does not make sense")
|
||||
}
|
||||
}
|
||||
|
||||
if e.requirements.Has(Confidentiality) &&
|
||||
!e.requirements.Has(Integrity) {
|
||||
if e.suite.Provides.Has(Confidentiality) &&
|
||||
!e.suite.Provides.Has(Integrity) {
|
||||
return nil, testInvalidToolset(e, "having confidentiality without integrity does not make sense")
|
||||
}
|
||||
|
||||
// add static key if needed
|
||||
if !asyncKeyEstablishmentPresent && !passDerPresent && keyDerPresent {
|
||||
e.suite.Provides.Add(SenderAuthentication)
|
||||
e.suite.Provides.Add(RecipientAuthentication)
|
||||
|
||||
key, err := getOrMakeSignet(t, nil, false, "test-key-1")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -489,7 +436,7 @@ func setupEnvelopeAndTrustStore(t *testing.T, toolIDs []string) (*Envelope, erro
|
|||
e.Secrets = append(e.Secrets, key)
|
||||
|
||||
// add a second one!
|
||||
if len(toolIDs) <= 2 {
|
||||
if len(suite.Tools) <= 2 {
|
||||
key2, err := getOrMakeSignet(t, nil, false, "test-key-2")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -3,10 +3,10 @@ package jess
|
|||
var (
|
||||
// must be var in order decrease for testing for better speed
|
||||
|
||||
defaultSecurityLevel = 256
|
||||
defaultSecurityLevel = 128
|
||||
minimumSecurityLevel = 0
|
||||
|
||||
defaultSymmetricKeySize = 32
|
||||
defaultSymmetricKeySize = 16
|
||||
minimumSymmetricKeySize = 0
|
||||
)
|
||||
|
||||
|
|
112
envelope.go
112
envelope.go
|
@ -9,7 +9,8 @@ import (
|
|||
type Envelope struct { //nolint:maligned // TODO
|
||||
Version uint8
|
||||
Name string
|
||||
Tools []string
|
||||
SuiteID string
|
||||
suite *Suite
|
||||
|
||||
// Secret keys and passwords
|
||||
Secrets []*Signet
|
||||
|
@ -26,11 +27,10 @@ type Envelope struct { //nolint:maligned // TODO
|
|||
|
||||
// For users, envelopes describe how a letter is closed.
|
||||
// Therefore Secrets and Senders always refer to private keys and Recipients to public keys in that context.
|
||||
// These distictions are important in order for the user to easily and confidently distinguish what is going to happen. Think of it as "human security".
|
||||
// These distinctions are important in order for the user to easily and confidently distinguish what is going to happen. Think of it as "human security".
|
||||
|
||||
MinimumSecurityLevel int
|
||||
No string
|
||||
requirements *Requirements
|
||||
// SecurityLevel is the security level of the envelope when it was created
|
||||
SecurityLevel int
|
||||
|
||||
// flag to signify if envelope is used for opening
|
||||
opening bool
|
||||
|
@ -39,10 +39,8 @@ type Envelope struct { //nolint:maligned // TODO
|
|||
// NewUnconfiguredEnvelope returns an unconfigured, but slightly initialized envelope.
|
||||
func NewUnconfiguredEnvelope() *Envelope {
|
||||
e := &Envelope{
|
||||
Version: 1,
|
||||
requirements: NewRequirements(),
|
||||
Version: 1,
|
||||
}
|
||||
e.SerializeRequirements()
|
||||
return e
|
||||
}
|
||||
|
||||
|
@ -52,14 +50,17 @@ func (e *Envelope) Correspondence(trustStore TrustStore) (*Session, error) {
|
|||
}
|
||||
|
||||
func (e *Envelope) initCorrespondence(trustStore TrustStore, verifying bool) (*Session, error) {
|
||||
err := e.LoadRequirements()
|
||||
err := e.LoadSuite()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//nolint:gocritic // TODO: see below
|
||||
if verifying {
|
||||
// prep sender signets only
|
||||
err = e.prepSignets(e.Senders, e.opening, trustStore)
|
||||
// TODO: prep sender signets only
|
||||
// TODO: for this to work, newSession needs to only check verification related things
|
||||
// err = e.prepSignets(e.Senders, e.opening, trustStore)
|
||||
err = e.PrepareSignets(trustStore)
|
||||
} else {
|
||||
// prep all signets
|
||||
err = e.PrepareSignets(trustStore)
|
||||
|
@ -92,82 +93,27 @@ func (e *Envelope) Check(trustStore TrustStore) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// NoRecipientAuth removes the requirement to authenticate the recipient.
|
||||
func (e *Envelope) NoRecipientAuth() *Envelope {
|
||||
if e.requirements == nil {
|
||||
e.requirements = NewRequirements()
|
||||
}
|
||||
|
||||
e.requirements.Remove(RecipientAuthentication)
|
||||
return e
|
||||
// Suite returns the loaded suite.
|
||||
func (e *Envelope) Suite() *Suite {
|
||||
return e.suite
|
||||
}
|
||||
|
||||
// NoSenderAuth removes the requirement to authenticate the sender.
|
||||
func (e *Envelope) NoSenderAuth() *Envelope {
|
||||
if e.requirements == nil {
|
||||
e.requirements = NewRequirements()
|
||||
}
|
||||
|
||||
e.requirements.Remove(SenderAuthentication)
|
||||
e.SerializeRequirements()
|
||||
return e
|
||||
}
|
||||
|
||||
// NoConfidentiality removes the requirement to provide confidentiality.
|
||||
func (e *Envelope) NoConfidentiality() *Envelope {
|
||||
if e.requirements == nil {
|
||||
e.requirements = NewRequirements()
|
||||
}
|
||||
|
||||
e.requirements.Remove(Confidentiality)
|
||||
e.SerializeRequirements()
|
||||
return e
|
||||
}
|
||||
|
||||
// NoIntegrity removes the requirement to provide integrity.
|
||||
func (e *Envelope) NoIntegrity() *Envelope {
|
||||
if e.requirements == nil {
|
||||
e.requirements = NewRequirements()
|
||||
}
|
||||
|
||||
e.requirements.Remove(Integrity)
|
||||
e.SerializeRequirements()
|
||||
return e
|
||||
}
|
||||
|
||||
// Unsafe removes all requirements.
|
||||
func (e *Envelope) Unsafe() *Envelope {
|
||||
e.requirements = &Requirements{}
|
||||
e.SerializeRequirements()
|
||||
return e
|
||||
}
|
||||
|
||||
// Requirements returns the required requirements.
|
||||
func (e *Envelope) Requirements() *Requirements {
|
||||
return e.requirements
|
||||
}
|
||||
|
||||
// SetRequirements sets new requirements.
|
||||
func (e *Envelope) SetRequirements(requirements *Requirements) {
|
||||
e.requirements = requirements
|
||||
}
|
||||
|
||||
// LoadRequirements loads the required requirements from the struct's exposed negated "No" specification.
|
||||
func (e *Envelope) LoadRequirements() error {
|
||||
if e.requirements == nil {
|
||||
attrs, err := ParseRequirementsFromNoSpec(e.No)
|
||||
if err != nil {
|
||||
return nil
|
||||
// LoadSuite loads the suite specified in the envelope.
|
||||
func (e *Envelope) LoadSuite() error {
|
||||
if e.suite == nil {
|
||||
suite, ok := GetSuite(e.SuiteID)
|
||||
if !ok {
|
||||
return fmt.Errorf("suite %s does not exist", e.SuiteID)
|
||||
}
|
||||
|
||||
e.requirements = attrs
|
||||
e.suite = suite
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SerializeRequirements saves the requirement requirements in the struct's exposed negated "No" specification.
|
||||
func (e *Envelope) SerializeRequirements() {
|
||||
e.No = e.requirements.SerializeToNoSpec()
|
||||
// ReloadSuite forces reloading the suite specified in the envelope.
|
||||
func (e *Envelope) ReloadSuite() error {
|
||||
e.suite = nil
|
||||
return e.LoadSuite()
|
||||
}
|
||||
|
||||
// LoopSecrets loops over all secrets of the given scheme.
|
||||
|
@ -233,12 +179,16 @@ func (e *Envelope) prepSignets(signets []*Signet, recipients bool, storage Trust
|
|||
// load from storage
|
||||
if len(signet.Key) == 0 {
|
||||
if signet.Scheme == SignetSchemePassword {
|
||||
err := fillPassword(signet, !recipients, storage, e.MinimumSecurityLevel)
|
||||
err := fillPassword(signet, !recipients, storage, e.suite.SecurityLevel)
|
||||
if err != nil {
|
||||
return fmt.Errorf(`failed to get password for "%s": %s`, signet.ID, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// keys are _always_ signets
|
||||
if signet.Scheme == SignetSchemeKey {
|
||||
recipients = false
|
||||
}
|
||||
|
||||
// signet is referrer
|
||||
if len(signet.ID) == 0 {
|
||||
|
|
|
@ -15,9 +15,7 @@ import (
|
|||
- 2: Sending Keys
|
||||
- 4: Apply Keys
|
||||
- Version: varint (if Setup Msg)
|
||||
- Tools: (if Setup Msg)
|
||||
- Amount: varint
|
||||
- Names: byte blocks
|
||||
- SuiteID: byte block (if Setup Msg)
|
||||
- Keys:
|
||||
- Amount: varint
|
||||
- IDs/Values: byte blocks
|
||||
|
@ -58,13 +56,8 @@ func (letter *Letter) ToWire() (*container.Container, error) {
|
|||
// Version: varint (if Setup Msg)
|
||||
c.AppendNumber(uint64(letter.Version))
|
||||
|
||||
// Tools: (if Setup Msg)
|
||||
// - Amount: varint
|
||||
// - Names: byte blocks
|
||||
c.AppendInt(len(letter.Tools))
|
||||
for _, toolName := range letter.Tools {
|
||||
c.AppendAsBlock([]byte(toolName))
|
||||
}
|
||||
// SuiteID: byte block (if Setup Msg)
|
||||
c.AppendAsBlock([]byte(letter.SuiteID))
|
||||
}
|
||||
|
||||
if len(letter.Keys) > 0 {
|
||||
|
@ -136,21 +129,12 @@ func LetterFromWire(c *container.Container) (*Letter, error) {
|
|||
}
|
||||
letter.Version = n
|
||||
|
||||
// Tools: (if Setup Msg)
|
||||
// - Amount: varint
|
||||
// - Names: byte blocks
|
||||
n, err = c.GetNextN8()
|
||||
// SuiteID: byte block (if Setup Msg)
|
||||
suiteID, err := c.GetNextBlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
letter.Tools = make([]string, n)
|
||||
for i := 0; i < len(letter.Tools); i++ {
|
||||
toolName, err := c.GetNextBlock()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
letter.Tools[i] = string(toolName)
|
||||
}
|
||||
letter.SuiteID = string(suiteID)
|
||||
}
|
||||
|
||||
if sendingKeys {
|
||||
|
|
55
letter.go
55
letter.go
|
@ -17,8 +17,8 @@ import (
|
|||
|
||||
// Letter is the data format for encrypted data at rest or in transit.
|
||||
type Letter struct { //nolint:maligned // TODO
|
||||
Version uint8 // signed, MAC'd (may not exist when wired)
|
||||
Tools []string // signed, MAC'd (may not exist when wired)
|
||||
Version uint8 // signed, MAC'd (may not exist when wired)
|
||||
SuiteID string // signed, MAC'd (may not exist when wired)
|
||||
|
||||
Nonce []byte // signed, MAC'd
|
||||
Keys []*Seal `json:",omitempty"` // signed, MAC'd
|
||||
|
@ -45,18 +45,34 @@ type Seal struct {
|
|||
}
|
||||
|
||||
// Envelope returns an envelope built from the letter, configured for opening it.
|
||||
func (letter *Letter) Envelope() (*Envelope, error) {
|
||||
func (letter *Letter) Envelope(requirements *Requirements) (*Envelope, error) {
|
||||
// basic checks
|
||||
if letter.Version == 0 {
|
||||
return nil, fmt.Errorf("letter does not specify version")
|
||||
}
|
||||
if len(letter.Tools) == 0 {
|
||||
return nil, fmt.Errorf("letter does not specify any tools")
|
||||
if len(letter.SuiteID) == 0 {
|
||||
return nil, fmt.Errorf("letter does not specify a suite")
|
||||
}
|
||||
|
||||
// create envelope
|
||||
e := &Envelope{
|
||||
Version: letter.Version,
|
||||
Tools: letter.Tools,
|
||||
requirements: newEmptyRequirements(),
|
||||
Version: letter.Version,
|
||||
SuiteID: letter.SuiteID,
|
||||
}
|
||||
|
||||
// get and check suite
|
||||
err := e.LoadSuite()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// default to full requirements
|
||||
if requirements == nil {
|
||||
requirements = NewRequirements()
|
||||
}
|
||||
// check suite against requirements
|
||||
err = e.suite.Provides.CheckComplianceTo(requirements)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, seal := range letter.Keys {
|
||||
|
@ -91,13 +107,10 @@ func (letter *Letter) Envelope() (*Envelope, error) {
|
|||
|
||||
// Open creates a session and opens the letter in one step.
|
||||
func (letter *Letter) Open(requirements *Requirements, trustStore TrustStore) ([]byte, error) {
|
||||
e, err := letter.Envelope()
|
||||
e, err := letter.Envelope(requirements)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if requirements != nil {
|
||||
e.requirements = requirements
|
||||
}
|
||||
|
||||
s, err := e.Correspondence(trustStore)
|
||||
if err != nil {
|
||||
|
@ -109,13 +122,10 @@ func (letter *Letter) Open(requirements *Requirements, trustStore TrustStore) ([
|
|||
|
||||
// Verify creates a session and verifies the letter in one step.
|
||||
func (letter *Letter) Verify(requirements *Requirements, trustStore TrustStore) error {
|
||||
e, err := letter.Envelope()
|
||||
e, err := letter.Envelope(requirements)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if requirements != nil {
|
||||
e.requirements = requirements
|
||||
}
|
||||
|
||||
s, err := e.initCorrespondence(trustStore, true)
|
||||
if err != nil {
|
||||
|
@ -127,7 +137,7 @@ func (letter *Letter) Verify(requirements *Requirements, trustStore TrustStore)
|
|||
|
||||
// WireCorrespondence creates a wire session (communication over a network connection) from a letter.
|
||||
func (letter *Letter) WireCorrespondence(trustStore TrustStore) (*Session, error) {
|
||||
e, err := letter.Envelope()
|
||||
e, err := letter.Envelope(NewRequirements().Remove(SenderAuthentication))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -179,7 +189,7 @@ const (
|
|||
// These IDs MUST NOT CHANGE
|
||||
|
||||
fieldIDLetterVersion uint64 = 1 // signed, MAC'd (may not exist when wired)
|
||||
fieldIDLetterTools uint64 = 2 // signed, MAC'd (may not exist when wired)
|
||||
fieldIDLetterSuiteID uint64 = 2 // signed, MAC'd (may not exist when wired)
|
||||
fieldIDLetterNonce uint64 = 3 // signed, MAC'd
|
||||
fieldIDLetterKeys uint64 = 4 // signed, MAC'd
|
||||
fieldIDLetterMac uint64 = 5 // signed
|
||||
|
@ -199,12 +209,9 @@ func (letter *Letter) compileAssociatedData() []byte {
|
|||
c.AppendNumber(fieldIDLetterVersion) // append field ID
|
||||
c.AppendNumber(uint64(letter.Version))
|
||||
}
|
||||
if len(letter.Tools) > 0 {
|
||||
c.AppendNumber(fieldIDLetterTools) // append field ID
|
||||
c.AppendInt(len(letter.Tools)) // append number of tools
|
||||
for _, toolID := range letter.Tools {
|
||||
c.AppendAsBlock([]byte(toolID)) // append field content with length
|
||||
}
|
||||
if len(letter.SuiteID) > 0 {
|
||||
c.AppendNumber(fieldIDLetterSuiteID) // append field ID
|
||||
c.AppendAsBlock([]byte(letter.SuiteID)) // append field content with length
|
||||
}
|
||||
if len(letter.Nonce) > 0 {
|
||||
c.AppendNumber(fieldIDLetterNonce) // append field ID
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
func TestSerialization(t *testing.T) {
|
||||
subject := &Letter{
|
||||
Version: 1,
|
||||
Tools: RecommendedNetwork,
|
||||
SuiteID: SuiteComplete,
|
||||
Keys: []*Seal{
|
||||
{ID: "a"},
|
||||
{ID: "b"},
|
||||
|
@ -25,7 +25,7 @@ func TestSerialization(t *testing.T) {
|
|||
testSerialize(t, subject, true)
|
||||
|
||||
subject.Version = 0
|
||||
subject.Tools = nil
|
||||
subject.SuiteID = ""
|
||||
testSerialize(t, subject, true)
|
||||
|
||||
subject.ApplyKeys = false
|
||||
|
|
|
@ -2,6 +2,24 @@ package jess
|
|||
|
||||
import "testing"
|
||||
|
||||
func init() {
|
||||
SetPasswordCallbacks(
|
||||
func(signet *Signet, minSecurityLevel int) error {
|
||||
return getTestPassword(signet)
|
||||
},
|
||||
getTestPassword,
|
||||
)
|
||||
}
|
||||
|
||||
func getTestPassword(signet *Signet) error {
|
||||
pwSignet, err := testTrustStore.GetSignet(signet.ID, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
signet.Key = pwSignet.Key
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestCalculatePasswordSecurityLevel(t *testing.T) {
|
||||
// basic weak
|
||||
testPWSL(t, "asdf", -1)
|
||||
|
@ -13,62 +31,62 @@ func TestCalculatePasswordSecurityLevel(t *testing.T) {
|
|||
testPWSL(t, "aaaaaaaaAAAAAAAA00000000********", -1)
|
||||
|
||||
// chars only
|
||||
testPWSL(t, "AVWHBwmF", 58)
|
||||
testPWSL(t, "AVWHBwmFGt", 70)
|
||||
testPWSL(t, "AVWHBwmFGtLM", 81)
|
||||
testPWSL(t, "AVWHBwmFGtLMGh", 93)
|
||||
testPWSL(t, "AVWHBwmFGtLMGhYf", 104)
|
||||
testPWSL(t, "AVWHBwmFGtLMGhYfPkcyawfmZXRTQdxs", 195)
|
||||
testPWSL(t, "AVWHBwmF", 64)
|
||||
testPWSL(t, "AVWHBwmFGt", 76)
|
||||
testPWSL(t, "AVWHBwmFGtLM", 87)
|
||||
testPWSL(t, "AVWHBwmFGtLMGh", 98)
|
||||
testPWSL(t, "AVWHBwmFGtLMGhYf", 110)
|
||||
testPWSL(t, "AVWHBwmFGtLMGhYfPkcyawfmZXRTQdxs", 201)
|
||||
|
||||
// with number
|
||||
testPWSL(t, "AVWHBwm1", 60)
|
||||
testPWSL(t, "AVWHBwmFG1", 72)
|
||||
testPWSL(t, "AVWHBwmFGtL1", 84)
|
||||
testPWSL(t, "AVWHBwmFGtLMG1", 96)
|
||||
testPWSL(t, "AVWHBwmFGtLMGhY1", 108)
|
||||
testPWSL(t, "AVWHBwmFGtLMGhYfPkcyawfmZXRTQdx1", 203)
|
||||
testPWSL(t, "AVWHBwm1", 66)
|
||||
testPWSL(t, "AVWHBwmFG1", 78)
|
||||
testPWSL(t, "AVWHBwmFGtL1", 90)
|
||||
testPWSL(t, "AVWHBwmFGtLMG1", 102)
|
||||
testPWSL(t, "AVWHBwmFGtLMGhY1", 114)
|
||||
testPWSL(t, "AVWHBwmFGtLMGhYfPkcyawfmZXRTQdx1", 209)
|
||||
|
||||
// with number and special
|
||||
testPWSL(t, "AVWHBw1_", 61)
|
||||
testPWSL(t, "AVWHBwmF1_", 73)
|
||||
testPWSL(t, "AVWHBwmFGt1_", 86)
|
||||
testPWSL(t, "AVWHBwmFGtLM1_", 98)
|
||||
testPWSL(t, "AVWHBwmFGtLMGh1_", 110)
|
||||
testPWSL(t, "AVWHBwmFGtLMGhYfPkcyawfmZXRTQd1_", 207)
|
||||
testPWSL(t, "AVWHBw1_", 67)
|
||||
testPWSL(t, "AVWHBwmF1_", 79)
|
||||
testPWSL(t, "AVWHBwmFGt1_", 91)
|
||||
testPWSL(t, "AVWHBwmFGtLM1_", 103)
|
||||
testPWSL(t, "AVWHBwmFGtLMGh1_", 116)
|
||||
testPWSL(t, "AVWHBwmFGtLMGhYfPkcyawfmZXRTQd1_", 213)
|
||||
|
||||
// with number and more special
|
||||
testPWSL(t, "AVWHBw1*", 65)
|
||||
testPWSL(t, "AVWHBwmF1*", 78)
|
||||
testPWSL(t, "AVWHBwmFGt1*", 91)
|
||||
testPWSL(t, "AVWHBwmFGtLM1*", 104)
|
||||
testPWSL(t, "AVWHBwmFGtLMGh1*", 117)
|
||||
testPWSL(t, "AVWHBwmFGtLMGhYfPkcyawfmZXRTQd1*", 221)
|
||||
testPWSL(t, "AVWHBw1*", 70)
|
||||
testPWSL(t, "AVWHBwmF1*", 83)
|
||||
testPWSL(t, "AVWHBwmFGt1*", 96)
|
||||
testPWSL(t, "AVWHBwmFGtLM1*", 109)
|
||||
testPWSL(t, "AVWHBwmFGtLMGh1*", 122)
|
||||
testPWSL(t, "AVWHBwmFGtLMGhYfPkcyawfmZXRTQd1*", 226)
|
||||
|
||||
// created, strong
|
||||
|
||||
// "Schneier scheme"
|
||||
// source: https://www.schneier.com/blog/archives/2014/03/choosing_secure_1.html
|
||||
testPWSL(t, "WIw7,mstmsritt...", 116)
|
||||
testPWSL(t, "Wow...doestcst", 94)
|
||||
testPWSL(t, "Ltime@go-inag~faaa!", 135)
|
||||
testPWSL(t, "uTVM,TPw55:utvm,tpwstillsecure", 210)
|
||||
testPWSL(t, "WIw7,mstmsritt...", 122)
|
||||
testPWSL(t, "Wow...doestcst", 100)
|
||||
testPWSL(t, "Ltime@go-inag~faaa!", 140)
|
||||
testPWSL(t, "uTVM,TPw55:utvm,tpwstillsecure", 216)
|
||||
|
||||
// generated, strong
|
||||
testPWSL(t, "YebGPQuuoxQwyeJMvEWACTLexUUxVBFdHYqqUybBUNfBttCvWQxDdDCdYfgMPCQp", 378)
|
||||
testPWSL(t, "dpPyXmXpbECn6LWuQDJaitTTJguGfRTqNUxWfoHnBKDHvRhjR2WiQ7iDcuRJNnEd", 394)
|
||||
testPWSL(t, "WgEKCp8c8{bPrG{Zo(Ms97pKt3EsR9ycz4R=kMjPp^Uafqxsd2ZTFtkfvnoueKJz", 428)
|
||||
testPWSL(t, "galena-fighter-festival", 127)
|
||||
testPWSL(t, "impotent-drug-dropout-damage", 152)
|
||||
testPWSL(t, "artless-newswire-rill-belgium-marplot", 196)
|
||||
testPWSL(t, "forbade-momenta-spook-sure-devilish-wobbly", 221)
|
||||
testPWSL(t, "YebGPQuuoxQwyeJMvEWACTLexUUxVBFdHYqqUybBUNfBttCvWQxDdDCdYfgMPCQp", 383)
|
||||
testPWSL(t, "dpPyXmXpbECn6LWuQDJaitTTJguGfRTqNUxWfoHnBKDHvRhjR2WiQ7iDcuRJNnEd", 400)
|
||||
testPWSL(t, "WgEKCp8c8{bPrG{Zo(Ms97pKt3EsR9ycz4R=kMjPp^Uafqxsd2ZTFtkfvnoueKJz", 434)
|
||||
testPWSL(t, "galena-fighter-festival", 132)
|
||||
testPWSL(t, "impotent-drug-dropout-damage", 157)
|
||||
testPWSL(t, "artless-newswire-rill-belgium-marplot", 202)
|
||||
testPWSL(t, "forbade-momenta-spook-sure-devilish-wobbly", 227)
|
||||
}
|
||||
|
||||
func testPWSL(t *testing.T, password string, expectedSecurityLevel int) {
|
||||
securityLevel := CalculatePasswordSecurityLevel(password, 20000)
|
||||
securityLevel := CalculatePasswordSecurityLevel(password, 1<<20)
|
||||
|
||||
if securityLevel < expectedSecurityLevel {
|
||||
t.Errorf("password %s (%di): %d - expected at least %d", password, 20000, securityLevel, expectedSecurityLevel)
|
||||
t.Errorf("password %s (%di): %d - expected at least %d", password, 1<<20, securityLevel, expectedSecurityLevel)
|
||||
} else {
|
||||
t.Logf("password %s (%di): %d", password, 20000, securityLevel)
|
||||
t.Logf("password %s (%di): %d", password, 1<<20, securityLevel)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ func (requirements *Requirements) CheckComplianceTo(requirement *Requirements) e
|
|||
}
|
||||
}
|
||||
if missing != nil {
|
||||
return fmt.Errorf("missing tools with security requirements: %s", missing.String())
|
||||
return fmt.Errorf("missing security requirements: %s", missing.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
124
session.go
124
session.go
|
@ -57,15 +57,34 @@ func (sh *managedHasher) Sum() ([]byte, error) {
|
|||
}
|
||||
|
||||
func newSession(e *Envelope) (*Session, error) { //nolint:gocognit,gocyclo
|
||||
if len(e.Tools) == 0 {
|
||||
return nil, errors.New("envelope is missing tools")
|
||||
if e.suite == nil {
|
||||
return nil, errors.New("suite not loaded")
|
||||
}
|
||||
|
||||
// create session
|
||||
s := &Session{
|
||||
envelope: e,
|
||||
toolRequirements: newEmptyRequirements(),
|
||||
}
|
||||
|
||||
// check envelope security level
|
||||
if e.SecurityLevel > 0 {
|
||||
err := s.checkSecurityLevel(e.SecurityLevel, func() string {
|
||||
return fmt.Sprintf(`envelope "%s"`, e.Name)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// check suite security level
|
||||
err := s.checkSecurityLevel(e.suite.SecurityLevel, func() string {
|
||||
return fmt.Sprintf(`suite "%s"`, e.suite.ID)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// prepare variables
|
||||
var (
|
||||
keySourceAvailable bool = false
|
||||
totalSignetsSeen int
|
||||
|
@ -74,13 +93,13 @@ func newSession(e *Envelope) (*Session, error) { //nolint:gocognit,gocyclo
|
|||
)
|
||||
|
||||
// tool init loop: start
|
||||
for i, toolID := range s.envelope.Tools {
|
||||
for i, toolID := range s.envelope.suite.Tools {
|
||||
|
||||
///////////////////////////////////////
|
||||
// tool init loop: check for duplicates
|
||||
///////////////////////////////////////
|
||||
|
||||
for j, dupeToolID := range s.envelope.Tools {
|
||||
for j, dupeToolID := range s.envelope.suite.Tools {
|
||||
if i != j && toolID == dupeToolID {
|
||||
return nil, fmt.Errorf("cannot use tool %s twice, each tool may be only specified once", toolID)
|
||||
}
|
||||
|
@ -311,7 +330,10 @@ func newSession(e *Envelope) (*Session, error) { //nolint:gocognit,gocyclo
|
|||
}
|
||||
|
||||
// key signets
|
||||
err := e.LoopSecrets(SignetSchemeKey, func(signet *Signet) error {
|
||||
err = e.LoopSecrets(SignetSchemeKey, func(signet *Signet) error {
|
||||
s.toolRequirements.Add(SenderAuthentication)
|
||||
s.toolRequirements.Add(RecipientAuthentication)
|
||||
|
||||
totalSignetsSeen++
|
||||
keySourceAvailable = true
|
||||
return s.calcAndCheckSecurityLevel(nil, signet)
|
||||
|
@ -350,7 +372,7 @@ func newSession(e *Envelope) (*Session, error) { //nolint:gocognit,gocyclo
|
|||
if s.toolRequirements.Empty() {
|
||||
return nil, errors.New("envelope excludes all security requirements, no meaningful operation possible")
|
||||
}
|
||||
err = s.toolRequirements.CheckComplianceTo(s.envelope.requirements)
|
||||
err = s.toolRequirements.CheckComplianceTo(s.envelope.suite.Provides)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -368,7 +390,7 @@ func newSession(e *Envelope) (*Session, error) { //nolint:gocognit,gocyclo
|
|||
}
|
||||
|
||||
// check if we are missing a kdf, but need one
|
||||
if s.kdf == nil && len(s.signers) != len(s.envelope.Tools) {
|
||||
if s.kdf == nil && len(s.signers) != len(s.envelope.suite.Tools) {
|
||||
return nil, errors.New("missing a key derivation tool")
|
||||
}
|
||||
|
||||
|
@ -393,6 +415,15 @@ func newSession(e *Envelope) (*Session, error) { //nolint:gocognit,gocyclo
|
|||
return nil, fmt.Errorf("detected signet or recipient in envelope that is not used by any tool")
|
||||
}
|
||||
|
||||
// check session security level
|
||||
// while this should never result in an error (because every part was already checked separately) this is used as a precaution to catch errors in future code changes
|
||||
err = s.checkSecurityLevel(s.SecurityLevel, func() string {
|
||||
return "current session"
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
|
@ -415,6 +446,9 @@ func (s *Session) calcAndCheckSecurityLevel(logic tools.ToolLogic, signet *Signe
|
|||
// existence check is done when opening/closing
|
||||
if len(signet.Key) > 0 {
|
||||
switch logic.Info().Name {
|
||||
case "SCRYPT-20":
|
||||
// TODO: integrate this into the tool interface
|
||||
calculatedSecurityLevel = CalculatePasswordSecurityLevel(string(signet.Key), 1<<20)
|
||||
case "PBKDF2-SHA2-256":
|
||||
// TODO: integrate this into the tool interface
|
||||
calculatedSecurityLevel = CalculatePasswordSecurityLevel(string(signet.Key), 20000)
|
||||
|
@ -451,38 +485,18 @@ func (s *Session) calcAndCheckSecurityLevel(logic tools.ToolLogic, signet *Signe
|
|||
}
|
||||
|
||||
if signet != nil {
|
||||
|
||||
// signet based security level checks
|
||||
switch {
|
||||
case minimumSecurityLevel > 0:
|
||||
// check against minimumSecurityLevel
|
||||
// minimumSecurityLevel overrides other checks
|
||||
if calculatedSecurityLevel < minimumSecurityLevel {
|
||||
return fmt.Errorf(`supplied %s signet "%s" with a security level of %d is weaker than the desired security level of %d`, signet.Scheme, signet.ID, calculatedSecurityLevel, minimumSecurityLevel)
|
||||
}
|
||||
case s.envelope.MinimumSecurityLevel > 0 && calculatedSecurityLevel < s.envelope.MinimumSecurityLevel:
|
||||
// check against envelope's minimum security level
|
||||
return fmt.Errorf(`supplied %s signet "%s" with a security level of %d is weaker than the envelope's minimum security level of %d`, signet.Scheme, signet.ID, calculatedSecurityLevel, s.envelope.MinimumSecurityLevel)
|
||||
case s.SecurityLevel > 0 && calculatedSecurityLevel < s.SecurityLevel:
|
||||
// check against toolset's security level
|
||||
return fmt.Errorf(`supplied %s signet "%s" with a security level of %d is weaker than the toolset's security level of %d`, signet.Scheme, signet.ID, calculatedSecurityLevel, s.SecurityLevel)
|
||||
}
|
||||
|
||||
err = s.checkSecurityLevel(calculatedSecurityLevel, func() string {
|
||||
return fmt.Sprintf(`supplied %s signet "%s"`, signet.Scheme, signet.ID)
|
||||
})
|
||||
} else {
|
||||
|
||||
// tool based security level checks
|
||||
switch {
|
||||
case minimumSecurityLevel > 0:
|
||||
// check against minimumSecurityLevel
|
||||
// minimumSecurityLevel overrides other checks
|
||||
if calculatedSecurityLevel < minimumSecurityLevel {
|
||||
return fmt.Errorf(`tool %s with a security level of %d is weaker than the desired security level of %d`, logic.Info().Name, calculatedSecurityLevel, minimumSecurityLevel)
|
||||
}
|
||||
case s.envelope.MinimumSecurityLevel > 0 && calculatedSecurityLevel < s.envelope.MinimumSecurityLevel:
|
||||
// check against envelope's minimum security level
|
||||
return fmt.Errorf(`tool %s with a security level of %d is weaker than the envelope's minimum security level of %d`, logic.Info().Name, calculatedSecurityLevel, s.envelope.MinimumSecurityLevel)
|
||||
}
|
||||
|
||||
// tool based securty level checks
|
||||
err = s.checkSecurityLevel(calculatedSecurityLevel, func() string {
|
||||
return "tool %s" + logic.Info().Name
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// adapt security level of session
|
||||
|
@ -499,6 +513,42 @@ func (s *Session) calcAndCheckSecurityLevel(logic tools.ToolLogic, signet *Signe
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Session) checkSecurityLevel(levelToCheck int, subject func() string) error {
|
||||
switch {
|
||||
case minimumSecurityLevel > 0:
|
||||
// check against minimumSecurityLevel
|
||||
// minimumSecurityLevel overrides other checks
|
||||
if levelToCheck < minimumSecurityLevel {
|
||||
return fmt.Errorf(
|
||||
`%s with a security level of %d is weaker than the desired security level of %d`,
|
||||
subject(),
|
||||
levelToCheck,
|
||||
minimumSecurityLevel,
|
||||
)
|
||||
}
|
||||
case s.envelope.SecurityLevel > 0:
|
||||
// check against envelope's minimum security level
|
||||
if levelToCheck < s.envelope.SecurityLevel {
|
||||
return fmt.Errorf(
|
||||
`%s with a security level of %d is weaker than the envelope's minimum security level of %d`,
|
||||
subject(),
|
||||
levelToCheck,
|
||||
s.envelope.SecurityLevel,
|
||||
)
|
||||
}
|
||||
case levelToCheck < defaultSecurityLevel:
|
||||
// check against default security level as fallback
|
||||
return fmt.Errorf(
|
||||
`%s with a security level of %d is weaker than the default minimum security level of %d`,
|
||||
subject(),
|
||||
levelToCheck,
|
||||
defaultSecurityLevel,
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NonceSize returns the nonce size to use for new letters.
|
||||
func (s *Session) NonceSize() int {
|
||||
size := s.maxSecurityLevel / 32
|
||||
|
|
|
@ -220,8 +220,8 @@ func (signet *Signet) StoreKey() error {
|
|||
|
||||
// Verify verifies the signature of the signet.
|
||||
func (signet *Signet) Verify() error {
|
||||
// FIXME
|
||||
return errors.New("NIY")
|
||||
// TODO
|
||||
return errors.New("signet verification not yet implemented")
|
||||
}
|
||||
|
||||
// Burn destroys all the key material and renders the Signet unusable. This is currently ineffective, see known issues in the project's README.
|
||||
|
|
17
suite.go
Normal file
17
suite.go
Normal file
|
@ -0,0 +1,17 @@
|
|||
package jess
|
||||
|
||||
// Suite status options
|
||||
const (
|
||||
SuiteStatusDeprecated uint8 = 0
|
||||
SuiteStatusPermitted uint8 = 1
|
||||
SuiteStatusRecommended uint8 = 2
|
||||
)
|
||||
|
||||
// Suite describes a cipher suite - a set of algorithms and the attributes they provide.
|
||||
type Suite struct {
|
||||
ID string
|
||||
Tools []string
|
||||
Provides *Requirements
|
||||
SecurityLevel int
|
||||
Status uint8
|
||||
}
|
100
suites.go
Normal file
100
suites.go
Normal file
|
@ -0,0 +1,100 @@
|
|||
package jess
|
||||
|
||||
var (
|
||||
// lists
|
||||
suitesMap = make(map[string]*Suite)
|
||||
suitesList []*Suite
|
||||
|
||||
// suite definitions
|
||||
|
||||
// SuiteKeyV1 is a cipher suite for encryption with a key.
|
||||
SuiteKeyV1 = registerSuite(&Suite{
|
||||
ID: "key_v1",
|
||||
Tools: []string{"HKDF(BLAKE2b-256)", "CHACHA20-POLY1305"},
|
||||
Provides: NewRequirements(),
|
||||
SecurityLevel: 128,
|
||||
Status: SuiteStatusRecommended,
|
||||
})
|
||||
// SuitePasswordV1 is a cipher suite for encryption with a password.
|
||||
SuitePasswordV1 = registerSuite(&Suite{
|
||||
ID: "pw_v1",
|
||||
Tools: []string{"SCRYPT-20", "HKDF(BLAKE2b-256)", "CHACHA20-POLY1305"},
|
||||
Provides: NewRequirements(),
|
||||
SecurityLevel: 128,
|
||||
Status: SuiteStatusRecommended,
|
||||
})
|
||||
// SuiteRcptOnlyV1 is a cipher suite for encrypting for someone, but without verifying the sender/source.
|
||||
SuiteRcptOnlyV1 = registerSuite(&Suite{
|
||||
ID: "rcpt_v1",
|
||||
Tools: []string{"ECDH-X25519", "HKDF(BLAKE2b-256)", "CHACHA20-POLY1305"},
|
||||
Provides: NewRequirements().Remove(SenderAuthentication),
|
||||
SecurityLevel: 128,
|
||||
Status: SuiteStatusRecommended,
|
||||
})
|
||||
// SuiteSignV1 is a cipher suite for signing (no encryption).
|
||||
SuiteSignV1 = registerSuite(&Suite{
|
||||
ID: "sign_v1",
|
||||
Tools: []string{"Ed25519(BLAKE2b-256)"},
|
||||
Provides: newEmptyRequirements().Add(SenderAuthentication),
|
||||
SecurityLevel: 128,
|
||||
Status: SuiteStatusRecommended,
|
||||
})
|
||||
// SuiteCompleteV1 is a cipher suite for both encrypting for someone and signing.
|
||||
SuiteCompleteV1 = registerSuite(&Suite{
|
||||
ID: "v1",
|
||||
Tools: []string{"ECDH-X25519", "Ed25519(BLAKE2b-256)", "HKDF(BLAKE2b-256)", "CHACHA20-POLY1305"},
|
||||
Provides: NewRequirements(),
|
||||
SecurityLevel: 128,
|
||||
Status: SuiteStatusRecommended,
|
||||
})
|
||||
// SuiteWireV1 is a cipher suite for network communication, including authentication of the server, but not the client.
|
||||
SuiteWireV1 = registerSuite(&Suite{
|
||||
ID: "w1",
|
||||
Tools: []string{"ECDH-X25519", "HKDF(BLAKE2b-256)", "CHACHA20-POLY1305"},
|
||||
Provides: NewRequirements().Remove(SenderAuthentication),
|
||||
SecurityLevel: 128,
|
||||
Status: SuiteStatusRecommended,
|
||||
})
|
||||
|
||||
// currently recommended suites
|
||||
|
||||
// SuiteKey is a a cipher suite for encryption with a key.
|
||||
SuiteKey = SuiteKeyV1
|
||||
// SuitePassword is a a cipher suite for encryption with a password.
|
||||
SuitePassword = SuitePasswordV1
|
||||
// SuiteRcptOnly is a a cipher suite for encrypting for someone, but without verifying the sender/source.
|
||||
SuiteRcptOnly = SuiteRcptOnlyV1
|
||||
// SuiteSign is a a cipher suite for signing (no encryption).
|
||||
SuiteSign = SuiteSignV1
|
||||
// SuiteComplete is a a cipher suite for both encrypting for someone and signing.
|
||||
SuiteComplete = SuiteCompleteV1
|
||||
// SuiteWire is a a cipher suite for network communication, including authentication of the server, but not the client.
|
||||
SuiteWire = SuiteWireV1
|
||||
)
|
||||
|
||||
func registerSuite(suite *Suite) (suiteID string) {
|
||||
// add if not exists
|
||||
_, ok := suitesMap[suite.ID]
|
||||
if !ok {
|
||||
suitesMap[suite.ID] = suite
|
||||
suitesList = append(suitesList, suite)
|
||||
}
|
||||
|
||||
return suite.ID
|
||||
}
|
||||
|
||||
// GetSuite returns the suite with the given ID.
|
||||
func GetSuite(suiteID string) (suite *Suite, ok bool) {
|
||||
suite, ok = suitesMap[suiteID]
|
||||
return
|
||||
}
|
||||
|
||||
// Suites returns all registered suites as a slice.
|
||||
func Suites() []*Suite {
|
||||
return suitesList
|
||||
}
|
||||
|
||||
// SuitesMap returns all registered suites as a map.
|
||||
func SuitesMap() map[string]*Suite {
|
||||
return suitesMap
|
||||
}
|
474
suites_test.go
Normal file
474
suites_test.go
Normal file
|
@ -0,0 +1,474 @@
|
|||
package jess
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/safing/jess/hashtools"
|
||||
"github.com/safing/jess/tools"
|
||||
)
|
||||
|
||||
func getSuite(t *testing.T, suiteID string) (suite *Suite) {
|
||||
suite, ok := GetSuite(suiteID)
|
||||
if !ok {
|
||||
t.Fatalf("suite %s does not exist", suiteID)
|
||||
return nil
|
||||
}
|
||||
return suite
|
||||
}
|
||||
|
||||
func TestSuites(t *testing.T) {
|
||||
for _, suite := range Suites() {
|
||||
|
||||
err := suiteBullshitCheck(suite)
|
||||
if err != nil {
|
||||
t.Errorf("suite %s has incorrect property: %s", suite.ID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
envelope, err := setupEnvelopeAndTrustStore(t, suite)
|
||||
if err != nil {
|
||||
t.Errorf("failed to setup test envelope for suite %s: %s", suite.ID, err)
|
||||
continue
|
||||
}
|
||||
if envelope == nil {
|
||||
t.Errorf("suite %s has an invalid toolset", suite.ID)
|
||||
continue
|
||||
}
|
||||
|
||||
session, err := envelope.Correspondence(testTrustStore)
|
||||
if err != nil {
|
||||
t.Errorf("failed to init session for suite %s: %s", suite.ID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
letter, err := session.Close([]byte(testData1))
|
||||
if err != nil {
|
||||
tErrorf(t, "suite %s failed to close (1): %s", suite.ID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
msg, err := letter.ToJSON()
|
||||
if err != nil {
|
||||
tErrorf(t, "suite %s failed to json encode (1): %s", suite.ID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// test 2: open
|
||||
|
||||
letter2, err := LetterFromJSON(msg)
|
||||
if err != nil {
|
||||
tErrorf(t, "suite %s failed to json decode (2): %s", suite.ID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
origData2, err := letter2.Open(envelope.suite.Provides, testTrustStore)
|
||||
if err != nil {
|
||||
tErrorf(t, "suite %s failed to open (2): %s", suite.ID, err)
|
||||
continue
|
||||
}
|
||||
if string(origData2) != testData1 {
|
||||
tErrorf(t, "%v original data mismatch (2): %s", suite.ID, string(origData2))
|
||||
continue
|
||||
}
|
||||
|
||||
// test 2.1: verify
|
||||
|
||||
letter21, err := LetterFromJSON(msg)
|
||||
if err != nil {
|
||||
tErrorf(t, "suite %s failed to json decode (2): %s", suite.ID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(letter21.Signatures) > 0 {
|
||||
err = letter21.Verify(envelope.suite.Provides, testTrustStore)
|
||||
if err != nil {
|
||||
tErrorf(t, "suite %s failed to verify (2): %s", suite.ID, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func suiteBullshitCheck(suite *Suite) error { //nolint:gocognit,gocyclo
|
||||
// pre checks
|
||||
if suite.Provides == nil {
|
||||
return errors.New("provides no requirement attributes")
|
||||
}
|
||||
if suite.SecurityLevel == 0 {
|
||||
return errors.New("does not specify security level")
|
||||
}
|
||||
|
||||
// create session struct for holding information
|
||||
s := &Session{
|
||||
envelope: &Envelope{
|
||||
suite: suite,
|
||||
},
|
||||
toolRequirements: newEmptyRequirements(),
|
||||
}
|
||||
|
||||
// check if we are assuming we have a key
|
||||
assumeKey := strings.Contains(suite.ID, "key")
|
||||
if assumeKey {
|
||||
s.toolRequirements.Add(SenderAuthentication)
|
||||
s.toolRequirements.Add(RecipientAuthentication)
|
||||
}
|
||||
|
||||
// tool check loop: start
|
||||
for i, toolID := range suite.Tools {
|
||||
|
||||
////////////////////////////////////////
|
||||
// tool check loop: check for duplicates
|
||||
////////////////////////////////////////
|
||||
|
||||
for j, dupeToolID := range suite.Tools {
|
||||
if i != j && toolID == dupeToolID {
|
||||
return fmt.Errorf("cannot use tool %s twice, each tool may be only specified once", toolID)
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// tool check loop: parse, prep and get
|
||||
///////////////////////////////////////
|
||||
|
||||
var (
|
||||
hashTool *hashtools.HashTool
|
||||
hashSumFn func() ([]byte, error)
|
||||
)
|
||||
|
||||
// parse ID for args
|
||||
var arg string
|
||||
if strings.Contains(toolID, "(") {
|
||||
splitted := strings.Split(toolID, "(")
|
||||
toolID = splitted[0]
|
||||
arg = strings.Trim(splitted[1], "()")
|
||||
}
|
||||
|
||||
// get tool
|
||||
tool, err := tools.Get(toolID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("the specified tool %s could not be found", toolID)
|
||||
}
|
||||
|
||||
// create logic instance and add to logic and state lists
|
||||
logic := tool.Factory()
|
||||
s.all = append(s.all, logic)
|
||||
if tool.Info.HasOption(tools.OptionHasState) {
|
||||
s.toolsWithState = append(s.toolsWithState, logic)
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////
|
||||
// tool check loop: assign tools to queues and add requirements
|
||||
///////////////////////////////////////////////////////////////
|
||||
|
||||
switch tool.Info.Purpose {
|
||||
case tools.PurposeKeyDerivation:
|
||||
if s.kdf != nil {
|
||||
return fmt.Errorf("cannot use %s, you may only specify one key derivation tool and %s was already specified", tool.Info.Name, s.kdf.Info().Name)
|
||||
}
|
||||
s.kdf = logic
|
||||
|
||||
case tools.PurposePassDerivation:
|
||||
if s.passDerivator != nil {
|
||||
return fmt.Errorf("cannot use %s, you may only specify one password derivation tool and %s was already specified", tool.Info.Name, s.passDerivator.Info().Name)
|
||||
}
|
||||
s.passDerivator = logic
|
||||
s.toolRequirements.Add(SenderAuthentication)
|
||||
s.toolRequirements.Add(RecipientAuthentication)
|
||||
|
||||
case tools.PurposeKeyExchange:
|
||||
s.keyExchangers = append(s.keyExchangers, logic)
|
||||
s.toolRequirements.Add(RecipientAuthentication)
|
||||
|
||||
case tools.PurposeKeyEncapsulation:
|
||||
s.keyEncapsulators = append(s.keyEncapsulators, logic)
|
||||
s.toolRequirements.Add(RecipientAuthentication)
|
||||
|
||||
case tools.PurposeSigning:
|
||||
s.signers = append(s.signers, logic)
|
||||
s.toolRequirements.Add(SenderAuthentication)
|
||||
|
||||
case tools.PurposeIntegratedCipher:
|
||||
s.integratedCiphers = append(s.integratedCiphers, logic)
|
||||
s.toolRequirements.Add(Confidentiality)
|
||||
s.toolRequirements.Add(Integrity)
|
||||
|
||||
case tools.PurposeCipher:
|
||||
s.ciphers = append(s.ciphers, logic)
|
||||
s.toolRequirements.Add(Confidentiality)
|
||||
|
||||
case tools.PurposeMAC:
|
||||
s.macs = append(s.macs, logic)
|
||||
s.toolRequirements.Add(Integrity)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// tool check loop: process options, get hashers
|
||||
////////////////////////////////////////////////
|
||||
|
||||
for _, option := range tool.Info.Options {
|
||||
switch option {
|
||||
|
||||
case tools.OptionNeedsManagedHasher:
|
||||
// get managed hasher list
|
||||
var managedHashers map[string]*managedHasher
|
||||
switch tool.Info.Purpose {
|
||||
case tools.PurposeMAC:
|
||||
if s.managedMACHashers == nil {
|
||||
s.managedMACHashers = make(map[string]*managedHasher)
|
||||
}
|
||||
managedHashers = s.managedMACHashers
|
||||
case tools.PurposeSigning:
|
||||
if s.managedSigningHashers == nil {
|
||||
s.managedSigningHashers = make(map[string]*managedHasher)
|
||||
}
|
||||
managedHashers = s.managedSigningHashers
|
||||
default:
|
||||
return fmt.Errorf("only MAC and Signing tools may use managed hashers")
|
||||
}
|
||||
|
||||
// get or assign a new managed hasher
|
||||
mngdHasher, ok := managedHashers[arg]
|
||||
if !ok {
|
||||
// get hashtool
|
||||
ht, err := hashtools.Get(arg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("the specified hashtool for %s(%s) could not be found", toolID, arg)
|
||||
}
|
||||
|
||||
// save to managed hashers
|
||||
mngdHasher = &managedHasher{
|
||||
tool: ht,
|
||||
hash: ht.New(),
|
||||
}
|
||||
managedHashers[arg] = mngdHasher
|
||||
}
|
||||
|
||||
hashTool = mngdHasher.tool
|
||||
hashSumFn = mngdHasher.Sum
|
||||
|
||||
case tools.OptionNeedsDedicatedHasher:
|
||||
hashTool, err = hashtools.Get(arg)
|
||||
if err != nil {
|
||||
return fmt.Errorf("the specified hashtool for %s(%s) could not be found", toolID, arg)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////
|
||||
// tool check loop: initialize tool
|
||||
///////////////////////////////////
|
||||
|
||||
// init tool
|
||||
logic.Init(
|
||||
tool,
|
||||
&Helper{
|
||||
session: s,
|
||||
info: tool.Info,
|
||||
},
|
||||
hashTool,
|
||||
hashSumFn,
|
||||
)
|
||||
|
||||
//////////////////////////////////////////////////
|
||||
// tool check loop: calc and check security levels
|
||||
//////////////////////////////////////////////////
|
||||
|
||||
err = s.calcAndCheckSecurityLevel(logic, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
} // tool check loop: end
|
||||
|
||||
///////////////
|
||||
// final checks
|
||||
///////////////
|
||||
|
||||
// check requirements requirements
|
||||
if s.toolRequirements.Empty() {
|
||||
return errors.New("suite does not provide any security attributes")
|
||||
}
|
||||
|
||||
// check if we have recipient auth without confidentiality
|
||||
if s.toolRequirements.Has(RecipientAuthentication) &&
|
||||
!s.toolRequirements.Has(Confidentiality) {
|
||||
return errors.New("having recipient authentication without confidentiality does not make sense")
|
||||
}
|
||||
|
||||
// check if we have confidentiality without integrity
|
||||
if s.toolRequirements.Has(Confidentiality) &&
|
||||
!s.toolRequirements.Has(Integrity) {
|
||||
return errors.New("having confidentiality without integrity does not make sense")
|
||||
}
|
||||
|
||||
// check if we are missing a kdf, but need one
|
||||
if s.kdf == nil && len(s.signers) != len(s.envelope.suite.Tools) {
|
||||
return errors.New("missing a key derivation tool")
|
||||
}
|
||||
|
||||
// check if have a kdf, even if we don't need one
|
||||
if len(s.integratedCiphers) == 0 &&
|
||||
len(s.ciphers) == 0 &&
|
||||
len(s.macs) == 0 &&
|
||||
s.kdf != nil {
|
||||
return errors.New("key derivation tool specified, but not needed")
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
// check if values match suite definition
|
||||
/////////////////////////////////////////
|
||||
|
||||
// check if security level matches
|
||||
if s.SecurityLevel != suite.SecurityLevel {
|
||||
return fmt.Errorf("suite has incorrect security level: %d (expected %d)", suite.SecurityLevel, s.SecurityLevel)
|
||||
}
|
||||
|
||||
// check if requirements match
|
||||
if s.toolRequirements.SerializeToNoSpec() != suite.Provides.SerializeToNoSpec() {
|
||||
return fmt.Errorf(
|
||||
"suite has incorrect attributes: no %s (expected no %s)",
|
||||
suite.Provides.SerializeToNoSpec(),
|
||||
s.toolRequirements.SerializeToNoSpec(),
|
||||
)
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
// check if computeSuiteAttributes returns the same results
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
computedSuite := computeSuiteAttributes(suite.Tools, assumeKey)
|
||||
if computedSuite == nil {
|
||||
return errors.New("internal error: could not compute suite attributes")
|
||||
}
|
||||
if suite.SecurityLevel != computedSuite.SecurityLevel {
|
||||
return fmt.Errorf("internal error: computeSuiteAttributes error: security level: suite=%d computed=%d", suite.SecurityLevel, computedSuite.SecurityLevel)
|
||||
}
|
||||
if suite.Provides.SerializeToNoSpec() != computedSuite.Provides.SerializeToNoSpec() {
|
||||
return fmt.Errorf(
|
||||
"internal error: computeSuiteAttributes error: attributes: suite=no %s compute=no %s)",
|
||||
suite.Provides.SerializeToNoSpec(),
|
||||
computedSuite.Provides.SerializeToNoSpec(),
|
||||
)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func computeSuiteAttributes(toolIDs []string, assumeKey bool) *Suite {
|
||||
new := &Suite{
|
||||
Provides: newEmptyRequirements(),
|
||||
SecurityLevel: 0,
|
||||
}
|
||||
|
||||
// if we have a key
|
||||
if assumeKey {
|
||||
new.Provides.Add(SenderAuthentication)
|
||||
new.Provides.Add(RecipientAuthentication)
|
||||
}
|
||||
|
||||
// check all security levels and collect attributes
|
||||
for _, toolID := range toolIDs {
|
||||
|
||||
///////////////////////////////////////
|
||||
// tool check loop: parse, prep and get
|
||||
///////////////////////////////////////
|
||||
|
||||
var hashTool *hashtools.HashTool
|
||||
|
||||
// parse ID for args
|
||||
var arg string
|
||||
if strings.Contains(toolID, "(") {
|
||||
splitted := strings.Split(toolID, "(")
|
||||
toolID = splitted[0]
|
||||
arg = strings.Trim(splitted[1], "()")
|
||||
}
|
||||
|
||||
// get tool
|
||||
tool, err := tools.Get(toolID)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// create logic instance and add to logic and state lists
|
||||
logic := tool.Factory()
|
||||
|
||||
//////////////////////////////////////
|
||||
// tool check loop: collect attributes
|
||||
//////////////////////////////////////
|
||||
|
||||
switch tool.Info.Purpose {
|
||||
case tools.PurposePassDerivation:
|
||||
new.Provides.Add(SenderAuthentication)
|
||||
new.Provides.Add(RecipientAuthentication)
|
||||
|
||||
case tools.PurposeKeyExchange:
|
||||
new.Provides.Add(RecipientAuthentication)
|
||||
|
||||
case tools.PurposeKeyEncapsulation:
|
||||
new.Provides.Add(RecipientAuthentication)
|
||||
|
||||
case tools.PurposeSigning:
|
||||
new.Provides.Add(SenderAuthentication)
|
||||
|
||||
case tools.PurposeIntegratedCipher:
|
||||
new.Provides.Add(Confidentiality)
|
||||
new.Provides.Add(Integrity)
|
||||
|
||||
case tools.PurposeCipher:
|
||||
new.Provides.Add(Confidentiality)
|
||||
|
||||
case tools.PurposeMAC:
|
||||
new.Provides.Add(Integrity)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////
|
||||
// tool check loop: process options, get hashers
|
||||
////////////////////////////////////////////////
|
||||
|
||||
for _, option := range tool.Info.Options {
|
||||
switch option {
|
||||
case tools.OptionNeedsManagedHasher,
|
||||
tools.OptionNeedsDedicatedHasher:
|
||||
hashTool, err = hashtools.Get(arg)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////
|
||||
// tool check loop: initialize tool
|
||||
///////////////////////////////////
|
||||
|
||||
// init tool
|
||||
logic.Init(
|
||||
tool,
|
||||
&Helper{
|
||||
info: tool.Info,
|
||||
},
|
||||
hashTool,
|
||||
nil,
|
||||
)
|
||||
|
||||
//////////////////////////////////////////
|
||||
// tool check loop: compute security level
|
||||
//////////////////////////////////////////
|
||||
|
||||
toolSecurityLevel, err := logic.SecurityLevel(nil)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if new.SecurityLevel == 0 || toolSecurityLevel < new.SecurityLevel {
|
||||
new.SecurityLevel = toolSecurityLevel
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return new
|
||||
}
|
|
@ -35,6 +35,9 @@ func (oaep *RsaOAEP) EncapsulateKey(key []byte, signet tools.SignetInt) ([]byte,
|
|||
if !ok {
|
||||
return nil, tools.ErrInvalidKey
|
||||
}
|
||||
if rsaPubKey == nil {
|
||||
return nil, tools.ErrInvalidKey
|
||||
}
|
||||
|
||||
// check key length: The message must be no longer than the length of the public modulus minus twice the hash length, minus a further 2.
|
||||
maxMsgSize := rsaPubKey.Size() - (2 * oaep.HashTool().DigestSize) - 2
|
||||
|
|
159
tools_test.go
159
tools_test.go
|
@ -1,7 +1,12 @@
|
|||
package jess
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/safing/jess/hashtools"
|
||||
|
||||
"github.com/safing/jess/tools"
|
||||
|
||||
|
@ -32,7 +37,39 @@ func TestConformity(t *testing.T) {
|
|||
|
||||
}
|
||||
|
||||
func TestPasswordHashingSpeed(t *testing.T) {
|
||||
// skip in short tests and when not running comprehensive
|
||||
if testing.Short() || !runComprehensiveTestsActive {
|
||||
return
|
||||
}
|
||||
// run this test with
|
||||
// go test -timeout 10m github.com/safing/jess -v -count=1 -ldflags "-X github.com/safing/jess.RunComprehensiveTests=true" -run ^TestPasswordHashingSpeed$
|
||||
|
||||
for _, tool := range tools.AsList() {
|
||||
if tool.Info.Purpose == tools.PurposePassDerivation {
|
||||
password := []byte(testPassword1)
|
||||
salt, err := RandomBytes(4)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
_, err = tool.StaticLogic.DeriveKeyFromPassword(password, salt)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Logf("%s took %s to derive key from password", tool.Info.Name, time.Since(start))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//nolint:gocognit,gocyclo
|
||||
func TestSignetHandling(t *testing.T) {
|
||||
hashTool, err := hashtools.Get("SHA2-256")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, tool := range tools.AsList() {
|
||||
switch tool.Info.Purpose {
|
||||
case tools.PurposeKeyExchange,
|
||||
|
@ -88,6 +125,128 @@ func TestSignetHandling(t *testing.T) {
|
|||
t.Fatalf("failed to load %s recipient: %s", tool.Info.Name, err)
|
||||
}
|
||||
|
||||
// store signet
|
||||
signetJSON, err := json.Marshal(signet)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to serialize %s signet: %s", tool.Info.Name, err)
|
||||
}
|
||||
|
||||
// load signet
|
||||
loadedSignet := &Signet{}
|
||||
err = json.Unmarshal(signetJSON, loadedSignet)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse serialized %s signet: %s", tool.Info.Name, err)
|
||||
}
|
||||
err = loadedSignet.LoadKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load key of %s signet: %s", tool.Info.Name, err)
|
||||
}
|
||||
|
||||
// store rcpt
|
||||
rcptJSON, err := json.Marshal(rcpt)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to serialize %s rcpt: %s", tool.Info.Name, err)
|
||||
}
|
||||
|
||||
// load rcpt
|
||||
loadedRcpt := &Signet{}
|
||||
err = json.Unmarshal(rcptJSON, loadedRcpt)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to parse serialized %s rcpt: %s", tool.Info.Name, err)
|
||||
}
|
||||
err = loadedRcpt.LoadKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load key of %s rcpt: %s", tool.Info.Name, err)
|
||||
}
|
||||
|
||||
// load tool
|
||||
err = loadedSignet.loadTool()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load tool of %s: %s", tool.Info.Name, err)
|
||||
}
|
||||
|
||||
// init tool with hashtool
|
||||
toolLogic := tool.Factory()
|
||||
hasher := managedHasher{
|
||||
tool: hashTool,
|
||||
hash: hashTool.New(),
|
||||
}
|
||||
toolLogic.Init(
|
||||
tool,
|
||||
&Helper{info: tool.Info},
|
||||
hashTool,
|
||||
hasher.Sum,
|
||||
)
|
||||
|
||||
// do an operation
|
||||
switch loadedSignet.tool.Info.Purpose {
|
||||
case tools.PurposeKeyExchange:
|
||||
// create and generate signet
|
||||
peerSignet := NewSignetBase(tool)
|
||||
err := peerSignet.GenerateKey()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to generate key with %s peer: %s", tool.Info.Name, err)
|
||||
}
|
||||
|
||||
// transform to recipient
|
||||
peerRcpt, err := peerSignet.AsRecipient()
|
||||
if err != nil {
|
||||
t.Fatalf("failed to get %s peer as recipient: %s", tool.Info.Name, err)
|
||||
}
|
||||
|
||||
sharedSecret1, err := toolLogic.MakeSharedKey(loadedSignet, peerRcpt)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to make shared secret 1 with %s: %s", tool.Info.Name, err)
|
||||
}
|
||||
|
||||
sharedSecret2, err := toolLogic.MakeSharedKey(peerSignet, loadedRcpt)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to make shared secret 2 with %s: %s", tool.Info.Name, err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(sharedSecret1, sharedSecret2) {
|
||||
t.Fatalf("shared secrets made with %s do not match, got:\ns1: %v\ns2: %v", tool.Info.Name, sharedSecret1, sharedSecret2)
|
||||
}
|
||||
case tools.PurposeKeyEncapsulation:
|
||||
origKey, err := RandomBytes(16)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to generate test key: %s", err)
|
||||
}
|
||||
|
||||
wrappedKey, err := toolLogic.EncapsulateKey(origKey, loadedRcpt)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to encapsulate key with %s: %s", tool.Info.Name, err)
|
||||
}
|
||||
|
||||
unwrappedKey, err := toolLogic.UnwrapKey(wrappedKey, loadedSignet)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to unwrap key with %s: %s", tool.Info.Name, err)
|
||||
}
|
||||
|
||||
if !bytes.Equal(origKey, unwrappedKey) {
|
||||
t.Fatalf("original and unwrapped key with %s do not match, got:\norig: %v\nunwrapped: %v", tool.Info.Name, origKey, unwrappedKey)
|
||||
}
|
||||
|
||||
case tools.PurposeSigning:
|
||||
testData, err := RandomBytes(16)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to generate test data: %s", err)
|
||||
}
|
||||
_, err = hasher.hash.Write(testData)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to write to hash: %s", err)
|
||||
}
|
||||
|
||||
signature, err := toolLogic.Sign(testData, nil, loadedSignet)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to sign with %s: %s", tool.Info.Name, err)
|
||||
}
|
||||
|
||||
err = toolLogic.Verify(testData, nil, signature, loadedRcpt)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to verify with %s: %s", tool.Info.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,9 +65,6 @@ func WriteEnvelopeToFile(envelope *jess.Envelope, filename string) error {
|
|||
return errInvalidEnvelopeNameChars
|
||||
}
|
||||
|
||||
// serialize requirements
|
||||
envelope.SerializeRequirements()
|
||||
|
||||
// serialize
|
||||
data, err := dsd.DumpIndent(envelope, dsd.JSON, "\t")
|
||||
if err != nil {
|
||||
|
@ -100,8 +97,8 @@ func LoadEnvelopeFromFile(filename string) (*jess.Envelope, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// parse requirements from "No"
|
||||
err = envelope.LoadRequirements()
|
||||
// load suite using SuiteID
|
||||
err = envelope.LoadSuite()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue