-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
X.509 Extensions #59191
Comments
Tagging subscribers to this area: @bartonjs, @vcsjones, @krwq, @GrabYourPitchforks Issue DetailsHi, I do not find equivalent of some of these extensions in System.Security.Cryptography.X509Certificates:
Is there a plan to add Certificate Template Information, Certificate Policies, Authority Key Identifier and S/MIME Capabilities extensions?
|
The only one that has a tracking issue is the AKI at #50488.
As far as I know, this is just an extension that contains a BMPString, so it's doable to create this extension with For example: static X509Extension GetTemplateExtension(string templateName)
{
AsnWriter writer = new(AsnEncodingRules.DER);
writer.WriteCharacterString(UniversalTagNumber.BMPString, templateName);
return new X509Extension("1.3.6.1.4.1.311.20.2", writer.Encode(), false);
} |
They all (along with the rest of https://datatracker.ietf.org/doc/html/rfc5280#section-4.2) seem generally reasonable and on-theme for improving the support for creating (and then reading) Certification Signing Requests. |
@vcsjones You must have found a different certificate template than I did. I found 1.3.6.1.4.1.311.21.7, which has structure 😄 |
I used the one from the cited link https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/ff182332(v=ws.10).
I think that is "V2 Template Names". |
Thanks, Items include following: How can i do that? |
Let's look at the ASN.1 syntax that
We can build this with We can package this nicely up in to our own public sealed class CertificateTemplate2X509Extension : X509Extension
{
public Oid TemplateOid { get; }
public long? MajorVersion { get; }
public long? MinorVersion { get; }
public CertificateTemplate2X509Extension(Oid templateOid, long? majorVersion = null, long? minorVersion = null)
: base("1.3.6.1.4.1.311.21.7", Encode(templateOid, majorVersion, minorVersion), critical: false)
{
TemplateOid = templateOid;
MajorVersion = majorVersion;
MinorVersion = minorVersion;
}
private static byte[] Encode(
Oid templateOid,
long? majorVersion,
long? minorVersion)
{
if (templateOid is null || templateOid.Value is null)
throw new ArgumentException(nameof(templateOid));
if (minorVersion is not null && majorVersion is null)
throw new ArgumentException("Specifying a minor version requires a major version", nameof(minorVersion));
if (majorVersion is < 0 or > uint.MaxValue)
throw new ArgumentOutOfRangeException(nameof(majorVersion));
if (minorVersion is < 0 or > uint.MaxValue)
throw new ArgumentOutOfRangeException(nameof(minorVersion));
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
using (writer.PushSequence())
{
writer.WriteObjectIdentifier(templateOid.Value);
if (majorVersion is not null)
{
writer.WriteInteger(majorVersion.Value);
}
if (minorVersion is not null)
{
writer.WriteInteger(minorVersion.Value);
}
}
return writer.Encode();
}
} And then you can add it to your CertificateRequest req = new("CN=blah", ecdsa, HashAlgorithmName.SHA256);
Oid templateOid = new Oid("1.3.6.1.2.3.4.5.6.7", null);
req.CertificateExtensions.Add(new CertificateTemplate2X509Extension(templateOid, majorVersion: 100, minorVersion: 37));
using X509Certificate2 cert = req.CreateSelfSigned(DateTime.Now, DateTime.Now); You can follow this pattern for any |
Very thanks @vcsjones |
Sure. Here is a complete example of creating a certificate with the extension, then parsing it back out. #nullable enable
using System;
using System.Formats.Asn1;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using ECDsa ecdsa = ECDsa.Create();
CertificateRequest req = new CertificateRequest("CN=hello", ecdsa, HashAlgorithmName.SHA256);
req.CertificateExtensions.Add(new CertificateTemplate2X509Extension(new Oid("1.3.6.1.2.3.4", null), 70, 35));
X509Certificate2 cert = req.CreateSelfSigned(DateTime.Now, DateTime.Now);
foreach (X509Extension ext in cert.Extensions)
{
if (ext.Oid?.Value == CertificateTemplate2X509Extension.ExtensionOid)
{
CertificateTemplate2X509Extension template2X509Extension = CertificateTemplate2X509Extension.Parse(ext.RawData);
Console.WriteLine(template2X509Extension.TemplateOid.Value);
Console.WriteLine(template2X509Extension.MajorVersion?.ToString() ?? "no major");
Console.WriteLine(template2X509Extension.MinorVersion?.ToString() ?? "no minor");
}
}
public sealed class CertificateTemplate2X509Extension : X509Extension
{
public const string ExtensionOid = "1.3.6.1.4.1.311.21.7";
public Oid TemplateOid { get; }
public long? MajorVersion { get; }
public long? MinorVersion { get; }
public CertificateTemplate2X509Extension(Oid templateOid, long? majorVersion = null, long? minorVersion = null)
: base(ExtensionOid, Encode(templateOid, majorVersion, minorVersion), critical: false)
{
TemplateOid = templateOid;
MajorVersion = majorVersion;
MinorVersion = minorVersion;
}
private static byte[] Encode(
Oid templateOid,
long? majorVersion,
long? minorVersion)
{
if (templateOid is null || templateOid.Value is null)
throw new ArgumentException(nameof(templateOid));
if (minorVersion is not null && majorVersion is null)
throw new ArgumentException("Specifying a minor version requires a major version", nameof(minorVersion));
if (majorVersion is < 0 or > uint.MaxValue)
throw new ArgumentOutOfRangeException(nameof(majorVersion));
if (minorVersion is < 0 or > uint.MaxValue)
throw new ArgumentOutOfRangeException(nameof(minorVersion));
AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);
using (writer.PushSequence())
{
writer.WriteObjectIdentifier(templateOid.Value);
if (majorVersion is not null)
{
writer.WriteInteger(majorVersion.Value);
}
if (minorVersion is not null)
{
writer.WriteInteger(minorVersion.Value);
}
}
return writer.Encode();
}
public static CertificateTemplate2X509Extension Parse(byte[] extensionDer)
{
AsnReader reader = new AsnReader(extensionDer, AsnEncodingRules.DER);
AsnReader sequenceReader = reader.ReadSequence();
reader.ThrowIfNotEmpty(); // Validate there is no data after the outer sequence.
string templateId = sequenceReader.ReadObjectIdentifier();
long? major = null, minor = null;
if (sequenceReader.HasData) // Is there optional data? Then we have at least a major
{
// Read the major version. We know there is more data, so if it fails,
// either the number is out-of-bounds or it is the wrong tag.
if (!sequenceReader.TryReadUInt32(out uint parsedMajor))
{
throw new InvalidOperationException("Major version is invalid.");
}
major = parsedMajor;
}
if (sequenceReader.HasData) // Is there still more optional data? Then we have a minor
{
if (!sequenceReader.TryReadUInt32(out uint parsedMinor))
{
throw new InvalidOperationException("Minor version is invalid.");
}
minor = parsedMinor;
}
// We've read everything we can possibly read. Let's validate the SEQUENCE is empty
// because if it isn't, we don't know what to do with the rest of it and the extension
// is malformed.
sequenceReader.ThrowIfNotEmpty();
return new CertificateTemplate2X509Extension(new Oid(templateId, null), major, minor);
}
} |
I believe all questions have been answered, and that the actionable pieces are already tracked by other issues. Closing. |
Hi,
The following link provides several extensions for X.509 Request:
https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/ff182332(v=ws.10)
I do not find equivalent of some of these extensions in System.Security.Cryptography.X509Certificates:
Is there a plan to add Certificate Template Information, Certificate Policies, Authority Key Identifier and S/MIME Capabilities extensions?
The text was updated successfully, but these errors were encountered: