The External Command Certificate Validator allows validating issuance based on other certificate values after the certificate (or eventual pre-certificate) has been generated but not issued, stored and published.

Validator Types 

External Command Certificate Validator

The External Command Certificate Validator allows calling an external script for the generated certificate. The exit code of the external call determines if the validation has failed. This can be used not only to validate certificate criteria, but also to call other external commands or scripts. The user running EJBCA's application server requires the OS file system permissions to do so.

To be able to view and edit the External Script Validator, access to external scripts must be enabled by activating Enable External Script Access under System Configuration → External Scripts.

The first token of the External command field must be the external command or script called, followed by its arguments, all separated by spaces. The certificate is stored as a temporary file on the EJBCA server, and its full path is used as first argument. All subsequent arguments are shifted to the right. If the placeholder %cert% is used as an argument at any position, the certificate is not stored on the EJBCA server file system. Instead the placeholder is removed, and the PEM encoded certificate is fed to the external command or script via STDIN.

The platform for MS Windows and Unix/Linux is auto-detected and the default shell command and shell options are set:

  • MS Windows: cmd.exe /C
  • Unix/Linux: /bin/sh -c

The following displays examples of external commands for Unix/Linux platforms:

$ /usr/local/opt/script.sh -param1 -param2
$ /usr/local/opt/script.sh -param1 -param2 %cert%
$ openssl x509 -text -noout -in %cert%    
BASH

Script Allow Listing

An administrator can restrict which scrips can be executed for security reasons, by configuring an allow list on the System Configuration External scripts tab. The allow list should contain a list of paths to all scripts allowed to be executed by the External Command Certificate Validator. If the allow list is enabled by an administrator, any execution of scripts not explicitly listed on the allow list is prevented by EJBCA.

If the External Scripts Allow List has been enabled by an administrator and a Validator tries to execute a command which is not on the allow list, the "Validator was not applicable" action is carried out.

The allow list is formatted according to the following: Each line contains the full path of the allow listed script. Lines beginning with the character # are treated as comments. The allow list can contain any number of scripts. An empty (enabled) allow list will effectively block execution of all external scripts.

The following displays an example of a syntactically valid allow list:

# -----------------------------------------------------------------------
# This is an example, this configuration does not necessarily make sense
# -----------------------------------------------------------------------
/bin/echo
# X.509 Certificate Linter by Amazon 
# https://github.com/awslabs/certlint
/opt/certlint/certlint
/opt/certlint/cablint
# X.509 Certificate Linter based on CA/B Forum Baseline Requirements and RFC 5280 
# https://github.com/zmap/zlint
/opt/scripts/zLint.sh
#/opt/scripts/IAmDisabled.sh

This allow list allows the three scripts /opt/certlint/certlint, /opt/certlint/cablint, and /opt/scripts/zLint.sh to be executed. There is no restriction on the parameters which can be given as input to these scripts. Any input validation should be done in the script itself.

Example Certificate Lint

You can use the External Command Certificate Validator to run a lint check on issued certificates, and abort issuance if certificates don't pass the tests.

Preparations:

  1. First, to enable external scripts, select CA UI → System Configuration → External Scripts:
    • For Enable External Script Access, select Activate
    • In Configure Scripts Allow List, select Use the allow list below and specify a full path. For example /opt/bin/zlint.sh.
  2. To add an External Command Certificate Validator, go to Navigators:
    • In Validator Type, select External Command Certificate Validator.
    • In Full pathname of script, add the full path to the script ending with %cert%. For example /opt/bin/zlint.sh %cert%.
    • Ensure that at least the options Fail on script error code and Log error out are selected.

  3. To enable the validator for the CA, go to Certificate Authorities, click Edit and select the Validator for the CA.

Issue a certificate using a server certificate Certificate Profile. You can see the Validator being triggered in the server.log. To test failures, set Key Usage to Key certificate sign in the Certificate Profile used to issue the end entity certificate. This option is not allowed in the CAB Forum Baseline Requirements. For more information, see Key Usage in Certificate Profile Fields.

ZLint

ZLint is a X.509 certificate linter that can be downloaded and built from the ZLint homepage.

You must wrap zlint in a zlint.sh script to allow the script to return a 0 exit code on success, and 1 as exit code on failure.

Place the zlint.sh script in the same location as ZLint:

#!/bin/sh
mydir="$(dirname "$(realpath "$0")")"
OUTPUT=`$mydir/zlint -pretty <&0|grep -1 '"error"'`
#echo Output:\"$OUTPUT\"
if [ -z "$OUTPUT" ]; then
  echo "No error in zlint"
  exit 0
else
  echo "Error in zlint"
  echo $OUTPUT >&2
  exit 1
fi
CODE

Test by issuing certificate both with and without the Key Usage option set to Key certificate sign and view the log output in the server.log and the security audit log.

