sdk

package module
v0.36.0 Latest Latest
Warning

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

Go to latest
Published: Oct 30, 2026 License: BSD-3-Clause-Clear Imports: 63 Imported by: 14

README

OpenTDF Data Security SDK

A Go implementation of the OpenTDF protocol, and access library for services included in the Data Security Platform.

New to the OpenTDF SDK? See the OpenTDF SDK Quickstart Guide for a comprehensive introduction.

Note: if you are consuming the SDK as a submodule you may need to add replace directives as follows:

replace (
  github.com/opentdf/platform/service => ./opentdf/service
	github.com/opentdf/platform/lib/fixtures => ./opentdf/lib/fixtures
	github.com/opentdf/platform/protocol/go => ./opentdf/protocol/go
	github.com/opentdf/platform/lib/ocrypto => ./opentdf/lib/ocrypto
	github.com/opentdf/platform/sdk => ./opentdf/sdk
	github.com/opentdf/platform/service => ./opentdf/service
)

Quick Start of the Go SDK

This example demonstrates how to create and read TDF (Trusted Data Format) files using the OpenTDF SDK.

Prerequisites: Follow the OpenTDF Quickstart to get a local platform running, or if you already have a hosted version, replace the values with your OpenTDF platform details.

For more code examples, see:

package main

import (
	"bytes"
	"context"
	"fmt"
	"log"
	"os"
	"strings"

	"github.com/opentdf/platform/sdk"
)

func main() {
	// Initialize SDK with platform endpoint and authentication
	// Replace these values with your actual configuration:
	platformEndpoint := "http://localhost:8080"           // Your platform URL
	clientID := "opentdf"                                 // Your OAuth client ID
	clientSecret := "secret"                              // Your OAuth client secret
	keycloakURL := "http://localhost:8888/auth/realms/opentdf" // Your Keycloak realm URL

	s, err := sdk.New(
		platformEndpoint,
		sdk.WithClientCredentials(clientID, clientSecret, []string{"email", "profile"}),
		sdk.WithPlatformConfiguration(sdk.PlatformConfiguration{
			"platform_issuer": keycloakURL,
		}),
		sdk.WithInsecurePlaintextConn(), // Only for local development with HTTP
	)
	if err != nil {
		log.Fatalf("Failed to create SDK: %v", err)
	}
	defer s.Close()

	// Create a TDF
	// This attribute is created in the quickstart guide
	dataAttribute := "https://opentdf.io/attr/department/value/finance"

	plaintext := strings.NewReader("Hello, world!")
	var ciphertext bytes.Buffer
	_, err = s.CreateTDF(
		&ciphertext,
		plaintext,
		sdk.WithDataAttributes(dataAttribute),
	)
	if err != nil {
		log.Fatalf("Failed to create TDF: %v", err)
	}

	fmt.Printf("Ciphertext is %d bytes long\n", ciphertext.Len())

	// Decrypt the TDF and write the plaintext to a file.
	// DecryptTo contacts the Key Access Service (KAS) to verify that this
	// client has been granted access to the data attributes, then decrypts
	// the TDF and writes the plaintext directly to the given writer.
	// Note: The client must have entitlements configured on the platform first.
	f, err := os.Create("output.txt")
	if err != nil {
		log.Fatalf("Failed to create output file: %v", err)
	}
	defer f.Close()

	if err := s.DecryptTo(context.Background(), f, ciphertext.Bytes()); err != nil {
		log.Fatalf("Failed to decrypt TDF: %v", err)
	}

	fmt.Println("Successfully created and decrypted TDF")
}

DecryptTo is one of three decrypt convenience helpers, each a thin wrapper over LoadTDF + Reader.WriteTo for the common decrypt-to-plaintext case — pick whichever shape fits. Each takes a ctx context.Context that governs its KAS rewrap request.

DecryptBytes — decrypt ciphertext bytes to plaintext bytes:

Before:

reader, err := s.LoadTDF(bytes.NewReader(ciphertext))
if err != nil {
    return err
}
var buf bytes.Buffer
_, err = reader.WriteTo(&buf)
plaintext := buf.Bytes()

After:

plaintext, err := s.DecryptBytes(ctx, ciphertext)

DecryptTo — decrypt ciphertext bytes to any io.Writer:

Before:

reader, err := s.LoadTDF(bytes.NewReader(ciphertext))
if err != nil {
    return err
}
_, err = reader.WriteTo(os.Stdout)

After:

err := s.DecryptTo(ctx, os.Stdout, ciphertext)

DecryptFile — decrypt a TDF file to an output file:

Before (elided — open input, LoadTDF, create output, WriteTo, close both, handle errors at each step):

in, err := os.Open("secret.tdf")
// ... LoadTDF, os.Create("secret.txt"), WriteTo, close both, handle errors at each step

After:

err := s.DecryptFile(ctx, "secret.tdf", "secret.txt")

Call LoadTDF directly instead when streaming very large payloads, or when you need to read manifest data (attributes, assertions) between load and write.

Configuration Values

Replace these placeholder values with your actual configuration:

Variable Default (Quickstart) Description
platformEndpoint http://localhost:8080 Your OpenTDF platform URL
clientID opentdf OAuth client ID (from quickstart)
clientSecret secret OAuth client secret (from quickstart)
keycloakURL http://localhost:8888/auth/realms/opentdf Your Keycloak realm URL
dataAttribute https://opentdf.io/attr/department/value/finance Data attribute FQN (created in quickstart)

Before running:

  1. Follow the OpenTDF Quickstart to start the platform
  2. Create an OAuth client in Keycloak and note the credentials
  3. Grant your client entitlements to the department attribute (see Managing policy)

Expected Output:

Ciphertext is 1234 bytes long
Successfully created and decrypted TDF

The output.txt file will contain the decrypted plaintext: Hello, world!

Authentication Options

The SDK supports multiple authentication methods:

Client Credentials (OAuth 2.0):

sdk.WithClientCredentials("client-id", "client-secret", []string{"scope1", "scope2"})

Early Token Renewal:

Use sdk.WithTokenExpirationBuffer(90 * time.Second) to renew SDK-managed tokens on the next request when less than 90 seconds remain. Defaults to 10 seconds. Zero disables early renewal; negative values are rejected.

TLS/mTLS Authentication:

import "crypto/tls"

// Load your client certificate and key
cert, err := tls.LoadX509KeyPair("client.crt", "client.key")
if err != nil {
	log.Fatal(err)
}

tlsConfig := &tls.Config{
	Certificates: []tls.Certificate{cert},
	MinVersion:   tls.VersionTLS12,
}
sdk.WithTLSCredentials(tlsConfig, []string{"audience1", "audience2"})

Custom OAuth2 Token Source:

import "golang.org/x/oauth2"

tokenSource := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: "your-token"})
sdk.WithOAuthAccessTokenSource(tokenSource)

Token Exchange:

sdk.WithTokenExchange("subject-token", []string{"audience1", "audience2"})

Base key

The platform may publish a base KAS public key in its well-known configuration. Retrieve it via:

baseKey, err := s.GetBaseKey(ctx)

Development

To test, run

go test ./... -short -race -cover

Documentation

Index

Constants

View Source
const (
	SystemMetadataAssertionID = "system-metadata"
	SystemMetadataSchemaV1    = "system-metadata-v1"
)
View Source
const (
	// Failure while connecting to a service.
	// Check your configuration and/or retry.
	ErrGrpcDialFailed      = Error("failed to dial grpc endpoint")
	ErrShutdownFailed      = Error("failed to shutdown sdk")
	ErrPlatformUnreachable = Error("platform unreachable or not responding")
	// ErrHealthCheckUnsupported is returned by SDK.IsHealthy when the SDK is configured
	// in IPC mode, which does not support the gRPC Health protocol.
	ErrHealthCheckUnsupported        = Error("health check not supported in IPC mode")
	ErrPlatformConfigFailed          = Error("failed to retrieve platform configuration")
	ErrPlatformEndpointMalformed     = Error("platform endpoint is malformed")
	ErrPlatformIssuerNotFound        = Error("issuer not found in well-known idp configuration")
	ErrPlatformAuthzEndpointNotFound = Error("authorization_endpoint not found in well-known idp configuration")
	ErrPlatformTokenEndpointNotFound = Error("token_endpoint not found in well-known idp configuration")
	ErrPlatformEndpointNotFound      = Error("platform_endpoint not found in well-known configuration")
	ErrAccessTokenInvalid            = Error("access token is invalid")
	ErrTokenExpirationBufferInvalid  = Error("token expiration buffer must not be negative")
	ErrNoAccessTokenSource           = Error("no access token source configured; SDK was created without credentials")
	ErrWellKnowConfigEmpty           = Error("well-known configuration is empty")
	ErrAttributeNotFound             = Error("attribute not found")
)
View Source
const (
	DefaultRSAKeySize = 2048
	ECKeySize256      = 256
	ECKeySize384      = 384
	ECKeySize521      = 521
)
View Source
const (
	// Deprecated: unused; the manifest is always JSON.
	JSONFormat = iota
	// Deprecated: never implemented.
	XMLFormat
)
View Source
const (
	// HS256 selects HMAC-SHA256.
	//
	// Deprecated: use [RootHS256] or [SegmentHS256].
	HS256 = iota
	// GMAC selects AES-GCM tag extraction.
	//
	// Deprecated: use [SegmentGMAC]. GMAC is not a legal root algorithm.
	GMAC
)
View Source
const (
	// The latest version of TDF Spec currently targeted by the SDK.
	// By default, new files will conform to this version of the spec
	// and, where possible, older versions will still be readable.
	TDFSpecVersion = "4.3.0"

	// The three-part semantic version number of this SDK
	Version = "0.36.0" // x-release-please-version
)

Variables

