Skip to content

Commit 9547cd7

Browse files
yzz127arvind5
authored andcommitted
CASSINI-8033: Support Azure TDX report generation in Amber client CLI (intel#43)
1 parent 07d6011 commit 9547cd7

File tree

2 files changed

+208
-0
lines changed

2 files changed

+208
-0
lines changed

go-tdx/azure_adapter.go

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
//go:build !test
2+
3+
/*
4+
* Copyright (c) 2023 Intel Corporation
5+
* All rights reserved.
6+
* SPDX-License-Identifier: BSD-3-Clause
7+
*/
8+
package tdx
9+
10+
import (
11+
"bytes"
12+
"crypto/sha512"
13+
"encoding/base64"
14+
"encoding/json"
15+
"io"
16+
"net/http"
17+
"syscall"
18+
"unsafe"
19+
20+
"github.com/intel/trustauthority-client/go-connector"
21+
"github.com/pkg/errors"
22+
)
23+
24+
// AzureAdapter manages TDX Quote collection from Azure TDX platform
25+
type azureAdapter struct {
26+
uData []byte
27+
EvLogParser EventLogParser
28+
}
29+
30+
// NewEvidenceAdapter returns a new Azure Adapter instance
31+
func NewEvidenceAdapter(udata []byte, evLogParser EventLogParser) (connector.EvidenceAdapter, error) {
32+
return &azureAdapter{
33+
uData: udata,
34+
EvLogParser: evLogParser,
35+
}, nil
36+
}
37+
38+
type QuoteRequest struct {
39+
Report string `json:"report"`
40+
}
41+
42+
type QuoteResponse struct {
43+
Quote string `json:"quote"`
44+
}
45+
46+
func IOC(dir, t, nr, size uintptr) uintptr {
47+
return (dir << IocDirshift) |
48+
(t << IocTypeShift) |
49+
(nr << IocNrShift) |
50+
(size << IocSizeShift)
51+
}
52+
53+
func IOWR(t, nr, size uintptr) uintptr {
54+
return IOC(IocRead|IocWrite, t, nr, size)
55+
}
56+
57+
func TdxCmdGetReportIO() uintptr {
58+
return IOWR('T', 1, TdxReportDataLen+TdxReportLen)
59+
}
60+
61+
// CollectEvidence is used to get TDX quote using Azure Quote Generation service
62+
func (adapter *azureAdapter) CollectEvidence(nonce []byte) (*connector.Evidence, error) {
63+
64+
hash := sha512.New()
65+
_, err := hash.Write(nonce)
66+
if err != nil {
67+
return nil, err
68+
}
69+
_, err = hash.Write(adapter.uData)
70+
if err != nil {
71+
return nil, err
72+
}
73+
reportData := hash.Sum(nil)
74+
75+
var tdrequest TdxReportRequest
76+
copy(tdrequest.ReportData[:], []byte(reportData))
77+
78+
fd, err := syscall.Open(TdxAttestDevPath, syscall.O_RDWR|syscall.O_SYNC, 0)
79+
if err != nil {
80+
return nil, err
81+
}
82+
defer syscall.Close(fd)
83+
84+
cmd := TdxCmdGetReportIO()
85+
_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), cmd, uintptr(unsafe.Pointer(&tdrequest)))
86+
if errno != 0 {
87+
return nil, syscall.Errno(errno)
88+
}
89+
90+
report := make([]byte, TdReportSize)
91+
copy(report, tdrequest.TdReport[:])
92+
93+
quote, err := getQuote(report)
94+
if err != nil {
95+
return nil, errors.Errorf("getQuote return error %v", err)
96+
}
97+
98+
var eventLog []byte
99+
if adapter.EvLogParser != nil {
100+
rtmrEventLogs, err := adapter.EvLogParser.GetEventLogs()
101+
if err != nil {
102+
return nil, errors.Wrap(err, "There was an error while collecting RTMR Event Log Data")
103+
}
104+
105+
eventLog, err = json.Marshal(rtmrEventLogs)
106+
if err != nil {
107+
return nil, errors.Wrap(err, "Error while marshalling RTMR Event Log Data")
108+
}
109+
}
110+
111+
return &connector.Evidence{
112+
Type: 1,
113+
Evidence: quote,
114+
UserData: adapter.uData,
115+
EventLog: eventLog,
116+
}, nil
117+
}
118+
119+
func getQuote(report []byte) ([]byte, error) {
120+
121+
quoteReq := &QuoteRequest{
122+
Report: base64.URLEncoding.EncodeToString(report),
123+
}
124+
125+
body, err := json.Marshal(quoteReq)
126+
if err != nil {
127+
return nil, err
128+
}
129+
130+
req, err := http.NewRequest(http.MethodPost, "http://169.254.169.254/acc/tdquote", bytes.NewReader(body))
131+
if err != nil {
132+
return nil, err
133+
}
134+
req.Header.Add("Content-Type", "application/json")
135+
136+
httpClient := http.DefaultClient
137+
resp, err := httpClient.Do(req)
138+
if err != nil {
139+
return nil, errors.Wrapf(err, "Request to %q failed", req.URL)
140+
}
141+
142+
if resp != nil {
143+
defer func() {
144+
err := resp.Body.Close()
145+
if err != nil {
146+
errors.Errorf("Failed to close response body")
147+
}
148+
}()
149+
}
150+
151+
response, err := io.ReadAll(resp.Body)
152+
if err != nil {
153+
return nil, errors.Errorf("Failed to read response body: %s", err)
154+
}
155+
156+
if resp.StatusCode != http.StatusOK || resp.ContentLength == 0 {
157+
return nil, errors.Errorf("Request to %q failed: StatusCode = %d, Response = %s", req.URL, resp.StatusCode, string(response))
158+
}
159+
160+
var quoteRes QuoteResponse
161+
err = json.Unmarshal(response, &quoteRes)
162+
if err != nil {
163+
return nil, errors.Wrap(err, "Error unmarshalling Quote response from azure")
164+
}
165+
166+
quote, err := base64.RawURLEncoding.DecodeString(quoteRes.Quote)
167+
if err != nil {
168+
return nil, errors.Wrap(err, "Error decoding Quote from azure")
169+
}
170+
return quote, nil
171+
}

go-tdx/constants.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//go:build !test
2+
3+
/*
4+
* Copyright (c) 2023 Intel Corporation
5+
* All rights reserved.
6+
* SPDX-License-Identifier: BSD-3-Clause
7+
*/
8+
package tdx
9+
10+
const (
11+
TdxReportDataLen = 64
12+
TdxReportLen = 1024
13+
TdxAttestDevPath = "/dev/tdx_guest"
14+
15+
TdxGetReportSuccess = 0
16+
TdxGetReportFailed = -1
17+
18+
TdReportSize = 1024
19+
TdQuoteMaxSize = 8192
20+
)
21+
22+
type TdxReportRequest struct {
23+
ReportData [TdxReportDataLen]byte
24+
TdReport [TdxReportLen]byte
25+
}
26+
27+
const (
28+
IocNrBits = 8
29+
IocTypeBits = 8
30+
IocSizeBits = 14
31+
IocNrShift = 0
32+
IocWrite uintptr = 1
33+
IocRead uintptr = 2
34+
IocTypeShift = IocNrShift + IocNrBits
35+
IocSizeShift = IocTypeShift + IocTypeBits
36+
IocDirshift = IocSizeShift + IocSizeBits
37+
)

0 commit comments

Comments
 (0)