Skip to content

Instantly share code, notes, and snippets.

@tsaarni
Last active April 12, 2026 13:39
Show Gist options
  • Select an option

  • Save tsaarni/62d6cb773e8e2b4047077778f896adad to your computer and use it in GitHub Desktop.

Select an option

Save tsaarni/62d6cb773e8e2b4047077778f896adad to your computer and use it in GitHub Desktop.

Reproduction steps for https://github.com/orgs/openbao/discussions/2721

Overview

The Puppet server CA fails to preserve the encoding of the CA certificate subject name when issuing new certificates. The issuer field in issued certificates is always re-encoded as a UTF8String.

When Go crypto builds a chain to a trust anchor, it compares the raw bytes of a certificate's issuer to the subject of its issuing certificate. Because the CA re-encodes this field, validation fails due to mismatching DNs.

This general problem was discussed in Go issue golang#31440, where it was concluded that this behavior complies with the specification (comment link).

The following issue relates to this problem:

Reproduction steps

To reproduce the issue with latest of openvox puppet server source code, follow the steps below:

git clone https://github.com/OpenVoxProject/openvox-server.git

cd openvox-server

# Initialize git submodules
git submodule init && git submodule update

# Install vendored JRuby gems and create dev puppet.conf
./dev-setup

Enable autosign so that submitted agent CSRs are signed immediately

sed -i '/^\[main\]/a autosign = true' ~/.puppetlabs/etc/puppet/puppet.conf

Generate CA key and self-signed cert with PrintableString subject.

CADIR=~/.puppetlabs/etc/puppetserver/ca
mkdir -p "$CADIR/signed" "$CADIR/requests"

openssl genrsa -out "$CADIR/ca_key.pem" 4096 2>/dev/null
openssl req -new -x509 -key "$CADIR/ca_key.pem" -out "$CADIR/ca_crt.pem" -days 3650 \
  -config <(printf '[req]\ndistinguished_name=d\nstring_mask=default\nprompt=no\n[d]\nCN=Puppet CA: localhost\n') 2>/dev/null 

Verify the CA uses PrintableString subject name:

openssl x509 -in ~/.puppetlabs/etc/puppetserver/ca/ca_crt.pem -noout -subject -nameopt show_type

The output is subject=CN=PRINTABLESTRING:Puppet CA: localhost

Initialize remaining mandatory CA directory files required by puppet server

echo "01" > "$CADIR/crlnumber"
openssl ca -gencrl -keyfile "$CADIR/ca_key.pem" -cert "$CADIR/ca_crt.pem" \
  -out "$CADIR/ca_crl.pem" -crldays 3650 \
  -config <(printf "[ca]\ndefault_ca=d\n[d]\ndatabase=/dev/null\ncrlnumber=$CADIR/crlnumber\ndefault_md=sha256\n") 2>/dev/null

echo "02" > "$CADIR/serial"
touch "$CADIR/inventory.txt"

mkdir -p ~/.puppetlabs/etc/puppet/ssl
ln -sf ~/.puppetlabs/etc/puppetserver/ca ~/.puppetlabs/etc/puppet/ssl/ca
cp "$CADIR/ca_crl.pem" ~/.puppetlabs/etc/puppet/ssl/crl.pem

Start the server and wait for server certificate to appear

lein trampoline run \
    --config ./dev/puppetserver.conf \
    --bootstrap-config ./dev/bootstrap.cfg

Verify server certificate issuer encoding

openssl x509 -in ~/.puppetlabs/etc/puppet/ssl/certs/localhost.pem -noout -issuer -nameopt show_type

The server has converted issuer name to UTF8String instead of actual PrintableString: issuer=CN=UTF8STRING:Puppet CA: localhost

Simulate agent certificate signing by generating agent key and CSR:

openssl genrsa -out agent-key.pem 2048 2>/dev/null
openssl req -new -key agent-key.pem -out agent.csr -subj "/CN=test-agent" 2>/dev/null

Submit CSR to the Puppet CA API:

curl -sk -X PUT \
  --cert ~/.puppetlabs/etc/puppet/ssl/certs/localhost.pem \
  --key ~/.puppetlabs/etc/puppet/ssl/private_keys/localhost.pem \
  --cacert ~/.puppetlabs/etc/puppetserver/ca/ca_crt.pem \
  -H "Content-Type: text/plain" \
  --data-binary @agent.csr \
  "https://localhost:8140/puppet-ca/v1/certificate_request/test-agent"

Fetch the signed agent certificate:

curl -sk \
  --cert ~/.puppetlabs/etc/puppet/ssl/certs/localhost.pem \
  --key ~/.puppetlabs/etc/puppet/ssl/private_keys/localhost.pem \
  --cacert ~/.puppetlabs/etc/puppetserver/ca/ca_crt.pem \
  "https://localhost:8140/puppet-ca/v1/certificate/test-agent" > agent-cert.pem

Verify agent cert issuer encoding:

openssl x509 -in agent-cert.pem -noout -issuer -nameopt show_type

The server has converted issuer name to UTF8String instead of actual PrintableString: issuer=CN=UTF8STRING:Puppet CA: localhost

Root cause

The encoding changes when issuer is treated as Java string and not maintained in original encoding. Refer to the following code:

  1. Puppet Server signs certificates using an SSL utils library, treating the CA name as a string. See first parameter of utils/sign-certificate calls in https://github.com/OpenVoxProject/openvox-server/blob/main/src/clj/puppetlabs/puppetserver/certificate_authority.clj

  2. The implementation of SSLUtils::signCertificate() in SSL utils library receives the String issuerDn and constructs a BouncyCastle X500Name object. See https://github.com/OpenVoxProject/jvm-ssl-utils/blob/main/src/java/com/puppetlabs/ssl_utils/SSLUtils.java#L258-L273

The problem could be fixed in puppetserver and jvm-ssl-utils by passing either the complete CA certificate or the issuer DN in its original encoded format.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment