Skip to content

Commit a40c1ed

Browse files
authored
feat(locking): Add experimental locking API (#17)
1 parent 18fcab0 commit a40c1ed

File tree

11 files changed

+543
-7
lines changed

11 files changed

+543
-7
lines changed

.releaserc.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,13 @@ plugins:
88
- prepareCmd: "make build-release"
99
- - "@semantic-release/github"
1010
- assets:
11+
- path: "sedlockctl.linux.amd64"
12+
label: "sedlockctl (Linux AMD64)"
13+
- path: "sedlockctl.linux.arm64"
14+
label: "sedlockctl (Linux ARM64)"
1115
- path: "tcgsdiag.linux.amd64"
1216
label: "tcgsdiag (Linux AMD64)"
1317
- path: "tcgsdiag.linux.arm64"
1418
label: "tcgsdiag (Linux ARM64)"
1519

20+

Makefile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,20 @@
55
.PHONY: build
66
build:
77
go build ${LDFLAGS} -v -o target/tcgsdiag $(CURDIR)/cmd/tcgsdiag
8+
go build ${LDFLAGS} -v -o target/sedlockctl $(CURDIR)/cmd/sedlockctl
89

910
.PHONY: build-release
1011
build-release: build-release-amd64 build-release-arm64
1112

1213
.PHONY: build-release-amd64
1314
build-release-amd64:
1415
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ${LDFLAGS} -o=tcgsdiag.linux.amd64 $(CURDIR)/cmd/tcgsdiag
16+
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build ${LDFLAGS} -o=sedlockctl.linux.amd64 $(CURDIR)/cmd/sedlockctl
1517

1618
.PHONY: build-release-arm64
1719
build-release-arm64:
1820
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build ${LDFLAGS} -o=tcgsdiag.linux.arm64 $(CURDIR)/cmd/tcgsdiag
21+
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build ${LDFLAGS} -o=sedlockctl.linux.arm64 $(CURDIR)/cmd/sedlockctl
1922

2023
.PHONY: test
2124
test:

cmd/sedlockctl/hash.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) 2021 by library authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"crypto/sha1"
9+
"fmt"
10+
11+
"golang.org/x/crypto/pbkdf2"
12+
)
13+
14+
func HashSedutilDTA(password string, serial string) []byte {
15+
// This needs to match https://github.com/Drive-Trust-Alliance/sedutil/
16+
salt := fmt.Sprintf("%-20s", serial)
17+
return pbkdf2.Key([]byte(password), []byte(salt[:20]), 75000, 32, sha1.New)
18+
}

cmd/sedlockctl/hash_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"encoding/hex"
6+
"testing"
7+
)
8+
9+
func TestSedutilHashCompatibility(t *testing.T) {
10+
got := HashSedutilDTA("dummy", "S2RBNB0HA12200B")
11+
want := []byte{
12+
0x4f, 0x2a, 0xcc, 0xfd, 0x1a, 0x17, 0x64, 0xdc, 0x5b, 0x5b, 0xb3, 0x8f, 0x40, 0xf9, 0x06, 0x8d,
13+
0x2d, 0x1a, 0x1f, 0x6d, 0xd5, 0x39, 0x27, 0x07, 0xde, 0xa1, 0x4c, 0x3b, 0xb7, 0xde, 0xea, 0xcc,
14+
}
15+
if !bytes.Equal(want, got) {
16+
t.Errorf("Unexpected PBKDF2 hash, got %s want %s", hex.EncodeToString(got), hex.EncodeToString(want))
17+
}
18+
}

