github.com/trustbloc/kms-go@v1.1.2/doc/jose/jwk/jwksupport/jwk.go (about) 1 /* 2 Copyright SecureKey Technologies Inc. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package jwksupport 8 9 import ( 10 "crypto/ecdsa" 11 "crypto/ed25519" 12 "crypto/elliptic" 13 "crypto/rsa" 14 "crypto/x509" 15 "crypto/x509/pkix" 16 "encoding/asn1" 17 "encoding/json" 18 "errors" 19 "fmt" 20 "math/big" 21 22 "github.com/btcsuite/btcd/btcec/v2" 23 "github.com/go-jose/go-jose/v3" 24 "github.com/trustbloc/bbs-signature-go/bbs12381g2pub" 25 26 "github.com/trustbloc/kms-go/doc/jose/jwk" 27 cryptoapi "github.com/trustbloc/kms-go/spi/crypto" 28 "github.com/trustbloc/kms-go/spi/kms" 29 ) 30 31 const ( 32 ecKty = "EC" 33 okpKty = "OKP" 34 x25519Crv = "X25519" 35 bls12381G2Crv = "BLS12381_G2" 36 bls12381G2Size = 96 37 ) 38 39 // JWKFromKey creates a JWK from an opaque key struct. 40 // It's e.g. *ecdsa.PublicKey, *ecdsa.PrivateKey, ed25519.VerificationMethod, *bbs12381g2pub.PrivateKey or 41 // *bbs12381g2pub.PublicKey. 42 func JWKFromKey(opaqueKey interface{}) (*jwk.JWK, error) { 43 key := &jwk.JWK{ 44 JSONWebKey: jose.JSONWebKey{ 45 Key: opaqueKey, 46 }, 47 } 48 49 // marshal/unmarshal to get all JWK's fields other than Key filled. 50 keyBytes, err := key.MarshalJSON() 51 if err != nil { 52 return nil, fmt.Errorf("create JWK: %w", err) 53 } 54 55 err = key.UnmarshalJSON(keyBytes) 56 if err != nil { 57 return nil, fmt.Errorf("create JWK: %w", err) 58 } 59 60 return key, nil 61 } 62 63 // PubKeyBytesToKey creates an opaque key struct from the given public key bytes. 64 // It's e.g. *ecdsa.PublicKey, *ecdsa.PrivateKey, ed25519.VerificationMethod, *bbs12381g2pub.PrivateKey or 65 // *bbs12381g2pub.PublicKey. 66 func PubKeyBytesToKey(bytes []byte, keyType kms.KeyType) (interface{}, error) { // nolint:gocyclo,funlen 67 switch keyType { 68 case kms.ED25519Type: 69 return ed25519.PublicKey(bytes), nil 70 case kms.X25519ECDHKWType: 71 return bytes, nil 72 case kms.BLS12381G2Type: 73 return bbs12381g2pub.UnmarshalPublicKey(bytes) 74 case kms.ECDSAP256TypeIEEEP1363, kms.ECDSAP384TypeIEEEP1363, kms.ECDSAP521TypeIEEEP1363: 75 crv := getECDSACurve(keyType) 76 x, y := elliptic.Unmarshal(crv, bytes) 77 78 return &ecdsa.PublicKey{ 79 Curve: crv, 80 X: x, 81 Y: y, 82 }, nil 83 case kms.ECDSASecp256k1TypeIEEEP1363: 84 pubKey, err := btcec.ParsePubKey(bytes) 85 if err != nil { 86 return nil, fmt.Errorf("failed to parse ecdsa secp 256k1 in IEEEP1363 format: %w", err) 87 } 88 89 return pubKey.ToECDSA(), nil 90 91 case kms.ECDSAP256TypeDER, kms.ECDSAP384TypeDER, kms.ECDSAP521TypeDER: 92 pubKey, err := x509.ParsePKIXPublicKey(bytes) 93 if err != nil { 94 return nil, fmt.Errorf("failed to parse ecdsa key in DER format: %w", err) 95 } 96 97 ecKey, ok := pubKey.(*ecdsa.PublicKey) 98 if !ok { 99 return nil, errors.New("invalid EC key") 100 } 101 102 return ecKey, nil 103 case kms.RSARS256, kms.RSAPS256: 104 pubKeyRsa, err := x509.ParsePKIXPublicKey(bytes) 105 if err != nil { 106 return nil, errors.New("rsa: invalid public key") 107 } 108 109 return pubKeyRsa, nil 110 case kms.ECDSASecp256k1TypeDER: 111 return parseSecp256k1DER(bytes) 112 case kms.NISTP256ECDHKWType, kms.NISTP384ECDHKWType, kms.NISTP521ECDHKWType: 113 crv := getECDSACurve(keyType) 114 pubKey := &cryptoapi.PublicKey{} 115 116 err := json.Unmarshal(bytes, pubKey) 117 if err != nil { 118 return nil, err 119 } 120 121 ecdsaKey := &ecdsa.PublicKey{ 122 Curve: crv, 123 X: new(big.Int).SetBytes(pubKey.X), 124 Y: new(big.Int).SetBytes(pubKey.Y), 125 } 126 127 return ecdsaKey, nil 128 default: 129 return nil, fmt.Errorf("invalid key type: %s", keyType) 130 } 131 } 132 133 // JWKFromX25519Key is similar to JWKFromKey but is specific to X25519 keys when using a public key as raw []byte. 134 // This builder function presets the curve and key type in the JWK. 135 // Using JWKFromKey for X25519 raw keys will not have these fields set and will not provide the right JWK output. 136 func JWKFromX25519Key(pubKey []byte) (*jwk.JWK, error) { 137 key := &jwk.JWK{ 138 JSONWebKey: jose.JSONWebKey{ 139 Key: pubKey, 140 }, 141 Crv: x25519Crv, 142 Kty: okpKty, 143 } 144 145 // marshal/unmarshal to get all JWK's fields other than Key filled. 146 keyBytes, err := key.MarshalJSON() 147 if err != nil { 148 return nil, fmt.Errorf("create JWK: %w", err) 149 } 150 151 err = key.UnmarshalJSON(keyBytes) 152 if err != nil { 153 return nil, fmt.Errorf("create JWK: %w", err) 154 } 155 156 return key, nil 157 } 158 159 // PubKeyBytesToJWK converts marshalled bytes of keyType into JWK. 160 func PubKeyBytesToJWK(bytes []byte, keyType kms.KeyType) (*jwk.JWK, error) { 161 switch keyType { 162 case kms.ED25519Type: 163 return &jwk.JWK{ 164 JSONWebKey: jose.JSONWebKey{ 165 Key: ed25519.PublicKey(bytes), 166 }, 167 Kty: "OKP", 168 Crv: "Ed25519", 169 }, nil 170 case kms.X25519ECDHKWType: 171 return JWKFromX25519Key(bytes) 172 case kms.BLS12381G2Type, 173 kms.ECDSASecp256k1TypeIEEEP1363, kms.ECDSASecp256k1TypeDER, 174 kms.ECDSAP256TypeIEEEP1363, kms.ECDSAP384TypeIEEEP1363, kms.ECDSAP521TypeIEEEP1363, 175 kms.ECDSAP256TypeDER, kms.ECDSAP384TypeDER, kms.ECDSAP521TypeDER, 176 kms.NISTP256ECDHKWType, kms.NISTP384ECDHKWType, kms.NISTP521ECDHKWType, 177 kms.RSARS256, kms.RSAPS256: 178 key, err := PubKeyBytesToKey(bytes, keyType) 179 if err != nil { 180 return nil, err 181 } 182 183 return JWKFromKey(key) 184 default: 185 return nil, fmt.Errorf("convertPubKeyJWK: invalid key type: %s", keyType) 186 } 187 } 188 189 func getECDSACurve(keyType kms.KeyType) elliptic.Curve { 190 switch keyType { 191 case kms.ECDSAP256TypeIEEEP1363, kms.ECDSAP256TypeDER, kms.NISTP256ECDHKWType: 192 return elliptic.P256() 193 case kms.ECDSAP384TypeIEEEP1363, kms.ECDSAP384TypeDER, kms.NISTP384ECDHKWType: 194 return elliptic.P384() 195 case kms.ECDSAP521TypeIEEEP1363, kms.ECDSAP521TypeDER, kms.NISTP521ECDHKWType: 196 return elliptic.P521() 197 case kms.ECDSASecp256k1TypeIEEEP1363, kms.ECDSASecp256k1TypeDER: 198 return btcec.S256() 199 } 200 201 return nil 202 } 203 204 type publicKeyInfo struct { 205 Raw asn1.RawContent 206 Algorithm pkix.AlgorithmIdentifier 207 PublicKey asn1.BitString 208 } 209 210 func parseSecp256k1DER(keyBytes []byte) (*ecdsa.PublicKey, error) { 211 var ( 212 pki publicKeyInfo 213 rest []byte 214 err error 215 pubKey *btcec.PublicKey 216 ) 217 218 if rest, err = asn1.Unmarshal(keyBytes, &pki); err != nil { 219 return nil, err 220 } else if len(rest) != 0 { 221 return nil, fmt.Errorf("x509: trailing data after ASN.1 of public-key") 222 } 223 224 pubKey, err = btcec.ParsePubKey(pki.PublicKey.RightAlign()) 225 if err != nil { 226 return nil, err 227 } 228 229 return pubKey.ToECDSA(), nil 230 } 231 232 // PublicKeyFromJWK builds a cryptoapi.PublicKey from jwkKey. 233 func PublicKeyFromJWK(jwkKey *jwk.JWK) (*cryptoapi.PublicKey, error) { 234 if jwkKey != nil { 235 pubKey := &cryptoapi.PublicKey{ 236 KID: jwkKey.KeyID, 237 Curve: jwkKey.Crv, 238 Type: jwkKey.Kty, 239 } 240 241 switch key := jwkKey.Key.(type) { 242 case *ecdsa.PublicKey: 243 pubKey.X = key.X.Bytes() 244 pubKey.Y = key.Y.Bytes() 245 case *ecdsa.PrivateKey: 246 pubKey.X = key.X.Bytes() 247 pubKey.Y = key.Y.Bytes() 248 case *bbs12381g2pub.PublicKey: 249 bbsKey, _ := key.Marshal() //nolint:errcheck // bbs marshal public key does not return any error 250 251 pubKey.X = bbsKey 252 case *bbs12381g2pub.PrivateKey: 253 bbsKey, _ := key.PublicKey().Marshal() //nolint:errcheck // bbs marshal public key does not return any error 254 255 pubKey.X = bbsKey 256 case ed25519.PublicKey: 257 pubKey.X = key 258 case *rsa.PublicKey: 259 pubKey.N = key.N.Bytes() 260 pubKey.E = big.NewInt(int64(key.E)).Bytes() 261 case ed25519.PrivateKey: 262 var ok bool 263 264 pubEdKey, ok := key.Public().(ed25519.PublicKey) 265 if !ok { 266 return nil, errors.New("publicKeyFromJWK: invalid 25519 private key") 267 } 268 269 pubKey.X = pubEdKey 270 default: 271 return nil, fmt.Errorf("publicKeyFromJWK: unsupported jwk key type %T", jwkKey.Key) 272 } 273 274 return pubKey, nil 275 } 276 277 return nil, errors.New("publicKeyFromJWK: jwk is empty") 278 }