Skip to content

Commit 61e2fec

Browse files
committed
fix: support hash attestation domains in certificate audit
Certificate audit now handles .hatt.tinfoil.sh domains by decoding the attestation hash, fetching the full attestation from the server, and verifying the hash matches.
1 parent 8ba04e1 commit 61e2fec

File tree

1 file changed

+64
-11
lines changed

1 file changed

+64
-11
lines changed

certificate_audit.go

Lines changed: 64 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ import (
44
"crypto/ecdsa"
55
"crypto/tls"
66
"crypto/x509"
7+
"encoding/base32"
78
"encoding/pem"
89
"fmt"
910
"os"
11+
"sort"
1012
"strings"
1113

1214
log "github.com/sirupsen/logrus"
@@ -27,37 +29,86 @@ func init() {
2729
rootCmd.AddCommand(certificateAuditCmd)
2830
}
2931

30-
func attestationFromCertificate(cert *x509.Certificate) (*attestation.Document, string, error) {
32+
func decodeHashDomains(domains []string) (string, error) {
33+
sort.Slice(domains, func(i, j int) bool {
34+
return domains[i][:2] < domains[j][:2]
35+
})
36+
37+
var encodedData string
38+
for _, domain := range domains {
39+
domain = strings.Split(domain, ".")[0]
40+
encodedData += domain[2:]
41+
}
42+
43+
encoder := base32.StdEncoding.WithPadding(base32.NoPadding)
44+
hashBytes, err := encoder.DecodeString(strings.ToUpper(encodedData))
45+
if err != nil {
46+
return "", fmt.Errorf("failed to decode base32: %v", err)
47+
}
48+
return string(hashBytes), nil
49+
}
50+
51+
func attestationFromCertificate(cert *x509.Certificate, enclaveHost string) (*attestation.Document, string, error) {
3152
pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey)
3253
if !ok {
3354
return nil, "", fmt.Errorf("public key is not an ECDSA key")
3455
}
3556
keyFP := tlsutil.KeyFP(pubKey)
3657

3758
var attDomains []string
59+
var hashAttDomains []string
3860
for _, name := range cert.DNSNames {
3961
if strings.HasSuffix(name, ".att.tinfoil.sh") {
4062
attDomains = append(attDomains, name)
4163
log.Debugf("Attestation domain: %s", name)
64+
} else if strings.HasSuffix(name, ".hatt.tinfoil.sh") {
65+
hashAttDomains = append(hashAttDomains, name)
66+
log.Debugf("Hash attestation domain: %s", name)
4267
}
4368
}
4469

45-
if len(attDomains) == 0 {
46-
return nil, "", fmt.Errorf("no attestation domains found in certificate")
70+
if len(attDomains) > 0 {
71+
att, err := dcode.Decode(attDomains)
72+
if err != nil {
73+
return nil, "", fmt.Errorf("failed to decode attestation: %v", err)
74+
}
75+
return att, keyFP, nil
4776
}
4877

49-
att, err := dcode.Decode(attDomains)
50-
if err != nil {
51-
return nil, "", fmt.Errorf("failed to decode attestation: %v", err)
78+
if len(hashAttDomains) > 0 {
79+
if enclaveHost == "" {
80+
return nil, "", fmt.Errorf("certificate contains only hash attestation domains; use -s flag to specify server for attestation fetch")
81+
}
82+
83+
certAttHash, err := decodeHashDomains(hashAttDomains)
84+
if err != nil {
85+
return nil, "", fmt.Errorf("failed to decode hash attestation: %v", err)
86+
}
87+
log.Debugf("Certificate attestation hash: %s", certAttHash)
88+
89+
att, err := attestation.Fetch(enclaveHost)
90+
if err != nil {
91+
return nil, "", fmt.Errorf("failed to fetch attestation from server: %v", err)
92+
}
93+
serverAttHash := att.Hash()
94+
log.Debugf("Server attestation hash: %s", serverAttHash)
95+
96+
if certAttHash != serverAttHash {
97+
return nil, "", fmt.Errorf("attestation hash mismatch: cert=%s server=%s", certAttHash, serverAttHash)
98+
}
99+
log.Infof("Attestation hash verified: %s", certAttHash)
100+
return att, keyFP, nil
52101
}
53-
return att, keyFP, nil
102+
103+
return nil, "", fmt.Errorf("no attestation domains found in certificate")
54104
}
55105

56106
var certificateAuditCmd = &cobra.Command{
57107
Use: "certificate audit",
58108
Short: "Audit enclave certificate",
59109
Run: func(cmd *cobra.Command, args []string) {
60110
var cert *x509.Certificate
111+
var enclaveHost string
61112
if certFile != "" {
62113
certBytes, err := os.ReadFile(certFile)
63114
if err != nil {
@@ -75,11 +126,13 @@ var certificateAuditCmd = &cobra.Command{
75126
if server == "" {
76127
log.Fatal("Server address is required")
77128
}
78-
if !strings.Contains(server, ":") {
79-
server += ":443"
129+
enclaveHost = strings.TrimSuffix(server, ":443")
130+
serverAddr := server
131+
if !strings.Contains(serverAddr, ":") {
132+
serverAddr += ":443"
80133
}
81134

82-
conn, err := tls.Dial("tcp", server, nil)
135+
conn, err := tls.Dial("tcp", serverAddr, nil)
83136
if err != nil {
84137
log.Fatalf("Failed to connect to server: %v", err)
85138
}
@@ -91,7 +144,7 @@ var certificateAuditCmd = &cobra.Command{
91144
cert = certs[0]
92145
}
93146

94-
att, certKeyFP, err := attestationFromCertificate(cert)
147+
att, certKeyFP, err := attestationFromCertificate(cert, enclaveHost)
95148
if err != nil {
96149
log.Fatalf("Failed to get attestation from certificate: %v", err)
97150
}

0 commit comments

Comments
 (0)