-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This adds PIN support to KeyData which is distinct from the existing passphrase support. Passphrases are used both for authentication with the hardware element (such as the TPM) and for additional encryption on the host CPU with a passphrase derived key, and are intended to use a memory hard key derivation. The intention here is that this configuration provides some additional protection in the event of a TPM compromise (eg, say a TPM manufacturer is coerced by a government agency to provide firmware that bypasses authentications), where sensitive data is able to be extracted without the usual authentication, because extracting the secret from the TPM will not be sufficient to obtain all of the key material necessary to unlock a device. PINs (in the literal sense) have a fairly low entropy - an 8 digit PIN only has an entropy of 26.5bits, so this additional encryption will provide little protection in the event of a TPM compromise - if sensitive data is obtained from the TPM, the 26.5bits of entropy won't provide a significant barrier to deriving the remaining key material necessary to unlock a device. We take advantage of this by implementing distinct PIN support that is only used for authentication. With this in mind, the memory hard key derivation does not provide a lot of benefit, so PINs only support PBKDF2, and it can be configured to run faster than the key derivation for passphrases. In that sense, PIN support is essentially just a faster and slightly weaker passphrase. As the PIN is a PIN in the literal sense, it is encoded as a length prefixed binary number before going through the key derivation. This only implements the support to KeyData for now - unlocking support will be added in another PR.
- Loading branch information
1 parent
80b2a5f
commit 0ba2bf4
Showing
3 changed files
with
239 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// -*- 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 secboot | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"math" | ||
"math/big" | ||
) | ||
|
||
type PIN struct { | ||
length uint8 // the length of the input PIN. This is *not* the length of the encoded binary number | ||
value big.Int // the PIN value. This is encoded in big-endian form without leading zeroes. | ||
} | ||
|
||
func ParsePIN(s string) (PIN, error) { | ||
l := len(s) | ||
if l > math.MaxUint8 { | ||
return PIN{}, errors.New("invalid PIN: too long") | ||
} | ||
|
||
val, ok := new(big.Int).SetString(s, 10) | ||
if !ok { | ||
return PIN{}, errors.New("invalid PIN") | ||
} | ||
|
||
return PIN{ | ||
length: uint8(l), | ||
value: *val, | ||
}, nil | ||
} | ||
|
||
func (p PIN) String() string { | ||
return fmt.Sprintf("%0*s", p.length, p.value.String()) | ||
} | ||
|
||
func (p PIN) Bytes() []byte { | ||
return append([]byte{p.length}, p.value.Bytes()...) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package secboot_test | ||
|
||
import ( | ||
. "github.com/snapcore/secboot" | ||
"github.com/snapcore/secboot/internal/testutil" | ||
|
||
. "gopkg.in/check.v1" | ||
) | ||
|
||
type pinSuite struct{} | ||
|
||
var _ = Suite(&pinSuite{}) | ||
|
||
func (s *pinSuite) TestPIN(c *C) { | ||
pin, err := ParsePIN("1234") | ||
c.Assert(err, IsNil) | ||
|
||
c.Check(pin.String(), Equals, "1234") | ||
c.Check(pin.Bytes(), DeepEquals, testutil.DecodeHexString(c, "0404d2")) | ||
} | ||
|
||
func (s *pinSuite) TestPINZeroPaddedIsDifferent(c *C) { | ||
pin, err := ParsePIN("00001234") | ||
c.Assert(err, IsNil) | ||
|
||
c.Check(pin.String(), Equals, "00001234") | ||
c.Check(pin.Bytes(), DeepEquals, testutil.DecodeHexString(c, "0804d2")) | ||
} | ||
|
||
func (s *pinSuite) TestPIN2(c *C) { | ||
pin, err := ParsePIN("12345678") | ||
c.Assert(err, IsNil) | ||
|
||
c.Check(pin.String(), Equals, "12345678") | ||
c.Check(pin.Bytes(), DeepEquals, testutil.DecodeHexString(c, "08bc614e")) | ||
} |