Forum Discussion
F5 iRule Example integrating HMAC
Hi Dtwesten,
I found some time to code the mentioned TMM cache. I've already compared the performance of my previously posted v10.x iRule, with the new version containing the TMM cache with added garbage collection and some other little performance optimization. Here are the results...
Old iRule: (without TMM caching)
-----------------------------------------------
Ltm::Rule Event: iRule_HMAC_VERIFY:HTTP_REQUEST
-----------------------------------------------
Priority 500
Executions
Total 1.0K
Failures 0
Aborts 0
CPU Cycles on Executing
Average 456.2K
Maximum 584.0K
Minimum 325.8K
Optimized iRule: (with TMM caching)
-----------------------------------------------
Ltm::Rule Event: iRule_HMAC_VERIFY:HTTP_REQUEST
-----------------------------------------------
Priority 500
Executions
Total 1.0K
Failures 0
Aborts 0
CPU Cycles on Executing
Average 80.0K
Maximum 532.3K
Minimum 41.2K
Note: The result contains the TMM cache creation and initial fresh HMAC calculation.
The TMM cache is doing a pretty good job. The cache is able to increase the per-request HMAC verification throughput for ~570% or in other words it will reduce the required Avg. CPU cycles down to ~17,5%.
Let me know, if you're able to optimize the code even further, or if you find some unhandled exceptions. But I believe the new iRule is already somewhat save to use within production environments... 😉
Optimized v10.x Code
when RULE_INIT {
set static::tmm_cache_timestamp ""
set static::crypto_sign_key "12345678"
set static::genarate_hmac_token {
set bsize 64
if { [string length $static::crypto_sign_key] > $bsize } {
set key [sha256 $static::crypto_sign_key]
} else {
set key $static::crypto_sign_key
}
set ipad ""
set opad ""
for { set j 0 }{ $j < [string length $key] }{ incr j }{
binary scan $key @${j}H2 k
set o [expr 0x$k ^ 0x5c]
set i [expr 0x$k ^ 0x36]
append ipad [format %c $i]
append opad [format %c $o]
}
for { }{ $j < $bsize }{ incr j }{
append ipad 6
append opad \\
}
set token [sha256 $opad[sha256 "${ipad}$app_cookie:$cert_value"]]
binary scan $token H* hmac_output
}
}
when CLIENTSSL_HANDSHAKE {
if { [SSL::cert count] > 0 } then {
if { [set cert_value [X509::subject [SSL::cert 0]]] eq "" } then {
reject
}
} else {
reject
}
}
when HTTP_REQUEST {
if { ( [set app_cookie [HTTP::cookie value "ASP.NET_SessionId"]] ne "" ) and
( [set hmac_input [HTTP::cookie value "hmac_01"]] ne "" ) } then {
if { [catch {
if { [expr { [clock seconds] & 0xFFFFFF00 } ] eq $static::tmm_cache_timestamp } then {
if { $static::hmac_values($app_cookie:$cert_value) eq $hmac_input } then {
log -noname local0.debug "Request : Cached HMAC Verified"
} else {
log -noname local0.debug "Request : Cached HMAC not Verified"
HTTP::cookie remove "ASP.NET_SessionId"
}
} else {
log -noname local0.debug "Request : TMM Cache Bucket Recycling"
set static::tmm_cache_timestamp [expr { [clock seconds] & 0xFFFFFF00 } ]
unset -nocomplain static::hamc_values
Jumping to the [catch] exception
return
}
}]} then {
log local0.debug "Request : Generate fresh HMAC"
eval $static::genarate_hmac_token
if { $hmac_output eq $hmac_input } then {
log -noname local0.debug "Request : Fresh HMAC Verified"
set static::hmac_values($app_cookie:$cert_value) $hmac_output
} else {
log -noname local0.debug "Request : Fresh HMAC not Verified"
HTTP::cookie remove "ASP.NET_SessionId"
}
}
} else {
HTTP::cookie remove "ASP.NET_SessionId"
}
HTTP::cookie remove "hmac_01"
}
when HTTP_RESPONSE {
if { [set app_cookie [HTTP::cookie value "ASP.NET_SessionId"]] ne "" } then {
if { [catch {
HTTP::header insert "Set-Cookie" "hmac_01=$static::hmac_values($app_cookie:$cert_value); HttpOnly; Secure; Path=/"
log -noname local0.debug "Response : Cached HMAC cookie injected"
}]} then {
eval $static::genarate_hmac_token
set static::hmac_values($app_cookie:$cert_value) $hmac_output
HTTP::header insert "Set-Cookie" "hmac_01=$hmac_output; HttpOnly; Secure; Path=/"
log -noname local0.debug "Response : Fresh HMAC cookie injected"
}
}
}
Note: The bitmask of 0xFFFFFF00 (=256 seconds) defines the TMM cache garbage collection interval. When a garbage collection occurs, then the entire HMAC cache is getting flushed and recreated on demand on each TMM core independently.
Note: The HTTP_RESPONSE event is optimized for sites which are reapplying the cookie on every response. The code could be further optimized for those sites which are setting the cookie just once. The required change would be an [info exist] instead of [catch] syntax. But the difference would be marginal and only for this single response...
Cheers, Kai
Recent Discussions
Related Content
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com