diff --git a/signxml/__init__.py b/signxml/__init__.py index 2e96753..d5777f6 100644 --- a/signxml/__init__.py +++ b/signxml/__init__.py @@ -24,7 +24,8 @@ ec="http://www.w3.org/2001/10/xml-exc-c14n#", dsig_more="http://www.w3.org/2001/04/xmldsig-more#", xenc="http://www.w3.org/2001/04/xmlenc#", - xenc11="http://www.w3.org/2009/xmlenc11#" + xenc11="http://www.w3.org/2009/xmlenc11#", + xades="http://uri.etsi.org/01903/v1.3.2#" ) def ds_tag(tag): @@ -586,6 +587,13 @@ def _get_signature(self, root): else: return self._find(root, "Signature", anywhere=True) + def _get_certificates(self, signature, x509_data): + certs = [cert.text for cert in self._findall(x509_data, "X509Certificate")] + encapsulated_path = "ds:Object/xades:QualifyingProperties//xades:EncapsulatedX509Certificate" + for encapsulated in signature.findall(encapsulated_path, namespaces=namespaces): + certs.append(encapsulated.text) + return certs + def _verify_signature_with_pubkey(self, signed_info_c14n, raw_signature, key_value, der_encoded_key_value, signature_alg): if der_encoded_key_value is not None: @@ -823,7 +831,7 @@ def verify(self, data, require_x509=True, x509_cert=None, cert_subject_name=None if self.x509_cert is None: if x509_data is None: raise InvalidInput("Expected a X.509 certificate based signature") - certs = [cert.text for cert in self._findall(x509_data, "X509Certificate")] + certs = self._get_certificates(signature, x509_data) if len(certs) == 0: x509_iss = x509_data.find("ds:X509IssuerSerial/ds:X509IssuerName", namespaces=namespaces) x509_sn = x509_data.find("ds:X509IssuerSerial/ds:X509SerialNumber", namespaces=namespaces) diff --git a/test/cert-chain/Makefile b/test/cert-chain/Makefile new file mode 100644 index 0000000..d5ad4bf --- /dev/null +++ b/test/cert-chain/Makefile @@ -0,0 +1,4 @@ +all: + ./generate.sh +clean: + rm -f intermediate.* leaf.* root.* diff --git a/test/cert-chain/config.ext b/test/cert-chain/config.ext new file mode 100644 index 0000000..03986d4 --- /dev/null +++ b/test/cert-chain/config.ext @@ -0,0 +1,23 @@ +[req] + +req_extensions = root +distinguished_name = req_distinguished_name + +[req_distinguished_name] + +[root] +keyUsage = keyCertSign,cRLSign +subjectKeyIdentifier = hash +basicConstraints = critical, CA:true + +[intermediate] +basicConstraints = critical, CA:true, pathlen:0 +extendedKeyUsage = clientAuth,emailProtection +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid + +[leaf] +keyUsage = critical,digitalSignature,keyEncipherment +basicConstraints = critical,CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid diff --git a/test/cert-chain/generate.sh b/test/cert-chain/generate.sh new file mode 100755 index 0000000..a2164a0 --- /dev/null +++ b/test/cert-chain/generate.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -eu + +# This script generates three certificates: +# 1. A self-signed root certificate authority +# 2. An intermediate certificate authority +# 3. A leaf certificate, intended for signing/verifying XML signatures + +# Generate private key and self-signed certificate for certificate authority +openssl genrsa -out root.key 2048 +openssl req -new -key root.key -out root.csr -subj "/CN=root.example.com" +openssl x509 -req -in root.csr -out root.crt -signkey root.key -CAcreateserial -days 3650 -sha256 -extfile config.ext -extensions root + +# Generate private key for intermediate certificate +openssl genrsa -out intermediate.key 2048 + +# Generate intermediate certificate request +openssl req -new -key intermediate.key -out intermediate.csr -subj "/CN=intermediate.example.com" + +# Generate intermediate certificate based on request +openssl x509 -req -in intermediate.csr -out intermediate.crt -CA root.crt -CAkey root.key -CAcreateserial -days 3650 -sha256 -extfile config.ext -extensions intermediate + +# Generate private key for leaf certificate +openssl genrsa -out leaf.key 2048 + +# Generate leaf certificate request +openssl req -new -key leaf.key -out leaf.csr -subj "/CN=leaf.example.com" + +# Generate leaf certificate based on request +openssl x509 -req -in leaf.csr -out leaf.crt -CA intermediate.crt -CAkey intermediate.key -CAcreateserial -days 3650 -sha256 -extfile config.ext -extensions leaf diff --git a/test/cert-chain/intermediate.crt b/test/cert-chain/intermediate.crt new file mode 100644 index 0000000..de63c66 --- /dev/null +++ b/test/cert-chain/intermediate.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDNjCCAh6gAwIBAgIJAPWimSdeOwH3MA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV +BAMMEHJvb3QuZXhhbXBsZS5jb20wHhcNMjIwNDA0MTI1ODM0WhcNMzIwNDAxMTI1 +ODM0WjAjMSEwHwYDVQQDDBhpbnRlcm1lZGlhdGUuZXhhbXBsZS5jb20wggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDG/kwWE285/2ExkQfmdY75L7Dl08pp +uXG1WswmEdziM2HcAhLtOWUWzrIl/nSyVE05u3tx7Ylv1aG5bkSxcRJR8CqRIbuJ +OM+zQCWeJd4JHIsXQOB4MZKgOHLHbyzeIrbMhi1Hliv+khsR4CBkrKQFrgqn8IjC +w32PAgqgBeMM9rnNkWLe4T1TWbgSbtuVP2+EEYG6NpQ0j5dl6QjEd/lWbh4itlwh +EO5otrZbrRmEYwIutZhfUJwkHIojOLvWvOLRvx20h6pS3xsA+V0DQqyQeT2E0gdS +c6Sqkiol2xh1v6cQzXVdIKCIQnK5yIU3Y2KNy0ni9Jqvp2DJYGXfzq9NAgMBAAGj +dTBzMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsG +AQUFBwMEMB0GA1UdDgQWBBTWzCF4+GsA/dxOPPKtpo/jYDwbtTAfBgNVHSMEGDAW +gBTA2CuH0iKWFP743/WvxRSV4KuO7DANBgkqhkiG9w0BAQsFAAOCAQEAIXsgm9/f +iaeUHR32L6KrMwmP552YS4Ds546AUdvdem/xgtfEOZMLjdKFNUGom7c85Qx8p1N0 +RGjISDL25RBhRFq3NEURAcF+bFwMtheCvFZwl2B2akOw/4EakApXDxHrTfDulcCx +KNvZPT+5E7jkkScTcbDecPzFpJgJtkpIvR0CUyygHgueYvt759qIoOt1mkqP6HQr +OgZiFe+5iyA5YepJo7FKqf6xGnq1U5o/DpXEm5wvnkt/QPN9u4yUOeBPJpaQ+Fpc +Tw2InPCzYyaiKIPKeYHf28ZskbPcUDh8r9+N5GqanrmKUYxLqBFjZOhQxFZFhNw0 +81bA+LF0vJLJ6g== +-----END CERTIFICATE----- diff --git a/test/cert-chain/intermediate.csr b/test/cert-chain/intermediate.csr new file mode 100644 index 0000000..0c69682 --- /dev/null +++ b/test/cert-chain/intermediate.csr @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICaDCCAVACAQAwIzEhMB8GA1UEAwwYaW50ZXJtZWRpYXRlLmV4YW1wbGUuY29t +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxv5MFhNvOf9hMZEH5nWO ++S+w5dPKablxtVrMJhHc4jNh3AIS7TllFs6yJf50slRNObt7ce2Jb9WhuW5EsXES +UfAqkSG7iTjPs0AlniXeCRyLF0DgeDGSoDhyx28s3iK2zIYtR5Yr/pIbEeAgZKyk +Ba4Kp/CIwsN9jwIKoAXjDPa5zZFi3uE9U1m4Em7blT9vhBGBujaUNI+XZekIxHf5 +Vm4eIrZcIRDuaLa2W60ZhGMCLrWYX1CcJByKIzi71rzi0b8dtIeqUt8bAPldA0Ks +kHk9hNIHUnOkqpIqJdsYdb+nEM11XSCgiEJyuciFN2NijctJ4vSar6dgyWBl386v +TQIDAQABoAAwDQYJKoZIhvcNAQELBQADggEBAHePfNLKAIBfBNSEVBcR1bqSfY3p +h6/PXsfHeyWH3pMj2ADwRifHs4RrK4SvbEkgFr6gHKccBpHeweNQLeru0wg1/DLI +ZKPswMOfQ+U3wGYLMahMYXvdpECSBiIPMHVlwPzy4kpy+WkC9y661J8epNaglmjI +9YUn6ygOpkYmhcuZGP5oANH/9FvF0w0bc+qwlciawzYkBKNPo0umFifKh1epKj+E +sQu9u6SHtjiaerg1o4mFLwUU8jRjx+Xrns9NNXafdBp1wLh9OZAPwXJl+IWKbfYk +ZrYTwIm255zBuqpoot4m0bSsfzDlhPtgvERMmhevkrLS4sbERGMYMzqvVtg= +-----END CERTIFICATE REQUEST----- diff --git a/test/cert-chain/intermediate.key b/test/cert-chain/intermediate.key new file mode 100644 index 0000000..9f30c8d --- /dev/null +++ b/test/cert-chain/intermediate.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAxv5MFhNvOf9hMZEH5nWO+S+w5dPKablxtVrMJhHc4jNh3AIS +7TllFs6yJf50slRNObt7ce2Jb9WhuW5EsXESUfAqkSG7iTjPs0AlniXeCRyLF0Dg +eDGSoDhyx28s3iK2zIYtR5Yr/pIbEeAgZKykBa4Kp/CIwsN9jwIKoAXjDPa5zZFi +3uE9U1m4Em7blT9vhBGBujaUNI+XZekIxHf5Vm4eIrZcIRDuaLa2W60ZhGMCLrWY +X1CcJByKIzi71rzi0b8dtIeqUt8bAPldA0KskHk9hNIHUnOkqpIqJdsYdb+nEM11 +XSCgiEJyuciFN2NijctJ4vSar6dgyWBl386vTQIDAQABAoIBABkjUMtNIzTpbQbM +8nmLikcyXh96dMyMT7AAS1/Xy9aLdSZM4MU1Be8up1SjY2yPt72+UGbhAgatryN0 +qZrc1NqjA02YPE+mbJ6RUO88i2MNRwjl+jVU1dgFqYJGKh3Ztsv5e0ja0K31GRRW +AuGU6ZeKF/CFM1GfToI9WMhEVh1x6JF9CRpjvrBtayrVM11TyE5Du6nbmvOJqd84 +8IjOqWtckQNwJTk4r1cVn2/jTrwZEvIW3q1xRcOYnMQ+dA0M2/9JoEfEvbjOYp8X +RlBgdVRRLae4xuAykD/NdvlXGRBRUvnnxm1LtokxzpKDJ2MDdmW9ZBaOP1hHvlvB +dqAyTgUCgYEA6cKS9TxyBqFkT5rPTGLHOjVmTvsDNzbFXkV9QPkspahuZCGvr3Z+ +ExfIzm0LlZ0f+qohjDp9sOJx64VyPQAM0f249RKoPwehXrRTCXAWj4AIF1Km+Gwa +U8dq4+I10Y8D3NAyfC79T4ofUYn90v8kxOsLmLbe7Kkt8m5TApSJPr8CgYEA2ezz +Rzd7NXP1HIQaruAe6wBP63w3U73LSvDmfCMDRcOk/bD3Ecyu2rRvqvhJTryQpCll +bMOjimoB7lYvX1hIcio217qr06MtzDWV3RgUl1269b6xjHkmrvhvsyUvg9W+34Tz +JsmTmRLn7AXHHMU4itwtQK5Y2DeLUJ/jqa6f4PMCgYAymHvIesnPZ5VXqZFe3i5z +CeXYCHqcs80qZ24B5yzjuj4SjDwDhWkqZsZ+75lHS9gFIFfcizhzVcAEk0CztVQR +C5LB8MTbx6IE5pDmhQ1NCBA4RBqBwJw+L/aR1n+BmSvj2mhi+qS3V5UJyA1ZYwIp +YRqEdmhv3vpj878h2taN7wKBgQCbu9s2v41K66z0TeuLoRo3Mifqzv/y1iUbTwBH +IfZKur+DlB1cGPuzy1IpyfkJTXPH/NVAXqbWWV875VdBOaO8AjLjA8GbIneuAXUx +ZO4CJbdfuoDDNCjSzTN1wFMuUWdv8GCbDV5u+7XFU3OxObdodGPaXz2adkcWvMxD +DEmwxQKBgGrNk3a+ZMwrNFUKd26ay0Zs6OY8Uhbr2Hj10Lk+DKWNyxHd4XnCywr1 +CuGgBbIFDtS5yrLiK9lqKE9tWkMT+NHn+dvPmv3HSLxqbK/obCwPKVS09d3or2Xv +hdBd18clnYN44dwpLtHwzbzgRL26FSu/Gt4KAYcR1TN5I/90bFEW +-----END RSA PRIVATE KEY----- diff --git a/test/cert-chain/intermediate.srl b/test/cert-chain/intermediate.srl new file mode 100644 index 0000000..0592848 --- /dev/null +++ b/test/cert-chain/intermediate.srl @@ -0,0 +1 @@ +815A6E9E93988530 diff --git a/test/cert-chain/leaf.crt b/test/cert-chain/leaf.crt new file mode 100644 index 0000000..e6021ef --- /dev/null +++ b/test/cert-chain/leaf.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDITCCAgmgAwIBAgIJAIFabp6TmIUwMA0GCSqGSIb3DQEBCwUAMCMxITAfBgNV +BAMMGGludGVybWVkaWF0ZS5leGFtcGxlLmNvbTAeFw0yMjA0MDQxMjU4MzRaFw0z +MjA0MDExMjU4MzRaMBsxGTAXBgNVBAMMEGxlYWYuZXhhbXBsZS5jb20wggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC7/fHkBOM7nhKA2IowLhAA1gvddUIE +1t00x3AT2tsl2fZo2YiODiaHauNVTtv5oigCQxR9yITpxfibgTHYnyojjeUrJPvR +zEaFAchoYRFtlyRyjxRRlBBl94edCDB5JPnkxCp3WzRVH2b5gg0Bxb6lgR1qZsfU +/sYlxYFf32V34Rfqltwp7u/vSIiQX9k/+GftQ5yXQc9dhvrS8ebj7AktA2v5e/tI +pdaxgfKAFNAvw05nVXP7a8t+JM+45gSicemXV3EbJr3CnahIsUK+cdOrgdp9A+6k +2uH0G2UqVHaAVBsvyEnIti1qSG+dlOrYR0toJ5Hj4fxwBYjkIHZTV4LdAgMBAAGj +YDBeMA4GA1UdDwEB/wQEAwIFoDAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBRLRYy6 +MzS9gPt1zHOc8s9bw/t7njAfBgNVHSMEGDAWgBTWzCF4+GsA/dxOPPKtpo/jYDwb +tTANBgkqhkiG9w0BAQsFAAOCAQEAwGQ0mTu5SZ7rvvKiaSCoZrvUov5nncovYATd +tvHDpC+0HCtvg2vSw6kmJXjc8XHsoNiIWFYO0qAZTVlJMUVzlTWVjQjeaiHokKTn +10I+dakBQdnxAcafipCfTjL52y2uQxBDykJf8gjuIgXAxnIPV83ye1E7fiDlW8xp +tbLx0uv7m1U8BurH26rSbrI+/msT3O+flOY66JKCl0wNl/ZVWPNSKxGmoS0DPD0k +OKURGlhkcUugIkYYrlnfrw7bUAVUUJ7iv4KDdGc6ecjyH4ydf9zOnoMKbekeXZ6c +zLXYEZ5D/itoPEs4YazZjipyfz9bxX144JPt9Y9iw2609Rx05g== +-----END CERTIFICATE----- diff --git a/test/cert-chain/leaf.csr b/test/cert-chain/leaf.csr new file mode 100644 index 0000000..abf95cd --- /dev/null +++ b/test/cert-chain/leaf.csr @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICYDCCAUgCAQAwGzEZMBcGA1UEAwwQbGVhZi5leGFtcGxlLmNvbTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALv98eQE4zueEoDYijAuEADWC911QgTW +3TTHcBPa2yXZ9mjZiI4OJodq41VO2/miKAJDFH3IhOnF+JuBMdifKiON5Ssk+9HM +RoUByGhhEW2XJHKPFFGUEGX3h50IMHkk+eTEKndbNFUfZvmCDQHFvqWBHWpmx9T+ +xiXFgV/fZXfhF+qW3Cnu7+9IiJBf2T/4Z+1DnJdBz12G+tLx5uPsCS0Da/l7+0il +1rGB8oAU0C/DTmdVc/try34kz7jmBKJx6ZdXcRsmvcKdqEixQr5x06uB2n0D7qTa +4fQbZSpUdoBUGy/ISci2LWpIb52U6thHS2gnkePh/HAFiOQgdlNXgt0CAwEAAaAA +MA0GCSqGSIb3DQEBCwUAA4IBAQCILxnkHMMCuY4uNEOXo2KQ56KKoWjGf0w1hpHX +z/8xR/Jqb8tvTYv8IC7u0fjcFndZjJKyqjKN4g/8iJVo5TK+PKVFuajGkJjlpH5n +NcGc8ZTYFGophGsRS1YbpQJ4Waz6CtyZutAYowMzuP4X1l6+Jkggjo7V0ePUMODi +zuLerM8OO5zQav4ypEhGP6S++SnIUU2OI1mnrJl9Th0Ni0ij5bAy2XUWAOiWvXmr +NqHdPAUqZhhwr+kQ+hekjTuY+Zm7QDn+cUNAP3zysu0CMR8zHwGx6FhN3wGyupE2 +TK86NZJZhC4cUbztvPmk/r2BlUzqD52/CknqmUjEfmEm9L1h +-----END CERTIFICATE REQUEST----- diff --git a/test/cert-chain/leaf.key b/test/cert-chain/leaf.key new file mode 100644 index 0000000..285e205 --- /dev/null +++ b/test/cert-chain/leaf.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAu/3x5ATjO54SgNiKMC4QANYL3XVCBNbdNMdwE9rbJdn2aNmI +jg4mh2rjVU7b+aIoAkMUfciE6cX4m4Ex2J8qI43lKyT70cxGhQHIaGERbZckco8U +UZQQZfeHnQgweST55MQqd1s0VR9m+YINAcW+pYEdambH1P7GJcWBX99ld+EX6pbc +Ke7v70iIkF/ZP/hn7UOcl0HPXYb60vHm4+wJLQNr+Xv7SKXWsYHygBTQL8NOZ1Vz ++2vLfiTPuOYEonHpl1dxGya9wp2oSLFCvnHTq4HafQPupNrh9BtlKlR2gFQbL8hJ +yLYtakhvnZTq2EdLaCeR4+H8cAWI5CB2U1eC3QIDAQABAoIBACbVZHx3zgDovGXF +VXZybXfev4C10jdxsyxN7ocLdK2zAsXR+fVuUuMyX1el/Kbqql0dQkRhgaNQ8/Qb +khJvfqLtkuOAtkw2aHLdVWrKcnEzAaJwj//yGBkYMvlrUagUzVJGe4dAXeUfoYP1 +K36sPJ+vtkXeiXUkVAZFcF4/pZRHnnJTGgIUob+Ensf9KaIpnwyqHA3eCMAWmGyL +uN4+ZBZ1HvyVD6MQ0iq9nvCWTAfFm3nrYHushAH7OuwcH6ys/WvOnDhq+hODMJkt +jDwFG0ki1oNzTWcewxkiMdV1JdKVyehtkE+KKsXly+Y/51vwggxx4LJO+mesWaFB +SBjoLrkCgYEA6uoz2vf30XVRwc5EAsDsrEH042nm7t/pwZqXSoIwZg/MXWec7Q8n +InWnjeb9lR9DEMjUm2PZYMCXp0WRDP0B51FiewD+yd32Hkx9w82PaYZCQMft9VLE +EyILQWWB3ILYaa+WiuV1s6z6dvpuZglByeF1exI3Ty2t1WZ6MNxULIsCgYEAzN2Q +RK46XYTF+860JN74WLpgJQA8FIcoM0x4nN/C7hgWKhulkNnD4+60lFwtkgKXGQ6C +KYGBGgY3jjKHAbDsDg7QxIBcBVGWobDmWvHrA0WenAv17LgCa0gcaapxpWD+Wa4K +oFi1yR8OoKFqHA08r065Z49gFVN15O2nTgIu8zcCgYEAq0E7tnkph+BwTspxWFSO +9XFL9vIAccp43jQ18RKB+BWyVbGwfD2cuQlusgtgeHMG8FiIbhPXqCofJMmZWg+k +cJ8rHSL3m/CdeS8oTDMyRqqi6BkYh8zjtlMOQ4mdp0UYQcvJAs8PBIKpQU2GaAp9 +lJAxlhwMiENzw+vmTnKBRssCgYA2+q8g/3ECcAOCFHMcAgq8JShwRaPaDnunaLpl +v1dc9nHcUxcXzJlZrlIgDqzcJn3OZ6pe4TZ4eXqnWsAIoCZ5j1hPo/MOKls2gXcQ +qSPc+O4cCsmxAaEEkZGueeON8n3QK3kGl0gR9ZfDXA5SAOtsUMBJHp02m/NjwLPJ +p6RZ+QKBgQC/aM9VOFd33vkjcOAL/0PsgF9qqPf5tbOU+StwM/oK9W7s1G0h6M4g +TvGOJb2ZAH35R+cgrcZZ7m5Koddnoocu8Y/I7A0aXAUiH5dHvK3ou8OMknPgqa3K +R9AdkJJt9UYUsq8hqhR4kKetoKr4hhm8rffqxQ8fiUedqAbq9KP59A== +-----END RSA PRIVATE KEY----- diff --git a/test/cert-chain/root.crt b/test/cert-chain/root.crt new file mode 100644 index 0000000..7be2e4a --- /dev/null +++ b/test/cert-chain/root.crt @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC+DCCAeCgAwIBAgIJAK8CuHZ8q/VTMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV +BAMMEHJvb3QuZXhhbXBsZS5jb20wHhcNMjIwNDA0MTI1ODM0WhcNMzIwNDAxMTI1 +ODM0WjAbMRkwFwYDVQQDDBByb290LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAyH2fpTMLu2USKAZzFLLM3virbctKkbS8A38ZNKKT +GyodwUuIYGHG1kf1RtIXnrXg5xG/XndeNciZWFJFgYKjxwn4YutRlGjnywan7pMM +LS+IuBJx4XIsRoP05+vyt0t3V/ntphGwuyZBZWLpj+DZm2HfbeYob4NrcaaUbmXv +x7xsLMwuNYcQZiSf3uUPq7/fWmRhIFczoQRUzVicZdmH2WRaiXdPdX9XHys9C4LQ +RdF+Ge6GAMdAF7lMhG518OXZu2g8aViysaBs7wUAnOAGJScDmfe7gL4AbZAPh1VR +i4Q8c/hPtY6/UUUmy1cYLsH80G/c/j2AGHdCC0q31Cst9wIDAQABoz8wPTALBgNV +HQ8EBAMCAQYwHQYDVR0OBBYEFMDYK4fSIpYU/vjf9a/FFJXgq47sMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHFci3DC44wA7/qQ6BJUSk8ThuDY +p6QBO/xIc/6gUq+9119Vs29E8yLj79qp66r5i4dWAYI//jgLY2o5piq53F1KJG47 +dduIoycnpRMXo+/Ko4ZKJSraz3wyAWi6ifhUg9xID8Id8c+iKp2M1CcaYsjJUkGX +XrthBSLTezE/t/Wv2rUVO85LvqrTDFQCdPUnYuEYhstIIc0H9Gv/vjxFB0nWYjoR +KSXZgXeH6weoOvJ5+ExuU7MJLPHAavg4PXsP5SsuVcIlWXgV5qVeqrbx1tueJmFc ++YcKyBysH+2nP16rg2/l0YXN8shEm0rN/dnndO2M8zNsYi+s/If3XfPHyfI= +-----END CERTIFICATE----- diff --git a/test/cert-chain/root.csr b/test/cert-chain/root.csr new file mode 100644 index 0000000..0939e7b --- /dev/null +++ b/test/cert-chain/root.csr @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE REQUEST----- +MIICYDCCAUgCAQAwGzEZMBcGA1UEAwwQcm9vdC5leGFtcGxlLmNvbTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBAMh9n6UzC7tlEigGcxSyzN74q23LSpG0 +vAN/GTSikxsqHcFLiGBhxtZH9UbSF5614OcRv153XjXImVhSRYGCo8cJ+GLrUZRo +58sGp+6TDC0viLgSceFyLEaD9Ofr8rdLd1f57aYRsLsmQWVi6Y/g2Zth323mKG+D +a3GmlG5l78e8bCzMLjWHEGYkn97lD6u/31pkYSBXM6EEVM1YnGXZh9lkWol3T3V/ +Vx8rPQuC0EXRfhnuhgDHQBe5TIRudfDl2btoPGlYsrGgbO8FAJzgBiUnA5n3u4C+ +AG2QD4dVUYuEPHP4T7WOv1FFJstXGC7B/NBv3P49gBh3QgtKt9QrLfcCAwEAAaAA +MA0GCSqGSIb3DQEBCwUAA4IBAQDHoXzoTB/nnM16ssKMCsgo9kB33YX788bfSyqb +ZX1+YEbSrU0W21/bvX34Rlv2bELyR5UWQaVP+o9PCPVzsBCB9UivhqgVAUaPqWzq +riFs/mqT3Tu4CbOLFTCy4Y4jvsNMg/oTB/BUoL8kSdZRBeFSgoTf9fias/4ypiZS +1XML7KEKP5ffwZYtZCQpqkhY4gofInWmZwDFsnnPiSJ72pCaZ6pLBZ4Ha9UzhrJW +saYiFAI9v7qPCAtOPaMS7GzPr3D1n4r8ufRGW3aPAY6H2tijsMR7tVQdnFpOvfRZ +uqDGzEF9AoCq+g8+sctPz673x/EgHHT8HXU8FfWsaX8AnsBL +-----END CERTIFICATE REQUEST----- diff --git a/test/cert-chain/root.key b/test/cert-chain/root.key new file mode 100644 index 0000000..e32cb1c --- /dev/null +++ b/test/cert-chain/root.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAyH2fpTMLu2USKAZzFLLM3virbctKkbS8A38ZNKKTGyodwUuI +YGHG1kf1RtIXnrXg5xG/XndeNciZWFJFgYKjxwn4YutRlGjnywan7pMMLS+IuBJx +4XIsRoP05+vyt0t3V/ntphGwuyZBZWLpj+DZm2HfbeYob4NrcaaUbmXvx7xsLMwu +NYcQZiSf3uUPq7/fWmRhIFczoQRUzVicZdmH2WRaiXdPdX9XHys9C4LQRdF+Ge6G +AMdAF7lMhG518OXZu2g8aViysaBs7wUAnOAGJScDmfe7gL4AbZAPh1VRi4Q8c/hP +tY6/UUUmy1cYLsH80G/c/j2AGHdCC0q31Cst9wIDAQABAoIBAAKKzT5sAkcTBgLp +6gWmKsDdCFdxD3X/g67LqscnFJRwmUX9LjKCquHGsc5/FXuWtM5ZRELvYotuCru6 +91SoEmmQr8yZTUSDfATwBasZxDrCcopa+YSxTOxr+ewC6uX2GAJOkfvcF5CX8JZX +hbykTj4RJKMhGvwm/3LGePVZZ4vxyvJMP5cCAnttd1a5Z8p3mDWHwv/NjcF9GKa+ +eoEdMTsO6hq1uXS+Trpq8/Vw1MJviMnMNYl088ChN/dvI/FuHkOR8U4O5XM8hhjm +7XEMV4sCxW6g6kRpNm87B6XMaCMWAo7a0BA3uw4W03icE9p1TyovEekbvY8+h8Ym +BEbQoxkCgYEA5q7DyP2Edh/lAhM7xorELyZJ9AHBYq/F7YpSzzlXFKcEEHxCbkpx +Md3X5pFYOf927gKXiM3GfODASMT8735/xNYRs18VHeyqBV7/a7YP4XfNW4yZBQGk +5WRg8Ggy8qcdO7keuiySn1KLIyKcs4T2wtaBy1+lFmDNQmWn2riGSSUCgYEA3n6W +wUAkpYm66dQOyaFTlfrQBSDhHo+iLCm4tZQcruI8MiNwl7SGJQgfxn2eqjd56o8t +TCqI3JrLPNir8NxaeDAiNAO7kaXbMTZeMqMbIN8o2JpbDFhxQlTTDGH3keD35uTw +tsvl3EbZkndE4PSaXFPP2X9HzYjPk52w51NuFesCgYEAiHkUMzBo0UmFPnkKgCdQ +cWSBk+4F7tB2lFWlMBuIPRuh9+7LjlxUI2BPfoS2YXmVbrHx3GmA6Bg/Kc4Apd98 +z4Kl7ixuXcnJvGu7SInpU0aBI4xGawPR/jQodZHvskbTsKWQXCxKgh9fWWX8tugO +5K3rE9p93INga8ugRnGsYFECgYBKQDaxUWWpdNhS1nkE4vjREX3AaGOYXljBoj7J +Ih+cYVWzac5WYmFuFFL+W8fKiG8ATz3PsFYyQNpYePqQjAkJGQ8hCqnbBl2rA7jV +70bLZo3sEz8VVKKff01bUYpcPZadkIOgjVUteNt9HJ548EhfTX0M2YQt3F1hpvt1 +h4sydwKBgQDXXScbgU7dCGcXyQD0Bk1qoDLHv5aKtjiyC3LC5wU87g3ULq4K/eKK +5CFJ27icBz4reBu7CqZhidsJWeoWKnCXibBv+oVkiXoLjkRfSKDVmKBDhSEZHv78 +cbveKuFULjoMtg76o1JtAGgQXW5dEZtMoyuu+FNnY/RHs+cZfGR5Yw== +-----END RSA PRIVATE KEY----- diff --git a/test/cert-chain/root.srl b/test/cert-chain/root.srl new file mode 100644 index 0000000..0f982dd --- /dev/null +++ b/test/cert-chain/root.srl @@ -0,0 +1 @@ +F5A299275E3B01F7 diff --git a/test/test.py b/test/test.py index a56eac7..1aa1708 100755 --- a/test/test.py +++ b/test/test.py @@ -22,6 +22,24 @@ def reset_tree(t, method): continue s.getparent().remove(s) +def extract_pem(pem): + r = re.sub(r"-+BEGIN CERTIFICATE-+(.*?)-+END CERTIFICATE-+", r"\1", pem, flags=re.DOTALL) + r = re.sub(r"[ \t\r\n]", "", r, count=0, flags=re.DOTALL) + return r + +# See https://www.w3.org/TR/XAdES/#Syntax_forXAdES-X-L_form +def add_certificate_path(signature_elem, certs): + object_elem = etree.SubElement(signature_elem, "{http://www.w3.org/2000/09/xmldsig#}Object") + qprop_elem = etree.SubElement(object_elem, "{http://uri.etsi.org/01903/v1.3.2#}QualifyingProperties") + usprop_elem = etree.SubElement(qprop_elem, "{http://uri.etsi.org/01903/v1.3.2#}UnsignedProperties") + ussigprop_elem = etree.SubElement(usprop_elem, "{http://uri.etsi.org/01903/v1.3.2#}UnsignedSignatureProperties") + certvalues_elem = etree.SubElement(ussigprop_elem, "{http://uri.etsi.org/01903/v1.3.2#}CertificateValues") + + for cert in certs: + cert_elem = etree.SubElement(certvalues_elem, "{http://uri.etsi.org/01903/v1.3.2#}EncapsulatedX509Certificate") + cert_elem.text = cert + + class URIResolver(etree.Resolver): def resolve(self, url, id, context): print("Resolving URL '%s'" % url) @@ -174,6 +192,35 @@ def test_x509_certs(self): XMLVerifier().verify(signed_data) # TODO: negative: verify with wrong cert, wrong CA + def test_x509_cert_chain(self): + from OpenSSL.crypto import load_certificate, FILETYPE_PEM, Error as OpenSSLCryptoError + + tree = etree.parse(self.example_xml_files[0]) + root_filename = os.path.join(os.path.dirname(__file__), "cert-chain", "root.crt") + with open(root_filename, "r") as fh: + root_cert = fh.read() + with open(os.path.join(os.path.dirname(__file__), "cert-chain", "intermediate.crt"), "r") as fh: + intermediate_cert = fh.read() + with open(os.path.join(os.path.dirname(__file__), "cert-chain", "leaf.crt"), "r") as fh: + leaf_cert = fh.read() + with open(os.path.join(os.path.dirname(__file__), "cert-chain", "leaf.key"), "r") as fh: + leaf_key = fh.read() + + certs = [root_cert, intermediate_cert, leaf_cert] + method = methods.enveloped + hash_alg = "sha256" + data = tree.getroot() + signer = XMLSigner(method=method, signature_algorithm="rsa-" + hash_alg) + signed = signer.sign(data, key=leaf_key, cert=leaf_cert) + + signature_elem = signed.find("{http://www.w3.org/2000/09/xmldsig#}Signature") + add_certificate_path(signature_elem, certs) + signed_data = etree.tostring(signed) + + with self.assertRaisesRegex(InvalidCertificate, "unable to get local issuer certificate"): + XMLVerifier().verify(signed_data) + XMLVerifier().verify(signed_data, ca_pem_file=root_filename) + def test_xmldsig_interop_examples(self): ca_pem_file = os.path.join(os.path.dirname(__file__), "interop", "cacert.pem").encode("utf-8") for signature_file in glob(os.path.join(os.path.dirname(__file__), "interop", "*.xml")):