Skip to content
This repository has been archived by the owner on Sep 6, 2023. It is now read-only.

Commit

Permalink
Add ability to generate pcr7data for an existing keyset
Browse files Browse the repository at this point in the history
Signed-off-by: Joy Latten <[email protected]>
  • Loading branch information
Joy Latten authored and hallyn committed May 8, 2023
1 parent 1b98eab commit b588fd2
Show file tree
Hide file tree
Showing 3 changed files with 293 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ Trust also offers the following subcommands for administration:
generated certificates. The key repo may be used whereever a
keysetname is required.

'trust keyset pcr7data keysetName --passwdPolicy <pathname> \
--luksPolicy <pathname> \
--pcr7-tpm <pathname> \
--pcr7-prod <pathname> \
--pcr7-limited <pathname>
Adds the specified data to the named keyset. This generates
the "pcr7data" directory in the keyset.

Exported functions in trust:

doSudiCert(VMname, keysetname string) - Generates a unique uuid,
Expand Down
221 changes: 221 additions & 0 deletions cmd/trust/keyset.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package main

import (
"crypto/x509"
"crypto/rsa"
"fmt"
"os"
"path/filepath"
"strings"
"time"
"encoding/json"

"github.com/apex/log"
"github.com/go-git/go-git/v5"
Expand Down Expand Up @@ -239,6 +241,34 @@ var keysetCmd = cli.Command{
},
},
},
cli.Command{
Name: "pcr7data",
Action: doAddPCR7data,
Usage: "include the specified pcr7data into keyset",
ArgsUsage: "<keyset-name>",
Flags: []cli.Flag{
cli.StringFlag{
Name: "pcr7-tpm",
Usage: "Pathname to the pcr7 tpm binary file",
},
cli.StringFlag{
Name: "pcr7-limited",
Usage: "Pathname to the pcr7 limited binary file",
},
cli.StringFlag{
Name: "pcr7-prod",
Usage: "Pathname to the pcr7 production binary file",
},
cli.StringFlag{
Name: "passwdPolicy",
Usage: "Pathname to the tpm passwd policy file (optional)",
},
cli.StringFlag{
Name: "luksPolicy",
Usage: "Pathname to the luks policy file (optional)",
},
},
},
},
}

Expand Down Expand Up @@ -400,3 +430,194 @@ func doShowKeyset(ctx *cli.Context) error {

return nil
}

type Pcr7Data struct {
limited string
tpm string
production string
passwdPolicy string
luksPolicy string
}

func doAddPCR7data(ctx *cli.Context) error {
var p Pcr7Data
args := ctx.Args()
if len(args) != 1 {
return errors.New("Missing arguments")
}

keysetName := args[0]

p.passwdPolicy = ctx.String("passwdPolicy")
p.luksPolicy = ctx.String("luksPolicy")
p.limited = ctx.String("pcr7-limited")
p.tpm = ctx.String("pcr7-tpm")
p.production = ctx.String("pcr7-prod")

if err := addPcr7data(keysetName, p); err != nil {
return err
}
return nil
}

