in linux/tpm.go [136:276]
func (tpm *tpmDevice) GenerateKey(parent tpmutil.Handle, keyID string, persistentHandle tpmutil.Handle, template *tpm2.Public) (CryptoKey, error) {
db, err := diskio.OpenDB()
if err != nil {
return nil, err
}
key := &tpmKey{}
if parent == tpm2.HandleEndorsement || parent == tpm2.HandleOwner ||
parent == tpm2.HandleNull {
flog.Debugf("Generating a primary key under hierarchy 0x%x", parent)
// Yes, the canonical Golang way is to use short assignment. But that
// blocks directly using the existing fields in the TPMKey struct. Go
// complain to https://github.com/golang/go/issues/30318
var publicArea []byte
var creationData []byte
var keyName []byte
var err error
key.Handle, publicArea, creationData, key.CreationHash, key.Ticket, keyName, err = tpm2.CreatePrimaryEx(
tpm.rwc,
parent,
// We are not sealing this key to any PCR state
tpm2.PCRSelection{},
"",
"",
// Changing this template will change the primary key that gets
// generated. Modify this at your peril.
DefaultECCEKTemplate(),
)
if err != nil {
flog.Debugf("Error in CreatePrimaryEx: %+v", err)
return nil, err
}
err = key.FillKeyData(publicArea, nil, creationData, keyName)
if err != nil {
return nil, err
}
flog.Debugf("Generated primary key at handle 0x%x", key.Handle)
return key, nil
}
flog.Debugf("Generating new key under parent handle 0x%x", parent)
var keyTmpl tpm2.Public
if template == nil {
keyTmpl = DefaultECCKeyTemplate()
} else {
keyTmpl = *template
}
flog.Debugf("Using template: %+v", keyTmpl)
privateBlob, publicBlob, _, _, _, err := tpm2.CreateKey(
tpm.rwc,
parent,
// We are not sealing this key to any PCR state
tpm2.PCRSelection{},
"",
"",
keyTmpl,
)
if err != nil {
flog.Criticalf("Error generating SRK: %+v", err)
return nil, err
}
flog.Debug("Created new key")
err = key.FillKeyData(publicBlob, privateBlob, nil, nil)
if err != nil {
return nil, err
}
key.Parent = parent
if persistentHandle > 0 {
// Need to load the key, then evict it, and unload it when we're done
loadedHandle, _, err := tpm2.Load(
tpm.rwc,
parent,
"",
publicBlob,
privateBlob,
)
if err != nil {
flog.Criticalf("Failed to load new key: %+v", err)
return nil, err
}
defer tpm2.FlushContext(tpm.rwc, loadedHandle)
flog.Debugf("Loaded new key at handle 0x%x", loadedHandle)
// Attempt to remove the key stored at persistentHandle, in case one
// already exists in the TPM and/or disk cache.
err = tpm.doKeyDeletion(keyID, persistentHandle, false)
if err != nil {
flog.Errorf(
"Failed deleting key at NV index 0x%x: %+v",
persistentHandle,
err,
)
}
err = tpm2.EvictControl(
tpm.rwc,
"",
// You may note elsewhere we state we want only the endorsement
// hierarchy because it's privacy-sensitive, but here we use Owner.
// Owner isn't a hierarchy, it's an authorization handle, but the
// go-tpm library doesn't distinguish between handle types in the
// variable names.
tpm2.HandleOwner,
loadedHandle,
persistentHandle,
)
if err != nil {
flog.Criticalf(
"Failed to evict new key to persistent storage: %+v", err)
return nil, err
}
key.Handle = persistentHandle
flog.Debugf("Key persisted to storage at handle 0x%x", persistentHandle)
// Now save the key so we can use it later, needed for loading the key
// into the TPM once it's been flushed.S
keyBytes, err := utils.MarshalBytes(key)
if err != nil {
flog.Criticalf("Failed to marshal key: %+v", err)
return nil, err
}
_, err = db.Save(keyID, keyBytes)
if err != nil {
flog.Criticalf("Failed to save marshaled key to disk: %+v", err)
return nil, err
}
flog.Debugf("Key marshaled with identifier %s", keyID)
}
return key, nil
}