@@ -10,6 +10,10 @@ import (
10
10
"fmt"
11
11
"log"
12
12
"net/http"
13
+ "net/http/httputil"
14
+ "net/url"
15
+ "os"
16
+ "strings"
13
17
14
18
"github.com/caddyserver/certmagic"
15
19
"github.com/google/go-sev-guest/abi"
@@ -18,13 +22,33 @@ import (
18
22
"github.com/tinfoilanalytics/verifier/pkg/attestation"
19
23
)
20
24
25
+ var version = "dev"
26
+
21
27
var (
22
28
listenAddr = flag .String ("l" , ":443" , "listen address" )
23
- domain = flag .String ("d" , "" , "TLS domain name" )
24
- email = flag .String ("e" , "" , "TLS email address" )
25
29
staging = flag .Bool ("s" , false , "use staging CA" )
30
+ upstream = flag .Int ("u" , 8080 , "upstream port" )
31
+
32
+
26
33
)
27
34
35
+ // cmdlineParam returns the value of a parameter from the kernel command line
36
+ func cmdlineParam (key string ) (string , error ) {
37
+ cmdline , err := os .ReadFile ("/proc/cmdline" )
38
+ if err != nil {
39
+ return "" , err
40
+ }
41
+
42
+ for _ , p := range strings .Split (string (cmdline ), " " ) {
43
+ if strings .HasPrefix (p , key + "=" ) {
44
+ return strings .TrimPrefix (p , key + "=" ), nil
45
+ }
46
+ }
47
+
48
+ return "" , fmt .Errorf ("missing %s" , key )
49
+ }
50
+
51
+ // attestationReport gets a SEV-SNP signed attestation report over a TLS certificate fingerprint
28
52
func attestationReport (certFP string ) (* attestation.Document , error ) {
29
53
var userData [64 ]byte
30
54
copy (userData [:], certFP )
@@ -48,44 +72,69 @@ func attestationReport(certFP string) (*attestation.Document, error) {
48
72
}, nil
49
73
}
50
74
75
+ func cors (w http.ResponseWriter , r * http.Request ) {
76
+ w .Header ().Set ("Access-Control-Allow-Origin" , "*" )
77
+ w .Header ().Set ("Access-Control-Allow-Methods" , "*" )
78
+ w .Header ().Set ("Access-Control-Allow-Headers" , "*" )
79
+
80
+ if r .Method == "OPTIONS" {
81
+ w .WriteHeader (http .StatusOK )
82
+ return
83
+ }
84
+ }
85
+
51
86
func main () {
52
87
flag .Parse ()
53
- if * domain == "" {
54
- log .Fatal ("domain is required" )
55
- }
56
- if * email == "" {
57
- log .Fatal ("email is required" )
88
+
89
+ domain , err := cmdlineParam ("tinfoil-domain" )
90
+ if err != nil {
91
+ log .Fatal (err )
58
92
}
59
93
94
+ log .Printf ("Starting SEV-SNP attestation shim %s domain %s" , version , domain )
95
+
60
96
mux := http .NewServeMux ()
61
97
62
- certmagic .DefaultACME .Email = * email
98
+ // Request TLS certificate
99
+ certmagic .DefaultACME .Email = email
63
100
if * staging {
64
101
certmagic .DefaultACME .CA = certmagic .LetsEncryptStagingCA
65
102
} else {
66
103
certmagic .DefaultACME .CA = certmagic .LetsEncryptProductionCA
67
104
}
68
- tlsConfig , err := certmagic .TLS ([]string {* domain })
105
+ tlsConfig , err := certmagic .TLS ([]string {domain })
69
106
if err != nil {
70
107
log .Fatalf ("Failed to get TLS config: %v" , err )
71
108
}
72
109
110
+ // Get certificate from TLS config
73
111
cert , err := tlsConfig .GetCertificate (& tls.ClientHelloInfo {
74
- ServerName : * domain ,
112
+ ServerName : domain ,
75
113
})
76
114
if err != nil {
77
115
log .Fatalf ("Failed to get certificate: %v" , err )
78
116
}
79
117
certFP := sha256 .Sum256 (cert .Leaf .Raw )
80
118
certFPHex := hex .EncodeToString (certFP [:])
81
119
120
+ // Request SEV-SNP attestation
82
121
log .Printf ("Fetching attestation over %s" , certFPHex )
83
122
att , err := attestationReport (certFPHex )
84
123
if err != nil {
85
124
log .Fatal (err )
86
125
}
87
126
88
127
mux .HandleFunc ("/" , func (w http.ResponseWriter , r * http.Request ) {
128
+ cors (w , r )
129
+ proxy := httputil .NewSingleHostReverseProxy (& url.URL {
130
+ Scheme : "http" ,
131
+ Host : fmt .Sprintf ("localhost:%d" , * upstream ),
132
+ })
133
+ proxy .ServeHTTP (w , r )
134
+ })
135
+
136
+ mux .HandleFunc ("/.well-known/tinfoil-attestation" , func (w http.ResponseWriter , r * http.Request ) {
137
+ cors (w , r )
89
138
w .WriteHeader (http .StatusOK )
90
139
w .Header ().Set ("Content-Type" , "application/json" )
91
140
json .NewEncoder (w ).Encode (att )
0 commit comments