Skip to content

Commit

Permalink
Release 1.6.1045.1129
Browse files Browse the repository at this point in the history
  • Loading branch information
Sleepw4lker committed Nov 16, 2023
1 parent 75e535f commit 804e915
Show file tree
Hide file tree
Showing 60 changed files with 393 additions and 1,894 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ bld/

# Visual Studio 2015/2017 cache/options directory
.vs/
.vscode/

# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/

Expand Down Expand Up @@ -341,4 +343,4 @@ ASALocalRun/
# BeatPulse healthcheck temp database
healthchecksdb

helpers/*
*.il
4 changes: 2 additions & 2 deletions AutoVersionIncrement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
// Build Number
// Revision

[assembly: AssemblyVersion("1.6.1027.907")]
[assembly: AssemblyFileVersion("1.6.1027.907")]
[assembly: AssemblyVersion("1.6.1045.1129")]
[assembly: AssemblyFileVersion("1.6.1045.1129")]
1,258 changes: 0 additions & 1,258 deletions CERTCLILIB.il

This file was deleted.

291 changes: 0 additions & 291 deletions CERTPOLICYLIB.il

This file was deleted.

13 changes: 4 additions & 9 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
## Changelog for the TameMyCerts policy module {#changelog}

### Version \<ProductVersion\>
### Version 1.6.1045.1129

_This version was released on \<DocumentDate\>_.
_This version was released on Nov 12, 2023._

> **NOTE**
> TameMyCerts has developed into a reliable, secure and stable enterprise product. Many organizations around the world are relying on it to improve their security and their PKI workflows. Professional development, testing and documentation consumes a considerable amount of time and resources. Whilst still being fully committed on keeping source code available for the community, _digitally signed binaries_, a _print-optimized documentation_ and _priority support_ are benefits **only available for customers with an active maintenance contract**.
This is a major release containing lots of bug fixes for edge-cases as well as many new exciting features, whilst staying backwards-compatible to existing configuration files.

- The _SubjectDistingushedName_ directive within _DirectoryServicesMapping_ has been renamed to _DsBoundSubject_. **Note that this breaks existing policy files. These must be adjusted when upgrading.**
- The _RelativeDistingushedName_ directive within _DirectoryServicesMapping_ has been renamed to _DsBoundSubjectRule_. **Note that this breaks existing policy files. These must be adjusted when upgrading.**
- TameMyCerts now implements caching for policy configuration files. Instead of loading them over and over again for any incoming request, this is now only done if the file has changed.
- TameMyCerts now supports for building or extending the Subject Alternative Name extension of issued certificates with configurable attributes from a mapped Active Directory object. You configure a _DsBoundSubjectAlternativeName_ Node containing at least one _DsBoundSubjectRule_ within _DirectoryServicesMapping_.
- TameMyCerts now supports setting static values into the Subject Relative Distinguished Name with the _StaticSubject_ directive containing at least one _StaticSubjectRule_.
- TameMyCerts now supports setting static values into the Subject Alternative Name with the _StaticSubjectAlternativeName_ directive containing at least one _StaticSubjectRule_.
- TameMyCerts now supports modifying the Subject Distinguished Name and Subject Alternative Name of issued certificates with attributes of mapped Active Directory objects, values from certificate request fields, static strings, or a combination of all these. **Note that this breaks existing policy files. These must be adjusted when upgrading.**
- TameMyCerts now implements caching for policy configuration files. Instead of loading them over and over again for any incoming request, this is now only done if the file has changed..
- TameMyCerts now supports configuring per-Template CRL Distribution Point, Authority Information Access, and Online Certificate Status Protocol URIs. Configure them with the _CrlDistributionPoints_, _AuthorityInformationAccess_ and _OnlineCertificateStatusProtocol_ directives.
- TameMyCerts now automatically determines the desired key algorithm from the certificate template. The _KeyAlgorithm_ parameter has therefore been removed. Existing configurations will continue to work but without using the configured _KeyAlgorithm_.
- TameMyCerts now reads all available request properties directly from the certification authority instead of parsing the inline request. The inline certificate request will now only be parsed when _AllowedProcesses_ or _DisallowedProcesses_ directives are configured, as this information cannot be obtained from the CA directly. There are rare cases where it may not be possible to parse the inline certificate request. In this case, the requested properties will be treated as non-existent.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.

namespace TameMyCerts.Models
using System.Text.RegularExpressions;

namespace TameMyCerts.ClassExtensions
{
// Must be public due to XML serialization, otherwise 0x80131509 / System.InvalidOperationException
public class DsBoundSubjectRule
public static class StringExtensions
{
public string Field { get; set; } = string.Empty;
public string DirectoryServicesAttribute { get; set; } = "userPrincipalName";
public bool Mandatory { get; set; }
public static string ReplaceCaseInsensitive(this string input, string from, string to)
{
return Regex.Replace(input, from, to, RegexOptions.IgnoreCase);
}
}
}
5 changes: 5 additions & 0 deletions Enums/WinError.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ internal static class WinError
/// </summary>
public const int CERTSRV_E_KEY_LENGTH = unchecked((int)0x80094811);

/// <summary>
/// The certificate is not valid for the requested usage.
/// </summary>
public const int CERT_E_WRONG_USAGE = unchecked((int)0x800B0110);

/// <summary>
/// The certificate has an invalid name. The name is not included in the permitted list or is explicitly excluded.
/// </summary>
Expand Down
30 changes: 24 additions & 6 deletions LocalizedStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 11 additions & 4 deletions LocalizedStrings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -300,11 +300,11 @@
<data name="DirVal_Invalid_Rule_Attribute" xml:space="preserve">
<value>The mandatory "{0}" attribute is not present on {1}. Unable to apply syntax rules.</value>
</data>
<data name="StatVal_Rdn_Invalid_Field" xml:space="preserve">
<value>The field name "{0}" that was specified for construction of a static subject relative distinguished is unsupported.</value>
<data name="Rdn_Invalid_Field" xml:space="preserve">
<value>The field name "{0}" that was specified for construction of a Subject Relative Distinguished name is unsupported.</value>
</data>
<data name="StatVal_Rdn_Value_Too_Long" xml:space="preserve">
<value>The value "{0}" for that was specified for construction of the static subject relative distinguished name with type "{1}" is too long. The maximum length is {2} characters for this RDN but the attribute is {3} characters long.</value>
<data name="Rdn_Value_Too_Long" xml:space="preserve">
<value>The value "{0}" for that was specified for construction of the Subject Relative Distinguished Name of type "{1}" is too long. The maximum length is {2} characters for this RDN, but the attribute is {3} characters long.</value>
</data>
<data name="DirVal_San_Failed_to_add" xml:space="preserve">
<value>The attempt to add the mandatory directory attribute "{0}" to the mandatory "{1}" subject alternative name type failed for {2}. This may be because of an incompatibility of data types.</value>
Expand All @@ -318,4 +318,11 @@
<data name="FinVal_No_Identity" xml:space="preserve">
<value>The resulting certificate wouldn't contain any identity in form of a commonName or a Subject Alternative Name.</value>
</data>
<data name="San_unable_to_add" xml:space="preserve">
<value>Unable to add entry of type "{0}" with value "{1}" to the Subject Alternative Name certificate extension. Either type or value is invalid.</value>
</data>
<data name="Token_invalid" xml:space="preserve">
<value>The "{0}" token for the construction of a Subject Relative Distinguished Name is unknown. Ensure that Directory Service Mapping is enabled if it is an AD attribute, and that the originating certificate request contains the token, if it is a request field.</value>
<comment>"</comment>
</data>
</root>
7 changes: 2 additions & 5 deletions Models/ActiveDirectoryObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ internal class ActiveDirectoryObject
private const StringComparison COMPARISON = StringComparison.InvariantCultureIgnoreCase;

public ActiveDirectoryObject(string forestRootDomain, string dsAttribute, string identity,
string objectCategory, string searchRoot, bool loadExtendedAttributes = false)
string objectCategory, string searchRoot)
{
if (!DsMappingAttributes.Any(s => s.Equals(dsAttribute, COMPARISON)))
{
Expand All @@ -55,10 +55,7 @@ public ActiveDirectoryObject(string forestRootDomain, string dsAttribute, string
"memberOf", "userAccountControl", "objectSid", "distinguishedName", "servicePrincipalName"
};

// Only load extended attributes if we have a use for them (e.g. modifying Subject DN from AD attributes)
attributesToRetrieve.AddRange(loadExtendedAttributes
? DsRetrievalAttributes
: new List<string> {"sAMAccountName"}); // "sAMAccountName" attribute is mandatory
attributesToRetrieve.AddRange(DsRetrievalAttributes);

var dsObject = GetDirectoryEntry($"LDAP://{searchRoot}", dsAttribute, identity, objectCategory,
attributesToRetrieve);
Expand Down
4 changes: 2 additions & 2 deletions Models/CertificateRequestPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ public class CertificateRequestPolicy
public int MaximumKeyLength { get; set; }
public List<SubjectRule> Subject { get; set; } = new List<SubjectRule>();
public List<SubjectRule> SubjectAlternativeName { get; set; } = new List<SubjectRule>();
public List<StaticSubjectRule> StaticSubject { get; set; } = new List<StaticSubjectRule>();
public List<StaticSubjectRule> StaticSubjectAlternativeName { get; set; } = new List<StaticSubjectRule>();
public List<OutboundSubjectRule> OutboundSubject { get; set; } = new List<OutboundSubjectRule>();
public List<OutboundSubjectRule> OutboundSubjectAlternativeName { get; set; } = new List<OutboundSubjectRule>();
public string SecurityIdentifierExtension { get; set; } = "Deny";
public DirectoryServicesMapping DirectoryServicesMapping { get; set; }
public bool SupplementDnsNames { get; set; }
Expand Down
20 changes: 18 additions & 2 deletions Models/CertificateRequestValidationResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using TameMyCerts.Enums;
using TameMyCerts.X509;

Expand Down Expand Up @@ -99,15 +100,30 @@ public Dictionary<string, byte[]> CertificateExtensions
/// <summary>
/// A list of certificate properties that shall be set after TameMyCerts has processed the certificate request
/// </summary>
public List<KeyValuePair<string, string>> CertificateProperties { get; } =
new List<KeyValuePair<string, string>>();
public Dictionary<string, string> CertificateProperties { get; } = new Dictionary<string, string>();

// TODO: Implement setter method
/// <summary>
/// The Subject Alternative Name certificate extension class. It allows to inspect or add or remove entries.
/// </summary>
public X509CertificateExtensionSubjectAlternativeName SubjectAlternativeNameExtension { get; }

public void SetSubjectDistinguishedName(string key, string value)
{
if (!RdnTypes.ToList().Contains(key))
{
throw new NotSupportedException(string.Format(LocalizedStrings.Rdn_Invalid_Field, key));
}

if (value.Length > RdnTypes.LengthConstraint[key])
{
throw new NotSupportedException(string.Format(LocalizedStrings.Rdn_Value_Too_Long, value,
key, RdnTypes.LengthConstraint[key], value.Length));
}

CertificateProperties[RdnTypes.NameProperty[key]] = value;
}

public void AddCertificateExtension(string key, byte[] value)
{
_certificateExtensions[key] = value;
Expand Down
2 changes: 1 addition & 1 deletion Models/CertificateTemplateCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ private static KeyAlgorithmType GetKeyAlgorithm(string keyAlgorithmString)
{
foreach (var algorithmName in Enum.GetNames(typeof(KeyAlgorithmType)))
{
if (keyAlgorithmString.Contains(algorithmName))
if (keyAlgorithmString.Contains($"msPKI-Asymmetric-Algorithm`PZPWSTR`{algorithmName}`"))
{
return (KeyAlgorithmType)Enum.Parse(typeof(KeyAlgorithmType), algorithmName);
}
Expand Down
2 changes: 0 additions & 2 deletions Models/DirectoryServicesMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,5 @@ public class DirectoryServicesMapping
public bool PermitDisabledAccounts { get; set; } = false;
public bool SupplementServicePrincipalNames { get; set; } = false;
public bool AddSidUniformResourceIdentifier { get; set; } = false;
public List<DsBoundSubjectRule> DsBoundSubject { get; set; } = new List<DsBoundSubjectRule>();
public List<DsBoundSubjectRule> DsBoundSubjectAlternativeName { get; set; } = new List<DsBoundSubjectRule>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
namespace TameMyCerts.Models
{
// Must be public due to XML serialization, otherwise 0x80131509 / System.InvalidOperationException
public class StaticSubjectRule
public class OutboundSubjectRule
{
public string Field { get; set; } = string.Empty;
public string Value { get; set; } = string.Empty;
public bool Mandatory { get; set; }
public bool Force { get; set; }
}
}
13 changes: 8 additions & 5 deletions Policy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public class Policy : ICertPolicy2
private readonly CertificateRequestValidator _crValidator = new CertificateRequestValidator();
private readonly DirectoryServiceValidator _dsValidator = new DirectoryServiceValidator();
private readonly RequestAttributeValidator _raValidator = new RequestAttributeValidator();
private readonly StaticContentValidator _scValidator = new StaticContentValidator();
private readonly CertificateContentValidator _ccValidator = new CertificateContentValidator();
private readonly FinalResultValidator _frValidator = new FinalResultValidator();
private readonly CertificateTemplateCache _templateCache = new CertificateTemplateCache();
private CertificateAuthorityConfiguration _caConfig;
Expand Down Expand Up @@ -160,8 +160,11 @@ public int VerifyRequest(string strConfig, int context, int isNewRequest, int fl
#region Process policy-dependent validators

result = _crValidator.VerifyRequest(result, policy, dbRow, template);
result = _dsValidator.VerifyRequest(result, policy, dbRow, template);
result = _scValidator.VerifyRequest(result, policy, dbRow, _caConfig);

result = _dsValidator.GetMappedActiveDirectoryObject(result, policy, dbRow, template, out var dsObject);

result = _dsValidator.VerifyRequest(result, policy, dsObject);
result = _ccValidator.VerifyRequest(result, policy, dbRow, dsObject, _caConfig);
result = _frValidator.VerifyRequest(result, policy, dbRow);

#endregion
Expand Down Expand Up @@ -193,7 +196,7 @@ public int VerifyRequest(string strConfig, int context, int isNewRequest, int fl
result.DisabledCertificateProperties.ForEach(name =>
serverPolicy.DisableCertificateProperty(name));

result.CertificateProperties.ForEach(keyValuePair =>
result.CertificateProperties.ToList().ForEach(keyValuePair =>
serverPolicy.SetCertificateProperty(keyValuePair.Key, keyValuePair.Value));

#endregion
Expand All @@ -215,7 +218,7 @@ public int VerifyRequest(string strConfig, int context, int isNewRequest, int fl
#region Deny request in any other case

_logger.Log(Events.REQUEST_DENIED, requestId, template.Name,
string.Join("\n", result.Description));
string.Join("\n", result.Description.Distinct().ToList()));

// Seems that lower error codes must be thrown as exception
if (result.StatusCode > CertSrv.VR_INSTANT_BAD &&
Expand Down
Loading

0 comments on commit 804e915

Please sign in to comment.