Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: Add e2e test for CRL #1969

Merged
merged 47 commits into from
Dec 24, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
566ae11
test: init crl e2e test
junczhu Dec 8, 2024
b0c7a07
test: init crl e2e test 2
junczhu Dec 8, 2024
17ce77c
test: init crl e2e test 3
junczhu Dec 8, 2024
5e2f3d5
test: crl e2e test add host
junczhu Dec 8, 2024
afd8791
test: crl e2e test add host 2
junczhu Dec 8, 2024
9ce26a7
test: update e2e script
junczhu Dec 9, 2024
543d43c
test: update e2e script 2
junczhu Dec 9, 2024
e5a719c
test: update e2e script 3
junczhu Dec 9, 2024
c2615b0
test: update e2e script 4
junczhu Dec 9, 2024
31e37ae
test: update e2e script 4
junczhu Dec 9, 2024
8c7dccb
test: update e2e script 5
junczhu Dec 10, 2024
d3ad414
test: e2e k8s
junczhu Dec 11, 2024
bee2ce3
test: e2e k8s 2
junczhu Dec 11, 2024
afa4dcb
test: update test
junczhu Dec 11, 2024
c249d88
test: update e2e
junczhu Dec 12, 2024
3570acf
test: update e2e test
junczhu Dec 12, 2024
d3a1302
test: update e2e CLI
junczhu Dec 12, 2024
c4d46c5
test: update e2e CLI 2
junczhu Dec 12, 2024
3f3e700
test: update e2e CLI 3
junczhu Dec 12, 2024
5489ca2
test: update e2e CLI 4
junczhu Dec 12, 2024
82c29c0
test: update e2e CLI 5
junczhu Dec 12, 2024
2088512
test: update e2e CLI 6
junczhu Dec 12, 2024
4224702
test: update e2e CLI 7
junczhu Dec 13, 2024
3508fc7
fix: update test
junczhu Dec 15, 2024
f7b177c
fix: update test
junczhu Dec 15, 2024
aab1e2c
fix: update test 2
junczhu Dec 15, 2024
7acc57c
fix: update test 3
junczhu Dec 15, 2024
94aba4f
fix: update test 4
junczhu Dec 15, 2024
7b520f1
fix: update test script 5
junczhu Dec 16, 2024
14e4cd3
fix: update test script 6
junczhu Dec 16, 2024
6f05a67
fix: another test
junczhu Dec 16, 2024
ac1693b
fix: another test 2
junczhu Dec 16, 2024
61dc0e1
fix: another test 3
junczhu Dec 16, 2024
c80d398
fix: another test 4
junczhu Dec 16, 2024
4b334dd
fix: another test 5
junczhu Dec 16, 2024
a4a737c
fix: another test 6
junczhu Dec 16, 2024
708f438
fix: another test 7
junczhu Dec 16, 2024
4d6d181
test: crl e2e
junczhu Dec 16, 2024
6d11895
test: crl e2e 2
junczhu Dec 16, 2024
b1f8258
test: crl e2e 3
junczhu Dec 16, 2024
57b6d1f
test: address comments
junczhu Dec 18, 2024
769e82d
test: address comments 2
junczhu Dec 18, 2024
3e2f503
test: address comments 3
junczhu Dec 18, 2024
862b1c5
Merge branch 'dev' into crl_e2e
junczhu Dec 19, 2024
d987f11
test: fix ci test
junczhu Dec 19, 2024
efc277e
Merge branch 'dev' into crl_e2e
binbin-li Dec 23, 2024
508d51b
Merge branch 'dev' into crl_e2e
binbin-li Dec 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ test-e2e: generate-rotation-certs
EXPIRING_CERT_DIR=.staging/rotation/expiring-certs CERT_DIR=.staging/rotation GATEKEEPER_VERSION=${GATEKEEPER_VERSION} bats -t ${BATS_PLUGIN_TESTS_FILE}

