For example,
openssl x509 \
-req -sha256 \
-days "365" \
-CAcreateserial \
-CA "ca.crt" -CAkey "ca.key" -passin "pass:abcd" \
-in "csr.csr" -extfile "ext.ext" \
-out "c.crt";
It also creates a file ca.srl
which contains signed certificate's serial.
The above won't work if -CAcreateserial
argument is absent and outputs an error:
/test/ca.srl: No such file or directory
140413509251520:error:06067099:digital envelope routines:EVP_PKEY_copy_parameters:different parameters:../crypto/evp/p_lib.c:93:
140413509251520:error:02001002:system library:fopen:No such file or directory:../crypto/bio/bss_file.c:72:fopen('/test/ca.srl','r')
140413509251520:error:2006D080:BIO routines:BIO_new_file:no such file:../crypto/bio/bss_file.c:79:
Isn't that argument used to output a file with a serial which is possible to get via a command below anyways?
openssl x509 \
-in "c.crt" \
-noout \
-serial;
What's the point? Why does it not create the file internally if required, but saves it on a storage?
The -serial
option of your second command just outputs the serial number of an existing certificate. But when you're signing a certificate the CA needs to generate a unique serial number for each certificate, and until it does that, there's no serial number for -serial
to output yet.
Since the serial number for each certificate needs to be unique for each issuer, an issuer needs to keep track of which serial numbers it has used before, to make sure it doesn't reuse any. OpenSSL gives you a simple way to keep track of this using a serial number file. When you specify -CAcreateserial
, it'll assign the serial number 01
to the signed certificate, and then create this serial number file with the next serial number (02
) in it. On future signing operations, you should be using -CAserial
with the name of that file, and not -CAcreateserial
, and OpenSSL will increment the value in that file for each certificate signed. In this way, you can sign a bunch of certificates with one issuer certificate, and all their serial numbers will be unique.
If you're using multiple issuer certificates, then you can use a separate serial number file for each one.
Note that while this approach works, it's unsuitable for production use, as there are some problems with using strictly sequentially increasing certificate serial numbers.
Thanks to the @Crowman's answer, I created a script which might demonstrate the issue:
#! /usr/bin/env bash
# -------------------------- #
# User variables #
# -------------------------- #
certificateAuthorityName="certificate_authority";
certificateAuthorityPrivateKeyPassword="";
certificateName="certificate";
certificateTestPostfix="_test";
# -------------------------- #
# Variables #
# -------------------------- #
stdout='/dev/null';
stderr='/dev/null';
certificateAuthorityFilepath="$( pwd )/${certificateAuthorityName}";
certificateFilepath="$( pwd )/${certificateName}";
# -------------------------- #
# Functions #
# -------------------------- #
function OR
{
declare i;
for (( i=0; i < "$1"; i++ ));
do
printf '%s' "$2";
done;
}
function SignedCertificateCreate
{
declare createSerial_l="-CAserial ${certificateAuthorityFilepath}.srl";
if [ "$1" = "1" ];
then
rm "${certificateAuthorityFilepath}.srl" > "/dev/null" 2>&1;
createSerial_l='-CAcreateserial';
fi
if ! openssl x509 \
-req -sha256 \
-days "365" \
$createSerial_l \
-CA "${certificateAuthorityFilepath}.crt" -CAkey "${certificateAuthorityFilepath}.key" -passin "pass:${certificateAuthorityPrivateKeyPassword}" \
-in "${certificateFilepath}.csr" -extfile "${certificateFilepath}.ext" \
-out "${certificateFilepath}${certificateTestPostfix}.crt" \
> "$stdout" 2> "$stderr";
then
printf $'Couldn\'t create a certificate\n';
return 1;
fi
}
function SignedCertificatesCreate
{
declare loops_l="1";
if [ "$1" != "" ];
then
loops_l="$1";
fi
declare i;
for (( i=0; i < "$loops_l"; i++ ));
do
if ! SignedCertificateCreate "$2";
then
return 1;
fi
done
}
function ReadCertificateSerialFromFile
{
cat "${certificateAuthorityFilepath}.srl" 2> "$stderr";
}
# -------------------------- #
# Methods #
# -------------------------- #
function Help
{
echo
printf ' Description: OpenSSL serial generation test\n\n';
printf ' Additional arguments:\n\n';
printf ' -d - Enable certain output for debugging\n';
printf ' -h - Help message\n\n';
}
function Main
{
if [[ "$1" == *"h"* ]];
then
Help;
exit 0;
fi
if [[ "$1" == *"d"* ]];
then
stdout='/dev/stdout';
stderr='/dev/stderr';
fi
if [ ! -f "${certificateAuthorityFilepath}.key" ];
then
printf $'There\'s no Certificate Authority private key: %s\n' "${certificateAuthorityFilepath}.key";
exit 1;
fi
if [ "$certificateAuthorityPrivateKeyPassword" = "" ];
then
echo
read -s -p " [ ? ] Certificate Authority Private Key Password: " certificateAuthorityPrivateKeyPassword;
echo
fi
printf '\n %s \n' "$( OR 80 "-" )";
printf ' | %35s | ' 'A new {serial #1} generated';
SignedCertificateCreate 1 || exit 2;
printf '%40s |\n' "$( ReadCertificateSerialFromFile )"
printf ' | %35s | ' 'A new {serial #2} generated';
SignedCertificateCreate 1 || exit 3;
printf '%40s |\n' "$( ReadCertificateSerialFromFile )"
printf ' | %35s | ' 'Used the same {serial #2} 5 times';
SignedCertificatesCreate 5 || exit 4;
printf '%40s |\n' "$( ReadCertificateSerialFromFile )"
printf ' | %35s | ' 'Used the same {serial #2} 256 times';
SignedCertificatesCreate 256 || exit 5;
printf '%40s |\n' "$( ReadCertificateSerialFromFile )"
printf ' %s \n\n' "$( OR 80 "-" )";
}
# -------------------------- #
# Main #
# -------------------------- #
Main "$@";
A possible script's result:
--------------------------------------------------------------------------------
| A new {serial #1} generated | 310BD94F916BDF47913249966B85A9F7771D746A |
| A new {serial #2} generated | 0AC91627E4E99612D3CC7D99BB9793445CEDB36B |
| Used the same {serial #2} 5 times | 0AC91627E4E99612D3CC7D99BB9793445CEDB370 |
| Used the same {serial #2} 256 times | 0AC91627E4E99612D3CC7D99BB9793445CEDB470 |
--------------------------------------------------------------------------------
Just to clarify, the {serial #2}
output differs (the very endings):
B36B
hex or 45931
dec (0);B370
hex or 45936
dec (+5);B470
hex or 46192
dec (+256).If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With