View Source
var (
	ErrBaseKeyNotFound        = errors.New("base key not found in well-known configuration")
	ErrBaseKeyInvalidFormat   = errors.New("base key has invalid format")
	ErrBaseKeyEmpty           = errors.New("base key is empty or not provided")
	ErrMarshalBaseKeyFailed   = errors.New("failed to marshal base key configuration")
	ErrUnmarshalBaseKeyFailed = errors.New("failed to unmarshal base key configuration")
)
View Source
var (
	// ErrChunkedAlreadyFinalized is returned when a ChunkedWriter
	// method is called after Finalize has already succeeded.
	ErrChunkedAlreadyFinalized = errors.New("chunked: writer already finalized")

	// ErrChunkedCleanupFailed is returned when a failed WriteSegment
	// could not roll its partial write back out of the archive, and by
	// every later call on that writer.
	//
	// CleanupSegment is what makes a failed WriteSegment retryable: it
	// returns the archive to a state indistinguishable from never
	// having attempted the index. If it fails, the archive may still
	// carry that attempt's record and its contribution to the payload's
	// size and CRC, and nothing here can tell how much. Continuing
	// would write later segments at offsets computed from a payload
	// length that counts bytes the manifest never describes, producing
	// an archive that assembles cleanly and fails at decrypt. Fencing
	// the writer surfaces it at the next call instead.
	//
	// Unreachable with the default archive writer, whose CleanupSegment
	// cannot fail; it is the injected-factory case this guards.
	ErrChunkedCleanupFailed = errors.New("chunked: segment cleanup failed after a failed write; writer is unusable")

	// ErrChunkedCloseFailed is returned when the archive's Close fails
	// after its Finalize already succeeded. The archive is terminally
	// finalized internally at that point regardless, so the writer is
	// unusable: every subsequent call returns this same error rather
	// than retrying against an archive that can only fail again.
	//
	// Note what is being discarded. Finalize had already returned a
	// complete, valid trailer; it is dropped because the archive
	// reported a fault afterwards, not because the bytes were bad. The
	// payload segments already uploaded are still sound -- the TDF is
	// unfinishable through this writer, but nothing about the data
	// itself is in question.
	//
	// Unreachable with the default archive writer, whose Close cannot
	// fail; it is the injected-factory case this guards.
	ErrChunkedCloseFailed = errors.New("chunked: archive close failed after finalize; writer is unusable")

	// ErrChunkedFinalizeFailed is returned when the archive reports
	// that it had already mutated itself before failing -- or reports
	// nothing either way -- and by every later call on that writer.
	// Such a failure is not retryable: zipstream appends the payload
	// entry to the central directory partway through finalizing, then
	// can still fail on the manifest entry, on a ZIP64 requirement, or
	// on generating the directory bytes, and it does not roll that back
	// or mark itself finalized. A second attempt would append the
	// payload entry again, yielding a central directory with two
	// entries for one payload: an archive some readers accept and
	// silently misread. Failing fast is the only safe answer.
	//
	// An archive failure raised before any mutation does not produce
	// this error and does not fence the writer; see Finalize.
	ErrChunkedFinalizeFailed = errors.New("chunked: archive finalize failed; writer is unusable")

	// ErrChunkedInvalidSegmentIndex is returned when WriteSegment
	// receives a negative index.
	ErrChunkedInvalidSegmentIndex = errors.New("chunked: invalid segment index")

	// ErrChunkedMissingSegmentZero is returned when Finalize is called
	// on a writer that never wrote segment 0. Only segment 0 emits the
	// payload's ZIP local file header, and every offset in the manifest
	// and central directory is measured from it.
	ErrChunkedMissingSegmentZero = errors.New("chunked: segment 0 was never written; it carries the payload's ZIP local file header")

	// ErrChunkedSegmentAlreadyWritten is returned when WriteSegment
	// receives an index that was already written.
	ErrChunkedSegmentAlreadyWritten = errors.New("chunked: segment already written")

	// ErrChunkedWriteInFlight is returned by Finalize when a
	// WriteSegment has reserved an index but the archive has not yet
	// accepted its bytes. Finalizing inside that window would omit the
	// segment from the manifest while the racing WriteSegment still
	// returned success, so the caller would have no signal at all.
	//
	// Nothing was written and the writer is not fenced: join the
	// outstanding goroutines and call Finalize again.
	ErrChunkedWriteInFlight = errors.New("chunked: a segment write is still in flight; every WriteSegment must return before Finalize")
)

Sentinel errors returned by ChunkedWriter.

Experimental: not part of the stable SDK API; may change or be removed.

View Source
var (
	// ErrTDFNotDecryptable marks DecryptBytes/DecryptTo/DecryptFile as having
	// failed before decryption began — the input itself isn't decryptable
	// (corrupt/invalid TDF bytes, a rejected TDFReaderOption, a schema
	// validation failure). Retrying with the same input won't help. Test for
	// it with errors.Is(err, ErrTDFNotDecryptable); the underlying LoadTDF
	// error remains reachable through the same chain.
	ErrTDFNotDecryptable = errors.New("tdf: input is not decryptable")

	// ErrTDFDecryptFailed marks DecryptBytes/DecryptTo/DecryptFile as having
	// failed during decryption itself — most commonly a KAS rewrap failure
	// (the caller isn't entitled), but also writer errors or payload
	// integrity errors. Test for it with errors.Is(err, ErrTDFDecryptFailed);
	// the underlying Reader.WriteTo error remains reachable through the same
	// chain.
	ErrTDFDecryptFailed = errors.New("tdf: decrypt failed")
)
View Source
var (

	// ErrAESGCMExhausted is returned by a TDF writer that refuses to encrypt
	// another segment under its data encryption key (DEK). Payload segment IVs
	// are random 96-bit values, so the chance that any two collide grows with
	// the square of the segment count (about k^2 / 2^97 for k segments). NIST SP
	// 800-38D §8 limits that probability to 2^-32 per key, which is reached near
	// 2^32 encryptions; see maxAESGCMSegmentsPerDEK. A collision would expose the
	// XOR of two plaintexts and allow forgery under the DEK, so the writer fails
	// rather than continue. Start a new TDF, which draws a new DEK, or use a
	// larger segment size.
	ErrAESGCMExhausted = errors.New("tdf: AES-GCM IV collision limit reached for this data encryption key")

	// Exposed tamper detection errors, Catch all possible tamper errors with errors.Is(ErrTampered)
	ErrTampered                = errors.New("tamper detected")
	ErrRootSigValidation       = fmt.Errorf("[%w] tdf: failed integrity check on root signature", ErrTampered)
	ErrSegSizeMismatch         = fmt.Errorf("[%w] tdf: mismatch encrypted segment size in manifest", ErrTampered)
	ErrSegSizeUnresolved       = fmt.Errorf("[%w] tdf: segment size invalid or missing from manifest, with no default to fall back on", ErrTampered)
	ErrSegSigValidation        = fmt.Errorf("[%w] tdf: failed integrity check on segment hash", ErrTampered)
	ErrGMACSignatureFailed     = fmt.Errorf("[%w] tdf: ciphertext too short for a gmac signature", ErrTampered)
	ErrTDFPayloadReadFail      = fmt.Errorf("[%w] tdf: fail to read payload from tdf", ErrTampered)
	ErrTDFPayloadInvalidOffset = fmt.Errorf("[%w] sdk.Reader.ReadAt: negative offset", ErrTampered)
	ErrRootSignatureFailure    = fmt.Errorf("[%w] tdf: issue verifying root signature", ErrTampered)
	ErrRewrapBadRequest        = fmt.Errorf("[%w] tdf: rewrap request 400", ErrTampered)

	// ErrUnsupportedRootIntegrityAlgorithm rejects any root signature algorithm
	// other than HS256, on both the write and the read path.
	ErrUnsupportedRootIntegrityAlgorithm = errors.New("tdf: unsupported root integrity algorithm")

	// ErrUnsupportedSegmentIntegrityAlgorithm rejects a segment algorithm that
	// is neither HS256 nor GMAC. SegmentIntegrityAlg is int-backed, so this
	// catches an out-of-range value before it reaches a manifest.
	ErrUnsupportedSegmentIntegrityAlgorithm = errors.New("tdf: unsupported segment integrity algorithm")

	// KAS request errors — client/configuration issues, not integrity failures
	ErrKASRequestError = errors.New("tdf: KAS request error")
	ErrRewrapForbidden = errors.New("tdf: rewrap request 403")
)
View Source
var ErrInvalid = errors.New("invalid type")
View Source
var ErrInvalidPerSchema = errors.New("manifest was not valid")

Indicates JSON Schema validation failed for the manifest or header of the TDF file. Some invalid manifests are still usable, so this file may still be usable.

View Source
var ErrSplitterRequiresDefaultKAS = errors.New("chunked: default splitter requires a default KAS; supply WithChunkedDefaultKAS or WithChunkedKeySplitter")

ErrSplitterRequiresDefaultKAS is returned by the default key splitter when no default KAS was supplied. The default splitter is single-KAS only; multi-attribute splits require injecting a full splitter via WithChunkedKeySplitter.

View Source
var ErrSplitterUnsupportedAlgorithm = errors.New("chunked: unsupported KAS key algorithm")

ErrSplitterUnsupportedAlgorithm is returned by the default key splitter when the default KAS advertises a key algorithm this SDK has no wrapping scheme for.

Functions

func FromBulkErrors added in v0.3.26

func FromBulkErrors(err error) ([]error, bool)

FromBulkErrors Returns List of Decrypt Failures and true if is decryption failures

func IsPlatformEndpointMalformed added in v0.4.5

func IsPlatformEndpointMalformed(e string) bool

func IsValidTdf added in v0.3.5

func IsValidTdf(reader io.ReadSeeker) (bool, error)

Detects whether, or not the reader is a valid TDF. It first checks if it can "open" it Then attempts to extract a manifest, then finally it validates the manifest using the json schema If any of the checks fail, it will return false.

Something to keep in mind is that if we make updates to the schema, such as making certain fields 'required', older TDF versions will fail despite being valid. So each time we release an update to the TDF spec, we'll need to include the respective schema in the schema directory, then update this code to validate against all previously known schema versions.

func KeyTypeToPolicyAlgorithm added in v0.21.0

func KeyTypeToPolicyAlgorithm(kt ocrypto.KeyType) (policy.Algorithm, error)

func NewCertExchangeTokenSource added in v0.2.1

func NewCertExchangeTokenSource(logger *slog.Logger, info oauth.CertExchangeInfo, credentials oauth.ClientCredentials, idpTokenEndpoint string, dpop *ocrypto.RsaKeyPair) (auth.AccessTokenSource, error)

func NewDPoPValidationHTTPClient added in v0.30.0

func NewDPoPValidationHTTPClient(base *http.Client, opts ...Option) (*http.Client, error)

NewDPoPValidationHTTPClient wraps base so its requests carry a DPoP proof signed with the key resolved from opts (the same WithDPoP* options passed to New). It is intended for token-endpoint calls made outside the SDK's own connection (e.g. a CLI pre-flight credential check): the proof binds the request via htu but carries no ath claim or Authorization header, and DPoP-Nonce challenges are retried.

When no DPoP key is configured in opts a fresh ephemeral ES256 key is generated, mirroring the default the real SDK client applies in buildIDPTokenSource. This keeps the pre-flight validation token request consistent with the credentialed client so a DPoP-enforcing token endpoint accepts both; the throwaway validation token is never reused, so an ephemeral key is fine.

func PolicyAlgorithmToKeyType added in v0.21.0

func PolicyAlgorithmToKeyType(alg policy.Algorithm) (ocrypto.KeyType, error)

func SupportedFeatures added in v0.30.0

func SupportedFeatures() []string

SupportedFeatures returns a list of optional features supported by this SDK build. Used by xtest integration harness for feature detection.

These strings are part of the stable API surface. The xtest harness silently SKIPs (rather than fails) tests gated on an unknown feature string, so removing or renaming a feature here must be coordinated with opentdf/tests before merging to avoid quietly disabling coverage.

Types

type AllowList added in v0.4.4

type AllowList map[string]bool

func (AllowList) Add added in v0.4.4

func (a AllowList) Add(kasURL string) error

func (AllowList) IsAllowed added in v0.4.4

func (a AllowList) IsAllowed(kasURL string) bool

type AppliesToState added in v0.3.5

type AppliesToState string

AppliesToState indicates whether the assertion applies to encrypted or unencrypted data.

const (
	Encrypted   AppliesToState = "encrypted"
	Unencrypted AppliesToState = "unencrypted"
)

func (AppliesToState) String added in v0.3.5

func (ats AppliesToState) String() string

String returns the string representation of the applies to state.

type Assertion

type Assertion struct {
	ID             string         `json:"id"`
	Type           AssertionType  `json:"type"`
	Scope          Scope          `json:"scope"`
	AppliesToState AppliesToState `json:"appliesToState,omitempty"`
	Statement      Statement      `json:"statement"`
	Binding        Binding        `json:"binding,omitempty"`
}

func (Assertion) GetHash added in v0.3.5

func (a Assertion) GetHash() ([]byte, error)

GetHash returns the hash of the assertion in hex format.

func (*Assertion) Sign added in v0.3.5

func (a *Assertion) Sign(hash, sig string, key AssertionKey) error

Sign signs the assertion with the given hash and signature using the key. It returns an error if the signing fails. The assertion binding is updated with the method and the signature.

func (Assertion) Verify added in v0.3.5

func (a Assertion) Verify(key AssertionKey) (string, string, error)