.PHONY: test-e2e-cli
test-e2e-cli: e2e-dependencies e2e-create-local-registry e2e-notation-setup e2e-notation-leaf-cert-setup e2e-cosign-setup e2e-licensechecker-setup e2e-sbom-setup e2e-trivy-setup e2e-schemavalidator-setup e2e-vulnerabilityreport-setup
test-e2e-cli: e2e-dependencies e2e-create-local-registry e2e-notation-setup e2e-notation-leaf-cert-setup e2e-notation-crl-setup e2e-cosign-setup e2e-licensechecker-setup e2e-sbom-setup e2e-trivy-setup e2e-schemavalidator-setup e2e-vulnerabilityreport-setup
rm ${GOCOVERDIR} -rf
mkdir ${GOCOVERDIR} -p
RATIFY_DIR=${INSTALL_DIR} TEST_REGISTRY=${TEST_REGISTRY} ${GITHUB_WORKSPACE}/bin/bats -t ${BATS_CLI_TESTS_FILE}
Expand Down Expand Up @@ -327,6 +327,26 @@ e2e-notation-leaf-cert-setup:
rm .staging/notation/notation.tar
NOTATION_EXPERIMENTAL=1 .staging/notation/notation sign -u ${TEST_REGISTRY_USERNAME} -p ${TEST_REGISTRY_PASSWORD} --key "leaf-test" ${TEST_REGISTRY}/notation@`${GITHUB_WORKSPACE}/bin/oras manifest fetch ${TEST_REGISTRY}/notation:leafSigned --descriptor | jq .digest | xargs`

e2e-notation-crl-setup:
mkdir -p .staging/notation/crl-test
mkdir -p ~/.config/notation/truststore/x509/ca/crl-test
./scripts/generate-crl-testing-certs.sh .staging/notation/crl-test
cp .staging/notation/crl-test/root.crt ~/.config/notation/truststore/x509/ca/crl-test/root.crt
cp .staging/notation/crl-test/certchain_with_crl.pem ~/.config/notation/truststore/x509/ca/crl-test/certchain_with_crl.pem

jq '.keys += [{"name":"crl-test","keyPath":".staging/notation/crl-test/leaf.key","certPath":".staging/notation/crl-test/certchain_with_crl.pem"}]' ~/.config/notation/signingkeys.json > tmp && mv tmp ~/.config/notation/signingkeys.json

printf 'FROM ${ALPINE_IMAGE}\nCMD ["echo", "notation crl signed image"]' > .staging/notation/Dockerfile
docker buildx create --use
docker buildx build --output type=oci,dest=.staging/notation/notation.tar -t notation:v0 .staging/notation
${GITHUB_WORKSPACE}/bin/oras cp --from-oci-layout .staging/notation/notation.tar:v0 ${TEST_REGISTRY}/notation:crl
rm .staging/notation/notation.tar
NOTATION_EXPERIMENTAL=1 .staging/notation/notation sign -u ${TEST_REGISTRY_USERNAME} -p ${TEST_REGISTRY_PASSWORD} --key "crl-test" ${TEST_REGISTRY}/notation@`${GITHUB_WORKSPACE}/bin/oras manifest fetch ${TEST_REGISTRY}/notation:crl --descriptor | jq .digest | xargs`
# run the CRL server in the background
python3 ./scripts/crl_server.py &
CRL_SERVER_PID=$(shell $!)


e2e-cosign-setup:
rm -rf .staging/cosign
mkdir -p .staging/cosign
Expand Down
81 changes: 81 additions & 0 deletions scripts/crl_server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Copyright The Ratify Authors.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import http.server
import socketserver
import os

PORT = 10086
DATA_DIR = '.staging/notation/crl-test'
leaf_crl = 'leaf.crl'
intermediate_crl = 'intermediate.crl'


class CRLRequestHandler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
global leaf_crl
global intermediate_crl
if self.path == '/leaf.crl':
file_path = os.path.join(DATA_DIR, leaf_crl)
self.crl_response(file_path)
elif self.path == '/intermediate.crl':
file_path = os.path.join(DATA_DIR, intermediate_crl)
self.crl_response(file_path)
else:
self.send_error(404, 'Not Found')

def crl_response(self, file_path):
if os.path.exists(file_path):
self.send_response(200)
self.send_header('Content-Type', 'application/pkix-crl')
self.end_headers()
with open(file_path, 'rb') as f:
self.wfile.write(f.read())
else:
self.send_error(404, 'File Not Found')

