github.com/hyperledger/aries-framework-go@v0.3.2/pkg/didcomm/common/middleware/middleware.go (about)

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package middleware
     8  
     9  import (
    10  	"encoding/json"
    11  	"errors"
    12  	"fmt"
    13  	"time"
    14  
    15  	"github.com/google/uuid"
    16  
    17  	"github.com/hyperledger/aries-framework-go/pkg/common/log"
    18  	"github.com/hyperledger/aries-framework-go/pkg/common/model"
    19  	"github.com/hyperledger/aries-framework-go/pkg/crypto"
    20  	didcomm "github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service"
    21  	"github.com/hyperledger/aries-framework-go/pkg/doc/did"
    22  	"github.com/hyperledger/aries-framework-go/pkg/doc/jose"
    23  	"github.com/hyperledger/aries-framework-go/pkg/doc/util/jwkkid"
    24  	"github.com/hyperledger/aries-framework-go/pkg/doc/util/vmparse"
    25  	vdrapi "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr"
    26  	"github.com/hyperledger/aries-framework-go/pkg/kms"
    27  	"github.com/hyperledger/aries-framework-go/pkg/store/connection"
    28  	didstore "github.com/hyperledger/aries-framework-go/pkg/store/did"
    29  	"github.com/hyperledger/aries-framework-go/pkg/vdr/peer"
    30  	"github.com/hyperledger/aries-framework-go/spi/storage"
    31  )
    32  
    33  var logger = log.New("didcomm/common/middleware")
    34  
    35  // DIDCommMessageMiddleware performs inbound/outbound message handling tasks that apply to all DIDComm V2 messages.
    36  //   - Rotates DIDs on outbound messages, and handles inbound messages that rotate DIDs.
    37  type DIDCommMessageMiddleware struct {
    38  	kms               kms.KeyManager
    39  	crypto            crypto.Crypto
    40  	vdr               vdrapi.Registry
    41  	connStore         *connection.Recorder
    42  	didStore          didstore.ConnectionStore
    43  	mediaTypeProfiles []string
    44  }
    45  
    46  type provider interface {
    47  	Crypto() crypto.Crypto
    48  	KMS() kms.KeyManager
    49  	VDRegistry() vdrapi.Registry
    50  	StorageProvider() storage.Provider
    51  	ProtocolStateStorageProvider() storage.Provider
    52  	MediaTypeProfiles() []string
    53  	DIDConnectionStore() didstore.ConnectionStore
    54  }
    55  
    56  // New creates a DIDCommMessageMiddleware.
    57  func New(p provider) (*DIDCommMessageMiddleware, error) {
    58  	connRecorder, err := connection.NewRecorder(p)
    59  	if err != nil {
    60  		return nil, fmt.Errorf("failed to initialize connection recorder: %w", err)
    61  	}
    62  
    63  	return &DIDCommMessageMiddleware{
    64  		kms:               p.KMS(),
    65  		crypto:            p.Crypto(),
    66  		vdr:               p.VDRegistry(),
    67  		connStore:         connRecorder,
    68  		mediaTypeProfiles: p.MediaTypeProfiles(),
    69  		didStore:          p.DIDConnectionStore(),
    70  	}, nil
    71  }
    72  
    73  type rotatePayload struct {
    74  	Sub string `json:"sub"`
    75  	ISS string `json:"iss"`
    76  	IAT int64  `json:"iat"`
    77  }
    78  
    79  const (
    80  	fromPriorJSONKey  = "from_prior"
    81  	fromDIDJSONKey    = "from"
    82  	bodyJSONKey       = "body"
    83  	initialStateParam = "initialState"
    84  )
    85  
    86  // HandleInboundMessage processes did rotation and invitee connection creation on inbound messages.
    87  func (h *DIDCommMessageMiddleware) HandleInboundMessage( // nolint:gocyclo,funlen
    88  	msg didcomm.DIDCommMsgMap,
    89  	theirDID, myDID string,
    90  ) error {
    91  	// TODO: clean up connection record management across all the handler methods. Currently correct but messy.
    92  	// TODO: clean up some logic:
    93  	//  - inbound invitation acceptance cannot be a rotation
    94  	// GetConnectionRecordByDIDs(myDID, theirDID)
    95  	// if no connection, create connection
    96  	rec, err := h.handleInboundInvitationAcceptance(theirDID, myDID)
    97  	if err != nil {
    98  		return err
    99  	}
   100  
   101  	isV2, err := didcomm.IsDIDCommV2(&msg)
   102  	if !isV2 || err != nil {
   103  		return err
   104  	}
   105  
   106  	var updatedConnRec bool
   107  
   108  	// if they don't rotate: GetConnectionRecordByTheirDID(theirDID)
   109  	// if they do rotate: GetConnectionRecordByTheirDID(theirOldDID), GetConnectionRecordByTheirDID(theirNewDID)
   110  	rec2, stepUpdated, err := h.handleInboundRotate(msg, theirDID, myDID, rec)
   111  	if err != nil {
   112  		return err
   113  	}
   114  
   115  	updatedConnRec = updatedConnRec || stepUpdated
   116  
   117  	if rec2 != nil {
   118  		rec = rec2
   119  	}
   120  
   121  	if rec == nil {
   122  		rec, err = h.connStore.GetConnectionRecordByTheirDID(theirDID)
   123  		if err != nil {
   124  			return err
   125  		}
   126  	}
   127  
   128  	rec2, stepUpdated, err = h.handleInboundRotateAck(myDID, rec)
   129  	if err != nil {
   130  		return err
   131  	}
   132  
   133  	updatedConnRec = updatedConnRec || stepUpdated
   134  
   135  	if rec2 != nil {
   136  		rec = rec2
   137  	}
   138  
   139  	// handle inbound ack of peer DID
   140  	if rec != nil && rec.PeerDIDInitialState != "" && myDID == rec.MyDID {
   141  		rec.PeerDIDInitialState = ""
   142  		updatedConnRec = true
   143  	}
   144  
   145  	if updatedConnRec && rec != nil {
   146  		err = h.connStore.SaveConnectionRecord(rec)
   147  		if err != nil {
   148  			return fmt.Errorf("updating connection: %w", err)
   149  		}
   150  	}
   151  
   152  	return nil
   153  }
   154  
   155  // HandleOutboundMessage processes an outbound message.
   156  func (h *DIDCommMessageMiddleware) HandleOutboundMessage(msg didcomm.DIDCommMsgMap, rec *connection.Record,
   157  ) didcomm.DIDCommMsgMap {
   158  	if rec.PeerDIDInitialState != "" {
   159  		msg[fromDIDJSONKey] = rec.MyDID + "?" + initialStateParam + "=" + rec.PeerDIDInitialState
   160  	}
   161  
   162  	if isV2, err := didcomm.IsDIDCommV2(&msg); !isV2 || err != nil {
   163  		return msg
   164  	}
   165  
   166  	// if there's no from DID, add a from DID.
   167  	if _, ok := msg[fromDIDJSONKey]; !ok {
   168  		msg[fromDIDJSONKey] = rec.MyDID
   169  	}
   170  
   171  	// if there's no body, add a body.
   172  	if _, ok := msg[bodyJSONKey]; !ok {
   173  		msg[bodyJSONKey] = map[string]interface{}{}
   174  	}
   175  
   176  	if rec.MyDIDRotation != nil {
   177  		msg[fromPriorJSONKey] = rec.MyDIDRotation.FromPrior
   178  	}
   179  
   180  	return msg
   181  }
   182  
   183  type invitationStub struct {
   184  	Type string `json:"type"`
   185  	ID   string `json:"id"`
   186  }
   187  
   188  func (h *DIDCommMessageMiddleware) handleInboundInvitationAcceptance(senderDID, recipientDID string,
   189  ) (*connection.Record, error) {
   190  	didParsed, err := did.Parse(recipientDID)
   191  	if err != nil {
   192  		logger.Warnf("failed to parse inbound recipient DID: %s", err.Error())
   193  		return nil, nil
   194  	}
   195  
   196  	if didParsed.Method == peer.DIDMethod { // TODO any more exception cases like peer?
   197  		// can't be an invitation DID
   198  		return nil, nil
   199  	}
   200  
   201  	inv := &invitationStub{}
   202  
   203  	err = h.connStore.GetOOBv2Invitation(recipientDID, inv)
   204  	if errors.Is(err, storage.ErrDataNotFound) {
   205  		// if there's no invitation, this message isn't an acceptance
   206  		return nil, nil
   207  	} else if err != nil {
   208  		return nil, err
   209  	}
   210  
   211  	rec, err := h.connStore.GetConnectionRecordByDIDs(recipientDID, senderDID)
   212  	if err == nil {
   213  		return rec, nil
   214  	} else if !errors.Is(err, storage.ErrDataNotFound) {
   215  		return rec, fmt.Errorf("failed to get connection record: %w", err)
   216  	}
   217  
   218  	// if we created an invitation with this DID, and have no connection, we create a connection.
   219  
   220  	rec = &connection.Record{
   221  		ConnectionID:    uuid.New().String(),
   222  		MyDID:           recipientDID,
   223  		TheirDID:        senderDID,
   224  		InvitationID:    inv.ID,
   225  		State:           connection.StateNameCompleted,
   226  		Namespace:       connection.MyNSPrefix,
   227  		ServiceEndPoint: model.NewDIDCommV2Endpoint([]model.DIDCommV2Endpoint{{Accept: h.mediaTypeProfiles}}),
   228  		DIDCommVersion:  didcomm.V2,
   229  	}
   230  
   231  	err = h.connStore.SaveConnectionRecord(rec)
   232  	if err != nil {
   233  		return nil, fmt.Errorf("failed to save new connection: %w", err)
   234  	}
   235  
   236  	return rec, nil
   237  }
   238  
   239  // HandleInboundPeerDID checks if an inbound message contains a peer DID, saving the peer DID if so.
   240  func (h *DIDCommMessageMiddleware) HandleInboundPeerDID(msg didcomm.DIDCommMsgMap) error { // nolint:gocyclo
   241  	from, ok := msg[fromDIDJSONKey].(string)
   242  	if !ok {
   243  		return nil
   244  	}
   245  
   246  	didURL, err := did.ParseDIDURL(from)
   247  	if err != nil {
   248  		// special case - some didcomm v1 messages might have a "from" field, which isn't necessarily a DID
   249  		if isV2, e := didcomm.IsDIDCommV2(&msg); !isV2 || e != nil {
   250  			return nil // nolint:nilerr // ignore error from IsDIDCommV2, simply skip unusual unexpected messages.
   251  		}
   252  
   253  		return fmt.Errorf("parsing their DID: %w", err)
   254  	}
   255  
   256  	if didURL.Method != peer.DIDMethod {
   257  		return nil
   258  	}
   259  
   260  	initialState, ok := didURL.Queries[initialStateParam]
   261  	if !ok {
   262  		return nil
   263  	}
   264  
   265  	if len(initialState) == 0 {
   266  		return fmt.Errorf("expected initialState to have value")
   267  	}
   268  
   269  	theirDoc, err := peer.DocFromGenesisDelta(initialState[0])
   270  	if err != nil {
   271  		return fmt.Errorf("parsing DID doc from peer DID initialState: %w", err)
   272  	}
   273  
   274  	_, err = h.vdr.Create(peer.DIDMethod, theirDoc, vdrapi.WithOption("store", true))
   275  	if err != nil {
   276  		return fmt.Errorf("saving their peer DID: %w", err)
   277  	}
   278  
   279  	err = h.didStore.SaveDIDFromDoc(theirDoc)
   280  	if err != nil {
   281  		return fmt.Errorf("saving key to did map for their peer DID: %w", err)
   282  	}
   283  
   284  	msg[fromDIDJSONKey] = didURL.DID.String()
   285  
   286  	return nil
   287  }
   288  
   289  func (h *DIDCommMessageMiddleware) handleInboundRotate( // nolint:funlen,gocyclo
   290  	msg didcomm.DIDCommMsgMap,
   291  	senderDID, recipientDID string,
   292  	recIn *connection.Record,
   293  ) (*connection.Record, bool, error) {
   294  	var (
   295  		jws            *jose.JSONWebSignature
   296  		payload        *rotatePayload
   297  		err            error
   298  		alreadyRotated bool
   299  		updatedConnRec bool
   300  	)
   301  
   302  	fromPriorInterface, theyRotate := msg[fromPriorJSONKey]
   303  	if !theyRotate {
   304  		return recIn, false, nil
   305  	}
   306  
   307  	fromPrior, ok := fromPriorInterface.(string)
   308  	if !ok {
   309  		return nil, false, fmt.Errorf("didcomm message 'from_prior' field should be a string")
   310  	}
   311  
   312  	jws, payload, err = h.getUnverifiedJWS(senderDID, fromPrior)
   313  	if err != nil {
   314  		return nil, false, err
   315  	}
   316  
   317  	theirOldDID := payload.ISS
   318  	theirNewDID := payload.Sub
   319  
   320  	// Note: if we rotated our DID, we need to accept messages to either our old DID or our new DID.
   321  	// When we rotate a connection, we store the connection's record twice - once under our old DID and their DID,
   322  	//  and once under our new DID and their DID.
   323  	// On top of that, when we receive a message containing a DID rotation, we might need to check for a record under
   324  	//  their old DID and their new DID
   325  
   326  	// TODO: maybe useful if connection.Lookup would be able to look up a connection record given
   327  	//  two candidate DIDs for myDID and two candidate DIDs for theirDID?
   328  
   329  	rec, err := h.connStore.GetConnectionRecordByDIDs(recipientDID, theirOldDID)
   330  	if err != nil {
   331  		_, err = h.connStore.GetConnectionRecordByDIDs(recipientDID, theirNewDID)
   332  		if err == nil {
   333  			// if we have a connection under their new DID, then we've already rotated.
   334  			alreadyRotated = true
   335  		}
   336  	}
   337  
   338  	if errors.Is(err, storage.ErrDataNotFound) {
   339  		// if the connection isn't found, we assume that this inbound message is the start of the communication,
   340  		// in which case there can be no rotation
   341  		return nil, false, fmt.Errorf("inbound message cannot rotate without an existing prior connection")
   342  	} else if err != nil {
   343  		return nil, false, fmt.Errorf("looking up did rotation connection record: %w", err)
   344  	}
   345  
   346  	if !alreadyRotated {
   347  		err = h.verifyJWSAndPayload(jws, payload)
   348  		if err != nil {
   349  			return nil, false, fmt.Errorf("'from_prior' validation: %w", err)
   350  		}
   351  
   352  		// update our connection to use their new DID
   353  		rec.TheirDID = payload.Sub
   354  		updatedConnRec = true
   355  	}
   356  
   357  	if rec != nil {
   358  		recIn = rec
   359  	}
   360  
   361  	return recIn, updatedConnRec, nil
   362  }
   363  
   364  func (h *DIDCommMessageMiddleware) handleInboundRotateAck(recipientDID string, rec *connection.Record,
   365  ) (*connection.Record, bool, error) {
   366  	var updatedConnRec bool
   367  
   368  	// if we performed a did rotation, check if they acknowledge it
   369  	if rec.MyDIDRotation != nil {
   370  		// check if they sent to our old DID or our new DID
   371  		switch recipientDID {
   372  		case rec.MyDIDRotation.OldDID:
   373  			// they used our old DID
   374  		case rec.MyDIDRotation.NewDID:
   375  			// they used our new DID, so we don't need to rotate anymore
   376  			rec.MyDIDRotation = nil
   377  			updatedConnRec = true
   378  		default:
   379  			return nil, false, fmt.Errorf("inbound message sent to unexpected DID")
   380  		}
   381  	}
   382  
   383  	return rec, updatedConnRec, nil
   384  }
   385  
   386  // RotateConnectionDID rotates the agent's DID on the connection under connectionID.
   387  func (h *DIDCommMessageMiddleware) RotateConnectionDID(connectionID, signingKID, newDID string) error { // nolint:funlen
   388  	record, err := h.connStore.GetConnectionRecord(connectionID)
   389  	if err != nil {
   390  		return fmt.Errorf("getting connection record: %w", err)
   391  	}
   392  
   393  	// TODO: known issue: if you perform multiple DID rotations without sending a message to the other party,
   394  	//  they won't be able to validate the rotation.
   395  
   396  	oldDID := record.MyDID
   397  
   398  	oldDocRes, err := h.vdr.Resolve(oldDID)
   399  	if err != nil {
   400  		return fmt.Errorf("resolving my DID: %w", err)
   401  	}
   402  
   403  	fromPrior, err := h.Create(oldDocRes.DIDDocument, signingKID, newDID)
   404  	if err != nil {
   405  		return fmt.Errorf("creating did rotation from_prior: %w", err)
   406  	}
   407  
   408  	record.MyDIDRotation = &connection.DIDRotationRecord{
   409  		NewDID:    newDID,
   410  		OldDID:    oldDID,
   411  		FromPrior: fromPrior,
   412  	}
   413  
   414  	// if newDID is a peer DID, we need to provide initialState to the recipient.
   415  	didParsed, err := did.Parse(newDID)
   416  	if err != nil {
   417  		return fmt.Errorf("parsing new DID: %w", err)
   418  	}
   419  
   420  	if didParsed.Method == peer.DIDMethod {
   421  		newDoc, e := h.vdr.Resolve(newDID)
   422  		if e != nil {
   423  			return fmt.Errorf("resolving new DID: %w", e)
   424  		}
   425  
   426  		initialState, e := peer.UnsignedGenesisDelta(newDoc.DIDDocument)
   427  		if e != nil {
   428  			return fmt.Errorf("generating peer DID initialState for new DID: %w", e)
   429  		}
   430  
   431  		record.PeerDIDInitialState = initialState
   432  	}
   433  
   434  	record.MyDID = newDID
   435  
   436  	err = h.connStore.SaveConnectionRecord(record)
   437  	if err != nil {
   438  		return fmt.Errorf("saving connection record under my new DID: %w", err)
   439  	}
   440  
   441  	// save a backup record under our old DID
   442  	record.MyDID = oldDID
   443  	record.ConnectionID = uuid.New().String()
   444  
   445  	err = h.connStore.SaveConnectionRecord(record)
   446  	if err != nil {
   447  		return fmt.Errorf("saving connection record under my old DID: %w", err)
   448  	}
   449  
   450  	return nil
   451  }
   452  
   453  // Create creates a didcomm/v2 DID rotation `from_prior`, as a compact-serialized JWS.
   454  func (h *DIDCommMessageMiddleware) Create(oldDoc *did.Doc, oldKID, newDID string) (string, error) {
   455  	payload := rotatePayload{
   456  		Sub: newDID,
   457  		ISS: oldDoc.ID,
   458  		IAT: time.Now().Unix(),
   459  	}
   460  
   461  	payloadBytes, err := json.Marshal(payload)
   462  	if err != nil {
   463  		return "", fmt.Errorf("marshalling did rotate payload: %w", err)
   464  	}
   465  
   466  	vm, found := did.LookupPublicKey(oldKID, oldDoc)
   467  	if !found {
   468  		return "", fmt.Errorf("sender KID not found in doc provided")
   469  	}
   470  
   471  	keyBytes, kty, crv, err := vmparse.VMToBytesTypeCrv(vm)
   472  	if err != nil {
   473  		return "", err
   474  	}
   475  
   476  	kmsKID, err := jwkkid.CreateKID(keyBytes, kty)
   477  	if err != nil {
   478  		return "", fmt.Errorf("get signing key KMS KID: %w", err)
   479  	}
   480  
   481  	kh, err := h.kms.Get(kmsKID)
   482  	if err != nil {
   483  		return "", fmt.Errorf("get signing key handle: %w", err)
   484  	}
   485  
   486  	var alg string
   487  
   488  	if vm.Type == ed25519VerificationKey2018 {
   489  		alg = "EdDSA"
   490  	} else if vm.Type == jsonWebKey2020 {
   491  		jwkKey := vm.JSONWebKey()
   492  		alg = jwkKey.Algorithm
   493  	}
   494  
   495  	protected := jose.Headers(map[string]interface{}{
   496  		"typ": "JWT",
   497  		"alg": alg,
   498  		"crv": crv,
   499  		"kid": oldKID,
   500  	})
   501  
   502  	jws, err := jose.NewJWS(protected, nil, payloadBytes, &cryptoSigner{kh: kh, crypto: h.crypto})
   503  	if err != nil {
   504  		return "", fmt.Errorf("creating DID rotation JWS: %w", err)
   505  	}
   506  
   507  	return jws.SerializeCompact(false)
   508  }
   509  
   510  func (h *DIDCommMessageMiddleware) getUnverifiedJWS(senderDID, fromPrior string,
   511  ) (*jose.JSONWebSignature, *rotatePayload, error) {
   512  	skipVerify := jose.SignatureVerifierFunc(func(_ jose.Headers, _, _, _ []byte) error {
   513  		return nil
   514  	})
   515  
   516  	jws, err := jose.ParseJWS(fromPrior, skipVerify)
   517  	if err != nil {
   518  		return nil, nil, fmt.Errorf("parsing DID rotation JWS: %w", err)
   519  	}
   520  
   521  	payload := rotatePayload{}
   522  
   523  	err = json.Unmarshal(jws.Payload, &payload)
   524  	if err != nil {
   525  		return nil, nil, fmt.Errorf("parsing DID rotation payload: %w", err)
   526  	}
   527  
   528  	if payload.ISS == "" || payload.Sub == "" {
   529  		return nil, nil, fmt.Errorf("from_prior payload missing iss or sub, both are required")
   530  	}
   531  
   532  	if senderDID != payload.Sub {
   533  		return nil, nil, fmt.Errorf("from_prior payload sub must be the DID of the message sender")
   534  	}
   535  
   536  	return jws, &payload, nil
   537  }
   538  
   539  // Verify verifies a didcomm/v2 DID rotation.
   540  //   - senderDID: the DID of the sender of the message containing this DID Rotation, known from the envelope
   541  //     or from the message's `to` field.
   542  //   - fromPrior: the `from_prior` field of the rotated message.
   543  //
   544  // Returns the sender's old DID (superseded by the new DID), if verification succeeds, or an error otherwise.
   545  func (h *DIDCommMessageMiddleware) Verify(senderDID, fromPrior string) (string, error) {
   546  	jws, payload, err := h.getUnverifiedJWS(senderDID, fromPrior)
   547  	if err != nil {
   548  		return "", err
   549  	}
   550  
   551  	err = h.verifyJWSAndPayload(jws, payload)
   552  	if err != nil {
   553  		return "", err
   554  	}
   555  
   556  	return payload.ISS, nil
   557  }
   558  
   559  func (h *DIDCommMessageMiddleware) verifyJWSAndPayload(jws *jose.JSONWebSignature, payload *rotatePayload) error {
   560  	oldKID, ok := jws.ProtectedHeaders.KeyID()
   561  	if !ok {
   562  		return fmt.Errorf("from_prior protected headers missing KID")
   563  	}
   564  
   565  	oldDocRes, err := h.vdr.Resolve(payload.ISS)
   566  	if err != nil {
   567  		return fmt.Errorf("resolving prior DID doc: %w", err)
   568  	}
   569  
   570  	vm, found := did.LookupPublicKey(oldKID, oldDocRes.DIDDocument)
   571  	if !found {
   572  		return fmt.Errorf("kid not found in doc")
   573  	}
   574  
   575  	keyBytes, kty, _, err := vmparse.VMToBytesTypeCrv(vm)
   576  	if err != nil {
   577  		return err
   578  	}
   579  
   580  	pubKH, err := h.kms.PubKeyBytesToHandle(keyBytes, kty)
   581  	if err != nil {
   582  		return fmt.Errorf("get verification key handle: %w", err)
   583  	}
   584  
   585  	verify := jose.DefaultSigningInputVerifier(
   586  		func(joseHeaders jose.Headers, payload, signingInput, signature []byte) error {
   587  			return h.crypto.Verify(signature, signingInput, pubKH)
   588  		})
   589  
   590  	err = verify.Verify(jws.ProtectedHeaders, jws.Payload, nil, jws.Signature())
   591  	if err != nil {
   592  		return fmt.Errorf("signature verification: %w", err)
   593  	}
   594  
   595  	return nil
   596  }
   597  
   598  type cryptoSigner struct {
   599  	kh     interface{}
   600  	crypto crypto.Crypto
   601  }
   602  
   603  // Sign signs the input using the stored key handle.
   604  func (c *cryptoSigner) Sign(data []byte) ([]byte, error) {
   605  	return c.crypto.Sign(data, c.kh)
   606  }
   607  
   608  // Headers returns nil, cryptoSigner doesn't add its own headers.
   609  func (c *cryptoSigner) Headers() jose.Headers {
   610  	return nil
   611  }
   612  
   613  const (
   614  	jsonWebKey2020             = "JsonWebKey2020"
   615  	ed25519VerificationKey2018 = "Ed25519VerificationKey2018"
   616  )