-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathcmds_object.go
723 lines (692 loc) · 42.1 KB
/
cmds_object.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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
// Copyright 2019 Canonical Ltd.
// Licensed under the LGPLv3 with static-linking exception.
// See LICENCE file for details.
package tpm2
// Section 12 - Object Commands
import (
"errors"
"fmt"
"github.com/canonical/go-tpm2/mu"
)
// Create executes the TPM2_Create command to create a new ordinary object as a child of the
// storage parent associated with parentContext.
//
// The command requires authorization with the user auth role for parentContext, with session based
// authorization provided via parentContextAuthSession.
//
// A template for the object is provided via the inPublic parameter. The Type field of inPublic
// defines the algorithm for the object. The NameAlg field defines the digest algorithm for
// computing the name of the object. The Attrs field defines the attributes of the object. The
// AuthPolicy field allows an authorization policy to be defined for the new object.
//
// Data that will form part of the sensitive area of the object can be provided via inSensitive,
// which is optional.
//
// If the Attrs field of inPublic does not have the [AttrSensitiveDataOrigin] attribute set, then
// the sensitive data in the created object is initialized with the data provided via the Data
// field of inSensitive.
//
// If the Attrs field of inPublic has the [AttrSensitiveDataOrigin] attribute set and Type is
// [ObjectTypeSymCipher], then the sensitive data in the created object is initialized with a TPM
// generated key. The size of this key is determined by the symmetric algorithm defined in the
// Params field of inPublic. If Type is [ObjectTypeKeyedHash], then the sensitive data in the
// created object is initialized with a TPM generated value that is the same size as the name
// algorithm selected by the NameAlg field of inPublic.
//
// If the Type field of inPublic is [ObjectTypeRSA] or [ObjectTypeECC], then the sensitive data
// in the created object is initialized with a TPM generated private key. The size of this is
// determined by the asymmetric algorithm defined in the Params field of inPublic.
//
// If the Type field of inPublic is [ObjectTypeKeyedHash] and the Attrs field has
// [AttrSensitiveDataOrigin], [AttrSign] and [AttrDecrypt] all clear, then the created object is a
// sealed data object.
//
// If the Attrs field of inPublic has the [AttrRestricted] and [AttrDecrypt] attributes set, and
// the Type field is not [ObjectTypeKeyedHash], then the newly created object will be a storage
// parent.
//
// If the Attrs field of inPublic has the [AttrRestricted] and [AttrDecrypt] attributes set, and
// the Type field is [ObjectTypeKeyedHash], then the newly created object will be a derivation
// parent.
//
// The authorization value for the created object is initialized to the value of the UserAuth field
// of inSensitive.
//
// If the object associated with parentContext is not a valid storage parent object, a
// *[TPMHandleError] error with an error code of [ErrorType] will be returned for handle index 1.
//
// If there are no available slots for new objects on the TPM, a *[TPMWarning] error with a warning
// code of [WarningObjectMemory] will be returned.
//
// If the Attrs field of inPublic as the [AttrSensitiveDataOrigin] attribute set and the Data field
// of inSensitive has a non-zero size, or the [AttrSensitiveDataOrigin] attribute is clear and the
// Data field of inSensitive has a zero size, a *[TPMParameterError] error with an error code of
// [ErrorAttributes] will be returned for parameter index 1.
//
// If the attributes in the Attrs field of inPublic are inconsistent or inappropriate for the
// usage, a *[TPMParameterError] error with an error code of [ErrorAttributes] will be returned for
// parameter index 2.
//
// If the NameAlg field of inPublic is [HashAlgorithmNull], then a *[TPMParameterError] error with
// an error code of [ErrorHash] will be returned for parameter index 2.
//
// If an authorization policy is defined via the AuthPolicy field of inPublic then the length of
// the digest must match the name algorithm selected via the NameAlg field, else a
// *[TPMParameterError] error with an error code of [ErrorSize] is returned for parameter index 2.
//
// If the scheme in the Params field of inPublic is inappropriate for the usage, a
// *[TPMParameterError] error with an error code of [ErrorScheme] will be returned for parameter
// index 2.
//
// If the Type field of inPublic is [ObjectTypeRSA], [ObjectTypeECC] or [ObjectTypeKeyedHash] and
// the digest algorithm specified by the scheme in the Params field of inPublic is inappropriate
// for the usage, a *[TPMParameterError] error with an error code of [ErrorHash] will be returned
// for parameter index 2.
//
// If the Type field of inPublic is not [ObjectTypeKeyedHash], a *[TPMParameterError] error with an
// error code of [ErrorSymmetric] will be returned for parameter index 2 if the symmetric algorithm
// specified in the Params field of inPublic is inappropriate for the usage.
//
// If the Type field of inPublic is [ObjectTypeECC] and the KDF scheme specified in the Params
// field of inPublic is not [KDFAlgorithmNull], a *[TPMParameterError] error with an error code of
// [ErrorKDF] will be returned for parameter index 2.
//
// If the Type field of inPublic is not [ObjectTypeKeyedHash] and the [AttrRestricted],
// [AttrFixedParent] and [AttrDecrypt] attributes of Attrs are set, a *[TPMParameterError] error
// with an error code of [ErrorHash] will be returned for parameter index 2 if the NameAlg field of
// inPublic does not select the same name algorithm as the parent object. A *[TPMParameterError]
// error with an error code of [ErrorSymmetric] will be returned for parameter index 2 if the
// symmetric algorithm specified in the Params field of inPublic does not match the symmetric
// algorithm of the parent object.
//
// If the length of the UserAuth field of inSensitive is longer than the name algorithm selected by
// the NameAlg field of inPublic, a *[TPMParameterError] error with an error code of [ErrorSize]
// will be returned for parameter index 1.
//
// If the Type field of inPublic is [ObjectTypeRSA] and the Params field specifies an unsupported
// exponent, a *[TPMError] with an error code of [ErrorRange] will be returned. If the specified
// key size is an unsupported value, a *[TPMError] with an error code of [ErrorValue] will be
// returned.
//
// If the Type field of inPublic is [ObjectTypeSymCipher] and the key size is an unsupported value,
// a *[TPMError] with an error code of [ErrorKeySize] will be returned. If the
// [AttrSensitiveDataOrigin] attribute is not set and the length of the Data field of inSensitive
// does not match the key size specified in the Params field of inPublic, a *[TPMError] with an
// error code of [ErrorKeySize] will be returned.
//
// If the Type field of inPublic is [ObjectTypeKeyedHash] and the [AttrSensitiveDataOrigin]
// attribute is not set, a *[TPMError] with an error code of [ErrorSize] will be returned if the
// length of the Data field of inSensitive is longer than permitted for the digest algorithm
// selected by the specified scheme.
//
// This function will call [TPMContext.InitProperties] if it hasn't already been called.
//
// On success, the private and public parts of the newly created object will be returned. The newly
// created object will not exist on the TPM. If the Type field of inPublic is [ObjectTypeKeyedHash]
// or [ObjectTypeSymCipher], then the returned *Public object will have a Unique field that is the
// digest of the sensitive data and the value of the object's seed in the sensitive area, computed
// using the object's name algorithm. If the Type field of inPublic is [ObjectTypeECC] or
// [ObjectTypeRSA], then the returned *Public object will have a Unique field containing details
// about the public part of the key, computed from the private part of the key.
//
// The returned *CreationData will contain a digest computed from the values of PCRs selected by
// the creationPCR parameter at creation time in the PCRDigest field. It will also contain the
// provided outsideInfo in the OutsideInfo field. The returned *TkCreation ticket can be used to
// prove the association between the created object and the returned *CreationData via the
// [TPMContext.CertifyCreation] method.
func (t *TPMContext) Create(parentContext ResourceContext, inSensitive *SensitiveCreate, inPublic *Public, outsideInfo Data, creationPCR PCRSelectionList, parentContextAuthSession SessionContext, sessions ...SessionContext) (outPrivate Private, outPublic *Public, creationData *CreationData, creationHash Digest, creationTicket *TkCreation, err error) {
if err := t.initPropertiesIfNeeded(); err != nil {
return nil, nil, nil, nil, nil, err
}
if inSensitive == nil {
inSensitive = &SensitiveCreate{}
}
if err := t.StartCommand(CommandCreate).
AddHandles(UseResourceContextWithAuth(parentContext, parentContextAuthSession)).
AddParams(mu.Sized(inSensitive), mu.Sized(inPublic), outsideInfo, creationPCR.WithMinSelectSize(t.properties.minPcrSelectSize)).
AddExtraSessions(sessions...).
Run(nil, &outPrivate, mu.Sized(&outPublic), mu.Sized(&creationData), &creationHash, &creationTicket); err != nil {
return nil, nil, nil, nil, nil, err
}
return outPrivate, outPublic, creationData, creationHash, creationTicket, nil
}
// Load executes the TPM2_Load command in order to load both the public and private parts of an
// object in to the TPM.
//
// The parentContext parameter corresponds to the parent key. The command requires authorization
// with the user auth role for parentContext, with session based authorization provided via
// parentContextAuthSession.
//
// The object to load is specified by providing the inPrivate and inPublic arguments.
//
// If there are no available slots for new objects on the TPM, a *[TPMWarning] error with a warning
// code of [WarningObjectMemory] will be returned.
//
// If inPrivate is empty, a *[TPMParameterError] error with an error code of [ErrorSize] will be
// returned for parameter index 1.
//
// If parentContext does not correspond to a storage parent, a *[TPMHandleError] error with an
// error code of [ErrorType] will be returned.
//
// If the name algorithm associated with inPublic is invalid, a *[TPMParameterError] error with an
// error code of [ErrorHash] will be returned for parameter index 2.
//
// If the integrity value or IV for inPrivate cannot be unmarshalled correctly, a
// *[TPMParameterError] error with an error code of either [ErrorSize] or [ErrorInsufficient] will
// be returned for parameter index 1. If the integrity check of inPrivate fails, a
// *[TPMParameterError] error with an error code of [ErrorIntegrity] will be returned for parameter
// index 1. If the size of the IV for inPrivate doesn't match the block size for the encryption
// algorithm, a *[TPMParameterError] error with an error code of [ErrorValue] will be returned for
// parameter index 1.
//
// TPM2_Load performs many of the same validations of the public attributes as TPM2_Create, and may
// return similar error codes as *[TPMParameterError] for parameter index 2.
//
// If the object associated with parentContext has the [AttrFixedTPM] attribute clear, some
// additional validation of the decrypted sensitive data is performed as detailed below.
//
// If the Type field of inPublic does not match the type specified in the sensitive data, a
// *[TPMParameterError] error with an error code of [ErrorType] is returned for parameter index 1.
// If the authorization value in the sensitive area is larger than the name algorithm, a
// *[TPMParameterError] error with an error code of [ErrorSize] is returned for parameter index 1.
//
// If the Type field of inPublic is [ObjectTypeRSA] and the size of the modulus in the Unique field
// is inconsistent with the size specified in the Params field, a *[TPMParameterError] error with
// an error code of [ErrorKey] will be returned for parameter index 2. If the value of the exponent
// in the Params field is invalid, a *[TPMParameterError] error with an error code of [ErrorValue]
// will be returned for parameter index 2. If the size of private key in the sensitive area is not
// the correct size, a *[TPMParameterError] error with an error code of [ErrorKeySize] will be
// returned for parameter index 1.
//
// If the Type field of inPublic is [ObjectTypeECC] and the private key in the sensitive area is
// invalid, a *[TPMParameterError] error with an error code of [ErrorKeySize] will be returned for
// parameter index 1. If the public point specified in the Unique field of inPublic does not belong
// to the private key, a *[TPMError] with an error code of [ErrorBinding] will be returned.
//
// If the Type field of inPublic is [ObjectTypeSymCipher] and the size of the symmetric key in the
// sensitive area is inconsistent with the symmetric algorithm specified in the Params field of
// inPublic, a *[TPMParameterError] error with an error code of [ErrorKeySize] will be returned for
// parameter index 1.
//
// If the Type field of inPublic is [ObjectTypeKeyedHash] and the size of the sensitive data is
// larger than permitted for the digest algorithm selected by the scheme defined in the Params
// field of inPublic, a *[TPMParameterError] error with an error code of [ErrorKeySize] will be
// returned for parameter index 1.
//
// If the Type field of inPublic is [ObjectTypeSymCipher] or [ObjectTypeKeyedHash] and the size of
// seed value in the sensitive area does not match the name algorithm, a *[TPMError] error with an
// error code of [ErrorKeySize] will be returned. If the digest in the Unique field of inPublic is
// inconsistent with the value of the sensitive data and the seed value, a *[TPMError] with an
// error code of [ErrorBinding] will be returned.
//
// If the loaded object is a storage parent and the size of the seed value in the sensitive area
// isn't sufficient for the selected name algorithm, a *[TPMParameterError] error with an error
// code of [ErrorSize] will be returned for parameter index 1.
//
// On success, a ResourceContext corresponding to the newly loaded transient object will be
// returned. If subsequent use of the returned ResourceContext requires knowledge of the
// authorization value of the corresponding TPM resource, this should be provided by calling
// [ResourceContext].SetAuthValue. The return ResourceContext can be type asserted to [ObjectContext].
func (t *TPMContext) Load(parentContext ResourceContext, inPrivate Private, inPublic *Public, parentContextAuthSession SessionContext, sessions ...SessionContext) (objectContext ResourceContext, err error) {
var objectHandle Handle
var name Name
if err := t.StartCommand(CommandLoad).
AddHandles(UseResourceContextWithAuth(parentContext, parentContextAuthSession)).
AddParams(inPrivate, mu.Sized(inPublic)).
AddExtraSessions(sessions...).
Run(&objectHandle, &name); err != nil {
return nil, err
}
if objectHandle.Type() != HandleTypeTransient {
return nil, &InvalidResponseError{CommandLoad, fmt.Errorf("handle 0x%08x returned from TPM is the wrong type", objectHandle)}
}
if inPublic == nil {
return nil, &InvalidResponseError{CommandLoad, errors.New("expected an error because no public area was supplied")}
}
if inPublic.NameAlg.Available() && !inPublic.compareName(name) {
return nil, &InvalidResponseError{CommandLoad, errors.New("name returned from TPM not consistent with supplied public area")}
}
var public *Public
if err := mu.CopyValue(&public, inPublic); err != nil {
// if this fails then the TPM should have returned an error.
return nil, &InvalidResponseError{CommandLoad, fmt.Errorf("expected an error because the public area was invalid: %w", err)}
}
return newObjectContext(objectHandle, name, public), nil
}
// LoadExternal executes the TPM2_LoadExternal command in order to load an object that is not a
// protected object in to the TPM. The object is specified by providing the inPrivate and inPublic
// arguments, although inPrivate is optional. If only the public part is to be loaded, the
// hierarchy parameter must specify a hierarchy to associate the loaded object with so that
// tickets can be created properly. If both the public and private parts are to be loaded, then
// hierarchy should be [HandleNull].
//
// If there are no available slots for new objects on the TPM, a *[TPMWarning] error with a warning
// code of [WarningObjectMemory] will be returned.
//
// If the hierarchy specified by the hierarchy parameter is disabled, a *[TPMParameterError] error
// with an error code of [ErrorHierarchy] will be returned for parameter index 3.
//
// If inPrivate is provided and hierarchy is not [HandleNull], a *[TPMParameterError] error with an
// error code of [ErrorHierarchy] will be returned for parameter index 3.
//
// If inPrivate is provided and the Attrs field of inPublic has either [AttrFixedTPM],
// [AttrFixedParent] or [AttrRestricted] attribute set, a *[TPMParameterError] error with an error
// code of [ErrorAttributes] will be returned for parameter index 2.
//
// TPM2_LoadExternal performs many of the same validations of the public attributes as TPM2_Create,
// and may return similar error codes as *[TPMParameterError] for parameter index 2.
//
// If inPrivate is provided and the Type field of inPublic does not match the type specified in the
// sensitive data, a *[TPMParameterError] error with an error code of [ErrorType] is returned for
// parameter index 1. If the authorization value in the sensitive area is larger than the name
// algorithm, a *[TPMParameterError] error with an error code of [ErrorSize] is returned for
// parameter index 1.
//
// If the Type field of inPublic is [ObjectTypeRSA] and the size of the modulus in the Unique field
// is inconsistent with the size specified in the Params field, a *[TPMParameterError] error with
// an error code of [ErrorKey] will be returned for parameter index 2. If the value of the exponent
// in the Params field is invalid, a *[TPMParameterError] error with an error code of [ErrorValue]
// will be returned for parameter index 2. If inPrivate is provided and the size of private key in
// the sensitive area is not the correct size, a *[TPMParameterError] error with an error code of
// [ErrorKeySize] will be returned for parameter index 1.
//
// If the Type field of inPublic is [ObjectTypeECC], inPrivate is provided and the private key in
// the sensitive area is invalid, a *[TPMParameterError] error with an error code of [ErrorKeySize]
// will be returned for parameter index 1. If the public point specified in the Unique field of
// inPublic does not belong to the private key, a *[TPMError] with an error code of [ErrorBinding]
// will be returned.
//
// If the Type field of inPublic is [ObjectTypeECC], inPrivate is not provided and the size of the
// public key in the Unique field of inPublic is inconsistent with the value of the Params field of
// inPublic, a *[TPMParameterError] error with an error code of [ErrorKey] is returned for
// parameter index 2. If the public point is not on the curve specified in the Params field of
// inPublic, a *[TPMParameterError] error with an error code of [ErrorECCPoint] will be returned
// for parameter index 2.
//
// If the Type field of inPublic is [ObjectTypeSymCipher], inPrivate is provided and the size of
// the symmetric key in the sensitive area is inconsistent with the symmetric algorithm specified
// in the Params field of inPublic, a *[TPMParameterError] error with an error code of
// [ErrorKeySize] will be returned for parameter index 1.
//
// If the Type field of inPublic is [ObjectTypeKeyedHash], inPrivate is provided and the size of
// the sensitive data is larger than permitted for the digest algorithm selected by the scheme
// defined in the Params field of inPublic, a *[TPMParameterError] error with an error code of
// [ErrorKeySize] will be returned for parameter index 1.
//
// If the Type field of inPublic is [ObjectTypeSymCipher] or [ObjectTypeKeyedHash] and inPrivate
// has not been provided, a *[TPMParameterError] error with an error code of [ErrorKey] will be
// returned for parameter index 2 if the size of the digest in the Unique field of inPublic does
// not match the selected name algorithm.
//
// If the Type field of inPublic is [ObjectTypeSymCipher] or [ObjectTypeKeyedHash], inPrivate has
// been provided and the size of seed value in the sensitive area does not match the name
// algorithm, a *[TPMError] error with an error code of [ErrorKeySize] will be returned. If the
// digest in the Unique field of inPublic is inconsistent with the value of the sensitive data and
// the seed value, a *[TPMError] with an error code of [ErrorBinding] will be returned.
//
// On success, a ResourceContext corresponding to the newly loaded transient object will be
// returned. If inPrivate has been provided, it will not be necessary to call
// [ResourceContext].SetAuthValue on it - this function sets the correct authorization value so
// that it can be used in subsequent commands that require knowledge of the authorization value.
// The return ResourceContext can be type asserted to [ObjectContext].
func (t *TPMContext) LoadExternal(inPrivate *Sensitive, inPublic *Public, hierarchy Handle, sessions ...SessionContext) (objectContext ResourceContext, err error) {
var objectHandle Handle
var name Name
if err := t.StartCommand(CommandLoadExternal).
AddParams(mu.Sized(inPrivate), mu.Sized(inPublic), hierarchy).
AddExtraSessions(sessions...).
Run(&objectHandle, &name); err != nil {
return nil, err
}
if objectHandle.Type() != HandleTypeTransient {
return nil, &InvalidResponseError{CommandLoadExternal,
fmt.Errorf("handle 0x%08x returned from TPM is the wrong type", objectHandle)}
}
if inPublic == nil {
return nil, &InvalidResponseError{CommandLoadExternal, errors.New("expected an error because no public area was supplied")}
}
if inPublic.NameAlg.Available() && !inPublic.compareName(name) {
return nil, &InvalidResponseError{CommandLoadExternal, errors.New("name returned from TPM not consistent with supplied public area")}
}
var public *Public
if err := mu.CopyValue(&public, inPublic); err != nil {
// if this fails then the TPM should have returned an error.
return nil, &InvalidResponseError{CommandLoadExternal, fmt.Errorf("expected an error because the public area was invalid: %w", err)}
}
rc := newObjectContext(objectHandle, name, public)
if inPrivate != nil {
rc.authValue = make([]byte, len(inPrivate.AuthValue))
copy(rc.authValue, inPrivate.AuthValue)
}
return rc, nil
}
// ReadPublic executes the TPM2_ReadPublic command to read the public area of the object associated
// with objectContext.
//
// If objectContext corresponds to a sequence object, a *[TPMError] with an error code of
// [ErrorSequence] will be returned.
//
// On success, the public part of the object is returned, along with the object's name and
// qualified name.
func (t *TPMContext) ReadPublic(objectContext HandleContext, sessions ...SessionContext) (outPublic *Public, name Name, qualifiedName Name, err error) {
if err := t.StartCommand(CommandReadPublic).
AddHandles(UseHandleContext(objectContext)).
AddExtraSessions(sessions...).
Run(nil, mu.Sized(&outPublic), &name, &qualifiedName); err != nil {
return nil, nil, nil, err
}
return outPublic, name, qualifiedName, nil
}
// ActivateCredential executes the TPM2_ActivateCredential command to associate a credential with
// the object associated with activateContext.
//
// The activateContext parameter corresponds to an object to which credentialBlob is to be
// associated. It would typically be an attestation key, and the credential issuer would have
// validated that this object has the expected properties of an attestation key (it is a
// restricted, non-duplicable signing key) before issuing the credential. Authorization with the
// admin role is required for activateContext, with session based authorization provided via
// activateContextAuthSession.
//
// The credentialBlob is an encrypted and integrity protected credential (see section 24 -
// "Credential Protection" of Part 1 of the Trusted Platform Module Library specification). The
// secret parameter is used by the private part of the key associated with keyContext in order to
// recover the seed used to protect the credential.
//
// The keyContext parameter corresponds to an asymmetric restricted decrypt. It is typically an
// endorsement key, and the credential issuer would have verified that it is a valid endorsement
// key by verifying the associated endorsement certificate. Authorization with the user auth role
// is required for keyContext, with session based authorization provided via keyContextAuthSession.
//
// If keyContext does not correspond to an asymmetric restricted decrypt key, a *[TPMHandleError]
// error with an error code of [ErrorType] is returned for handle index 2.
//
// If recovering the seed from secret fails, a *[TPMParameterError] error with an error code of
// [ErrorScheme], [ErrorValue], [ErrorSize] or [ErrorECCPoint] may be returned for parameter index
// 2.
//
// If the integrity value or IV for credentialBlob cannot be unmarshalled correctly or any other
// errors occur during unmarshalling of credentialBlob, a *[TPMParameterError] error with an error
// code of either [ErrorSize] or [ErrorInsufficient] will be returned for parameter index 1. If
// the integrity check of credentialBlob fails, a *[TPMParameterError] error with an error code of
// [ErrorIntegrity] will be returned for parameter index 1. If the size of the IV for
// credentialBlob doesn't match the block size for the encryption algorithm, a *[TPMParameterError]
// error with an error code of [ErrorValue] will be returned for parameter index 1.
//
// On success, the decrypted credential is returned. This is typically used to decrypt a
// certificate associated with activateContext, or provide a response to a challenge provided by
// the credential issuer.
func (t *TPMContext) ActivateCredential(activateContext, keyContext ResourceContext, credentialBlob IDObject, secret EncryptedSecret, activateContextAuthSession, keyContextAuthSession SessionContext, sessions ...SessionContext) (certInfo Digest, err error) {
if err := t.StartCommand(CommandActivateCredential).
AddHandles(UseResourceContextWithAuth(activateContext, activateContextAuthSession), UseResourceContextWithAuth(keyContext, keyContextAuthSession)).
AddParams(credentialBlob, secret).
AddExtraSessions(sessions...).
Run(nil, &certInfo); err != nil {
return nil, err
}
return certInfo, nil
}
// MakeCredential executes the TPM2_MakeCredential command to allow the TPM to perform the actions
// of a certificate authority, in order to create an activation credential.
//
// The object associated with context must be the public part of a storage key, which would
// typically be the endorsement key of the TPM from which the request originates. The certificate
// authority would normally be in receipt of the TPM manufacturer issued endorsement certificate
// corresponding to this key and would have validated this. The certificate is an assertion from
// the manufacturer that the key is a valid endorsement key (a restricted, non-duplicable decrypt
// key) that is resident on a genuine TPM.
//
// The credential parameter is the activation credential, which would typically be used to protect
// the generated certificate or supply a challenge. The objectName parameter is the name of object
// for which a certificate is requested. The public part of this object would normally be validated
// by the certificate authority to ensure that it has the properties expected of an attestation key
// (it is a restricted, non-duplicable signing key).
//
// If context does not correspond to an asymmetric restricted decrypt key, a *[TPMHandleError]
// error with an error code of [ErrorType] is returned.
//
// If the size of credential is larger than the name algorithm associated with context, a
// *[TPMParameterError] error with an error code of [ErrorSize] will be returned for parameter
// index 1.
//
// If the algorithm of the object associated with context is [ObjectTypeECC], a *[TPMError] with an
// error code of [ErrorKey] will be returned if the ECC key is invalid. If the algorithm of the
// object associated with context is [ObjectTypeRSA], a *[TPMError] with an error code of
// [ErrorScheme] will be returned if the padding scheme is invalid or not supported.
//
// On success, the encrypted and integrity protected activation credential is returned as
// IDObject (see section 24 - "Credential Protection" of Part 1 of the Trusted Platform Module
// Library specification). A secret which can be used by the private part of the key associated
// with context to recover the seed used to protect the credential (using the
// TPM2_ActivateCredential command) is returned as EncryptedSecret.
func (t *TPMContext) MakeCredential(context ResourceContext, credential Digest, objectName Name, sessions ...SessionContext) (credentialBlob IDObject, secret EncryptedSecret, err error) {
if err := t.StartCommand(CommandMakeCredential).
AddHandles(UseHandleContext(context)).
AddParams(credential, objectName).
AddExtraSessions(sessions...).
Run(nil, &credentialBlob, &secret); err != nil {
return nil, nil, err
}
return credentialBlob, secret, nil
}
// Unseal executes the TPM2_Unseal command to decrypt the sealed data object associated with
// itemContext and retrieve its sensitive data. The command requires authorization with the user
// auth role for itemContext, with session based authorization provided via itemContextAuthSession.
//
// If the type of object associated with itemContext is not [ObjectTypeKeyedHash], a
// *[TPMHandleError] error with an error code of [ErrorType] will be returned. If the object
// associated with itemContext has either the [AttrDecrypt], [AttrSign] or [AttrRestricted]
// attributes set, a *[TPMHandleError] error with an error code of [ErrorAttributes] will be
// returned.
//
// On success, the object's sensitive data is returned in decrypted form.
func (t *TPMContext) Unseal(itemContext ResourceContext, itemContextAuthSession SessionContext, sessions ...SessionContext) (outData SensitiveData, err error) {
if err := t.StartCommand(CommandUnseal).
AddHandles(UseResourceContextWithAuth(itemContext, itemContextAuthSession)).
AddExtraSessions(sessions...).
Run(nil, &outData); err != nil {
return nil, err
}
return outData, nil
}
// ObjectChangeAuth executes the TPM2_ObjectChangeAuth to change the authorization value of the
// object associated with objectContext. This command requires authorization with the admin role
// for objectContext, with sessio based authorization provided via objectContextAuthSession.
//
// The new authorization value is provided via newAuth. The parentContext parameter must
// correspond to the parent object for objectContext. No authorization is required for
// parentContext.
//
// If the object associated with objectContext is a sequence object, a *[TPMHandleError] error with
// an error code of ErrorType will be returned for handle index 1.
//
// If the length of newAuth is longer than the name algorithm for objectContext, a
// *[TPMParameterError] error with an error code of [ErrorSize] will be returned.
//
// If the object associated with parentContext is not the parent object of objectContext, a
// *[TPMHandleError] error with an error code of [ErrorType] will be returned for handle index 2.
//
// On success, this returns a new private area for the object associated with objectContext. This
// function does not make any changes to the version of the object that is currently loaded in to
// the TPM.
func (t *TPMContext) ObjectChangeAuth(objectContext, parentContext ResourceContext, newAuth Auth, objectContextAuthSession SessionContext, sessions ...SessionContext) (outPrivate Private, err error) {
if err := t.StartCommand(CommandObjectChangeAuth).
AddHandles(UseResourceContextWithAuth(objectContext, objectContextAuthSession), UseHandleContext(parentContext)).
AddParams(newAuth).
AddExtraSessions(sessions...).
Run(nil, &outPrivate); err != nil {
return nil, err
}
return outPrivate, nil
}
// CreateLoaded executes the TPM2_CreateLoaded command to create a new primary, ordinary or derived
// object. To create a new primary object, parentContext should correspond to a hierarchy. To
// create a new ordinary object, parentContext should correspond to a storage parent. To create a
// new derived object, parentContext should correspond to a derivation parent.
//
// The command requires authorization with the user auth role for parentContext, with session based
// authorization provided via parentContextAuthSession.
//
// A template for the object is provided via the inPublic parameter. Because of the way that this
// parameter is handled by the TPM spec, the parameter is an interface that serializes the actual
// template. The interface is implemented by both the [Public] and [PublicDerived] types.
//
// The Type field of the template defines the algorithm for the object. The NameAlg field defines
// the digest algorithm for computing the name of the object. The Attrs field defines the
// attributes of the object. The AuthPolicy field allows an authorization policy to be defined for
// the new object.
//
// Data that will form part of the sensitive area of the object can be provided via inSensitive,
// which is optional.
//
// If parentContext does not correspond to a derivation parent and the Attrs field of of the
// template does not have the [AttrSensitiveDataOrigin] attribute set, then the sensitive data in
// the created object is initialized with the data provided via the Data field of inSensitive.
//
// If the Attrs field of the template has the [AttrSensitiveDataOrigin] attribute set and Type is
// [ObjectTypeSymCipher], then the sensitive data in the created object is initialized with a TPM
// generated key. The size of this key is determined by the symmetric algorithm defined in the
// Params field of the template. If Type is [ObjectTypeKeyedHash], then the sensitive data in the
// created object is initialized with a TPM generated value that is the same size as the name
// algorithm selected by the NameAlg field of the template.
//
// If the Type field of the template is [ObjectTypeRSA] then the sensitive data in the created
// object is initialized with a TPM generated private key. The size of this is determined by the
// asymmetric algorithm defined in the Params field of the template.
//
// If the Type field of the template is [ObjectTypeECC] and parentContext does not correspond to a
// derivation parent, then the sensitive data in the created object is initialized with a TPM
// generated private key. The size of this is determined by the asymmetric algorithm defined in
// the Params field of the template.
//
// If parentContext corresponds to a derivation parent, the sensitive data in the created object is
// initialized with a value derived from the parent object's private seed, and the derivation
// values specified in either the Unique field of the template or the Data field of inSensitive.
//
// If the Type field of the template is [ObjectTypeKeyedHash], the Attrs field has
// [AttrSensitiveDataOrigin], [AttrSign] and [AttrDecrypt] all clear, then the created object is a
// sealed data object.
//
// If the Attrs field of the template has the [AttrRestricted] and [AttrDecrypt] attributes set,
// and the Type field is not [ObjectTypeKeyedHash], then the newly created object will be a storage
// parent.
//
// If the Attrs field of the template has the [AttrRestricted] and [AttrDecrypt] attributes set,
// and the Type field is [ObjectTypeKeyedHash], then the newly created object will be a derivation
// parent.
//
// The authorization value for the created object is initialized to the value of the UserAuth field
// of inSensitive.
//
// If parentContext corresponds to an object and it isn't a valid storage parent or derivation
// parent, *[TPMHandleError] error with an error code of [ErrorType] will be returned for handle
// index 1.
//
// If there are no available slots for new objects on the TPM, a *[TPMWarning] error with a warning
// code of [WarningObjectMemory] will be returned.
//
// If the attributes in the Attrs field of the template are inconsistent or inappropriate for the
// usage, a *[TPMParameterError] error with an error code of [ErrorAttributes] will be returned for
// parameter index 2.
//
// If the NameAlg field of the template is [HashAlgorithmNull], then a *[TPMParameterError] error
// with an error code of [ErrorHash] will be returned for parameter index 2.
//
// If an authorization policy is defined via the AuthPolicy field of the template then the length
// of the digest must match the name algorithm selected via the NameAlg field, else a
// *[TPMParameterError] error with an error code of [ErrorSize] is returned for parameter index 2.
//
// If the scheme in the Params field of the template is inappropriate for the usage, a
// *[TPMParameterError] errow with an error code of [ErrorScheme] will be returned for parameter
// index 2.
//
// If the Type field of the template is [ObjectTypeRSA], [ObjectTypeECC] or [ObjectTypeKeyedHash]
// and the digest algorithm specified by the scheme in the Params field of the template is
// inappropriate for the usage, a *[TPMParameterError] error with an error code of [ErrorHash] will
// be returned for parameter index 2.
//
// If the Type field of the template is not [ObjectTypeKeyedHash], a *[TPMParameterError] error
// with an error code of [ErrorSymmetric] will be returned for parameter index 2 if the symmetric
// algorithm specified in the Params field of the template is inappropriate for the usage.
//
// If the Type field of the template is [ObjectTypeECC] and the KDF scheme specified in the Params
// field is not [KDFAlgorithmNull], a *[TPMParameterError] error with an error code of [ErrorKDF]
// will be returned for parameter index 2.
//
// If the Type field of the template is not [ObjectTypeKeyedHash] and the [AttrRestricted],
// [AttrFixedParent] and [AttrDecrypt] attributes of Attrs are set, a *[TPMParameterError] error
// with an error code of [ErrorHash] will be returned for parameter index 2 if the NameAlg field of
// the template does not select the same name algorithm as the parent object. A
// *[TPMParameterError] error with an error code of [ErrorSymmetric] will be returned for parameter
// index 2 if the symmetric algorithm specified in the Params field of the template does not match
// the symmetric algorithm of the parent object.
//
// If the length of the UserAuth field of inSensitive is longer than the name algorithm selected by
// the NameAlg field of the template, a *[TPMParameterError] error with an error code of
// [ErrorSize] will be returned for parameter index 1.
//
// If the Type field of the template is [ObjectTypeRSA] and the Params field specifies an
// unsupported exponent, a *[TPMError] with an error code of [ErrorRange] will be returned. If the
// specified key size is an unsupported value, a *[TPMError] with an error code of [ErrorValue]
// will be returned.
//
// If the Type field of the template is [ObjectTypeSymCipher] and the key size is an unsupported
// value, a *[TPMError] with an error code of [ErrorKeySize] will be returned. If the
// [AttrSensitiveDataOrigin] attribute is not set and the length of the Data field of inSensitive
// does not match the key size specified in the Params field of the template, a *[TPMError] with an
// error code of [ErrorKeySize] will be returned.
//
// If the Type field of the template is [ObjectTypeKeyedHash] and the [AttrSensitiveDataOrigin]
// attribute is not set, a *[TPMError] with an error code of [ErrorSize] will be returned if the
// length of the Data field of inSensitive is longer than permitted for the digest algorithm
// selected by the specified scheme.
//
// On success, a ResourceContext instance will be returned that corresponds to the newly created
// object on the TPM, along with the private and public parts. It will not be necessary to call
// [ResourceContext].SetAuthValue on the returned ResourceContext - this function sets the correct
// authorization value so that it can be used in subsequent commands that require knowledge of the
// authorization value. The returned ResourceContext can be type asserted to [ObjectContext]. If
// the Type field of the template is [ObjectTypeKeyedHash] or [ObjectTypeSymCipher], then the
// returned *Public object will have a Unique field that is the digest of the sensitive data and
// the value of the object's seed in the sensitive area, computed using the object's name algorithm.
// If the Type field of the template is [ObjectTypeECC] or [ObjectTypeRSA], then the returned *Public
// object will have a Unique field containing details about the public part of the key, computed from
// the private part of the key.
func (t *TPMContext) CreateLoaded(parentContext ResourceContext, inSensitive *SensitiveCreate, inPublic PublicTemplate, parentContextAuthSession SessionContext, sessions ...SessionContext) (objectContext ResourceContext, outPrivate Private, outPublic *Public, err error) {
if inSensitive == nil {
inSensitive = &SensitiveCreate{}
}
if inPublic == nil {
return nil, nil, nil, makeInvalidArgError("inPublic", "nil value")
}
inTemplate, err := inPublic.ToTemplate()
if err != nil {
return nil, nil, nil, fmt.Errorf("cannot marshal public template: %v", err)
}
var objectHandle Handle
var name Name
if err := t.StartCommand(CommandCreateLoaded).
AddHandles(UseResourceContextWithAuth(parentContext, parentContextAuthSession)).
AddParams(mu.Sized(inSensitive), inTemplate).
AddExtraSessions(sessions...).
Run(&objectHandle, &outPrivate, mu.Sized(&outPublic), &name); err != nil {
return nil, nil, nil, err
}
if objectHandle.Type() != HandleTypeTransient {
return nil, nil, nil, &InvalidResponseError{CommandCreateLoaded,
fmt.Errorf("handle 0x%08x returned from TPM is the wrong type", objectHandle)}
}
if outPublic == nil {
return nil, nil, nil, &InvalidResponseError{CommandCreateLoaded, errors.New("no public area returned from TPM")}
}
if outPublic.NameAlg.Available() && !outPublic.compareName(name) {
return nil, nil, nil, &InvalidResponseError{CommandCreateLoaded, errors.New("name and public area returned from TPM are not consistent")}
}
var public *Public
if err := mu.CopyValue(&public, outPublic); err != nil {
return nil, nil, nil, &InvalidResponseError{CommandCreateLoaded, fmt.Errorf("cannot copy returned public area from TPM: %w", err)}
}
rc := newObjectContext(objectHandle, name, public)
rc.authValue = make([]byte, len(inSensitive.UserAuth))
copy(rc.authValue, inSensitive.UserAuth)
return rc, outPrivate, outPublic, nil
}