vault_auth_tee

package module
v0.0.0-...-b0d7bc1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 19, 2024 License: MPL-2.0 Imports: 30 Imported by: 0

README

vault-auth-tee

TEE remote attestation plugin for Hashicorp Vault

Disclaimer

This plugin has not yet received an audit. Use at your own risk.

License

All of the code is licensed under the Mozilla Public License 2.0 unless otherwise specified. Most of the vault plugin code is based on the vault builtin/credential/cert plugin.

Build Setup

$ wget -qO - https://download.01.org/intel-sgx/sgx_repo/ubuntu/intel-sgx-deb.key | sudo apt-key add -
$ sudo bash -c 'echo "deb [arch=amd64] https://download.01.org/intel-sgx/sgx_repo/ubuntu focal main" > /etc/apt/sources.list.d/intel-sgx.list'
$ sudo apt update
$ sudo apt install -y --no-install-recommends \
    libsgx-headers \
    libsgx-enclave-common \
    libsgx-urts \
    libsgx-dcap-quote-verify \
    libsgx-dcap-quote-verify-dev

Configuration

Create or Update via the ${plugin}/tees/$name endpoint

{
    "name": "TEE_role_name",
    "token_policies": "policy1,policy2,...",
    "types": "sgx",
    "sgx_mrsigner": "298037d88782e022e019b3020745b78aa40ed95c77da4bf7f3253d3a44c4fd7e",
    "sgx_mrenclave": "18946b3547d3ca036f4df7b516857e28fd512d69fed3411dc660537912faabf8",
    "sgx_isv_prodid": 0,
    "sgx_min_isv_svn": 0,
    "sgx_allowed_tcb_levels": "Ok,ConfigNeeded,OutOfDate,OutOfDateConfigNeeded,SwHardeningNeeded,ConfigAndSwHardeningNeeded"
}
  • At least one of sgx_mrsigner or sgx_mrenclave must be set. If both are set, both are used for matching.
  • sgx_isv_prodid is optional and defaults to 0.
  • sgx_min_isv_svn is optional and defaults to 0.
  • sgx_allowed_tcb_levels is optional and defaults to Ok.

Authentication

  • Client TEE generates a self-signed TLS client certificate
  • Client TEE generates an attestation report, which includes the hash of the public key of the client certificate (in case of SGX, a sha256 sum of the public key)
  • Client TEE fetches all collateral material via e.g. Intel DCAP (tee_qv_get_collateral)
  • Client TEE sends POST request with a TLS connection using the client certificate to Vault via the ${plugin}/login endpoint with the name, attestation report and the attestation collateral material
  • An optional challenge can be included in the POST request, which is then included in the attestation report of the vault response
{
    "name": "The name of the TEE role to authenticate against.",
    "quote": "The quote Base64 encoded.",
    "collateral": "The collateral Json string encoded.",
    "challenge": "An optional challenge hex encoded."
}

The response contains the Vault token and, if a challenge was included, the vault attestation report, which must contain the challenge bytes in the report_data of the quote.

{
    "auth": {
        "client_token": "The Vault token.",
        "....": "...."
    },
    "data": {
        "quote": "The vault quote Base64 encoded.",
        "collateral": "The vault collateral Json string encoded."
    }
}
Collateral Json encoding

See sgx_ql_lib_common.h

{
    "major_version": uint16,
    "minor_version": uint16,
    "tee_type": uint32,
    "pck_crl_issuer_chain": []byte,
    "root_ca_crl": []byte,
    "pck_crl": []byte,
    "tcb_info_issuer_chain": []byte,
    "tcb_info": []byte,
    "qe_identity_issuer_chain": []byte,
    "qe_identity": []byte
}

Documentation

Index

Constants

View Source
const (
	SgxQlQvResultOk                         = SgxQlQvResult(C.SGX_QL_QV_RESULT_OK)
	SgxQlQvResultConfigNeeded               = SgxQlQvResult(C.SGX_QL_QV_RESULT_CONFIG_NEEDED)
	SgxQlQvResultOutOfDate                  = SgxQlQvResult(C.SGX_QL_QV_RESULT_OUT_OF_DATE)
	SgxQlQvResultOutOfDateConfigNeeded      = SgxQlQvResult(C.SGX_QL_QV_RESULT_OUT_OF_DATE_CONFIG_NEEDED)
	SgxQlQvResultInvalidSignature           = SgxQlQvResult(C.SGX_QL_QV_RESULT_INVALID_SIGNATURE)
	SgxQlQvResultRevoked                    = SgxQlQvResult(C.SGX_QL_QV_RESULT_REVOKED)
	SgxQlQvResultUnspecified                = SgxQlQvResult(C.SGX_QL_QV_RESULT_UNSPECIFIED)
	SgxQlQvResultSwHardeningNeeded          = SgxQlQvResult(C.SGX_QL_QV_RESULT_SW_HARDENING_NEEDED)
	SgxQlQvResultConfigAndSwHardeningNeeded = SgxQlQvResult(C.SGX_QL_QV_RESULT_CONFIG_AND_SW_HARDENING_NEEDED)
)
View Source
const Name = "vault-auth-tee"
View Source
const Version = "0.1.0+dev"

