issuer

package
v0.0.0-...-64dd8ac Latest Latest
Warning

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

Go to latest
Published: Mar 27, 2024 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package issuer enables the Issuer: An entity that creates SD-JWTs.

An SD-JWT is a digitally signed document containing digests over the claims (per claim: a random salt, the claim name and the claim value). It MAY further contain clear-text claims that are always disclosed to the Verifier. It MUST be digitally signed using the Issuer's private key.

SD-JWT-DOC = (METADATA, SD-CLAIMS, NON-SD-CLAIMS)
SD-JWT = SD-JWT-DOC | SIG(SD-JWT-DOC, ISSUER-PRIV-KEY)

SD-CLAIMS is an array of digest values that ensure the integrity of and map to the respective Disclosures. Digest values are calculated over the Disclosures, each of which contains the claim name (CLAIM-NAME), the claim value (CLAIM-VALUE), and a random salt (SALT). Digests are calculated using a hash function:

SD-CLAIMS = ( HASH(SALT, CLAIM-NAME, CLAIM-VALUE) )*

SD-CLAIMS can also be nested deeper to capture more complex objects.

The Issuer further creates a set of Disclosures for all claims in the SD-JWT. The Disclosures are sent to the Holder together with the SD-JWT:

DISCLOSURES = ( (SALT, CLAIM-NAME, CLAIM-VALUE) )*

The SD-JWT and the Disclosures are sent to the Holder by the Issuer:

COMBINED-ISSUANCE = SD-JWT | DISCLOSURES

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Claims

type Claims jwt.Claims

