Skip to content

Commit

Permalink
NOISSUE - Add CLI option to download ASK and ARK (ultravioletrs#149)
Browse files Browse the repository at this point in the history
* add cli option to download ask and ark

* add ARK and ASK to cert chain of the attestation report

* fix spelling mistake

* add explanation for aTLS testing

* remove commented code
  • Loading branch information
danko-miladinovic authored Jul 3, 2024
1 parent 30092c6 commit 7c090fd
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 16 deletions.
69 changes: 69 additions & 0 deletions cli/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package cli

import (
"log"
"os"
"path"

"github.com/google/go-sev-guest/abi"
"github.com/google/go-sev-guest/kds"
"github.com/google/go-sev-guest/verify/trust"
"github.com/spf13/cobra"
"github.com/ultravioletrs/cocos/pkg/clients/grpc"
)

const (
caBundleName = "ask_ark.pem"
filePermisionKeys = 0o766
)

func (cli *CLI) NewCABundleCmd(fileSavePath string) *cobra.Command {
return &cobra.Command{
Use: "ca-bundle",
Short: "Fetch AMD SEV-SNPs CA Bundle (ASK and ARK)",
Example: "ca-bundle <path_to_platform_info_json>",
Args: cobra.ExactArgs(1),
Run: func(cmd *cobra.Command, args []string) {
attestationConfiguration := grpc.AttestationConfiguration{}
err := grpc.ReadManifest(args[0], &attestationConfiguration)
if err != nil {
log.Fatalf("Error while reading manifest: %v", err)
}

product := attestationConfiguration.RootOfTrust.Product

getter := trust.DefaultHTTPSGetter()
caURL := kds.ProductCertChainURL(abi.VcekReportSigner, product)

bundle, err := getter.Get(caURL)
if err != nil {
log.Fatalf("Error fetching ARK and ASK from AMD KDS for product: %s, error: %v", product, err)
}

err = os.MkdirAll(path.Join(fileSavePath, product), filePermisionKeys)
if err != nil {
log.Fatalf("Error while creating directory for product name %s, error: %v", product, err)
}

bundleFilePath := path.Join(fileSavePath, product, caBundleName)
if err = saveToFile(bundleFilePath, bundle); err != nil {
log.Fatalf("Error while saving ARK-ASK to file: %v", err)
}
},
}
}

func saveToFile(fileSavePath string, content []byte) error {
file, err := os.OpenFile(fileSavePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, filePermisionKeys)
if err != nil {
return err
}

if _, err := file.Write(content); err != nil {
return err
}

return nil
}
11 changes: 3 additions & 8 deletions cli/measurement.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,11 @@ import (
"log"
"os"

"github.com/google/go-sev-guest/proto/check"
"github.com/spf13/cobra"
"github.com/ultravioletrs/cocos/pkg/clients/grpc"
)

const filePermision = 0o755

type AttestationConfiguration struct {
SNPPolicy *check.Policy `json:"snp_policy,omitempty"`
RootOFTrust *check.RootOfTrust `json:"root_of_trust,omitempty"`
}
const filePermision = 0o644

func (cli *CLI) NewAddMeasurementCmd() *cobra.Command {
return &cobra.Command{
Expand All @@ -31,7 +26,7 @@ func (cli *CLI) NewAddMeasurementCmd() *cobra.Command {
log.Fatalf("Error could not decode base64: %v", err)
}

attestationConfiguration := AttestationConfiguration{}
attestationConfiguration := grpc.AttestationConfiguration{}

manifest, err := os.OpenFile(args[1], os.O_RDWR, filePermision)
if err != nil {
Expand Down
18 changes: 18 additions & 0 deletions cmd/cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import (
"fmt"
"log"
"os"
"path"

mglog "github.com/absmach/magistrala/logger"
"github.com/google/logger"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/ultravioletrs/cocos/cli"
Expand All @@ -21,6 +23,8 @@ const (
svcName = "cli"
envPrefixAgentGRPC = "AGENT_GRPC_"
completion = "completion"
filePermision = 0o755
cocosDirectory = ".cocos"
)

type config struct {
Expand All @@ -29,10 +33,23 @@ type config struct {

func main() {
var cfg config
logger.Init("", false, false, os.Stderr)

if err := env.Parse(&cfg); err != nil {
log.Fatalf("failed to load %s configuration : %s", svcName, err)
}

homePath, err := os.UserHomeDir()
if err != nil {
log.Fatalf("Error fetching user home directory: %v", err)
}

directoryCachePath := path.Join(homePath, cocosDirectory)

if err := os.MkdirAll(directoryCachePath, filePermision); err != nil {
log.Fatalf("Error while creating directory %s, error: %v", directoryCachePath, err)
}

logger, err := mglog.New(os.Stdout, cfg.LogLevel)
if err != nil {
log.Fatalf("Error creating logger: %s", err)
Expand Down Expand Up @@ -92,6 +109,7 @@ func main() {
rootCmd.AddCommand(cliSVC.NewFileHashCmd())
rootCmd.AddCommand(cliSVC.NewAddMeasurementCmd())
rootCmd.AddCommand(cliSVC.NewKeysCmd())
rootCmd.AddCommand(cliSVC.NewCABundleCmd(directoryCachePath))

// Attestation commands
attestaionCmd.AddCommand(cliSVC.NewGetAttestationCmd())
Expand Down
56 changes: 49 additions & 7 deletions pkg/clients/grpc/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ import (
"encoding/json"
"fmt"
"os"
"path"
"time"

"github.com/absmach/magistrala/pkg/errors"
"github.com/google/go-sev-guest/abi"
"github.com/google/go-sev-guest/proto/check"
"github.com/google/go-sev-guest/proto/sevsnp"
"github.com/google/go-sev-guest/validate"
"github.com/google/go-sev-guest/verify"
"github.com/google/go-sev-guest/verify/trust"
Expand All @@ -32,6 +34,13 @@ const (
withmTLS
)

const (
cocosDirectory = ".cocos"
caBundleName = "ask_ark.pem"
productNameMilan = "Milan"
productNameGenoa = "Genoa"
)

var (
errGrpcConnect = errors.New("failed to connect to grpc server")
errGrpcClose = errors.New("failed to close grpc connection")
Expand Down Expand Up @@ -63,7 +72,7 @@ type Config struct {

type AttestationConfiguration struct {
SNPPolicy *check.Policy `json:"snp_policy,omitempty"`
RootOFTrust *check.RootOfTrust `json:"root_of_trust,omitempty"`
RootOfTrust *check.RootOfTrust `json:"root_of_trust,omitempty"`
}

type Client interface {
Expand Down Expand Up @@ -132,7 +141,7 @@ func connect(cfg Config) (*grpc.ClientConn, security, error) {
tc := insecure.NewCredentials()

if cfg.AttestedTLS {
err := readManifest(cfg)
err := ReadManifest(cfg.Manifest, &attestationConfiguration)
if err != nil {
return nil, secure, fmt.Errorf("failed to read Manifest %w", err)
}
Expand Down Expand Up @@ -183,16 +192,16 @@ func connect(cfg Config) (*grpc.ClientConn, security, error) {
return conn, secure, nil
}

func readManifest(cfg Config) error {
if cfg.Manifest != "" {
manifest, err := os.Open(cfg.Manifest)
func ReadManifest(manifestPath string, attestationConfiguration *AttestationConfiguration) error {
if manifestPath != "" {
manifest, err := os.Open(manifestPath)
if err != nil {
return errors.Wrap(errManifestOpen, err)
}
defer manifest.Close()

decoder := json.NewDecoder(manifest)
err = decoder.Decode(&attestationConfiguration)
err = decoder.Decode(attestationConfiguration)
if err != nil {
return errors.Wrap(errManifestDecode, err)
}
Expand Down Expand Up @@ -226,7 +235,7 @@ func verifyAttestationReportTLS(rawCerts [][]byte, verifiedChains [][]*x509.Cert
attestationConfiguration.SNPPolicy.ReportData = expectedReportData[:]

// Attestation verification and validation
sopts, err := verify.RootOfTrustToOptions(attestationConfiguration.RootOFTrust)
sopts, err := verify.RootOfTrustToOptions(attestationConfiguration.RootOfTrust)
if err != nil {
return errors.Wrap(errAttVerification, err)
}
Expand All @@ -243,6 +252,10 @@ func verifyAttestationReportTLS(rawCerts [][]byte, verifiedChains [][]*x509.Cert
return errors.Wrap(errAttVerification, err)
}

if err := fillInAttestationLocal(attestationPB); err != nil {
return err
}

if err = verify.SnpAttestation(attestationPB, sopts); err != nil {
return errors.Wrap(errAttVerification, err)
}
Expand Down Expand Up @@ -278,3 +291,32 @@ func checkIfCertificateSelfSigned(cert *x509.Certificate) error {

return nil
}

func fillInAttestationLocal(attestation *sevsnp.Attestation) error {
product := attestationConfiguration.RootOfTrust.Product

chain := attestation.GetCertificateChain()
if chain == nil {
chain = &sevsnp.CertificateChain{}
attestation.CertificateChain = chain
}
if len(chain.GetAskCert()) == 0 || len(chain.GetArkCert()) == 0 {
homePath, err := os.UserHomeDir()
if err != nil {
return err
}

bundleFilePath := path.Join(homePath, cocosDirectory, product, caBundleName)
if _, err := os.Stat(bundleFilePath); err == nil {
amdRootCerts := trust.AMDRootCerts{}
if err := amdRootCerts.FromKDSCert(bundleFilePath); err != nil {
return err
}

chain.ArkCert = amdRootCerts.ProductCerts.Ark.Raw
chain.AskCert = amdRootCerts.ProductCerts.Ask.Raw
}
}

return nil
}
8 changes: 7 additions & 1 deletion test/manual/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@ LINE="earlyprintk=serial console=ttyS0"
sev-snp-measure --mode snp --vcpus 4 --vcpu-type EPYC-v4 --ovmf $OVMF_CODE --kernel $KERNEL --initrd $INITRD --append "$LINE" --output-format base64
```

```sh
To speed up the verification process of attested TLS, download the ARK and ASK certificates using the CLI tool. The CLI tool will download the certificates under your home directory in the `.cocos` directory.
```bash
go run cmd/cli/main.go ca-bundle <path/to/platfrom_info.json>
```

In the following text, we can see an example of how the CLI tool is used.
```bash
export AGENT_GRPC_URL=localhost:7002

# For attested TLS, the CLI should also be aware of the VM measurement. To
Expand Down

0 comments on commit 7c090fd

Please sign in to comment.