holder

package
v0.0.0-...-bd860cc Latest Latest
Warning

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

Go to latest
Published: Nov 7, 2024 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package holder enables the Holder: an entity that receives SD-JWTs from the Issuer and has control over them.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func CreateHolderVerification

func CreateHolderVerification(info *BindingInfo) (string, error)

CreateHolderVerification will create holder verification from binding info.

func CreatePresentation

func CreatePresentation(combinedFormatForIssuance string, claimsToDisclose []string, opts ...Option) (string, error)

CreatePresentation is a convenience method to assemble combined format for presentation using selected disclosures (claimsToDisclose) and optional holder verification. This call assumes that combinedFormatForIssuance has already been parsed and verified using Parse() function.

For presentation to a Verifier, the Holder MUST perform the following (or equivalent) steps:

  • Decide which Disclosures to release to the Verifier, obtaining proper End-User consent if necessary.
  • If Holder Binding is required, create a Holder Binding JWT.
  • Create the Combined Format for Presentation from selected Disclosures and Holder Verification JWT(if applicable).
  • Send the Presentation to the Verifier.
Example
signer, signatureVerifier, err := setUp()
if err != nil {
	fmt.Println("failed to set-up test: %w", err.Error())
}

holderSigner, holderJWK, err := setUpHolderBinding()
if err != nil {
	fmt.Println("failed to set-up test: %w", err.Error())
}

claims := map[string]interface{}{
	"given_name": "Albert",
	"last_name":  "Smith",
}

// Issuer will issue SD-JWT for specified claims and holder public key.
token, err := issuer.New(testIssuer, claims, nil, signer,
	issuer.WithHolderPublicKey(holderJWK))
if err != nil {
	fmt.Println("failed to issue SD-JWT: %w", err.Error())
}

combinedFormatForIssuance, err := token.Serialize(false)
if err != nil {
	fmt.Println("failed to issue SD-JWT: %w", err.Error())
}

// Holder will parse combined format for issuance and hold on to that
// combined format for issuance and the claims that can be selected.
holderClaims, err := Parse(combinedFormatForIssuance, WithSignatureVerifier(signatureVerifier))
if err != nil {
	fmt.Println("holder failed to parse SD-JWT: %w", err.Error())
}

// The Holder will only select given_name
selectedDisclosures := getDisclosuresFromClaimNames([]string{"given_name"}, holderClaims)

// Holder will disclose only sub-set of claims to verifier and create holder binding for the verifier.
combinedFormatForPresentation, err := CreatePresentation(combinedFormatForIssuance, selectedDisclosures,
	WithHolderVerification(&BindingInfo{
		Payload: BindingPayload{
			Nonce:    "nonce",
			Audience: "https://test.com/verifier",
			IssuedAt: jwt.NewNumericDate(time.Now()),
		},
		Signer: holderSigner,
	}))
if err != nil {
	fmt.Println("holder failed to create presentation: %w", err.Error())
}

cfp := common.ParseCombinedFormatForPresentation(combinedFormatForPresentation)

fmt.Println(cfp.HolderVerification != "")
Output:

true

Types

type BindingInfo

type BindingInfo struct {
	Payload BindingPayload
	Signer  jose.Signer
	Headers jose.Headers
}

BindingInfo defines holder verification payload and signer.

type BindingPayload

type BindingPayload struct {
	Nonce    string           `json:"nonce,omitempty"`
	Audience string           `json:"aud,omitempty"`
	IssuedAt *jwt.NumericDate `json:"iat,omitempty"`
}

BindingPayload represents holder verification payload.

type Claim

type Claim struct {
	Disclosure string
	Name       string
	Value      interface{}
}

Claim defines claim.

func Parse

func Parse(combinedFormatForIssuance string, opts ...ParseOpt) ([]*Claim, error)

Parse parses issuer SD-JWT and returns claims that can be selected. The Holder MUST perform the following (or equivalent) steps when receiving a Combined Format for Issuance:

  • Separate the SD-JWT and the Disclosures in the Combined Format for Issuance.

  • Hash all the Disclosures separately.

  • Find the places in the SD-JWT where the digests of the Disclosures are included.

  • If any of the digests cannot be found in the SD-JWT, the Holder MUST reject the SD-JWT.

  • Decode Disclosures and obtain plaintext of the claim values.

    It is up to the Holder how to maintain the mapping between the Disclosures and the plaintext claim values to be able to display them to the End-User when needed.