Claims defines JSON Web Token Claims (https://tools.ietf.org/html/rfc7519#section-4)

type DisclosureEntity

type DisclosureEntity struct {
	Result      string
	Salt        string
	Key         string
	Value       interface{}
	DebugArr    []interface{} `json:"-"`
	DebugStr    string
	DebugDigest string
}

DisclosureEntity represents disclosure with extra information.

type NewOpt

type NewOpt func(opts *newOpts)

NewOpt is the SD-JWT New option.

func WithAlwaysIncludeObjects

func WithAlwaysIncludeObjects(alwaysIncludeObjects []string) NewOpt

WithAlwaysIncludeObjects is an option for provide object keys that should be a part of selectively disclosable claims. Eexample if you would like to keep original claims structure from example below, but selectively disclose all claims

{
	"degree": {
	   "degree": "MIT",
	   "type": "BachelorDegree",
	 },
	 "name": "Jayden Doe",
	 "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
	}

you should specify the following array: []string{"degree"}. As output, you will receive:

{
	"_sd": [
		"zDSZ9PKx_bB2CrFU8Xd__LkpMip06ApY-V6Y9fnppuo",
		"5Hnqg9PgQ4MdHxTv2KDt9qp8ILd1JEYq0luNO8JZ7G4"
	],
	"degree": {
		"_sd": [
			"i03SehlKmaFrwPM-gX8s3XuF_LTTE2T1XQQSJXjo6pw",
			"qZEZR8g_uc8fMyQCvs4DjXdY8uOI9IHpOokzx0cH_Qw"
		]
	}
}

func WithAudience

func WithAudience(audience string) NewOpt

WithAudience is an option for SD-JWT payload. This is a clear-text claim that is always disclosed.

func WithDecoyDigests

func WithDecoyDigests(flag bool) NewOpt

WithDecoyDigests is an option for adding decoy digests(default is false).

func WithExpiry

func WithExpiry(expiry *jwt.NumericDate) NewOpt

WithExpiry is an option for SD-JWT payload. This is a clear-text claim that is always disclosed.

func WithHashAlgorithm

func WithHashAlgorithm(alg crypto.Hash) NewOpt

WithHashAlgorithm is an option for hashing disclosures.

func WithHolderPublicKey

func WithHolderPublicKey(jwk *jwk.JWK) NewOpt

WithHolderPublicKey is an option for SD-JWT payload. The Holder can prove legitimate possession of an SD-JWT by proving control over the same private key during the issuance and presentation. An SD-JWT with Holder Binding contains a public key or a reference to a public key that matches to the private key controlled by the Holder. The "cnf" claim value MUST represent only a single proof-of-possession key. This implementation is using CNF "jwk".

func WithID

func WithID(id string) NewOpt

WithID is an option for SD-JWT payload. This is a clear-text claim that is always disclosed.

func WithIssuedAt

func WithIssuedAt(issuedAt *jwt.NumericDate) NewOpt

WithIssuedAt is an option for SD-JWT payload. This is a clear-text claim that is always disclosed.

func WithJSONMarshaller

func WithJSONMarshaller(jsonMarshal func(v interface{}) ([]byte, error)) NewOpt

WithJSONMarshaller is option is for marshalling disclosure.

func WithJTI

func WithJTI(jti string) NewOpt

WithJTI is an option for SD-JWT payload. This is a clear-text claim that is always disclosed.

func WithNonSelectivelyDisclosableClaims

func WithNonSelectivelyDisclosableClaims(nonSDClaims []string) NewOpt

WithNonSelectivelyDisclosableClaims is an option for provide claim names that should be ignored when creating selectively disclosable claims. For example if you would like to not selectively disclose id and degree type from the following claims: {

"degree": {
   "degree": "MIT",
   "type": "BachelorDegree",
 },
 "name": "Jayden Doe",
 "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
}

you should specify the following array: []string{"id", "degree.type"}.

func WithNotBefore

func WithNotBefore(notBefore *jwt.NumericDate) NewOpt

WithNotBefore is an option for SD-JWT payload. This is a clear-text claim that is always disclosed.

func WithRecursiveClaimsObjects

func WithRecursiveClaimsObjects(recursiveClaimsObject []string) NewOpt

WithRecursiveClaimsObjects is an option for provide object keys that should be selective disclosed recursively, e.g. output digest for given object will refer to the disclosure, that contains digests of nested claims. For example if you would like to define degree object as selective disclosed recursively

{
	"degree": {
	   "degree": "MIT",
	   "type": "BachelorDegree",
	 },
	 "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
}

you should specify the following array: []string{"degree"}. As output, you will receive:

{
		"_sd": [
			"fgoQstuIzTLQ4zqosjUC_qCk-xx3wjDQU2QkQtbn7FI",
			"mdephPRizMUa-LLs3JVeuTRS0tPaTd0faHg5kgKHNGk"
		]
}

and 4 disclosures: nolint:lll [

{
	"Result": "WyJ2Y2g2YXVDVEo3bGdWWjFxNjN3cWF3IiwiZGVncmVlIix7Il9zZCI6WyJnZnNlcUhtTml0SXUwLTBoMTR5bnFNenV2cTFFaXJUQXpVaERuRWxTVlgwIiwiNDNoZm5NN1N6WnNhbEFkYlhReXE3dzRVdmQ1M1lPeFRORnBGSnI0WkcwQSJdfV0",
	"Salt": "vch6auCTJ7lgVZ1q63wqaw",
	"Key": "degree",
	"Value": {
		"_sd": [
			"gfseqHmNitIu0-0h14ynqMzuvq1EirTAzUhDnElSVX0",
			"43hfnM7SzZsalAdbXQyq7w4Uvd53YOxTNFpFJr4ZG0A"
		]
	},
	"DebugStr": "[\"vch6auCTJ7lgVZ1q63wqaw\",\"degree\",{\"_sd\":[\"gfseqHmNitIu0-0h14ynqMzuvq1EirTAzUhDnElSVX0\",\"43hfnM7SzZsalAdbXQyq7w4Uvd53YOxTNFpFJr4ZG0A\"]}]",
	"DebugDigest": "mdephPRizMUa-LLs3JVeuTRS0tPaTd0faHg5kgKHNGk"
},
{
	"Result": "WyJaVHFiUzI0ZWlybmpQMFlObmFmakxRIiwiaWQiLCJkaWQ6ZXhhbXBsZTplYmZlYjFmNzEyZWJjNmYxYzI3NmUxMmVjMjEiXQ",
	"Salt": "ZTqbS24eirnjP0YNnafjLQ",
	"Key": "id",
	"Value": "did:example:ebfeb1f712ebc6f1c276e12ec21",
	"DebugStr": "[\"ZTqbS24eirnjP0YNnafjLQ\",\"id\",\"did:example:ebfeb1f712ebc6f1c276e12ec21\"]",
	"DebugDigest": "fgoQstuIzTLQ4zqosjUC_qCk-xx3wjDQU2QkQtbn7FI"
},
{
	"Result": "WyIyOEEzMmR0OW9JR0lLZW9iVEdIM2F3IiwiZGVncmVlIiwiTUlUIl0",
	"Salt": "28A32dt9oIGIKeobTGH3aw",
	"Key": "degree",
	"Value": "MIT",
	"DebugStr": "[\"28A32dt9oIGIKeobTGH3aw\",\"degree\",\"MIT\"]",
	"DebugDigest": "43hfnM7SzZsalAdbXQyq7w4Uvd53YOxTNFpFJr4ZG0A"
},
{
	"Result": "WyJUNE8wRlZ2MDBpREhGNFZpYy0wR1VnIiwidHlwZSIsIkJhY2hlbG9yRGVncmVlIl0",
	"Salt": "T4O0FVv00iDHF4Vic-0GUg",
	"Key": "type",
	"Value": "BachelorDegree",
	"DebugStr": "[\"T4O0FVv00iDHF4Vic-0GUg\",\"type\",\"BachelorDegree\"]",
	"DebugDigest": "gfseqHmNitIu0-0h14ynqMzuvq1EirTAzUhDnElSVX0"
}

].

func WithSDJWTVersion

func WithSDJWTVersion(version common.SDJWTVersion) NewOpt

WithSDJWTVersion sets version for SD-JWT VC.

func WithSaltFnc

func WithSaltFnc(fnc func() (string, error)) NewOpt

WithSaltFnc is an option for generating salt. Mostly used for testing. A new salt MUST be chosen for each claim independently of other salts. The RECOMMENDED minimum length of the randomly-generated portion of the salt is 128 bits. It is RECOMMENDED to base64url-encode the salt value, producing a string.

func WithStructuredClaims

func WithStructuredClaims(flag bool) NewOpt

WithStructuredClaims is an option for handling structured claims(default is false).

func WithSubject

func WithSubject(subject string) NewOpt

WithSubject is an option for SD-JWT payload. This is a clear-text claim that is always disclosed.

type SDJWTBuilderV2

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

SDJWTBuilderV2 represents builder struct for SD-JWT v2 spec.

func NewSDJWTBuilderV2

func NewSDJWTBuilderV2() *SDJWTBuilderV2

NewSDJWTBuilderV2 returns new instance of SDJWTBuilderV2.

func (*SDJWTBuilderV2) CreateDisclosuresAndDigests

func (s *SDJWTBuilderV2) CreateDisclosuresAndDigests(
	path string,
	claims map[string]interface{},
	opts *newOpts,
) ([]*DisclosureEntity, map[string]interface{}, error)

CreateDisclosuresAndDigests creates disclosures and digests.

func (*SDJWTBuilderV2) ExtractCredentialClaims

func (s *SDJWTBuilderV2) ExtractCredentialClaims(vcClaims map[string]interface{}) (map[string]interface{}, error)

ExtractCredentialClaims extracts credential claims.

func (*SDJWTBuilderV2) GenerateSalt

func (s *SDJWTBuilderV2) GenerateSalt() (string, error)

GenerateSalt generates salt.

type SDJWTBuilderV5

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

SDJWTBuilderV5 represents builder struct for SD-JWT v5 spec.

func NewSDJWTBuilderV5

func NewSDJWTBuilderV5() *SDJWTBuilderV5

NewSDJWTBuilderV5 returns new instance of SDJWTBuilderV5.

func (*SDJWTBuilderV5) CreateDisclosuresAndDigests

func (s *SDJWTBuilderV5) CreateDisclosuresAndDigests(
	path string,
	claims map[string]interface{},
	opts *newOpts,
) ([]*DisclosureEntity, map[string]interface{}, error)

CreateDisclosuresAndDigests creates disclosures and digests.

func (*SDJWTBuilderV5) ExtractCredentialClaims

func (s *SDJWTBuilderV5) ExtractCredentialClaims(
	vc map[string]interface{},
) (map[string]interface{}, error)

ExtractCredentialClaims extracts credential claims.

func (*SDJWTBuilderV5) GenerateSalt

func (s *SDJWTBuilderV5) GenerateSalt() (string, error)

GenerateSalt generates salt.

type SelectiveDisclosureJWT

type SelectiveDisclosureJWT struct {
	SignedJWT   *afgjwt.JSONWebToken
	Disclosures []string
}

SelectiveDisclosureJWT defines Selective Disclosure JSON Web Token (https://tools.ietf.org/html/rfc7519)

func New

func New(issuer string, claims interface{}, headers jose.Headers,
	signer jose.Signer, opts ...NewOpt) (*SelectiveDisclosureJWT, error)

New creates new signed Selective Disclosure JWT based on input claims. The Issuer MUST create a Disclosure for each selectively disclosable claim as follows: Create an array of three elements in this order:

A salt value. Generated by the system, the salt value MUST be unique for each claim that is to be selectively
disclosed.
The claim name, or key, as it would be used in a regular JWT body. This MUST be a string.
The claim's value, as it would be used in a regular JWT body. The value MAY be of any type that is allowed in JSON,
including numbers, strings, booleans, arrays, and objects.

Then JSON-encode the array such that an UTF-8 string is produced. Then base64url-encode the byte representation of the UTF-8 string to create the Disclosure.

Example
package main

import (
	"crypto/ed25519"
	"crypto/rand"
	"encoding/json"
	"fmt"

	afjwt "github.com/hyperledger/aries-framework-go/component/models/jwt"
)

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

	claims := map[string]interface{}{
		"last_name": "Smith",
		"address": map[string]interface{}{
			"street_address": "123 Main St",
			"country":        "US",
		},
	}

	// Issuer will issue SD-JWT for specified claims. Salt function is only provided to keep example outcome the same.
	token, err := New("https://example.com/issuer", claims, nil, signer,
		WithStructuredClaims(true),
		WithNonSelectivelyDisclosableClaims([]string{"address.country"}),
		WithSaltFnc(func() (string, error) {
			return sampleSalt, nil
		}))
	if err != nil {
		fmt.Println("failed to issue SD-JWT: %w", err.Error())
	}

	var decoded map[string]interface{}

	err = token.DecodeClaims(&decoded)
	if err != nil {
		fmt.Println("failed to decode SD-JWT claims: %w", err.Error())
	}

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

	fmt.Println(issuerClaimsJSON)

}

func setUp() (*afjwt.JoseED25519Signer, *afjwt.JoseEd25519Verifier, error) {
	issuerPublicKey, issuerPrivateKey, err := ed25519.GenerateKey(rand.Reader)
	if err != nil {
		return nil, nil, err
	}

	signer := afjwt.NewEd25519Signer(issuerPrivateKey)

	signatureVerifier, err := afjwt.NewEd25519Verifier(issuerPublicKey)
	if err != nil {
		return nil, nil, err
	}

	return signer, signatureVerifier, nil
}

func marshalObj(obj interface{}) (string, error) {
	objBytes, err := json.Marshal(obj)
	if err != nil {
		fmt.Println("failed to marshal object: %w", err.Error())
	}

	return prettyPrint(objBytes)
}
Output:

{
	"_sd": [
		"V9-Eiizd3iJpdlxojQuwps44Zba7z6R08S7rPCDg_wU"
	],
	"_sd_alg": "sha-256",
	"address": {
		"_sd": [
			"tD1XVFffEo0KTGuvHn9UlXCBgt3vot5xAanqXMdvVMg"
		],
		"country": "US"
	},
	"iss": "https://example.com/issuer"
}

func NewFromVC

func NewFromVC(vc map[string]interface{}, headers jose.Headers,
	signer jose.Signer, opts ...NewOpt) (*SelectiveDisclosureJWT, error)

NewFromVC creates new signed Selective Disclosure JWT based on Verifiable Credential in map representation.

Algorithm:

  • extract credential subject map from verifiable credential
  • create un-signed SD-JWT plus Disclosures with credential subject map
  • decode claims from SD-JWT to get credential subject map with selective disclosures
  • replace VC credential subject with newly created credential subject with selective disclosures
  • create signed SD-JWT based on VC
  • return signed SD-JWT plus Disclosures

func (*SelectiveDisclosureJWT) DecodeClaims

func (j *SelectiveDisclosureJWT) DecodeClaims(c interface{}) error

DecodeClaims fills input c with claims of a token.

func (*SelectiveDisclosureJWT) LookupStringHeader

func (j *SelectiveDisclosureJWT) LookupStringHeader(name string) string

LookupStringHeader makes look up of particular header with string value.

func (*SelectiveDisclosureJWT) Serialize

func (j *SelectiveDisclosureJWT) Serialize(detached bool) (string, error)

Serialize makes (compact) serialization of token.

Jump to

Keyboard shortcuts

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