Post Processing Validators
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%
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:
- 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
.
- 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.
- 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
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
Debian Weak Key Checks
The script below was written for the Debian packages, and likely needs to be adjusted for the HARICA keys.
- CODE
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
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).CODE#!/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
In the External Command Validator, specify the following:
- Full pathname of script: /opt/weak-keys/weak-key-check.sh.
- Fail on script error code: true.
- Fail on output to error out: true.
- Issuance phase should be Pre-sign Certificate Validation to ensure that checks are done before the CAs private key is used.
- Save the Validator.
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.
CODE-----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-----
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.