Skip to content
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

Prototype: Don't Be A CA #2

Closed
wants to merge 43 commits into from
Closed
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
b5f340a
First stab at a CRL builder
bartonjs May 20, 2022
f56f197
Use the new CertificateRevocationListBuilder in the test CA system
bartonjs May 26, 2022
486ea9b
Start adding CrlBuilder tests
bartonjs Jun 1, 2022
f3de733
Add AKID
bartonjs Jun 2, 2022
215437b
Add SAN extension
bartonjs Jun 3, 2022
59b267a
Use less memory in SANBuilder
bartonjs Jun 3, 2022
1322165
CDP Builder
bartonjs Jun 3, 2022
e8cd63e
PKCS10 loading, part 1
bartonjs Jun 3, 2022
a9f179e
X509BasicConstraintsExtension, Quality of Life
bartonjs Jun 3, 2022
6d5dc06
Don't Be A CA.
bartonjs Jun 3, 2022
79961fd
Support CRLs numbered to (practically) infinity... and beyond.
bartonjs Jun 6, 2022
f62cdbf
Respond to early review feedback
bartonjs Jun 7, 2022
ff72707
Words matter, apparently
bartonjs Jun 7, 2022
0569f63
Early draft iterator for X.500 name AttributeTypeAndValue values
bartonjs Jun 7, 2022
0c0123e
Start moving MatchesTlsHostname to X509Certificate2
bartonjs Jun 8, 2022
8d686cd
Rename to MatchesHostname, add first wave of tests
bartonjs Jun 8, 2022
e9eba9b
Use list pattern in GetSharedOrNullOid
bartonjs Jun 8, 2022
778ddfd
Be more stringent with acceptable tag values
bartonjs Jun 8, 2022
4c9c049
Push MatchesHostname coverage to 100%
bartonjs Jun 8, 2022
2046ebf
Add CreateSigningRequestPem, some code cleanup
bartonjs Jun 9, 2022
f38d49c
Add unsafeLoadCertificateExtensions parameter to LoadCertificateRequest
bartonjs Jun 9, 2022
4386438
Share PssParamsAsn to RSASignaturePadding conversions
bartonjs Jun 9, 2022
1fe525b
Get PKCS10 signature verification happy
bartonjs Jun 9, 2022
6897174
Add a static data load test
bartonjs Jun 9, 2022
e0f8140
Add PKCS10PEM export tests
bartonjs Jun 9, 2022
5ccef31
Add PEM-based PKCS10 loading
bartonjs Jun 9, 2022
b7d9803
Make SKI.SubjectKeyIdentifierBytes nullable
bartonjs Jun 10, 2022
99c1835
SubjectKeyIdentifierBytes back to not-nullable
bartonjs Jun 13, 2022
aa1b125
LoadCertificateRequest => LoadSigningRequest
bartonjs Jun 13, 2022
97791b9
Commit missing test changes
bartonjs Jun 13, 2022
b6f2a10
Move RelativeDistinguishedName to non-nested-level type
bartonjs Jun 13, 2022
3322643
Delay the processing of RDN's Single-Value-Value
bartonjs Jun 13, 2022
34e14b3
Make HasMultipleValues computed, add MemberNotNullWhen
bartonjs Jun 14, 2022
af0b922
Add more RDN tests
bartonjs Jun 14, 2022
8003581
Move CRL HashAlgorithm and RSAPadding to parameters
bartonjs Jun 14, 2022
3c33e17
Argument validation to CRLBuilder.Build
bartonjs Jun 15, 2022
62ffa1b
Fix AKID with Issuer+Serial
bartonjs Jun 15, 2022
944ed03
Add some tests that build CRLs
bartonjs Jun 16, 2022
0283f9d
Split CRLBuilder into partial files
bartonjs Jul 1, 2022
f0f3c73
Add CrlBuilder.RemoveEntry
bartonjs Jul 1, 2022
19e35ec
Apply feedback
bartonjs Jul 1, 2022
0840313
Add X509RevocationReason support
bartonjs Jul 1, 2022
936a95a
Add an argument validation test for reason codes
bartonjs Jul 1, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// 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 Internal.Cryptography;

