From: Douglas Bagnall Date: Wed, 6 Aug 2025 02:01:14 +0000 (+1200) Subject: samba-tool: add user keytrust command X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2681fe5df87db07b080e12fa7aeaaea0a0518546;p=thirdparty%2Fsamba.git samba-tool: add user keytrust command This allows manipulation of key credential links for users. See `man -l bin/default/docs-xml/manpages/samba-tool.8` for documentation. Signed-off-by: Douglas Bagnall Reviewed-by: Gary Lockyer --- diff --git a/python/samba/netcmd/user/__init__.py b/python/samba/netcmd/user/__init__.py index fab657c2278..e73f2d323e0 100644 --- a/python/samba/netcmd/user/__init__.py +++ b/python/samba/netcmd/user/__init__.py @@ -27,6 +27,7 @@ from .disable import cmd_user_disable from .edit import cmd_user_edit from .enable import cmd_user_enable from .getgroups import cmd_user_getgroups +from .keytrust import cmd_user_keytrust from .list import cmd_user_list from .move import cmd_user_move from .password import cmd_user_password @@ -52,6 +53,7 @@ class cmd_user(SuperCommand): subcommands["delete"] = cmd_user_delete() subcommands["disable"] = cmd_user_disable() subcommands["enable"] = cmd_user_enable() + subcommands["keytrust"] = cmd_user_keytrust() subcommands["list"] = cmd_user_list() subcommands["setexpiry"] = cmd_user_setexpiry() subcommands["password"] = cmd_user_password() diff --git a/python/samba/netcmd/user/keytrust.py b/python/samba/netcmd/user/keytrust.py new file mode 100644 index 00000000000..c72e304d9cd --- /dev/null +++ b/python/samba/netcmd/user/keytrust.py @@ -0,0 +1,223 @@ +# samba-tool commands to manager Key Credential Links on a user +# +# Copyright © Douglas Bagnall 2025 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import ldb +import samba.getopt as options +from samba.domain.models import User +from samba.domain.models.exceptions import ModelError +from samba.netcmd import Command, CommandError, Option, SuperCommand +from samba.netcmd import exception_to_command_error +from samba.key_credential_link import (create_key_credential_link, + kcl_in_list, + filter_kcl_list) + + +class cmd_user_keycredentiallink_add(Command): + """Add a key-credential-link.""" + + synopsis = "%prog [options] " + + takes_args = ["username", "pubkey"] + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "credopts": options.CredentialsOptions, + "hostopts": options.HostOptions, + } + + takes_options = [ + Option("--link-target", metavar="DN", + help="link to this DN (default: this user's DN)"), + Option("--encoding", default='auto', choices=('pem', 'der', 'auto'), + help="Key format (optional)"), + Option("--force", default=False, action='store_true', + help="proceed with operations that seems ill-fated"), + ] + + @exception_to_command_error(ValueError, ModelError, FileNotFoundError) + def run(self, username, pubkey, + hostopts=None, sambaopts=None, credopts=None, + link_target=None, encoding='auto', force=False): + + samdb = self.ldb_connect(hostopts, sambaopts, credopts) + user = User.find(samdb, username) + + if link_target is None: + link_target = user.dn + + with open(pubkey, 'rb') as f: + data = f.read() + + try: + link = create_key_credential_link(samdb, + link_target, + data, + encoding=encoding, + force=force) + except ldb.LdbError as e: + # with --force, we will end up with CONSTRAINT_VIOLATION + # at user.save(), rather than NO_SUCH_OBJECT now. + if e.args[0] == ldb.ERR_NO_SUCH_OBJECT: + raise CommandError(f"Link target '{link_target}' does not exist") + raise + + if not force and kcl_in_list(link, user.key_credential_link): + # It is not allowed to have duplicate linked attributes, + # which in the case of key credential links means having + # the same key blob and the same DN target. + # + # It is still possible to have the same key material and + # DN target if other fields (e.g. creation date) in the + # blob differ. The creation date is set with one second + # resolution in create_key_credential_link() just above, + # which puts us in the awkward position of creating a race + # if people are running samba-tool in a script. + # + # While the uniqueness invariant is a feature of AD/DSDB, + # not of key credential links, duplicates are not going to + # be useful, so we try to avoid this by checking first + # unless --force is used. + # + # if --force is used to add a key for the second time in + # the same second, user.save() below will raise an + # ERR_ATTRIBUTE_OR_VALUE_EXISTS LdbError. + raise CommandError(f"User {username} " + "already has this key credential link") + + user.key_credential_link.append(link) + user.save(samdb) + + +class cmd_user_keycredentiallink_delete(Command): + """Delete a key-credential-link.""" + + synopsis = "%prog [options]" + + takes_args = ["username"] + + takes_options = [ + Option("--link-target", metavar="DN", + help="Delete this key credential link (a DN)"), + Option("--fingerprint", metavar="HH:HH:..", + help="Delete the key credential link with this key fingerprint"), + Option("--all", action='store_true', + help="Delete all key credential links"), + Option("-n", "--dry-run", action='store_true', + help="Do nothing but print what would happen"), + ] + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "credopts": options.CredentialsOptions, + "hostopts": options.HostOptions, + } + + @exception_to_command_error(ValueError, ModelError) + def run(self, username, hostopts=None, sambaopts=None, credopts=None, + link_target=None, fingerprint=None, all=False, dry_run=False): + + samdb = self.ldb_connect(hostopts, sambaopts, credopts) + user = User.find(samdb, username) + + keycredlinks = user.key_credential_link + + if all: + goners = keycredlinks + else: + goners = filter_kcl_list(samdb, + keycredlinks, + link_target=link_target, + fingerprint=fingerprint) + + keepers = [x for x in keycredlinks if x not in goners] + nk = len(keepers) + + if dry_run: + self.message("Without --dry-run, this would happen:") + if not goners: + self.message("NO key credential links are deleted") + for x in goners: + self.message(f"DELETE {x} (fingerprint {x.fingerprint()})") + self.message('') + for x in keepers: + self.message(f"KEEP {x} (fingerprint {x.fingerprint()})") + + self.message(f"{username} would now have {nk} key credential link" + f"{'' if nk == 1 else 's'}") + return + + if not goners: + # fail without traceback if the filter matches no links + raise CommandError("no key credential links deleted") + + user.key_credential_link = keepers + user.save(samdb) + + for x in goners: + self.message(f"Deleted {x} (fingerprint {x.fingerprint()})") + self.message('') + for x in keepers: + self.message(f"Keeping {x} (fingerprint {x.fingerprint()})") + + self.message(f"{username} now has {nk} key credential link" + f"{'' if nk == 1 else 's'}") + + +class cmd_user_keycredentiallink_view(Command): + """View a user's key credential links.""" + synopsis = "%prog [options]" + + takes_args = ["username"] + + takes_options = [ + Option("-v", "--verbose", help="Be verbose", action="store_true"), + ] + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "credopts": options.CredentialsOptions, + "hostopts": options.HostOptions, + } + + @exception_to_command_error(ValueError, ModelError) + def run(self, username, hostopts=None, sambaopts=None, credopts=None, + verbose=False): + + samdb = self.ldb_connect(hostopts, sambaopts, credopts) + user = User.find(samdb, username) + + if verbose: + verbosity = 3 + else: + verbosity = 2 + + n = len(user.key_credential_link) + self.message(f"{username} has {n} key credential link" + f"{'' if n == 1 else 's'}\n") + + for kcl in user.key_credential_link: + self.message(kcl.description(verbosity), '') + + +class cmd_user_keytrust(SuperCommand): + """Manage key-credential links on a user.""" + + subcommands = { + "add": cmd_user_keycredentiallink_add(), + "delete": cmd_user_keycredentiallink_delete(), + "view": cmd_user_keycredentiallink_view(), + } diff --git a/python/samba/tests/samba_tool/user_keytrust.py b/python/samba/tests/samba_tool/user_keytrust.py new file mode 100644 index 00000000000..bcc587be32f --- /dev/null +++ b/python/samba/tests/samba_tool/user_keytrust.py @@ -0,0 +1,360 @@ +# Unix SMB/CIFS implementation. +# +# Tests for `samba-tool user keytrust` +# +# Copyright © Douglas Bagnall 2025 +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +import os +from pathlib import Path + +from samba.domain.models import User +from samba.tests.samba_tool.base import SambaToolCmdTest +from samba import key_credential_link as kcl + + +HOST = "ldap://{DC_SERVER}".format(**os.environ) +CREDS = "-U{DC_USERNAME}%{DC_PASSWORD}".format(**os.environ) + +ROOT = (Path(__file__) / '../../../../../').resolve() +TESTDATA = ROOT / 'testdata' / 'keytrust' + +GOOD_CERTS = [ + str(TESTDATA / 'cert-rsa-2048.pem'), + str(TESTDATA / 'ca-cert-rsa-2048.pem'), +] + +WRONG_SIZE_CERTS = [ + str(TESTDATA / 'cert-rsa-1024.pem'), + str(TESTDATA / 'ca-cert-rsa-4096.pem'), +] + +NON_RSA_CERTS = [ + str(TESTDATA / 'ca-cert-ecdsa-p256.pem'), +] + +GOOD_KEYS = [ + str(TESTDATA / 'rsa2048-pkcs1.der'), + str(TESTDATA / 'rsa2048b-spki.pem'), +] + +DUPLICATE_KEYS = [ + str(TESTDATA / 'cert-rsa-2048.pem'), + str(TESTDATA / 'public-key-from-cert-rsa-2048-pkcs1.pem'), +] + + +class SambaToolUserKeyTrustTest(SambaToolCmdTest): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.samdb = cls.getSamDB("-H", HOST, CREDS) + cls.runcmd("user", "key-trust", "delete", + "-H", HOST, CREDS, + 'joe', '--all') + cls.runcmd("user", "key-trust", "delete", + "-H", HOST, CREDS, + 'alice', '--all') + + def get_links(self, username): + result = self.samdb.search(expression=f'sAMAccountName={username}', + attrs=['msDS-KeyCredentialLink']) + self.assertEqual(len(result), 1) + links = result[0].get('msDS-KeyCredentialLink', []) + return [kcl.KeyCredentialLinkDn(self.samdb, v) for v in links] + + def test_add_good_cert(self): + """These ones should just succeed.""" + links = self.get_links('joe') + n = len(links) + for f in GOOD_CERTS: + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + 'joe', f) + self.assertCmdSuccess(result, out, err) + + n += 1 + links = self.get_links('joe') + self.assertEqual(len(links), n) + + result, out, err = self.runcmd("user", "key-trust", "delete", + "-H", HOST, CREDS, + 'joe', '--all') + self.assertCmdSuccess(result, out, err) + + for link in links: + self.assertIn(f"Deleted {link}", out) + + links = self.get_links('joe') + self.assertEqual(links, []) + + def test_add_and_delete_good_keys(self): + """Add known good keys, and also check the view and delete commands.""" + links = self.get_links('alice') + self.assertEqual(links, []) + + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + 'alice', GOOD_KEYS[0]) + self.assertCmdSuccess(result, out, err) + links = self.get_links('alice') + self.assertEqual(len(links), 1) + + result, out, err = self.runcmd("user", "key-trust", "view", + "-H", HOST, CREDS, + 'alice') + self.assertCmdSuccess(result, out, err) + self.assertIn('alice has 1 key credential link\n', out) + self.assertIn('Link target: CN=alice,CN=Users,DC=addom,DC=samba,DC=example,DC=com\n', out) + self.assertIn('Number of key entries: 5', out) + + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + 'alice', GOOD_KEYS[1]) + self.assertCmdSuccess(result, out, err) + result, out, err = self.runcmd("user", "key-trust", "view", + "-H", HOST, CREDS, + 'alice', '--verbose') + self.assertCmdSuccess(result, out, err) + self.assertIn('alice has 2 key credential links\n', out) + + links = self.get_links('alice') + fingerprints = [('16:CD:1B:C2:7A:0B:FC:C9:4B:95:11:9F:AD:97:EC:1B:' + 'ED:BD:64:91:42:2E:AF:CA:CB:1E:C3:EE:86:6D:F1:5A'), + ('86:61:6D:B2:6A:3A:04:BD:E0:59:10:13:21:9A:2B:2C:' + 'C4:FD:CE:50:05:16:3C:66:1B:38:63:79:8C:B1:DA:17')] + + self.assertEqual(set(x.fingerprint() for x in links), + set(fingerprints)) + + # test delete --dry-run / -n + result, out, err = self.runcmd("user", "key-trust", "delete", + "-H", HOST, CREDS, + 'alice', '--all', '-n') + self.assertCmdSuccess(result, out, err) + self.assertIn('Without --dry-run, this would happen:\n', out) + self.assertIn(f'DELETE {links[0]} (fingerprint {links[0].fingerprint()})', + out) + self.assertIn(f'DELETE {links[1]} (fingerprint {links[1].fingerprint()})', + out) + self.assertNotIn('KEEP', out) + self.assertIn('alice would now have 0 key credential links\n', out) + + result, out, err = self.runcmd("user", "key-trust", "delete", + "-H", HOST, CREDS, + 'alice', '--fingerprint=whatever', + '--dry-run') + self.assertCmdSuccess(result, out, err) + self.assertIn('NO key credential links are deleted\n', out) + + self.assertIn(f'KEEP {links[0]} (fingerprint {links[0].fingerprint()})', + out) + self.assertIn(f'KEEP {links[1]} (fingerprint {links[1].fingerprint()})', + out) + self.assertIn('alice would now have 2 key credential links\n', out) + + result, out, err = self.runcmd("user", "key-trust", "delete", + "-H", HOST, CREDS, + 'alice', + '--fingerprint', + fingerprints[1], + '--dry-run') + self.assertCmdSuccess(result, out, err) + self.assertIn(f'DELETE {links[1]} (fingerprint {links[1].fingerprint()})', + out) + self.assertIn(f'KEEP {links[0]} (fingerprint {links[0].fingerprint()})', + out) + self.assertIn('alice would now have 1 key credential link\n', out) + + # this time deleting for real + result, out, err = self.runcmd("user", "key-trust", "delete", + "-H", HOST, CREDS, + 'alice', '--all') + self.assertCmdSuccess(result, out, err) + links = self.get_links('alice') + self.assertEqual(links, []) + + result, out, err = self.runcmd("user", "key-trust", "view", + "-H", HOST, CREDS, + 'alice') + self.assertCmdSuccess(result, out, err) + self.assertIn('alice has 0 key credential links\n', out) + + def test_add_duplicate_keys(self): + """You should not be able to add the same link twice.""" + + self.addCleanup(self.runcmd, "user", "key-trust", "delete", + "-H", HOST, CREDS, + 'alice', '--all') + + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + 'alice', DUPLICATE_KEYS[0]) + self.assertCmdSuccess(result, out, err) + + # This source file is different, but contains the same public + # key. samba-tool should notice this and fail *before* it + # fails in the dsdb layer with ERR_ATTRIBUTE_OR_VALUE_EXISTS + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + 'alice', DUPLICATE_KEYS[1]) + self.assertCmdFail(result) + self.assertNotIn('ATTRIBUTE_OR_VALUE_EXISTS', err) + + # adding the first file again should also fail. + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + 'alice', DUPLICATE_KEYS[0]) + self.assertCmdFail(result) + + # adding to a different DN is OK + base_dn = self.samdb.domain_dn() + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + "--link-target", base_dn, + 'alice', DUPLICATE_KEYS[1]) + self.assertCmdSuccess(result, out, err) + + self.assertEqual(len(self.get_links('alice')), 2) + + def test_add_wrong_size_keys(self): + """You should not be able to add the same link twice.""" + + self.addCleanup(self.runcmd, "user", "key-trust", "delete", + "-H", HOST, CREDS, + 'joe', '--all') + + for fn in WRONG_SIZE_CERTS: + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + 'joe', fn) + self.assertCmdFail(result) + self.assertIn('ERROR: 2048 bit RSA key expected, not', err) + + self.assertEqual(self.get_links('joe'), []) + + for fn in WRONG_SIZE_CERTS: + # it will work with --force + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + '--force', + 'joe', fn) + + self.assertCmdSuccess(result, out, err) + + self.assertEqual(len(self.get_links('joe')), 2) + + def test_add_non_rsa_keys(self): + """You should not be able to add the same link twice.""" + + self.addCleanup(self.runcmd, "user", "key-trust", "delete", + "-H", HOST, CREDS, + 'joe', '--all') + + for fn in NON_RSA_CERTS: + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + 'joe', fn) + self.assertCmdFail(result) + self.assertIn('only RSA Public Keys are supported', err) + + self.assertEqual(self.get_links('joe'), []) + + for fn in NON_RSA_CERTS: + # it will NOT work with --force + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + '--force', + 'joe', fn) + + self.assertCmdFail(result) + self.assertIn('only RSA Public Keys are supported', err) + + self.assertEqual(self.get_links('joe'), []) + + def test_add_good_cert_bad_dn(self): + """Fails differently with --force""" + links = self.get_links('joe') + n = len(links) + target = f"CN=an RDN that is not there,{self.samdb.domain_dn()}" + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + '--link-target', target, + 'joe', GOOD_CERTS[0]) + self.assertCmdFail(result) + self.assertIn(f"ERROR: Link target '{target}' does not exist", err) + self.assertEqual(len(links), 0) + + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + '--link-target', target, + '--force', + 'joe', GOOD_CERTS[1]) + self.assertCmdFail(result) + self.assertIn("ERROR(ldb): uncaught exception", err) + self.assertIn("LDAP_CONSTRAINT_VIOLATION", err) + self.assertEqual(len(links), 0) + + def test_add_good_cert_bad_encoding(self): + """If we use --encoding=pem with a DER file or vice versa, it + should fail.""" + self.addCleanup(self.runcmd, "user", "key-trust", "delete", + "-H", HOST, CREDS, + 'joe', '--all') + + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + '--encoding', 'der', + 'joe', GOOD_CERTS[0]) + self.assertCmdFail(result) + self.assertIn("ERROR: could not decode public key", err) + self.assertEqual(self.get_links('joe'), []) + + # try to --force this one, to no avail + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + '--force', + '--encoding', 'pem', + 'joe', GOOD_KEYS[0]) + self.assertCmdFail(result) + self.assertIn("ERROR: could not decode public key", err) + self.assertEqual(self.get_links('joe'), []) + + with self.assertRaises(SystemExit): + # we can't catch result and output here because it fails + # in optparse which prints straight to stderr. + self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + '--encoding', 'pineapple', + 'joe', GOOD_CERTS[1]) + self.assertCmdFail(result) + self.assertEqual(self.get_links('joe'), []) + + # right encoding + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + '--encoding', 'pem', + 'joe', GOOD_CERTS[1]) + self.assertCmdSuccess(result, out, err) + self.assertEqual(len(self.get_links('joe')), 1) + + # 'auto' encoding + result, out, err = self.runcmd("user", "key-trust", "add", + "-H", HOST, CREDS, + '--encoding', 'auto', + 'joe', GOOD_CERTS[0]) + self.assertCmdSuccess(result, out, err) + self.assertEqual(len(self.get_links('joe')), 2) diff --git a/source4/selftest/tests.py b/source4/selftest/tests.py index 57a5a66ef62..13d868c6873 100755 --- a/source4/selftest/tests.py +++ b/source4/selftest/tests.py @@ -1194,6 +1194,7 @@ planpythontestsuite("ad_dc_default:local", "samba.tests.samba_tool.processes") planpythontestsuite("ad_dc_ntvfs:local", "samba.tests.samba_tool.user") planpythontestsuite("ad_dc_default", "samba.tests.samba_tool.user_auth_policy") planpythontestsuite("ad_dc_default", "samba.tests.samba_tool.user_auth_silo") +planpythontestsuite("ad_dc_default", "samba.tests.samba_tool.user_keytrust") for env in ["ad_dc_default:local", "ad_dc_no_ntlm:local"]: planpythontestsuite(env, "samba.tests.samba_tool.user_wdigest") for env, nt_hash in [("ad_dc:local", True), diff --git a/testdata/keytrust/ca-cert-ecdsa-p256.pem b/testdata/keytrust/ca-cert-ecdsa-p256.pem new file mode 100644 index 00000000000..3522b096d18 --- /dev/null +++ b/testdata/keytrust/ca-cert-ecdsa-p256.pem @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBuTCCAWCgAwIBAgIBATAKBggqhkjOPQQDAjA2MQswCQYDVQQGEwJTRTEQMA4G +A1UECgwHSGVpbWRhbDEVMBMGA1UEAwwMQ0Egc2VjcDI1NnIxMCAXDTE5MDMyMjIy +MjUyNVoYDzI1MTgxMTIxMjIyNTI1WjA2MQswCQYDVQQGEwJTRTEQMA4GA1UECgwH +SGVpbWRhbDEVMBMGA1UEAwwMQ0Egc2VjcDI1NnIxMFkwEwYHKoZIzj0CAQYIKoZI +zj0DAQcDQgAE5SuFK+KhglopQr1aMjl4ZEBaw4HYM2yVORyBOQWx3e8Pj90bFocE +4gyS4P2V0YraxACsQgMp+s4e8/6gXPeMtqNdMFswHQYDVR0OBBYEFOtR3wCoaF9m +8dWylzOdd5vfbwmDMB8GA1UdIwQYMBaAFOtR3wCoaF9m8dWylzOdd5vfbwmDMAwG +A1UdEwQFMAMBAf8wCwYDVR0PBAQDAgEGMAoGCCqGSM49BAMCA0cAMEQCIF/JTbEv +iuYcuREFzWgZ/AgfLe2sRwEgSy6UcAWOYllkAiApMzA3xKjaX1/hhkDGKZnHfcTM +tRuM0FuTdO+e15ku8w== +-----END CERTIFICATE----- diff --git a/testdata/keytrust/ca-cert-rsa-2048.pem b/testdata/keytrust/ca-cert-rsa-2048.pem new file mode 100644 index 00000000000..45ae8e81477 --- /dev/null +++ b/testdata/keytrust/ca-cert-rsa-2048.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEajCCA1KgAwIBAgIBATANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJKUDEN +MAsGA1UECgwESlBLSTEpMCcGA1UECwwgUHJlZmVjdHVyYWwgQXNzb2NpYXRpb24g +Rm9yIEpQS0kxETAPBgNVBAsMCEJyaWRnZUNBMB4XDTAzMTIyNzA1MDgxNVoXDTEz +MTIyNjE0NTk1OVowWjELMAkGA1UEBhMCSlAxDTALBgNVBAoMBEpQS0kxKTAnBgNV +BAsMIFByZWZlY3R1cmFsIEFzc29jaWF0aW9uIEZvciBKUEtJMREwDwYDVQQLDAhC +cmlkZ2VDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANTnUmg7K3m8 +52vd77kwkq156euwoWm5no8E8kmaTSc7x2RABPpqNTlMKdZ6ttsyYrqREeDkcvPL +yF7yf/I8+innasNtsytcTAy8xY8Avsbd4JkCGW9dyPjk9pzzc3yLQ64Rx2fujRn2 +agcEVdPCr/XpJygX8FD5bbhkZ0CVoiASBmlHOcC3YpFlfbT1QcpOSOb7o+VdKVEi +MMfbBuU2IlYIaSr/R1nO7RPNtkqkFWJ1/nKjKHyzZje7j70qSxb+BTGcNgTHa1YA +UrogKB+UpBftmb4ds+XlkEJ1dvwokiSbCDaWFKD+YD4B2s0bvjCbw8xuZFYGhNyR +/2D5XfN1s2MCAwEAAaOCATkwggE1MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MG0GA1UdHwRmMGQwYqBgoF6kXDBaMQswCQYDVQQGEwJKUDENMAsGA1UE +CgwESlBLSTEpMCcGA1UECwwgUHJlZmVjdHVyYWwgQXNzb2NpYXRpb24gRm9yIEpQ +S0kxETAPBgNVBAsMCEJyaWRnZUNBMIGDBgNVHREEfDB6pHgwdjELMAkGA1UEBhMC +SlAxJzAlBgNVBAoMHuWFrOeahOWAi+S6uuiqjeiovOOCteODvOODk+OCuTEeMBwG +A1UECwwV6YO96YGT5bqc55yM5Y2U6K2w5LyaMR4wHAYDVQQLDBXjg5bjg6rjg4Pj +grjoqo3oqLzlsYAwHQYDVR0OBBYEFNQXMiCqQNkR2OaZmQgLtf8mR8p8MA0GCSqG +SIb3DQEBBQUAA4IBAQATjJo4reTNPC5CsvAKu1RYT8PyXFVYHbKsEpGt4GR8pDCg +HEGAiAhHSNrGh9CagZMXADvlG0gmMOnXowriQQixrtpkmx0TB8tNAlZptZWkZC+R +8TnjOkHrk2nFAEC3ezbdK0R7MR4tJLDQCnhEWbg50rf0wZ/aF8uAaVeEtHXa6W0M +Xq3dSe0XAcrLbX4zZHQTaWvdpLAIjl6DZ3SCieRMyoWUL+LXaLFdTP5WBCd+No58 +IounD9X4xxze2aeRVaiV/WnQ0OSPNS7n7YXy6xQdnaOU4KRW/Lne1EDf5IfWC/ih +bVAmhZMbcrkWWcsR6aCPG+2mV3zTD6AUzuKPal8Y +-----END CERTIFICATE----- diff --git a/testdata/keytrust/ca-cert-rsa-4096.pem b/testdata/keytrust/ca-cert-rsa-4096.pem new file mode 100644 index 00000000000..7aa8bcf7fa8 --- /dev/null +++ b/testdata/keytrust/ca-cert-rsa-4096.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFczCCA1ugAwIBAgIJAI34CtjBcJHEMA0GCSqGSIb3DQEBCwUAMCoxGzAZBgNV +BAMMEmh4NTA5IFRlc3QgUm9vdCBDQTELMAkGA1UEBhMCU0UwIBcNMTkwMzIyMjIy +NTAxWhgPMjUxODExMjEyMjI1MDFaMCoxGzAZBgNVBAMMEmh4NTA5IFRlc3QgUm9v +dCBDQTELMAkGA1UEBhMCU0UwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDE4gbVQ/vlPFU2W62rukqiUkJ/EIDo1HE4r+xpxO12Ke45NtqSep0d2FfSvEu8 +dhot1jWIkijF7B/bFuB0LyFryCAV/zlU9rLoadCmur5ONIgXRm7eW19wxo5YRD4C +A1IRwvT+Axz0TC3eyquUN1C0r7ZWbiOY8uQy3Sjfar16Z3TtqlKgo4R/yF7dIPJO +OVHaznC+xsfLsYE2r9PqbTjBF3O1pIhwV9oA3tfs23EtvcZBP3y3LSsjnKaF0b/N +XmjLNW9hbmAfN+16TEMOlVZvBjUPO3CC/GU0PJzm1/FqyzXWeRx5FZNi7fCPKg8J +9QDAgK5mMn+ZPazuUt70uxUFrnRLCjCia/TgC+t2d+3AqsnRlYnLYDv/MeP/QwqH +GK3+WuAS6uqXZMtilDhY+oiMTZ4vDHvwzJ5q3UhIpWXj5cSGWAxQurKgUsjT9sta +gGmXlBauMYSzFM5T+TXica1qE7dNXjXr2sTy9BHIp+aWJuGkX9rSx8tHwbkIkVTp +4UCZ+QoxBRaSmiuyFPM77yg6wZBuSuRRN/BNKvAhuJaE1MdA+vobbyyNbv56MU0+ +WI4ucD+b08JmJp3k+fgM0fKXBQlEL4mp7zeUoLmC1yCy48Zk1foPZTRH9pIGB/zU +z4B8o20NmereB9bX0IjJ6eqMDqvAZWZ99Nf16Q3X88T88wIDAQABo4GZMIGWMB0G +A1UdDgQWBBRTuMwJxp9C6tXkdCC0Ze1o+J21BTBaBgNVHSMEUzBRgBRTuMwJxp9C +6tXkdCC0Ze1o+J21BaEupCwwKjEbMBkGA1UEAwwSaHg1MDkgVGVzdCBSb290IENB +MQswCQYDVQQGEwJTRYIJAI34CtjBcJHEMAwGA1UdEwQFMAMBAf8wCwYDVR0PBAQD +AgHmMA0GCSqGSIb3DQEBCwUAA4ICAQCdea8Tx/1vuQCqn2AOmIzEO9xgmaY3opl9 +0Px82DafNuFFJu9WlPrsKeADtSqpA/MwBjL8K+T3dhL4Bxhq8jed0gGsS3C3xFTl +/RJbnFiLuveMErPTEtxaRYpa3oibQ15eJbDq533Is1x8oeK6NnHB6St3nboST0f3 +6SeAsoeHrI16eUEJQ3UKJYJlxATEqOpeaWwdlT6jF9u0WyENz0ijD0b9FPY/zq6D +zx47Zd5F6aisrtKNXFjB9/oHV6jOh9OGxz6WfT1z2AZ+69jEm+xE8coq4nyWcJrS +cf7ENBIw1Rknpxk3/H1p0q+Zze5/JBYlKOtEML1dwRIRquVgfhcI/tOq7m5jUxTl +/6dW8FCnuEFBnUvUrZ0Hv3g2jvHElpPjYkLwZyKFYyvY/G+xCZAiqaYZ2kQqRmti +KvSfh8fJlV2Jj2aDI1I4JjACG7LYBe7WXCs7TccRrhnx/RUY7cpJwEQrIOKBq8wx +DD58oPgvkmNPP5lZcFARjnWcY8xS9KzT+KaZWM3ZPefg3Vk//3HfwZfDE3Y7IMgu +quuLcpeGtMDyurnm6piUdPITt8yW+MMJR8V+PeF0zLdN4dA0nuJpZWZ3fvnevmAL +jh/ia0LuzkhVSj1R1dXXopZevazh/tmAuKU9BbeYGvwI1RFXVvyzpGRfMbgaze3Q +tIrreKeFxg== +-----END CERTIFICATE----- diff --git a/testdata/keytrust/cert-rsa-1024.pem b/testdata/keytrust/cert-rsa-1024.pem new file mode 100644 index 00000000000..9a89e59e2ad --- /dev/null +++ b/testdata/keytrust/cert-rsa-1024.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIICzTCCAjagAwIBAgIJAOSnzE4Qx2H/MA0GCSqGSIb3DQEBBQUAMDkxCzAJBgNV +BAYTAkpQMRQwEgYDVQQKEwtDQSBURVNUIDEtNDEUMBIGA1UEAxMLQ0EgVEVTVCAx +LTQwHhcNMDYwOTA3MTY0MDM3WhcNMDcwOTA3MTY0MDM3WjBPMQswCQYDVQQGEwJK +UDEOMAwGA1UECBMFVG9reW8xFjAUBgNVBAoTDVRFU1QgMiBDTElFTlQxGDAWBgNV +BAMTD3d3dzIuZXhhbXBsZS5qcDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +vSpZ6ig9DpeKB60h7ii1RitNuvkn4INOfEXjCjPSFwmIbGJqnyWvKTiMKzguEYkG +6CZAbsx44t3kvsVDeUd5WZBRgMoeQd1tNJBU4BXxOA8bVzdwstzaPeeufQtZDvKf +M4ej+fo/j9lYH9udCug1huaNybcCtijzGonkddX4JEUCAwEAAaOBxjCBwzAJBgNV +HRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZp +Y2F0ZTAdBgNVHQ4EFgQUK0DZtd8K1P2ij9gVKUNcHlx7uCIwaQYDVR0jBGIwYIAU +340JbeYcg6V9zi8aozy48aIhtfihPaQ7MDkxCzAJBgNVBAYTAkpQMRQwEgYDVQQK +EwtDQSBURVNUIDEtNDEUMBIGA1UEAxMLQ0EgVEVTVCAxLTSCCQDkp8xOEMdh/jAN +BgkqhkiG9w0BAQUFAAOBgQCkGhwCDLRwWbDnDFReXkIZ1/9OhfiR8yL1idP9iYVU +cSoWxSHPBWkv6LORFS03APcXCSzDPJ9pxTjFjGGFSI91fNrzkKdHU/+0WCF2uTh7 +Dz2blqtcmnJqMSn1xHxxfM/9e6M3XwFUMf7SGiKRAbDfsauPafEPTn83vSeKj1lg +Dw== +-----END CERTIFICATE----- diff --git a/testdata/keytrust/cert-rsa-2048.pem b/testdata/keytrust/cert-rsa-2048.pem new file mode 100644 index 00000000000..f6631b2e06f --- /dev/null +++ b/testdata/keytrust/cert-rsa-2048.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlFeGFt +cGxlQ0EwHhcNMTQwMTE1MTU0MDUwWhcNMTUwMTE1MTU0MDUwWjAAMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAncvm0aOBK05rdNInYXzJGV5SFteVUFpt +XFxg4evROvlulB3BzUmFGQYFDcItVnJX2fAvf0UJLtLBVBQggb5ylL6bRpj72cS3 +oyNbs0CGmix9Z1QDjkZZFvIsD1GcKO0tvsCvsEItH8Cm0fq8WcGFijWLdRD5eulP +55pq1bAHAvIo4+VLMJVBG71xrKGZeHPjKoq6seYjh7AGy+hk2vmFzpZ8Ghdgqv+K +02IZ7FEdzuylHW8U3qsxBHysMut4inj6AiVf467OOs5meHiifIK9MGkovMrfY9iX +uUVUs/KXpE1sgeoX9BLvx1BPcODosr5K+z5i71OtIXy4CXrPvcGzRwIDAQABo4IB +XjCCAVowQAYIKwYBBQUHAQEENDAyMDAGCCsGAQUFBzAChiRodHRwOi8vd3d3LmV4 +YW1wbGUuY29tL0V4YW1wbGVDQS5jcnQwDgYDVR0PAQH/BAQDAgAgMFkGA1UdEQEB +/wRPME2kSzBJMRYwFAYFZ4EFAgEMC2lkOjU0NDM0NzAwMRcwFQYFZ4EFAgIMDEFC +Q0RFRjEyMzQ1NjEWMBQGBWeBBQIDDAtpZDowMDAxMDAyMzAMBgNVHRMBAf8EAjAA +MDUGA1UdHwQuMCwwKqAooCaGJGh0dHA6Ly93d3cuZXhhbXBsZS5jb20vRXhhbXBs +ZUNBLmNybDAQBgNVHSAECTAHMAUGAyoDBDAfBgNVHSMEGDAWgBQ0d2ckTESv554q +4LJMaVeVJLM92jAQBgNVHSUECTAHBgVngQUIATAhBgNVHQkEGjAYMBYGBWeBBQIQ +MQ0wCwwDMi4wAgEAAgFjMA0GCSqGSIb3DQEBCwUAA4IBAQAba2btJ/+4z02MWpNp +99AFGpEu3yIaJqI6NeHvC6fxxe/9lWlHKISR+CnpAh03/MKT8TP2/cUSi0jjkQNh +MtueUNofE79fYXtHXHU7wzzUFWNwCmhTuHDYl3jmD0fJ9yA2CuUHT6q3UV+PwXN+ +EHE1hQwC8QtNC/5A7wY1e5dBLdgwSSIgTc4lSsbNcZ9d+m7mWEWpumSYU0czTDEN +Hmdu/VJuDN/RCOAyBb+hc19LAucGmnFYOhxWHfd9zbXZA1ldFUxrpPuVfKx+Eo8f +rMsB2oZKMwSYUAWotqolhLe2wdBMRjdmVz44kIhuFB7y4BpQjlB1+xAzX9Hb31CG +eoS2 +-----END CERTIFICATE----- diff --git a/testdata/keytrust/cert-rsa-2048b.pem b/testdata/keytrust/cert-rsa-2048b.pem new file mode 100644 index 00000000000..66b769c7a67 --- /dev/null +++ b/testdata/keytrust/cert-rsa-2048b.pem @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlFeGFt +cGxlQ0EwHhcNMTQwMTE1MTU0MDUwWhcNMTUwMTE1MTU0MDUwWjAAMIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAncvm0aOBK05rdNInYXzJGV5SFteVUFpt +XFxg4evROvlulB3BzUmFGQYFDcItVnJX2fAvf0UJLtLBVBQggb5ylL6bRpj72cS3 +oyNbs0CGmix9Z1QDjkZZFvIsD1GcKO0tvsCvsEItH8Cm0fq8WcGFijWLdRD5eulP +55pq1bAHAvIo4+VLMJVBG71xrKGZeHPjKoq6seYjh7AGy+hk2vmFzpZ8Ghdgqv+K +02IZ7FEdzuylHW8U3qsxBHysMut4inj6AiVf467OOs5meHiifIK9MGkovMrfY9iX +uUVUs/KXpE1sgeoX9BLvx1BPcODosr5K+z5i71OtIXy4CXrPvcGzRwIDAQABo4IB +hzCCAYMwQAYIKwYBBQUHAQEENDAyMDAGCCsGAQUFBzAChiRodHRwOi8vd3d3LmV4 +YW1wbGUuY29tL0V4YW1wbGVDQS5jcnQwDgYDVR0PAQH/BAQDAgAgMIGBBgNVHREB +Af8EdzB1pEswSTEWMBQGBWeBBQIBDAtpZDo1NDQzNDcwMDEXMBUGBWeBBQICDAxB +QkNERUYxMjM0NTYxFjAUBgVngQUCAwwLaWQ6MDAwMTAwMjOgJgYIKwYBBQUHCASg +GjAYBgVngQUBAgQPdHBtc2VyaWFsbnVtYmVyMAwGA1UdEwEB/wQCMAAwNQYDVR0f +BC4wLDAqoCigJoYkaHR0cDovL3d3dy5leGFtcGxlLmNvbS9FeGFtcGxlQ0EuY3Js +MBAGA1UdIAQJMAcwBQYDKgMEMB8GA1UdIwQYMBaAFDR3ZyRMRK/nnirgskxpV5Uk +sz3aMBAGA1UdJQQJMAcGBWeBBQgBMCEGA1UdCQQaMBgwFgYFZ4EFAhAxDTALDAMy +LjACAQACAWMwDQYJKoZIhvcNAQELBQADggEBABtrZu0n/7jPTYxak2n30AUakS7f +Ihomojo14e8Lp/HF7/2VaUcohJH4KekCHTf8wpPxM/b9xRKLSOORA2Ey255Q2h8T +v19he0dcdTvDPNQVY3AKaFO4cNiXeOYPR8n3IDYK5QdPqrdRX4/Bc34QcTWFDALx +C00L/kDvBjV7l0Et2DBJIiBNziVKxs1xn136buZYRam6ZJhTRzNMMQ0eZ279Um4M +39EI4DIFv6FzX0sC5waacVg6HFYd933NtdkDWV0VTGuk+5V8rH4Sjx+sywHahkoz +BJhQBai2qiWEt7bB0ExGN2ZXPjiQiG4UHvLgGlCOUHX7EDNf0dvfUIZ6hLY= +-----END CERTIFICATE----- diff --git a/testdata/keytrust/public-key-from-cert-rsa-2048-pkcs1.pem b/testdata/keytrust/public-key-from-cert-rsa-2048-pkcs1.pem new file mode 100644 index 00000000000..79c449917a6 --- /dev/null +++ b/testdata/keytrust/public-key-from-cert-rsa-2048-pkcs1.pem @@ -0,0 +1,8 @@ +-----BEGIN RSA PUBLIC KEY----- +MIIBCgKCAQEAncvm0aOBK05rdNInYXzJGV5SFteVUFptXFxg4evROvlulB3BzUmF +GQYFDcItVnJX2fAvf0UJLtLBVBQggb5ylL6bRpj72cS3oyNbs0CGmix9Z1QDjkZZ +FvIsD1GcKO0tvsCvsEItH8Cm0fq8WcGFijWLdRD5eulP55pq1bAHAvIo4+VLMJVB +G71xrKGZeHPjKoq6seYjh7AGy+hk2vmFzpZ8Ghdgqv+K02IZ7FEdzuylHW8U3qsx +BHysMut4inj6AiVf467OOs5meHiifIK9MGkovMrfY9iXuUVUs/KXpE1sgeoX9BLv +x1BPcODosr5K+z5i71OtIXy4CXrPvcGzRwIDAQAB +-----END RSA PUBLIC KEY----- diff --git a/testdata/keytrust/rsa2048-pkcs1.der b/testdata/keytrust/rsa2048-pkcs1.der new file mode 100644 index 00000000000..247b275e42a Binary files /dev/null and b/testdata/keytrust/rsa2048-pkcs1.der differ diff --git a/testdata/keytrust/rsa2048b-spki.pem b/testdata/keytrust/rsa2048b-spki.pem new file mode 100644 index 00000000000..edaa8d51f66 --- /dev/null +++ b/testdata/keytrust/rsa2048b-spki.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAncvm0aOBK05rdNInYXzJ +GV5SFteVUFptXFxg4evROvlulB3BzUmFGQYFDcItVnJX2fAvf0UJLtLBVBQggb5y +lL6bRpj72cS3oyNbs0CGmix9Z1QDjkZZFvIsD1GcKO0tvsCvsEItH8Cm0fq8WcGF +ijWLdRD5eulP55pq1bAHAvIo4+VLMJVBG71xrKGZeHPjKoq6seYjh7AGy+hk2vmF +zpZ8Ghdgqv+K02IZ7FEdzuylHW8U3qsxBHysMut4inj6AiVf467OOs5meHiifIK9 +MGkovMrfY9iXuUVUs/KXpE1sgeoX9BLvx1BPcODosr5K+z5i71OtIXy4CXrPvcGz +RwIDAQAB +-----END PUBLIC KEY-----