func addPcr7data(keysetName string, pdata Pcr7Data) error {
var err error
var notexist = true
var moskeypath, pcrIndex, newFile string
var tpmpolAdminpubkey, tpmpolLukspubkey *rsa.PublicKey
var jsonInfo []byte
type PCR7info struct {
Key string `json:"key"`
KeyType string `json:"key_type"`
Date string `json:"est_date"`
Comment string `json:"comment"`
}

pcr7 := make(map[string]string)

if keysetName == "" {
return errors.New("Please specify a keyset name")
}

pcr7["limited"] = pdata.limited
pcr7["tpm"] = pdata.tpm
pcr7["production"] = pdata.production

if pcr7["limited"] == "" || pcr7["tpm"] == "" || pcr7["production"] == "" {
return errors.New("Must specify all 3 pcr7 values: tpm, limited and production")
}

// Make sure the pcr7 files exist
for _, path := range pcr7 {
if !PathExists(path) {
return fmt.Errorf("%s does not exist.", path)
}
}

// For now, don't generate. Only accept the 2 policies.
if pdata.passwdPolicy == "" || !PathExists(pdata.passwdPolicy) {
return errors.New("The passwd policy file is missing.")
}
if pdata.luksPolicy == "" || !PathExists(pdata.luksPolicy) {
return errors.New("The luks policy file is missing.")
}

moskeypath, err = getMosKeyPath()
if err != nil {
return err
}
keysetPath := filepath.Join(moskeypath, keysetName)
if !PathExists(keysetPath) {
return fmt.Errorf("The keyset, %s, does not exist.", keysetName)
}

// Its ok if pcr7data dir already exists. We might be adding additional signdata
pcr7dataPath := filepath.Join(keysetPath, "pcr7data/policy2")
if !PathExists(pcr7dataPath) {
err = os.MkdirAll(keysetPath, 0750)
if err != nil {
return err
}
} else {
notexist = false
}

defer func() {
if err != nil && notexist == true {
os.RemoveAll(filepath.Join(keysetPath, "pcr7data"))
}
}()

// Check to see if public keys already exist for this keyset, if not
// then extract public keys and save them
pcr7dataPubkeys := filepath.Join(pcr7dataPath, "pubkeys")
if !PathExists(pcr7dataPubkeys) {
if err = trust.EnsureDir(pcr7dataPubkeys); err != nil {
return errors.New("Failed to create directory for public keys")
}
}

tpmpolAdminpubkey, err = extractPubkey(filepath.Join(keysetPath, "tpmpol-admin/cert.pem"))
if err != nil {
return err
}
err = savePubkeytoFile(tpmpolAdminpubkey, filepath.Join(pcr7dataPubkeys, "tpmpass-snakeoil.pem"))
if err != nil {
return err
}
tpmpolLukspubkey, err = extractPubkey(filepath.Join(keysetPath, "tpmpol-luks/cert.pem"))
if err != nil {
return err
}
err = savePubkeytoFile(tpmpolLukspubkey, filepath.Join(pcr7dataPubkeys, "luks-snakeoil.pem"))
if err != nil {
return err
}

// - Generate the index for pcr7-limited.bin.
// Add the binary pcr7 values into this index.
// - Generate the index for pcr7-production.bin.
// Add the signed tpm-luks policy into this index.
// - Generate the index for pcr7-tpm.bin.
// Add the signed tpm-passwd policy into this index.
for key, path := range pcr7 {
// create index used to name the sub-directories under policy-2 directory
pcrIndex, err = createPCR7Index(path)
if err != nil {
return err
}
indexdir := filepath.Join(pcr7dataPath, pcrIndex[0:2], pcrIndex[2:])
if err = trust.EnsureDir(indexdir); err != nil {
return err
}

// create info.json
jsonFile := filepath.Join(indexdir, "info.json")

date := time.Now()
formatted := date.Format("2006-01-02")
timestamp := strings.ReplaceAll(formatted, "-", "")
info := &PCR7info{Key: keysetName, KeyType: key, Date: timestamp, Comment: "mos"+" "+keysetName}
jsonInfo, err = json.Marshal(info)
if err != nil {
return err
}
if err = os.WriteFile(jsonFile, jsonInfo, 0644); err != nil {
return err
}

// write out info
switch key {
case "limited" :
newFile = filepath.Join(indexdir, "pcr_limited.bin")
if err = trust.CopyFile(pcr7["limited"], newFile); err != nil {
return err
}
newFile = filepath.Join(indexdir, "pcr_tpm.bin")
if err = trust.CopyFile(pcr7["tpm"], newFile); err != nil {
return err
}
newFile = filepath.Join(indexdir, "pcr_prod.bin")
if err = trust.CopyFile(pcr7["production"], newFile); err != nil {
return err
}
case "tpm" :
// Sign the policy
newFile = filepath.Join(indexdir, "tpm_passwd.policy.signed")
signingKey := filepath.Join(keysetPath, "tpmpol-admin/privkey.pem")
if err = trust.Sign(pdata.passwdPolicy, newFile, signingKey); err != nil {
return err
}
case "production" :
// Sign the policy
newFile = filepath.Join(indexdir, "tpm_luks.policy.signed")
signingKey := filepath.Join(keysetPath, "tpmpol-luks/privkey.pem")
if err = trust.Sign(pdata.luksPolicy, newFile, signingKey); err != nil {
return err
}
default :
return errors.New("Unrecognized uki key")
}
}
return nil
}
64 changes: 64 additions & 0 deletions cmd/trust/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"encoding/hex"
"fmt"
"io"
"math/big"
Expand Down Expand Up @@ -72,6 +73,19 @@ func getMosKeyPath() (string, error) {
return filepath.Join(dataDir, "machine", "trust", "keys"), nil
}

func KeysetExists(keysetname string) bool {
mosKeyPath, err := getMosKeyPath()
if err != nil {
return false
}
keysetPath := filepath.Join(mosKeyPath, keysetname)
if PathExists(keysetPath) {
return true
} else {
return false
}
}

// SignCert creates a CA signed certificate and keypair in destdir
func SignCert(template, CAcert *x509.Certificate, CAkey any, destdir string) error {
// Check if credentials already exist
Expand Down Expand Up @@ -405,3 +419,53 @@ func generateCreds(destdir string, doguid bool, template *x509.Certificate) erro

return nil
}

func createPCR7Index(pcr7file string) (string, error) {
c, err := os.ReadFile(pcr7file)
if err != nil {
return "", err
}
for start := 0; start+1 < len(c); start += 2 {
tmp := c[start]
c[start] = c[start+1]
c[start+1] = tmp
}
encodedStr := hex.EncodeToString(c)
return encodedStr, nil
}

func extractPubkey(certPath string) (*rsa.PublicKey, error) {
certPEM, err := os.ReadFile(certPath)
if err != nil {
return nil, err
}
block, _ := pem.Decode([]byte(certPEM))
if block == nil {
return nil, fmt.Errorf("Failed to decode the certificate (%q)", certPath)
}
parsedCert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, err
}
return parsedCert.PublicKey.(*rsa.PublicKey), nil
}

func savePubkeytoFile(pubkey *rsa.PublicKey, outPath string) error {
pubkeyPem, err := os.Create(outPath)
if err != nil {
return err
}
pkix, err := x509.MarshalPKIXPublicKey(pubkey)
if err != nil {
return err
}
err = pem.Encode(pubkeyPem, &pem.Block{Type: "PUBLIC KEY", Bytes: pkix})
if err != nil {
return err
}
err = os.Chmod(outPath, 0644)
if err != nil {
return err
}
return nil
}

0 comments on commit b588fd2

Please sign in to comment.