holder

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: May 2, 2023 License: Apache-2.0 Imports: 5 Imported by: 1

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 CreateHolderBinding

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

CreateHolderBinding will create holder binding 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 binding. 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 Binding 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,
	WithHolderBinding(&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.HolderBinding != "")
Output:

true

Types

type BindingInfo

type BindingInfo struct {
	Payload BindingPayload
	Signer  jose.Signer
}

BindingInfo defines holder binding 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 binding 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) Verify

func (sv *NoopSignatureVerifier) Verify(joseHeaders jose.Headers, payload, signingInput, signature []byte) error

Verify 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.

type ParseOpt

type ParseOpt func(opts *parseOpts)

ParseOpt is the SD-JWT Parser option.

func WithJWTDetachedPayload

func WithJWTDetachedPayload(payload []byte) ParseOpt

WithJWTDetachedPayload option is for definition of JWT detached payload.

func WithSignatureVerifier

func WithSignatureVerifier(signatureVerifier jose.SignatureVerifier) 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