Results 1 to 4 of 4

Thread: WinHTTPRequest Client Certificate

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Mar 2014
    Posts
    117

    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

  2. #2
    Smooth Moperator techgnome's Avatar
    Join Date
    May 2002
    Posts
    33,856

    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
    * I don't respond to private (PM) requests for help. It's not conducive to the general learning of others.*
    * I also don't respond to friend requests. Save a few bits and don't bother. I'll just end up rejecting anyways.*
    * How to get EFFECTIVE help: The Hitchhiker's Guide to Getting Help at VBF - Removing eels from your hovercraft *
    * How to Use Parameters * Create Disconnected ADO Recordset Clones * Set your VB6 ActiveX Compatibility * Get rid of those pesky VB Line Numbers * I swear I saved my data, where'd it run off to??? *

  3. #3

    Thread Starter
    Lively Member
    Join Date
    Mar 2014
    Posts
    117

    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!

  4. #4
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Posts
    4,043

    Re: WinHTTPRequest Client Certificate

    Quote Originally Posted by Brad. View Post
    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>

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width