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 }