Verify checks the binding signature of the assertion and returns the hash and the signature. It returns an error if the verification fails.

type AssertionConfig added in v0.3.5

type AssertionConfig struct {
	ID             string         `validate:"required"`
	Type           AssertionType  `validate:"required"`
	Scope          Scope          `validate:"required"`
	AppliesToState AppliesToState `validate:"required"`
	Statement      Statement
	SigningKey     AssertionKey
}

AssertionConfig is a shadow of Assertion with the addition of the signing key. It is used on creation

func GetSystemMetadataAssertionConfig added in v0.5.0

func GetSystemMetadataAssertionConfig() (AssertionConfig, error)

GetSystemMetadataAssertionConfig returns a default assertion configuration with predefined values.

type AssertionKey added in v0.3.5

type AssertionKey struct {
	// Algorithm of the key.
	Alg AssertionKeyAlg
	// Key value. Can be raw key material or a crypto.Signer for hardware-backed keys (HSM/KMS).
	Key interface{}
}

AssertionKey represents a key for assertions.

func (AssertionKey) Algorithm added in v0.3.5

func (k AssertionKey) Algorithm() AssertionKeyAlg

Algorithm returns the algorithm of the key.

func (AssertionKey) IsEmpty added in v0.3.5

func (k AssertionKey) IsEmpty() bool

IsEmpty returns true if the key and the algorithm are empty.

type AssertionKeyAlg added in v0.3.5

type AssertionKeyAlg string

AssertionKeyAlg represents the algorithm of an assertion key.

const (
	AssertionKeyAlgRS256 AssertionKeyAlg = "RS256"
	AssertionKeyAlgHS256 AssertionKeyAlg = "HS256"
)

func (AssertionKeyAlg) String added in v0.3.5

func (a AssertionKeyAlg) String() string

String returns the string representation of the algorithm.

type AssertionType added in v0.3.5

type AssertionType string

AssertionType represents the type of the assertion.

const (
	HandlingAssertion AssertionType = "handling"
	BaseAssertion     AssertionType = "other"
)

func (AssertionType) String added in v0.3.5

func (at AssertionType) String() string

String returns the string representation of the assertion type.

type AssertionVerificationKeys added in v0.3.5

type AssertionVerificationKeys struct {
	// Default key to use if the key for the assertion ID is not found.
	DefaultKey AssertionKey
	// Map of assertion ID to key.
	Keys map[string]AssertionKey
}

AssertionVerificationKeys represents the verification keys for assertions.

func (AssertionVerificationKeys) Get added in v0.3.5

func (k AssertionVerificationKeys) Get(assertionID string) (AssertionKey, error)

Get returns the key for the given assertion ID or the default key if the key is not found. If the default key is not set, it returns an empty key.

func (AssertionVerificationKeys) IsEmpty added in v0.3.5

func (k AssertionVerificationKeys) IsEmpty() bool

IsEmpty returns true if the default key and the keys map are empty.

type AttributeNameFQN added in v0.3.9

type AttributeNameFQN struct {
	// contains filtered or unexported fields
}

AttributeNameFQN represents the FQN for an attribute.

func NewAttributeNameFQN added in v0.3.9

func NewAttributeNameFQN(u string) (AttributeNameFQN, error)

func (AttributeNameFQN) Authority added in v0.3.9

func (a AttributeNameFQN) Authority() string

func (AttributeNameFQN) Name added in v0.3.9

func (a AttributeNameFQN) Name() string

func (AttributeNameFQN) Prefix added in v0.3.9

func (a AttributeNameFQN) Prefix() string

func (AttributeNameFQN) Select added in v0.3.9

func (AttributeNameFQN) String added in v0.3.9

func (a AttributeNameFQN) String() string

type AttributeValueFQN added in v0.3.9

type AttributeValueFQN struct {
	// contains filtered or unexported fields
}

AttributeValueFQN is a utility type to represent an FQN for an attribute value.

func NewAttributeValueFQN added in v0.3.9

func NewAttributeValueFQN(u string) (AttributeValueFQN, error)

func (AttributeValueFQN) Authority added in v0.3.9

func (a AttributeValueFQN) Authority() string

func (AttributeValueFQN) Name added in v0.3.9

func (a AttributeValueFQN) Name() string

func (AttributeValueFQN) Prefix added in v0.3.9

func (AttributeValueFQN) String added in v0.3.9

func (a AttributeValueFQN) String() string

func (AttributeValueFQN) Value added in v0.3.9

func (a AttributeValueFQN) Value() string

type AuthClient added in v0.28.0

type AuthClient struct {
	// contains filtered or unexported fields
}

AuthClient groups authentication operations for the SDK.

func (*AuthClient) AccessToken added in v0.28.0

func (a *AuthClient) AccessToken(ctx context.Context) (auth.AccessToken, error)

AccessToken returns a valid access token for the SDK's configured credentials. It returns ErrNoAccessTokenSource if the SDK was created without credentials, and ErrAccessTokenInvalid if the token source returns an empty token.

type Binding added in v0.3.5

type Binding struct {
	// Method used to bind the assertion. (e.g. jws)
	Method string `json:"method,omitempty"`
	// Signature of the assertion.
	Signature string `json:"signature,omitempty"`
}

Binding enforces cryptographic integrity of the assertion. So the can't be modified or copied to another tdf.

type BindingMethod added in v0.3.5

type BindingMethod string

BindingMethod represents the method used to bind the assertion.

const (
	JWS BindingMethod = "jws"
)

func (BindingMethod) String added in v0.3.5

func (bm BindingMethod) String() string

String returns the string representation of the binding method.

type BulkDecryptOption added in v0.3.26

type BulkDecryptOption func(request *BulkDecryptRequest) error

func WithBulkIgnoreAllowlist added in v0.4.4

func WithBulkIgnoreAllowlist(ignore bool) BulkDecryptOption

func WithBulkKasAllowlist added in v0.4.4

func WithBulkKasAllowlist(kasList []string) BulkDecryptOption

func WithTDF3DecryptOptions added in v0.4.4

func WithTDF3DecryptOptions(options ...TDFReaderOption) BulkDecryptOption

func WithTDFType added in v0.3.26

func WithTDFType(tdfType TdfType) BulkDecryptOption

WithTDFType Type of TDFs to be decrypted

func WithTDFs added in v0.3.26

func WithTDFs(tdfs ...*BulkTDF) BulkDecryptOption

WithTDFs Adds Lists of TDFs to be decrypted

type BulkDecryptPrepared added in v0.10.0

type BulkDecryptPrepared struct {
	PolicyTDF map[string]*BulkTDF
	// contains filtered or unexported fields
}

BulkDecryptPrepared holds the prepared state for bulk decryption The PolicyTDF is a map of created policy IDs to their corresponding BulkTDF The policy IDs are generated during the prepareDecryptors function

func (*BulkDecryptPrepared) BulkDecrypt added in v0.10.0

func (bp *BulkDecryptPrepared) BulkDecrypt(ctx context.Context) error

Allow the bulk decryption to occur

type BulkDecryptRequest added in v0.3.26

type BulkDecryptRequest struct {
	TDFs               []*BulkTDF
	TDF3DecryptOptions []TDFReaderOption // Options for TDF3 Decryptor
	TDFType            TdfType
	// contains filtered or unexported fields
}

type BulkErrors added in v0.3.26

type BulkErrors []error

BulkErrors List of Errors that Failed during Bulk Decryption

func (BulkErrors) Error added in v0.3.26

func (b BulkErrors) Error() string

func (BulkErrors) Unwrap added in v0.3.26

func (b BulkErrors) Unwrap() []error

type BulkTDF added in v0.3.26

type BulkTDF struct {
	Reader               io.ReadSeeker
	Writer               io.Writer
	Error                error
	TriggeredObligations RequiredObligations
}

BulkTDF: Reader is TDF Content. Writer writes encrypted data. Error is the error that occurs if decrypting fails.

type CertExchangeTokenSource added in v0.2.1

type CertExchangeTokenSource struct {
	auth.AccessTokenSource

	IdpEndpoint string
	// contains filtered or unexported fields
}

func (*CertExchangeTokenSource) AccessToken added in v0.2.1

func (*CertExchangeTokenSource) AccessTokenCredential added in v0.28.0

func (c *CertExchangeTokenSource) AccessTokenCredential(ctx context.Context, _ *http.Client) (auth.AccessTokenCredential, error)

AccessTokenCredential returns the cached certificate-exchange token and its DPoP status atomically.

func (*CertExchangeTokenSource) MakeToken added in v0.2.1

func (c *CertExchangeTokenSource) MakeToken(tokenMaker func(jwk.Key) ([]byte, error)) ([]byte, error)

type ChunkedFinalizeOption added in v0.33.0

type ChunkedFinalizeOption func(*chunkedFinalizeConfig) error

ChunkedFinalizeOption configures a single Finalize call.

Experimental: not part of the stable SDK API; may change or be removed.

func WithChunkedAssertions added in v0.33.0

func WithChunkedAssertions(assertions []AssertionConfig) ChunkedFinalizeOption

WithChunkedAssertions attaches signed assertions to the produced TDF. Each assertion is bound to the payload's aggregate hash, so they are signed at Finalize once every segment is in. Assertions without their own SigningKey are signed with HS256 over the DEK.

Experimental: not part of the stable SDK API; may change or be removed.

func WithChunkedAttributes added in v0.33.0

func WithChunkedAttributes(values []*policy.Value) ChunkedFinalizeOption

WithChunkedAttributes overrides the writer's initial attributes for this Finalize call.

An empty or nil slice does not clear the writer's initial attributes -- it reads as "not specified" and the initial ones still apply. There is deliberately no way to finalize with no attributes once the writer was constructed with some: dropping attributes silently would loosen the policy on the data, which is the one mistake here that cannot be detected after the fact. Construct a writer without WithChunkedInitialAttributes instead.

Experimental: not part of the stable SDK API; may change or be removed.

func WithChunkedDefaultKASForFinalize added in v0.33.0

func WithChunkedDefaultKASForFinalize(kas *policy.SimpleKasKey) ChunkedFinalizeOption

WithChunkedDefaultKASForFinalize overrides the writer's initial default KAS for this Finalize call.

A nil argument reads as "not specified", so the writer's initial default KAS still applies; there is no way to unset it for one call.

Experimental: not part of the stable SDK API; may change or be removed.

func WithChunkedEncryptedMetadata added in v0.33.0

func WithChunkedEncryptedMetadata(metadata string) ChunkedFinalizeOption

WithChunkedEncryptedMetadata attaches AES-GCM-encrypted metadata to every KAO in the TDF. The metadata is keyed on the split share and only decryptable by a reader that has been granted access.

Experimental: not part of the stable SDK API; may change or be removed.

func WithChunkedMimeType added in v0.33.0

func WithChunkedMimeType(mimeType string) ChunkedFinalizeOption

WithChunkedMimeType records the payload MIME type in the manifest.

Experimental: not part of the stable SDK API; may change or be removed.

func WithChunkedSegments added in v0.33.0

func WithChunkedSegments(indices []int) ChunkedFinalizeOption

WithChunkedSegments sets the segments the finalized manifest describes. Passing no indices emits every written segment in ascending index order, which is what most callers want.

The indices need not be contiguous. A caller that reserves a fixed block of indices per upload part -- part N owning [N*stride, (N+1)*stride) -- and fills only part of each block writes a sparse index set by construction; listing it here is fine.

What the indices must be is a prefix of the written segments in ascending index order: they may drop from the end, but may not reorder or skip. The archive stores segments sorted by index, so a manifest that reorders them would not describe the bytes on disk, and one that skips a segment with bytes after it would misread every segment that follows. For the same reason the caller must concatenate each segment's TDFData in ascending index order.

