Skip to content

Commit

Permalink
Use the managed implementation of extendedKeyUsage codec everywhere
Browse files Browse the repository at this point in the history
  • Loading branch information
vcsjones authored Oct 5, 2024
1 parent ed05fa9 commit 6160518
Show file tree
Hide file tree
Showing 15 changed files with 49 additions and 248 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,6 @@ internal static int BioTell(SafeBioHandle bio)
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetX509PublicKeyParameterBytes")]
private static partial int GetX509PublicKeyParameterBytes(SafeX509Handle x509, byte[]? buf, int cBuf);

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetX509EkuFieldCount")]
internal static partial int GetX509EkuFieldCount(SafeEkuExtensionHandle eku);

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetX509EkuField")]
internal static partial IntPtr GetX509EkuField(SafeEkuExtensionHandle eku, int loc);

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetX509NameInfo")]
internal static partial SafeBioHandle GetX509NameInfo(SafeX509Handle x509, int nameType, [MarshalAs(UnmanagedType.Bool)] bool forIssuer);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,5 @@ internal static partial bool DecodeX509BasicConstraints2Extension(
[MarshalAs(UnmanagedType.Bool)] out bool certificateAuthority,
[MarshalAs(UnmanagedType.Bool)] out bool hasPathLengthConstraint,
out int pathLengthConstraint);

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_DecodeExtendedKeyUsage")]
internal static partial SafeEkuExtensionHandle DecodeExtendedKeyUsage(byte[] buf, int len);

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_ExtendedKeyUsageDestroy")]
internal static partial void ExtendedKeyUsageDestroy(IntPtr a);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,4 @@ public override bool IsInvalid
get { return handle == IntPtr.Zero; }
}
}

internal sealed class SafeEkuExtensionHandle : SafeHandle
{
public SafeEkuExtensionHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}

protected override bool ReleaseHandle()
{
Interop.Crypto.ExtendedKeyUsageDestroy(handle);
SetHandle(IntPtr.Zero);
return true;
}

public override bool IsInvalid
{
get { return handle == IntPtr.Zero; }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,5 @@ internal interface IX509Pal
byte[] EncodeX509BasicConstraints2Extension(bool certificateAuthority, bool hasPathLengthConstraint, int pathLengthConstraint);
void DecodeX509BasicConstraintsExtension(byte[] encoded, out bool certificateAuthority, out bool hasPathLengthConstraint, out int pathLengthConstraint);
void DecodeX509BasicConstraints2Extension(byte[] encoded, out bool certificateAuthority, out bool hasPathLengthConstraint, out int pathLengthConstraint);
byte[] EncodeX509EnhancedKeyUsageExtension(OidCollection usages);
void DecodeX509EnhancedKeyUsageExtension(byte[] encoded, out OidCollection usages);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,55 +53,5 @@ public virtual void DecodeX509BasicConstraints2Extension(
hasPathLengthConstraint = constraints.PathLengthConstraint.HasValue;
pathLengthConstraint = constraints.PathLengthConstraint.GetValueOrDefault();
}

public virtual byte[] EncodeX509EnhancedKeyUsageExtension(OidCollection usages)
{
// https://tools.ietf.org/html/rfc5280#section-4.2.1.12
//
// extKeyUsage EXTENSION ::= {
// SYNTAX SEQUENCE SIZE(1..MAX) OF KeyPurposeId
// IDENTIFIED BY id-ce-extKeyUsage
// }
//
// KeyPurposeId ::= OBJECT IDENTIFIER

AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);

using (writer.PushSequence())
{
foreach (Oid usage in usages)
{
writer.WriteObjectIdentifierForCrypto(usage.Value!);
}
}

return writer.Encode();
}

public virtual void DecodeX509EnhancedKeyUsageExtension(byte[] encoded, out OidCollection usages)
{
// https://tools.ietf.org/html/rfc5924#section-4.1
//
// ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
//
// KeyPurposeId ::= OBJECT IDENTIFIER

try
{
AsnReader reader = new AsnReader(encoded, AsnEncodingRules.BER);
AsnReader sequenceReader = reader.ReadSequence();
reader.ThrowIfNotEmpty();
usages = new OidCollection();

while (sequenceReader.HasData)
{
usages.Add(new Oid(sequenceReader.ReadObjectIdentifier(), null));
}
}
catch (AsnContentException e)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -169,35 +169,6 @@ public override void DecodeX509BasicConstraints2Extension(
}
}