Variables

View Source
var (
	// ErrEmptyReport is returned by VerifyRemoteReport if reportBytes is empty.
	ErrEmptyReport                               = errors.New("empty report")
	ErrSgxQlErrorUnexpected                      = errors.New("SGX_QL_ERROR_UNEXPECTED")
	ErrSgxQlErrorInvalidParameter                = errors.New("SGX_QL_ERROR_INVALID_PARAMETER")
	ErrSgxQlErrorOutOfMemory                     = errors.New("SGX_QL_ERROR_OUT_OF_MEMORY")
	ErrSgxQlErrorEcdsaIdMismatch                 = errors.New("SGX_QL_ERROR_ECDSA_ID_MISMATCH")
	ErrSgxQlPathnameBufferOverflowError          = errors.New("SGX_QL_PATHNAME_BUFFER_OVERFLOW_ERROR")
	ErrSgxQlFileAccessError                      = errors.New("SGX_QL_FILE_ACCESS_ERROR")
	ErrSgxQlErrorStoredKey                       = errors.New("SGX_QL_ERROR_STORED_KEY")
	ErrSgxQlErrorPubKeyIdMismatch                = errors.New("SGX_QL_ERROR_PUB_KEY_ID_MISMATCH")
	ErrSgxQlErrorInvalidPceSigScheme             = errors.New("SGX_QL_ERROR_INVALID_PCE_SIG_SCHEME")
	ErrSgxQlAttKeyBlobError                      = errors.New("SGX_QL_ATT_KEY_BLOB_ERROR")
	ErrSgxQlUnsupportedAttKeyId                  = errors.New("SGX_QL_UNSUPPORTED_ATT_KEY_ID")
	ErrSgxQlUnsupportedLoadingPolicy             = errors.New("SGX_QL_UNSUPPORTED_LOADING_POLICY")
	ErrSgxQlInterfaceUnavailable                 = errors.New("SGX_QL_INTERFACE_UNAVAILABLE")
	ErrSgxQlPlatformLibUnavailable               = errors.New("SGX_QL_PLATFORM_LIB_UNAVAILABLE")
	ErrSgxQlAttKeyNotInitialized                 = errors.New("SGX_QL_ATT_KEY_NOT_INITIALIZED")
	ErrSgxQlAttKeyCertDataInvalid                = errors.New("SGX_QL_ATT_KEY_CERT_DATA_INVALID")
	ErrSgxQlNoPlatformCertData                   = errors.New("SGX_QL_NO_PLATFORM_CERT_DATA")
	ErrSgxQlOutOfEpc                             = errors.New("SGX_QL_OUT_OF_EPC")
	ErrSgxQlErrorReport                          = errors.New("SGX_QL_ERROR_REPORT")
	ErrSgxQlEnclaveLost                          = errors.New("SGX_QL_ENCLAVE_LOST")
	ErrSgxQlInvalidReport                        = errors.New("SGX_QL_INVALID_REPORT")
	ErrSgxQlEnclaveLoadError                     = errors.New("SGX_QL_ENCLAVE_LOAD_ERROR")
	ErrSgxQlUnableToGenerateQeReport             = errors.New("SGX_QL_UNABLE_TO_GENERATE_QE_REPORT")
	ErrSgxQlKeyCertifcationError                 = errors.New("SGX_QL_KEY_CERTIFCATION_ERROR")
	ErrSgxQlNetworkError                         = errors.New("SGX_QL_NETWORK_ERROR")
	ErrSgxQlMessageError                         = errors.New("SGX_QL_MESSAGE_ERROR")
	ErrSgxQlNoQuoteCollateralData                = errors.New("SGX_QL_NO_QUOTE_COLLATERAL_DATA")
	ErrSgxQlQuoteCertificationDataUnsupported    = errors.New("SGX_QL_QUOTE_CERTIFICATION_DATA_UNSUPPORTED")
	ErrSgxQlQuoteFormatUnsupported               = errors.New("SGX_QL_QUOTE_FORMAT_UNSUPPORTED")
	ErrSgxQlUnableToGenerateReport               = errors.New("SGX_QL_UNABLE_TO_GENERATE_REPORT")
	ErrSgxQlQeReportInvalidSignature             = errors.New("SGX_QL_QE_REPORT_INVALID_SIGNATURE")
	ErrSgxQlQeReportUnsupportedFormat            = errors.New("SGX_QL_QE_REPORT_UNSUPPORTED_FORMAT")
	ErrSgxQlPckCertUnsupportedFormat             = errors.New("SGX_QL_PCK_CERT_UNSUPPORTED_FORMAT")
	ErrSgxQlPckCertChainError                    = errors.New("SGX_QL_PCK_CERT_CHAIN_ERROR")
	ErrSgxQlTcbinfoUnsupportedFormat             = errors.New("SGX_QL_TCBINFO_UNSUPPORTED_FORMAT")
	ErrSgxQlTcbinfoMismatch                      = errors.New("SGX_QL_TCBINFO_MISMATCH")
	ErrSgxQlQeidentityUnsupportedFormat          = errors.New("SGX_QL_QEIDENTITY_UNSUPPORTED_FORMAT")
	ErrSgxQlQeidentityMismatch                   = errors.New("SGX_QL_QEIDENTITY_MISMATCH")
	ErrSgxQlTcbOutOfDate                         = errors.New("SGX_QL_TCB_OUT_OF_DATE")
	ErrSgxQlTcbOutOfDateConfigurationNeeded      = errors.New("SGX_QL_TCB_OUT_OF_DATE_CONFIGURATION_NEEDED")
	ErrSgxQlSgxEnclaveIdentityOutOfDate          = errors.New("SGX_QL_SGX_ENCLAVE_IDENTITY_OUT_OF_DATE")
	ErrSgxQlSgxEnclaveReportIsvsvnOutOfDate      = errors.New("SGX_QL_SGX_ENCLAVE_REPORT_ISVSVN_OUT_OF_DATE")
	ErrSgxQlQeIdentityOutOfDate                  = errors.New("SGX_QL_QE_IDENTITY_OUT_OF_DATE")
	ErrSgxQlSgxTcbInfoExpired                    = errors.New("SGX_QL_SGX_TCB_INFO_EXPIRED")
	ErrSgxQlSgxPckCertChainExpired               = errors.New("SGX_QL_SGX_PCK_CERT_CHAIN_EXPIRED")
	ErrSgxQlSgxCrlExpired                        = errors.New("SGX_QL_SGX_CRL_EXPIRED")
	ErrSgxQlSgxSigningCertChainExpired           = errors.New("SGX_QL_SGX_SIGNING_CERT_CHAIN_EXPIRED")
	ErrSgxQlSgxEnclaveIdentityExpired            = errors.New("SGX_QL_SGX_ENCLAVE_IDENTITY_EXPIRED")
	ErrSgxQlPckRevoked                           = errors.New("SGX_QL_PCK_REVOKED")
	ErrSgxQlTcbRevoked                           = errors.New("SGX_QL_TCB_REVOKED")
	ErrSgxQlTcbConfigurationNeeded               = errors.New("SGX_QL_TCB_CONFIGURATION_NEEDED")
	ErrSgxQlUnableToGetCollateral                = errors.New("SGX_QL_UNABLE_TO_GET_COLLATERAL")
	ErrSgxQlErrorInvalidPrivilege                = errors.New("SGX_QL_ERROR_INVALID_PRIVILEGE")
	ErrSgxQlNoQveIdentityData                    = errors.New("SGX_QL_NO_QVE_IDENTITY_DATA")
	ErrSgxQlCrlUnsupportedFormat                 = errors.New("SGX_QL_CRL_UNSUPPORTED_FORMAT")
	ErrSgxQlQeidentityChainError                 = errors.New("SGX_QL_QEIDENTITY_CHAIN_ERROR")
	ErrSgxQlTcbinfoChainError                    = errors.New("SGX_QL_TCBINFO_CHAIN_ERROR")
	ErrSgxQlErrorQvlQveMismatch                  = errors.New("SGX_QL_ERROR_QVL_QVE_MISMATCH")
	ErrSgxQlTcbSwHardeningNeeded                 = errors.New("SGX_QL_TCB_SW_HARDENING_NEEDED")
	ErrSgxQlTcbConfigurationAndSwHardeningNeeded = errors.New("SGX_QL_TCB_CONFIGURATION_AND_SW_HARDENING_NEEDED")
	ErrSgxQlUnsupportedMode                      = errors.New("SGX_QL_UNSUPPORTED_MODE")
	ErrSgxQlNoDevice                             = errors.New("SGX_QL_NO_DEVICE")
	ErrSgxQlServiceUnavailable                   = errors.New("SGX_QL_SERVICE_UNAVAILABLE")
	ErrSgxQlNetworkFailure                       = errors.New("SGX_QL_NETWORK_FAILURE")
	ErrSgxQlServiceTimeout                       = errors.New("SGX_QL_SERVICE_TIMEOUT")
	ErrSgxQlErrorBusy                            = errors.New("SGX_QL_ERROR_BUSY")
	ErrSgxQlUnknownMessageResponse               = errors.New("SGX_QL_UNKNOWN_MESSAGE_RESPONSE")
	ErrSgxQlPersistentStorageError               = errors.New("SGX_QL_PERSISTENT_STORAGE_ERROR")
	ErrSgxQlErrorMessageParsingError             = errors.New("SGX_QL_ERROR_MESSAGE_PARSING_ERROR")
	ErrSgxQlPlatformUnknown                      = errors.New("SGX_QL_PLATFORM_UNKNOWN")
	ErrSgxQlUnknownApiVersion                    = errors.New("SGX_QL_UNKNOWN_API_VERSION")
	ErrSgxQlCertsUnavailable                     = errors.New("SGX_QL_CERTS_UNAVAILABLE")
	ErrSgxQlQveidentityMismatch                  = errors.New("SGX_QL_QVEIDENTITY_MISMATCH")
	ErrSgxQlQveOutOfDate                         = errors.New("SGX_QL_QVE_OUT_OF_DATE")
	ErrSgxQlPswNotAvailable                      = errors.New("SGX_QL_PSW_NOT_AVAILABLE")
	ErrSgxQlCollateralVersionNotSupported        = errors.New("SGX_QL_COLLATERAL_VERSION_NOT_SUPPORTED")
	ErrSgxQlTdxModuleMismatch                    = errors.New("SGX_QL_TDX_MODULE_MISMATCH")
	ErrSgxQlQeidentityNotFound                   = errors.New("SGX_QL_QEIDENTITY_NOT_FOUND")
	ErrSgxQlTcbinfoNotFound                      = errors.New("SGX_QL_TCBINFO_NOT_FOUND")
	ErrSgxQlInternalServerError                  = errors.New("SGX_QL_INTERNAL_SERVER_ERROR")
	ErrSgxQlSupplementalDataVersionNotSupported  = errors.New("SGX_QL_SUPPLEMENTAL_DATA_VERSION_NOT_SUPPORTED")
	ErrSgxQlRootCaUntrusted                      = errors.New("SGX_QL_ROOT_CA_UNTRUSTED")
	ErrSgxQlTcbNotSupported                      = errors.New("SGX_QL_TCB_NOT_SUPPORTED")
)
View Source
var (

	// ErrNotFound indicates the request OCSP response was not found. It is used to
	// indicate that the responder should reply with unauthorizedErrorResponse.
	ErrNotFound = errors.New("Request OCSP Response not found")
)