Dropping a segment from the manifest does not shrink the archive: the underlying writer never rolls back a completed segment's contribution to the payload's recorded size and CRC, so every segment that was actually written -- including ones this option excludes from the manifest -- must still be appended by the caller when assembling the final file. Skipping a dropped segment's bytes produces an archive whose central directory offsets overshoot.

Experimental: not part of the stable SDK API; may change or be removed.

type ChunkedFinalizeResult added in v0.33.0

type ChunkedFinalizeResult struct {
	// Data is the ZIP closing bytes, in order: the payload's data
	// descriptor, the embedded manifest entry (its own local file
	// header + JSON data), and the central directory + EOCD record.
	// Append after every segment's TDFData to form the complete TDF
	// file -- including any segment WithChunkedSegments excluded from
	// the manifest; the archive's recorded size and CRC already
	// account for it regardless.
	Data []byte

	// EncryptedSize is the total ciphertext byte length across the
	// segments the manifest describes -- post-trim if
	// WithChunkedSegments was used.
	//
	// This is a property of the manifest, not of the file. It is not
	// the number of bytes to append: it counts nonce+ciphertext only,
	// where segment 0's TDFData additionally carries the payload's ZIP
	// local file header, and it omits any segment WithChunkedSegments
	// dropped, whose bytes the caller must still append. Size an upload
	// by measuring the TDFData readers as they are consumed -- the only
	// quantity that counts every byte exactly once. Sizing it from this
	// field truncates the payload, and the corruption surfaces only at
	// decrypt.
	EncryptedSize int64

	// Manifest is the finalized manifest that was serialized into the
	// archive.
	Manifest *Manifest

	// TotalSegments is the number of segments in the finalized
	// manifest (post-trim if WithChunkedSegments was used).
	TotalSegments int

	// TotalSize is the total plaintext byte length across the segments
	// the manifest describes, post-trim on the same basis as
	// EncryptedSize.
	TotalSize int64
}

ChunkedFinalizeResult carries the finalized TDF's closing bytes and metadata about what was written.

Experimental: not part of the stable SDK API; may change or be removed.

type ChunkedSegmentResult added in v0.33.0

type ChunkedSegmentResult struct {
	// EncryptedSize is the ciphertext byte length including nonce and
	// GCM tag. It is the size the manifest records for this segment,
	// which for segment 0 is *not* the number of bytes TDFData yields:
	// that reader is prefixed with the payload's ZIP local file header,
	// which the manifest does not count. Size an upload from TDFData
	// itself (or from len(header)+EncryptedSize), never from
	// EncryptedSize alone.
	EncryptedSize int64

	// Hash is the base64-encoded segment integrity hash.
	Hash string

	// Index is the zero-based segment index.
	Index int

	// PlaintextSize is the byte length of the pre-encryption input.
	PlaintextSize int64

	// TDFData is a reader over the segment's ZIP-embedded ciphertext:
	// for segment 0 this is the payload's local file header + nonce +
	// AES-GCM output; every other segment omits the local header and
	// is nonce + AES-GCM output only. Callers assemble the TDF by
	// concatenating each segment's TDFData in emission order followed
	// by ChunkedFinalizeResult.Data.
	//
	// It may be read only once -- it is a stream over the buffers this
	// call produced, not a rewindable view of them. A second read
	// yields zero bytes and no error, so an upload that retries by
	// re-reading it silently writes nothing. Buffer the bytes yourself
	// if you need them twice.
	TDFData io.Reader
}

ChunkedSegmentResult carries the ZIP bytes for one segment plus its integrity metadata.

Experimental: not part of the stable SDK API; may change or be removed.

type ChunkedWriter added in v0.33.0

type ChunkedWriter interface {
	// Finalize completes TDF creation. Every option applies only to
	// this Finalize call; writer-level defaults set at NewChunked*
	// remain otherwise. Returns the closing bytes (the payload's data
	// descriptor, the embedded manifest entry, and the central
	// directory + end-of-central-directory record) that must be
	// appended after every segment's TDFData. Returns
	// ErrChunkedMissingSegmentZero if segment 0 was never written,
	// ErrChunkedAlreadyFinalized on a second call, and
	// ErrChunkedWriteInFlight if a WriteSegment has not yet returned.
	//
	// Only a mutation of the archive fences the writer. A refusal made
	// before the archive is touched -- an in-flight write, a cancelled
	// ctx, a rejected option, a splitter fault -- leaves the writer
	// usable: fix the cause and call Finalize again. A failure from the
	// archive itself after it has begun mutating, or a Close failure
	// after Finalize succeeded, leaves the writer unusable
	// (ErrChunkedFinalizeFailed / ErrChunkedCloseFailed), and every
	// subsequent call on it returns that same error rather than
	// retrying.
	//
	// A permitted retry is safe, not idempotent: each call mints a
	// fresh policy UUID and re-splits the DEK, so the manifest it
	// produces differs from the one the failed call would have.
	//
	// Finalize must happen-after every WriteSegment call returns.
	// Sequencing that is the caller's job -- wait on the errgroup,
	// close the channel, join the pool. Finalize does not block waiting
	// for in-flight writes (it cannot know how many are still coming);
	// it refuses with ErrChunkedWriteInFlight instead, so a missed join
	// is a deterministic error rather than a silently short TDF.
	Finalize(ctx context.Context, opts ...ChunkedFinalizeOption) (*ChunkedFinalizeResult, error)

	// GetManifest returns the manifest for the TDF. After Finalize it
	// is exactly the manifest that was written.
	//
	// Before Finalize it is a preview of the manifest's *shape* --
	// segment count, sizes, hashes, which KASes appear -- and nothing
	// more. It is not byte-stable and is not what Finalize will
	// produce: each call re-runs the whole manifest build, minting a
	// fresh policy UUID, re-splitting the DEK (so ephemeral wrapping
	// keys, and therefore every key access object, differ), and
	// re-signing any assertions. Two back-to-back calls with identical
	// options disagree, and so will Finalize. Use it to inspect
	// progress, never to predict or cache the final manifest.
	//
	// It reflects only segments the archive has already accepted;
	// writes still in flight are skipped rather than waited on or
	// reported. Unlike Finalize it produces nothing durable, so a
	// snapshot one segment short is a correct snapshot of that instant
	// -- which is why, unlike Finalize, it does not refuse them.
	//
	// It is safe to call concurrently with WriteSegment. The writer lock
	// is held only long enough to copy segment metadata out; the key
	// split, which may make network calls to resolve KAS keys, runs
	// unlocked. That is why the result describes the writer as of the
	// snapshot rather than as of the return: a segment that lands while
	// the split is in flight is absent here and present in the next
	// call. Finalize, being terminal, keeps the lock throughout instead.
	GetManifest(ctx context.Context, opts ...ChunkedFinalizeOption) (*Manifest, error)

	// WriteSegment encrypts data as segment index and returns the ZIP
	// bytes for that segment: segment 0 is preceded by the payload's
	// ZIP local file header, every other segment is nonce + ciphertext
	// only. Callers upload or buffer those bytes; Finalize does not
	// re-emit them. Indices need not arrive in order and need not be
	// contiguous, but index 0 is mandatory: it carries that local file
	// header, so Finalize refuses a write set without it.
	//
	// data is neither retained nor modified; the caller may reuse the
	// buffer as soon as the call returns.
	WriteSegment(ctx context.Context, index int, data []byte) (*ChunkedSegmentResult, error)
}

ChunkedWriter creates a TDF from segments that may arrive in any order. Callers write each segment independently — typically off-thread or in parallel — then call Finalize to close the archive. Contrast with SDK.CreateTDF, which requires the full plaintext up front.

Experimental: not part of the stable SDK API; may change or be removed.

func NewChunkedWriter added in v0.33.0

func NewChunkedWriter(_ context.Context, opts ...ChunkedWriterOption) (ChunkedWriter, error)

NewChunkedWriter constructs a per-segment TDF writer. WriteSegment may be called from several goroutines at once so long as each targets a distinct segment index; two concurrent calls for the same index are not allowed, and one of them will fail with ErrChunkedSegmentAlreadyWritten rather than corrupt the archive.

Finalize must happen-after every WriteSegment returns. The writer cannot sequence that for you, but it will not paper over a missed join either: Finalize refuses with ErrChunkedWriteInFlight while any index is reserved but not yet accepted by the archive, rather than emitting a TDF that is short by however many writes lost the race. It does not block — it has no way to know how many more writes are coming — so join your goroutines and call it again.

No SDK value is needed. The key splitter (WithChunkedKeySplitter) and the attribute and KAS defaults (WithChunkedInitialAttributes, WithChunkedDefaultKAS) are supplied through options; the clock, cipher, archive-writer and entropy seams are unexported test seams and are not reachable from outside this package.

Experimental: not part of the stable SDK API; may change or be removed.

type ChunkedWriterOption added in v0.33.0

type ChunkedWriterOption func(*chunkedWriterConfig) error

ChunkedWriterOption configures a ChunkedWriter at construction time.

Experimental: not part of the stable SDK API; may change or be removed.

func WithChunkedDefaultKAS added in v0.33.0

func WithChunkedDefaultKAS(kas *policy.SimpleKasKey) ChunkedWriterOption

WithChunkedDefaultKAS sets the default KAS used by Finalize when the Finalize call does not supply its own.

Experimental: not part of the stable SDK API; may change or be removed.

func WithChunkedInitialAttributes added in v0.33.0

func WithChunkedInitialAttributes(values []*policy.Value) ChunkedWriterOption

WithChunkedInitialAttributes sets attribute values used by Finalize when the Finalize call does not supply its own.

Experimental: not part of the stable SDK API; may change or be removed.

func WithChunkedKeySplitter added in v0.33.0

func WithChunkedKeySplitter(splitter KeySplitter) ChunkedWriterOption

WithChunkedKeySplitter overrides the key splitter used by the ChunkedWriter. Callers with multi-KAS attribute grants should inject a splitter that understands their grant model. The splitter must not be nil.

Experimental: not part of the stable SDK API; may change or be removed.

func WithChunkedTargetMode added in v0.33.0

func WithChunkedTargetMode(mode string) ChunkedWriterOption

WithChunkedTargetMode targets a specific TDF spec version, given as a semver string such as "4.2.2". An empty mode selects the most recently available target version (4.3.0).

Experimental: not part of the stable SDK API; may change or be removed.

type ConnectRPCConnection added in v0.4.5

type ConnectRPCConnection struct {
	Client   *http.Client
	Endpoint string
	Options  []connect.ClientOption
}

type EncryptedMetadata

type EncryptedMetadata struct {
	Cipher string `json:"ciphertext"`
	Iv     string `json:"iv"`
}

type EncryptionInformation

type EncryptionInformation struct {
	KeyAccessType        string      `json:"type"`
	Policy               string      `json:"policy"`
	KeyAccessObjs        []KeyAccess `json:"keyAccess"`
	Method               Method      `json:"method"`
	IntegrityInformation `json:"integrityInformation"`
}

type ErrAssertionFailure added in v0.3.16

type ErrAssertionFailure struct {
	ID string
}

Custom error struct for Assertion errors

func (ErrAssertionFailure) Error added in v0.3.16

func (e ErrAssertionFailure) Error() string

func (ErrAssertionFailure) Unwrap added in v0.3.16

func (e ErrAssertionFailure) Unwrap() error

type Error

type Error string

func (Error) Error

func (c Error) Error() string

type IDPAccessTokenSource

type IDPAccessTokenSource struct {
	// contains filtered or unexported fields
}

IDPAccessTokenSource credentials that allow us to connect to an IDP and obtain an access token that is bound to a DPoP key

