From afc1c49b998281039c7b2fb8ef88683a9870ed9a Mon Sep 17 00:00:00 2001 From: Satyajit Das Date: Wed, 24 Jun 2026 17:49:54 +0530 Subject: [PATCH] Fixes #39446 - Reject non-PEM content in katello-certs-check Certificate files exported from PKCS#12/PFX bundles may contain OpenSSL metadata between PEM blocks that Pulp rejects at sync time. Add an early PEM structure check for the server cert and CA bundle. Co-authored-by: Cursor --- bin/katello-certs-check | 54 +++++++++++++++++++ .../certs/ca-bundle-bag-attributes.crt | 41 ++++++++++++++ .../katello-certs-check/create_cert.sh | 14 +++++ spec/katello_certs_check_spec.rb | 13 +++++ 4 files changed, 122 insertions(+) create mode 100644 spec/fixtures/katello-certs-check/certs/ca-bundle-bag-attributes.crt diff --git a/bin/katello-certs-check b/bin/katello-certs-check index a2c04b5a..22a92cf0 100755 --- a/bin/katello-certs-check +++ b/bin/katello-certs-check @@ -259,7 +259,61 @@ function check-ca-signing-algorithm () { fi } +function check-pem-content () { + local FILE=$1 + local TYPE=$2 + + printf "Checking ${TYPE} for non-PEM content: " + + if awk ' + BEGIN { + in_cert = 0 + bad = 0 + } + + /^-----BEGIN (TRUSTED )?CERTIFICATE-----$/ { + if (in_cert) { + bad = 1 + } + in_cert = 1 + next + } + + /^-----END (TRUSTED )?CERTIFICATE-----$/ { + if (!in_cert) { + bad = 1 + } + in_cert = 0 + next + } + + /^[[:space:]]*$/ { + next + } + + { + if (!in_cert) { + bad = 1 + } + } + + END { + if (in_cert) { + bad = 1 + } + exit bad + } + ' "$FILE" + then + success + else + error 12 "The ${TYPE} '$FILE' contains content outside PEM CERTIFICATE blocks. Only PEM CERTIFICATE blocks are allowed." + fi +} + check-files-exist +check-pem-content "$CERT_FILE" "certificate file" +check-pem-content "$CA_BUNDLE_FILE" "CA bundle" check-server-cert-encoding check-expiration check-cert-ca-flag diff --git a/spec/fixtures/katello-certs-check/certs/ca-bundle-bag-attributes.crt b/spec/fixtures/katello-certs-check/certs/ca-bundle-bag-attributes.crt new file mode 100644 index 00000000..85b76864 --- /dev/null +++ b/spec/fixtures/katello-certs-check/certs/ca-bundle-bag-attributes.crt @@ -0,0 +1,41 @@ +-----BEGIN CERTIFICATE----- +MIIDETCCAfmgAwIBAgIUW99nJU3DgZdPE4KtDWgL6cTrEAgwDQYJKoZIhvcNAQEL +BQAwGDEWMBQGA1UEAwwNVGhpcmRwYXJ0eSBDQTAeFw0yMDExMTgxNTQ0NTJaFw0z +MDExMTYxNTQ0NTJaMBgxFjAUBgNVBAMMDVRoaXJkcGFydHkgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDs4Haoc6xj4cTiGYzcqLBiX6fnDpmVPXaD +kE6s0iFYuqZcZgFIuVetgWn4ew7NvDgm1HwCA6EnKBY4zxMd+xic2vO8Pm9SqNWB +0bIdyKvHn1o3u9TMRcnHbp4MvlTTsd0Hr91n+J6Kv7TVUihhsWQH6YILqaKMaEa3 +78ssaLrTULdCHQ3vB0XyZGj3NLv5PYq6Yt92hG8M7vyVeBPdEECidD1csAOefk8T +EBRgXgl7dpBa16dZ9nNQzurxOGrRgFsW4wIQit3AU/Y3Zyz1f9hTcG+xHGHUzzsy +jaV345Mdito5DNaGqkh+7PUccb1JihuS6ePZl5J6GQSjktFwPL2jAgMBAAGjUzBR +MB0GA1UdDgQWBBRKB5Wwmh4CsZHFmnAczPb6wjMRajAfBgNVHSMEGDAWgBRKB5Ww +mh4CsZHFmnAczPb6wjMRajAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA +A4IBAQCs7kfOgqFXpYqAYjxq+NlQeeWSyEMdU/5QbSjxS68U3wXZ2JR+N7ptmn8B +IaeIF8BMFkLKKCG0s486YnOGKBkmbE5xxAJYctzJSrAjCtkBqqCVMtqpomuXawJv +tB+HwKV3IW43lM8S3DJ5XbEWlZctqGb803ud6Mt2Rlyc6afPyFzt5DPrgvwkgKmX +cLgkvUP0W4dinOG3PqE5NbxqIMw+0kzyrbGYLO7Klwsqjfms++XXIdREzS/nt8+9 +c2uERABlpV58p/xyZjJMGGnU0YIhOfn6+LQ6gyqU3qKdj6/VtcQ6SnZC3GE3adqT +LpdSdMc5aL5hr2hZl/uVvrKLYDGz +-----END CERTIFICATE----- +Bag Attributes: +subject=DC=example, CN=Test CA +issuer=CN=Test CA +-----BEGIN CERTIFICATE----- +MIIDHTCCAgWgAwIBAgIUK+x25LNYYMHS83aWDnAYviwxEYEwDQYJKoZIhvcNAQEL +BQAwHjEcMBoGA1UEAwwTVGVzdCBTZWxmLVNpZ25lZCBDQTAeFw0yMDExMTgwMjMw +NDNaFw0zMDExMTYwMjMwNDNaMB4xHDAaBgNVBAMME1Rlc3QgU2VsZi1TaWduZWQg +Q0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC92114uygw5KcqPCz1 +E/Cwd3Lo2ytyPD9FchWKPOxXpNisHMOr4zAfsxERXmgBLawHIkqc2Xae3TqHGGQa +ll3J3HukwghZQAyjcNG/Q2Q2QqfQW1tzxHRnz2EKBoRoyhmVXcnu+qBoEgkf5QI/ +Rk9HzLJINZPcZuMEkRgcf5q1h/F+PY2yCMwT5qjB6whn6zX6FP6G3//fRtkZw4cI +FPPjKJedbHlYEifRigmJfu+T5Q5xz19Og/1zDwfl7is5eBUV+KEoIE7UpmvR1UrM ++T6WYl3vxeM08y1QU6vR9GqummDMinfWLj0hV+dYwI9/1fHIjfPqgxPUa5AGw7ik +vyrvAgMBAAGjUzBRMB0GA1UdDgQWBBQz80R5aRb/egnEMKHQonUM3xgj6DAfBgNV +HSMEGDAWgBQz80R5aRb/egnEMKHQonUM3xgj6DAPBgNVHRMBAf8EBTADAQH/MA0G +CSqGSIb3DQEBCwUAA4IBAQCdiBvQx6ExmteTzwkGCheKwUMvzCehuwvpoJRE/JXo +zz67414oyWXkSN8/9HE3nkH/xxunD/Ni+N9ppk7iicSpyOKfdDXiaS8qq1O1OXCx +CjoVuIFAPFWOEEhLdnb1v8YVWx2JwcbGvhCLNSoK1a6uwCmWixtoeQiKspBfwFcb +wfU9qNdXsezBljahE4Q2E4SR+XclA6iHdooX4ajnleamqeH0ephyCqvMAhzfJA5F +O1+SJRFbIjwfKxsEJS6Czrn+EU2eLtxk5g5+oO06ZYj4rVOfgc2Wc0+cisgP0fT/ +WVkAxgGS6L0jGvZSisEUBpoidJNddWnf9mzUT2kJ5DCO +-----END CERTIFICATE----- diff --git a/spec/fixtures/katello-certs-check/create_cert.sh b/spec/fixtures/katello-certs-check/create_cert.sh index e3a0cb7d..c8109d65 100755 --- a/spec/fixtures/katello-certs-check/create_cert.sh +++ b/spec/fixtures/katello-certs-check/create_cert.sh @@ -120,3 +120,17 @@ if [[ ! -f "$CERTS_DIR/$CERT_NAME.key" || ! -f "$CERTS_DIR/$CERT_NAME.crt" ]]; t else echo "Shortname server certificate exists. Skipping." fi + +CA_BUNDLE_BAG_ATTRIBUTES=ca-bundle-bag-attributes +if [[ ! -f "$CERTS_DIR/$CA_BUNDLE_BAG_ATTRIBUTES.crt" ]]; then + echo "Generate CA bundle with PKCS#12 metadata between certificates" + sed -n '1,19p' $CERTS_DIR/$CA_BUNDLE.crt > $CERTS_DIR/$CA_BUNDLE_BAG_ATTRIBUTES.crt + cat >> $CERTS_DIR/$CA_BUNDLE_BAG_ATTRIBUTES.crt <<'EOF' +Bag Attributes: +subject=DC=example, CN=Test CA +issuer=CN=Test CA +EOF + sed -n '20,$p' $CERTS_DIR/$CA_BUNDLE.crt >> $CERTS_DIR/$CA_BUNDLE_BAG_ATTRIBUTES.crt +else + echo "CA bundle with PKCS#12 metadata exists. Skipping." +fi diff --git a/spec/katello_certs_check_spec.rb b/spec/katello_certs_check_spec.rb index 9d2934b1..96fb1623 100644 --- a/spec/katello_certs_check_spec.rb +++ b/spec/katello_certs_check_spec.rb @@ -149,4 +149,17 @@ def fixture(filename) expect(status.exitstatus).to eq 4 end end + + context 'with PKCS#12 metadata in CA bundle' do + let(:key) { File.join(certs_directory, 'foreman.example.com.key') } + let(:cert) { File.join(certs_directory, 'foreman.example.com.crt') } + let(:ca) { File.join(certs_directory, 'ca-bundle-bag-attributes.crt') } + + it 'fails on non-PEM content' do + command_with_certs = "#{command} -b #{ca} -k #{key} -c #{cert}" + _stdout, stderr, status = Open3.capture3(command_with_certs) + expect(stderr).to include "The CA bundle '#{ca}' contains content outside PEM CERTIFICATE blocks. Only PEM CERTIFICATE blocks are allowed." + expect(status.exitstatus).to eq 12 + end + end end