Functions

func Backend

func Backend() *backend

func Contains

func Contains[T comparable](s []T, e T) bool

func Factory

func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, error)

func SgxGetQuote

func SgxGetQuote(reportData []byte) ([]byte, error)

Types

type InMemorySource

type InMemorySource map[string][]byte

An InMemorySource is a map from serialNumber -> der(response)

func (InMemorySource) Response

func (src InMemorySource) Response(request *ocsp.Request) ([]byte, http.Header, error)

Response looks up an OCSP response to provide for a given request. InMemorySource looks up a response purely based on serial number, without regard to what issuer the request is asking for.

type Quote

type Quote struct {
	Version    [2]byte  `json:"version"`
	KeyType    [2]byte  `json:"key_type"`
	Reserved   [4]byte  `json:"reserved"`
	QeSvn      [2]byte  `json:"qe_svn"`
	PceSvn     [2]byte  `json:"pce_svn"`
	QeVendorId [16]byte `json:"qe_vendor_id"`
	UserData   [20]byte `json:"user_data"`
	ReportBody struct {
		Cpusvn     [16]byte `json:"cpusvn"`
		Miscselect [4]byte  `json:"miscselect"`
		Reserved1  [28]byte `json:"reserved1"`
		Features   [8]byte  `json:"features"`
		Xfrm       [8]byte  `json:"xfrm"`
		MrEnclave  [32]byte `json:"mrenclave"`
		Reserved2  [32]byte `json:"reserved2"`
		MrSigner   [32]byte `json:"mrsigner"`
		Reserved3  [96]byte `json:"reserved3"`
		IsvProdid  [2]byte  `json:"isv_prodid"`
		IsvSvn     [2]byte  `json:"isv_svn"`
		Reserved4  [60]byte `json:"reserved4"`
		ReportData [64]byte `json:"reportdata"`
	} `json:"report_body"`
}

