diff --git a/sdk/assertion.go b/sdk/assertion.go index 4c3a9244bd..da7bca9d47 100644 --- a/sdk/assertion.go +++ b/sdk/assertion.go @@ -362,7 +362,7 @@ type AssertionVerificationKeys struct { } // 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 error. +// If the default key is not set, it returns an empty key. func (k AssertionVerificationKeys) Get(assertionID string) (AssertionKey, error) { if key, ok := k.Keys[assertionID]; ok { return key, nil diff --git a/sdk/experimental/tdf/assertion.go b/sdk/experimental/tdf/assertion.go index db417a5479..26ed3be522 100644 --- a/sdk/experimental/tdf/assertion.go +++ b/sdk/experimental/tdf/assertion.go @@ -3,422 +3,122 @@ package tdf import ( - "encoding/json" - "errors" - "fmt" - - "github.com/gowebpki/jcs" - "github.com/lestrrat-go/jwx/v2/cert" - "github.com/lestrrat-go/jwx/v2/jwa" - "github.com/lestrrat-go/jwx/v2/jws" - "github.com/lestrrat-go/jwx/v2/jwt" - "github.com/opentdf/platform/lib/ocrypto" + "github.com/opentdf/platform/sdk" ) const ( - // SystemMetadataAssertionID is the standard ID for system metadata assertions - SystemMetadataAssertionID = "system-metadata" - // SystemMetadataSchemaV1 defines the schema version for system metadata - SystemMetadataSchemaV1 = "system-metadata-v1" - // kAssertionSignature is the JWT claim key for assertion signatures kAssertionSignature = "assertionSig" - // kAssertionHash is the JWT claim key for assertion hashes - kAssertionHash = "assertionHash" + kAssertionHash = "assertionHash" ) -// AssertionConfig defines an assertion to be included in the TDF during creation. -// -// AssertionConfig extends Assertion with a signing key, enabling creation -// of cryptographically signed assertions. The signing key is used during -// TDF creation but is not stored in the final TDF. -// -// Required fields: -// - ID: Unique identifier for the assertion -// - Type: The kind of assertion (BaseAssertion, HandlingAssertion) -// - Scope: What the assertion applies to (PayloadScope, TrustedDataObjScope) -// - AppliesToState: When the assertion is relevant (Encrypted, Unencrypted) -// - Statement: The assertion content and metadata -// -// Optional fields: -// - SigningKey: Custom signing key (defaults to DEK with HS256) -// -// Example: -// -// assertion := AssertionConfig{ -// ID: "retention-policy", -// Type: HandlingAssertion, -// Scope: PayloadScope, -// AppliesToState: Unencrypted, -// Statement: Statement{ -// Format: "json", -// Schema: "retention-v1", -// Value: `{"retain_days": 90, "auto_delete": true}`, -// }, -// } -type AssertionConfig struct { - ID string `validate:"required"` - Type AssertionType `validate:"required"` - Scope Scope `validate:"required"` - AppliesToState AppliesToState `validate:"required"` - Statement Statement - SigningKey AssertionKey -} - -// Assertion represents a cryptographically signed assertion in the TDF manifest. -// -// Assertions provide integrity verification and handling instructions that are -// cryptographically bound to the TDF. They cannot be modified or copied to -// another TDF without detection due to the cryptographic binding. -// -// The assertion structure includes: -// - Metadata: ID, type, scope, and state applicability -// - Statement: The actual assertion content in structured format -// - Binding: Cryptographic signature ensuring integrity -// -// Assertions are verified during TDF reading to ensure they haven't been -// tampered with since TDF creation. -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"` -} - -var errAssertionVerifyKeyFailure = errors.New("assertion: failed to verify with provided key") - -// 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 (a *Assertion) Sign(hash, sig string, key AssertionKey) error { - tok := jwt.New() - if err := tok.Set(kAssertionHash, hash); err != nil { - return fmt.Errorf("failed to set assertion hash: %w", err) - } - if err := tok.Set(kAssertionSignature, sig); err != nil { - return fmt.Errorf("failed to set assertion signature: %w", err) - } - - // sign the hash and signature - signedTok, err := jwt.Sign(tok, jwt.WithKey(jwa.KeyAlgorithmFrom(key.Alg.String()), key.Key)) - if err != nil { - return fmt.Errorf("signing assertion failed: %w", err) - } - - // set the binding - a.Binding.Method = JWS.String() - a.Binding.Signature = string(signedTok) - - return nil -} - -// Verify checks the binding signature of the assertion and -// returns the hash and the signature. It returns an error if the verification fails. -func (a Assertion) Verify(key AssertionKey) (string, string, error) { - parseOptions := []jwt.ParseOption{ - jwt.WithKey(jwa.KeyAlgorithmFrom(key.Alg.String()), key.Key), - } - - // Try to get a key from the JWS protected header if it exists - if decodedSig, err := jws.Parse([]byte(a.Binding.Signature)); err == nil && len(decodedSig.Signatures()) > 0 { //nolint:nestif // many keys - sig := decodedSig.Signatures()[0] - // First, try to get a JWK from the header - if jwkKey := sig.ProtectedHeaders().JWK(); jwkKey != nil { - var rawKey interface{} - if err := jwkKey.Raw(&rawKey); err == nil { - parseOptions = append(parseOptions, jwt.WithKey(sig.ProtectedHeaders().Algorithm(), rawKey)) - } - } - // Also try to get a key from x5c (certificate chain) header - if x5cChain := sig.ProtectedHeaders().X509CertChain(); x5cChain != nil && x5cChain.Len() > 0 { - // Get the first certificate (the signing certificate) - certBytes, ok := x5cChain.Get(0) - if ok { - // Parse the certificate to extract the public key - x509Cert, err := cert.Parse(certBytes) - if err == nil && x509Cert != nil { - parseOptions = append(parseOptions, jwt.WithKey(sig.ProtectedHeaders().Algorithm(), x509Cert.PublicKey)) - } - } - } - } - - tok, err := jwt.Parse([]byte(a.Binding.Signature), parseOptions...) - if err != nil { - return "", "", fmt.Errorf("%w: %w", errAssertionVerifyKeyFailure, err) - } - hashClaim, found := tok.Get(kAssertionHash) - if !found { - return "", "", errors.New("hash claim not found") - } - hash, ok := hashClaim.(string) - if !ok { - return "", "", errors.New("hash claim is not a string") - } - - sigClaim, found := tok.Get(kAssertionSignature) - if !found { - return "", "", errors.New("signature claim not found") - } - sig, ok := sigClaim.(string) - if !ok { - return "", "", errors.New("signature claim is not a string") - } - return hash, sig, nil -} - -// GetHash returns the hash of the assertion in hex format. -func (a Assertion) GetHash() ([]byte, error) { - // Clear out the binding - a.Binding = Binding{} - - // Marshal the assertion to JSON - assertionJSON, err := json.Marshal(a) - if err != nil { - return nil, fmt.Errorf("json.Marshal failed: %w", err) - } - - // Unmarshal the JSON into a map to manipulate it - var jsonObject map[string]interface{} - if err := json.Unmarshal(assertionJSON, &jsonObject); err != nil { - return nil, fmt.Errorf("json.Unmarshal failed: %w", err) - } - - // Remove the binding key - delete(jsonObject, "binding") - - // Marshal the map back to JSON - assertionJSON, err = json.Marshal(jsonObject) - if err != nil { - return nil, fmt.Errorf("json.Marshal failed: %w", err) - } - - // Transform the JSON using JCS - transformedJSON, err := jcs.Transform(assertionJSON) - if err != nil { - return nil, fmt.Errorf("jcs.Transform failed: %w", err) - } - - return ocrypto.SHA256AsHex(transformedJSON), nil -} - -func (s *Statement) UnmarshalJSON(data []byte) error { - // Define a custom struct for deserialization - type Alias Statement - aux := &struct { - Value json.RawMessage `json:"value,omitempty"` - *Alias - }{ - Alias: (*Alias)(s), - } - - if err := json.Unmarshal(data, &aux); err != nil { - return err - } - - // Attempt to decode Value as an object - var temp map[string]interface{} - if json.Unmarshal(aux.Value, &temp) == nil { - // Re-encode the object as a string and assign to Value - objAsString, err := json.Marshal(temp) - if err != nil { - return err - } - s.Value = string(objAsString) - } else { - // Assign raw string to Value - var str string - if err := json.Unmarshal(aux.Value, &str); err != nil { - return fmt.Errorf("value is neither a valid JSON object nor a string: %s", string(aux.Value)) - } - s.Value = str - } - - return nil -} - -// Statement includes information applying to the scope of the assertion. -// It could contain rights, handling instructions, or general metadata. -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"` -} - -// Binding enforces cryptographic integrity of the assertion. -// So the can't be modified or copied to another tdf. -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"` -} - -// AssertionType represents the category of assertion being made. -// -// Different assertion types serve different purposes in TDF handling: -// - HandlingAssertion: Instructions for data processing, retention, deletion -// - BaseAssertion: General-purpose assertions including metadata, audit info -type AssertionType string - -const ( - // HandlingAssertion provides instructions for data handling and processing. - // Examples: retention policies, deletion schedules, processing requirements - HandlingAssertion AssertionType = "handling" - // BaseAssertion is a general-purpose assertion type for metadata and other content. - // Examples: audit information, system metadata, custom business logic - BaseAssertion AssertionType = "other" +// Aliases onto [github.com/opentdf/platform/sdk], which owns the +// implementation. See the package doc for why. +type ( + // AssertionConfig defines an assertion to be included in the TDF during + // creation. It extends [Assertion] with a signing key, which is used + // during TDF creation but is not stored in the final TDF. An empty + // SigningKey defaults to the TDF's DEK with HS256. + // + // See [sdk.AssertionConfig]. + AssertionConfig = sdk.AssertionConfig + + // Assertion represents a cryptographically signed assertion in the TDF + // manifest. Assertions provide integrity verification and handling + // instructions that are cryptographically bound to the TDF, so they + // cannot be modified or copied to another TDF without detection. + // + // See [sdk.Assertion]. + Assertion = sdk.Assertion + + // Statement includes information applying to the scope of the assertion. + // It could contain rights, handling instructions, or general metadata. + // + // See [sdk.Statement]. + Statement = sdk.Statement + + // Binding enforces cryptographic integrity of the assertion, so it + // cannot be modified or copied to another TDF. + // + // See [sdk.Binding]. + Binding = sdk.Binding + + // AssertionType represents the category of assertion being made. + // + // See [sdk.AssertionType]. + AssertionType = sdk.AssertionType + + // Scope defines what component of the TDF the assertion applies to. + // + // See [sdk.Scope]. + Scope = sdk.Scope + + // AppliesToState declares whether the assertion applies to encrypted or + // unencrypted data. It is a marker for consumers; nothing in the SDK + // dispatches on it. + // + // See [sdk.AppliesToState]. + AppliesToState = sdk.AppliesToState + + // BindingMethod represents the cryptographic method used to bind + // assertions to the TDF. + // + // See [sdk.BindingMethod]. + BindingMethod = sdk.BindingMethod + + // AssertionKeyAlg represents the cryptographic algorithm for assertion + // signing keys. + // + // See [sdk.AssertionKeyAlg]. + AssertionKeyAlg = sdk.AssertionKeyAlg + + // AssertionKey represents a cryptographic key for signing and verifying + // assertions. For RS256 the Key is an RSA private key, a jwk.Key, or a + // [crypto.Signer] for hardware-backed keys; for HS256 it is the shared + // secret bytes. + // + // See [sdk.AssertionKey]. + AssertionKey = sdk.AssertionKey + + // AssertionVerificationKeys represents the verification keys for + // assertions, with an optional default for unlisted assertion IDs. Get + // returns an empty key, not an error, when neither is set. + // + // See [sdk.AssertionVerificationKeys]. + AssertionVerificationKeys = sdk.AssertionVerificationKeys ) -// String returns the string representation of the assertion type. -func (at AssertionType) String() string { - return string(at) -} - -// Scope defines what component of the TDF the assertion applies to. -// -// Scope determines which part of the TDF structure the assertion governs: -// - TrustedDataObjScope: Assertion applies to the entire TDF object -// - PayloadScope: Assertion applies only to the encrypted payload data -type Scope string - const ( - // TrustedDataObjScope indicates the assertion applies to the complete TDF object. - // This includes manifest, key access objects, and payload. - TrustedDataObjScope Scope = "tdo" + // SystemMetadataAssertionID is the standard ID for system metadata assertions. + SystemMetadataAssertionID = sdk.SystemMetadataAssertionID + // SystemMetadataSchemaV1 defines the schema version for system metadata. + SystemMetadataSchemaV1 = sdk.SystemMetadataSchemaV1 + + // HandlingAssertion provides instructions for data handling and processing. + // Examples: retention policies, deletion schedules, processing requirements. + HandlingAssertion = sdk.HandlingAssertion + // BaseAssertion is a general-purpose assertion type for metadata and other + // content. Examples: audit information, system metadata, custom business logic. + BaseAssertion = sdk.BaseAssertion + + // TrustedDataObjScope indicates the assertion applies to the complete TDF + // object, including manifest, key access objects, and payload. + TrustedDataObjScope = sdk.TrustedDataObjScope // PayloadScope indicates the assertion applies only to the payload data. // This is the most common scope for data handling assertions. - PayloadScope Scope = "payload" -) - -// String returns the string representation of the scope. -func (s Scope) String() string { - return string(s) -} - -// AppliesToState indicates when the assertion is relevant in the TDF lifecycle. -// -// This determines whether the assertion should be processed before or after -// decryption, enabling different handling patterns: -// - Encrypted: Process before decryption (e.g., access logging) -// - Unencrypted: Process after decryption (e.g., content filtering) -type AppliesToState string - -const ( - // Encrypted means the assertion should be processed before payload decryption. - // Used for access control, audit logging, and pre-processing requirements. - Encrypted AppliesToState = "encrypted" - // Unencrypted means the assertion should be processed after payload decryption. - // Used for content analysis, post-processing, and data handling requirements. - Unencrypted AppliesToState = "unencrypted" -) - -// String returns the string representation of the applies to state. -func (ats AppliesToState) String() string { - return string(ats) -} + PayloadScope = sdk.PayloadScope -// BindingMethod represents the cryptographic method used to bind assertions to the TDF. -// -// The binding method ensures assertions cannot be modified or transferred -// to other TDFs without detection. -type BindingMethod string + // Encrypted marks the assertion as applying to the encrypted payload. + Encrypted = sdk.Encrypted + // Unencrypted marks the assertion as applying to the decrypted payload. + Unencrypted = sdk.Unencrypted -const ( // JWS (JSON Web Signature) is the standard method for assertion binding. - // Uses JWT-based cryptographic signatures for tamper detection. - JWS BindingMethod = "jws" + JWS = sdk.JWS + + // AssertionKeyAlgRS256 uses RSA-SHA256 for assertion signatures. Suitable + // when assertions must be verified without access to the signing key. + AssertionKeyAlgRS256 = sdk.AssertionKeyAlgRS256 + // AssertionKeyAlgHS256 uses HMAC-SHA256 for assertion signatures. More + // efficient, and lets the TDF's DEK double as the signing key. + AssertionKeyAlgHS256 = sdk.AssertionKeyAlgHS256 ) - -// String returns the string representation of the binding method. -func (bm BindingMethod) String() string { - return string(bm) -} - -// AssertionKeyAlg represents the cryptographic algorithm for assertion signing keys. -// -// Different algorithms provide different security and compatibility characteristics: -// - RS256: RSA-based signatures, widely supported, good for public key scenarios -// - HS256: HMAC-based signatures, simpler, good for shared key scenarios -type AssertionKeyAlg string - -const ( - // AssertionKeyAlgRS256 uses RSA-SHA256 for assertion signatures. - // Suitable when assertions need to be verified by parties without access to signing keys. - AssertionKeyAlgRS256 AssertionKeyAlg = "RS256" - // AssertionKeyAlgHS256 uses HMAC-SHA256 for assertion signatures. - // More efficient, suitable when the same key used for TDF encryption can sign assertions. - AssertionKeyAlgHS256 AssertionKeyAlg = "HS256" -) - -// String returns the string representation of the algorithm. -func (a AssertionKeyAlg) String() string { - return string(a) -} - -// AssertionKey represents a cryptographic key for signing and verifying assertions. -// -// The key can be either RSA or HMAC-based depending on the algorithm: -// - RS256: Key should be an RSA private key (*rsa.PrivateKey or jwk.Key) -// - HS256: Key should be a byte slice containing the shared secret -// -// Example usage: -// -// // HMAC key using TDF's Data Encryption Key -// hmacKey := AssertionKey{ -// Alg: AssertionKeyAlgHS256, -// Key: dek, // 32-byte AES key -// } -// -// // RSA key for public key scenarios -// rsaKey := AssertionKey{ -// Alg: AssertionKeyAlgRS256, -// Key: privateKey, // *rsa.PrivateKey -// } -type AssertionKey struct { - // Alg specifies the cryptographic algorithm for this key - Alg AssertionKeyAlg - // Key contains the actual key material (type depends on algorithm). - // Can be raw key material or a crypto.Signer for hardware-backed keys (HSM/KMS). - Key interface{} -} - -// Algorithm returns the cryptographic algorithm of the key. -func (k AssertionKey) Algorithm() AssertionKeyAlg { - return k.Alg -} - -// IsEmpty returns true if the key has no algorithm or key material configured. -// Used to check if a default signing key should be used instead. -func (k AssertionKey) IsEmpty() bool { - return k.Key == nil && k.Alg == "" -} - -// AssertionVerificationKeys represents the verification keys for assertions. -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 -} - -// 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 (k AssertionVerificationKeys) Get(assertionID string) (AssertionKey, error) { - if key, ok := k.Keys[assertionID]; ok { - return key, nil - } - if k.DefaultKey.IsEmpty() { - return AssertionKey{}, nil - } - return k.DefaultKey, nil -} - -// IsEmpty returns true if the default key and the keys map are empty. -func (k AssertionVerificationKeys) IsEmpty() bool { - return k.DefaultKey.IsEmpty() && len(k.Keys) == 0 -} diff --git a/sdk/experimental/tdf/doc.go b/sdk/experimental/tdf/doc.go index b149c0212d..a4102fecca 100644 --- a/sdk/experimental/tdf/doc.go +++ b/sdk/experimental/tdf/doc.go @@ -140,6 +140,17 @@ // - Standard ZIP tools (for archive structure inspection) // - TDF specification version 4.3.0 // +// # Relationship to the Stable SDK +// +// The manifest and assertion types this package exports are aliases onto +// [github.com/opentdf/platform/sdk], which owns the definitions. A manifest +// produced here is therefore the same Go type the stable SDK produces and +// needs no conversion at the boundary. The aliases exist so existing importers +// compile unchanged; prefer the sdk-scoped names in new code. +// +// Policy, PolicyBody, and PolicyAttribute are the exception: they remain +// local. See their declarations in manifest.go for why. +// // # Error Handling // // The package uses structured error reporting with operation context: diff --git a/sdk/experimental/tdf/manifest.go b/sdk/experimental/tdf/manifest.go index 4171368f89..cf6bd14501 100644 --- a/sdk/experimental/tdf/manifest.go +++ b/sdk/experimental/tdf/manifest.go @@ -7,70 +7,90 @@ import ( "fmt" "github.com/opentdf/platform/lib/ocrypto" + "github.com/opentdf/platform/sdk" ) +// kGMACPayloadLength and kSplitKeyType copy sdk's identically-named unexported +// constants; kPolicyBindingAlg has no sdk counterpart, but matches the value +// sdk writes there via hmacIntegrityAlgorithm. All three stay only while this +// package still builds manifests itself. The follow-up that delegates manifest +// construction must delete them along with their callers, or they become +// unused. const ( kGMACPayloadLength = 16 kSplitKeyType = "split" kPolicyBindingAlg = "HS256" ) -type RootSignature struct { - Algorithm string `json:"alg"` - Signature string `json:"sig"` -} - -type IntegrityInformation struct { - RootSignature `json:"rootSignature"` - SegmentHashAlgorithm string `json:"segmentHashAlg"` - DefaultSegmentSize int64 `json:"segmentSizeDefault"` - DefaultEncryptedSegSize int64 `json:"encryptedSegmentSizeDefault"` - Segments []Segment `json:"segments"` -} - -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 Method struct { - Algorithm string `json:"algorithm"` - IV string `json:"iv"` - IsStreamable bool `json:"isStreamable"` -} - -type Payload struct { - Type string `json:"type"` - URL string `json:"url"` - Protocol string `json:"protocol"` - MimeType string `json:"mimeType"` - IsEncrypted bool `json:"isEncrypted"` - // IntegrityInformation IntegrityInformation `json:"integrityInformation"` -} - -type EncryptionInformation struct { - KeyAccessType string `json:"type"` - Policy string `json:"policy"` - KeyAccessObjs []KeyAccess `json:"keyAccess"` - Method Method `json:"method"` - IntegrityInformation `json:"integrityInformation"` -} - -type Manifest struct { - EncryptionInformation `json:"encryptionInformation"` - Payload `json:"payload"` - Assertions []Assertion `json:"assertions,omitempty"` - TDFVersion string `json:"schemaVersion,omitempty"` -} +// Aliases onto [github.com/opentdf/platform/sdk], which owns the definitions. +// See the package doc for why. +type ( + // RootSignature is the HMAC-SHA256 over the concatenated segment hashes, + // in manifest order, keyed by the payload key. HS256 is the only accepted + // algorithm. + // + // See [sdk.RootSignature]. + RootSignature = sdk.RootSignature + + // IntegrityInformation describes segment layout and the hashes that + // protect the payload. + // + // See [sdk.IntegrityInformation]. + IntegrityInformation = sdk.IntegrityInformation + + // KeyAccess is one wrapped key share addressed to a single KAS. Its + // PolicyBinding field is an interface{}: usually a [PolicyBinding], but a + // bare string in legacy manifests. + // + // See [sdk.KeyAccess]. + KeyAccess = sdk.KeyAccess + + // Method describes the payload encryption algorithm, IV, and whether the + // payload is streamable. + // + // See [sdk.Method]. + Method = sdk.Method + + // Payload describes the payload entry in the archive: its type, URL, mime + // type, and whether it is encrypted. + // + // See [sdk.Payload]. + Payload = sdk.Payload + + // EncryptionInformation carries the policy, key access objects, and + // integrity information for a TDF. + // + // See [sdk.EncryptionInformation]. + EncryptionInformation = sdk.EncryptionInformation + + // Manifest is the TDF manifest, written to the archive as + // 0.manifest.json. + // + // See [sdk.Manifest]. + Manifest = sdk.Manifest + + // Segment is one encrypted chunk of the payload plus its integrity hash. + // Size and EncryptedSize may be omitted when they equal the manifest + // defaults; see [sdk.Segment] for the defaulting rule, which matters when + // writing segments. + Segment = sdk.Segment + + // PolicyBinding is the {alg, hash} record binding a key share to the + // policy, where hash is the HMAC keyed by that split's symmetric key. + // + // See [sdk.PolicyBinding]. + PolicyBinding = sdk.PolicyBinding + + // EncryptedMetadata is the AES-GCM envelope for a key access object's + // opaque metadata. + // + // See [sdk.EncryptedMetadata]. + EncryptedMetadata = sdk.EncryptedMetadata +) +// PolicyAttribute is one attribute entry in a [PolicyBody]. It mirrors sdk's +// unexported attributeObject field-for-field; see [Policy] for why it is not +// an alias. type PolicyAttribute struct { Attribute string `json:"attribute"` DisplayName string `json:"displayName"` @@ -79,30 +99,25 @@ type PolicyAttribute struct { KasURL string `json:"kasURL"` } +// Policy is the attribute policy, serialized into +// EncryptionInformation.Policy. It is JSON-identical to [sdk.PolicyObject] but +// deliberately not aliased onto it: sdk declares PolicyObject.Body as an +// anonymous struct over the unexported attributeObject, so [PolicyBody] and +// [PolicyAttribute] have no sdk names to alias, and the local ones are not +// assignable to Body. Aliasing Policy alone would break every caller naming +// the other two. For the alias to become possible, sdk would have to both +// export the attribute type and give Body a named one. type Policy struct { UUID string `json:"uuid"` Body PolicyBody `json:"body"` } +// PolicyBody carries the attributes and dissem list of a [Policy]. type PolicyBody struct { DataAttributes []PolicyAttribute `json:"dataAttributes"` Dissem []string `json:"dissem"` } -type Segment struct { - Hash string `json:"hash"` - Size int64 `json:"segmentSize"` - EncryptedSize int64 `json:"encryptedSegmentSize"` -} -type PolicyBinding struct { - Alg string `json:"alg"` - Hash string `json:"hash"` -} -type EncryptedMetadata struct { - Cipher string `json:"ciphertext"` - Iv string `json:"iv"` -} - var ( // ErrUnsupportedRootIntegrityAlgorithm rejects any root signature // algorithm other than HS256.