cmd/sedlockctl/main.go

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Copyright (c) 2021 by library authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package main
6+
7+
import (
8+
"flag"
9+
"fmt"
10+
"log"
11+
"os"
12+
13+
"github.com/bluecmd/go-tcg-storage/pkg/drive"
14+
"github.com/bluecmd/go-tcg-storage/pkg/locking"
15+
)
16+
17+
var (
18+
sidPIN = flag.String("sid", "", "PIN to authenticate to the AdminSP as SID")
19+
sidPINMSID = flag.Bool("try-sid-msid", false, "Try to use the MSID as PIN to authenticate to the AdminSP in addition to other methods")
20+
sidPINHash = flag.String("sid-hash", "sedutil-dta", "If set, transform the SID PIN using the specified hash function")
21+
user = flag.String("user", "", "Username to authenticate to the LockingSP (admin1 or bandmaster0 is the default)")
22+
userPIN = flag.String("password", "", "PIN used to authenticate ot the LockingSP (MSID is the default)")
23+
userPINHash = flag.String("hash", "sedutil-dta", "If set, transform the PIN using the specified hash function")
24+
)
25+
26+
func main() {
27+
flag.Parse()
28+
29+
if flag.NArg() == 0 {
30+
fmt.Printf("Usage: %s [-flags ..] device\n", os.Args[0])
31+
return
32+
}
33+
d, err := drive.Open(flag.Arg(0))
34+
if err != nil {
35+
log.Fatalf("drive.Open: %v", err)
36+
}
37+
defer d.Close()
38+
snRaw, err := d.SerialNumber()
39+
if err != nil {
40+
log.Fatalf("drive.SerialNumber: %v", err)
41+
}
42+
sn := string(snRaw)
43+
44+
spin := []byte{}
45+
if *sidPIN != "" {
46+
switch *sidPINHash {
47+
case "sedutil-dta":
48+
spin = HashSedutilDTA(*sidPIN, sn)
49+
default:
50+
log.Fatalf("Unknown hash method %q", *sidPINHash)
51+
}
52+
}
53+
54+
initOps := []locking.InitializeOpt{}
55+
if len(spin) > 0 {
56+
initOps = append(initOps, locking.WithAuth(locking.DefaultAdminAuthority(spin)))
57+
}
58+
if *sidPINMSID {
59+
initOps = append(initOps, locking.WithAuth(locking.DefaultAuthorityWithMSID))
60+
}
61+
62+
cs, lmeta, err := locking.Initialize(d, initOps...)
63+
if err != nil {
64+
log.Fatalf("locking.Initalize: %v", err)
65+
}
66+
defer cs.Close()
67+
68+
var auth locking.LockingSPAuthenticator
69+
pin := []byte{}
70+
if *userPIN != "" {
71+
switch *userPINHash {
72+
case "sedutil-dta":
73+
pin = HashSedutilDTA(*userPIN, sn)
74+
default:
75+
log.Fatalf("Unknown hash method %q", *userPINHash)
76+
}
77+
}
78+
if *user != "" {
79+
var ok bool
80+
auth, ok = locking.AuthorityFromName(*user, pin)
81+
if !ok {
82+
log.Fatalf("Authority %q is not known for this device", *user)
83+
}
84+
} else {
85+
if len(pin) == 0 {
86+
auth = locking.DefaultAuthorityWithMSID
87+
} else {
88+
auth = locking.DefaultAuthority(pin)
89+
}
90+
}
91+
92+
l, err := locking.NewSession(cs, lmeta, auth)
93+
if err != nil {
94+
log.Fatalf("locking.NewSession: %v", err)
95+
}
96+
defer l.Close()
97+
98+
if len(l.Ranges) == 0 {
99+
log.Fatalf("No available locking ranges as this user\n")
100+
}
101+
for i, r := range l.Ranges {
102+
strr := "whole disk"
103+
if r.End > 0 {
104+
strr = fmt.Sprintf("%d to %d", r.Start, r.End)
105+
}
106+
if !r.WriteLockEnabled && !r.ReadLockEnabled {
107+
strr = "disabled"
108+
} else {
109+
if r.WriteLocked {
110+
strr += " [write locked]"
111+
}
112+
if r.ReadLocked {
113+
strr += " [read locked]"
114+
}
115+
}
116+
fmt.Printf("Range %3d: %s\n", i, strr)
117+
}
118+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ go 1.15
44

55
require (
66
github.com/davecgh/go-spew v1.1.1
7+
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a
78
golang.org/x/sys v0.0.0-20210531080801-fdfd190a6549
89
)

go.sum

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
22
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
3-
golang.org/x/sys v0.0.0-20210521203332-0cec03c779c1 h1:lCnv+lfrU9FRPGf8NeRuWAAPjNnema5WtBinMgs1fD8=
4-
golang.org/x/sys v0.0.0-20210521203332-0cec03c779c1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
5-
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea h1:+WiDlPBBaO+h9vPNZi8uJ3k4BkKQB7Iow3aqwHVA5hI=
6-
golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
3+
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
4+
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
5+
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
6+
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
77
golang.org/x/sys v0.0.0-20210531080801-fdfd190a6549 h1:OL5GcZ2XPkte3dpfuFQ9o884vrE3BZQhajdntNMruv4=
88
golang.org/x/sys v0.0.0-20210531080801-fdfd190a6549/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
9+
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
10+
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
11+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

pkg/core/session.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,9 @@ var (
5151
type ProtocolLevel uint
5252

5353
const (
54-
ProtocolLevelEnterprise = 1
55-
ProtocolLevelCore = 2
54+
ProtocolLevelUnknown ProtocolLevel = 0
55+
ProtocolLevelEnterprise ProtocolLevel = 1
56+
ProtocolLevelCore ProtocolLevel = 2
5657
)
5758

5859
func (p *ProtocolLevel) String() string {

pkg/core/table/thissp.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,17 @@
77
package table
88

99
import (
10+
"errors"
1011
"fmt"
1112

1213
"github.com/bluecmd/go-tcg-storage/pkg/core"
1314
"github.com/bluecmd/go-tcg-storage/pkg/core/stream"
1415
)
1516

17+
var (
18+
ErrAuthenticationFailed = errors.New("authentication failed")
19+
)
20+
1621
func ThisSP_Random(s *core.Session, count uint) ([]byte, error) {
1722
mc := s.NewMethodCall(core.InvokeIDThisSP, MethodIDRandom)
1823
mc.UInt(count)
@@ -60,7 +65,7 @@ func ThisSP_Authenticate(s *core.Session, authority core.AuthorityObjectUID, pro
6065
return core.ErrMalformedMethodResponse
6166
}
6267
if success == 0 {
63-
return fmt.Errorf("authentication failed")
68+
return ErrAuthenticationFailed
6469
}
6570
return nil
6671
}

0 commit comments

Comments
 (0)