Forum Discussion

quangtran's avatar
quangtran
Icon for Cirrus rankCirrus
Dec 21, 2022

use irule to digitally sign

Hello everyone, I have a request like this:

{

    "Data": "eyJVc2VyTmFtZSI6ImVjdXN0b21zIiwiUGdCJ9"

}

Here is the body when calling on F5.

Add Sign to call the server as follows:

{

    "Data": "eyJVc2VyTmFtZSI6ImVjdXN0b21zIiwiUGdCJ9",

    "Signature": {

        "Sign": {

            "Signature_Value": "B35uPWwF9ujq1zXbpsU3xFYPPI78nmqRagGG3p8yqVn+lDqNstTH3BewfA3SN8g=",

            "Key_Info": "iZPyLGQBGRYDRklTMREwDwYDVQQjETMBEGCgmSJomT8ixkARkWA0ZJUzERMA8GA1UEAxMIRUNVU1RPTVOCEEX/rIy8omGgS98InicxkpIwDQYJKoZIhvcNAQEEBQADgYEA"

        }

    }

}

- The algorithm is as follows

hash data with SHA256 then encrypt RSA with private key -> return 1 signature string + file cer (public key)

 

- I consulted from Kai_Wilke and write irule similar to this, but it doesn't work.

when RULE_INIT {
set static::max_payload_size "1048576" ;
set pub_key "NRLtULvKDtRjzevpNPz/BRDfTRKh9i
2n6rg+65jcOSeJb\nu7iqwKw6EWx1+7nUkiQqbJ2RXb
Ak/wYh4hIkS0stdJki\nlFLgce6uhmwHfsAUb1+s/OBnG
XcdxKMjWQd6b6Y2QZWttWYddcuS\n"
set pri_key "X7udSSJCpsnZFdv7CFqeqHPrUshldx
MdIzoCT/BiHiEiRLSy10mSKUUuODJvkh8toFfnacRja1c/
hMY319+Ax/cQXQR94/YGyz5qoK5S7Io8sCtyo0zf+IdLR
WpsUC6bJI8TezKMvtXnGUcWLVUESH777PPWurtuN2m
WKAw3i2XO/DXI6jdXIdccjEFkoxDb6mjpPL1ARat
uOXVc6yOnTXqA/+vS3nI+hOEQp6KtRD/D6Btv2GZ8W"
}
when HTTP_REQUEST {
if { ( [string tolower [HTTP::path]] equals "/api/xxxx/yyyy" )
and ( [HTTP::method] equals "POST")
and ( [HTTP::header value "Content-Length"] ne "" )
and ( [HTTP::header value "Content-Length"] < $static::max_payload_size ) } then {
HTTP::collect [HTTP::header value "Content-Length"]
}
}
when HTTP_REQUEST_DATA {
set temp(data) [HTTP::payload]
set temp(hash_data) [CRYPTO::hash -alg sha256 $temp(data) ]
set temp(enc_data) [CRYPTO::encrypt -alg RSA -key $pri_key $temp(hash_data) ]
set temp(new_payload) "[string trimright [HTTP::payload] "\}"],\"Signature_Value\":\"$temp(enc_data)\"\,\"Key_info\":\"$pub_key\"\}"
HTTP::payload replace 0 [HTTP::payload length] $temp(new_payload)
unset -nocomplain temp

}

What do I need to change here?

Any and all help is appreciated. Thanks you

 
  • Hi quangtran,

    I'm really not sure at this point about what's wrong, but I always find that some logging within iRules can help you in debugging what's happening.

    For instance, you can add a line like this:

    log local0. "encrypted data = $enc_data"

    ...after the CRYPTO::encrypt function, to make sure what has been calculated thus far in your iRule makes sense.

    With local0, the logs will be inserted in /var/log/ltm.

    If your VS is running on plain HTTP, a simple tcpdump will also help understand what's coming in and what's going out.

    /Mike

    • quangtran's avatar
      quangtran
      Icon for Cirrus rankCirrus

      Thanks Mike,   

      Thank you and really appreciate the feedback. 

  • Hi, I haven't tested but maybe is just below line

    set temp(enc_data) [CRYPTO::encrypt -alg rsa-priv -key $pri_key $temp(hash_data) ]

  • Hi Quangtran,

    > What do I need to change here?

    you will need to change those two things...

    1.) Your pub/pri key is stored in the RULE_INIT event in a global varibable. Those can't become accessed from the HTTP_REQUEST* events via $pri_key / $priv_key, you would need to prefix those global varibals to $::pri_key and $::pub_key, but this HIGHLY NOT recommended, since it would disable CMP-mode for the entire Virtual Server. Rename those variables to $static::pub_key and static::pri_key to make them accessible in the HTTP_REQUEST events without loosing CMP-mode is my recommendation.

    2.) You include the raw RSA encrypted data without applying any encodings to the message. This may break the JSON message syntax, if the RSA output contains non-escaped character used by JSON (e.g. " { } , ). Apply [b64encode $temp(enc_data)] before inserting it to the JSON message.

    Cheers, Kai

    • quangtran's avatar
      quangtran
      Icon for Cirrus rankCirrus

      my data was base64 encoded before sending, thanks for your suggestion. 

      can i extract the data with this command: 

      when HTTP_REQUEST_DATA {
      set temp(data) [findstr [HTTP::payload] "\"\Data\"\: 9 \"\ "]

      • Kai_Wilke's avatar
        Kai_Wilke
        Icon for MVP rankMVP

        The output of the CRYPTO::encrypt command is binary data and should be encoded before inserted in Json. Otherwise it may crash an ordinary Json parser on every N request... 

        Cheers, Kai