@@ -66,6 +66,10 @@ type VerifyOpts struct {
66
66
// "Calling EFI Application from Boot Option". This option is useful when
67
67
// the host platform loads EFI Applications unrelated to OS boot.
68
68
AllowEFIAppBeforeCallingEvent bool
69
+ // HashNonce will apply the attestation key's signing scheme hash algorithm
70
+ // to the input Nonce field and use the resulting digest in place of the
71
+ // original Nonce.
72
+ HashNonce bool
69
73
}
70
74
71
75
// Bootloader refers to the second-stage bootloader that loads and transfers
@@ -114,16 +118,24 @@ func VerifyAttestation(attestation *pb.Attestation, opts VerifyOpts) (*pb.Machin
114
118
return nil , fmt .Errorf ("bad options: %w" , err )
115
119
}
116
120
117
- machineState , akPubKey , err := validateAK (attestation , opts )
121
+ machineState , akPub , akPubKey , err := validateAK (attestation , opts )
118
122
if err != nil {
119
123
return nil , fmt .Errorf ("failed to parse and validate AK: %w" , err )
120
124
}
125
+ extraData := opts .Nonce
126
+ if opts .HashNonce {
127
+ var err error
128
+ extraData , err = internal .HashNonce (akPub , extraData )
129
+ if err != nil {
130
+ return nil , fmt .Errorf ("failed to hash the input nonce: %w" , err )
131
+ }
132
+ }
121
133
122
134
// Attempt to replay the log against our PCRs in order of hash preference
123
135
var lastErr error
124
136
for _ , quote := range supportedQuotes (attestation .GetQuotes ()) {
125
137
// Verify the Quote
126
- if err := internal .VerifyQuote (quote , akPubKey , opts . Nonce ); err != nil {
138
+ if err := internal .VerifyQuote (quote , akPubKey , extraData ); err != nil {
127
139
lastErr = fmt .Errorf ("failed to verify quote: %w" , err )
128
140
continue
129
141
}
@@ -158,44 +170,48 @@ func VerifyAttestation(attestation *pb.Attestation, opts VerifyOpts) (*pb.Machin
158
170
159
171
// validateAK validates AK cert in the attestation, and returns AK cert (if exists) and public key.
160
172
// It also pulls out the GCE Instance Info if it exists.
161
- func validateAK (attestation * pb.Attestation , opts VerifyOpts ) (* pb.MachineState , crypto.PublicKey , error ) {
173
+ func validateAK (attestation * pb.Attestation , opts VerifyOpts ) (* pb.MachineState , tpm2.Public , crypto.PublicKey , error ) {
174
+ // If the AK Cert is not in the attestation, use the AK Public Area.
175
+ akPubArea , err := tpm2 .DecodePublic (attestation .GetAkPub ())
176
+ if err != nil {
177
+ return nil , tpm2.Public {}, nil , fmt .Errorf ("failed to decode AK public area: %w" , err )
178
+ }
179
+ akPubKey , err := akPubArea .Key ()
180
+ if err != nil {
181
+ return nil , tpm2.Public {}, nil , fmt .Errorf ("failed to get AK public key: %w" , err )
182
+ }
162
183
if len (attestation .GetAkCert ()) == 0 || len (opts .TrustedRootCerts ) == 0 {
163
- // If the AK Cert is not in the attestation, use the AK Public Area.
164
- akPubArea , err := tpm2 .DecodePublic (attestation .GetAkPub ())
165
- if err != nil {
166
- return nil , nil , fmt .Errorf ("failed to decode AK public area: %w" , err )
167
- }
168
- akPubKey , err := akPubArea .Key ()
169
- if err != nil {
170
- return nil , nil , fmt .Errorf ("failed to get AK public key: %w" , err )
171
- }
172
184
if err := validateAKPub (akPubKey , opts ); err != nil {
173
- return nil , nil , fmt .Errorf ("failed to validate AK public key: %w" , err )
185
+ return nil , tpm2. Public {}, nil , fmt .Errorf ("failed to validate AK public key: %w" , err )
174
186
}
175
- return & pb.MachineState {}, akPubKey , nil
187
+ return & pb.MachineState {}, akPubArea , akPubKey , nil
176
188
}
177
189
178
190
// If AK Cert is presented, ignore the AK Public Area.
179
191
akCert , err := x509 .ParseCertificate (attestation .GetAkCert ())
192
+ certPubKey := akCert .PublicKey .(crypto.PublicKey ) // This cast cannot fail
193
+ if ! internal .PubKeysEqual (certPubKey , akPubKey ) {
194
+ return nil , tpm2.Public {}, nil , errors .New ("AK certificate does not match key" )
195
+ }
180
196
if err != nil {
181
- return nil , nil , fmt .Errorf ("failed to parse AK certificate: %w" , err )
197
+ return nil , tpm2. Public {}, nil , fmt .Errorf ("failed to parse AK certificate: %w" , err )
182
198
}
183
199
// Use intermediate certs from the attestation if they exist.
184
200
certs , err := parseCerts (attestation .IntermediateCerts )
185
201
if err != nil {
186
- return nil , nil , fmt .Errorf ("attestation intermediates: %w" , err )
202
+ return nil , tpm2. Public {}, nil , fmt .Errorf ("attestation intermediates: %w" , err )
187
203
}
188
204
opts .IntermediateCerts = append (opts .IntermediateCerts , certs ... )
189
205
190
206
if err := VerifyAKCert (akCert , opts .TrustedRootCerts , opts .IntermediateCerts ); err != nil {
191
- return nil , nil , fmt .Errorf ("failed to validate AK certificate: %w" , err )
207
+ return nil , tpm2. Public {}, nil , fmt .Errorf ("failed to validate AK certificate: %w" , err )
192
208
}
193
209
instanceInfo , err := getInstanceInfoFromExtensions (akCert .Extensions )
194
210
if err != nil {
195
- return nil , nil , fmt .Errorf ("error getting instance info: %v" , err )
211
+ return nil , tpm2. Public {}, nil , fmt .Errorf ("error getting instance info: %v" , err )
196
212
}
197
213
198
- return & pb.MachineState {Platform : & pb.PlatformState {InstanceInfo : instanceInfo }}, akCert .PublicKey , nil
214
+ return & pb.MachineState {Platform : & pb.PlatformState {InstanceInfo : instanceInfo }}, akPubArea , akCert .PublicKey , nil
199
215
}
200
216
201
217
// GetGCEInstanceInfo takes a GCE-issued x509 EK/AK certificate and tries to
0 commit comments