Skip to content

Commit

Permalink
hooks: Accommodate changes in crypto/ecdsa between go 1.21 and go 1.22
Browse files Browse the repository at this point in the history
The way that the nonce is generated when creating ECDSA signatures
changed between go 1.21 and 1.22, breaking some of our tests that
rely on hardcoded byte sequences and signatures. Thankfully the new
mechanism still consumes the same amount of entropy so this is fairly
easy to work around, and the new behaviour can still be made
deterministic with our BypassMaybeReadByte hack.

This adds a function that converts a set of input parameters to a
hardcoded signature, with alternate versions compiled for different go
versions.
  • Loading branch information
chrisccoulson committed Jun 14, 2024
1 parent fe5d1a9 commit df6251f
Show file tree
Hide file tree
Showing 6 changed files with 354 additions and 581 deletions.
504 changes: 128 additions & 376 deletions hooks/keydata_test.go

Large diffs are not rendered by default.

54 changes: 54 additions & 0 deletions hooks/mockdata_1_21_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// -*- Mode: Go; indent-tabs-mode: t -*-

//go:build !go1.22

/*
* Copyright (C) 2024 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

package hooks_test

import (
"reflect"

. "gopkg.in/check.v1"

"github.com/snapcore/secboot"
)

// bootscopeJsonSignature maps the supplied parameters to a hardcoded bootscope signature for
// signatures generated with go < 1.22.
func bootscopeJsonSignature(c *C, primaryKey, role string, bootModes []string, models []secboot.SnapModel) string {
switch {
case primaryKey == primaryKey1 && role == "foo" && reflect.DeepEqual(bootModes, []string{"run"}) && reflect.DeepEqual(models, []secboot.SnapModel{model1}):
return "MEQCIA19SEUAhiGMpFpBzZYUfiC3iGC9W3n9G2DfztjNaORRAiBpX/6zHRUC6XFScX+0vajpMYdgrpckXmlO4imyYDrvCw=="
case primaryKey == primaryKey1 && role == "bar" && reflect.DeepEqual(bootModes, []string{"run"}) && reflect.DeepEqual(models, []secboot.SnapModel{model1}):
return "MEYCIQDbGuOz+1CJOPuzXFJtc87OjH5du7rPcPO66Y4N3ypyPQIhAMlMVMcyXLgAxGVrhMeMpNLuV+xBeUo+Pjq1ezt3m6i2"
case primaryKey == primaryKey1 && role == "foo" && reflect.DeepEqual(bootModes, []string{"run", "recover"}) && reflect.DeepEqual(models, []secboot.SnapModel{model1, model2}):
return "MEQCIGRKp3aXbNyn2vIbZC/cA65FcrhGGaOwgNs2SnrKYZJ6AiABNaEs1JDBCDitVG9Td68P/D8HsaSs8KlKLWIp8GNa/w=="
case primaryKey == primaryKey1 && role == "foo" && len(bootModes) == 0 && len(models) == 0:
return "MEUCIQDzPqopz+v505PetuBsnxvMF+FdxgwdQE1ZmoXW5Q6LZAIgEyMjnb9BndR6l6KUaLzgnMDoK986CxZ4/cfIOELmYSs="
case primaryKey == primaryKey2 && role == "foo" && len(bootModes) == 0 && len(models) == 0:
return "MEUCIQD2r1Th4xtwzjj8p9LQwLIf98QPOlMbmCDvK2DVAICqGwIgVKo6tNpjcfHiguLLAcPfTF2KEpgWozWhxSRpDn6IseM="
case primaryKey == primaryKey3 && role == "foo" && len(bootModes) == 0 && len(models) == 0:
return "MEQCIC7G/zO4BtP7PYQQKvf1jR4hm9vTbzca7k5h/ZuiGh7HAiAdfbplIZvWtU03BYQw4q1oOpRtN34mpRkFnOf1t3Y7YQ=="
default:
// TODO: should be fatal
c.Error("no signature for parameter combination")
return ""
}
panic("not reached")
}
54 changes: 54 additions & 0 deletions hooks/mockdata_1_22_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// -*- Mode: Go; indent-tabs-mode: t -*-

//go:build go1.22

/*
* Copyright (C) 2024 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

package hooks_test

import (
"reflect"

. "gopkg.in/check.v1"

"github.com/snapcore/secboot"
)

// bootscopeJsonSignature maps the supplied parameters to a hardcoded bootscope signature for
// signatures generated with go >= 1.22.
func bootscopeJsonSignature(c *C, primaryKey, role string, bootModes []string, models []secboot.SnapModel) string {
switch {
case primaryKey == primaryKey1 && role == "foo" && reflect.DeepEqual(bootModes, []string{"run"}) && reflect.DeepEqual(models, []secboot.SnapModel{model1}):
return "MEQCIC1TpdJB7WkibO5E0lM4wf/2pxUCqLSdglYZ2u0ODZPhAiADkQXehucH9jI7Ft/G8gvE4i6EY3leqN2dwM9fOuAXsQ=="
case primaryKey == primaryKey1 && role == "bar" && reflect.DeepEqual(bootModes, []string{"run"}) && reflect.DeepEqual(models, []secboot.SnapModel{model1}):
return "MEYCIQCAW1hsiPaHb+K5EEIdVVHK5nJ6d0MLiLXqgDgEZqjI0QIhAIrfaZ1QnatOrauFdTcbewJu2N0vzsl8nTyOz65KejEF"
case primaryKey == primaryKey1 && role == "foo" && reflect.DeepEqual(bootModes, []string{"run", "recover"}) && reflect.DeepEqual(models, []secboot.SnapModel{model1, model2}):
return "MEQCICTZ9puVJIC5Gp7hMSUMq48QpH6mJfR2U+dr8cmfVd17AiALiRvp/K4kCf90KJwZVfQM6zOIXi2b/Wf+PG7wW3uRZQ=="
case primaryKey == primaryKey1 && role == "foo" && len(bootModes) == 0 && len(models) == 0:
return "MEUCIQC7WkvJvAnhtXUwy17nTZjgJJPghkU0kcWgoWzfH/fppQIgSX9myUAecaMFVQW6qm23reb/hs5PbemkPRcZwLVlbPM="
case primaryKey == primaryKey2 && role == "foo" && len(bootModes) == 0 && len(models) == 0:
return "MEYCIQCTGRwz1dpF7MbsiYx/Bd4sqUcdD1vmSj1M9LjgolC1OAIhAPwQlMwK43HOA6qF2UCQX+mLboAi00rbNExYXduX5T4A"
case primaryKey == primaryKey3 && role == "foo" && len(bootModes) == 0 && len(models) == 0:
return "MEQCIF2xMnO/TOu6ceLaddrBvP8P2C5zm1kRcxCodK8WA1oaAiAbxMVXObPUZHyJ+OK9PR8gvNbqWYWNAXSny85R/wMYHQ=="
default:
// TODO: should be fatal
c.Error("no signature for parameter combination")
return ""
}
panic("not reached")
}
52 changes: 52 additions & 0 deletions hooks/mockdata_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// -*- Mode: Go; indent-tabs-mode: t -*-

/*
* Copyright (C) 2024 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

package hooks_test

import (
"github.com/snapcore/secboot/internal/testutil"
)

// This contains some test parameters that affect bootscope signatures, in order to
// make it possible to have different sets of hardcoded signatures depending on the
// go version where go changes the mechanism it uses to perform nonce generation. We
// are fortunate so far that the changes between 1.21 and 1.22 result in mechanisms
// that still consume the same amount of entropy, so we don't have to customize our
// hardcoded entropy sources which would make things even more complicated.

var (
model1 = testutil.MustMakeMockCore20ModelAssertion(map[string]interface{}{
"authority-id": "fake-brand",
"series": "16",
"brand-id": "fake-brand",
"model": "fake-model",
"grade": "secured",
}, "Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij")
model2 = testutil.MustMakeMockCore20ModelAssertion(map[string]interface{}{
"authority-id": "fake-brand",
"series": "16",
"brand-id": "fake-brand",
"model": "other-model",
"grade": "secured",
}, "Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij")

primaryKey1 = "f51ad3cfef16e7076153d3a994f1fe09cc82c2ae4186d5322ffaae2f6e2b58fa"
primaryKey2 = "a2c13845528f207216587b52f904fe8c322530d23f10ac47b04e1be6f06c3c04"
primaryKey3 = "4ace63fad0a9adc77234322739d873c81da6e4e3d006214411d18ad81b2518b5"
)
Loading

0 comments on commit df6251f

Please sign in to comment.