-
Sep 17th, 2019, 12:49 PM
#1
Thread Starter
Lively Member
WinHTTPRequest Client Certificate
Hi,
We have a need to use a client certificate in order to work with an API endpoint. Everything is working until we try to have a different user account run the process. Apparently the issue we're having is due to the client certificate being installed in my personal store (LOCAL_MACHINE\MY\Certificate).
Installing the certificate in each user's personal store isn't an option as they aren't able to establish a console session on the server in question (RemoteApp). I need to install the client certificate in a location where all users can access it (and it can be used with the SetClientCertificate method), or be able to reference the certificate PFX file.
Any assistance would be greatly appreciated!
Best Regards
Brad
-
Sep 17th, 2019, 03:49 PM
#2
Re: WinHTTPRequest Client Certificate
I work in an evironment where I have to install a dozen certificates to use a system (literally there's 12, don't ask) ... we install them by downloading them to our local computer and then double-clicking them... that installs them into our local keystore ... once there, I can delete them from the download folder.
-tg
-
Sep 17th, 2019, 05:32 PM
#3
Thread Starter
Lively Member
Re: WinHTTPRequest Client Certificate
Hi,
Apologies for the confusion. The client certificate provided to us is a .der file, which we have to import to the server in question (we're using the 'Certificates (Local Computer)' MMC snap-in). I need to install this certificate in a store (and have the relevant path to the store) so it can be referenced by all users when calling the SetClientCertificate method. How would I do this?
When installing under the 'Certificates (Local Computer)\Personal\Certificates' node and using 'LOCAL_MACHINE\MY\CertificateName' as the path when calling SetClientCertificate other users receive a Method '~' of Object '~' failed message.
Thanks!
-
Jun 18th, 2022, 06:56 AM
#4
Re: WinHTTPRequest Client Certificate
 Originally Posted by Brad.
I need to install the client certificate in a location where all users can access it (and it can be used with the SetClientCertificate method), or be able to reference the certificate PFX file.
Here is how to import (all certificates from) a PFX file into a system store so its (first) certificate can be used with SetClientCertificate method.
Code:
Option Explicit
Private Declare Function GetFileAttributes Lib "kernel32" Alias "GetFileAttributesA" (ByVal lpFileName As String) As Long
'--- crypt32
Private Declare Function PFXImportCertStore Lib "crypt32" (pPFX As Any, ByVal szPassword As Long, ByVal dwFlags As Long) As Long
Private Declare Function CertUnregisterSystemStore Lib "crypt32" (ByVal pvSystemStore As Long, ByVal dwFlags As Long) As Long
Private Declare Function CertOpenStore Lib "crypt32" (ByVal lpszStoreProvider As Long, ByVal dwEncodingType As Long, ByVal hCryptProv As Long, ByVal dwFlags As Long, ByVal pvPara As Long) As Long
Private Declare Function CertCloseStore Lib "crypt32" (ByVal hCertStore As Long, ByVal dwFlags As Long) As Long
Private Declare Function CertEnumCertificatesInStore Lib "crypt32" (ByVal hCertStore As Long, ByVal pPrevCertContext As Long) As Long
Private Declare Function CertAddCertificateContextToStore Lib "crypt32" (ByVal hCertStore As Long, ByVal pCertContext As Long, ByVal dwAddDisposition As Long, ppStoreContext As Any) As Long
Private Declare Function CertFreeCertificateContext Lib "crypt32" (ByVal pCertContext As Long) As Long
Private Declare Function CertGetNameStringW Lib "crypt32" (ByVal pCertContext As Long, ByVal dwType As Long, ByVal dwFlags As Long, ByVal pvTypePara As Long, ByVal pszNameString As Long, ByVal cchNameString As Long) As Long
Private Type CRYPT_DATA_BLOB
cbData As Long
pbData As Long
End Type
Private Function ImportPfxToSystemStore(sStoreName As String, sPfxFile As String, Optional sPassword As String) As String
Const CERT_SYSTEM_STORE_CURRENT_USER As Long = &H10000
Const CERT_STORE_PROV_SYSTEM As Long = 10
Const CRYPT_EXPORTABLE As Long = &H1
Const NTE_BAD_ALGID As Long = &H80090008
Const CERT_STORE_DELETE_FLAG As Long = &H10
Const CERT_STORE_ADD_NEW As Long = 1
Const CERT_STORE_ADD_REPLACE_EXISTING As Long = 3
Const CERT_NAME_SIMPLE_DISPLAY_TYPE As Long = 4
Const LNG_FACILITY_WIN32 As Long = &H80070000
Dim baPfx() As Byte
Dim uBlob As CRYPT_DATA_BLOB
Dim hPfxStore As Long
Dim hCertStore As Long
Dim pCertContext As Long
Dim lSize As Long
Dim sApiSource As String
Dim hResult As Long
baPfx = ReadBinaryFile(sPfxFile)
If UBound(baPfx) < 0 Then
GoTo QH
End If
uBlob.cbData = UBound(baPfx) + 1
uBlob.pbData = VarPtr(baPfx(0))
hPfxStore = PFXImportCertStore(uBlob, StrPtr(sPassword), CRYPT_EXPORTABLE)
If hPfxStore = 0 And Err.LastDllError <> NTE_BAD_ALGID Then
hPfxStore = PFXImportCertStore(baPfx(0), 0, CRYPT_EXPORTABLE)
End If
If hPfxStore = 0 Then
sApiSource = "PFXImportCertStore"
hResult = Err.LastDllError
GoTo QH
End If
Call CertUnregisterSystemStore(StrPtr(sStoreName), CERT_SYSTEM_STORE_CURRENT_USER Or CERT_STORE_DELETE_FLAG)
hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER, StrPtr(sStoreName))
If hCertStore = 0 Then
hResult = Err.LastDllError
sApiSource = "CertOpenStore(" & sStoreName & ")"
GoTo QH
End If
Do
pCertContext = CertEnumCertificatesInStore(hPfxStore, pCertContext)
If pCertContext = 0 Then
Exit Do
End If
If CertAddCertificateContextToStore(hCertStore, pCertContext, CERT_STORE_ADD_REPLACE_EXISTING, ByVal 0) <> 0 Then
If CertAddCertificateContextToStore(hCertStore, pCertContext, CERT_STORE_ADD_NEW, ByVal 0) <> 0 Then
sApiSource = "CertAddCertificateContextToStore"
hResult = Err.LastDllError
GoTo QH
End If
End If
If LenB(ImportPfxToSystemStore) = 0 Then
lSize = CertGetNameStringW(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, 0, 0, 0)
If lSize > 0 Then
ImportPfxToSystemStore = String$(lSize - 1, 0)
Call CertGetNameStringW(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, 0, StrPtr(ImportPfxToSystemStore), lSize)
ImportPfxToSystemStore = "CURRENT_USER\" & sStoreName & "\" & ImportPfxToSystemStore
End If
End If
Loop
QH:
If pCertContext <> 0 Then
Call CertFreeCertificateContext(pCertContext)
End If
If hPfxStore <> 0 Then
Call CertCloseStore(hPfxStore, 0)
End If
If hCertStore <> 0 Then
Call CertCloseStore(hCertStore, 0)
End If
If LenB(sApiSource) <> 0 Then
Err.Raise IIf(hResult < 0, hResult, hResult Or LNG_FACILITY_WIN32), sApiSource
End If
End Function
Private Function ReadBinaryFile(sFile As String) As Byte()
Dim baBuffer() As Byte
Dim nFile As Integer
baBuffer = vbNullString
If GetFileAttributes(sFile) <> -1 Then
nFile = FreeFile
Open sFile For Binary Access Read Shared As nFile
If LOF(nFile) > 0 Then
ReDim baBuffer(0 To LOF(nFile) - 1) As Byte
Get nFile, , baBuffer
End If
Close nFile
End If
ReadBinaryFile = baBuffer
End Function
Private Sub Form_Load()
Const PFX_FILE As String = "C:\Work\Temp\VbAsyncSocket\test\Secure\ClientCerts\client1.pfx"
On Error GoTo EH
With New WinHttpRequest
.Open "GET", "https://server.cryptomix.com/secure/"
.SetClientCertificate ImportPfxToSystemStore("MyApp Certificate Store", PFX_FILE)
.Send
Debug.Print .ResponseText
End With
Exit Sub
EH:
MsgBox Err.Description, vbCritical
End Sub
You might want to additionally call CertUnregisterSystemStore on "MyApp Certificate Store" after WinHttpRequest finishes so that the system store does not show up in certmgr.msc under "Certificates - Current User" esp. if the PFX is password protected as the certificate will be available (though private key is not exportable so it's still safe enough).
cheers,
</wqw>
Last edited by wqweto; Jun 19th, 2022 at 09:19 AM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|