github.com/hyperledger/aries-framework-go@v0.3.2/pkg/doc/util/kmsdidkey/kmsdidkey.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 Copyright Avast Software. All Rights Reserved. 4 5 SPDX-License-Identifier: Apache-2.0 6 */ 7 8 package kmsdidkey 9 10 import ( 11 "crypto/elliptic" 12 "encoding/json" 13 "fmt" 14 15 "github.com/btcsuite/btcutil/base58" 16 commonpb "github.com/google/tink/go/proto/common_go_proto" 17 18 cryptoapi "github.com/hyperledger/aries-framework-go/pkg/crypto" 19 "github.com/hyperledger/aries-framework-go/pkg/doc/util/jwkkid" 20 "github.com/hyperledger/aries-framework-go/pkg/kms" 21 "github.com/hyperledger/aries-framework-go/pkg/vdr/fingerprint" 22 didfingerprint "github.com/hyperledger/aries-framework-go/pkg/vdr/fingerprint/didfp" 23 ) 24 25 // keyTypeCodecs maps kms.KeyType to did:key codec. 26 // nolint: gochecknoglobals 27 var keyTypeCodecs = map[kms.KeyType]uint64{ 28 // signing keys 29 kms.ED25519Type: fingerprint.ED25519PubKeyMultiCodec, 30 kms.BLS12381G2Type: fingerprint.BLS12381g2PubKeyMultiCodec, 31 kms.ECDSAP256TypeIEEEP1363: fingerprint.P256PubKeyMultiCodec, 32 kms.ECDSAP256TypeDER: fingerprint.P256PubKeyMultiCodec, 33 kms.ECDSAP384TypeIEEEP1363: fingerprint.P384PubKeyMultiCodec, 34 kms.ECDSAP384TypeDER: fingerprint.P384PubKeyMultiCodec, 35 kms.ECDSAP521TypeIEEEP1363: fingerprint.P521PubKeyMultiCodec, 36 kms.ECDSAP521TypeDER: fingerprint.P521PubKeyMultiCodec, 37 38 // encryption keys 39 kms.X25519ECDHKWType: fingerprint.X25519PubKeyMultiCodec, 40 kms.NISTP256ECDHKWType: fingerprint.P256PubKeyMultiCodec, 41 kms.NISTP384ECDHKWType: fingerprint.P384PubKeyMultiCodec, 42 kms.NISTP521ECDHKWType: fingerprint.P521PubKeyMultiCodec, 43 } 44 45 // BuildDIDKeyByKeyType creates a did key for pubKeyBytes based on the kms keyType. 46 func BuildDIDKeyByKeyType(pubKeyBytes []byte, keyType kms.KeyType) (string, error) { 47 switch keyType { 48 case kms.X25519ECDHKW: 49 pubKey := &cryptoapi.PublicKey{} 50 51 err := json.Unmarshal(pubKeyBytes, pubKey) 52 if err != nil { 53 return "", fmt.Errorf("buildDIDkeyByKMSKeyType failed to unmarshal key type %v: %w", keyType, err) 54 } 55 56 pubKeyBytes = make([]byte, len(pubKey.X)) 57 copy(pubKeyBytes, pubKey.X) 58 case kms.NISTP256ECDHKWType, kms.NISTP384ECDHKWType, kms.NISTP521ECDHKWType: 59 pubKey := &cryptoapi.PublicKey{} 60 61 err := json.Unmarshal(pubKeyBytes, pubKey) 62 if err != nil { 63 return "", fmt.Errorf("buildDIDkeyByKMSKeyType failed to unmarshal key type %v: %w", keyType, err) 64 } 65 66 ecKey, err := cryptoapi.ToECKey(pubKey) 67 if err != nil { 68 return "", fmt.Errorf("buildDIDkeyByKMSKeyType failed to unmarshal key type %v: %w", keyType, err) 69 } 70 71 // used Compressed EC format for did:key, the same way as vdr key creator. 72 pubKeyBytes = elliptic.MarshalCompressed(ecKey.Curve, ecKey.X, ecKey.Y) 73 } 74 75 if codec, ok := keyTypeCodecs[keyType]; ok { 76 didKey, _ := fingerprint.CreateDIDKeyByCode(codec, pubKeyBytes) 77 78 return didKey, nil 79 } 80 81 return "", fmt.Errorf("keyType '%s' does not have a multi-base codec", keyType) 82 } 83 84 // EncryptionPubKeyFromDIDKey parses the did:key DID and returns the key's raw value. 85 // note: for NIST P ECDSA keys, the raw value does not have the compression point. 86 // In order to use elliptic.Unmarshal() with the raw value, the uncompressed point ([]byte{4}) must be prepended. 87 // see https://github.com/golang/go/blob/master/src/crypto/elliptic/elliptic.go#L384. 88 //nolint:funlen,gocyclo 89 func EncryptionPubKeyFromDIDKey(didKey string) (*cryptoapi.PublicKey, error) { 90 pubKey, code, err := extractRawKey(didKey) 91 if err != nil { 92 return nil, fmt.Errorf("encryptionPubKeyFromDIDKey: %w", err) 93 } 94 95 var ( 96 crv string 97 kmtKT kms.KeyType 98 kt string 99 x []byte 100 y []byte 101 ) 102 103 switch code { 104 case fingerprint.ED25519PubKeyMultiCodec: // TODO remove this case when legacyPacker is decommissioned. 105 var edKID string 106 107 kmtKT = kms.ED25519Type 108 pubEDKey := &cryptoapi.PublicKey{ 109 X: pubKey, 110 Curve: "Ed25519", 111 Type: "OKP", 112 } 113 114 edKID, err = jwkkid.CreateKID(pubKey, kmtKT) 115 if err != nil { 116 return nil, fmt.Errorf("encryptionPubKeyFromDIDKey: %w", err) 117 } 118 119 pubEDKey.KID = edKID 120 121 return pubEDKey, nil 122 case fingerprint.X25519PubKeyMultiCodec: 123 var ( 124 mPubXKey []byte 125 xKID string 126 ) 127 128 kmtKT = kms.X25519ECDHKWType 129 pubXKey := &cryptoapi.PublicKey{ 130 X: pubKey, 131 Curve: "X25519", 132 Type: "OKP", 133 } 134 135 mPubXKey, err = json.Marshal(pubXKey) 136 if err != nil { 137 return nil, fmt.Errorf("encryptionPubKeyFromDIDKey: %w", err) 138 } 139 140 xKID, err = jwkkid.CreateKID(mPubXKey, kmtKT) 141 if err != nil { 142 return nil, fmt.Errorf("encryptionPubKeyFromDIDKey: %w", err) 143 } 144 145 pubXKey.KID = xKID 146 147 return pubXKey, nil 148 case fingerprint.P256PubKeyMultiCodec: 149 kmtKT = kms.ECDSAP256IEEEP1363 150 kt = "EC" 151 crv, x, y, pubKey = unmarshalECKey(elliptic.P256(), pubKey) 152 case fingerprint.P384PubKeyMultiCodec: 153 kmtKT = kms.ECDSAP384IEEEP1363 154 kt = "EC" 155 crv, x, y, pubKey = unmarshalECKey(elliptic.P384(), pubKey) 156 case fingerprint.P521PubKeyMultiCodec: 157 kmtKT = kms.ECDSAP521TypeIEEEP1363 158 kt = "EC" 159 crv, x, y, pubKey = unmarshalECKey(elliptic.P521(), pubKey) 160 default: 161 return nil, fmt.Errorf("encryptionPubKeyFromDIDKey: unsupported key multicodec code [0x%x]", code) 162 } 163 164 kid, err := jwkkid.CreateKID(pubKey, kmtKT) 165 if err != nil { 166 return nil, fmt.Errorf("encryptionPubKeyFromDIDKey: %w", err) 167 } 168 169 return &cryptoapi.PublicKey{ 170 KID: kid, 171 X: x, 172 Y: y, 173 Curve: crv, 174 Type: kt, 175 }, nil 176 } 177 178 func unmarshalECKey(ecCRV elliptic.Curve, pubKey []byte) (string, []byte, []byte, []byte) { 179 var ( 180 x []byte 181 y []byte 182 ) 183 184 ecCurves := map[elliptic.Curve]string{ 185 elliptic.P256(): commonpb.EllipticCurveType_NIST_P256.String(), 186 elliptic.P384(): commonpb.EllipticCurveType_NIST_P384.String(), 187 elliptic.P521(): commonpb.EllipticCurveType_NIST_P521.String(), 188 } 189 190 xBig, yBig := elliptic.UnmarshalCompressed(ecCRV, pubKey) 191 if xBig != nil && yBig != nil { 192 x = xBig.Bytes() 193 y = yBig.Bytes() 194 195 // need to marshal pubKey in uncompressed format for CreateKID() call in EncryptionPubKeyFromDIDKey above since 196 // did:key uses compressed elliptic format. 197 pubKey = elliptic.Marshal(ecCRV, xBig, yBig) 198 } else { // try normal Unmarshal if compressed returned nil xBig and yBig. 199 // add compression byte for uncompressed key, comment of fingerprint.PubKeyFromDIDKey(). 200 pubKey = append([]byte{4}, pubKey...) 201 xBig, yBig = elliptic.Unmarshal(ecCRV, pubKey) 202 203 x = xBig.Bytes() 204 y = yBig.Bytes() 205 } 206 207 return ecCurves[ecCRV], x, y, pubKey 208 } 209 210 func extractRawKey(didKey string) ([]byte, uint64, error) { 211 idMethodSpecificID, err := didfingerprint.MethodIDFromDIDKey(didKey) 212 if err != nil { 213 return nil, 0, fmt.Errorf("extractRawKey: MethodIDFromDIDKey failure: %w", err) 214 } 215 216 pubKey, code, err := fingerprint.PubKeyFromFingerprint(idMethodSpecificID) 217 if err != nil { 218 return nil, 0, fmt.Errorf("extractRawKey: PubKeyFromFingerprint failure: %w", err) 219 } 220 221 return pubKey, code, nil 222 } 223 224 // GetBase58PubKeyFromDIDKey parses the did:key DID and returns the key's base58 encoded value. 225 func GetBase58PubKeyFromDIDKey(didKey string) (string, error) { 226 key, err := EncryptionPubKeyFromDIDKey(didKey) 227 if err != nil { 228 return "", fmt.Errorf("GetBase58PubKeyFromDIDKey: failed to parse public key bytes from "+ 229 "%s: %w", didKey, err) 230 } 231 232 return base58.Encode(key.X), nil 233 }