mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-06-23 04:10:25 +00:00
8eb1fac9ad
* Refactor and update dependencies in the project - Updated go.sum to replace `github.com/absmach/magistrala` with `github.com/absmach/supermq` across various modules. - Removed VSock configuration from environment variables and QEMU arguments. - Updated QEMU configuration and related tests to remove references to guest CID and VSock. - Added new HTTP transport layer for API endpoints in the manager. - Introduced Prometheus monitoring configuration with alert rules and Alertmanager setup. - Updated service and VM interfaces to remove unused methods and references. - Refactored tests to align with the new structure and dependencies. Signed-off-by: Sammy Oina <sammyoina@gmail.com> * Add MaxVMs configuration and enforce limit on VM creation Signed-off-by: Sammy Oina <sammyoina@gmail.com> * Add comprehensive tests for HTTP transport handlers and endpoints Signed-off-by: Sammy Oina <sammyoina@gmail.com> * Add test case for exceeding maximum number of VMs in TestRun Signed-off-by: Sammy Oina <sammyoina@gmail.com> * Improve error handling in TestHandlerWithCustomRouter to ensure response writing is checked Signed-off-by: Sammy Oina <sammyoina@gmail.com> * Update dependencies to latest versions - Upgrade cel.dev/expr from v0.23.0 to v0.24.0 - Upgrade github.com/absmach/supermq from v0.16.0 to v0.17.0 - Upgrade github.com/cenkalti/backoff from v4.3.0 to v5.0.2 - Upgrade github.com/cncf/xds/go to v0.0.0-20250501225837-2ac532fd4443 - Upgrade github.com/go-chi/chi/v5 from v5.2.1 to v5.2.2 - Upgrade github.com/go-jose/go-jose/v3 from v3.0.3 to v3.0.4 - Upgrade github.com/gofrs/uuid/v5 from v5.3.0 to v5.3.2 - Upgrade github.com/prometheus/client_golang from v1.22.0 to v1.23.0 - Upgrade github.com/prometheus/client_model from v0.6.1 to v0.6.2 - Upgrade github.com/prometheus/common from v0.62.0 to v0.65.0 - Upgrade github.com/prometheus/procfs from v0.15.1 to v0.16.1 - Upgrade go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp from v0.60.0 to v0.62.0 - Upgrade go.opentelemetry.io/otel/exporters/otlp/otlptrace from v1.36.0 to v1.37.0 - Upgrade golang.org/x/crypto from v0.39.0 to v0.40.0 - Upgrade golang.org/x/sys from v0.33.0 to v0.34.0 - Upgrade golang.org/x/text from v0.26.0 to v0.27.0 - Upgrade golang.org/x/time from v0.11.0 to v0.12.0 - Upgrade google.golang.org/grpc from v1.73.0 to v1.74.2 Signed-off-by: Sammy Oina <sammyoina@gmail.com> --------- Signed-off-by: Sammy Oina <sammyoina@gmail.com>
259 lines
6.7 KiB
Go
259 lines
6.7 KiB
Go
// Copyright (c) Ultraviolet
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
package cli
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/absmach/supermq/pkg/errors"
|
|
ccpb "github.com/google/go-tdx-guest/proto/checkconfig"
|
|
"github.com/spf13/cobra"
|
|
"github.com/ultravioletrs/cocos/pkg/attestation"
|
|
"google.golang.org/protobuf/encoding/protojson"
|
|
)
|
|
|
|
var (
|
|
cfgTDX = &ccpb.Config{
|
|
RootOfTrust: &ccpb.RootOfTrust{},
|
|
Policy: &ccpb.Policy{HeaderPolicy: &ccpb.HeaderPolicy{}, TdQuoteBodyPolicy: &ccpb.TDQuoteBodyPolicy{}},
|
|
}
|
|
rtmrsS string
|
|
trustedRootS string
|
|
errNumberRtmrs = fmt.Errorf("expected 4 RTMRS values")
|
|
errDecodeRtmrs = fmt.Errorf("failed to decode RTMRS hex string")
|
|
errTrustedRootPath = fmt.Errorf("trusted root path must be a file, not a directory")
|
|
errNotAFile = fmt.Errorf("trusted root path must be a file")
|
|
)
|
|
|
|
func addTDXVerificationOptions(cmd *cobra.Command) *cobra.Command {
|
|
cmd.Flags().BytesHexVar(
|
|
&cfgTDX.Policy.HeaderPolicy.QeVendorId,
|
|
"qe_vendor_id",
|
|
[]byte{},
|
|
"The expected QE_VENDOR_ID field as a hex string. Must encode 16 bytes. Unchecked if unset.",
|
|
)
|
|
cmd.Flags().BytesHexVar(
|
|
&cfgTDX.Policy.TdQuoteBodyPolicy.MrSeam,
|
|
"mr_seam",
|
|
[]byte{},
|
|
"The expected MR_SEAM field as a hex string. Must encode 48 bytes. Unchecked if unset.",
|
|
)
|
|
cmd.Flags().BytesHexVar(
|
|
&cfgTDX.Policy.TdQuoteBodyPolicy.TdAttributes,
|
|
"td_attributes",
|
|
[]byte{},
|
|
"The expected TD_ATTRIBUTES field as a hex string. Must encode 8 bytes. Unchecked if unset.",
|
|
)
|
|
cmd.Flags().BytesHexVar(
|
|
&cfgTDX.Policy.TdQuoteBodyPolicy.Xfam,
|
|
"xfam",
|
|
[]byte{},
|
|
"The expected XFAM field as a hex string. Must encode 8 bytes. Unchecked if unset.",
|
|
)
|
|
cmd.Flags().BytesHexVar(
|
|
&cfgTDX.Policy.TdQuoteBodyPolicy.MrTd,
|
|
"mr_td",
|
|
[]byte{},
|
|
"The expected MR_TD field as a hex string. Must encode 48 bytes. Unchecked if unset.",
|
|
)
|
|
cmd.Flags().BytesHexVar(
|
|
&cfgTDX.Policy.TdQuoteBodyPolicy.MrConfigId,
|
|
"mr_config_id",
|
|
[]byte{},
|
|
"The expected MR_CONFIG_ID field as a hex string. Must encode 48 bytes. Unchecked if unset.",
|
|
)
|
|
cmd.Flags().BytesHexVar(
|
|
&cfgTDX.Policy.TdQuoteBodyPolicy.MrOwnerConfig,
|
|
"mr_owner",
|
|
[]byte{},
|
|
"The expected MR_OWNER field as a hex string. Must encode 48 bytes. Unchecked if unset.",
|
|
)
|
|
cmd.Flags().BytesHexVar(
|
|
&cfgTDX.Policy.TdQuoteBodyPolicy.MrOwnerConfig,
|
|
"mr_config_owner",
|
|
[]byte{},
|
|
"The expected MR_OWNER_CONFIG field as a hex string. Must encode 48 bytes. Unchecked if unset.",
|
|
)
|
|
cmd.Flags().BytesHexVar(
|
|
&cfgTDX.Policy.TdQuoteBodyPolicy.MinimumTeeTcbSvn,
|
|
"minimum_tee_tcb_svn",
|
|
[]byte{},
|
|
"The minimum acceptable value for TEE_TCB_SVN field as a hex string. Must encode 16 bytes. Unchecked if unset.",
|
|
)
|
|
cmd.Flags().StringVar(
|
|
&rtmrsS,
|
|
"rtmrs",
|
|
"",
|
|
"Comma-separated hex strings representing expected values of RTMRS field. Expected 4 strings, either empty or each must encode 48 bytes. Unchecked if unset",
|
|
)
|
|
cmd.Flags().StringVar(
|
|
&trustedRootS,
|
|
"trusted_root",
|
|
"",
|
|
"Comma-separated paths to CA bundles for the Intel TDX. Must be in PEM format, Root CA certificate. If unset, uses embedded root certificate.",
|
|
)
|
|
cmd.Flags().Uint32Var(
|
|
&cfgTDX.Policy.HeaderPolicy.MinimumQeSvn,
|
|
"minimum_qe_svn",
|
|
0,
|
|
"The minimum acceptable value for QE_SVN field.",
|
|
)
|
|
cmd.Flags().Uint32Var(
|
|
&cfgTDX.Policy.HeaderPolicy.MinimumPceSvn,
|
|
"minimum_pce_svn",
|
|
0,
|
|
"The minimum acceptable value for PCE_SVN field.",
|
|
)
|
|
cmd.Flags().BoolVar(
|
|
&cfgTDX.RootOfTrust.GetCollateral,
|
|
"get_collateral",
|
|
false,
|
|
"If true, then permitted to download necessary collaterals for additional checks.",
|
|
)
|
|
|
|
return cmd
|
|
}
|
|
|
|
func parseRtmrs() ([][]byte, error) {
|
|
if rtmrsS == "" {
|
|
return nil, nil // No RTMRS provided, return nil
|
|
}
|
|
|
|
hexString := strings.Split(rtmrsS, ",")
|
|
if len(hexString) != 4 {
|
|
return nil, errNumberRtmrs
|
|
}
|
|
|
|
var result [][]byte
|
|
for _, hexStr := range hexString {
|
|
h, err := hex.DecodeString(strings.TrimSpace(hexStr))
|
|
if err != nil {
|
|
return nil, errors.Wrap(errDecodeRtmrs, err)
|
|
}
|
|
|
|
result = append(result, h)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func parseTrustedRoot() ([]string, error) {
|
|
if trustedRootS == "" {
|
|
return nil, nil // No trusted roots provided, return nil
|
|
}
|
|
|
|
roots := strings.Split(trustedRootS, ",")
|
|
var result []string
|
|
for _, root := range roots {
|
|
p := strings.TrimSpace(root)
|
|
state, err := os.Stat(p)
|
|
if err != nil {
|
|
return nil, errors.Wrap(errTrustedRootPath, err)
|
|
}
|
|
if state.IsDir() {
|
|
return nil, errNotAFile
|
|
}
|
|
|
|
result = append(result, p)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func parseTDXConfig() error {
|
|
if cfgString == "" {
|
|
return nil // No config provided, return nil
|
|
}
|
|
|
|
policyByte, err := os.ReadFile(cfgString)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := protojson.Unmarshal(policyByte, cfgTDX); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func validateTDXFlags() error {
|
|
if err := parseTDXConfig(); err != nil {
|
|
return err
|
|
}
|
|
|
|
rtrms, err := parseRtmrs()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if rtrms != nil {
|
|
cfgTDX.Policy.TdQuoteBodyPolicy.Rtmrs = rtrms
|
|
}
|
|
trustedRoots, err := parseTrustedRoot()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if trustedRoots != nil {
|
|
cfgTDX.RootOfTrust.CabundlePaths = trustedRoots
|
|
}
|
|
|
|
if err := validateTDXinput(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func tdxVerify(reportFilePath string, verifier attestation.Verifier) error {
|
|
attestationFile = reportFilePath
|
|
input, err := openInputFile()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if closer, ok := input.(*os.File); ok {
|
|
defer closer.Close()
|
|
}
|
|
attestationBytes, err := io.ReadAll(input)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return verifier.VerifyAttestation(attestationBytes, reportData, nil)
|
|
}
|
|
|
|
func validateTDXinput() error {
|
|
if err := validateFieldLength("qe_vendor_id", cfgTDX.Policy.HeaderPolicy.QeVendorId, size16); err != nil {
|
|
return err
|
|
}
|
|
if err := validateFieldLength("mr_seam", cfgTDX.Policy.TdQuoteBodyPolicy.MrSeam, size48); err != nil {
|
|
return err
|
|
}
|
|
if err := validateFieldLength("td_attributes", cfgTDX.Policy.TdQuoteBodyPolicy.TdAttributes, size8); err != nil {
|
|
return err
|
|
}
|
|
if err := validateFieldLength("xfam", cfgTDX.Policy.TdQuoteBodyPolicy.Xfam, size8); err != nil {
|
|
return err
|
|
}
|
|
if err := validateFieldLength("mr_td", cfgTDX.Policy.TdQuoteBodyPolicy.MrTd, size48); err != nil {
|
|
return err
|
|
}
|
|
if err := validateFieldLength("mr_config_id", cfgTDX.Policy.TdQuoteBodyPolicy.MrConfigId, size48); err != nil {
|
|
return err
|
|
}
|
|
if err := validateFieldLength("mr_owner", cfgTDX.Policy.TdQuoteBodyPolicy.MrOwnerConfig, size48); err != nil {
|
|
return err
|
|
}
|
|
if err := validateFieldLength("mr_config_owner", cfgTDX.Policy.TdQuoteBodyPolicy.MrOwnerConfig, size48); err != nil {
|
|
return err
|
|
}
|
|
if err := validateFieldLength("minimum_tee_tcb_svn", cfgTDX.Policy.TdQuoteBodyPolicy.MinimumTeeTcbSvn, size16); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|