func NewIDPAccessTokenSource

func NewIDPAccessTokenSource(
	credentials oauth.ClientCredentials,
	idpTokenEndpoint string,
	scopes []string,
	key *ocrypto.RsaKeyPair,
) (*IDPAccessTokenSource, error)

func (*IDPAccessTokenSource) AccessToken

func (t *IDPAccessTokenSource) AccessToken(ctx context.Context, client *http.Client) (auth.AccessToken, error)

AccessToken use a pointer receiver so that the token state is shared

func (*IDPAccessTokenSource) AccessTokenCredential added in v0.28.0

func (t *IDPAccessTokenSource) AccessTokenCredential(_ context.Context, client *http.Client) (auth.AccessTokenCredential, error)

AccessTokenCredential returns the cached access token and its DPoP status atomically.

func (*IDPAccessTokenSource) MakeToken

func (t *IDPAccessTokenSource) MakeToken(tokenMaker func(jwk.Key) ([]byte, error)) ([]byte, error)

type IDPTokenExchangeTokenSource

type IDPTokenExchangeTokenSource struct {
	IDPAccessTokenSource
	oauth.TokenExchangeInfo
	// contains filtered or unexported fields
}

func NewIDPTokenExchangeTokenSource

func NewIDPTokenExchangeTokenSource(logger *slog.Logger, exchangeInfo oauth.TokenExchangeInfo, credentials oauth.ClientCredentials, idpTokenEndpoint string, scopes []string, key *ocrypto.RsaKeyPair) (*IDPTokenExchangeTokenSource, error)

func (*IDPTokenExchangeTokenSource) AccessToken

func (i *IDPTokenExchangeTokenSource) AccessToken(ctx context.Context, client *http.Client) (auth.AccessToken, error)

func (*IDPTokenExchangeTokenSource) AccessTokenCredential added in v0.28.0

func (i *IDPTokenExchangeTokenSource) AccessTokenCredential(ctx context.Context, client *http.Client) (auth.AccessTokenCredential, error)

AccessTokenCredential returns the cached exchanged token and its DPoP status atomically.

func (*IDPTokenExchangeTokenSource) MakeToken

func (i *IDPTokenExchangeTokenSource) MakeToken(keyMaker func(jwk.Key) ([]byte, error)) ([]byte, error)

type IntegrityAlgorithm deprecated

type IntegrityAlgorithm = int

IntegrityAlgorithm named an integrity algorithm without saying what it was allowed to protect.

Deprecated: the root signature and the segment hashes accept different sets of algorithms, which one type cannot express. Use RootIntegrityAlg or SegmentIntegrityAlg.

type IntegrityInformation

type IntegrityInformation struct {
	RootSignature           `json:"rootSignature"`
	SegmentHashAlgorithm    string    `json:"segmentHashAlg"`
	DefaultSegmentSize      int64     `json:"segmentSizeDefault"`
	DefaultEncryptedSegSize int64     `json:"encryptedSegmentSizeDefault"`
	Segments                []Segment `json:"segments"`
}

type KASClient

type KASClient struct {
	// contains filtered or unexported fields
}

type KASInfo

type KASInfo struct {
	// URL of the KAS server
	URL string
	// Public key can be empty.
	// If it is empty, the public key will be fetched from the KAS server.
	PublicKey string
	// Key identifier associated with the given key, if present.
	KID string
	// The algorithm associated with this key
	Algorithm string
	// If this KAS should be used as the default for 'encrypt' calls
	Default bool
}

KASInfo contains Key Access Server information.

type KASKeyFetcher added in v0.6.0

type KASKeyFetcher interface {
	// contains filtered or unexported methods
}

type KASPublicKey added in v0.33.0

type KASPublicKey struct {
	// Algorithm identifies the wrapping scheme. It must be one of the
	// values ocrypto.ParseKeyType accepts, e.g. ocrypto.RSA2048Key or
	// ocrypto.EC256Key -- use PolicyAlgorithmToKeyType to derive it
	// from a policy.Algorithm. An unrecognized value falls through
	// createKeyAccess's RSA default, which sniffs the PEM rather than
	// honoring the declared scheme, and produces a KAO that cannot be
	// decrypted; SplitResult.Validate rejects it first.
	Algorithm ocrypto.KeyType

	// KID identifies which key at that KAS to use.
	KID string

	// PEM is the wrapping key in PEM form.
	PEM string

	// URL of the KAS.
	URL string
}

KASPublicKey is the wrapping key resolved for one KAS URL.

Experimental: not part of the stable SDK API; may change or be removed.

type KeyAccess

type KeyAccess struct {
	KeyType            string      `json:"type"`
	KasURL             string      `json:"url"`
	Protocol           string      `json:"protocol"`
	WrappedKey         string      `json:"wrappedKey"`
	PolicyBinding      interface{} `json:"policyBinding"`
	EncryptedMetadata  string      `json:"encryptedMetadata,omitempty"`
	KID                string      `json:"kid,omitempty"`
	SplitID            string      `json:"sid,omitempty"`
	SchemaVersion      string      `json:"schemaVersion,omitempty"`
	EphemeralPublicKey string      `json:"ephemeralPublicKey,omitempty"`
}

type KeySplitter added in v0.33.0

type KeySplitter interface {
	// Split evaluates the ABAC policy expressed by attrs, produces N
	// splits of dek per the resulting boolean expression, and returns
	// each split alongside the KAS public keys it must be wrapped to.
	//
	// Split must not retain or modify attrs or dek, nor the elements of
	// attrs. The writer passes copies precisely so a splitter that scribbles
	// on them cannot desynchronize the DEK from signatures already computed
	// against it, but it reuses neither across calls, so a splitter that
	// retains either is reading state its caller has moved on from.
	Split(ctx context.Context, attrs []*policy.Value, dek []byte, defaultKAS *policy.SimpleKasKey) (*SplitResult, error)
}

KeySplitter converts attribute values plus a DEK into one or more key splits, each addressed to one or more KAS servers. Injected on the chunked Writer so tests can substitute an identity splitter without touching real attribute grants.

Implementations must be safe for concurrent use. The chunked writer calls Split with its lock released, so a caller that runs GetManifest alongside another GetManifest or a Finalize has two Splits in flight on the same splitter at once -- and both are documented as safe to do. A splitter holding per-call state in a field rather than on the stack corrupts one of the two manifests, and the damage is silent: the manifest is well-formed, carries splits that do not reconstruct the DEK, and fails only at decrypt.

Experimental: not part of the stable SDK API; may change or be removed.

func DefaultKeySplitter added in v0.33.0

func DefaultKeySplitter() KeySplitter

DefaultKeySplitter returns a single-KAS single-split splitter. Attributes are ignored; the entire DEK is bound to the caller's default KAS. Callers with attribute-based key splits requirements should inject their own splitter via WithChunkedKeySplitter.

Experimental: not part of the stable SDK API; may change or be removed.

type Manifest

type Manifest struct {
	EncryptionInformation `json:"encryptionInformation"`
	Payload               `json:"payload"`
	Assertions            []Assertion `json:"assertions,omitempty"`
	TDFVersion            string      `json:"schemaVersion,omitempty"`
}

func (*Manifest) UnmarshalJSON added in v0.35.0

func (m *Manifest) UnmarshalJSON(data []byte) error

UnmarshalJSON decodes a TDF manifest, reading a deprecated tdf_spec_version as the spec version when the canonical schemaVersion is absent, so that files written against the deprecated name stay readable.

Precedence is schemaVersion, then tdf_spec_version at the root, then tdf_spec_version under payload. Nothing is written back under the deprecated name -- re-marshalling a manifest always emits schemaVersion only, so a round trip normalizes the name rather than propagating it.

The reader uses the decoded version to choose the integrity digest encoding: hex when no version is recorded (pre-4.3.0), raw bytes otherwise. So a container whose version is recorded only under the deprecated name is read with the encoding its writer used.

type Method

type Method struct {
	Algorithm    string `json:"algorithm"`
	IV           string `json:"iv"`
	IsStreamable bool   `json:"isStreamable"`
}

type OAuthAccessTokenSource added in v0.3.9

type OAuthAccessTokenSource struct {
	// contains filtered or unexported fields
}

OAuthAccessTokenSource allows connecting to an IDP and obtaining an access token.

func NewOAuthAccessTokenSource added in v0.3.9

func NewOAuthAccessTokenSource(
	source oauth2.TokenSource, scopes []string, key *ocrypto.RsaKeyPair,
) (*OAuthAccessTokenSource, error)

func (*OAuthAccessTokenSource) AccessToken added in v0.3.9

func (t *OAuthAccessTokenSource) AccessToken(ctx context.Context, client *http.Client) (auth.AccessToken, error)

AccessToken use a pointer receiver so that the token state is shared

func (*OAuthAccessTokenSource) AccessTokenCredential added in v0.28.0

func (t *OAuthAccessTokenSource) AccessTokenCredential(_ context.Context, _ *http.Client) (auth.AccessTokenCredential, error)

AccessTokenCredential returns an access token and its DPoP status from the same token response.

func (*OAuthAccessTokenSource) MakeToken added in v0.3.9

func (t *OAuthAccessTokenSource) MakeToken(tokenMaker func(jwk.Key) ([]byte, error)) ([]byte, error)

type Option

type Option func(*config)

func WithClientCredentials

func WithClientCredentials(clientID, clientSecret string, scopes []string) Option

WithClientCredentials returns an Option that sets up authentication with client credentials.

func WithConnectionValidation added in v0.3.27

func WithConnectionValidation() Option

WithConnectionValidation will validate connection to a healthy, running platform at SDK construction time. For runtime readiness probes (e.g. Kubernetes liveness/readiness endpoints), use SDK.IsHealthy(ctx) instead — it honors ctx for deadlines and tracing and does not fail-fast at construction.

func WithCustomAuthorizationConnection deprecated

func WithCustomAuthorizationConnection(conn *ConnectRPCConnection) Option

Deprecated: Use WithCustomCoreConnection instead

func WithCustomCoreConnection added in v0.3.7

func WithCustomCoreConnection(conn *ConnectRPCConnection) Option

WithCoreConnection returns an Option that sets up a connection to the core platform

func WithCustomEntityResolutionConnection added in v0.2.3

func WithCustomEntityResolutionConnection(conn *ConnectRPCConnection) Option

func WithCustomPolicyConnection deprecated

func WithCustomPolicyConnection(conn *ConnectRPCConnection) Option

Deprecated: Use WithCustomCoreConnection instead

func WithCustomWellknownConnection added in v0.2.5

func WithCustomWellknownConnection(conn *ConnectRPCConnection) Option

func WithDPoPAlgorithm added in v0.30.0

func WithDPoPAlgorithm(alg SigningAlgorithm) Option

WithDPoPAlgorithm enables DPoP with an ephemeral key generated for the given algorithm. Supported: ES256, ES384, ES512, RS256, RS384, RS512. When no DPoP key is otherwise configured, the SDK auto-generates an ephemeral ES256 (P-256) key by default; ES256 is the recommended choice.

func WithDPoPJWK added in v0.30.0

func WithDPoPJWK(key jwk.Key) Option

WithDPoPJWK enables DPoP using a pre-built JWK private key. The JWK must have its Algorithm field set. This is the lowest-level DPoP key injection; prefer WithDPoPAlgorithm or WithDPoPKeyPEM for most use cases.

func WithDPoPKeyPEM added in v0.30.0

func WithDPoPKeyPEM(pemBytes []byte) Option

WithDPoPKeyPEM enables DPoP using a PEM-encoded private key. Algorithm is inferred from the key type unless also overridden via WithDPoPAlgorithm.