type QuoteVerificationResult

type QuoteVerificationResult struct {
	VerificationResult     SgxQlQvResult
	CollateralExpired      bool
	EarliestExpirationDate int64
	Advisory               string
	Quote                  Quote
}

func SgxVerifyRemoteReport

func SgxVerifyRemoteReport(reportBytes []byte, expirationCheckDate int64) (*QuoteVerificationResult, error)

SgxVerifyRemoteReport verifies the SGX attestation report. It needs to connect to servers to collect the collateral material.

func SgxVerifyRemoteReportCollateral

func SgxVerifyRemoteReportCollateral(reportBytes []byte, collateral TeeQvCollateral, expirationCheckDate int64) (*QuoteVerificationResult, error)

SgxVerifyRemoteReportCollateral verifies the report along with the collateral material. It does not need to start an SGX enclave, nor does it need to connect to any server.

type Responder

type Responder struct {
	Source Source
	// contains filtered or unexported fields
}

A Responder object provides the HTTP logic to expose a Source of OCSP responses.

func NewResponder

func NewResponder(t logger, source Source, stats Stats) *Responder

NewResponder instantiates a Responder with the give Source.

func (*Responder) ServeHTTP

func (rs *Responder) ServeHTTP(response http.ResponseWriter, request *http.Request)

