// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Security.Cryptography; using Microsoft.Win32.SafeHandles; internal static partial class Interop { internal static partial class Crypto { [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_ObjTxt2Obj", StringMarshalling = StringMarshalling.Utf8)] internal static partial SafeAsn1ObjectHandle ObjTxt2Obj(string s); [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_ObjObj2Txt")] private static unsafe partial int ObjObj2Txt(byte* buf, int buf_len, IntPtr a); [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_GetObjectDefinitionByName", StringMarshalling = StringMarshalling.Utf8)] private static partial IntPtr CryptoNative_GetObjectDefinitionByName(string friendlyName); internal static IntPtr GetObjectDefinitionByName(string friendlyName) { IntPtr ret = CryptoNative_GetObjectDefinitionByName(friendlyName); if (ret == IntPtr.Zero) { ErrClearError(); } return ret; } // Returns shared pointers, should not be tracked as a SafeHandle. [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_ObjNid2Obj")] internal static partial IntPtr ObjNid2Obj(int nid); [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_Asn1ObjectFree")] internal static partial void Asn1ObjectFree(IntPtr o); [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_Asn1OctetStringNew")] internal static partial SafeAsn1OctetStringHandle Asn1OctetStringNew(); [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_Asn1OctetStringSet")] [return: MarshalAs(UnmanagedType.Bool)] internal static partial bool Asn1OctetStringSet(SafeAsn1OctetStringHandle o, byte[] d, int len); [LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_Asn1OctetStringFree")] internal static partial void Asn1OctetStringFree(IntPtr o); internal static unsafe string GetOidValue(IntPtr asn1ObjectPtr) { // OBJ_obj2txt returns the number of bytes that should have been in the answer, but it does not accept // a NULL buffer. The documentation says "A buffer length of 80 should be more than enough to handle // any OID encountered in practice", so start with a buffer of size 80, and try again if required. const int StackCapacity = 80; byte* bufStack = stackalloc byte[StackCapacity]; int bytesNeeded = ObjObj2Txt(bufStack, StackCapacity, asn1ObjectPtr); if (bytesNeeded < 0) { throw CreateOpenSslCryptographicException(); } Debug.Assert(bytesNeeded != 0, "OBJ_obj2txt reported a zero-length response"); if (bytesNeeded < StackCapacity) { return Marshal.PtrToStringUTF8((IntPtr)bufStack, bytesNeeded); } // bytesNeeded does not count the \0 which will be written on the end (based on OpenSSL 1.0.1f), // so make sure to leave room for it. int initialBytesNeeded = bytesNeeded; byte[] bufHeap = new byte[bytesNeeded + 1]; fixed (byte* buf = &bufHeap[0]) { bytesNeeded = ObjObj2Txt(buf, bufHeap.Length, asn1ObjectPtr); if (bytesNeeded < 0) { throw CreateOpenSslCryptographicException(); } Debug.Assert( bytesNeeded == initialBytesNeeded, "OBJ_obj2txt changed the required number of bytes for the realloc call"); if (bytesNeeded > initialBytesNeeded) { // OBJ_obj2txt is demanding yet more memory throw new CryptographicException(); } return Marshal.PtrToStringUTF8((IntPtr)buf, bytesNeeded); } } } } |