namespace System.Security.Cryptography.Asn1
{
internal partial struct PssParamsAsn
{
internal RSASignaturePadding GetSignaturePadding(
int? digestValueLength = null)
{
if (TrailerField != 1)
{
throw new CryptographicException(SR.Cryptography_Pkcs_InvalidSignatureParameters);
}

if (MaskGenAlgorithm.Algorithm != Oids.Mgf1)
{
throw new CryptographicException(
SR.Cryptography_Pkcs_PssParametersMgfNotSupported,
MaskGenAlgorithm.Algorithm);
}

if (MaskGenAlgorithm.Parameters == null)
{
throw new CryptographicException(SR.Cryptography_Pkcs_InvalidSignatureParameters);
}

AlgorithmIdentifierAsn mgfParams = AlgorithmIdentifierAsn.Decode(
MaskGenAlgorithm.Parameters.Value,
AsnEncodingRules.DER);

if (mgfParams.Algorithm != HashAlgorithm.Algorithm)
{
throw new CryptographicException(
SR.Format(
SR.Cryptography_Pkcs_PssParametersMgfHashMismatch,
mgfParams.Algorithm,
HashAlgorithm.Algorithm));
}

int saltSize = digestValueLength.GetValueOrDefault();

if (!digestValueLength.HasValue)
{
saltSize = Helpers.HashOidToByteLength(HashAlgorithm.Algorithm);
}

if (SaltLength != saltSize)
{
throw new CryptographicException(
SR.Format(
SR.Cryptography_Pkcs_PssParametersSaltMismatch,
SaltLength,
HashAlgorithm.Algorithm));
}

// When RSASignaturePadding supports custom salt sizes this return will look different.
return RSASignaturePadding.Pss;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,14 +173,15 @@ internal AsnValueReader ReadSequence(Asn1Tag? expectedTag = default)
return new AsnValueReader(content, _ruleSet);
}

internal AsnValueReader ReadSetOf(Asn1Tag? expectedTag = default)
internal AsnValueReader ReadSetOf(Asn1Tag? expectedTag = default, bool skipSortOrderValidation = false)
{
AsnDecoder.ReadSetOf(
_span,
_ruleSet,
out int contentOffset,
out int contentLength,
out int bytesConsumed,
skipSortOrderValidation: skipSortOrderValidation,
expectedTag: expectedTag);

ReadOnlySpan<byte> content = _span.Slice(contentOffset, contentLength);
Expand Down
14 changes: 14 additions & 0 deletions src/libraries/Common/src/System/Security/Cryptography/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,19 @@ internal static bool TryCopyToDestination(this ReadOnlySpan<byte> source, Span<b
bytesWritten = 0;
return false;
}

internal static int HashOidToByteLength(string hashOid)
{
// This file is compiled in netstandard2.0, can't use the HashSizeInBytes consts.
return hashOid switch
{
Oids.Sha256 => 256 >> 3,
Oids.Sha384 => 384 >> 3,
Oids.Sha512 => 512 >> 3,
Oids.Sha1 => 160 >> 3,
Oids.Md5 => 128 >> 3,
_ => throw new CryptographicException(SR.Format(SR.Cryptography_UnknownHashAlgorithm, hashOid)),
};
}
}
}
165 changes: 121 additions & 44 deletions src/libraries/Common/src/System/Security/Cryptography/Oids.Shared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,55 +2,58 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Security.Cryptography;
using System.Formats.Asn1;

namespace System.Security.Cryptography
{
internal static partial class Oids
{
private static volatile Oid? _rsaOid;
private static volatile Oid? _ecPublicKeyOid;
private static volatile Oid? _tripleDesCbcOid;
private static volatile Oid? _aes256CbcOid;
private static volatile Oid? _secp256r1Oid;
private static volatile Oid? _secp384r1Oid;
private static volatile Oid? _secp521r1Oid;
private static volatile Oid? _sha256Oid;
private static volatile Oid? _pkcs7DataOid;
private static volatile Oid? _contentTypeOid;
private static volatile Oid? _documentDescriptionOid;
private static volatile Oid? _documentNameOid;
private static volatile Oid? _localKeyIdOid;
private static volatile Oid? _messageDigestOid;
private static volatile Oid? _signingTimeOid;
private static volatile Oid? _pkcs9ExtensionRequestOid;
private static volatile Oid? _basicConstraints2Oid;
private static volatile Oid? _enhancedKeyUsageOid;
private static volatile Oid? _keyUsageOid;
private static volatile Oid? _subjectKeyIdentifierOid;

internal static Oid RsaOid => _rsaOid ??= InitializeOid(Rsa);
internal static Oid EcPublicKeyOid => _ecPublicKeyOid ??= InitializeOid(EcPublicKey);
internal static Oid TripleDesCbcOid => _tripleDesCbcOid ??= InitializeOid(TripleDesCbc);
internal static Oid Aes256CbcOid => _aes256CbcOid ??= InitializeOid(Aes256Cbc);
internal static Oid secp256r1Oid => _secp256r1Oid ??= new Oid(secp256r1, nameof(ECCurve.NamedCurves.nistP256));
internal static Oid secp384r1Oid => _secp384r1Oid ??= new Oid(secp384r1, nameof(ECCurve.NamedCurves.nistP384));
internal static Oid secp521r1Oid => _secp521r1Oid ??= new Oid(secp521r1, nameof(ECCurve.NamedCurves.nistP521));
internal static Oid Sha256Oid => _sha256Oid ??= InitializeOid(Sha256);

internal static Oid Pkcs7DataOid => _pkcs7DataOid ??= InitializeOid(Pkcs7Data);
internal static Oid ContentTypeOid => _contentTypeOid ??= InitializeOid(ContentType);
internal static Oid DocumentDescriptionOid => _documentDescriptionOid ??= InitializeOid(DocumentDescription);
internal static Oid DocumentNameOid => _documentNameOid ??= InitializeOid(DocumentName);
internal static Oid LocalKeyIdOid => _localKeyIdOid ??= InitializeOid(LocalKeyId);
internal static Oid MessageDigestOid => _messageDigestOid ??= InitializeOid(MessageDigest);
internal static Oid SigningTimeOid => _signingTimeOid ??= InitializeOid(SigningTime);
internal static Oid Pkcs9ExtensionRequestOid => _pkcs9ExtensionRequestOid ??= InitializeOid(Pkcs9ExtensionRequest);

internal static Oid BasicConstraints2Oid => _basicConstraints2Oid ??= InitializeOid(BasicConstraints2);
internal static Oid EnhancedKeyUsageOid => _enhancedKeyUsageOid ??= InitializeOid(EnhancedKeyUsage);
internal static Oid KeyUsageOid => _keyUsageOid ??= InitializeOid(KeyUsage);
internal static Oid SubjectKeyIdentifierOid => _subjectKeyIdentifierOid ??= InitializeOid(SubjectKeyIdentifier);
private static volatile Oid? s_rsaOid;
private static volatile Oid? s_ecPublicKeyOid;
private static volatile Oid? s_tripleDesCbcOid;
private static volatile Oid? s_aes256CbcOid;
private static volatile Oid? s_secp256r1Oid;
private static volatile Oid? s_secp384r1Oid;
private static volatile Oid? s_secp521r1Oid;
private static volatile Oid? s_sha256Oid;
private static volatile Oid? s_pkcs7DataOid;
private static volatile Oid? s_contentTypeOid;
private static volatile Oid? s_documentDescriptionOid;
private static volatile Oid? s_documentNameOid;
private static volatile Oid? s_localKeyIdOid;
private static volatile Oid? s_messageDigestOid;
private static volatile Oid? s_signingTimeOid;
private static volatile Oid? s_pkcs9ExtensionRequestOid;
private static volatile Oid? s_basicConstraints2Oid;
private static volatile Oid? s_enhancedKeyUsageOid;
private static volatile Oid? s_keyUsageOid;
private static volatile Oid? s_subjectKeyIdentifierOid;
private static volatile Oid? s_commonNameOid;

internal static Oid RsaOid => s_rsaOid ??= InitializeOid(Rsa);
internal static Oid EcPublicKeyOid => s_ecPublicKeyOid ??= InitializeOid(EcPublicKey);
internal static Oid TripleDesCbcOid => s_tripleDesCbcOid ??= InitializeOid(TripleDesCbc);
internal static Oid Aes256CbcOid => s_aes256CbcOid ??= InitializeOid(Aes256Cbc);
internal static Oid secp256r1Oid => s_secp256r1Oid ??= new Oid(secp256r1, nameof(ECCurve.NamedCurves.nistP256));
internal static Oid secp384r1Oid => s_secp384r1Oid ??= new Oid(secp384r1, nameof(ECCurve.NamedCurves.nistP384));
internal static Oid secp521r1Oid => s_secp521r1Oid ??= new Oid(secp521r1, nameof(ECCurve.NamedCurves.nistP521));
internal static Oid Sha256Oid => s_sha256Oid ??= InitializeOid(Sha256);

internal static Oid Pkcs7DataOid => s_pkcs7DataOid ??= InitializeOid(Pkcs7Data);
internal static Oid ContentTypeOid => s_contentTypeOid ??= InitializeOid(ContentType);
internal static Oid DocumentDescriptionOid => s_documentDescriptionOid ??= InitializeOid(DocumentDescription);
internal static Oid DocumentNameOid => s_documentNameOid ??= InitializeOid(DocumentName);
internal static Oid LocalKeyIdOid => s_localKeyIdOid ??= InitializeOid(LocalKeyId);
internal static Oid MessageDigestOid => s_messageDigestOid ??= InitializeOid(MessageDigest);
internal static Oid SigningTimeOid => s_signingTimeOid ??= InitializeOid(SigningTime);
internal static Oid Pkcs9ExtensionRequestOid => s_pkcs9ExtensionRequestOid ??= InitializeOid(Pkcs9ExtensionRequest);

internal static Oid BasicConstraints2Oid => s_basicConstraints2Oid ??= InitializeOid(BasicConstraints2);
internal static Oid EnhancedKeyUsageOid => s_enhancedKeyUsageOid ??= InitializeOid(EnhancedKeyUsage);
internal static Oid KeyUsageOid => s_keyUsageOid ??= InitializeOid(KeyUsage);
internal static Oid SubjectKeyIdentifierOid => s_subjectKeyIdentifierOid ??= InitializeOid(SubjectKeyIdentifier);

internal static Oid CommonNameOid => s_commonNameOid ??= InitializeOid(CommonName);

private static Oid InitializeOid(string oidValue)
{
Expand All @@ -65,5 +68,79 @@ private static Oid InitializeOid(string oidValue)
return oid;
}

internal static Oid GetSharedOrNewOid(ref AsnValueReader asnValueReader)
{
Oid? ret = GetSharedOrNullOid(ref asnValueReader);

if (ret is not null)
{
return ret;
}

string oidValue = asnValueReader.ReadObjectIdentifier();
return new Oid(oidValue, null);
}

internal static Oid? GetSharedOrNullOid(ref AsnValueReader asnValueReader, Asn1Tag? expectedTag = null)
{
#if NET
Asn1Tag tag = asnValueReader.PeekTag();

// This isn't a valid OID, so return null and let whatever's going to happen happen.
if (tag.IsConstructed)
{
return null;
}

Asn1Tag expected = expectedTag.GetValueOrDefault(Asn1Tag.ObjectIdentifier);

Debug.Assert(
expected.TagClass != TagClass.Universal ||
expected.TagValue == (int)UniversalTagNumber.ObjectIdentifier,
$"{nameof(GetSharedOrNullOid)} was called with the wrong Universal class tag: {expectedTag}");

// Not the tag we're expecting, so don't match.
if (!tag.HasSameClassAndValue(expected))
{
return null;
}

ReadOnlySpan<byte> contentBytes = asnValueReader.PeekContentBytes();

Oid? ret = contentBytes switch
{
[0x55, 0x04, 0x03] => CommonNameOid,
_ => null,
};

if (ret is not null)
{
// Move to the next item.
asnValueReader.ReadEncodedValue();
}

return ret;
#else
// Cannot use list patterns on older TFMs.
return null;
#endif
}

internal static bool ValueEquals(this Oid oid, Oid? other)
{
Debug.Assert(oid is not null);

if (ReferenceEquals(oid, other))
{
return true;
}

if (other is null)
{
return false;
}

return oid.Value is not null && oid.Value.Equals(other.Value);
}
}
}
2 changes: 2 additions & 0 deletions src/libraries/Common/src/System/Security/Cryptography/Oids.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,12 @@ internal static partial class Oids
internal const string SubjectAltName = "2.5.29.17";
internal const string IssuerAltName = "2.5.29.18";
internal const string BasicConstraints2 = "2.5.29.19";
internal const string CrlNumber = "2.5.29.20";
internal const string CrlDistributionPoints = "2.5.29.31";
internal const string CertPolicies = "2.5.29.32";
internal const string AnyCertPolicy = "2.5.29.32.0";
internal const string CertPolicyMappings = "2.5.29.33";
internal const string AuthorityKeyIdentifier = "2.5.29.35";
internal const string CertPolicyConstraints = "2.5.29.36";
internal const string EnhancedKeyUsage = "2.5.29.37";
internal const string InhibitAnyPolicyExtension = "2.5.29.54";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,7 @@ internal static class PemLabels
internal const string EcPrivateKey = "EC PRIVATE KEY";
internal const string X509Certificate = "CERTIFICATE";
internal const string Pkcs7Certificate = "PKCS7";
internal const string Pkcs10CertificateRequest = "CERTIFICATE REQUEST";
internal const string X509CertificateRevocationList = "X509 CRL";
}
}
Loading