Answered by:
How to use ICertAdminD2::GetCASecurity

Question
-
Greetings,
I have a project in which I need to programmatically report the permissions set on a ADCS enterprise CA. I've been able to determine that the method GetCASecurity from the ICertADminD2 interface should be able to get what I need, however, I have a few questions:
1. What Namespace(s) do I need to be using in order to be able to leverage the ICertAdminD2 interface?
2. The MSDN documentation indicates that the return value from the GetCASecurity method is a pointer to data of type "CERTTRANSBLOB" is anyone familiar with working with that particular data structure? I need to somehow obtain a list of security groups from it.
Thanks in advance!
Monday, March 2, 2015 4:49 PM
Answers
-
Windows 2008 R2.
I was finally able to figure it out! I had to implement some methods included in the CommonObjectSecurity interface. The only other sticking point was determining which hex values mapped to each CA privilege. Most implementations I came across used an enumeration, but I opted to create a small class to handle it.
Here's what I did:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; using System.Security.AccessControl; using System.Security.Principal; using CERTADMINLib; namespace getCAPermissions { public class ProxySecurity : CommonObjectSecurity { public ProxySecurity(bool isContainer) : base(isContainer) { } public override AccessRule AccessRuleFactory(IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type) { return new ProxyAccessRule(identityReference, accessMask, type); } public override Type AccessRuleType { get { return typeof(ProxyAccessRule); } } public override AuditRule AuditRuleFactory(IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags) { throw new NotImplementedException(); } public override Type AuditRuleType { get { throw new NotImplementedException(); } } public override Type AccessRightType { //get { return typeof(ProxyRightsEnum); } get { return typeof(int); } } } public class ProxyAccessRule : AccessRule { public ProxyAccessRule(IdentityReference identity, int accessMask, AccessControlType accessType) : base(identity, accessMask, false, InheritanceFlags.None, PropagationFlags.None, accessType) { } public int AccessRights { get { return AccessMask; } } } class Program { static void Main(string[] args) { if (args.Length != 1) { Console.WriteLine("Usage: getCAPermissions.exe [CA Config parameter]"); return; } CCertAdmin certAdmin = new CCertAdmin(); byte[] security; try { //byte[] security = certAdmin.GetConfigEntry(@"DCCA.mikeslab.com\MIKESLAB Issuing CA", "", "Security"); security = certAdmin.GetConfigEntry(args[0], "", "Security"); } catch (Exception e) { Console.WriteLine(e.ToString() + Environment.NewLine + "Usage: getCAPermissions.exe [CA Config parameter]"); return; } ProxySecurity CASecurity = new ProxySecurity(false); CASecurity.SetSecurityDescriptorBinaryForm(security, AccessControlSections.All); AuthorizationRuleCollection coll = CASecurity.GetAccessRules(true, false, typeof(NTAccount)); int rights; PrivilegedUserOrGroup pg; foreach (AuthorizationRule rule in coll) { ProxyAccessRule accRule = rule as ProxyAccessRule; rights = accRule.AccessRights; pg = new PrivilegedUserOrGroup(rule.IdentityReference.Value, rights, accRule.AccessControlType.ToString()); foreach (string right in pg.rightsList) { Console.WriteLine("Name: " + pg.n + " Right: " + right + " Type:" + pg.type); } //Console.WriteLine("User or Group: \"{0}\" Permissions: {1} Access Type: {2}", rule.IdentityReference.Value, rights.ToString(), accRule.AccessControlType.ToString()); } } } class PrivilegedUserOrGroup { public string n; public List<string> rightsList; public string type; public PrivilegedUserOrGroup(string name, int accessRights, string accessType) { n = name; type = accessType; rightsList = getRights(accessRights); } private List<string> getRights(int rights) { string noRights = "No Rights"; string ca = "Manage CA"; string certs = "Issue and Manage Certificates"; string read = "Read"; string req = "Request Certificates"; List<string> result = new List<string>(); switch (rights) { case 0x000: result.Add(noRights); break; case 0x001: result.Add(ca); break; case 0x002: result.Add(certs); break; case 0x003: result.Add(ca); result.Add(certs); break; case 0x100: result.Add(read); break; case 0x101: result.Add(ca); result.Add(read); break; case 0x102: result.Add(certs); result.Add(read); break; case 0x103: result.Add(ca); result.Add(certs); result.Add(read); break; case 0x200: result.Add(req); break; case 0x201: result.Add(ca); result.Add(req); break; case 0x202: result.Add(certs); result.Add(req); break; case 0x203: result.Add(ca); result.Add(certs); result.Add(req); break; case 0x300: result.Add(read); result.Add(req); break; case 0x301: result.Add(ca); result.Add(read); result.Add(req); break; case 0x302: result.Add(certs); result.Add(read); result.Add(req); break; case 0x303: result.Add(ca); result.Add(certs); result.Add(read); result.Add(req); break; default: result.Add("ERROR"); break; } return result; } } }
- Marked as answer by Mike Bruno Thursday, March 5, 2015 1:29 PM
Thursday, March 5, 2015 1:28 PM
All replies
-
Hi Mike, thank you for your question. A member of the protocol documentation team will respond to you soon.
Josh Curry (jcurry) | Escalation Engineer | Open Specifications Support Team
Monday, March 2, 2015 9:16 PM -
Hi Mike:
I will help you with this issue and will be in touch as soon as I have an answer.
Regards, Obaid Farooqi
Tuesday, March 3, 2015 10:10 PM -
Thank you!Wednesday, March 4, 2015 2:22 PM
-
Hi Mike:
Which platform you are developing on? Windows or non-Windows?
Regards, Obaid Farooqi
Wednesday, March 4, 2015 6:27 PM -
Windows 2008 R2.
I was finally able to figure it out! I had to implement some methods included in the CommonObjectSecurity interface. The only other sticking point was determining which hex values mapped to each CA privilege. Most implementations I came across used an enumeration, but I opted to create a small class to handle it.
Here's what I did:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Runtime.InteropServices; using System.Security.AccessControl; using System.Security.Principal; using CERTADMINLib; namespace getCAPermissions { public class ProxySecurity : CommonObjectSecurity { public ProxySecurity(bool isContainer) : base(isContainer) { } public override AccessRule AccessRuleFactory(IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AccessControlType type) { return new ProxyAccessRule(identityReference, accessMask, type); } public override Type AccessRuleType { get { return typeof(ProxyAccessRule); } } public override AuditRule AuditRuleFactory(IdentityReference identityReference, int accessMask, bool isInherited, InheritanceFlags inheritanceFlags, PropagationFlags propagationFlags, AuditFlags flags) { throw new NotImplementedException(); } public override Type AuditRuleType { get { throw new NotImplementedException(); } } public override Type AccessRightType { //get { return typeof(ProxyRightsEnum); } get { return typeof(int); } } } public class ProxyAccessRule : AccessRule { public ProxyAccessRule(IdentityReference identity, int accessMask, AccessControlType accessType) : base(identity, accessMask, false, InheritanceFlags.None, PropagationFlags.None, accessType) { } public int AccessRights { get { return AccessMask; } } } class Program { static void Main(string[] args) { if (args.Length != 1) { Console.WriteLine("Usage: getCAPermissions.exe [CA Config parameter]"); return; } CCertAdmin certAdmin = new CCertAdmin(); byte[] security; try { //byte[] security = certAdmin.GetConfigEntry(@"DCCA.mikeslab.com\MIKESLAB Issuing CA", "", "Security"); security = certAdmin.GetConfigEntry(args[0], "", "Security"); } catch (Exception e) { Console.WriteLine(e.ToString() + Environment.NewLine + "Usage: getCAPermissions.exe [CA Config parameter]"); return; } ProxySecurity CASecurity = new ProxySecurity(false); CASecurity.SetSecurityDescriptorBinaryForm(security, AccessControlSections.All); AuthorizationRuleCollection coll = CASecurity.GetAccessRules(true, false, typeof(NTAccount)); int rights; PrivilegedUserOrGroup pg; foreach (AuthorizationRule rule in coll) { ProxyAccessRule accRule = rule as ProxyAccessRule; rights = accRule.AccessRights; pg = new PrivilegedUserOrGroup(rule.IdentityReference.Value, rights, accRule.AccessControlType.ToString()); foreach (string right in pg.rightsList) { Console.WriteLine("Name: " + pg.n + " Right: " + right + " Type:" + pg.type); } //Console.WriteLine("User or Group: \"{0}\" Permissions: {1} Access Type: {2}", rule.IdentityReference.Value, rights.ToString(), accRule.AccessControlType.ToString()); } } } class PrivilegedUserOrGroup { public string n; public List<string> rightsList; public string type; public PrivilegedUserOrGroup(string name, int accessRights, string accessType) { n = name; type = accessType; rightsList = getRights(accessRights); } private List<string> getRights(int rights) { string noRights = "No Rights"; string ca = "Manage CA"; string certs = "Issue and Manage Certificates"; string read = "Read"; string req = "Request Certificates"; List<string> result = new List<string>(); switch (rights) { case 0x000: result.Add(noRights); break; case 0x001: result.Add(ca); break; case 0x002: result.Add(certs); break; case 0x003: result.Add(ca); result.Add(certs); break; case 0x100: result.Add(read); break; case 0x101: result.Add(ca); result.Add(read); break; case 0x102: result.Add(certs); result.Add(read); break; case 0x103: result.Add(ca); result.Add(certs); result.Add(read); break; case 0x200: result.Add(req); break; case 0x201: result.Add(ca); result.Add(req); break; case 0x202: result.Add(certs); result.Add(req); break; case 0x203: result.Add(ca); result.Add(certs); result.Add(req); break; case 0x300: result.Add(read); result.Add(req); break; case 0x301: result.Add(ca); result.Add(read); result.Add(req); break; case 0x302: result.Add(certs); result.Add(read); result.Add(req); break; case 0x303: result.Add(ca); result.Add(certs); result.Add(read); result.Add(req); break; default: result.Add("ERROR"); break; } return result; } } }
- Marked as answer by Mike Bruno Thursday, March 5, 2015 1:29 PM
Thursday, March 5, 2015 1:28 PM -
Hi Mark:
Glad to see that you figured it out.
I see that you use a Windows API and that is the right approach if you are developing on Windows.
Your original question was about a DCOM interface described in MS-CSRA open specification. This forum is dedicated to supporting issues related to open specifications that can be found at http://microsoft.com/openspecifications by clicking on "Documentation Library" button.
If you have a question on a Managed Windows API, you have a better chance of getting an answer if you post it on forums related to C# development or a .net forum.
Please feel free to post here if you have a question/comment on any of the open specifications.
Regards, Obaid Farooqi
Thursday, March 5, 2015 4:04 PM