def do_POST(self):
global leaf_crl
global intermediate_crl
if self.path == '/leaf/revoke':
leaf_crl = 'leaf_revoked.crl'
self.post_response()
elif self.path == '/leaf/unrevoke':
leaf_crl = 'leaf.crl'
self.post_response()
elif self.path == '/leaf/expired':
leaf_crl = 'leaf_expired.crl'
self.post_response()
elif self.path == '/intermediate/revoke':
intermediate_crl = 'intermediate_revoked.crl'
self.post_response()
elif self.path == '/intermediate/unrevoke':
intermediate_crl = 'intermediate.crl'
self.post_response()
else:
self.send_error(404, 'Not Found')

def post_response(self):
self.send_response(201)
self.end_headers()
self.wfile.write(b'ok')

class ReusableTCPServer(socketserver.TCPServer):
allow_reuse_address = True

with ReusableTCPServer(('', PORT), CRLRequestHandler) as httpd:
print(f"Serving at port {PORT}")
try:
httpd.serve_forever()
finally:
httpd.server_close()
244 changes: 244 additions & 0 deletions scripts/generate-crl-testing-certs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
#!/bin/bash -ex
# Copyright The Ratify Authors.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# This file include the script to generate testing certificates for CRL testing.
# The generated files are:
# - certchain_with_crl.pem: the fullchain file that includes the leaf
# certificate with CRL, intermediate certificate with invalid OCSP and valid
# CRL, and the root certificate.
# - leaf.crl: the CRL file that includes the revoked leaf certificate.
junczhu marked this conversation as resolved.
Show resolved Hide resolved
# - leaf.key: the private key of the leaf certificate.
# - leaf_revoked.crl: the CRL file that includes the revoked leaf certificate.
# - intermediate.crl: the CRL file that includes the intermediate certificate.
# - intermediate_revoked.crl: the CRL file that includes the revoked intermediate
# - root.crt: the root certificate.
#
# Note: The script will not run in the pipeline, but we need to keep it for
# future maintenance because generating those test certificates with CRL is not
# easy.

set -o errexit
set -o nounset
set -o pipefail

CERT_DIR=$1

