
Introduction
Installing SSL Certificates in IIS 5.0 seems to be an easy task. One would
think to use ADSI to set the SSLCertHash property using Adsutil.vbs
or System.DirectoryServices in C#. Although that approach seems
logical, one quickly remembers they are using a Microsoft product and discovers
that the schema incorrectly specifies the SSLCertHash property as
an expanded null terminated string, instead of as binary data. A quick search of
the MS KB will pull up HOW TO:
Programmatically Install SSL Certificates for Internet Information Server
(IIS) confirming this little idiosyncrasy with ADSI. Great, a COM only
interface (IMSAdminBase) that is accessible through C/C++ is what
Microsoft leaves us to solve this little task. Sounds nasty.
Using the Microsoft .NET Framework it's possible to create a COM callable
wrapper/runtime callable wrapper (RCW) to allow VBScript and C# to use the
IMSAdminBase interface. My COM knowledge is very limited and
messing with C was the last thing I wanted to do, so I decided see what COM
Interop in the .NET Framework was all about.
Installing SSL Certificates in IIS 5.0 Programmatically involves the
following tasks:
- Generate/Load Certificate into Local Computer Certificate Store
- Get the Certificate Thumbprint
- Set the SSLCertHash and SSLStore Name Metabase Properties
The attached solution contains a C# sample tool and a VBScript sample for
installing SSL Certificates using the custom COM callable wrapper/runtime
callable wrapper (RCW).
Generating SSL Certificates and the Certificate Store
There are numerous ways to get a SSL Certificate for IIS. This article only
covers generating a self-signed certificate. Included in the .NET Framework SDK
and the Platform SDK is a tool called makecert.exe that works great for
generating fake (self-signed) certificates.
IIS SSL Certificates need the following parameters:
makecert.exe -a SHA1 -ss my -sr LocalMachine -n "CN="%ComputerName%
-b 01/01/2000 -e 01/01/2050 -eku 1.3.6.1.5.5.7.3.1 -sky exchange -sp "Microsoft
RSA SChannel Cryptographic Provider" -sy 12
The certificate's subject name and expiration date are configurable. The full
subject name can include
"CN=Name,OU=Container,O=Company,L=City,S=State,C=Country". The -ss my
-sr LocalMachine switches save the generated certificate to the Personal
Certificate Store (MY) for the Local Computer. If you import your own
certificate, make sure its stored there.
Platform SDK Redistributable: CAPICOM
It's possible to access the Local Machine Certificate Store using the
CryptoAPI but I found using the CAPICOM COM client to be much easier. You can download
the CAPICOM library from the Microsoft download site.
To install CAPICOM extract "CAPICOM.DLL" from CAPICOM.CAB to your system32
directory, then execute "regsvr32.exe CAPICOM.DLL". The debug symbols should
also be copied to the system32 directory for running C# projects in debug
mode.
Background
Runtime callable wrappers are used by .NET to access COM components. MSDN has
a great deal of documentation on the subject. I would suggest reading some
articles over there if you are interested. You may have of used RCWs without
noticing, Visual Studio .NET generates RCWs for you when add a COM Reference to
a project. Alternatively, you could use the Type Library Importer (Tlbimp.exe)
tool to generate a wrapper from a type library file (TLB). So where is the IIS
Admin Base Object in the COM Reference list? Luckily, our friends at Microsoft
don't seem to ship a TLB for the IMSAdminBase Interface. The next
step involved searching the Platform SDK for any trace of Interface Definition
Language (IDL) source. IDL source can be compiled by the MIDL compiler
command-line tool to generate the type library file (TLB). Compiling the IDL
quickly becomes difficult when the Platform SDK only provides C header files for
the IMSAdminBase Interface.
Custom Runtime Callable Wrapper
Armed with the Iadmw.h header file I started to create a custom RCW. The
MSAdminBase project contains the COM Interop wrappers. All Interop projects
begin with...
using System.Runtime.InteropServices;
Importing COM Interfaces are actually pretty easy.
Interface header file
DEFINE_GUID(CLSID_MSAdminBase_W, 0xa9e69610, 0xb80d, 0x11d0,
0xb9, 0xb9, 0x0, 0xa0, 0xc9, 0x22, 0xe7, 0x50);
#if defined(__cplusplus) && !defined(CINTERFACE)
MIDL_INTERFACE("70B51430-B6CA-11d0-B9B9-00A0C922E750")
IMSAdminBaseW : public IUnknown
{
...Interface Methods...
END_INTERFACE
}
.NET Wrapper
[ComImport, Guid("a9e69610-b80d-11d0-b9b9-00a0c922e750")]
public class MSAdminBase
{}
[ComImport, Guid("70B51430-B6CA-11d0-B9B9-00A0C922E750"),
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IMSAdminBase
{
...Interface Methods
}
The CLSID requires a public class with no constructor. The interface requires
implementing IUnknown.
The more time consuming aspect of this process is wrapping the Interface
methods. I did find out that you don't have to fully wrap the entire method
signature, but all the methods need to be declared sequentially in the C#
interface wrapper.
Interface Methods
virtual HRESULT STDMETHODCALLTYPE SetData(
METADATA_HANDLE hMDHandle,
LPCWSTR pszMDPath,
PMETADATA_RECORD pmdrMDData) = 0;
virtual HRESULT STDMETHODCALLTYPE GetData(
METADATA_HANDLE hMDHandle,
LPCWSTR pszMDPath,
PMETADATA_RECORD pmdrMDData,
DWORD *pdwMDRequiredDataLen) = 0
virtual HRESULT STDMETHODCALLTYPE AddKey(
METADATA_HANDLE hMDHandle,
LPCWSTR pszMDPath
.NET Methods
void SetData(IntPtr hMDHandle,
[MarshalAs(UnmanagedType.LPWStr)] String pszMDPath,
ref METADATA_RECORD pmdrMDData);
void GetData(IntPtr hMDHandle,
[MarshalAs(UnmanagedType.LPWStr)] String pszMDPath,
[MarshalAs(UnmanagedType.Struct)] ref METADATA_RECORD pmdrMDData,
out UInt32 pdwMDRequiredDataLen);
void AddKey();
The MarshalAs attribute can be used to tell the CLR how to Marshal objects
between .NET and COM. It is not always required but does help when looking at
the hungarian notation variable names. All structs used by the interface methods
also need a wrapper.
All Constants, Enums, and Structs are defined in IIScnfg.h. The
METADATA_RECORD structure contains information about a metabase
entry. It is used as an input parameter by the SetData method and
as an input/output parameter by methods that retrieve data from the metabase in
GetData.
typedef struct _METADATA_RECORD {
DWORD dwMDIdentifier;
DWORD dwMDAttributes;
DWORD dwMDUserType;
DWORD dwMDDataType;
DWORD dwMDDataLen;
unsigned char *pbMDData;
DWORD dwMDDataTag; }
I highly recommend looking at the NET Framework Developer's Guide
(VS.NET Help): COM Data Types. DWORDs are
a UInt32 and unsigned char * is a IntPtr.
MetaData Marshaling
COM Interop works with unmanaged memory. Effective use of
try..finally blocks can help with resource cleanup. All memory
allocated with the Marshal class and open handles must be manually freed, the
CLR garbage collector will not do it for you. Since the
METADATA_RECORD structure contains a pointer to MetaData, all
metabase entry data types will need to be marshaled to unmanaged memory before
calling the Interface method.
From Managed Code to Unmanaged Code
String MetaData
Windows 2000 uses Unicode strings (2 bytes per character) and the
METADATA_RECORD structure requires the MetaData length field to
include the null-terminated character.
stringData += '\0';
metaDataRecord.dwMDDataLen =
(UInt32)Encoding.Unicode.GetByteCount(stringData);
metaDataRecord.pbMDData = Marshal.StringToCoTaskMemUni(stringData);
Binary MetaData
Marshalling binary MetaData is simple. Use the Marshal.Copy
method.
metaDataRecord.dwMDDataLen = (UInt32)binaryData.Length;
metaDataRecord.pbMDData = Marshal.AllocCoTaskMem(binaryData.Length);
Marshal.Copy(binaryData, 0, metaDataRecord.pbMDData,
(int)metaDataRecord.dwMDDataLen);
MultiSz MetaData
MultiSz MetaData is marshaled as a string array of null-terminated strings
that has final null-terminated character after the last element. I had trouble
with the null-terminated characters so I marshalled this data type as binary
MetaData
ArrayList multiSzData = new ArrayList();
foreach(string stringData in stringArrayData)
{
Encoding.Unicode.GetBytes(stringData + '\0'));
}
binaryData = (byte[])multiSzData.ToArray(Type.GetType("System.Byte"));
metaDataRecord.dwMDDataLen = (UInt32)binaryData.Length;
metaDataRecord.pbMDData = Marshal.AllocCoTaskMem(binaryData.Length);
Marshal.Copy(binaryData, 0, metaDataRecord.pbMDData,
(int)metaDataRecord.dwMDDataLen);
DWORD MetaData
DWORD MetaData can be marshaled by allocating 4 bytes of unmanaged memory and
calling the Marshal.WriteInt32 method.
metaDataRecord.dwMDDataLen = (uint)Marshal.SizeOf(typeof(UInt32));
metaDataRecord.pbMDData = Marshal.AllocCoTaskMem(
(int)metaDataRecord.dwMDDataType);
Marshal.WriteInt32(metaDataRecord.pbMDData, uintData);;
Freeing Unmanged Memory
Always use finally blocks to free unmanaged memory.
finally
{
if(metaDataRecord.pbMDData != IntPtr.Zero)
{
Marshal.FreeCoTaskMem(metaDataRecord.pbMDData);
}
}
Using the code
The COM Interop project MSAdminBase can be used as runtime callable wrapper
for .NET projects or a COM callable wrapper for VB/VBScript projects.
C# - Using the Runtime Callable Wrapper
Using the MSAdminBaseClass (MSAdminBase.dll) to programatically
install SSL certificates is simple. Note: The CAPICOM dll must be registered for
this sample to work.
- Declare the namespace and Add a reference to either the project or the
compiled dll interop.MSAdminBase.dll.
using
Windows.Services.Iis.Metabase;
- Instantiate a new MSAdminBaseClass
- Call the
MSAdminBaseClass.SetMetabaseData method for the
SSLCertHash (5506) metabase entry and the SSLStoreName (5511)
metabase entry.
MSAdminBaseClass adminBaseClass = new MSAdminBaseClass();
adminBaseClass.SetMetabaseData(SslCertHashId,
metaDataPath, thumbprintByteArray);
adminBaseClass.SetMetabaseData(SslStoreNameId, metaDataPath, "MY");
The method signature for SetMetabaseData is
public void SetMetabaseData(uint metabaseDataId, string
metabaseDataPath, object data)
The SSLCertHash entry is a binary MetaData type and requires a
certificate thumbprint as a byte[]. The CAPICOM COM library
includes a few useful classes to convert from a thumbprint for hex string to a
byte[]ode>.
string hexThumbprint = certificate.Thumbprint;
Console.WriteLine("SSL Certificate Thumbprint: " + hexThumbprint);
string binaryThumbprint = certUtilities.HexToBinary(hexThumbprint);
thumbprintByteArray = (byte[])certUtilities.BinaryStringToByteArray(
binaryThumbprint);
The SSLStoreName entry in a string MetaData type and should always be
"MY" for IIS SSL Certificates.
VBScript - Using the COM Callable Wrapper
- Copy interop.MSAdminBase.dll to the system32 directory and run
RegAsm.exe interop.MSAdminBase.dll /tlb:interop.MSAdminBase.tlb
CreateObject("IIS.MSAdminBase")
- Call the
MSAdminBaseClass.SetMetabaseData method for the
SSLCertHash (5506) metabase entry and the SSLStoreName (5511)
metabase entry.
Dim metaBase
Set metaBase = CreateObject("IIS.MSAdminBase")
metaBase.SetMetabaseData SSLCertHashId, "/W3SVC/1", thumbprintByteArray
metaBase.SetMetabaseData SSLStoreNameId, "/W3SVC/1", SSLStoreName
Points of Interest
The COM Interop wrapper can be customized to support any IMSAdminBase
method. I only implemented the methods required to install SSL
Certificates. ADSI should normally be used to configure the IIS Metabase but
this wrapper comes in handy for the few times it's not possible.
History
- 2/8/2004 - Initial Release
| You must Sign In to use this message board. |
|
|
 |
|
 |
See http://msdn2.microsoft.com/en-us/library/ms525845.aspx
Suppose the thumbprint is "55 33 fb a1 e8 5f 60 99 4b e7 98 1b ab fd 10 56" i.e. a series of bytes in hexadecimal representation.
Do something like this: DirectoryEntry webSite = new DirectoryEntry(string.Format(@"IIS://{0}/W3SVC/{1}", serverName, siteId)); string[] hex = thumbPrint.Split(new char[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); object[] values = new object[hex.Length]; for (int i = 0; i < hex.Length; i++) { values[i] = hex[i]; }
webSite.Properties["SSLStoreName"].Add("MY"); webSite.Properties["SSLCertHash"].Add(values);
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I m getting following error 'System.Runtime.InteropServices.COMException' occurred in mscorlib.dll at the line webSite.Properties["SSLCertHash"].Add(values);
How to fix it ?
Any suggestion.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I am trying to use this from an asp page and getting the following error:
Error Code: 80070002 - Error Creating IIS.MSAdminBase. Error: -2147024894 MSG: File or assembly name interop.MSAdminBase, or one of its dependencies, was not found.
I have been researching and I can't figure out why I am receiving this error. Can you please help?
Thanks in advance
B. Adams
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I hope I'm not updating too old of an issue by posting here...
First of all, thanks for going the extra mile on this issue. I've had one heck of a time working through the programmatic administration of Certificates (thanks to MS Docs.), and your solution for setting Binary Data Types outside of ADSI (without Switching to C) has been a true gift.
I have one question, however:
Do you know why your Wrapper would not work when instantiating the "IIS.MSAdminBase" Object in Perl? After I run the RegAsm on your interop.MSAdminBase.dll, the .vbs sample works perfectly, but somehow I would have thought enough class definition existed to use these objects across any COM interface, or in my case, Perl's OLE Module. The object's class name is recognized, but I receive an error when it is attempted to be constructed:
error 0x80070002: "The system cannot find the file specified"
I'm afraid my limitted knowledge of how wrappers works for .NET is my roadblock. Will this wrapper only work for .NET? If so, is this because of it being an RCW? Any clarification on that would be appreciated.
I've looked into the possibility of writing my own wrapper for Perl, but I'd much rather use yours if at all possible.
Thanks!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Karl, What you've written here is absolutely fab'. i can't believe i found a top technical-level article about this technical point. and it's marvelously done. thank you; i'm a 4 year professional at MS techs and web techs and i must recognize you're, or that is, pure genius !!  
benfr1
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Currently I am trying to run VB.net Component from COM client. .NET Component has one method, which returns structure.Also .NET component has been provided with interface. .NET Component works fine from COM client, if the structure has integer type data field. But if the structure has string type data type, then it doesn't work. It displays the error message 'Compile Error: Variable uses an automation type not supported in Visual Basic' The code is as follows: Imports System Imports System.Runtime.InteropServices Public Interface iInterOp Function delrec() As strcPQR Structure strcPQR Public strQ As String End Structure End Interface Public Class InterOp Implements iInterOp Public Sub New() End Sub Public Function Delrec() As iInterOp.strcPQR Implements iInterOp.delrec Dim objPQR As iInterOp.strcPQR objPQR.strQ = "Tesing COM Interop Marshalling structure of having string" Return objPQR End Function End Class The code written in COM Client is as follows: Private Sub Form_Load() Dim infInterop As InterOp.iInterOp Dim objPQR As strcPQR Dim x As InterOp.InterOp Set x = New InterOp.InterOp Set infInterop = x objPQR = infInterop.delrec() MsgBox objPQR.strQ end sub I have tried using type created in Visual Basic COM client. Dim objPQR As strcP 'strcP is the type declared in module. It displays the ' error message 'Compile Error: Variable uses an automation type not ' supported in Visual basic' Please write me at nitinresume1@hotmail.com or nitinnarkar@hotmail.com
Thanks in advance, Nitin C. Narkar
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I'm working with a server client Visual Basic .NET program. My server has to save user's certificates in the right store sertificate, that I think it's the "CAPICOM.Constants.CAPICOM_OTHER_STORE" also named "AddressBook", of the CAPICOM_STORE_LOCATION.CAPICOM_LOCAL_MACHINE_STORE. I write these instructions:
Dim objCert As Certificate Dim objStore As Store ... objStore.Open(CAPICOM_STORE_LOCATION.CAPICOM_LOCAL_MACHINE_STORE, "My", CAPICOM_STORE_OPEN_MODE.CAPICOM_STORE_OPEN_READ_WRITE) objStore.Add(objCert)
The system send me this error: "System.UnauthorizedAccessException: Accesso negato at CAPICOM.StoreClass.Open(CAPICOM_STORE_LOCATION StoreLocation, String StoreName, CAPICOM_STORE_OPEN_MODE OpenMode)".
Do you Know what can I do?? or How can I write into this store? Thank you very much for your help.
Lucia Melotti
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
interop.capicom.dll is the C# COM Callable Wrapper for the CAPICOM.DLL that is auto-generated by Visual Studio.NET when you make a reference to the CAPICOM COM Library.
Follow the instructions above (Platform SDK Redistributable: CAPICOM)to install the CAPICOM.DLL
"To install CAPICOM extract "CAPICOM.DLL" from CAPICOM.CAB to your system32 directory, then execute "regsvr32.exe CAPICOM.DLL". The debug symbols should also be copied to the system32 directory for running C# projects in debug mode."
I don't have the source to CAPICOM as its a Microsoft library and only they have the source. All you need to do in VS.NET is Add Reference->COM->Browse and find CAPICOM.DLL
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
What if I want to get specific information about a particular certificate using the CAPICOM dll? Meaning all I have is the thumbprint hash of a cert. Just by that I need to get the details of the actual cert from the store. Things like valid date range, issued by, etc. From what I can see only the CAPICOM class gives you these utilities but I do not see something like CAPICOM.Certificate.LoadCertFromHash( "my_cert_hash" ) function.
Karl's the man! 
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I would try
Certificates.Find(CAPICOM_CERTIFICATE_FIND_TYPE.CAPICOM_CERTIFICATE_FIND_SHA1_HASH, thumbprintHash) where thumbprint hash is a string
Keep in mind this function returns a collection so more then likely you will need to foreach the collection that should have only one certificate.
If you download the CAPICOM library from Microsoft there are some C# sample projects that offer some good sample code. I also recommend taking a peak on msdn.microsoft.com. The CAPICOM library is easy once you get the hang of it.
-Karl
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Thanks I'll do that. After searching MSDN I found a lot of resources as you metioned that I can use. The above mentioned is what I need to implement at this time.
Nice article and follow up help!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Just to follow up from this I did the following to get my cert for those that might need some assistance:
Store localMachineCertStore = new Store(); localMachineCertStore.Open( CAPICOM_STORE_LOCATION.CAPICOM_LOCAL_MACHINE_STORE, "My", CAPICOM_STORE_OPEN_MODE.CAPICOM_STORE_OPEN_READ_ONLY ); Certificates certificates = (Certificates) localMachineCertStore.Certificates; certificates.Find( CAPICOM_CERTIFICATE_FIND_TYPE.CAPICOM_CERTIFICATE_FIND_SHA1_HASH, hexString, false ); foreach( Certificate myCert in certificates ) { // if done correctly there will only be one cert returned. myCert.SubjectName; }
|
| Sign In·View Thread·PermaLink | 2.00/5 |
|
|
|
 |
|
 |
I'm very impressed by this article. My question though is that I have 1 SSL cert installed properly (always will be static). I just want some IIS entries to use that same SSL cert. How could I implement your code to install the same cert but only at different IIS locations (ie LM/W3SVC/12 and LM/W3SVC/22)?
Thanks again!
Ryan
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
VBScript or C#?
Setting the SSL Cert needs two things, IIS Metabase Path and Certificate Thumbprint
From VBScript Example SslInstall.vbs found in demo download:
' Open Metabase Dim metaBase Set metaBase = CreateObject("IIS.MSAdminBase") ' Set SSL Certificate metaBase.SetMetabaseData SSLCertHashId, "/W3SVC/1", thumbprintByteArray metaBase.SetMetabaseData SSLStoreNameId, "/W3SVC/1", SSLStoreName WScript.Echo(stringData)
If you have a cert you need to install in multiple web sites, pass difference Metabase Paths into the field for /W3SVC/1. Do not specify LM as it is implied.
Getting the Certificate Thumbprint is easy...use the CAPICOM COM Library. Replace the computerName string with the subject name of the Certificate. You can modify the Find enum to fit your needs. Refer to http://msdn.microsoft.com/library/default.asp?url=/library/en-us/security/security/certificates_find.asp for more info.
' Open the store. Dim store Set store = CreateObject("CAPICOM.Store") store.Open CAPICOM_LOCAL_MACHINE_STORE, SSLStoreName, CAPICOM_STORE_OPEN_READ_ONLY ' Find Certificate Dim certificates Set certificates = store.Certificates Set certificates = certificates.Find(CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME, computerName, False) ' Get Byte Array Thumbprint Dim thumbprintByteArray If certificates.Count < 1 Then WScript.Echo("Certificate not found!") Return Else For Each certificate In certificates Dim hexThumbprint hexThumbprint = certificate.Thumbprint Dim certUtilities Set certUtilities = CreateObject("CAPICOM.Utilities") Dim binaryThumprint binaryThumbprint = certUtilities.HexToBinary(hexThumbprint) thumbprintByteArray = certUtilities.BinaryStringToByteArray(binaryThumbprint) Next End If
I can post a C# response if that is what you were looking for..
-Karl
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I'm using c#. I'm mainly interested on just setting the SSLCertHash but like you said you can't (which I found out the hard way prior to your article). I can set the other values manually (SecureBindings & SSLStoreName) but I'm interested on getting the ThumbPrint of the cert and then setting the cert.
Using your code how would I get the ThumbPrint of a SPECIFIC cert rather then iterating through a collection of certs. Would this be by the "friendly name" of the cert, like certificate.thumbprint("My Specific SSL Cert")?
Ryan
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Finding Certificates in the Certificate Store is done via the Certificates.Find method in Microsoft's CAPICOM library. If you add the CAPICOM.DLL to a C# project and include the namespace with using CAPICOM; you should be able to browse the library in the object browser. The CAPICOM library is well documented in MSDN.
Find a cert using the subject name ("CN=MySubjectName")
// Open Personal (Local Machine) Certificate Store Store machineCertStore = new Store(); machineCertStore.Open(CAPICOM_STORE_LOCATION.CAPICOM_LOCAL_MACHINE_STORE, "My", CAPICOM_STORE_OPEN_MODE.CAPICOM_STORE_OPEN_READ_ONLY);
// Get Certificates Certificates certificates = (Certificates)machineCertStore.Certificates;
// Find Certificate by using Subject Name Certificates certificateResults = certificates.Find(CAPICOM_CERTIFICATE_FIND_TYPE.CAPICOM_CERTIFICATE_FIND_SUBJECT_NAME, subjectName, false); // Find Returns a collection so loop through each result...most likely only 1 foreach(Certificate certificate in certificateResults) { // Get Hex String Thumbprint string thumbprint = certificate.Thumbprint; Console.WriteLine("\tCertificate Thumbprint: " + thumbprint); // Convert Hex String to Byte[] UtilitiesClass certConverter = new UtilitiesClass(); string binaryThumbprint = certConverter.HexToBinary(thumbprint); return (byte[])certConverter.BinaryStringToByteArray(binaryThumbprint); }
If you know the cert you want to install...you can skip this whole process...just get the SHA1 has from the Certificates MMC, throw it into a byte array and pass to the MSAdminBase Wrapper.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Correct, I already know what cert I wish to install thus it sounds like I don't even need to use capicom.dll ... right? I would do this just using DirectoryEntry but that's the whole problem, it doesn't post correctly.
Can you please confirm?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
Run MMC.exe Add the Certificates Snap-In Select Computer Account Expand Personal Select Certificates
You should see your cert in the right pane. Double-click and select the details tab.
Copy Thumbprint
byte[] thumbprintByteArray = new byte[] { Thumbprint Bytes go here...}
// Open Metabase Interface MSAdminBaseClass adminBaseClass = new MSAdminBaseClass(); // Set SSL Certificate adminBaseClass.SetMetabaseData(SslCertHashId, metaDataPath, thumbprintByteArray); adminBaseClass.SetMetabaseData(SslStoreNameId, metaDataPath, "MY");
That is all you need.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
I must be stupid but I can't seem to get this line to work:
byte[] thumbprintByteArray = new byte[] { Thumbprint Bytes go here...}
I'm inserting my thumbprint as:
byte[] thumbprintByteArray = new byte[] { 46, 82, 49, 19, 38, 26, 7f, 2d, d4, 0c, 09, cf, 0a, 25, 04, f0, 4f, 5c, 85, e1 }
that doesn't work though. I've done it a ton of different ways but with no success. So what should I be putting there if my thumbprint is "46 82 49 19 38 26 7f 2d d4 0c 09 cf 0a 25 04 f0 4f 5c 85 e1"?
Sorry for this minor 101 stuff.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
 |
That worked nicely ... thank you very much.
I have one last question, hopefully , I'm using your function GetMetabaseData() because I want to get back (as a string) the cert that is installed. Meaning I want to get back something like "4682491938267f2dd40c09cf0a2504f04f5c85e1". Your function returns the value as object but when I cast it I get weird results. For example I've done the following:
UTF8Encoding stringConvert = new UTF8Encoding(); return stringConvert.GetString( ( byte[] ) stringConvert.GetMetabaseData( 5506, "/W3SVC/1") );
I then get crap like "FI8&- %O\". How can I cleanly get this information back to my app as a string? The reason I need to do this is because I need to get information about a certificate installed (valid dates, etc.). I know how to do this from the CAPICOM, with the help you've given me, but I need a starting point as to what is installed which would be the cert which is store as "SSLCertHash" in the MetaBase but of course you already knew that ;P.
Thanks again!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
 |
You almost had it..
byte[] sslThumbprint = (byte[])MSAdminBaseClass.GetMetabaseData(5506, "/W3SVC/1");
// Convert thumbprint to hex string using CAPICOM UtilitiesClass certConverter = new UtilitiesClass(); string binaryString = certConverter.ByteArrayToBinaryString(sslThumbprint); string hexString = certConverter.BinaryToHex(binaryString);
-Karl
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|