Skip to main content

Root Certificate Requirements

This chapter outlines the requirements for the X.509 root certificate that partners need to provide in order to establish secure communication with our devices. The root certificate will be added to the trusted Certificate Authorities (CAs) of our device, enabling TLS handshakes with certificates issued by the partner's root certificate.

Cryptographic Algorithms

The root certificate must use one of the following cryptographic algorithms:

  • Elliptic Curve Cryptography (ECC) [recommended]:
    • Curve: secp384r1 or secp521r1
  • RSA [supported]:
    • Key Size: 4096 bits

Certificate Validity

The root certificate should have a validity period that aligns with the expected lifetime of the product, which is typically around 30 years. This is to ensure that the root certificate remains valid for the duration of the product's life cycle.

We recommend implementing a practice of "crypto agility". This involves updating the root certificate every 2, 4, or 6 years to adapt to current security standards and threats.

In the case that the root certificate expires, the partner will need to provide a new root certificate which can only be deployed to our devices through a software update, i.e. the device must be connected to our cloud and the end customer must approve the update. Also note that all partner devices that are already deployed in the field will need to be updated to include the new corresponding end entity certificate.

Certificate Authority (CA) Structure

The CA hierarchy should be a maximum of two levels deep. This means that the root CA can issue certificates directly to end entities or to intermediate CAs, which in turn issue certificates to end entities.

Compliance with RFC2459

The root certificate must comply with the specifications outlined in RFC 2459, which includes but is not limited to the following:

  • Version: The certificate should be X.509 version 2 or 3.
  • Serial Number: Must be unique for each certificate issued by the CA.
  • Signature Algorithm: Must match the chosen cryptographic algorithm (e.g., ECDSA with SHA-384 for secp384r1, ECDSA with SHA-512 for secp521r1, or SHA-256 with RSA for RSA4096).
  • Issuer: The distinguished name (DN) of the CA. Please ensure that at least the fields C, O, and CN are set, and that the O field is the same in the subject of the end entity certificate.
  • Validity Period: The "not before" and "not after" dates must be set appropriately to cover the expected lifetime of the device certificates.
  • Subject: The distinguished name of the entity associated with the public key.
  • Extensions:
    • Basic Constraints: Must indicate that the certificate is a CA certificate.
    • Key Usage: Must include keyCertSign and cRLSign.
    • Subject Key Identifier: Should be included to facilitate certificate path construction.
    • Authority Key Identifier: Should be included to facilitate certificate path construction.

Additional Recommendations

  • Security Practices: The CA should follow best security practices for key management, including secure generation, storage, and handling of private keys.

Validating the Root Certificate

Before providing the root certificate to us, the partner should validate it to ensure that it meets the requirements outlined in this document. The following script can be used to verify the root certificate:

#!/bin/bash

ERRORS=""

# Check for openssl
if ! command -v openssl &> /dev/null; then
echo -e "openssl could not be found"
exit 1
fi

CERT_FILE=$1

if [ -z "$CERT_FILE" ]; then
echo -e "Usage: $0 <certificate-file>"
exit 1
elif [ ! -f "$CERT_FILE" ] || [ ! -r "$CERT_FILE" ]; then
echo -e "Certificate file does not exist or is not readable: $CERT_FILE"
exit 1
fi

echo -e "Verifying certificate: $CERT_FILE\n"

# Check cryptographic algorithm and key size/curve
ALGORITHM=$(openssl x509 -in $CERT_FILE -noout -text \
| grep "Public Key Algorithm" | awk -F: '{print $2}' | xargs)

if [[ "$ALGORITHM" == "rsaEncryption" ]]; then
KEY_SIZE=$(openssl x509 -in $CERT_FILE -noout -text | grep "Public-Key" \
| awk -F"(" '{print $2}' | awk -F" " '{print $1}')
if [[ "$KEY_SIZE" -ne 4096 ]]; then
ERRORS+="\n- Invalid key size for RSA: \"$KEY_SIZE\". Must be 4096 bits."
fi
elif [[ "$ALGORITHM" == "id-ecPublicKey" ]]; then
CURVE=$(openssl x509 -in $CERT_FILE -noout -text | grep "ASN1 OID" \
| awk -F: '{print $2}' | xargs)
if [[ "$CURVE" != "secp384r1" && "$CURVE" != "secp521r1" ]]; then
ERRORS+="\n- Invalid curve for ECC: \"$CURVE\". Must be secp384r1 or secp521r1."
fi
else
ERRORS+="\n- Invalid cryptographic algorithm: "
ERRORS+="\"$ALGORITHM\". Must be RSA or ECC."
fi

