diff --git a/atst/domain/authnid/crl/__init__.py b/atst/domain/authnid/crl/__init__.py index 64594a93..218218f5 100644 --- a/atst/domain/authnid/crl/__init__.py +++ b/atst/domain/authnid/crl/__init__.py @@ -77,7 +77,7 @@ class CRLCache(): store.add_cert(ca) self.log_info("STORE ID: {}. Adding CA with subject {}".format(id(store), ca.get_subject())) - if issuer == ca.get_subject(): + if issuer == ca.get_issuer(): # i.e., it is the root CA and we are at the end of the chain return store diff --git a/atst/forms/request.py b/atst/forms/request.py index a7c556fe..dfd62b38 100644 --- a/atst/forms/request.py +++ b/atst/forms/request.py @@ -89,11 +89,13 @@ class RequestForm(ValidatedForm): data_transfers = SelectField( description="How much data is being transferred to the cloud?", choices=DATA_TRANSFER_AMOUNTS, + validators=[Required()], ) expected_completion_date = SelectField( description="When do you expect to complete your migration to the JEDI Cloud?", choices=COMPLETION_DATE_RANGES, + validators=[Required()], ) cloud_native = RadioField( diff --git a/tests/domain/authnid/test_crl.py b/tests/domain/authnid/test_crl.py index 7ba3a213..5068816c 100644 --- a/tests/domain/authnid/test_crl.py +++ b/tests/domain/authnid/test_crl.py @@ -80,6 +80,15 @@ def test_throws_error_for_missing_issuer(): assert "issuer" in message +def test_multistep_certificate_chain(): + cache = CRLCache( + "tests/fixtures/chain/ca-chain.pem", + crl_locations=["tests/fixtures/chain/intermediate.crl"], + ) + cert = open("tests/fixtures/chain/client.crt", "rb").read() + assert cache.crl_check(cert) + + def test_parse_disa_pki_list(): with open("tests/fixtures/disa-pki.html") as disa: disa_html = disa.read() diff --git a/tests/fixtures/chain/ca-chain.pem b/tests/fixtures/chain/ca-chain.pem new file mode 100644 index 00000000..6bfa5cb7 --- /dev/null +++ b/tests/fixtures/chain/ca-chain.pem @@ -0,0 +1,34 @@ +-----BEGIN CERTIFICATE----- +MIICsDCCAZigAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwEjEQMA4GA1UEAwwHUm9v +dC1jYTAeFw0xODA4MjAxNjIzMjdaFw0xOTA4MjAxNjIzMjdaMBIxEDAOBgNVBAMM +B0ludGVybS4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDE+tZpgnue +FVOMfXwzWMQDXHsKuuhq4jAESHeIkYFEuxTYKXGQbGEO9HBEuhpilpjg5lwOXCxn +lAEESt0DpKAbjVdW3oyzSh2D1ZpCwttuAOu/ds+Y4i3HZg0NCH3+zb14mINTjL1p +vg816X0n6r/u/jPsH5anXArjH9FJUJbaae1mTzupRj2R9AkS0UjJ4jR2sRGbD6M0 +eQE5OagBD7TMuznIjk8wb4HMp0v/HUlf+19FpU6KGkpBnETcW2zvlKWqrLZ4J8qD +cT0bxjufD+cxc0QlLcQpROdyvdCJJXZg9dO3fnGtPhgWeBNiZ5WACKKRkO4YgZIi +oIZQGsI9ayJrAgMBAAGjEDAOMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQAD +ggEBAD1jt/dN2EgRdBkHPqy3nZjYaEVXMGv16tQRp8C8TVPzsbHNafoCKvvMYeWR +MnBlrTXxqbPbJo83/HUEyHO5M16WsvtP2rNPQqMwXMMFQwxC55cCbsZT5PUv6zSg +sLdDH7wocoirU4RYK//2pHxpbAMvnbAmOl5zXpv3TkidiKSIXqS+KdjMF8L/GL0W +auKpJcvlWtTfp07CImeeEqQd4McKRvtaKCdnSR4KwQLz0zDZQ7Hlgr42LQt+y0Hj +uiMFbc1phJgoX9cDfF2u5wJzisRYusmL94suRaxtHr2hpE1CoHfNc8n3yT/jXRY3 +36A94m8qystWW51umYMaUzknPFs= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICtzCCAZ+gAwIBAgIJAKMhcOlV0Y12MA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV +BAMMB1Jvb3QtY2EwHhcNMTgwODIwMTYyMzI2WhcNMjgwODE3MTYyMzI2WjASMRAw +DgYDVQQDDAdSb290LWNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA +wLsU5/bGBw+JQzrOMhzzIhb44QJ+TZWQftXYHe1ayrMiMLn3bV0b2eztyL2O9DaH +N8WkMffl+lZW8xamovsCqdW4DXV9hSu9VoYqeIFHBhuzNmq8NRvAQ8GO3JPkSQwE +PTa4cJXtLYGv7dQzke+gLrjcs1KOxov3cCx6Zb+WFEqWF+9VzJyaXFSlfYQaGf3v +G+grmyoRoxOk/zsGuQFF/UTRci0SyGHrRCLrMAQZf3s3kfo3EDmOQcSYuSAv4LEa +qT3uuGo2Hvb9ElzMc/dC2PIqYCO/c3SHImjURNhCeST0LXq+QS5u/00q9bDWYu5Q +BAYY69Ucpz4eZJLelqnY8QIDAQABoxAwDjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQA41fvjsfuMTg8a0gyQuEbz/U1mrtFeQ/DZ03XK1aVn1MXkrxgH +wbk69WgyT28A+dOsPp9H+YQT3DP2elzWeJqHDQNEB7pL2bw7ZkvOF+0Qt9t0Ddrh +CT/3YAKBDPNRmsYYg92kadQIPGLJHIq2mhfUloFuchuB2HC1VAv9xQ5mKr7XXMwK +6/+NH2PoEWtxv63tAHCOZCjTP9VdY7EcTmjULZUjgJjgMUJCfziuCRXHLv2dr+oy +qXvcnK39318vbWfhBvhdRfLPCEI1Is5OUkL6U39kcXFSiIPJnexjq/7n5ckIi0hB +Spqr1VoqHJ82ovET+vomdiMU9lmq/unVRopx +-----END CERTIFICATE----- diff --git a/tests/fixtures/chain/client.crt b/tests/fixtures/chain/client.crt new file mode 100644 index 00000000..654d058a --- /dev/null +++ b/tests/fixtures/chain/client.crt @@ -0,0 +1,66 @@ +Certificate: + Data: + Version: 1 (0x0) + Serial Number: 4097 (0x1001) + Signature Algorithm: sha256WithRSAEncryption + Issuer: CN=Interm. + Validity + Not Before: Aug 20 16:23:27 2018 GMT + Not After : Aug 20 16:23:27 2019 GMT + Subject: CN=client.example.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:ed:f8:8b:b6:aa:55:fb:92:09:cd:b5:5e:6f:6f: + 1d:32:2b:8e:33:30:77:2e:95:14:e9:88:c3:8d:c6: + ef:02:a4:9a:b5:6d:3a:4e:cf:53:d8:b6:34:d1:27: + 33:64:3a:47:99:73:65:85:af:21:1d:25:ba:9e:e1: + d8:dd:aa:06:5f:72:bd:e0:4b:18:68:4d:82:99:ab: + 80:cd:da:37:96:df:e6:be:a6:e1:68:cf:83:db:73: + 28:34:3f:2a:9d:6f:75:9a:b4:26:25:5a:9d:d1:82: + 81:f6:b2:17:50:af:44:94:d5:17:09:3e:2d:dc:10: + aa:2f:6d:07:5d:19:6f:7a:de:2a:ef:d5:29:3d:c4: + 31:d2:d8:da:b3:db:d3:b4:9b:69:e3:97:d3:5b:43: + 75:93:37:2e:e7:89:f8:7a:6d:bc:49:05:32:ce:1a: + 3e:eb:b0:3b:b2:0f:7d:49:df:94:3b:bf:52:52:17: + 0f:1f:1b:6b:82:f8:c8:b0:d8:18:f3:54:12:3f:b9: + 08:41:6b:89:59:76:0a:ed:ed:1b:a6:8c:3d:54:8f: + 6d:47:f1:fb:62:33:8b:51:fa:ae:48:b1:a0:f7:1f: + 14:e4:e4:e5:e3:22:7f:c6:97:76:6a:4b:ca:a6:84: + 90:02:92:28:fa:ae:f2:c4:c2:67:2c:9d:23:1c:73: + 3e:dd + Exponent: 65537 (0x10001) + Signature Algorithm: sha256WithRSAEncryption + 0e:28:5c:3b:29:99:9d:aa:c4:19:71:cb:94:36:10:8f:f9:7c: + 12:01:83:3e:5f:71:83:c5:76:0f:10:76:15:06:2c:ff:c4:d2: + f7:f7:a3:82:84:f9:6f:e3:dd:14:33:fd:90:8e:30:6d:7c:28: + dd:e7:7a:38:51:09:37:32:41:dd:ed:b7:95:01:76:6a:c3:7d: + f3:c2:23:f3:85:67:8e:82:42:e8:55:48:92:3f:a8:b3:25:b1: + ae:73:5f:07:b8:d6:09:a1:66:1e:57:2b:0d:59:63:47:79:c4: + 0b:eb:d3:f9:04:f6:30:0f:fe:ed:b8:c4:8f:0f:a3:d8:e1:ec: + fb:8b:cb:d3:84:b5:46:23:a5:a9:f8:f0:06:48:85:6e:ac:27: + 30:6a:f5:da:e7:82:53:11:60:0f:64:78:a9:35:75:9d:3f:3f: + f5:85:fe:9b:e5:68:73:6b:18:6c:95:83:d1:cd:c5:8b:f6:9e: + 38:2c:70:e6:06:d5:8c:4b:95:ed:5a:a4:04:26:fa:de:f4:bb: + d7:44:73:a1:cb:fe:f9:ce:9b:c5:9e:1b:12:d3:e1:40:4a:2a: + 64:fc:5d:2c:07:d6:ca:45:42:db:f3:2f:bc:9c:63:b1:37:ef: + 1c:7c:2a:32:4b:88:97:7d:77:f5:66:0b:25:d4:09:c6:39:94: + b4:ee:3e:2c +-----BEGIN CERTIFICATE----- +MIICpDCCAYwCAhABMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNVBAMMB0ludGVybS4w +HhcNMTgwODIwMTYyMzI3WhcNMTkwODIwMTYyMzI3WjAdMRswGQYDVQQDExJjbGll +bnQuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDt ++Iu2qlX7kgnNtV5vbx0yK44zMHculRTpiMONxu8CpJq1bTpOz1PYtjTRJzNkOkeZ +c2WFryEdJbqe4djdqgZfcr3gSxhoTYKZq4DN2jeW3+a+puFoz4Pbcyg0Pyqdb3Wa +tCYlWp3RgoH2shdQr0SU1RcJPi3cEKovbQddGW963irv1Sk9xDHS2Nqz29O0m2nj +l9NbQ3WTNy7nifh6bbxJBTLOGj7rsDuyD31J35Q7v1JSFw8fG2uC+Miw2BjzVBI/ +uQhBa4lZdgrt7RumjD1Uj21H8ftiM4tR+q5IsaD3HxTk5OXjIn/Gl3ZqS8qmhJAC +kij6rvLEwmcsnSMccz7dAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAA4oXDspmZ2q +xBlxy5Q2EI/5fBIBgz5fcYPFdg8QdhUGLP/E0vf3o4KE+W/j3RQz/ZCOMG18KN3n +ejhRCTcyQd3tt5UBdmrDffPCI/OFZ46CQuhVSJI/qLMlsa5zXwe41gmhZh5XKw1Z +Y0d5xAvr0/kE9jAP/u24xI8Po9jh7PuLy9OEtUYjpan48AZIhW6sJzBq9drnglMR +YA9keKk1dZ0/P/WF/pvlaHNrGGyVg9HNxYv2njgscOYG1YxLle1apAQm+t70u9dE +c6HL/vnOm8WeGxLT4UBKKmT8XSwH1spFQtvzL7ycY7E37xx8KjJLiJd9d/VmCyXU +CcY5lLTuPiw= +-----END CERTIFICATE----- diff --git a/tests/fixtures/chain/intermediate.crl b/tests/fixtures/chain/intermediate.crl new file mode 100644 index 00000000..951a9372 Binary files /dev/null and b/tests/fixtures/chain/intermediate.crl differ diff --git a/tests/fixtures/chain/make-chain.sh b/tests/fixtures/chain/make-chain.sh new file mode 100755 index 00000000..eacd1655 --- /dev/null +++ b/tests/fixtures/chain/make-chain.sh @@ -0,0 +1,77 @@ +#!/bin/bash -x +# +# adapted from https://stackoverflow.com/a/40530391 +# +# make-chain.sh: +# 1. creates a root CA and an intermediate CA signed by the root +# 2. creates a client cert signed by the intermediate +# 3. creates a CRL with no revocations +# 4. concatenates the root and intermediate certs into a chain +# 5. cleans up anything we don't need for testing + +set -e + +for C in `echo root-ca intermediate`; do + + mkdir $C + cd $C + cd .. + + echo 1000 > $C/serial + touch $C/index.txt $C/index.txt.attr + + echo ' +[ ca ] +default_ca = CA_default +[ CA_default ] +dir = '$C' # Where everything is kept +certs = $dir # Where the issued certs are kept +crl_dir = $dir # Where the issued crl are kept +database = $dir/index.txt # database index file. +new_certs_dir = $dir # default place for new certs. +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crl = $dir/crl.pem # The current CRL +private_key = $dir/ca.key.pem # The private key +RANDFILE = $dir/.rnd # private random number file +nameopt = default_ca +certopt = default_ca +policy = policy_match +default_days = 365 +default_md = sha256 +default_crl_days = 365 + +[ policy_match ] +countryName = optional +stateOrProvinceName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[req] +req_extensions = v3_req +distinguished_name = req_distinguished_name + +[req_distinguished_name] + +[v3_req] +basicConstraints = CA:TRUE +' > $C/openssl.conf +done + +openssl genrsa -out root-ca/ca.key 2048 +openssl req -config root-ca/openssl.conf -new -x509 -days 3650 -key root-ca/ca.key -sha256 -extensions v3_req -out root-ca/ca.crt -subj '/CN=Root-ca' + +openssl genrsa -out intermediate/intermediate.key 2048 +openssl req -config intermediate/openssl.conf -sha256 -new -key intermediate/intermediate.key -out intermediate/intermediate.csr -subj '/CN=Interm.' +openssl ca -batch -config root-ca/openssl.conf -keyfile root-ca/ca.key -cert root-ca/ca.crt -extensions v3_req -notext -md sha256 -in intermediate/intermediate.csr -out intermediate/intermediate.crt + +openssl req -new -keyout client.key -out client.request -days 365 -nodes -subj "/CN=client.example.com" -newkey rsa:2048 +openssl ca -batch -config root-ca/openssl.conf -keyfile intermediate/intermediate.key -cert intermediate/intermediate.crt -out client.crt -infiles client.request + +openssl ca -gencrl -keyfile intermediate/intermediate.key -cert intermediate/intermediate.crt -out intermediate.pem.crl -config intermediate/openssl.conf +openssl crl -inform pem -outform der -in intermediate.pem.crl -out intermediate.crl + +cat intermediate/intermediate.crt root-ca/ca.crt >> ca-chain.pem +rm -r client.key client.request intermediate.pem.crl intermediate/ root-ca/ diff --git a/tests/forms/test_request.py b/tests/forms/test_request.py index 5f55a561..2a31ee3a 100644 --- a/tests/forms/test_request.py +++ b/tests/forms/test_request.py @@ -32,7 +32,11 @@ class TestRequestForm: assert request_form.errors == {"cloud_native": ["Not a valid choice"]} def test_require_migration_questions_when_migrating(self): - extra_data = {"jedi_migration": "yes"} + extra_data = { + "jedi_migration": "yes", + "data_transfers": "", + "expected_completion_date": "", + } request_form = RequestForm(data={**self.form_data, **extra_data}) assert not request_form.validate() assert request_form.errors == { @@ -40,8 +44,8 @@ class TestRequestForm: "technical_support_team": ["Not a valid choice"], "organization_providing_assistance": ["Not a valid choice"], "engineering_assessment": ["Not a valid choice"], - "data_transfers": ["Not a valid choice"], - "expected_completion_date": ["Not a valid choice"], + "data_transfers": ["This field is required."], + "expected_completion_date": ["This field is required."], } def test_require_organization_when_technical_support_team(self):