X509Lint

X509Lint is a certificate linter written in C, available for download on GitHub.

X509Lint expects the path to a PEM encoded certificate to be passed as first argument. Since EJBCA writes a DER-encoded certificate to disk, you need to parse the certificate to PEM before invoking the linter. We also need to parse the output to ensure EJBCA fails issuance if there is an error. The wrapper script below uses OpenSSL to convert the certificate to PEM and redirects any error messages to standard error.

Wrapper script for x509lint

#!/bin/sh
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# x509lint wrapper script for EJBCA.
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


# INSTRUCTIONS: Put this script (x509lint.sh) together
# with the x509lint binary in the directory ${BIN} and
# create a new External Command Certificate Validator
# in EJBCA with the following settings:

# Full pathname of script: ${BIN}/x509lint.sh
# Fail on script error code: true
# Fail on output to error out: true

# Issuance phase should be "Pre-certificate Validation"
# if CT is being used, and "Certificate Validation"
# otherwise.

mydir=$(dirname "$(realpath "$0")")
pem="/dev/shm/OpenSSL-$(date +%s%N).pem"
openssl x509 -in "$1" -inform DER -out "$pem" -outform PEM

if ! output=`$mydir/x509lint "$pem"`; then
  rm -f "$pem"
  exit 1
fi

rm -f "$pem"

fatals=$(   echo "$output" | grep 'F: ')
errors=$(   echo "$output" | grep 'E: ')
warnings=$( echo "$output" | grep 'W: ')
notices=$(  echo "$output" | grep 'N: ')
infos=$(    echo "$output" | grep 'I: ')
bugs=$(     echo "$output" | grep 'B: ')

if [ ! -z "$fatals" ]; then
  >&2 echo "$fatals"
fi
if [ ! -z "$errors" ]; then
  >&2 echo "$errors"
fi
if [ ! -z "$warnings" ]; then
  echo "$warnings"
fi
if [ ! -z "$notices" ]; then
  echo "$notices"
fi
if [ ! -z "$infos" ]; then 
  echo "$infos"
fi
if [ ! -z "$bugs" ]; then
  echo "$bugs"
fi
BASH

Debian Weak Key Checks

Due to an issue (CVE-2008-0166) from 2006 in OpenSSL, whereby a vulnerable version of the library only used the PID as seed when generating RSA or DSA keys, an attacker can find the private key from the corresponding public without much effort. The buggy version of OpenSSL was distributed in two Debian packages between the 17th of September 2006 and the 13th of May 2008.

The Debian project created block lists, which are unfortunately not available any longer:

HARICA has generously generated new lists of weak keys that can be used by the CA community.

The script below was written for the Debian packages, and likely needs to be adjusted for the HARICA keys.

You can check certificates against these block lists before issuance by extracting all the block lists and use a simple script to check for the presence of the key in one of them.

