issuer

package
v0.3.2 Latest Latest
Warning

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

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

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 NewOpt

type NewOpt func(opts *newOpts)

NewOpt is the SD-JWT New option.

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 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 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/pkg/doc/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.

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