Example
signer, signatureVerifier, err := setUp()
if err != nil {
	fmt.Println("failed to set-up test: %w", err.Error())
}

claims := map[string]interface{}{
	"given_name": "Albert",
	"last_name":  "Smith",
}

// Issuer will issue SD-JWT for specified claims. Salt function is only provided to keep example outcome the same.
token, err := issuer.New(testIssuer, claims, nil, signer,
	issuer.WithSaltFnc(func() (string, error) {
		return "3jqcb67z9wks08zwiK7EyQ", nil
	}))
if err != nil {
	fmt.Println("failed to issue SD-JWT: %w", err.Error())
}

combinedFormatForIssuance, err := token.Serialize(false)
if err != nil {
	fmt.Println("failed to issue SD-JWT: %w", err.Error())
}

// Holder will parse combined format for issuance and hold on to that
// combined format for issuance and the claims that can be selected.
holderClaims, err := Parse(combinedFormatForIssuance, WithSignatureVerifier(signatureVerifier))
if err != nil {
	fmt.Println("holder failed to parse SD-JWT: %w", err.Error())
}

// Sort by claim name, keeping original order or equal elements.
sort.SliceStable(holderClaims, func(i, j int) bool {
	return holderClaims[i].Name < holderClaims[j].Name
})

holderClaimsJSON, err := marshalObj(holderClaims)
if err != nil {
	fmt.Println("verifier failed to marshal holder claims: %w", err.Error())
}

fmt.Println(holderClaimsJSON)
Output:

[
	{
		"Disclosure": "WyIzanFjYjY3ejl3a3MwOHp3aUs3RXlRIiwiZ2l2ZW5fbmFtZSIsIkFsYmVydCJd",
		"Name": "given_name",
		"Value": "Albert"
	},
	{
		"Disclosure": "WyIzanFjYjY3ejl3a3MwOHp3aUs3RXlRIiwibGFzdF9uYW1lIiwiU21pdGgiXQ",
		"Name": "last_name",
		"Value": "Smith"
	}
]

type NoopSignatureVerifier

type NoopSignatureVerifier struct {
}

NoopSignatureVerifier is no-op signature verifier (signature will not get checked).

func (*NoopSignatureVerifier) CheckJWTProof

func (sv *NoopSignatureVerifier) CheckJWTProof(joseHeaders jose.Headers,
	expectedProofIssuer string, signingInput, signature []byte) error

CheckJWTProof implements signature verification.

type Option

type Option func(opts *options)

Option is a holder option.

func WithHolderBinding

func WithHolderBinding(info *BindingInfo) Option

WithHolderBinding option to set optional holder binding. Deprecated. Use WithHolderVerification instead.

func WithHolderVerification

func WithHolderVerification(info *BindingInfo) Option

WithHolderVerification option to set optional holder verification.

type ParseOpt

type ParseOpt func(opts *parseOpts)

ParseOpt is the SD-JWT Parser option.

func WithExpectedTypHeader

func WithExpectedTypHeader(typ string) ParseOpt

WithExpectedTypHeader is an option for JWT typ header validation. Might be relevant for SDJWT V5 VC validation. Spec: https://vcstuff.github.io/draft-terbu-sd-jwt-vc/draft-terbu-oauth-sd-jwt-vc.html#name-header-parameters

func WithIssuerSigningAlgorithms

func WithIssuerSigningAlgorithms(algorithms []string) ParseOpt

WithIssuerSigningAlgorithms option is for defining secure signing algorithms (for holder verification).

func WithJWTDetachedPayload

func WithJWTDetachedPayload(payload []byte) ParseOpt

WithJWTDetachedPayload option is for definition of JWT detached payload.

func WithLeewayForClaimsValidation

func WithLeewayForClaimsValidation(duration time.Duration) ParseOpt

WithLeewayForClaimsValidation is an option for claims time(s) validation.

func WithSDJWTV5Validation

func WithSDJWTV5Validation(flag bool) ParseOpt

WithSDJWTV5Validation option is for defining additional holder verification defined in SDJWT V5 spec. Section: https://www.ietf.org/archive/id/draft-ietf-oauth-selective-disclosure-jwt-05.html#section-6.1-3

func WithSignatureVerifier

func WithSignatureVerifier(signatureVerifier afgjwt.ProofChecker) ParseOpt

WithSignatureVerifier option is for definition of JWT detached payload.

Jump to

Keyboard shortcuts

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