generate() {
# Create root CA configuration file
cat > root.cnf <<EOF
[ req ]
default_bits = 2048
prompt = no
distinguished_name = root_distinguished_name
x509_extensions = v3_ca

[ root_distinguished_name ]
C = US
ST = State
L = City
O = Organization
OU = OrgUnit
CN = RootCA

[ ca ]
default_ca = CA_default

[ CA_default ]
dir = ./demoCA
new_certs_dir = \$dir/newcerts
database = \$dir/index.txt
serial = \$dir/serial
private_key = ./root.key
certificate = ./root.crt
default_md = sha256
policy = policy_any
x509_extensions = usr_cert
copy_extensions = copy
default_days = 36500
default_crl_days = 36500
crlnumber = \$dir/crlnumber
crl_extensions = crl_ext

[ policy_any ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied

[ v3_ca ]
basicConstraints = critical,CA:TRUE
keyUsage = critical,keyCertSign,cRLSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always

[ crl_ext ]
authorityKeyIdentifier = keyid:always
EOF

# Set up OpenSSL CA directory structure
mkdir -p demoCA/newcerts
touch demoCA/index.txt
echo '1002' > demoCA/serial
echo '1002' > demoCA/crlnumber

# Generate root private key
openssl genrsa -out root.key 2048

# Generate self-signed root certificate with extensions
openssl req -x509 -new -key root.key -sha256 -days 36500 -out root.crt \
-config root.cnf -extensions v3_ca

# Update intermediate.cnf to include [ca] and [CA_default] sections
cat > intermediate.cnf <<EOF
[ req ]
default_bits = 2048
prompt = no
distinguished_name = intermediate_distinguished_name
x509_extensions = v3_intermediate_ca

[ intermediate_distinguished_name ]
C = US
ST = State
L = City
O = Organization
OU = OrgUnit
CN = IntermediateCA

[ ca ]
default_ca = CA_default

[ CA_default ]
dir = ./intermediateCA
new_certs_dir = \$dir/newcerts
database = \$dir/index.txt
serial = \$dir/serial
private_key = ./intermediate.key
certificate = ./intermediate.crt
default_md = sha256
policy = policy_any
x509_extensions = usr_cert
copy_extensions = copy
default_days = 36500
default_crl_days = 36500
crlnumber = \$dir/crlnumber
crl_extensions = crl_ext

[ policy_any ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied

[ v3_intermediate_ca ]
basicConstraints = critical,CA:TRUE,pathlen:0
keyUsage = critical,keyCertSign,cRLSign
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
crlDistributionPoints = URI:http://localhost:10086/intermediate.crl
authorityInfoAccess = OCSP;URI:http://localhost.test/ocsp

[ crl_ext ]
authorityKeyIdentifier = keyid:always
EOF

# Set up OpenSSL CA directory structure for intermediate CA
mkdir -p intermediateCA/newcerts
touch intermediateCA/index.txt
echo '1000' > intermediateCA/serial
echo '1000' > intermediateCA/crlnumber

# Generate intermediate private key
openssl genrsa -out intermediate.key 2048

# Generate intermediate CSR
openssl req -new -key intermediate.key -out intermediate.csr -config intermediate.cnf

# Sign intermediate certificate with root CA
openssl ca -config root.cnf -in intermediate.csr -out intermediate.crt -batch -extensions v3_intermediate_ca -extfile intermediate.cnf -notext

# Update leaf.cnf to remove OCSP server
cat > leaf.cnf <<EOF
[ req ]
default_bits = 2048
prompt = no
distinguished_name = req_distinguished_name
req_extensions = v3_req

[ req_distinguished_name ]
C = US
ST = State
L = City
O = Organization
OU = OrgUnit
CN = LeafCert

[ v3_req ]
basicConstraints = critical,CA:FALSE
keyUsage = critical,digitalSignature
crlDistributionPoints = URI:http://localhost:10086/leaf.crl
EOF

# Generate leaf private key
openssl genrsa -out leaf.key 2048

# Generate leaf certificate signing request (CSR)
openssl req -new -key leaf.key -out leaf.csr -config leaf.cnf

# Sign leaf certificate with intermediate CA
openssl ca -config intermediate.cnf -in leaf.csr -out leaf.crt -batch -extensions v3_req -extfile leaf.cnf -notext

# Generate intermediate CRL using root.cnf (before revocation)
openssl ca -config root.cnf -gencrl -out intermediate.crl

# Convert root CRL to DER format
junczhu marked this conversation as resolved.
Show resolved Hide resolved
openssl crl -in intermediate.crl -outform der -out intermediate.crl

# Revoke intermediate certificate using root CA
openssl ca -config root.cnf -revoke intermediate.crt

# Generate intermediate CRL including revoked intermediate certificate
openssl ca -config root.cnf -gencrl -out intermediate_revoked.crl

# Convert intermediate CRL to DER format
openssl crl -in intermediate_revoked.crl -outform der -out intermediate_revoked.crl

# Generate leaf CRL
openssl ca -config intermediate.cnf -gencrl -out leaf.crl

# Convert leaf CRL to DER format
openssl crl -in leaf.crl -outform der -out leaf.crl

# Revoke leaf certificate
openssl ca -config intermediate.cnf -revoke leaf.crt

# Generate leaf CRL including revoked leaf certificate
openssl ca -config intermediate.cnf -gencrl -out leaf_revoked.crl

# Convert leaf CRL to DER format
openssl crl -in leaf_revoked.crl -outform der -out leaf_revoked.crl

# merge leaf cert and root cert to create fullchain file
cat leaf.crt intermediate.crt root.crt > certchain_with_crl.pem

}

rm -r ${CERT_DIR} || true
mkdir -p ${CERT_DIR}
pushd "${CERT_DIR}"
generate
popd
5 changes: 5 additions & 0 deletions test/bats/cli-test.bats
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ load helpers
assert_cmd_verify_failure
}

@test "notation verifier crl test" {
junczhu marked this conversation as resolved.
Show resolved Hide resolved
run bin/ratify verify -c $RATIFY_DIR/config_notation_crl.json -s $TEST_REGISTRY/notation:crl
assert_cmd_verify_success
junczhu marked this conversation as resolved.
Show resolved Hide resolved
}

@test "notation verifier with type test" {
run bin/ratify verify -c $RATIFY_DIR/config_notation_verifier_with_type.json -s $TEST_REGISTRY/notation:leafSigned
assert_cmd_verify_success_with_type
Expand Down
Loading
Loading