func WithExtraClientOptions added in v0.4.5

func WithExtraClientOptions(opts ...connect.ClientOption) Option

WithExtraClientOptions returns an Option that adds extra connect rpc client options to the conect rpc clients

func WithFulfillableObligationFQNs added in v0.10.0

func WithFulfillableObligationFQNs(fqns []string) Option

WithFulfillableObligationFQNs sets the list of obligation FQNs that can

func WithIPC added in v0.2.7

func WithIPC() Option

WithIPC returns an Option that indicates the SDK should use IPC for communication this will allow the platform endpoint to be an empty string

func WithInsecurePlaintextConn added in v0.2.1

func WithInsecurePlaintextConn() Option

WithInsecurePlaintextConn returns an Option that sets up HTTP connection sent in the clear.

func WithInsecureSkipVerifyConn added in v0.2.1

func WithInsecureSkipVerifyConn() Option

WithInsecureSkipVerifyConn returns an Option that sets up HTTPS connection without verification.

func WithLogger added in v0.9.0

func WithLogger(logger *slog.Logger) Option

WithLogger returns an Option that sets a custom slog.Logger for all SDK logging.

func WithNoKIDInKAO added in v0.2.8

func WithNoKIDInKAO() Option

WithNoKIDInKAO disables storing the KID in the KAO. This allows generating TDF files that are compatible with legacy file formats (no KID).

func WithOAuthAccessTokenSource added in v0.3.9

func WithOAuthAccessTokenSource(t oauth2.TokenSource) Option

WithOAuthAccessTokenSource directs the SDK to use a standard OAuth2 token source for authentication

func WithPlatformConfiguration added in v0.2.5

func WithPlatformConfiguration(platformConfiguration PlatformConfiguration) Option

WithPlatformConfiguration allows you to override the remote platform configuration Use this option with caution, as it may lead to unexpected behavior

func WithSessionEncryptionRSA added in v0.2.4

func WithSessionEncryptionRSA(key *rsa.PrivateKey) Option

The session key pair is used to encrypt responses from KAS for a given session and can be reused across an entire session. Please use with caution.

func WithSessionSignerRSA added in v0.2.4

func WithSessionSignerRSA(key *rsa.PrivateKey) Option

The DPoP key pair is used to implement sender constrained tokens from the identity provider, and should be associated with the lifetime of a session for a given identity. Please use with caution.

func WithTLSCredentials added in v0.2.1

func WithTLSCredentials(tls *tls.Config, audience []string) Option

func WithTokenEndpoint deprecated

func WithTokenEndpoint(tokenEndpoint string) Option

Deprecated: SDK will discover the token endpoint from the platform configuration

func WithTokenExchange

func WithTokenExchange(subjectToken string, audience []string) Option

WithTokenExchange specifies that the SDK should obtain its access token by exchanging the given token for a new one

func WithTokenExpirationBuffer added in v0.35.0

func WithTokenExpirationBuffer(buffer time.Duration) Option

WithTokenExpirationBuffer sets how early SDK-managed access tokens are renewed. The default is 10 seconds. Zero disables early renewal; negative values are rejected by New. It applies to client credentials, token exchange, and certificate exchange, not custom token sources.

type Payload

type Payload struct {
	Type        string `json:"type"`
	URL         string `json:"url"`
	Protocol    string `json:"protocol"`
	MimeType    string `json:"mimeType"`
	IsEncrypted bool   `json:"isEncrypted"`
}

type PlatformConfiguration added in v0.2.5

type PlatformConfiguration map[string]interface{}

func (PlatformConfiguration) AuthzEndpoint added in v0.3.8

func (c PlatformConfiguration) AuthzEndpoint() (string, error)

func (PlatformConfiguration) Issuer added in v0.3.8

func (c PlatformConfiguration) Issuer() (string, error)

func (PlatformConfiguration) TokenEndpoint added in v0.3.8

func (c PlatformConfiguration) TokenEndpoint() (string, error)

type PolicyBinding added in v0.3.3

type PolicyBinding struct {
	Alg  string `json:"alg"`
	Hash string `json:"hash"`
}

type PolicyObject

type PolicyObject struct {
	UUID string `json:"uuid"`
	Body struct {
		DataAttributes []attributeObject `json:"dataAttributes"`
		Dissem         []string          `json:"dissem"`
	} `json:"body"`
}

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

Loads and reads ZTDF files

func (*Reader) DataAttributes

func (r *Reader) DataAttributes() ([]string, error)

DataAttributes return the data attributes present in tdf.

func (*Reader) Init added in v0.2.11

func (r *Reader) Init(ctx context.Context) error

Do any network based operations required. This allows making the requests cancellable

func (*Reader) Manifest

func (r *Reader) Manifest() Manifest

func (*Reader) Obligations added in v0.10.0

func (r *Reader) Obligations(ctx context.Context) (RequiredObligations, error)

* Returns the obligations required for access to the TDF payload. * * If obligations are not populated we call Init() to populate them, * which will result in a rewrap call. *

func (*Reader) Policy

func (r *Reader) Policy() (PolicyObject, error)

Policy returns a copy of the policy object in manifest, if it is valid. Otherwise, returns an error.

func (*Reader) Read

func (r *Reader) Read(p []byte) (int, error)

Read reads up to len(p) bytes into p. It returns the number of bytes read (0 <= n <= len(p)) and any error encountered. It returns an io.EOF error when the stream ends.

func (*Reader) ReadAt

func (r *Reader) ReadAt(buf []byte, offset int64) (int, error)

ReadAt reads len(buf) bytes into buf starting at plaintext offset offset in the payload. It returns the number of bytes read (0 <= n <= len(buf)) and any error encountered.

A read that runs past the end of the payload returns the bytes that were available along with io.EOF; a zero-length read never reports io.EOF, even at the end. An offset beyond the end of the payload returns ErrTDFPayloadReadFail, and a negative one ErrTDFPayloadInvalidOffset.

The segment walk below assumes manifest.Segments covers the payload contiguously in ascending plaintext order -- it accumulates each segment's Size to derive that segment's plaintext extent, and stops at the first segment that starts at or after the end of the request. Segments listed out of order would be mapped to the wrong plaintext offsets.

func (*Reader) Seek added in v0.5.0

func (r *Reader) Seek(offset int64, whence int) (int64, error)

Seek updates cursor to `Read` or `WriteTo` at an offset.

func (*Reader) UnencryptedMetadata

func (r *Reader) UnencryptedMetadata() ([]byte, error)

UnencryptedMetadata return decrypted metadata in manifest.

func (*Reader) UnsafePayloadKeyRetrieval added in v0.3.5

func (r *Reader) UnsafePayloadKeyRetrieval() ([]byte, error)

*WARNING:* Using this function is unsafe since KAS will no longer be able to prevent access to the key.

Retrieve the payload key, either from performing an buildKey or from a previous buildKey, and write it to a user buffer.

OUTPUTS:

  • []byte - Byte array containing the DEK.
  • error - If an error occurred while processing

func (*Reader) WriteTo

func (r *Reader) WriteTo(writer io.Writer) (int64, error)

WriteTo writes data to writer until there's no more data to write or when an error occurs. This implements the io.WriterTo interface.

type RequiredObligations added in v0.10.0

type RequiredObligations struct {
	FQNs []string
}

type ResourceLocator added in v0.2.4

type ResourceLocator struct {
	// contains filtered or unexported fields
}

ResourceLocator - structure to contain a protocol + body comprising an URL

func NewResourceLocator added in v0.2.4

func NewResourceLocator(url string) (*ResourceLocator, error)

func NewResourceLocatorFromReader added in v0.2.4

func NewResourceLocatorFromReader(reader io.Reader) (*ResourceLocator, error)

func (ResourceLocator) Equals added in v0.5.0

func (rl ResourceLocator) Equals(r2 ResourceLocator) bool

func (ResourceLocator) GetIdentifier added in v0.3.12

func (rl ResourceLocator) GetIdentifier() (string, error)

GetIdentifier - identifier is returned if the correct protocol enum is set else error padding is removed unlike rl.identifier direct access

func (ResourceLocator) GetURL added in v0.3.12

func (rl ResourceLocator) GetURL() (string, error)

GetURL - Retrieve a fully qualified protocol+body URL string from a ResourceLocator struct

func (ResourceLocator) ID added in v0.5.0

func (rl ResourceLocator) ID() string

func (ResourceLocator) KASURI added in v0.5.0

func (rl ResourceLocator) KASURI() string

func (ResourceLocator) Less added in v0.5.0

func (rl ResourceLocator) Less(y *ResourceLocator) bool

func (ResourceLocator) String added in v0.5.0

func (rl ResourceLocator) String() string

type RootIntegrityAlg added in v0.32.0

type RootIntegrityAlg int

RootIntegrityAlg is the algorithm that signs a TDF's aggregate hash -- the concatenation of every segment hash, in manifest order. The root signature is the only thing that authenticates the manifest's description of the payload, so a segment list that has been truncated, reordered, or duplicated is caught here or not at all.

HS256 is the only value, and this type exists to say so at compile time. The aggregate hash is manifest data that never passed through the AEAD, so tag extraction has nothing to extract: a "GMAC" root signature is just a copy of the last segment hash, producible by an attacker with no key.

const RootHS256 RootIntegrityAlg = iota

RootHS256 is an HMAC-SHA256 over the aggregate hash, keyed by the payload key. It is the default, the only supported value, and what every TDF in the wild already declares.

func (RootIntegrityAlg) String added in v0.32.0

func (a RootIntegrityAlg) String() string

String returns the manifest spelling of the algorithm. Out-of-range values have no spelling: the type is int-backed, so they are representable, and naming one "HS256" in a manifest would claim a signature that was never computed.

type RootSignature

type RootSignature struct {
	Algorithm string `json:"alg"`
	Signature string `json:"sig"`
}

type SDK

func New

func New(platformEndpoint string, opts ...Option) (*SDK, error)

func (SDK) AttributeExists added in v0.14.0

func (s SDK) AttributeExists(ctx context.Context, attributeFqn string) (bool, error)

AttributeExists reports whether the attribute definition identified by attributeFqn exists on the platform.

attributeFqn should be an attribute-level FQN (no /value/ segment):

https://<namespace>/attr/<attribute_name>

Returns (true, nil) if the attribute exists, (false, nil) if it does not, and (false, err) if a service error occurs.

func (SDK) AttributeValueExists added in v0.14.0

func (s SDK) AttributeValueExists(ctx context.Context, fqn string) (bool, error)

AttributeValueExists reports whether the attribute value FQN exists on the platform.

fqn should be a full attribute value FQN (with /value/ segment):

https://<namespace>/attr/<attribute_name>/value/<value>

Returns (true, nil) if the value exists, (false, nil) if it does not, and (false, err) if a service error occurs.

func (*SDK) Auth added in v0.28.0

func (s *SDK) Auth() *AuthClient

Auth returns an AuthClient for authentication-related operations.

func (SDK) BulkDecrypt added in v0.3.26

func (s SDK) BulkDecrypt(ctx context.Context, opts ...BulkDecryptOption) error

BulkDecrypt Decrypts a list of BulkTDF and if a partial failure of TDFs unable to be decrypted, BulkErrors would be returned.

func (SDK) Close

func (s SDK) Close() error

func (SDK) Conn

func (s SDK) Conn() *ConnectRPCConnection

Conn returns the underlying http connection

func (SDK) CreateTDF

func (s SDK) CreateTDF(writer io.Writer, reader io.Reader, opts ...TDFOption) (*TDFObject, error)

CreateTDF encrypts the payload read from reader and writes a TDF to writer. See SDK.CreateTDFContext for how the payload length is resolved.