public override void DecodeX509EnhancedKeyUsageExtension(byte[] encoded, out OidCollection usages)
{
OidCollection oids;

using (SafeEkuExtensionHandle eku = Interop.Crypto.DecodeExtendedKeyUsage(encoded, encoded.Length))
{
Interop.Crypto.CheckValidOpenSslHandle(eku);

int count = Interop.Crypto.GetX509EkuFieldCount(eku);
oids = new OidCollection(count);

for (int i = 0; i < count; i++)
{
IntPtr oidPtr = Interop.Crypto.GetX509EkuField(eku, i);

if (oidPtr == IntPtr.Zero)
{
throw Interop.Crypto.CreateOpenSslCryptographicException();
}

string oidValue = Interop.Crypto.GetOidValue(oidPtr);

oids.Add(new Oid(oidValue));
}
}

usages = oids;
}

private static RSAOpenSsl BuildRsaPublicKey(byte[] encodedData)
{
var rsa = new RSAOpenSsl();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,6 @@ internal struct CERT_BASIC_CONSTRAINTS2_INFO
public int dwPathLenConstraint;
};

[StructLayout(LayoutKind.Sequential)]
internal unsafe struct CERT_ENHKEY_USAGE
{
public int cUsageIdentifier;
public IntPtr* rgpszUsageIdentifier; // LPSTR*
}

[StructLayout(LayoutKind.Sequential)]
internal struct CERT_POLICY_INFO
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// 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;

namespace System.Security.Cryptography.X509Certificates
{
public sealed class X509EnhancedKeyUsageExtension : X509Extension
Expand Down Expand Up @@ -28,7 +30,7 @@ public OidCollection EnhancedKeyUsages
{
if (!_decoded)
{
X509Pal.Instance.DecodeX509EnhancedKeyUsageExtension(RawData, out _enhancedKeyUsages);
DecodeX509EnhancedKeyUsageExtension(RawData, out _enhancedKeyUsages);
_decoded = true;
}

Expand All @@ -53,7 +55,52 @@ private static byte[] EncodeExtension(OidCollection enhancedKeyUsages)
{
ArgumentNullException.ThrowIfNull(enhancedKeyUsages);

return X509Pal.Instance.EncodeX509EnhancedKeyUsageExtension(enhancedKeyUsages);
// https://tools.ietf.org/html/rfc5280#section-4.2.1.12
//
// extKeyUsage EXTENSION ::= {
// SYNTAX SEQUENCE SIZE(1..MAX) OF KeyPurposeId
// IDENTIFIED BY id-ce-extKeyUsage
// }
//
// KeyPurposeId ::= OBJECT IDENTIFIER

AsnWriter writer = new AsnWriter(AsnEncodingRules.DER);

using (writer.PushSequence())
{
foreach (Oid usage in enhancedKeyUsages)
{
writer.WriteObjectIdentifierForCrypto(usage.Value!);
}
}

return writer.Encode();
}

private static void DecodeX509EnhancedKeyUsageExtension(byte[] encoded, out OidCollection usages)
{
// https://tools.ietf.org/html/rfc5924#section-4.1
//
// ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
//
// KeyPurposeId ::= OBJECT IDENTIFIER

try
{
AsnReader reader = new AsnReader(encoded, AsnEncodingRules.BER);
AsnReader sequenceReader = reader.ReadSequence();
reader.ThrowIfNotEmpty();
usages = new OidCollection();

while (sequenceReader.HasData)
{
usages.Add(new Oid(sequenceReader.ReadObjectIdentifier(), null));
}
}
catch (AsnContentException e)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
}
}

private OidCollection? _enhancedKeyUsages;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,49 +66,5 @@ static delegate (void* pvDecoded, int cbDecoded)
});
}
}