A Responder can process both GET and POST requests. The mapping from an OCSP request to an OCSP response is done by the Source; the Responder simply decodes the request, and passes back whatever response is provided by the source. Note: The caller must use http.StripPrefix to strip any path components (including '/') on GET requests. Do not use this responder in conjunction with http.NewServeMux, because the default handler will try to canonicalize path components by changing any strings of repeated '/' into a single '/', which will break the base64 encoding.

type SgxQlQvResult

type SgxQlQvResult uint32

type Source

type Source interface {
	Response(*ocsp.Request) ([]byte, http.Header, error)
}

Source represents the logical source of OCSP responses, i.e., the logic that actually chooses a response based on a request. In order to create an actual responder, wrap one of these in a Responder object and pass it to http.Handle. By default the Responder will set the headers Cache-Control to "max-age=(response.NextUpdate-now), public, no-transform, must-revalidate", Last-Modified to response.ThisUpdate, Expires to response.NextUpdate, ETag to the SHA256 hash of the response, and Content-Type to application/ocsp-response. If you want to override these headers, or set extra headers, your source should return a http.Header with the headers you wish to set. If you don'log want to set any extra headers you may return nil instead.

type Stats

type Stats interface {
	ResponseStatus(ocsp.ResponseStatus)
}

Stats is a basic interface that allows users to record information about returned responses

type TeeEntry

type TeeEntry struct {
	tokenutil.TokenParams

	Name                string
	DisplayName         string
	Types               map[string]bool
	SgxMrsigner         string
	SgxMrenclave        string
	SgxIsvProdid        int
	SgxMinIsvSvn        int
	SgxAllowedTcbLevels map[SgxQlQvResult]bool
}

type TeeQvCollateral

type TeeQvCollateral struct {
	MajorVersion          uint16 `json:"major_version"`
	MinorVersion          uint16 `json:"minor_version"`
	TeeType               uint32 `json:"tee_type"`
	PckCrlIssuerChain     []byte `json:"pck_crl_issuer_chain"`
	RootCaCrl             []byte `json:"root_ca_crl"`
	PckCrl                []byte `json:"pck_crl"`
	TcbInfoIssuerChain    []byte `json:"tcb_info_issuer_chain"`
	TcbInfo               []byte `json:"tcb_info"`
	QeIdentityIssuerChain []byte `json:"qe_identity_issuer_chain"`
	QeIdentity            []byte `json:"qe_identity"`
}

func SgxGetCollateral

func SgxGetCollateral(reportBytes []byte) (*TeeQvCollateral, error)

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL