def test_certonly_webroot(context: IntegrationTestsContext) -> None: """Test the certonly verb with webroot plugin""" with misc.create_http_server(context.http_01_port) as webroot: certname = context.get_domain('webroot') context.certbot(['certonly', '-a', 'webroot', '--webroot-path', webroot, '-d', certname]) assert_cert_count_for_lineage(context.config_dir, certname, 1)
def test_manual_dns_auth(context): """Test the DNS-01 challenge using manual plugin.""" certname = context.get_domain('dns') context.certbot([ '-a', 'manual', '-d', certname, '--preferred-challenges', 'dns', 'run', '--cert-name', certname, '--manual-auth-hook', context.manual_dns_auth_hook, '--manual-cleanup-hook', context.manual_dns_cleanup_hook, '--pre-hook', misc.echo('wtf_pre', context.hook_probe), '--post-hook', misc.echo('wtf_post', context.hook_probe), '--renew-hook', misc.echo('renew', context.hook_probe), ]) with pytest.raises(AssertionError): assert_hook_execution(context.hook_probe, 'renew') assert_saved_renew_hook(context.config_dir, certname) context.certbot( ['renew', '--cert-name', certname, '--authenticator', 'manual']) assert_cert_count_for_lineage(context.config_dir, certname, 2)
def test_certonly(context: IntegrationTestsContext) -> None: """Test the certonly verb on certbot.""" context.certbot([ 'certonly', '--cert-name', 'newname', '-d', context.get_domain('newname') ]) assert_cert_count_for_lineage(context.config_dir, 'newname', 1)
def test_renew_with_hook_scripts(context): """Test certificate renewal with script hooks.""" certname = context.get_domain('renew') context.certbot(['-d', certname]) assert_cert_count_for_lineage(context.config_dir, certname, 1) misc.generate_test_file_hooks(context.config_dir, context.hook_probe) context.certbot(['renew']) assert_cert_count_for_lineage(context.config_dir, certname, 2) assert_hook_execution(context.hook_probe, 'deploy')
def test_renew_ignoring_directory_hooks(context): """Test hooks are ignored during renewal with relevant CLI flag.""" certname = context.get_domain('renew') context.certbot(['-d', certname]) assert_cert_count_for_lineage(context.config_dir, certname, 1) misc.generate_test_file_hooks(context.config_dir, context.hook_probe) context.certbot(['renew', '--no-directory-hooks']) assert_cert_count_for_lineage(context.config_dir, certname, 2) with pytest.raises(AssertionError): assert_hook_execution(context.hook_probe, 'deploy')
def test_graceful_renew_it_is_not_time(context): """Test graceful renew is not done when it is not due time.""" certname = context.get_domain('renew') context.certbot(['-d', certname]) assert_cert_count_for_lineage(context.config_dir, certname, 1) context.certbot(['renew', '--deploy-hook', 'echo deploy >> "{0}"'.format(context.hook_probe)], force_renew=False) assert_cert_count_for_lineage(context.config_dir, certname, 1) with pytest.raises(AssertionError): assert_hook_execution(context.hook_probe, 'deploy')
def test_renew_with_ec_keys(context: IntegrationTestsContext) -> None: """Test proper renew with updated private key complexity.""" certname = context.get_domain('renew') context.certbot([ 'certonly', '--cert-name', certname, '--key-type', 'ecdsa', '--elliptic-curve', 'secp256r1', '--force-renewal', '-d', certname, ]) key1 = join(context.config_dir, "archive", certname, 'privkey1.pem') assert 200 < os.stat(key1).st_size < 250 # ec keys of 256 bits are ~225 bytes assert_elliptic_key(key1, SECP256R1) assert_cert_count_for_lineage(context.config_dir, certname, 1) assert_saved_lineage_option(context.config_dir, certname, 'key_type', 'ecdsa') context.certbot(['renew', '--elliptic-curve', 'secp384r1']) assert_cert_count_for_lineage(context.config_dir, certname, 2) key2 = join(context.config_dir, 'archive', certname, 'privkey2.pem') assert 280 < os.stat(key2).st_size < 320 # ec keys of 384 bits are ~310 bytes assert_elliptic_key(key2, SECP384R1) # When running non-interactively, if --key-type is unspecified but the default value differs # to the lineage key type, Certbot should keep the lineage key type. The curve will still # change to the default value, in order to stay consistent with the behavior of certonly. context.certbot(['certonly', '--force-renewal', '-d', certname]) assert_cert_count_for_lineage(context.config_dir, certname, 3) key3 = join(context.config_dir, 'archive', certname, 'privkey3.pem') assert 200 < os.stat(key3).st_size < 250 # ec keys of 256 bits are ~225 bytes assert_elliptic_key(key3, SECP256R1) # When running non-interactively, specifying a different --key-type requires user confirmation # with both --key-type and --cert-name. with pytest.raises(subprocess.CalledProcessError) as error: context.certbot(['certonly', '--force-renewal', '-d', certname, '--key-type', 'rsa']) assert 'Please provide both --cert-name and --key-type' in error.value.stderr context.certbot(['certonly', '--force-renewal', '-d', certname, '--key-type', 'rsa', '--cert-name', certname]) assert_cert_count_for_lineage(context.config_dir, certname, 4) key4 = join(context.config_dir, 'archive', certname, 'privkey4.pem') assert_rsa_key(key4) # We expect that the previous behavior of requiring both --cert-name and # --key-type to be set to not apply to the renew subcommand. context.certbot(['renew', '--force-renewal', '--key-type', 'ecdsa']) assert_cert_count_for_lineage(context.config_dir, certname, 5) key5 = join(context.config_dir, 'archive', certname, 'privkey5.pem') assert 200 < os.stat(key5).st_size < 250 # ec keys of 256 bits are ~225 bytes assert_elliptic_key(key5, SECP256R1)
def test_renew_empty_hook_scripts(context): """Test proper renew with empty hook scripts.""" certname = context.get_domain('renew') context.certbot(['-d', certname]) assert_cert_count_for_lineage(context.config_dir, certname, 1) misc.generate_test_file_hooks(context.config_dir, context.hook_probe) for hook_dir in misc.list_renewal_hooks_dirs(context.config_dir): shutil.rmtree(hook_dir) os.makedirs(join(hook_dir, 'dir')) open(join(hook_dir, 'file'), 'w').close() context.certbot(['renew']) assert_cert_count_for_lineage(context.config_dir, certname, 2)
def test_renew_files_propagate_permissions(context): """Test proper certificate renewal with custom permissions propagated on private key.""" certname = context.get_domain('renew') context.certbot(['-d', certname]) assert_cert_count_for_lineage(context.config_dir, certname, 1) os.chmod(join(context.config_dir, 'archive', certname, 'privkey1.pem'), 0o444) context.certbot(['renew']) assert_cert_count_for_lineage(context.config_dir, certname, 2) assert_world_permissions( join(context.config_dir, 'archive', certname, 'privkey2.pem'), 4) assert_equals_permissions( join(context.config_dir, 'archive', certname, 'privkey1.pem'), join(context.config_dir, 'archive', certname, 'privkey2.pem'), 0o074)
def test_graceful_renew_it_is_time(context): """Test graceful renew is done when it is due time.""" certname = context.get_domain('renew') context.certbot(['-d', certname]) assert_cert_count_for_lineage(context.config_dir, certname, 1) with open(join(context.config_dir, 'renewal', '{0}.conf'.format(certname)), 'r') as file: lines = file.readlines() lines.insert(4, 'renew_before_expiry = 100 years{0}'.format(os.linesep)) with open(join(context.config_dir, 'renewal', '{0}.conf'.format(certname)), 'w') as file: file.writelines(lines) context.certbot(['renew', '--deploy-hook', 'echo deploy >> "{0}"'.format(context.hook_probe)], force_renew=False) assert_cert_count_for_lineage(context.config_dir, certname, 2) assert_hook_execution(context.hook_probe, 'deploy')
def test_renew_files_permissions(context: IntegrationTestsContext) -> None: """Test proper certificate file permissions upon renewal""" certname = context.get_domain('renew') context.certbot(['-d', certname]) privkey1 = join(context.config_dir, 'archive', certname, 'privkey1.pem') privkey2 = join(context.config_dir, 'archive', certname, 'privkey2.pem') assert_cert_count_for_lineage(context.config_dir, certname, 1) assert_world_no_permissions(privkey1) context.certbot(['renew']) assert_cert_count_for_lineage(context.config_dir, certname, 2) assert_world_no_permissions(privkey2) assert_equals_group_owner(privkey1, privkey2) assert_equals_world_read_permissions(privkey1, privkey2) assert_equals_group_permissions(privkey1, privkey2)
def test_renew_files_propagate_permissions( context: IntegrationTestsContext) -> None: """Test proper certificate renewal with custom permissions propagated on private key.""" certname = context.get_domain('renew') context.certbot(['-d', certname]) assert_cert_count_for_lineage(context.config_dir, certname, 1) privkey1 = join(context.config_dir, 'archive', certname, 'privkey1.pem') privkey2 = join(context.config_dir, 'archive', certname, 'privkey2.pem') if os.name != 'nt': os.chmod(privkey1, 0o444) else: import win32security # pylint: disable=import-error import ntsecuritycon # pylint: disable=import-error # Get the current DACL of the private key security = win32security.GetFileSecurity( privkey1, win32security.DACL_SECURITY_INFORMATION) dacl = security.GetSecurityDescriptorDacl() # Create a read permission for Everybody group everybody = win32security.ConvertStringSidToSid(EVERYBODY_SID) dacl.AddAccessAllowedAce(win32security.ACL_REVISION, ntsecuritycon.FILE_GENERIC_READ, everybody) # Apply the updated DACL to the private key security.SetSecurityDescriptorDacl(1, dacl, 0) win32security.SetFileSecurity(privkey1, win32security.DACL_SECURITY_INFORMATION, security) context.certbot(['renew']) assert_cert_count_for_lineage(context.config_dir, certname, 2) if os.name != 'nt': # On Linux, read world permissions + all group permissions # will be copied from the previous private key assert_world_read_permissions(privkey2) assert_equals_world_read_permissions(privkey1, privkey2) assert_equals_group_permissions(privkey1, privkey2) else: # On Windows, world will never have any permissions, and # group permission is irrelevant for this platform assert_world_no_permissions(privkey2)
def test_renew_files_permissions(context): """Test proper certificate file permissions upon renewal""" certname = context.get_domain('renew') context.certbot(['-d', certname]) assert_cert_count_for_lineage(context.config_dir, certname, 1) assert_world_permissions( join(context.config_dir, 'archive', certname, 'privkey1.pem'), 0) context.certbot(['renew']) assert_cert_count_for_lineage(context.config_dir, certname, 2) assert_world_permissions( join(context.config_dir, 'archive', certname, 'privkey2.pem'), 0) assert_equals_group_owner( join(context.config_dir, 'archive', certname, 'privkey1.pem'), join(context.config_dir, 'archive', certname, 'privkey2.pem')) assert_equals_permissions( join(context.config_dir, 'archive', certname, 'privkey1.pem'), join(context.config_dir, 'archive', certname, 'privkey2.pem'), 0o074)
def test_renew_with_ec_keys(context): """Test proper renew with updated private key complexity.""" certname = context.get_domain('renew') context.certbot([ 'certonly', '--cert-name', certname, '--key-type', 'ecdsa', '--elliptic-curve', 'secp256r1', '--force-renewal', '-d', certname, ]) key1 = join(context.config_dir, "archive", certname, 'privkey1.pem') assert 200 < os.stat(key1).st_size < 250 # ec keys of 256 bits are ~225 bytes assert_elliptic_key(key1, SECP256R1) assert_cert_count_for_lineage(context.config_dir, certname, 1) context.certbot(['renew', '--elliptic-curve', 'secp384r1']) assert_cert_count_for_lineage(context.config_dir, certname, 2) key2 = join(context.config_dir, 'archive', certname, 'privkey2.pem') assert_elliptic_key(key2, SECP384R1) assert 280 < os.stat(key2).st_size < 320 # ec keys of 384 bits are ~310 bytes context.certbot(['renew', '--elliptic-curve', 'secp521r1']) assert_cert_count_for_lineage(context.config_dir, certname, 3) key3 = join(context.config_dir, 'archive', certname, 'privkey3.pem') assert_elliptic_key(key3, SECP521R1) assert 340 < os.stat(key3).st_size < 390 # ec keys of 521 bits are ~365 bytes # We expect here that the command will fail because without --key-type specified, # Certbot must error out to prevent changing an existing certificate key type, # without explicit user consent (by specifying both --cert-name and --key-type). with pytest.raises(subprocess.CalledProcessError): context.certbot([ 'certonly', '--force-renewal', '-d', certname ]) # We expect that the previous behavior of requiring both --cert-name and # --key-type to be set to not apply to the renew subcommand. context.certbot(['renew', '--force-renewal', '--key-type', 'rsa']) assert_cert_count_for_lineage(context.config_dir, certname, 4) key4 = join(context.config_dir, 'archive', certname, 'privkey4.pem') assert_rsa_key(key4)
def test_ocsp_renew(context: IntegrationTestsContext) -> None: """Test that revoked certificates are renewed.""" # Obtain a certificate certname = context.get_domain('ocsp-renew') context.certbot(['--domains', certname]) # Test that "certbot renew" does not renew the certificate assert_cert_count_for_lineage(context.config_dir, certname, 1) context.certbot(['renew'], force_renew=False) assert_cert_count_for_lineage(context.config_dir, certname, 1) # Revoke the certificate and test that it does renew the certificate context.certbot(['revoke', '--cert-name', certname, '--no-delete-after-revoke']) context.certbot(['renew'], force_renew=False) assert_cert_count_for_lineage(context.config_dir, certname, 2)
def test_renew_with_changed_private_key_complexity(context): """Test proper renew with updated private key complexity.""" certname = context.get_domain('renew') context.certbot(['-d', certname, '--rsa-key-size', '4096']) key1 = join(context.config_dir, 'archive', certname, 'privkey1.pem') assert os.stat(key1).st_size > 3000 # 4096 bits keys takes more than 3000 bytes assert_cert_count_for_lineage(context.config_dir, certname, 1) context.certbot(['renew']) assert_cert_count_for_lineage(context.config_dir, certname, 2) key2 = join(context.config_dir, 'archive', certname, 'privkey2.pem') assert os.stat(key2).st_size > 3000 context.certbot(['renew', '--rsa-key-size', '2048']) assert_cert_count_for_lineage(context.config_dir, certname, 3) key3 = join(context.config_dir, 'archive', certname, 'privkey3.pem') assert os.stat(key3).st_size < 1800 # 2048 bits keys takes less than 1800 bytes