Requiring an SSL Certificate for Parts of an Application

When building many enterprise web-based applications, security must be taken seriously. iRules provide powerful capabilities for influencing security decisions when processing for your web services and applications.

This is a rule for requiring a client certificate for certain parts of an application. The example below requires a certificate when the URL path is for a certain directory. Alternatively, a rule could be written to check the host name of file extension if that is more appropriate for your requirements.

Special Notes: this rule requires version 9.0.2 to operate correctly.
Log statements are commented out. For testing, they can be uncommented.

When the client connects, we set up variables to record two things - whether a certificate has been received and whether a certficate needs to be received. These variables start out with a value of zero, which means "false".

when CLIENT_ACCEPTED {
 set needcert 0
 set gotcert 0
}

When a client does an SSL handshake, this rule event is triggered. This is the time to validate that a certificate has been received. If a certificate has not been received, but we were expecting one ($needcert == 1), then the connection is rejected. If the certificate has been received, we note that for future reference (set gotcert 1) and we release the current request (HTTP::release) if we were waiting for a certificate before releasing the request.

when CLIENTSSL_HANDSHAKE {
# log LOCAL0.warn "cert count=[SSL::cert count] result=[SSL::verify_result]"
 if { [SSL::cert count] == 0 or [SSL::verify_result] != 0 } {
#  log LOCAL0.warn "Bad cert!"
   if { $needcert == 1 } {
    reject
  }
 }
  else {
#  log LOCAL0.warn "Good cert! ($needcert)"
   set gotcert 1
   if { $needcert == 1 } {
   HTTP::release
  }
 }
}

Here we process an HTTP request. If the request is for a directory that has been designated for extra security, then several things happen. We freeze the HTTP request until the client certificate is received, we tell SSL to require a certificate, we tell SSL to renegotiate now, and then we set a flag that indicates we need a certificate.

when HTTP_REQUEST {
 if { $gotcert == 0 and [HTTP::uri] starts_with "/needcert" } {
# log LOCAL0.warn "Requiring certificate..."
  HTTP::collect
  SSL::cert mode require
  SSL::renegotiate
  set needcert 1
 }
 else {
# log LOCAL0.warn "No cert needed."
 }
}

Questions about this iRule? Post them in the Technical Forum.

Updated Jan 26, 2023
Version 2.0
No CommentsBe the first to comment