/
challenge.go
90 lines (75 loc) · 1.89 KB
/
challenge.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package tpmdevid
import (
"bytes"
"crypto/ecdsa"
"crypto/rsa"
"crypto/x509"
"errors"
"fmt"
"github.com/google/go-tpm/legacy/tpm2"
"github.com/google/go-tpm/legacy/tpm2/credactivation"
devid "github.com/spiffe/spire/pkg/common/plugin/tpmdevid"
)
func newNonce(size int) ([]byte, error) {
nonce, err := devid.GetRandomBytes(size)
if err != nil {
return nil, err
}
return nonce, nil
}
func VerifyDevIDChallenge(cert *x509.Certificate, challenge, response []byte) error {
var signAlg x509.SignatureAlgorithm
switch publicKey := cert.PublicKey.(type) {
case *rsa.PublicKey:
signAlg = x509.SHA256WithRSA
case *ecdsa.PublicKey:
signAlg = x509.ECDSAWithSHA256
default:
return fmt.Errorf("unsupported private key type %T", publicKey)
}
return cert.CheckSignature(signAlg, challenge, response)
}
func NewCredActivationChallenge(akPub, ekPub tpm2.Public) (*devid.CredActivation, []byte, error) {
akName, err := akPub.Name()
if err != nil {
return nil, nil, fmt.Errorf("cannot extract name from AK public: %w", err)
}
hash, err := ekPub.NameAlg.Hash()
if err != nil {
return nil, nil, err
}
nonce, err := newNonce(hash.Size())
if err != nil {
return nil, nil, err
}
encKey, err := ekPub.Key()
if err != nil {
return nil, nil, err
}
var symBlockSize int
switch encKey.(type) {
case *rsa.PublicKey:
symBlockSize = int(ekPub.RSAParameters.Symmetric.KeyBits) / 8
default:
return nil, nil, errors.New("unsupported algorithm")
}
credentialBlob, secret, err := credactivation.Generate(
akName.Digest,
encKey,
symBlockSize,
nonce,
)
if err != nil {
return nil, nil, err
}
return &devid.CredActivation{
Credential: credentialBlob[2:],
Secret: secret[2:],
}, nonce, err
}
func VerifyCredActivationChallenge(expectedNonce, responseNonce []byte) error {
if !bytes.Equal(expectedNonce, responseNonce) {
return errors.New("nonces are different")
}
return nil
}