github.com/futurehomeno/fimpgo@v1.14.0/transport/signed_msg.go (about) 1 package transport 2 3 import ( 4 "crypto" 5 "encoding/base64" 6 "errors" 7 "strings" 8 9 "github.com/golang-jwt/jwt" 10 11 "github.com/futurehomeno/fimpgo" 12 "github.com/futurehomeno/fimpgo/security" 13 ) 14 15 /* 16 https://tools.ietf.org/html/rfc7518#section-3 17 +--------------+-------------------------------+--------------------+ 18 | "alg" Param | Digital Signature or MAC | Implementation | 19 | Value | Algorithm | Requirements | 20 +--------------+-------------------------------+--------------------+ 21 | HS256 | HMAC using SHA-256 | Required | 22 | HS384 | HMAC using SHA-384 | Optional | 23 | HS512 | HMAC using SHA-512 | Optional | 24 | RS256 | RSASSA-PKCS1-v1_5 using | Recommended | 25 | | SHA-256 | | 26 | RS384 | RSASSA-PKCS1-v1_5 using | Optional | 27 | | SHA-384 | | 28 | RS512 | RSASSA-PKCS1-v1_5 using | Optional | 29 | | SHA-512 | | 30 | ES256 | ECDSA using P-256 and SHA-256 | Recommended+ | 31 | ES384 | ECDSA using P-384 and SHA-384 | Optional | 32 | ES512 | ECDSA using P-521 and SHA-512 | Optional | 33 | PS256 | RSASSA-PSS using SHA-256 and | Optional | 34 | | MGF1 with SHA-256 | | 35 | PS384 | RSASSA-PSS using SHA-384 and | Optional | 36 | | MGF1 with SHA-384 | | 37 | PS512 | RSASSA-PSS using SHA-512 and | Optional | 38 | | MGF1 with SHA-512 | | 39 | none | No digital signature or MAC | Optional | 40 | | performed | | 41 +--------------+-------------------------------+--------------------+ 42 */ 43 44 // Message encapsulation 45 // Message signing 46 // Plain fimp msg -> serialize into []binary -> generate signature -> base64 encode original message -> encapsulate into evt.transport.signed or cmd.transport.signed message -> add signature to props 47 // { 48 // "type": "evt.transport.signed", 49 // "serv": "sensor_presence", 50 // "val_t": "bin", 51 // "val": "ewogICJ0eXBlIjogImV2dC5wcmVzZW5jZS5yZXBvcnQiLAogICJzZXJ2IjogInNlbnNvcl9wcmVzZW5jZSIsCiAgInZhbF90IjogImJvb2wiLAogICJ2YWwiOiB0cnVlLAogICJ0YWdzIjogbnVsbCwKICAicHJvcHMiOiBudWxsLAogICJ2ZXIiOiAiMSIsCiAgImNvcmlkIjogIiIsCiAgImN0aW1lIjogIjIwMjAtMDUtMDZUMDk6Mjk6NTkuNTI3KzA1OjAwIiwKICAidWlkIjogIjczZjYxMDMwLTQzOTktNGQyMS1iYjk3LTRjYTdjMTYyM2FjMyIKfQ==", 52 // "tags": null, 53 // "props": { 54 // "user_id":"aleks@gmail.com", 55 // "device_id":"dafdsafsf", 56 // "sig":"<computed signature>", 57 // "alg":"ES256" 58 // }, 59 // "ver": "1", 60 // "corid": "", 61 // "ctime": "2020-05-06T09:29:59.527+05:00", 62 // "uid": "73f61030-4399-4d21-bb97-4ca7c1623ac3" 63 //} 64 65 // SignMessageES256 encapsulate original message into special transport message with added signature. 66 func SignMessageES256(payload *fimpgo.FimpMessage, requestMsg *fimpgo.FimpMessage, userId string, keys *security.EcdsaKey, props *fimpgo.Props) (*fimpgo.FimpMessage, error) { 67 serializedMsg, err := payload.SerializeToJson() 68 if err != nil { 69 return nil, err 70 } 71 if props == nil { 72 props = &fimpgo.Props{"user_id": userId} 73 } 74 msgType := "evt.transport.signed" 75 if strings.Contains(payload.Type, "cmd") { 76 msgType = "cmd.transport.signed" 77 } 78 signedMsg := fimpgo.NewBinaryMessage(msgType, payload.Service, serializedMsg, *props, nil, requestMsg) 79 80 signingMethodES256 := &jwt.SigningMethodECDSA{Name: "ES256", Hash: crypto.SHA256, KeySize: 32, CurveBits: 256} 81 signature, err := signingMethodES256.Sign(signedMsg.Value.(string), keys.PrivateKey()) 82 if err != nil { 83 return nil, err 84 } 85 signedMsg.Properties["sig"] = signature 86 return signedMsg, nil 87 } 88 89 func GetVerifiedMessageES256(signedMsg *fimpgo.FimpMessage, key *security.EcdsaKey) (*fimpgo.FimpMessage, error) { 90 91 if signedMsg.Type != "cmd.transport.signed" && signedMsg.Type != "evt.transport.signed" { 92 return nil, errors.New("incorrect message type") 93 } 94 origMsgBin, ok1 := signedMsg.Value.(string) 95 if !ok1 { 96 return nil, errors.New("incorrect encapsulated message format") 97 } 98 sig, ok2 := signedMsg.Properties["sig"] 99 if !ok2 { 100 return nil, errors.New("missing signature") 101 } 102 signingMethodES256 := &jwt.SigningMethodECDSA{Name: "ES256", Hash: crypto.SHA256, KeySize: 32, CurveBits: 256} 103 err := signingMethodES256.Verify(origMsgBin, sig, key.PublicKey()) 104 if err == nil { 105 decodedPayloadBin, err := base64.StdEncoding.DecodeString(origMsgBin) 106 if err != nil { 107 return nil, err 108 } 109 return fimpgo.NewMessageFromBytes(decodedPayloadBin) 110 } else { 111 return nil, err 112 } 113 }