/
client.go
156 lines (130 loc) · 4.26 KB
/
client.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Package client implements the Oasis IAS proxy client endpoint.
package client
import (
"context"
"crypto/tls"
"fmt"
"strings"
"google.golang.org/grpc"
"google.golang.org/grpc/resolver"
"google.golang.org/grpc/resolver/manual"
"github.com/oasisprotocol/oasis-core/go/common/crypto/signature"
cmnGrpc "github.com/oasisprotocol/oasis-core/go/common/grpc"
"github.com/oasisprotocol/oasis-core/go/common/identity"
"github.com/oasisprotocol/oasis-core/go/common/logging"
"github.com/oasisprotocol/oasis-core/go/common/sgx/ias"
"github.com/oasisprotocol/oasis-core/go/ias/api"
"github.com/oasisprotocol/oasis-core/go/ias/proxy"
)
var _ api.Endpoint = (*proxyClient)(nil)
type proxyClient struct {
identity *identity.Identity
conn *grpc.ClientConn
endpoint api.Endpoint
spidInfo *api.SPIDInfo
logger *logging.Logger
}
func (c *proxyClient) fetchSPIDInfo(ctx context.Context) error {
if c.spidInfo != nil || c.endpoint == nil {
return nil
}
var err error
if c.spidInfo, err = c.endpoint.GetSPIDInfo(ctx); err != nil {
return err
}
return nil
}
func (c *proxyClient) VerifyEvidence(ctx context.Context, evidence *api.Evidence) (*ias.AVRBundle, error) {
if c.endpoint == nil {
// If the IAS proxy is not configured, generate a mock AVR, under the
// assumption that the runtime is built to support this. The runtime
// will reject the mock AVR if it is not.
avr, err := ias.NewMockAVR(evidence.Quote, evidence.Nonce)
if err != nil {
return nil, err
}
return &ias.AVRBundle{
Body: avr,
}, nil
}
// Ensure the evidence.Quote passes basic sanity/security checks before
// even bothering to contact the backend.
var untrustedQuote ias.Quote
if err := untrustedQuote.UnmarshalBinary(evidence.Quote); err != nil {
return nil, err
}
if err := untrustedQuote.Verify(); err != nil {
return nil, err
}
return c.endpoint.VerifyEvidence(ctx, evidence)
}
func (c *proxyClient) GetSPIDInfo(ctx context.Context) (*api.SPIDInfo, error) {
if err := c.fetchSPIDInfo(ctx); err != nil {
return nil, err
}
return c.spidInfo, nil
}
func (c *proxyClient) GetSigRL(ctx context.Context, epidGID uint32) ([]byte, error) {
if c.endpoint == nil {
return nil, fmt.Errorf("IAS proxy is not configured, mock used")
}
return c.endpoint.GetSigRL(ctx, epidGID)
}
func (c *proxyClient) Cleanup() {
if c.conn != nil {
_ = c.conn.Close()
}
}
// New creates a new IAS proxy client endpoint.
func New(identity *identity.Identity, addresses []string) (api.Endpoint, error) {
c := &proxyClient{
identity: identity,
logger: logging.GetLogger("ias/proxyclient"),
}
if len(addresses) == 0 {
c.logger.Warn("IAS proxy is not configured, all reports will be mocked")
c.spidInfo = &api.SPIDInfo{}
_ = c.spidInfo.SPID.UnmarshalBinary(make([]byte, ias.SPIDSize))
} else {
var resolverState resolver.State
pubKeys := make(map[signature.PublicKey]bool)
for _, addr := range addresses {
spl := strings.Split(addr, "@")
if len(spl) != 2 {
return nil, fmt.Errorf("missing public key in address '%s'", addr)
}
var pk signature.PublicKey
if err := pk.UnmarshalText([]byte(spl[0])); err != nil {
return nil, fmt.Errorf("malformed public key in address '%s': %w", addr, err)
}
pubKeys[pk] = true
resolverState.Addresses = append(resolverState.Addresses, resolver.Address{Addr: spl[1]})
}
creds, err := cmnGrpc.NewClientCreds(&cmnGrpc.ClientOptions{
ServerPubKeys: pubKeys,
CommonName: proxy.CommonName,
GetClientCertificate: func(cri *tls.CertificateRequestInfo) (*tls.Certificate, error) {
return identity.GetTLSCertificate(), nil
},
})
if err != nil {
return nil, fmt.Errorf("failed to create client credentials: %w", err)
}
manualResolver := manual.NewBuilderWithScheme("oasis-core-resolver")
conn, err := cmnGrpc.Dial(
"oasis-core-resolver:///",
grpc.WithTransportCredentials(creds),
// https://github.com/grpc/grpc-go/issues/3003
grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`),
grpc.WithDefaultCallOptions(grpc.WaitForReady(true)),
grpc.WithResolvers(manualResolver),
)
if err != nil {
return nil, fmt.Errorf("failed to dial IAS proxy: %w", err)
}
manualResolver.UpdateState(resolverState)
c.conn = conn
c.endpoint = api.NewEndpointClient(conn)
}
return c, nil
}