public byte[] EncodeX509EnhancedKeyUsageExtension(OidCollection usages)
{
int numUsages;
using (SafeHandle usagesSafeHandle = usages.ToLpstrArray(out numUsages))
{
unsafe
{
CERT_ENHKEY_USAGE enhKeyUsage = new CERT_ENHKEY_USAGE()
{
cUsageIdentifier = numUsages,
rgpszUsageIdentifier = (IntPtr*)(usagesSafeHandle.DangerousGetHandle()),
};

return Interop.crypt32.EncodeObject(Oids.EnhancedKeyUsage, &enhKeyUsage);
}
}
}

public void DecodeX509EnhancedKeyUsageExtension(byte[] encoded, out OidCollection usages)
{
unsafe
{
usages = encoded.DecodeObject(
CryptDecodeObjectStructType.X509_ENHANCED_KEY_USAGE,
static delegate (void* pvDecoded, int cbDecoded)
{

Debug.Assert(cbDecoded >= sizeof(CERT_ENHKEY_USAGE));
CERT_ENHKEY_USAGE* pEnhKeyUsage = (CERT_ENHKEY_USAGE*)pvDecoded;
int count = pEnhKeyUsage->cUsageIdentifier;
var localUsages = new OidCollection(count);
for (int i = 0; i < count; i++)
{
IntPtr oidValuePointer = pEnhKeyUsage->rgpszUsageIdentifier[i];
string oidValue = Marshal.PtrToStringAnsi(oidValuePointer)!;
Oid oid = new Oid(oidValue);
localUsages.Add(oid);
}

return localUsages;
});
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ static const Entry s_cryptoNative[] =
DllImportEntry(CryptoNative_CheckX509IpAddress)
DllImportEntry(CryptoNative_CreateMemoryBio)
DllImportEntry(CryptoNative_D2IPkcs7Bio)
DllImportEntry(CryptoNative_DecodeExtendedKeyUsage)
DllImportEntry(CryptoNative_DecodeOcspResponse)
DllImportEntry(CryptoNative_DecodePkcs7)
DllImportEntry(CryptoNative_DecodePkcs8PrivateKey)
Expand Down Expand Up @@ -182,7 +181,6 @@ static const Entry s_cryptoNative[] =
DllImportEntry(CryptoNative_EvpSha3_512)
DllImportEntry(CryptoNative_EvpShake128)
DllImportEntry(CryptoNative_EvpShake256)
DllImportEntry(CryptoNative_ExtendedKeyUsageDestroy)
DllImportEntry(CryptoNative_GetAsn1IntegerDerSize)
DllImportEntry(CryptoNative_GetAsn1StringBytes)
DllImportEntry(CryptoNative_GetBigNumBytes)
Expand All @@ -200,8 +198,6 @@ static const Entry s_cryptoNative[] =
DllImportEntry(CryptoNative_GetSubjectPublicKeyInfoSize)
DllImportEntry(CryptoNative_GetX509CrlNextUpdate)
DllImportEntry(CryptoNative_GetX509DerSize)
DllImportEntry(CryptoNative_GetX509EkuField)
DllImportEntry(CryptoNative_GetX509EkuFieldCount)
DllImportEntry(CryptoNative_GetX509EvpPublicKey)
DllImportEntry(CryptoNative_GetX509NameInfo)
DllImportEntry(CryptoNative_GetX509NameRawBytes)
Expand Down
34 changes: 0 additions & 34 deletions src/native/libs/System.Security.Cryptography.Native/openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -451,40 +451,6 @@ int32_t CryptoNative_GetX509NameRawBytes(X509_NAME* x509Name, uint8_t* pBuf, int
return 1;
}

/*
Function:
GetX509EkuFieldCount
Used by System.Security.Cryptography.X509Certificates' OpenSslX509Encoder to identify the
number of Extended Key Usage OIDs present in the EXTENDED_KEY_USAGE structure.
Return values:
0 if the field count cannot be determined, or the count of OIDs present in the EKU.
Note that 0 does not always indicate an error, merely that GetX509EkuField should not be called.
*/
int32_t CryptoNative_GetX509EkuFieldCount(EXTENDED_KEY_USAGE* eku)
{
// No error queue impact.
return sk_ASN1_OBJECT_num(eku);
}

/*
Function:
GetX509EkuField
Used by System.Security.Cryptography.X509Certificates' OpenSslX509Encoder to get a pointer to the
ASN1_OBJECT structure which represents the OID in a particular spot in the EKU.
Return values:
NULL if eku is NULL or loc is out of bounds, otherwise a pointer to the ASN1_OBJECT structure encoding
that particular OID.
*/
ASN1_OBJECT* CryptoNative_GetX509EkuField(EXTENDED_KEY_USAGE* eku, int32_t loc)
{
// No error queue impact.
return sk_ASN1_OBJECT_value(eku, loc);
}

/*
Function:
GetX509NameInfo
Expand Down
4 changes: 0 additions & 4 deletions src/native/libs/System.Security.Cryptography.Native/openssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,6 @@ PALEXPORT int32_t CryptoNative_GetAsn1StringBytes(ASN1_STRING* asn1, uint8_t* pB

PALEXPORT int32_t CryptoNative_GetX509NameRawBytes(X509_NAME* x509Name, uint8_t* pBuf, int32_t cBuf);

PALEXPORT int32_t CryptoNative_GetX509EkuFieldCount(EXTENDED_KEY_USAGE* eku);

PALEXPORT ASN1_OBJECT* CryptoNative_GetX509EkuField(EXTENDED_KEY_USAGE* eku, int32_t loc);

PALEXPORT BIO* CryptoNative_GetX509NameInfo(X509* x509, int32_t nameType, int32_t forIssuer);

PALEXPORT int32_t CryptoNative_CheckX509Hostname(X509* x509, const char* hostname, int32_t cchHostname);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,6 @@ extern bool g_libSslUses32BitTime;
LEGACY_FUNCTION(CRYPTO_num_locks) \
LEGACY_FUNCTION(CRYPTO_set_locking_callback) \
REQUIRED_FUNCTION(d2i_BASIC_CONSTRAINTS) \
REQUIRED_FUNCTION(d2i_EXTENDED_KEY_USAGE) \
REQUIRED_FUNCTION(d2i_OCSP_RESPONSE) \
REQUIRED_FUNCTION(d2i_PKCS12_fp) \
REQUIRED_FUNCTION(d2i_PKCS7) \
Expand Down Expand Up @@ -501,7 +500,6 @@ extern bool g_libSslUses32BitTime;
LIGHTUP_FUNCTION(EVP_sha3_512) \
LIGHTUP_FUNCTION(EVP_shake128) \
LIGHTUP_FUNCTION(EVP_shake256) \
REQUIRED_FUNCTION(EXTENDED_KEY_USAGE_free) \
REQUIRED_FUNCTION(GENERAL_NAMES_free) \
REQUIRED_FUNCTION(HMAC) \
LEGACY_FUNCTION(HMAC_CTX_cleanup) \
Expand Down Expand Up @@ -849,7 +847,6 @@ extern TYPEOF(OPENSSL_gmtime)* OPENSSL_gmtime_ptr;
#define CRYPTO_num_locks CRYPTO_num_locks_ptr
#define CRYPTO_set_locking_callback CRYPTO_set_locking_callback_ptr
#define d2i_BASIC_CONSTRAINTS d2i_BASIC_CONSTRAINTS_ptr
#define d2i_EXTENDED_KEY_USAGE d2i_EXTENDED_KEY_USAGE_ptr
#define d2i_OCSP_RESPONSE d2i_OCSP_RESPONSE_ptr
#define d2i_PKCS12_fp d2i_PKCS12_fp_ptr
#define d2i_PKCS7 d2i_PKCS7_ptr
Expand Down Expand Up @@ -1051,7 +1048,6 @@ extern TYPEOF(OPENSSL_gmtime)* OPENSSL_gmtime_ptr;
#define EVP_sha3_512 EVP_sha3_512_ptr
#define EVP_shake128 EVP_shake128_ptr
#define EVP_shake256 EVP_shake256_ptr
#define EXTENDED_KEY_USAGE_free EXTENDED_KEY_USAGE_free_ptr
#define GENERAL_NAMES_free GENERAL_NAMES_free_ptr
#define HMAC HMAC_ptr
#define HMAC_CTX_cleanup HMAC_CTX_cleanup_ptr
Expand Down
Loading

0 comments on commit 6160518

Please sign in to comment.