Bytes are consumed from the reader's current position until the resolved length is reached, or through EOF when the length cannot be resolved at all. A seekable reader is not rewound first: a caller that has already advanced it — sniffing a header for content-type detection, say — encrypts only what remains. Earlier releases took an io.ReadSeeker and always rewound to byte 0.

func (SDK) CreateTDFContext added in v0.3.0

func (s SDK) CreateTDFContext(ctx context.Context, writer io.Writer, reader io.Reader, opts ...TDFOption) (*TDFObject, error)

CreateTDFContext reads plain text from the given reader and saves it to the writer, subject to the given options. Bytes are consumed from the reader's current position.

A seekable reader is not rewound to byte 0 first — see SDK.CreateTDF, which spells out how that differs from the io.ReadSeeker signature this replaced.

Knowing the length up front lets the archive stay in the compact ZIP32 layout when it fits. The length comes from WithInputSize if given, otherwise from the reader when it is seekable; a payload that can be measured neither way is written as ZIP64.

A resolved length is exact, and it bounds the read no matter which of those two ways produced it. Reading stops after that many bytes rather than at EOF, and a reader that ends early fails the call. So a file that grows between the seek that measured it and the read that follows contributes only its measured length — the later bytes are left unread rather than silently appended — and one that is truncated in that window fails instead of yielding a short TDF. Only a payload whose length resolves neither way is read through to EOF.

Memory grows with the segment count rather than the payload: one manifest segment and one archive-writer entry apiece, all of them live until the archive is finalized. At the 2 MiB default that is roughly 500k entries per terabyte, which is the practical ceiling on a large stream now that the old 64 GB cap is gone. WithSegmentSize trades that count against per-segment overhead.

func (SDK) DecryptBytes added in v0.29.0

func (s SDK) DecryptBytes(ctx context.Context, ciphertext []byte, opts ...TDFReaderOption) ([]byte, error)

DecryptBytes decrypts a TDF payload held in memory and returns the plaintext. A thin wrapper over SDK.LoadTDF + Reader.WriteTo for the common case where the ciphertext already fits comfortably in memory:

plaintext, err := sdk.DecryptBytes(ctx, ciphertext)

ctx governs the KAS rewrap request (the only network call this method makes) and is honored for cancellation/timeout.

Rejects payloads over 1 GiB up front, before buffering anything, since DecryptBytes holds the full plaintext in memory. For streaming, very large payloads, or reading manifest data (attributes, assertions) between load and write, call SDK.LoadTDF directly, or use SDK.DecryptTo / SDK.DecryptFile, which stream to their destination instead of buffering.

func (SDK) DecryptFile added in v0.29.0

func (s SDK) DecryptFile(ctx context.Context, inputPath, outputPath string, opts ...TDFReaderOption) error

DecryptFile decrypts the TDF at inputPath and writes the plaintext to outputPath. A thin wrapper over SDK.LoadTDF + Reader.WriteTo for the common file-to-file case; streams directly from disk rather than buffering the ciphertext or plaintext in memory:

err := sdk.DecryptFile(ctx, "secret.tdf", "secret.txt")

ctx governs the KAS rewrap request (the only network call this method makes) and is honored for cancellation/timeout.

Plaintext is written to a temp file in outputPath's directory (created with mode 0600, since it holds decrypted content) and only renamed onto outputPath once decryption fully succeeds. A pre-existing file at outputPath is therefore never touched, truncated, or deleted if decryption fails partway — the rename is the only step that can change it, and that only happens on success. On any failure the temp file is removed; if that removal itself also fails, both errors are returned via errors.Join so callers can detect the leftover temp file with errors.Is/errors.As instead of it failing silently.

If outputPath already exists as a file, it's moved aside to a reserved backup name before the rename rather than removed outright: unlike POSIX, Windows' rename fails rather than replaces when the destination exists, so an existing file has to be out of the way first. If the rename then fails for any other reason, the backup is restored, so a pre-existing outputPath is never left destroyed by a failed finalize — only a successful finalize discards it. An existing outputPath that's a directory is rejected up front (before LoadTDF runs) rather than moved aside or removed.

inputPath and outputPath must not refer to the same file: the final rename would replace the input while it may still be open, which some platforms (notably Windows) reject or handle inconsistently. DecryptFile checks with os.SameFile and returns an error up front rather than relying on platform-specific rename-over-an-open-file semantics.

func (SDK) DecryptTo added in v0.29.0

func (s SDK) DecryptTo(ctx context.Context, out io.Writer, ciphertext []byte, opts ...TDFReaderOption) error

DecryptTo decrypts a TDF payload held in memory and writes the plaintext to out. A thin wrapper over SDK.LoadTDF + Reader.WriteTo for callers who already have a destination writer (a file, os.Stdout, an HTTP response, etc.) and don't need the plaintext held in memory:

err := sdk.DecryptTo(ctx, os.Stdout, ciphertext)

ctx governs the KAS rewrap request (the only network call this method makes) and is honored for cancellation/timeout.

func (SDK) GetBaseKey added in v0.12.0

func (s SDK) GetBaseKey(ctx context.Context) (*policy.SimpleKasKey, error)

GetBaseKey retrieves the platform base KAS key from the well-known configuration. The returned key material is expected to be public (algorithm, KID, PEM).

func (SDK) GetEntityAttributes added in v0.14.0

func (s SDK) GetEntityAttributes(ctx context.Context, entity *authorization.Entity) ([]string, error)

GetEntityAttributes returns the attribute value FQNs assigned to an entity (PE or NPE). Use this to inspect what attributes a user, service account, or other entity has been granted before making authorization decisions or constructing access policies.

The entity parameter identifies the subject. Use the appropriate field for the entity type:

// By email address
entity := &authorization.Entity{Id: "e1", EntityType: &authorization.Entity_EmailAddress{EmailAddress: "user@example.com"}}

// By username
entity := &authorization.Entity{Id: "e1", EntityType: &authorization.Entity_UserName{UserName: "alice"}}

// By client ID (NPE / service account)
entity := &authorization.Entity{Id: "e1", EntityType: &authorization.Entity_ClientId{ClientId: "my-service"}}

// By UUID
entity := &authorization.Entity{Id: "e1", EntityType: &authorization.Entity_Uuid{Uuid: "550e8400-e29b-41d4-a716-446655440000"}}

Returns a slice of attribute value FQNs (e.g., "https://example.com/attr/clearance/value/secret").

func (SDK) IsHealthy added in v0.18.0

func (s SDK) IsHealthy(ctx context.Context) (bool, error)

IsHealthy reports whether the platform's gRPC Health v1 endpoint is reachable and SERVING. The check honors ctx for deadline and cancellation; OTEL tracing works automatically when otelconnect.NewInterceptor is registered via WithExtraClientOptions at SDK construction.

Returns:

  • (true, nil) when the platform reports SERVING.
  • (false, nil) when the platform is reachable but reports NOT_SERVING or UNKNOWN.
  • (false, ErrHealthCheckUnsupported) when the SDK is configured in IPC mode.
  • (false, error) wrapping ErrPlatformUnreachable on transport failure or ctx errors.

func (SDK) ListAttributes added in v0.14.0

func (s SDK) ListAttributes(ctx context.Context, namespace ...string) ([]*policy.Attribute, error)

ListAttributes returns all active attributes available on the platform, auto-paginating through all results. An optional namespace name or ID may be provided to filter results.

Use this before calling CreateTDF() to see what attributes are available for data tagging.

Example:

attrs, err := sdk.ListAttributes(ctx)
for _, a := range attrs {
    fmt.Println(a.GetFqn())
}

func (SDK) LoadTDF

func (s SDK) LoadTDF(reader io.ReadSeeker, opts ...TDFReaderOption) (*Reader, error)

LoadTDF loads the tdf and prepare for reading the payload from TDF

func (SDK) Logger added in v0.9.0

func (s SDK) Logger() *slog.Logger

Logger returns the configured slog.Logger for this SDK instance

func (SDK) PrepareBulkDecrypt added in v0.10.0

func (s SDK) PrepareBulkDecrypt(ctx context.Context, opts ...BulkDecryptOption) (*BulkDecryptPrepared, error)

PrepareBulkDecrypt does everything except decrypt from the Bulk Decrypt ! Currently you cannot specify fulfillable obligations on an individual TDF basis

func (*SDK) StoreKASKeys added in v0.3.14

func (s *SDK) StoreKASKeys(url string, keys *policy.KasPublicKeySet) error

StoreKASKeys caches the given values as the public keys associated with the KAS at the given URL, replacing any existing keys that are cached for that URL with the same algorithm and URL. Only one key per url and algorithm is stored in the cache, so only store the most recent known key per url & algorithm pair.

func (SDK) ValidateAttributes added in v0.14.0

func (s SDK) ValidateAttributes(ctx context.Context, fqns ...string) error

ValidateAttributes checks that all provided attribute value FQNs exist on the platform. This provides fail-fast behavior: validate attributes before calling CreateTDF() to avoid late-stage decryption failures caused by missing or misspelled attributes.

fqns should be full attribute value FQNs in the form:

https://<namespace>/attr/<attribute_name>/value/<value>

Returns ErrAttributeNotFound if any FQNs are missing, with the missing FQNs listed in the error message.

Example:

err := sdk.ValidateAttributes(ctx,
    "https://example.com/attr/classification/value/secret",
    "https://example.com/attr/clearance/value/top-secret",
)
if err != nil {
    log.Fatalf("attributes not found: %v", err)
}

type SchemaValidationIntensity added in v0.3.27

type SchemaValidationIntensity int

Schema Validation where 0 = none (skip), 1 = lax (allowing novel entries, 'falsy' values for unkowns), 2 = strict (rejecting novel entries, strict match to manifest schema)

const (
	Skip SchemaValidationIntensity = iota
	Lax
	Strict
)

type Scope added in v0.3.5

type Scope string

Scope represents the object which the assertion applies to.

const (
	TrustedDataObjScope Scope = "tdo"
	PayloadScope        Scope = "payload"
)

func (Scope) String added in v0.3.5

func (s Scope) String() string

String returns the string representation of the scope.

type Segment

type Segment struct {
	Hash          string `json:"hash"`
	Size          int64  `json:"segmentSize"`
	EncryptedSize int64  `json:"encryptedSegmentSize"`
}

Segment describes one chunk of the payload.

Size and EncryptedSize are optional in the wire format: a writer may omit either key whenever its value equals the corresponding manifest-level default. Since JSON can't distinguish an omitted key from an explicit 0, a zero EncryptedSize always means "omitted" -- ciphertext is never legitimately zero bytes -- but a zero Size is ambiguous; see resolveSegmentSizes for how it's disambiguated.

type SegmentIntegrityAlg added in v0.32.0

type SegmentIntegrityAlg int

SegmentIntegrityAlg is the algorithm that authenticates a single segment's bytes. Unlike the root, both values are genuine authenticators, because the input is data the cipher itself produced.

const (
	// SegmentHS256 is an HMAC-SHA256 over the segment's bytes, keyed by the
	// payload key. It is the only meaningful choice when those bytes are not
	// AEAD output -- a plaintext segment has no tag to read out -- which the
	// experimental writer can produce and the stable one cannot. Readers must
	// keep accepting it either way.
	SegmentHS256 SegmentIntegrityAlg = iota
	// SegmentGMAC reads out the AES-GCM tag the cipher already computed over
	// exactly this segment's ciphertext. It is the default, and what
	// essentially every existing TDF declares.
	SegmentGMAC
)

func (SegmentIntegrityAlg) String added in v0.32.0

func (a SegmentIntegrityAlg) String() string

String returns the manifest spelling of the algorithm. See RootIntegrityAlg.String on out-of-range values.