To check the certificates against the block lists, do the following:

  1. Extract the fingerprint block lists into a single directory, and rename the files from the packages in order to keep them all in a single directory on the CA server (the directory /opt/weak-keys in the following example script):

    blacklist-openssh.DSA-1024
    blacklist-openssh.DSA-2048
    blacklist-openssh.RSA-1024
    blacklist-openssh.RSA-2048
    blacklist-openssh.RSA-4096
    blacklist-openssl.RSA-512
    blacklist-openssl.RSA-1024
    blacklist-openssl.RSA-2048
    blacklist-openssl.RSA-4096
    blacklist-openvpn.RSA-2048
    CODE
  2. Add the following script to the directory as /opt/weak-keys/weak-key-check.sh (name and patch can be changed by editing the script to suit your environment).

    #!/bin/sh
    #echo $1
    OUTPUT=`grep $(openssl x509 -noout -pubkey -inform DER -in $1 \
        | openssl rsa -pubin -noout -modulus \
        | sha1sum | cut -d ' ' -f 1 | cut -c 21-) \
        /opt/weak-keys/all-lists/blacklist*`
    
    if [ -z "$OUTPUT" ]; then
      echo "Key is not in block list"
      exit 0
    else
      echo "Key is in block list"
      echo $OUTPUT >&2
      exit 1
    fi
    CODE
  3. In the External Command Validator, specify the following:

    1. Full pathname of script: /opt/weak-keys/weak-key-check.sh.
    2. Fail on script error code: true.
    3. Fail on output to error out: true.
    4. Issuance phase should be Pre-sign Certificate Validation to ensure that checks are done before the CAs private key is used.
    5. Save the Validator.
  4. It is not easy to find examples of weak keys, without generating them yourself. You can test the script by editing the validator again, uploading the following certificate downloaded from https://crt.sh/?id=2531502044 to Test Certificate Path and clicking Test Command.

    -----BEGIN CERTIFICATE-----
    MIIFzDCCA7SgAwIBAgIQB66bp3FYMWG3OiIbZKgNPzANBgkqhkiG9w0BAQsFADBp
    MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0b24x
    GDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjEeMBwGA1UEAwwVU1NMLmNvbSBSU0Eg
    U1NMIHN1YkNBMB4XDTIwMDMwNDAwMjczNVoXDTIwMDYwMjAwMjczNVowFzEVMBMG
    A1UEAwwMbGViZXJnZXIuYml6MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
    AQEA+TYH57WzTTfARNmo/Vx8/TGHD774iWbQoglRH+RGeFjgjoDGongoYr9jDwwX
    c1QxK36fojJ5zmDxIsvn/CsIRBj1aWCWvJons4LGfvEEmnZWuyhWleLKxmTvgbFb
    VMyLe+3fsuKjrktntuhpK75GXkpcErKS/3aGFY3UbMDp5qmGTZfZbXUAOTBq6Uvj
    6SyyeGrxrR+xRFAYCrB80ilLL2XlZ9hjqXge7qhhSxP5JYcVG4Fr8BvwhzoQ9zV1
    tdEuU6E+nZlvA6m4Qm4pQByCMMRH2BoqBL4n1aR1fNu+WdWHMC3uVmq2P5WZNsYK
    gdccVMmlHGVfRbhC1wuCty4QUwIDAQABo4IBwDCCAbwwHwYDVR0jBBgwFoAUJhR+
    4NzXpvfi1AQn32HxwuznMsowfAYIKwYBBQUHAQEEcDBuMEoGCCsGAQUFBzAChj5o
    dHRwOi8vd3d3LnNzbC5jb20vcmVwb3NpdG9yeS9TU0xjb20tU3ViQ0EtU1NMLVJT
    QS00MDk2LVIxLmNydDAgBggrBgEFBQcwAYYUaHR0cDovL29jc3BzLnNzbC5jb20w
    KQYDVR0RBCIwIIIMbGViZXJnZXIuYml6ghB3d3cubGViZXJnZXIuYml6MFEGA1Ud
    IARKMEgwCAYGZ4EMAQIBMDwGDCsGAQQBgqkwAQMBATAsMCoGCCsGAQUFBwIBFh5o
    dHRwczovL3d3dy5zc2wuY29tL3JlcG9zaXRvcnkwHQYDVR0lBBYwFAYIKwYBBQUH
    AwIGCCsGAQUFBwMBMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9jcmxzLnNzbC5j
    b20vU1NMY29tUlNBU1NMc3ViQ0EuY3JsMB0GA1UdDgQWBBTCxWii5RK9474UxOJB
    wLerjO2QbTAOBgNVHQ8BAf8EBAMCBaAwEwYKKwYBBAHWeQIEAwEB/wQCBQAwDQYJ
    KoZIhvcNAQELBQADggIBAA+2tsRNgQIQMs93Q+NNCQgzj+9avNUbT8s1hZHBkoyf
    3zGgMRJgZkJ/xSEG/www/0SXKhhg8Bnp6r4PfpGn5t+T1XkZz8PhMvQlCT/zPBqC
    8W7voCSMdG0klWqz2hBJ3lNzEmHLKrkp63SM17xE8rGDd0oMfjKwxZKwb7z40jrA
    isEUWNq6FzSPiNllNJq7IbOffEuR0/oz21a3vruPJGB0opWYPBqQcLzemnEXDPEZ
    R2NzfSZB5UzZfAtGLbjxYoMXK+7JLoQjsPpQWlJqGjVaHd9K+Lthg1THwYtdMekK
    Flobw8WirkmuKBZEmo8x6nobfFh2VaBOjA8AXRr6jEO3EjwKvCHDm32td9SkDXe7
    tP4IO/gJma4dxWKV1Hyu/1/6qPUVn55XCCAiuyZcDo3A0t0nSIR8iGbyBtQb0OJH
    SzOyGFJ2SLM8lmyl3eJzXc5YLcJso4S2ZVgZQ9KVApitjvlBvgL7BPskNZxI/c0T
    ISPlOeYtD0O/rxQuQakWOqal9hk+l4Rrd7O+UguXijB92h/40AfLsaLUCRxBZgXA
    tSMLQNleqFMpxIwA93Ybm+iT3FmBqqDNZ2cJ77NTVL3sKeF77b0Xdppn+93Rz51z
    K9UmDRX973f9qi9p/1PbofcOBKZnMaFp7O7kXfdBRaXzslhSLDE2/X+Kx7SVe0GV
    -----END CERTIFICATE-----
    CODE
  5. The output should say Test Out: "Exit code: 1STDOUT: Key is in block listERROUT:(name of block list and fingerprint that matches)".

    When uploading another certificate, not on the block list, the Exit code should be 0.
    The following displays an example configuration.

External Command Validator for checking for weak keys