The branch, master has been updated via ddeedcb6b2a gpo: Add Cert Auto Enroll Advanced Config via a54d707435b gpo: Test Cert Auto Enroll Advanced Config via ab2ef316c18 gpo: Generalize Cert Auto Enroll CA data via 6171dfc5283 gpo: Fix crash in Cert Auth Enroll RSOP via 45d76ecad21 gpo: Certificate Auto Enroll correctly check templates via a49a5702ebb gpo: Correct CA Initilization to obey [MS-CAESO] from 64275fc1a22 ctdb-tests: Add backtrace on abort to some tests
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit ddeedcb6b2a036e5d51be94c7f7215543ff3f163 Author: David Mulder <dmul...@suse.com> Date: Tue Apr 12 12:50:25 2022 -0600 gpo: Add Cert Auto Enroll Advanced Config Advanced configuration for Certifcate Auto Enrollment is stored on the sysvol, and needs to be parsed/used when provided. Signed-off-by: David Mulder <dmul...@suse.com> Reviewed-by: Jeremy Allison <j...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Tue May 3 21:48:57 UTC 2022 on sn-devel-184 commit a54d707435b1d5098028d72a2021dbb463ef1d03 Author: David Mulder <dmul...@suse.com> Date: Tue Apr 12 12:27:41 2022 -0600 gpo: Test Cert Auto Enroll Advanced Config Adds advanced configuration to the testing of certificate auto enrollment. Currently fails. Signed-off-by: David Mulder <dmul...@suse.com> Reviewed-by: Jeremy Allison <j...@samba.org> commit ab2ef316c187b8cf239a7156980441569d908390 Author: David Mulder <dmul...@suse.com> Date: Tue Apr 12 10:29:39 2022 -0600 gpo: Generalize Cert Auto Enroll CA data This will simplify fetching CAs from the Registry.pol in a follow up commit. Signed-off-by: David Mulder <dmul...@suse.com> Reviewed-by: Jeremy Allison <j...@samba.org> commit 6171dfc52835058082fa5d86f82fca7f51827ab5 Author: David Mulder <dmul...@suse.com> Date: Tue Apr 12 10:25:51 2022 -0600 gpo: Fix crash in Cert Auth Enroll RSOP Signed-off-by: David Mulder <dmul...@suse.com> Reviewed-by: Jeremy Allison <j...@samba.org> commit 45d76ecad2159714af6ecc4f7d525ca39149cc07 Author: David Mulder <dmul...@suse.com> Date: Mon Apr 11 14:26:50 2022 -0600 gpo: Certificate Auto Enroll correctly check templates [MS-CAESO] 4.4.5.3.2.4 and 4.4.5.3.2.4.2 explain to fetch templates via cep, then to gather attrs for the templates after. This code was reversed. This will matter when implementing advanced endpoint configuration. Signed-off-by: David Mulder <dmul...@suse.com> Reviewed-by: Jeremy Allison <j...@samba.org> commit a49a5702ebbedf2d3d5dac973328e9fac1d4ad8c Author: David Mulder <dmul...@suse.com> Date: Fri Apr 8 13:42:55 2022 -0600 gpo: Correct CA Initilization to obey [MS-CAESO] fetch_certification_authorities() did not correctly obey the [MS-CAESO] spec. Signed-off-by: David Mulder <dmul...@suse.com> Reviewed-by: Jeremy Allison <j...@samba.org> ----------------------------------------------------------------------- Summary of changes: python/samba/gp_cert_auto_enroll_ext.py | 269 +++++++++++++++++++++++++------ python/samba/tests/gpo.py | 272 +++++++++++++++++++++++++++++++- 2 files changed, 495 insertions(+), 46 deletions(-) Changeset truncated at 500 lines: diff --git a/python/samba/gp_cert_auto_enroll_ext.py b/python/samba/gp_cert_auto_enroll_ext.py index e5c2f2e4394..b2903f3b7e0 100644 --- a/python/samba/gp_cert_auto_enroll_ext.py +++ b/python/samba/gp_cert_auto_enroll_ext.py @@ -15,9 +15,10 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import os +import operator from samba.gpclass import gp_pol_ext from samba import Ldb -from ldb import SCOPE_SUBTREE +from ldb import SCOPE_SUBTREE, SCOPE_BASE from samba.auth import system_session from samba.gpclass import get_dc_hostname import base64 @@ -28,34 +29,122 @@ import re from glob import glob import json from samba.gp.util.logging import log +import struct cert_wrap = b""" -----BEGIN CERTIFICATE----- %s -----END CERTIFICATE-----""" global_trust_dir = '/etc/pki/trust/anchors' +endpoint_re = '(https|HTTPS)://(?P<server>[a-zA-Z0-9.-]+)/ADPolicyProvider' + \ + '_CEP_(?P<auth>[a-zA-Z]+)/service.svc/CEP' +def octet_string_to_objectGUID(data): + return '%s-%s-%s-%s-%s' % ('%02x' % struct.unpack('<L', data[0:4])[0], + '%02x' % struct.unpack('<H', data[4:6])[0], + '%02x' % struct.unpack('<H', data[6:8])[0], + '%02x' % struct.unpack('>H', data[8:10])[0], + '%02x%02x' % struct.unpack('>HL', data[10:])) + +''' +Group and Sort End Point Information +[MS-CAESO] 4.4.5.3.2.3 +In this step autoenrollment processes the end point information by grouping it +by CEP ID and sorting in the order with which it will use the end point to +access the CEP information. +''' +def group_and_sort_end_point_information(end_point_information): + # Create groups of the CertificateEnrollmentPolicyEndPoint instances that + # have the same value of the EndPoint.PolicyID datum. + end_point_groups = {} + for e in end_point_information: + if e['PolicyID'] not in end_point_groups.keys(): + end_point_groups[e['PolicyID']] = [] + end_point_groups[e['PolicyID']].append(e) + + # Sort each group by following these rules: + for end_point_group in end_point_groups.values(): + # Sort the CertificateEnrollmentPolicyEndPoint instances in ascending + # order based on the EndPoint.Cost value. + end_point_group.sort(key=lambda e: e['Cost']) + + # For instances that have the same EndPoint.Cost: + cost_list = [e['Cost'] for e in end_point_group] + costs = set(cost_list) + for cost in costs: + i = cost_list.index(cost) + j = len(cost_list)-operator.indexOf(reversed(cost_list), cost)-1 + if i == j: + continue + + # Sort those that have EndPoint.Authentication equal to Kerberos + # first. Then sort those that have EndPoint.Authentication equal to + # Anonymous. The rest of the CertificateEnrollmentPolicyEndPoint + # instances follow in an arbitrary order. + def sort_auth(e): + # 0x2 - Kerberos + if e['AuthFlags'] == 0x2: + return 0 + # 0x1 - Anonymous + elif e['AuthFlags'] == 0x1: + return 1 + else: + return 2 + end_point_group[i:j+1] = sorted(end_point_group[i:j+1], + key=sort_auth) + return list(end_point_groups.values()) + +''' +Obtaining End Point Information +[MS-CAESO] 4.4.5.3.2.2 +In this step autoenrollment initializes the +CertificateEnrollmentPolicyEndPoints table. +''' +def obtain_end_point_information(entries): + end_point_information = {} + section = 'Software\\Policies\\Microsoft\\Cryptography\\PolicyServers\\' + for e in entries: + if not e.keyname.startswith(section): + continue + name = e.keyname.replace(section, '') + if name not in end_point_information.keys(): + end_point_information[name] = {} + end_point_information[name][e.valuename] = e.data + for ca in end_point_information.values(): + m = re.match(endpoint_re, ca['URL']) + if m: + name = '%s-CA' % m.group('server').replace('.', '-') + ca['name'] = name + ca['hostname'] = m.group('server') + ca['auth'] = m.group('auth') + else: + edata = { 'endpoint': ca['URL'] } + log.error('Failed to parse the endpoint', edata) + end_point_information = \ + group_and_sort_end_point_information(end_point_information.values()) + return end_point_information + +''' +Initializing CAs +[MS-CAESO] 4.4.5.3.1.2 +''' def fetch_certification_authorities(ldb): result = [] basedn = ldb.get_default_basedn() - dn = 'CN=Certification Authorities,CN=Public Key Services,CN=Services,CN=Configuration,%s' % basedn - expr = '(objectClass=certificationAuthority)' - res = ldb.search(dn, SCOPE_SUBTREE, expr, ['cn']) + # Autoenrollment MUST do an LDAP search for the CA information + # (pKIEnrollmentService) objects under the following container: + dn = 'CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,%s' % basedn + attrs = ['cACertificate', 'cn', 'dNSHostName'] + expr = '(objectClass=pKIEnrollmentService)' + res = ldb.search(dn, SCOPE_SUBTREE, expr, attrs) if len(res) == 0: return result - dn = 'CN=Enrollment Services,CN=Public Key Services,CN=Services,CN=Configuration,%s' % basedn - attrs = ['cACertificate', 'cn', 'certificateTemplates', 'dNSHostName'] - for ca in res: - expr = '(cn=%s)' % ca['cn'] - res2 = ldb.search(dn, SCOPE_SUBTREE, expr, attrs) - if len(res) != 1: - continue - templates = {} - for template in res2[0]['certificateTemplates']: - templates[template] = fetch_template_attrs(ldb, template) - res = dict(res2[0]) - res['certificateTemplates'] = templates - result.append(res) + for es in res: + data = { 'name': es['cn'][0], + 'hostname': es['dNSHostName'][0], + 'cACertificate': es['cACertificate'][0] + } + result.append(data) return result def fetch_template_attrs(ldb, name, attrs=['msPKI-Minimal-Key-Size']): @@ -91,14 +180,14 @@ def get_supported_templates(server): return out.strip().split() return [] -def cert_enroll(ca, trust_dir, private_dir): +def cert_enroll(ca, ldb, trust_dir, private_dir, auth='Kerberos'): # Install the root certificate chain data = {'files': [], 'templates': []} sscep = which('sscep') if sscep is not None: url = 'http://%s/CertSrv/mscep/mscep.dll/pkiclient.exe?' % \ - ca['dNSHostName'][0] - root_cert = os.path.join(trust_dir, '%s.crt' % ca['cn']) + ca['hostname'] + root_cert = os.path.join(trust_dir, '%s.crt' % ca['name']) ret = Popen([sscep, 'getca', '-F', 'sha1', '-c', root_cert, '-u', url]).wait() if ret != 0: @@ -135,23 +224,22 @@ def cert_enroll(ca, trust_dir, private_dir): getcert = which('getcert') cepces_submit = find_cepces_submit() if getcert is not None and os.path.exists(cepces_submit): - p = Popen([getcert, 'add-ca', '-c', ca['cn'][0], '-e', - '%s --server=%s --auth=Kerberos' % (cepces_submit, - ca['dNSHostName'][0])], + p = Popen([getcert, 'add-ca', '-c', ca['name'], '-e', + '%s --server=%s --auth=%s' % (cepces_submit, + ca['hostname'], auth)], stdout=PIPE, stderr=PIPE) out, err = p.communicate() log.debug(out.decode()) if p.returncode != 0: - data = { 'Error': err.decode(), 'CA': ca['cn'][0] } + data = { 'Error': err.decode(), 'CA': ca['name'] } log.error('Failed to add Certificate Authority', data) - supported_templates = get_supported_templates(ca['dNSHostName'][0]) - for template, attrs in ca['certificateTemplates'].items(): - if template not in supported_templates: - continue - nickname = '%s.%s' % (ca['cn'][0], template.decode()) + supported_templates = get_supported_templates(ca['hostname']) + for template in supported_templates: + attrs = fetch_template_attrs(ldb, template) + nickname = '%s.%s' % (ca['name'], template.decode()) keyfile = os.path.join(private_dir, '%s.key' % nickname) certfile = os.path.join(trust_dir, '%s.crt' % nickname) - p = Popen([getcert, 'request', '-c', ca['cn'][0], + p = Popen([getcert, 'request', '-c', ca['name'], '-T', template.decode(), '-I', nickname, '-k', keyfile, '-f', certfile, '-g', attrs['msPKI-Minimal-Key-Size'][0]], @@ -221,18 +309,96 @@ class gp_cert_auto_enroll_ext(gp_pol_ext): manage = e.data & 0x2 == 1 retrive_pending = e.data & 0x4 == 1 if enroll: - url = 'ldap://%s' % get_dc_hostname(self.creds, - self.lp) - ldb = Ldb(url=url, session_info=system_session(), - lp=self.lp, credentials=self.creds) - cas = fetch_certification_authorities(ldb) - for ca in cas: - data = cert_enroll(ca, trust_dir, private_dir) - self.gp_db.store(str(self), - base64.b64encode(ca['cn'][0]).decode(), - data) + self.__enroll(pol_conf.entries, trust_dir, + private_dir) self.gp_db.commit() + ''' + Read CEP Data + [MS-CAESO] 4.4.5.3.2.4 + In this step autoenrollment initializes instances of the + CertificateEnrollmentPolicy by accessing end points associated with CEP + groups created in the previous step. + ''' + def __read_cep_data(self, ldb, end_point_information, + trust_dir, private_dir): + # For each group created in the previous step: + for end_point_group in end_point_information: + # Pick an arbitrary instance of the + # CertificateEnrollmentPolicyEndPoint from the group + e = end_point_group[0] + + # If this instance does not have the AutoEnrollmentEnabled flag set + # in the EndPoint.Flags, continue with the next group. + if not e['Flags'] & 0x10: + continue + + # If the current group contains a + # CertificateEnrollmentPolicyEndPoint instance with EndPoint.URI + # equal to "LDAP": + if any([e['URL'] == 'LDAP:' for e in end_point_group]): + # Perform an LDAP search to read the value of the objectGuid + # attribute of the root object of the forest root domain NC. If + # any errors are encountered, continue with the next group. + res = ldb.search('', SCOPE_BASE, '(objectClass=*)', + ['rootDomainNamingContext']) + if len(res) != 1: + continue + res2 = ldb.search(res[0]['rootDomainNamingContext'][0], + SCOPE_BASE, '(objectClass=*)', + ['objectGUID']) + if len(res2) != 1: + continue + + # Compare the value read in the previous step to the + # EndPoint.PolicyId datum CertificateEnrollmentPolicyEndPoint + # instance. If the values do not match, continue with the next + # group. + objectGUID = '{%s}' % \ + octet_string_to_objectGUID(res2[0]['objectGUID'][0]).upper() + if objectGUID != e['PolicyID']: + continue + + # For each CertificateEnrollmentPolicyEndPoint instance for that + # group: + for ca in end_point_group: + # If EndPoint.URI equals "LDAP": + if ca['URL'] == 'LDAP:': + # This is a basic configuration. + cas = fetch_certification_authorities(ldb) + for ca in cas: + data = cert_enroll(ca, ldb, trust_dir, private_dir) + self.gp_db.store(str(self), + base64.b64encode(ca['name']).decode(), + data) + # If EndPoint.URI starts with "HTTPS//": + elif ca['URL'].lower().startswith('https://'): + data = cert_enroll(ca, ldb, trust_dir, + private_dir, auth=ca['auth']) + self.gp_db.store(str(self), + base64.b64encode(ca['name'].encode()).decode(), + data) + else: + edata = { 'endpoint': ca['URL'] } + log.error('Unrecognized endpoint', edata) + + def __enroll(self, entries, trust_dir, private_dir): + url = 'ldap://%s' % get_dc_hostname(self.creds, self.lp) + ldb = Ldb(url=url, session_info=system_session(), + lp=self.lp, credentials=self.creds) + + end_point_information = obtain_end_point_information(entries) + if len(end_point_information) > 0: + for end_point_group in end_point_information: + self.__read_cep_data(ldb, end_point_information, + trust_dir, private_dir) + else: + cas = fetch_certification_authorities(ldb) + for ca in cas: + data = cert_enroll(ca, ldb, trust_dir, private_dir) + self.gp_db.store(str(self), + base64.b64encode(ca['name']).decode(), data) + def rsop(self, gpo): output = {} pol_file = 'MACHINE/Registry.pol' @@ -251,17 +417,30 @@ class gp_cert_auto_enroll_ext(gp_pol_ext): url = 'ldap://%s' % get_dc_hostname(self.creds, self.lp) ldb = Ldb(url=url, session_info=system_session(), lp=self.lp, credentials=self.creds) + end_point_information = \ + obtain_end_point_information(pol_conf.entries) cas = fetch_certification_authorities(ldb) + if len(end_point_information) > 0: + cas2 = [ep for sl in end_point_information for ep in sl] + if any([ca['URL'] == 'LDAP:' for ca in cas2]): + cas.extend(cas2) + else: + cas = cas2 for ca in cas: + if 'URL' in ca and ca['URL'] == 'LDAP:': + continue policy = 'Auto Enrollment Policy' - cn = ca['cn'][0] + cn = ca['name'] + if policy not in output: + output[policy] = {} output[policy][cn] = {} - output[policy][cn]['CA Certificate'] = \ - format_root_cert(ca['cACertificate'][0]).decode() + if 'cACertificate' in ca: + output[policy][cn]['CA Certificate'] = \ + format_root_cert(ca['cACertificate']).decode() output[policy][cn]['Auto Enrollment Server'] = \ - ca['dNSHostName'][0] + ca['hostname'] supported_templates = \ - get_supported_templates(ca['dNSHostName'][0]) + get_supported_templates(ca['hostname']) output[policy][cn]['Templates'] = \ [t.decode() for t in supported_templates] return output diff --git a/python/samba/tests/gpo.py b/python/samba/tests/gpo.py index a22640c75c3..8d2b3545209 100644 --- a/python/samba/tests/gpo.py +++ b/python/samba/tests/gpo.py @@ -41,7 +41,8 @@ from samba.vgp_motd_ext import vgp_motd_ext from samba.vgp_issue_ext import vgp_issue_ext from samba.vgp_access_ext import vgp_access_ext from samba.gp_gnome_settings_ext import gp_gnome_settings_ext -from samba.gp_cert_auto_enroll_ext import gp_cert_auto_enroll_ext +from samba.gp_cert_auto_enroll_ext import gp_cert_auto_enroll_ext, \ + octet_string_to_objectGUID from samba.gp_firefox_ext import gp_firefox_ext from samba.gp_chromium_ext import gp_chromium_ext from samba.gp_firewalld_ext import gp_firewalld_ext @@ -59,6 +60,7 @@ from glob import glob from configparser import ConfigParser from samba.gpclass import get_dc_hostname from samba import Ldb +import ldb as _ldb from samba.auth import system_session import json from shutil import which @@ -231,6 +233,163 @@ b""" </PolFile> """ +advanced_enroll_reg_pol = \ +b""" +<?xml version="1.0" encoding="utf-8"?> +<PolFile num_entries="30" signature="PReg" version="1"> + <Entry type="1" type_name="REG_SZ"> + <Key>Software\Policies\Microsoft\Cryptography</Key> + <ValueName>**DeleteKeys</ValueName> + <Value>Software\Policies\Microsoft\Cryptography\PolicyServers</Value> + </Entry> + <Entry type="4" type_name="REG_DWORD"> + <Key>Software\Policies\Microsoft\Cryptography\AutoEnrollment</Key> + <ValueName>AEPolicy</ValueName> + <Value>7</Value> + </Entry> + <Entry type="4" type_name="REG_DWORD"> + <Key>Software\Policies\Microsoft\Cryptography\AutoEnrollment</Key> + <ValueName>OfflineExpirationPercent</ValueName> + <Value>25</Value> + </Entry> + <Entry type="1" type_name="REG_SZ"> + <Key>Software\Policies\Microsoft\Cryptography\AutoEnrollment</Key> + <ValueName>OfflineExpirationStoreNames</ValueName> + <Value>MY</Value> + </Entry> + <Entry type="1" type_name="REG_SZ"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers</Key> + <ValueName/> + <Value>{5AD0BE6D-3393-4940-BFC3-6E19555A8919}</Value> + </Entry> + <Entry type="4" type_name="REG_DWORD"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers</Key> + <ValueName>Flags</ValueName> + <Value>0</Value> + </Entry> + <Entry type="1" type_name="REG_SZ"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54</Key> + <ValueName>URL</ValueName> + <Value>LDAP:</Value> + </Entry> + <Entry type="1" type_name="REG_SZ"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54</Key> + <ValueName>PolicyID</ValueName> + <Value>%s</Value> + </Entry> + <Entry type="1" type_name="REG_SZ"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54</Key> + <ValueName>FriendlyName</ValueName> + <Value>Example</Value> + </Entry> + <Entry type="4" type_name="REG_DWORD"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54</Key> + <ValueName>Flags</ValueName> + <Value>16</Value> + </Entry> + <Entry type="4" type_name="REG_DWORD"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54</Key> + <ValueName>AuthFlags</ValueName> + <Value>2</Value> + </Entry> + <Entry type="4" type_name="REG_DWORD"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\37c9dc30f207f27f61a2f7c3aed598a6e2920b54</Key> + <ValueName>Cost</ValueName> + <Value>2147483645</Value> + </Entry> + <Entry type="1" type_name="REG_SZ"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe</Key> + <ValueName>URL</ValueName> + <Value>https://example2.com/ADPolicyProvider_CEP_Certificate/service.svc/CEP</Value> + </Entry> + <Entry type="1" type_name="REG_SZ"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe</Key> + <ValueName>PolicyID</ValueName> + <Value>%s</Value> + </Entry> + <Entry type="1" type_name="REG_SZ"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe</Key> + <ValueName>FriendlyName</ValueName> + <Value>Example2</Value> + </Entry> + <Entry type="4" type_name="REG_DWORD"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe</Key> + <ValueName>Flags</ValueName> + <Value>16</Value> + </Entry> + <Entry type="4" type_name="REG_DWORD"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe</Key> + <ValueName>AuthFlags</ValueName> + <Value>8</Value> + </Entry> + <Entry type="4" type_name="REG_DWORD"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\144bdbb8e4717c26e408f3c9a0cb8d6cfacbcbbe</Key> + <ValueName>Cost</ValueName> + <Value>10</Value> + </Entry> + <Entry type="1" type_name="REG_SZ"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9</Key> + <ValueName>URL</ValueName> + <Value>https://example0.com/ADPolicyProvider_CEP_Kerberos/service.svc/CEP</Value> + </Entry> + <Entry type="1" type_name="REG_SZ"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9</Key> + <ValueName>PolicyID</ValueName> + <Value>%s</Value> + </Entry> + <Entry type="1" type_name="REG_SZ"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9</Key> + <ValueName>FriendlyName</ValueName> + <Value>Example0</Value> + </Entry> + <Entry type="4" type_name="REG_DWORD"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9</Key> + <ValueName>Flags</ValueName> + <Value>16</Value> + </Entry> + <Entry type="4" type_name="REG_DWORD"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9</Key> + <ValueName>AuthFlags</ValueName> + <Value>2</Value> + </Entry> + <Entry type="4" type_name="REG_DWORD"> + <Key>Software\Policies\Microsoft\Cryptography\PolicyServers\\20d46e856e9b9746c0b1265c328f126a7b3283a9</Key> + <ValueName>Cost</ValueName> + <Value>1</Value> + </Entry> + <Entry type="1" type_name="REG_SZ"> -- Samba Shared Repository