# Check certificate validity period
NOT_BEFORE=$(openssl x509 -in $CERT_FILE -noout -startdate | cut -d= -f2)
NOT_AFTER=$(openssl x509 -in $CERT_FILE -noout -enddate | cut -d= -f2)
START_DATE=$(date -d"$NOT_BEFORE" +%s)
END_DATE=$(date -d"$NOT_AFTER" +%s)
DIFFERENCE=$(( ($END_DATE - $START_DATE) / (60*60*24*365) ))
if [[ $DIFFERENCE -lt 30 ]]; then
ERRORS+="\n- Invalid certificate validity period. It should be at least 30 years."
fi

# Check version
VERSION=$(openssl x509 -in $CERT_FILE -noout -text | grep "Version" \
| awk '{print $2}')
if [[ "$VERSION" != "2" && "$VERSION" != "3" ]]; then
ERRORS+="\n- Invalid version: \"$VERSION\". Must be X.509 version 2 or 3."
fi

# Check key usage
KEY_USAGE=$(openssl x509 -in $CERT_FILE -noout -text | grep -A1 "Key Usage" \
| tail -n1 | tr -d ' ')
if [[ "$KEY_USAGE" != "CertificateSign,CRLSign" ]]; then
ERRORS+="\n- Invalid key usage: \"$KEY_USAGE\". "
ERRORS+="Must include keyCertSign and cRLSign."
fi

# Check basic constraints
BASIC_CONSTRAINTS=$(openssl x509 -in $CERT_FILE -noout -text \
| grep -A1 "Basic Constraints" | tail -n1 | tr -d ' ')
if [[ ! "$BASIC_CONSTRAINTS" =~ ^CA:TRUE(,pathlen:[0-1])?$ ]]; then
ERRORS+="\n- Invalid basic constraints: \"$BASIC_CONSTRAINTS\". "
ERRORS+="Must indicate CA:TRUE with optional pathlen constraint (0-1)."
fi

# Check subject key identifier
SUBJECT_KEY_IDENTIFIER=$(openssl x509 -in $CERT_FILE -noout -text \
| grep -A1 "Subject Key Identifier" | tail -n1 | tr -d ' ')
if [ -z "$SUBJECT_KEY_IDENTIFIER" ]; then
ERRORS+="\n- Subject Key Identifier is missing."
fi

# Check authority key identifier
AUTHORITY_KEY_IDENTIFIER=$(openssl x509 -in $CERT_FILE -noout -text \
| grep -A1 "Authority Key Identifier" | tail -n1 | tr -d ' ')
if [ -z "$AUTHORITY_KEY_IDENTIFIER" ]; then
ERRORS+="\n- Authority Key Identifier is missing."
fi

# Check issuer DN
ISSUER=$(openssl x509 -in $CERT_FILE -noout -issuer)
ISSUER=${ISSUER#issuer=}
ISSUER_NORMALIZED=$(echo "$ISSUER" | sed 's/ *= */=/g')
if [[ ! "$ISSUER_NORMALIZED" =~ "C=" || ! "$ISSUER_NORMALIZED" =~ "O=" || ! "$ISSUER_NORMALIZED" =~ "CN=" ]]; then
ERRORS+="\n- Issuer DN is missing required fields. "
ERRORS+="Please ensure that at least the fields C, O, and CN are set."
fi

# Check subject DN
SUBJECT=$(openssl x509 -in $CERT_FILE -noout -subject)
SUBJECT=${SUBJECT#subject=}
SUBJECT_NORMALIZED=$(echo "$SUBJECT" | sed 's/ *= */=/g')
if [[ ! "$SUBJECT_NORMALIZED" =~ "C=" || ! "$SUBJECT_NORMALIZED" =~ "O=" || ! "$SUBJECT_NORMALIZED" =~ "CN=" ]]; then
ERRORS+="\n- Subject DN is missing required fields. "
ERRORS+="Please ensure that at least the fields C, O, and CN are set."
fi

# Check if issuer and subject are the same for the root certificate
if [[ "$ISSUER" != "$SUBJECT" ]]; then
ERRORS+="\n- For a self-signed root certificate, "
ERRORS+="the issuer and subject should be identical."
fi

# If there were any errors, print them and exit with a non-zero status
if [[ -n "$ERRORS" ]]; then
echo -e "Certificate verification failed with the following errors:$ERRORS"
exit 1
fi

echo "Certificate verification passed."