type SigningAlgorithm added in v0.30.0

type SigningAlgorithm string

SigningAlgorithm identifies a JWS signing algorithm (RFC 7518 §3.1).

const (
	ES256 SigningAlgorithm = "ES256"
	ES384 SigningAlgorithm = "ES384"
	ES512 SigningAlgorithm = "ES512"
	RS256 SigningAlgorithm = "RS256"
	RS384 SigningAlgorithm = "RS384"
	RS512 SigningAlgorithm = "RS512"
)

Supported JWS signing algorithms for DPoP proof tokens (RFC 9449 §4.2).

func (SigningAlgorithm) Valid added in v0.30.0

func (a SigningAlgorithm) Valid() bool

Valid reports whether a is a SigningAlgorithm supported for DPoP proofs.

type Split added in v0.33.0

type Split struct {
	// Data is this share of the DEK: the value that, XOR'd with every
	// other share in the result, reproduces the DEK. With a single
	// split -- what DefaultKeySplitter always produces -- there is
	// nothing to XOR against, so it is the DEK verbatim.
	Data []byte

	// ID uniquely identifies this split within a SplitResult. It is
	// what the reader groups shares on, so it is required once there
	// is more than one split and must be distinct across them. With a
	// single split there is nothing to distinguish, and it is
	// conventionally left empty.
	ID string

	// KASURLs lists every KAS that can unwrap this split. Multiple
	// URLs mean any one KAS is sufficient (OR semantics).
	KASURLs []string
}

Split is one XOR share of the DEK bound to one or more KAS servers.

Experimental: not part of the stable SDK API; may change or be removed.

type SplitResult added in v0.33.0

type SplitResult struct {
	// KASPublicKeys maps KAS URL to the wrapping key to use for that
	// URL. Populated for every URL referenced by any split.
	KASPublicKeys map[string]KASPublicKey

	// Splits are the DEK shares in emission order.
	Splits []Split
}

SplitResult is what KeySplitter.Split returns: the shares plus the KAS wrapping keys needed to encrypt each share into a KeyAccess object.

Experimental: not part of the stable SDK API; may change or be removed.

func (*SplitResult) Validate added in v0.33.0

func (r *SplitResult) Validate() error

Validate reports whether the result can be turned into a key access array that a reader can actually reconstruct the DEK from. The chunked writer calls it before wrapping anything, and third-party KeySplitter implementations can call it as a self-check.

Every rule here exists because breaking it produces a TDF that is accepted at creation and fails later in a way that does not name the cause. The reader derives the set of splits it must collect from the key access objects present in the manifest, so a share that never reached the manifest is invisible to its completeness check: it XORs what it has, reconstructs the wrong DEK, and reports a root signature failure, which reads as tampering. By then the plaintext is gone.

Validate sees only the shares, so it is half the contract: it can confirm they agree with each other, but not that they agree with the key. VerifyReconstruction is the other half.

Experimental: not part of the stable SDK API; may change or be removed.

func (*SplitResult) VerifyReconstruction added in v0.33.0

func (r *SplitResult) VerifyReconstruction(dek []byte) error

VerifyReconstruction reports whether the shares actually rebuild dek. It is the half of the splitter's contract Validate cannot check: Validate sees only the shares, so it can confirm they agree with each other but not that they agree with the key.

Mirrors the self-check the XOR splitter performs on its own output. A splitter that returns shares of the wrong length, or of the right length and the wrong value, produces a TDF that wraps, uploads and rewraps without complaint, then fails at the reader's root signature check -- reported as tampering, after the plaintext is gone.

With a single split there is nothing to XOR against, so the share must equal dek verbatim; the loop below expresses that as the degenerate case rather than special-casing it.

Experimental: not part of the stable SDK API; may change or be removed.

type Statement added in v0.3.5

type Statement struct {
	// Format describes the payload encoding format. (e.g. json)
	Format string `json:"format,omitempty" validate:"required"`
	// Schema describes the schema of the payload. (e.g. tdf)
	Schema string `json:"schema,omitempty" validate:"required"`
	// Value is the payload of the assertion.
	Value string `json:"value,omitempty"  validate:"required"`
}

Statement includes information applying to the scope of the assertion. It could contain rights, handling instructions, or general metadata.

func (*Statement) UnmarshalJSON added in v0.3.27

func (s *Statement) UnmarshalJSON(data []byte) error

type TDFConfig

type TDFConfig struct {
	// contains filtered or unexported fields
}

TDFConfig Internal config struct for building TDF options.

type TDFFormat deprecated

type TDFFormat = int

TDFFormat once selected a manifest serialization. Only JSON was ever implemented, and nothing reads this.

Deprecated: unused; the manifest is always JSON.

type TDFObject

type TDFObject struct {
	// contains filtered or unexported fields
}

func (*TDFObject) Manifest

func (t *TDFObject) Manifest() Manifest

func (TDFObject) Size added in v0.2.11

func (t TDFObject) Size() int64

type TDFOption

type TDFOption func(*TDFConfig) error

func WithAssertions added in v0.3.5

func WithAssertions(assertionList ...AssertionConfig) TDFOption

WithAssertions returns an Option that add assertions to TDF.

func WithAutoconfigure added in v0.3.0

func WithAutoconfigure(enable bool) TDFOption

WithAutoconfigure toggles inferring KAS info for encrypt from data attributes. This will use the Attributes service to look up key access grants. These are KAS URLs associated with attributes. Defaults to enabled.

func WithDataAttributeValues added in v0.3.0

func WithDataAttributeValues(attributes ...*policy.Value) TDFOption

WithDataAttributeValues appends the given data attributes to the bound policy. Unlike `WithDataAttributes`, this will not trigger an attribute definition lookup during autoconfigure. That is, to use autoconfigure in an 'offline' context, you must first store the relevant attribute information locally and load it to the `CreateTDF` method with this option. DEPRECATION: This option is deprecated and will be removed in a future release.

func WithDataAttributes

func WithDataAttributes(attributes ...string) TDFOption

WithDataAttributes appends the given data attributes to the bound policy

func WithInputSize added in v0.33.0

func WithInputSize(size int64) TDFOption

WithInputSize declares the payload length, in bytes, for the reader passed to CreateTDF. Supply it when the reader cannot report its own length — a pipe, a network stream — but the length is known anyway: it lets the archive keep the compact ZIP32 layout that an unmeasurable payload has to give up. When the reader is seekable the length is recovered automatically and this option is unnecessary.

The declared length is exact, not an upper bound: reading stops after size bytes even if the reader has more to give, and a reader that reaches EOF first fails the call rather than producing a TDF that is silently short of the payload.

func WithKasInformation

func WithKasInformation(kasInfoList ...KASInfo) TDFOption

WithKasInformation adds all the kas urls and their corresponding public keys that is required to create and read the tdf. For writing TDFs, this is optional, but adding it can bypass key lookup.

During creation, if the public key is set, the kas will not be contacted for the latest key. Please make sure to set the KID if the PublicKey is set to include a KID in any key wrappers.

func WithMetaData

func WithMetaData(metaData string) TDFOption

WithMetaData returns an Option that add metadata to TDF.

func WithMimeType added in v0.2.3

func WithMimeType(mimeType string) TDFOption

func WithPolicyFrom added in v0.21.0

func WithPolicyFrom(r *Reader) TDFOption

WithPolicyFrom returns a TDFOption that binds the source TDF's policy (its attribute value FQNs) to the new TDF being created.

Use this in re-wrap pipelines to preserve the source policy without having to know about the manifest's base64 + JSON encoding:

if ok, _ := sdk.IsValidTdf(file); !ok {
    // pass through unchanged
}
reader, err := s.LoadTDF(file)
if err != nil {
    return err
}
_, err = s.CreateTDF(out, transformed, sdk.WithPolicyFrom(reader))

Reader.Init is not required: Reader.DataAttributes reads the policy from the manifest, which SDK.LoadTDF has already populated. Calling Init would trigger an unnecessary KAS rewrap.

func WithSegmentSize

func WithSegmentSize(size int64) TDFOption

WithSegmentSize returns an Option that set the default segment size within the TDF. Any excessively large or small values will be replaced with a supported value.

func WithSystemMetadataAssertion added in v0.5.0

func WithSystemMetadataAssertion() TDFOption

WithDefaultAssertion returns an Option that adds a default assertion to the TDF.

func WithTargetMode added in v0.4.1

func WithTargetMode(mode string) TDFOption

WithTargetMode sets the target schema mode for the TDF

func WithWrappingKeyAlg deprecated added in v0.3.27

func WithWrappingKeyAlg(keyType ocrypto.KeyType) TDFOption

Deprecated: WithWrappingKeyAlg sets the key type for the TDF wrapping key for both storage and transit.

type TDFReaderConfig added in v0.3.5

type TDFReaderConfig struct {
	// contains filtered or unexported fields
}

type TDFReaderOption added in v0.3.5

type TDFReaderOption func(*TDFReaderConfig) error

func WithAssertionVerificationKeys added in v0.3.5

func WithAssertionVerificationKeys(keys AssertionVerificationKeys) TDFReaderOption

func WithDisableAssertionVerification added in v0.3.17

func WithDisableAssertionVerification(disable bool) TDFReaderOption

func WithIgnoreAllowlist added in v0.4.4

func WithIgnoreAllowlist(ignore bool) TDFReaderOption

func WithKasAllowlist added in v0.4.4

func WithKasAllowlist(kasList []string) TDFReaderOption

func WithMaxManifestSize added in v0.11.0

func WithMaxManifestSize(size int64) TDFReaderOption

WithMaxManifestSize sets the maximum allowed manifest size, in bytes, for the TDF reader. By default there is no limit: the manifest grows with the policy size and the number of segments, so very large payloads legitimately carry very large manifests. A declared manifest size is always bounded by the archive itself, so this option is not needed to reject forged ZIP sizes; use it to cap how much memory a manifest read may allocate. size must be greater than 0.

func WithSchemaValidation added in v0.3.27

func WithSchemaValidation(intensity SchemaValidationIntensity) TDFReaderOption

func WithSessionKeyType added in v0.3.27

func WithSessionKeyType(keyType ocrypto.KeyType) TDFReaderOption

func WithTDFFulfillableObligationFQNs added in v0.10.0

func WithTDFFulfillableObligationFQNs(fqns []string) TDFReaderOption

type TdfType added in v0.3.5

type TdfType string
const (
	Invalid  TdfType = "Invalid"
	Standard TdfType = "Standard"
)

func GetTdfType added in v0.3.5

func GetTdfType(reader io.ReadSeeker) TdfType

GetTdfType returns the type of TDF based on the reader. Reader is reset after the check.

func (TdfType) String added in v0.3.5

func (t TdfType) String() string

String returns the string representation of the applies to state.

Directories

Path Synopsis
experimental
tdf
Experimental: This package is EXPERIMENTAL and may change or be removed at any time Package tdf provides experimental streaming TDF (Trusted Data Format) creation capabilities.
Experimental: This package is EXPERIMENTAL and may change or be removed at any time Package tdf provides experimental streaming TDF (Trusted Data Format) creation capabilities.
tdf/keysplit
Experimental: This package is EXPERIMENTAL and may change or be removed at any time Package keysplit provides key splitting functionality for TDF (Trusted Data Format) encryption.
Experimental: This package is EXPERIMENTAL and may change or be removed at any time Package keysplit provides key splitting functionality for TDF (Trusted Data Format) encryption.
internal
Wrapper for ActionServiceClient (generated code) DO NOT EDIT
Wrapper for ActionServiceClient (generated code) DO NOT EDIT

Jump to

Keyboard shortcuts

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