func()

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
}