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

     1  /*
     2  Copyright SecureKey Technologies Inc. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package peerdid
     8  
     9  import (
    10  	"encoding/json"
    11  	"fmt"
    12  
    13  	gojose "github.com/go-jose/go-jose/v3"
    14  
    15  	"github.com/hyperledger/aries-framework-go/pkg/crypto"
    16  	"github.com/hyperledger/aries-framework-go/pkg/doc/did"
    17  	"github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk"
    18  	"github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk/jwksupport"
    19  	vdrapi "github.com/hyperledger/aries-framework-go/pkg/framework/aries/api/vdr"
    20  	"github.com/hyperledger/aries-framework-go/pkg/kms"
    21  	"github.com/hyperledger/aries-framework-go/pkg/vdr/peer"
    22  )
    23  
    24  const (
    25  	ed25519VerificationKey2018 = "Ed25519VerificationKey2018"
    26  	bls12381G2Key2020          = "Bls12381G2Key2020"
    27  	x25519KeyAgreementKey2019  = "X25519KeyAgreementKey2019"
    28  	jsonWebKey2020             = "JsonWebKey2020"
    29  )
    30  
    31  // Creator implements the Out-Of-Band V2 protocol.
    32  type Creator struct {
    33  	vdrRegistry      vdrapi.Registry
    34  	kms              kms.KeyManager
    35  	keyType          kms.KeyType
    36  	keyAgreementType kms.KeyType
    37  }
    38  
    39  // Provider provides this service's dependencies.
    40  type Provider interface {
    41  	VDRegistry() vdrapi.Registry
    42  	KMS() kms.KeyManager
    43  	KeyType() kms.KeyType
    44  	KeyAgreementType() kms.KeyType
    45  }
    46  
    47  // New creates a new instance of the out-of-band service.
    48  func New(p Provider) *Creator {
    49  	return &Creator{
    50  		vdrRegistry:      p.VDRegistry(),
    51  		kms:              p.KMS(),
    52  		keyType:          p.KeyType(),
    53  		keyAgreementType: p.KeyAgreementType(),
    54  	}
    55  }
    56  
    57  // CreatePeerDIDV2 create a peer DID suitable for use in DIDComm V2.
    58  func (s *Creator) CreatePeerDIDV2() (*did.Doc, error) {
    59  	// TODO: add routing keys so edge agents can rotate (currently only cloud agents do)
    60  	newDID := &did.Doc{Service: []did.Service{{Type: vdrapi.DIDCommV2ServiceType}}}
    61  
    62  	err := s.createNewKeyAndVM(newDID)
    63  	if err != nil {
    64  		return nil, fmt.Errorf("creating new keys and VMS for DID document failed: %w", err)
    65  	}
    66  
    67  	// set KeyAgreement.ID as RecipientKeys as part of DIDComm V2 service
    68  	newDID.Service[0].RecipientKeys = []string{newDID.KeyAgreement[0].VerificationMethod.ID}
    69  
    70  	myDID, err := s.vdrRegistry.Create(peer.DIDMethod, newDID)
    71  	if err != nil {
    72  		return nil, fmt.Errorf("creating new peer DID via VDR failed: %w", err)
    73  	}
    74  
    75  	return myDID.DIDDocument, nil
    76  }
    77  
    78  func (s *Creator) createNewKeyAndVM(didDoc *did.Doc) error {
    79  	vm, err := s.createSigningVM()
    80  	if err != nil {
    81  		return err
    82  	}
    83  
    84  	kaVM, err := s.createEncryptionVM()
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	didDoc.VerificationMethod = append(didDoc.VerificationMethod, *vm)
    90  
    91  	didDoc.Authentication = append(didDoc.Authentication, *did.NewReferencedVerification(vm, did.Authentication))
    92  	didDoc.KeyAgreement = append(didDoc.KeyAgreement, *did.NewReferencedVerification(kaVM, did.KeyAgreement))
    93  
    94  	return nil
    95  }
    96  
    97  // nolint:gochecknoglobals
    98  var vmTypeMap = map[kms.KeyType]string{
    99  	kms.ED25519Type:            ed25519VerificationKey2018,
   100  	kms.BLS12381G2Type:         bls12381G2Key2020,
   101  	kms.ECDSAP256TypeDER:       jsonWebKey2020,
   102  	kms.ECDSAP256TypeIEEEP1363: jsonWebKey2020,
   103  	kms.ECDSAP384TypeDER:       jsonWebKey2020,
   104  	kms.ECDSAP384TypeIEEEP1363: jsonWebKey2020,
   105  	kms.ECDSAP521TypeDER:       jsonWebKey2020,
   106  	kms.ECDSAP521TypeIEEEP1363: jsonWebKey2020,
   107  	kms.X25519ECDHKWType:       x25519KeyAgreementKey2019,
   108  	kms.NISTP256ECDHKWType:     jsonWebKey2020,
   109  	kms.NISTP384ECDHKWType:     jsonWebKey2020,
   110  	kms.NISTP521ECDHKWType:     jsonWebKey2020,
   111  }
   112  
   113  func getVerMethodType(kt kms.KeyType) string {
   114  	return vmTypeMap[kt]
   115  }
   116  
   117  func (s *Creator) createSigningVM() (*did.VerificationMethod, error) {
   118  	vmType := getVerMethodType(s.keyType)
   119  
   120  	_, pubKeyBytes, err := s.kms.CreateAndExportPubKeyBytes(s.keyType)
   121  	if err != nil {
   122  		return nil, fmt.Errorf("createSigningVM: %w", err)
   123  	}
   124  
   125  	vmID := "#key-1"
   126  
   127  	switch vmType {
   128  	case ed25519VerificationKey2018, bls12381G2Key2020:
   129  		return did.NewVerificationMethodFromBytes(vmID, vmType, "", pubKeyBytes), nil
   130  	case jsonWebKey2020:
   131  		j, err := jwksupport.PubKeyBytesToJWK(pubKeyBytes, s.keyType)
   132  		if err != nil {
   133  			return nil, fmt.Errorf("createSigningVM: failed to convert public key to JWK for VM: %w", err)
   134  		}
   135  
   136  		return did.NewVerificationMethodFromJWK(vmID, vmType, "", j)
   137  	default:
   138  		return nil, fmt.Errorf("createSigningVM: unsupported verification method: '%s'", vmType)
   139  	}
   140  }
   141  
   142  func (s *Creator) createEncryptionVM() (*did.VerificationMethod, error) {
   143  	encKeyType := s.keyAgreementType
   144  
   145  	vmType := getVerMethodType(encKeyType)
   146  
   147  	_, kaPubKeyBytes, err := s.kms.CreateAndExportPubKeyBytes(encKeyType)
   148  	if err != nil {
   149  		return nil, fmt.Errorf("createEncryptionVM: %w", err)
   150  	}
   151  
   152  	vmID := "#key-2"
   153  
   154  	switch vmType {
   155  	case x25519KeyAgreementKey2019:
   156  		key := &crypto.PublicKey{}
   157  
   158  		err = json.Unmarshal(kaPubKeyBytes, key)
   159  		if err != nil {
   160  			return nil, fmt.Errorf("createEncryptionVM: unable to unmarshal X25519 key: %w", err)
   161  		}
   162  
   163  		return did.NewVerificationMethodFromBytes(vmID, vmType, "", key.X), nil
   164  	case jsonWebKey2020:
   165  		j, err := buildJWKFromBytes(kaPubKeyBytes)
   166  		if err != nil {
   167  			return nil, fmt.Errorf("createEncryptionVM: %w", err)
   168  		}
   169  
   170  		vm, err := did.NewVerificationMethodFromJWK(vmID, vmType, "", j)
   171  		if err != nil {
   172  			return nil, fmt.Errorf("createEncryptionVM: %w", err)
   173  		}
   174  
   175  		return vm, nil
   176  	default:
   177  		return nil, fmt.Errorf("unsupported verification method for KeyAgreement: '%s'", vmType)
   178  	}
   179  }
   180  
   181  func buildJWKFromBytes(pubKeyBytes []byte) (*jwk.JWK, error) {
   182  	pubKey := &crypto.PublicKey{}
   183  
   184  	err := json.Unmarshal(pubKeyBytes, pubKey)
   185  	if err != nil {
   186  		return nil, fmt.Errorf("failed to unmarshal JWK for KeyAgreement: %w", err)
   187  	}
   188  
   189  	var j *jwk.JWK
   190  
   191  	switch pubKey.Type {
   192  	case "EC":
   193  		ecKey, err := crypto.ToECKey(pubKey)
   194  		if err != nil {
   195  			return nil, err
   196  		}
   197  
   198  		j = &jwk.JWK{
   199  			JSONWebKey: gojose.JSONWebKey{
   200  				Key:   ecKey,
   201  				KeyID: pubKey.KID,
   202  			},
   203  			Kty: pubKey.Type,
   204  			Crv: pubKey.Curve,
   205  		}
   206  	case "OKP":
   207  		j = &jwk.JWK{
   208  			JSONWebKey: gojose.JSONWebKey{
   209  				Key:   pubKey.X,
   210  				KeyID: pubKey.KID,
   211  			},
   212  			Kty: pubKey.Type,
   213  			Crv: pubKey.Curve,
   214  		}
   215  	}
   216  
   217  	return j, nil
   218  }