| File: System\Security\Cryptography\X509Certificates\X509BasicConstraintsExtension.cs | Web Access |
| Project: src\runtime\src\libraries\System.Security.Cryptography\src\System.Security.Cryptography.csproj (System.Security.Cryptography) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Formats.Asn1; using System.Security.Cryptography.X509Certificates.Asn1; namespace System.Security.Cryptography.X509Certificates { public sealed class X509BasicConstraintsExtension : X509Extension { public X509BasicConstraintsExtension() : base(Oids.BasicConstraints2Oid) { _decoded = true; } public X509BasicConstraintsExtension(bool certificateAuthority, bool hasPathLengthConstraint, int pathLengthConstraint, bool critical) : base(Oids.BasicConstraints2Oid, EncodeExtension(certificateAuthority, hasPathLengthConstraint, pathLengthConstraint), critical, skipCopy: true) { } public X509BasicConstraintsExtension(AsnEncodedData encodedBasicConstraints, bool critical) : base(Oids.BasicConstraints2Oid, encodedBasicConstraints.RawData, critical) { } public bool CertificateAuthority { get { if (!_decoded) DecodeExtension(); return _certificateAuthority; } } public bool HasPathLengthConstraint { get { if (!_decoded) DecodeExtension(); return _hasPathLenConstraint; } } public int PathLengthConstraint { get { if (!_decoded) DecodeExtension(); return _pathLenConstraint; } } public override void CopyFrom(AsnEncodedData asnEncodedData) { base.CopyFrom(asnEncodedData); _decoded = false; } /// <summary> /// Creates an instance of <see cref="X509BasicConstraintsExtension"/> appropriate for /// a certificate authority, optionally including a path length constraint value. /// </summary> /// <param name="pathLengthConstraint"> /// The longest valid length of a certificate chain between the certificate containing /// this extension and an end-entity certificate. /// The default is <see langword="null" />, an unconstrained length. /// </param> /// <returns> /// The configured basic constraints extension. /// </returns> /// <remarks> /// Following the guidance from IETF RFC 3280, the extension returned from this method /// will have the <see cref="X509Extension.Critical"/> property set to <see langword="true" />. /// </remarks> /// <exception cref="ArgumentOutOfRangeException"> /// <paramref name="pathLengthConstraint"/> is a non-null value less than zero. /// </exception> public static X509BasicConstraintsExtension CreateForCertificateAuthority(int? pathLengthConstraint = null) { return new X509BasicConstraintsExtension( true, pathLengthConstraint.HasValue, pathLengthConstraint.GetValueOrDefault(), true); } /// <summary> /// Creates an instance of <see cref="X509BasicConstraintsExtension"/> appropriate for /// an end-entity certificate, optionally marking the extension as critical. /// </summary> /// <param name="critical"> /// <see langword="true" /> to mark the extension as critical; <see langword="false" /> otherwise. /// The default is <see langword="false" />. /// </param> /// <returns> /// The configured basic constraints extension. /// </returns> public static X509BasicConstraintsExtension CreateForEndEntity(bool critical = false) { return new X509BasicConstraintsExtension(false, false, 0, critical); } private static byte[] EncodeExtension(bool certificateAuthority, bool hasPathLengthConstraint, int pathLengthConstraint) { if (hasPathLengthConstraint) { ArgumentOutOfRangeException.ThrowIfNegative(pathLengthConstraint); } return EncodeX509BasicConstraints2Extension(certificateAuthority, hasPathLengthConstraint, pathLengthConstraint); } private void DecodeExtension() { if (Oid!.Value == Oids.BasicConstraints) { LegacyBasicConstraintsDecoder.DecodeX509BasicConstraintsExtension( RawData, out _certificateAuthority, out _hasPathLenConstraint, out _pathLenConstraint); } else { DecodeX509BasicConstraints2Extension( RawData, out _certificateAuthority, out _hasPathLenConstraint, out _pathLenConstraint); } _decoded = true; } private static byte[] EncodeX509BasicConstraints2Extension( bool certificateAuthority, bool hasPathLengthConstraint, int pathLengthConstraint) { BasicConstraintsAsn constraints = default; constraints.CA = certificateAuthority; if (hasPathLengthConstraint) { constraints.PathLengthConstraint = pathLengthConstraint; } // Largest possible encoded extension is 11 bytes when pathLenConstraint is int.MaxValue. AsnWriter writer = new AsnWriter(AsnEncodingRules.DER, initialCapacity: 11); constraints.Encode(writer); return writer.Encode(); } private static void DecodeX509BasicConstraints2Extension( byte[] encoded, out bool certificateAuthority, out bool hasPathLengthConstraint, out int pathLengthConstraint) { BasicConstraintsAsn constraints = BasicConstraintsAsn.Decode(encoded, AsnEncodingRules.BER); certificateAuthority = constraints.CA; hasPathLengthConstraint = constraints.PathLengthConstraint.HasValue; pathLengthConstraint = constraints.PathLengthConstraint.GetValueOrDefault(); } private bool _certificateAuthority; private bool _hasPathLenConstraint; private int _pathLenConstraint; private bool _decoded; } }