Quantcast
Channel: Windows SDK Support Team Blog
Viewing all 126 articles
Browse latest View live

How to take a quartz log?

$
0
0

 

Many a times I do get this questions from my varied customers and colleagues and I cannot answer them instantly or even after looking here and there for a day. So I just wanted to blog it.

Please see the MSDN link http://msdn.microsoft.com/en-us/library/dd388394(v=VS.85).aspx for the steps in getting the logs.

Here are some steps to remember:

DebugRoot = SOFTWARE\Microsoft\DirectShow\Debug (Windows Vista or later)

Registry Location = HKEY_LOCAL_MACHINE\<DebugRoot>\<ModuleName>\<MessageType>

ModuleName = Quartz.dll

MessageType = TRACE

clip_image002

I would recommend making two tests by setting TRACE to:

1. 0x00000003 and

2. 0xFFFFFFFF

So you get two quartz logs.

-Shamik


How to get the CSP name from a certificate containing the private key?

$
0
0

 

I was testing with some code to get the CSP name from a certificate containing the private key. A sample code is shown below:

// GetCSPFromCert.cpp : Defines the entry point for the console application.

//

#include "stdafx.h"

#include <stdio.h>

#include <windows.h>

#include <wincrypt.h>

#pragma comment(lib, "crypt32.lib")

#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

// Replace the following string with the subject of the signer

// certificate.

#define SIGNER_NAME L"shmisra" // Your certificate name.

void MyHandleError(char *s);

void main(int argc, char* argv[])

{

    HCRYPTPROV hCryptProv;         // CSP handle

    HCERTSTORE hStoreHandle;       // Store handle

    PCCERT_CONTEXT pSignerCert;    // Signer certificate

    DWORD dwKeySpec;

//---------------------------------------------------------------

// Open the My system certificate store.

    hStoreHandle = CertOpenStore(

        CERT_STORE_PROV_SYSTEM,

        0,

        NULL,

        CERT_SYSTEM_STORE_CURRENT_USER,

        L"MY");

if(!hStoreHandle)

    {

        MyHandleError( "Could not open the MY system store.");

    }

    printf("Cert name: %s\n", argv[1]);

//---------------------------------------------------------------

// Get a pointer to a signer's signature certificate.

    pSignerCert = CertFindCertificateInStore(

        hStoreHandle,

        MY_ENCODING_TYPE,

        0,

        CERT_FIND_SUBJECT_STR,

        SIGNER_NAME,

        NULL);

if (!pSignerCert)

    {

        MyHandleError("Cert not found.\n");

    }

//---------------------------------------------------------------

// Get a handle to a cryptographic provider.

if( !(CryptAcquireCertificatePrivateKey(

        pSignerCert,

        0,

        NULL,

        &hCryptProv,

        &dwKeySpec,

        NULL)))

    {

        MyHandleError("CryptAcquireContext failed");

    }

    CHAR pszName[1000];

    DWORD cbName;

//---------------------------------------------------------------

// Read the name of the CSP.

    cbName = 1000;

if(CryptGetProvParam(

        hCryptProv,

        PP_NAME,

        (BYTE*)pszName,

        &cbName,

        0))

    {

        _tprintf(TEXT("CryptGetProvParam succeeded.\n"));

        printf("Provider name: %s\n", pszName);

    }

else

    {

        MyHandleError("Error reading CSP name.\n");

    }

//---------------------------------------------------------------

// Read the name of the key container.

    cbName = 1000;

if(CryptGetProvParam(

        hCryptProv,

        PP_CONTAINER,

        (BYTE*)pszName,

        &cbName,

        0))

    {

        _tprintf(TEXT("CryptGetProvParam succeeded.\n"));

        printf("Key Container name: %s\n", pszName);

    }

else

    {

        MyHandleError("Error reading key container name.\n");

    }

    CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_FORCE_FLAG);

    CryptReleaseContext(hCryptProv, 0);

}

//-------------------------------------------------------------------

//  Define function MyHandleError

void MyHandleError(char *s)

{

    fprintf(stderr,"An error occurred in running the program. \n");

    fprintf(stderr,"%s\n",s);

    fprintf(stderr,"Error number %x.\n",GetLastError());

    fprintf(stderr,"Program terminating. \n");

    exit(1);

}

A screen shot of my Smart Card logon certificate is shown below:

clip_image002

For logon certificates, they are stored in the certificate store and you can access the key/ certificate using MS-CAPI.

References:

· http://msdn.microsoft.com/en-us/library/aa379885(VS.85).aspx

· http://msdn.microsoft.com/en-us/library/aa380196(VS.85).aspx

-Shamik

Connect() fails with error 10061 (WSAECONNREFUSED) / datagram sent via sendto() lost / loopback address

$
0
0

 A server application (TCP) using socket functions is waiting on NIC address to receive connection from the client.

sockaddr_in service;

service.sin_family = AF_INET;

service.sin_addr.s_addr = inet_addr("10.171.xx.xx");

service.sin_port = htons(27015);

Now a client application on same machine uses connect() to connect to the server application get error 10061 (WSAECONNREFUSED) when the IP Address used is loopback address (127.0.0.1).

clientService.sin_family = AF_INET;

clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );

clientService.sin_port = htons( DEFAULT_PORT);

The same way, when an application using UDP protocol uses recvfrom() on NIC’s address, like below:

RecvAddr.sin_family = AF_INET;

RecvAddr.sin_port = htons(Port);

RecvAddr.sin_addr.s_addr = inet_addr("10.171.xx.xx");

And the UDP sender running on same machine is sending the datagram on loopback address (127.0.0.1), the packet does not get received by the receiver, sent on same port.

RecvAddr.sin_family = AF_INET;

RecvAddr.sin_port = htons(Port);

RecvAddr.sin_addr.s_addr = inet_addr("127.0.0.1");

This is happening on Windows Vista onwards Operating System, while it used to be working on earlier versions of OS. This is design change on Windows Vista onwards, Strong host model vs WeAk host model. Windows Vista onwards, we have strong host model on by default on all interfaces.

This can also be a problem if you connect() to a real IP address on interface A and the packets are trying to go out another interface, Interface B. This can occur when the default route points to Interface B.

Please check for more details- http://technet.microsoft.com/en-us/magazine/2007.09.cableguy.aspx

Attached is the minimal code sample to demonstrate the behavior explained above. You will need to change the IP Addresses mentioned to your machine’s adapter IP address.

More references- RFC 3484

Content developed by: Nitin Dhawan

Content reviewed by:  Jeff Lambert

Iphlpapi!AddIpAddress() adds the IP address but other machines can’t locate this machine (Windows Server 2008)

$
0
0

On Windows Server 2003, when an IP Address is added to the machine’s adapter, a gratuitous ARP packet is broadcast to the network. This indicates to other machines that there is a change in the IP Address of a
machine with “this” MAC address, so other machines can update their ARP table to identify the machine correctly.

On Windows Server 2008 onwards, when an IP address is added to the machine’s adapter, a gratuitous ARP packet is not broadcast to the network. This causes other machines on the network to be  unable to locate this machine because the ARP table on these machines (IP to MAC address) was not updated of this change. SendArp() and other methods (clearing ARP cache) will not be helpful.

As far as I know, this does not apply in cluster environment of Windows Server 2008, meaning a gratuitous ARP packet is broadcast to the network for a cluster IP Address change.

On Windows Server 2008, you can still send a gratuitous ARP packet on an IP Address change request, but you will need to implement it via NDIS. The NDISProt  sample in WDK can be modified to achieve this so a gratuitous ARP packet is broadcast to network on an IP Address change.

More references- RFC 826, RFC 5227 

Keywords- AddIpAddress, gratuitous ARP

 

Content developed by: Nitin Dhawan

Content reviewed by:  Jeff Lambert

Microsoft Platform Ready Test Tool & Windows Error Reporting

$
0
0

Hello everyone,

 

My name is Nathan Manis.  I work as part of the Microsoft Developer Support team here at Microsoft support.  My team supports customers who are using the technologies and tools that are part of the Microsoft Windows SDK.  One common question that we are seeing nowadays is around application certification for the Windows 8 and Server 2012 operating systems.  As part of the certification process for applications to be certified to be compatible with Windows Server 2012, Microsoft has released a tool called the Microsoft Platform Ready Test Tool.  The current version is at the time of this blog is version 3.6 and available here.

 

    

After setting up the Microsoft Platform Ready Test Tool, a common question is around an error that is reported on "Windows Error Reporting (WER)" being disabled.  Specifically, the error appears as part of doing the prerequisite check before running the Server 2012 tests.  An example of the error is shown in the image below:

 

 

 

This is the not uncommon and is the first error that you may encounter.  The error message above will appear with the default Windows Server 2012 settings since Windows Error Reporting is not enabled by default.  

 

To resolve the issue, go into server manager in Server 2012 and enable the Windows Error Reporting setting to "On".   After turning the Windows Error Reporting feature to “On” and re-running the Microsoft Platform Ready Test Tool to do the certification test, Windows Server 2012 will no longer report error and you are on your way to doing further testing. 

 

 

For more information on the Microsoft Platform Ready Test Tool, please visit http://microsoftplatformready.com  

How can my application work when UAC is enabled and fail when it is disabled?

$
0
0

Hello Everyone, My name is Frank Kim and I work in Developer Support.  My expertise is in Windows Security (Authorization + Authentication), Remote Desktop and Windows Services.  For my first blog post, I thought I would discuss an interesting issue encountered by several of my customers.

User Access Control (UAC) was introduced in Windows VISTA to force users to run as non Administrators.  A lot of applications encountered "Access Denied" errors when UAC was enabled.  A bad answer to resolving this issue was to turn off UAC. We would assume that if UAC was turned off and if the user was running as a FULL administrator, everything would just work.  In the case below, this wasn't true.

Let me explain what was going on.  With the introduction of UAC, we also introduced the Windows Integrity Mechanism.  The purpose of Windows Integrity is to restrict the access permissions of applications running under the same user account that are less trustworthy.  The mechanism prevents less trustworthy code from modifying objects at a higher level.  (This definition is from the following MSDN article):

http://msdn.microsoft.com/en-us/library/bb625962.aspx

The Windows Integrity Mechanism is used in Internet Explorer and is known as "Protected Mode".  Basically, it prevents code in Internet Explorer from accessing secured objects such as files since IE is running at a lower level.

I had several developers encounter impersonation issues with LogonUser() when UAC was turned off and the issue was with Integrity Levels.  What was happening is if you were running as a normal user (medium integrity level) and you attempt to impersonate a user who belongs to the Administrator group, you would get the following scenarios.

1. If UAC was turned ON, due to UAC, the user who was an Administrator would still be running as a non-Administrator and thus their resultant integrity level wouldl be medium.  A medium integrity level user can impersonate a medium integrity level user.

2. If UAC was turned OFF, the user whose an Administrator would be running as an actual Administrator and thus their resultant integrity level would be a high.  If a medium integrity level user attempts to impersonate an high integrity level user, the resultant impersonation would be at the IDENTIFY level and NOT IMPERSONATION level. 

This resultant impersonation level led to "Access Denied" issues in the code since at the IDENTITY level you can only do AccessChecks.

 

 

 

Adding certificates extensions via a Certificate Services Policy Module

$
0
0

Hi everyone,

My name is Carlos and my expertise is in Cryptography and Certificates APIs/interfaces.  My blog posts will mostly relate to PKI questions or problems that I see customers encountering and I will talk about how to resolve them.

For my first blog post, I'll write about how to add extensions to a certificate via a policy module and will provide a code example.  This topic is for those already experienced with certificate APIs.  For more information please read the documentation on writing custom modules -
http://msdn.microsoft.com/en-us/library/windows/desktop/aa388216(v=vs.85).aspx

 

What is a Policy Module?

A policy module is a DLL that is loaded by Microsoft Certificate Services to process certificate requests as they come in.  A module has the ability to accept or reject a certificate request as well as modify the certificate attributes/extensions before it's issued.

A policy module is a COM based component that must implement an ICertPolicy and ICertManageModule interface.  The most important being the ICertPolicy interface -http://msdn.microsoft.com/en-us/library/windows/desktop/aa385033(v=vs.85).aspx.  The ICertPolicy::VerifyRequest method is where most of the work is done.


How do I get started?

Writing a custom policy module is complex if you want to start from scratch.  Luckily, Microsoft provides Win2K8 and Win2k8R2 policy module samples in the Windows SDK for Windows 7.  You can download and review these samples to get a better understanding about how policy modules work.


How do I add an extension to the incoming certificate request?

As I stated earlier, most of the work is performed in the ICertPolicy::VerifyRequest method.  This method must acquire the ICertServerPolicy interface and call ICertServerPolicy::SetCertificateExtension to add the custom extension that you want the issued certificate to have.  The extensions must be encoded before calling ICertServerPolicy::SetCertificateExtension.

The samples already contain example extension methods that can be called from VerifyRequest.  Here's a list of some of them:
CCertPolicySample::_AddRevocationExtension
CCertPolicySample::_AddAuthorityKeyId
CCertPolicySample::_AddDefaultKeyUsageExtension
CCertPolicySample::_AddEnhancedKeyUsageExtension
CCertPolicySample::_AddDefaultBasicConstraintsExtension

You can add additional extensions recognized by Windows.  You encode them using CryptEncodeObject.  The extensions and constants that can be encoded can be found here -http://msdn.microsoft.com/en-us/library/windows/desktop/aa378145(v=vs.85).aspx. Or you can encode your own custom extension and pass that to SetCertificateExtension.

I recently wrote a method called _AddCertPoliciesExtension that adds a Certificate Policies extension to the certificate.  I've included it below as a code example.  The method itself uses a lot of the helper functions included with the sample.

That's it for now, until my next blog post. 

 

HRESULT CCertPolicySample::_AddCertPoliciesExtension(
        IN ICertServerPolicy *pServer) {
    HRESULT hr;
    CERT_NAME_VALUE NameValue;
    LPSTR strQualifier = "http://www.test.org/PKI/AssuranceLevel";
    BYTE *pbEncodedQualifier = NULL;
    DWORD cbEncodedQualifier = 0;
    CERT_POLICIES_INFO cpi;
    BYTE *pbPolicies = NULL;
    DWORD cbPolicies;
    CERT_POLICY_INFO *pcpi = NULL;
    CERT_POLICY_QUALIFIER_INFO *pcpqi = NULL;   
    VARIANT varExtension;

    ZeroMemory(&cpi, sizeof(cpi));
    VariantInit(&varExtension);

    NameValue.dwValueType = CERT_RDN_IA5_STRING;
    NameValue.Value.pbData = (LPBYTE) strQualifier;
    NameValue.Value.cbData = lstrlenA(strQualifier);

    if (!ceEncodeObject(
            X509_ASN_ENCODING,
            X509_ANY_STRING ,
            &NameValue,
            0,
            FALSE,
            &pbEncodedQualifier,
            &cbEncodedQualifier))
    {
        hr = ceHLastError();
        _JumpError(hr, error, "Policy:ceEncodeObject");
    }

    cpi.cPolicyInfo = 1;
    cpi.rgPolicyInfo = (CERT_POLICY_INFO *) LocalAlloc(
                LMEM_FIXED | LMEM_ZEROINIT,
                cpi.cPolicyInfo * sizeof(cpi.rgPolicyInfo[0]));
    if (NULL == cpi.rgPolicyInfo)
    {
        hr = E_OUTOFMEMORY;
        _JumpError(hr, error, "Policy:LocalAlloc");
    }

    pcpi = cpi.rgPolicyInfo;
    pcpi[0].cPolicyQualifier = 1;
    pcpi[0].pszPolicyIdentifier = "2.17.845.1.11293.1.12.1.1";

    cpi.rgPolicyInfo[0].rgPolicyQualifier = (CERT_POLICY_QUALIFIER_INFO*)  LocalAlloc(
                LMEM_FIXED | LMEM_ZEROINIT,
                cpi.rgPolicyInfo[0].cPolicyQualifier * sizeof(cpi.rgPolicyInfo[0].rgPolicyQualifier[0]));
    if (NULL == cpi.rgPolicyInfo[0].rgPolicyQualifier)
    {
        hr = E_OUTOFMEMORY;
        _JumpError(hr, error, "Policy:LocalAlloc");
    }

    pcpqi = cpi.rgPolicyInfo[0].rgPolicyQualifier;

    pcpqi[0].pszPolicyQualifierId = szOID_PKIX_POLICY_QUALIFIER_CPS;
    pcpqi[0].Qualifier.pbData = pbEncodedQualifier;
    pcpqi[0].Qualifier.cbData = cbEncodedQualifier;

    if (!ceEncodeObject(
            X509_ASN_ENCODING,
            X509_CERT_POLICIES,
            &cpi,
            0,
            FALSE,
            &pbPolicies,
            &cbPolicies))
    {
        hr = ceHLastError();
        _JumpError(hr, error, "Policy:ceEncodeObject");
    }

    varExtension.bstrVal = NULL;

    if (!ceConvertWszToBstr(
            &varExtension.bstrVal,
            (WCHAR const *) pbPolicies,
            cbPolicies))
    {
        hr = E_OUTOFMEMORY;
        _JumpError(hr, error, "Policy:ceConvertWszToBstr");
    }

    varExtension.vt = VT_BSTR;

    hr = polSetCertificateExtension(
                pServer,
                TEXT(szOID_CERT_POLICIES),
                PROPTYPE_BINARY,
                0,
                &varExtension);
    _JumpIfError(hr, error, "Policy:polSetCertificateExtension");

error:
    VariantClear(&varExtension);
    if (NULL != pcpi) LocalFree(pcpi);  
    if (NULL != pcpqi) LocalFree(pcpqi);
    if (NULL != pbPolicies) LocalFree(pbPolicies);
    if (NULL != pbEncodedQualifier) LocalFree(pbEncodedQualifier);

    return(hr);
}

Running the Microsoft Platform Ready Test Tool inside of Hyper-V image

$
0
0

Hi everyone,

Writing today to pass along a tip on using the Microsoft Platform Ready Test Tool (v4.0).  In my prior blog post, I had blogged on a common support request that we have getting for running the Microsoft Platform Ready Test Tool (v4.0) with Windows Error Reporting needing to be enabled on the server.   Another common issue that we have been receiving recently is around the requirements to run the Microsoft Platform Ready Test Tool (v4.0) inside of a Hyper-V hosted image.    You can find the latest version of toolkit at  Microsoft Platform Ready Test Tool v4.0

 

Specifically, we have had a couple of calls where customers would have a Windows 2008 R2 host operating system running Hyper-V with the intention to host a Server 2012 image for certification testing.  This configuration with Windows 2008 R2 as the host can happen since the Microsoft Platform Ready Test Tool (v4.0) setup will install in this configuration.  Currently, the setup does not restrict the host operating system to be solely Server 2012.  This is because the toolset can be used to perform in-house testing using Windows 2008 R2 as a Hyper-V host while preparing for doing an official certification submission.  The image below shows the configuration that can be setup but will not pass the Hyper-V verification requirement:

    

 

 

To prevent the Hyper-V verification error, the Microsoft Platform Ready Test Tool (v4.0) must be ran with the host operating system to be Windows Server 2012 or the Windows Server 2012 image can hosted in Windows Azure as defined here:

      http://www.windowsazure.com/en-us/manage/windows/common-tasks/upload-a-vhd/

 

 

Otherwise, if the MPR Test Tool will not pass the verification test as shown below with the failure message:

                   “Virtual Machine not on Microsoft Windows Server 2012 Hyper-V”

 

 

In addition, you should ensure that certification testing is being performed inside of the actual virtual machine itself versus the phyisical machine.   Otherwise, you will receive the same verification error when running the verification check test on a physical machine.   We outline virtual machine requirement on on the start screen inside the tool as shown below:

 

 

When doing preparing for an official submission request, the resulting report will need to have the Hyper-V check to show a passing verification result.  Therefore, ensure that your Hyper-V host operating system is running on Windows Server 2012 or being hosted inside of Windows Azure for the certification report creation.   You will want to see all green configuration status messages as shown below:

 

 

For information, please visit the Microsoft Platform Ready - Test Requirements Criteria 1.3 and the Microsoft Platform Ready website.     

Thanks,
Nathan

 


Finding Your Windows Terminal Server Virtual IP Address

$
0
0

My name is Jeff Lambert.  I work as part of the Microsoft Developer Support team here at Microsoft support.

My team supports customers who are using the technologies and tools that are part of the Microsoft Windows SDK to write desktop applications.

I normally handle networking cases so when a customer wanted to find out the Windows Terminal Server virtual IP address the client was assigned, I took the case.

Windows Terminal Server virtual IP addresses are treated just like a regular network adapter that has multiple IP addresses assigned. There isn’t any difference at the networking level. A machine with 5 client sessions will have 6 addresses, one for the terminal server itself and one for each client.

We can use the Windows Terminal Server APIs to discover the virtual IP addresses assigned to ours and, if we are an administrator, other sessions as well.

The API, WTSQuerySessionInformation() can be used to query 30 different types of information, and one of them is the virtual IP address assigned to a session. Using the short sample below we can find the virtual IP address our session is using.

// VirtualIP.cpp : Defines the entry point for the console application.

 #pragma comment(lib,"Wtsapi32.lib") // Library for WTS functions

 #include "stdafx.h"
#include "windows.h"
#include "Wtsapi32.h" 

int _tmain(int argc, _TCHAR* argv[])
{

       PWTS_SESSION_ADDRESS wAddr = NULL;
       DWORD dwBytes = 0;             

       // Use WTS_CURRENT_SERVER_HANDLE and
       // WTS_CURRENT_SESSION to get just our virtual address

       if(WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE,
              WTS_CURRENT_SESSION, WTSSessionAddressV4,
              (LPWSTR*)&wAddr, &dwBytes))
       {

              //wAddr->AddressFamily is always 2 (AF_INET)
              printf("Family: %d\n",wAddr->AddressFamily);
              printf("Address: %d.%d.%d.%d\n",wAddr->Address[2],
              wAddr->Address[3],wAddr->Address[4],wAddr->Address[5]);
       } else
       {
              printf("WTSQuerySessionInformation failed. GLE=%d\n",GetLastError());
       }     
       return 0;

}

The sample uses predefined handles for the local terminal server and session. Combining WTSQuerySessionInformation() with the APIs WTSOpenServer() and WTSEnumerateSessions() we can find the virtual IP assigned to any session of any terminal server.

For more information on Windows Terminal Services IP virtual IP addresses see this blog.

How to launch a process as a Full Administrator when UAC is enabled?

$
0
0

With the introduction of User Access Control (UAC) with Windows VISTA, the ability to launch a process as a full administrator when UAC was enabled doesn’t automatically happen anymore.  Typically, you make the following API calls to launch a process as an Administrator (if the current user is not an administrator):

  1. You call LogonUser() where you specify a user who belongs to the administrator group.
  2. CreateProcessAsUser() with the token returned from LogonUser().

If you run this code on Windows XP versus Windows 8, you are going to see different results.  The resultant process on Windows XP will be running as administrator while on Windows 8, the user will NOT be running as an Administrator.

A couple of things to note, UAC only impacts Interactive logons.  (This is specified by the logon type in LogonUser, LOGON32_LOGON_INTERACTIVE).  You can see this with services, a service configured for an Administrator runs as an Administrator.  One way to make sure your launched process is running as an
Administrator is to use a Service or Batch logon type.  The other way is to launch a process as an Administrator is to realize that the Administrator Token for a user who belongs to the Administrator group is embedded in their token.  Windows just doesn’t use it by default when UAC is enabled.  You can programmatically
retrieve the Administrator Token via the GetTokenInformation() call and specifying TokenLinkedToken as the token information class.  This operation requires the caller to have the SeTcbPrivilege so not any user can make this call.  The new steps to launch a process as an administrator with an interactive token are:

  1. You must have the SeTcbPrivilege and it must be enabled. 
  2. LogonUser() with LOGON32_LOGON_INTERACTIVE
  3. GetTokenInformation() with the token returned from LogonUser() specifying the TokenLinkedToken class.
  4. CreateProcessAsUser() with the token returned from GetTokenInformation().

If you don’t have the SeTcbPrivilege(), you will still be able to obtain the TokenLinkedToken but it will result in an IDENTIFY level token which will fail in the call to CreateProcessAsUser().

How to get a Cryptographic Public Key from a Certificate in a Windows Store application

$
0
0

If you're writing a Windows Store application you'll find that the WinRT runtime is missing the X509Certificate interfaces found in .NET.  In many instances, you may want to encrypt or verify a signature with any given certificate.  That means extracting the public key out of the certificate.  .NET has the X509Certificate2 class that simply contains the property X509Certificate.PublicKey.Key which returns an RSACryptographicServiceProvider.  However, there's no WinRT equivalent class.

The common suggestion to get around the problem is to build a .NET application to extract the public key into a base64 string.  Later this encoded public key could be used from your Windows Store application.
The code snippet to do this would look something like this:

// Base64 encoded public key gotten previously from a .NET app
string pubKeyStr = "MIGJ...";
byte[] pubKeyBytes = CryptographicBuffer.decodeFromBase64String(pubKeyStr);

AsymmetricKeyAlgorithmProvider alg = AsymmetricKeyAlgorithmProvider.openAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptographicKey pubKey = alg.importPublicKey(pubKeyBytes, CryptographicPublicKeyBlobType.pkcs1RsaPublicKey);

I wrote a general solution to the problem.  The code extracts the Public key from a base64 encoded certificate.  No need to pre-extract the key from a separate application.  This code can be used until WinRT provides a robust set of Certificate classes.

Hope this helps!

public CryptographicKey GetCryptographicPublicKeyFromCert(string strCert)
{
    int length;
    CryptographicKey CryptKey = null;
    byte[] bCert = Convert.FromBase64String(strCert);

    // Assume Cert contains RSA public key
    // Find matching OID in the certificate and return public key
    byte[] rsaOID = EncodeOID("1.2.840.113549.1.1.1");
    int index = FindX509PubKeyIndex(bCert, rsaOID, out length);

    // Found X509PublicKey in certificate so copy it.
    if (index > -1)
    {
        byte[] X509PublicKey = new byte[length];
        Array.Copy(bCert, index, X509PublicKey, 0, length);

        AsymmetricKeyAlgorithmProvider AlgProvider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
        CryptKey = AlgProvider.ImportPublicKey(CryptographicBuffer.CreateFromByteArray(X509PublicKey));
    }

    return CryptKey;
}

static int FindX509PubKeyIndex(byte[] Reference, byte[] value, out int length)
{
    int index = -1;
    bool found;
    length = 0;

    for (int n = 0; n < Reference.Length; n++)
    {
        if ((Reference[n] == value[0]) && (n + value.Length < Reference.Length))
        {
            index = n;
            found = true;

            for (int m = 1; m < value.Length; m++) {

                if (Reference[n+m] != value[m]) {
                    found = false;
                    break;
                }
            }

            if (found) break;
            else index = -1;
        }
    }           

    if (index > -1)
    {
        // Find outer Sequence
        while (index > 0 && Reference[index] != 0x30) index--;
        index--;
        while (index > 0 && Reference[index] != 0x30) index--;               
    }

    if (index > -1)
    {
        // Find the length of encoded Public Key
        if ((Reference[index + 1] & 0x80) == 0x80)
        {
            int numBytes = Reference[index + 1] & 0x7F;
            for (int m = 0; m < numBytes; m++)
            {
                length += (Reference[index + 2 + m] << ((numBytes - 1 - m) * 8));
            }

            length += 4;
        }
        else
        {
            length = Reference[index + 1] + 2;
        }
    }

    return index;
}

static public byte[] EncodeOID(string szOID)
{
    int[] OIDNums;
    byte[] pbEncodedTemp = new byte[64];
    byte[] pbEncoded = null;
    int n, index, num, count;

    OIDNums = ParseOID(szOID);
    pbEncodedTemp[0] = 6;
    pbEncodedTemp[2] = Convert.ToByte(OIDNums[0] * 40 + OIDNums[1]);

    count = 1;

    for (n = 2, index = 3; n < OIDNums.Length; n++)
    {
        num = OIDNums[n];

        if (num >= 16384)
        {
            pbEncodedTemp[index++] = Convert.ToByte(num / 16384 | 0x80);
            num = num % 16384;
            count++;
        }

        if (num >= 128)
        {
            pbEncodedTemp[index++] = Convert.ToByte(num / 128 | 0x80);
            num = num % 128;
            count++;
        } 

        pbEncodedTemp[index++] = Convert.ToByte(num);
        count++;
    }

    pbEncodedTemp[1] = Convert.ToByte(count);
    pbEncoded = new byte[count + 2];
    Array.Copy(pbEncodedTemp, 0, pbEncoded, 0, count + 2);

    return pbEncoded;
}

static public int[] ParseOID(string szOID)
{
    int nlast, n = 0;
    bool fFinished = false;
    int count = 0;
    int[] dwNums = null;

    do
    {
        nlast = n;
        n = szOID.IndexOf(".", nlast);
        if (n == -1) fFinished = true;
        count++;
        n++;
    } while (fFinished == false);

    dwNums = new int[count];
    count = 0;
    fFinished = false;

    do
    {
        nlast = n;
        n = szOID.IndexOf(".", nlast);
        if (n != -1)
        {
            dwNums[count] = Convert.ToInt32(szOID.Substring(nlast, n - nlast), 10);
        }
        else
        {
            fFinished = true;
            dwNums[count] = Convert.ToInt32(szOID.Substring(nlast, szOID.Length - nlast), 10);
        }

        n++;
        count++;
    } while (fFinished == false);

    return dwNums;
}

Getaddrinfo() returning 127.0.0.1 for the local machine

$
0
0

Hello everyone,

Getaddrinfo()
is an API that returns IP addresses for a passed in hostname. If the host has
multiple entries the results are returned in a linked list of addresses. The
hostname can either be the local machine name or a remote machine name.

A customer noticed that on one particular machine, after
installing MS12-032,
requests to look up the local machine name would return the loopback address,
127.0.0.1, and not the public IP address.

The customer’s code looked something like this:

struct addrinfo
*addrInfo,*ai,hints;

       struct sockaddr_in *sockaddr_ipv4;

       char szIP4[30];

memset(&hints, 0, sizeof(hints));

hints.ai_socktype = SOCK_STREAM;

hints.ai_family = AF_INET;

       addrInfo = NULL;

 

getaddrinfo( "computername", "0", &hints, &addrInfo );

 

ai = addrInfo;

 

while(ai != NULL)

       {      
            

              sockaddr_ipv4 = (struct sockaddr_in *) ai->ai_addr;

              sprintf(szIP4, "%s",
inet_ntoa(sockaddr_ipv4->sin_addr) );

              ai = ai->ai_next;

}

      

       printf("Address:
%s\n", szIP4);

 

One thing this code does is that it ends up using the last
IP address returned. Getaddrinfo() can return multiple entries and there is no
guarantee what order they will be returned in. Normally, there is only one IPv4
(AF_INET) address and this will work as expected, and did before the security
patch.

Two things were happening on the machine that returned the
wrong address.

1)     
This function had always returned multiple
addresses, it just so happens that the last one returned had been the one that
we wanted.

2)     
One of the IP addresses returned was the loop
back adapter address of 127.0.0.1.

After the security update, we changed the order that the IP
addresses were returned from the hosts file. The system administrator had added
2 entries to the local hosts file, the static public IP, and the loop back
address.

                192.168.15.8
      computername

                127.0.0.1              computername

Normally there is no reason to add 127.0.0.1 to the hosts
file. “Loopback” is usually what you want to resolve to 127.0.0.1, not the
actual computername, and it does this without an explicit entry in the hosts
file. The easiest way to work around this problem is to remove the 127.0.0.1
entry from the hosts file.

How to launch a process interactively from a Windows Service?

$
0
0

Launching an interactive process from a service used to be straight forward.  You could either configure your service to be interactive or you could specify “Winsta0\\Default” as the desktop (in CreateProcess API) and as long as the launched process had the appropriate permissions to the desktop, the launched process would run interactively.

These techniques stopped working with the introduction of Windows VISTA and continues today on Windows 8.  Beginning with Windows VISTA, Windows Services were isolated in their own session.  (Session 0).  This meant if you launched a process from a Windows Service, the process was going to run in session 0 and processes running in session 0 are not interactive.

The session the launched process would run in was determined by the user’s token.  If you set a different session ID in the token, the process would launch in that session.  You’ll notice that you won’t be able to use CreateProcess() any more since it is going to launch in the same session as the service.  Since you need to specify a token, you’ll need to call CreateProcessAsUser().  The other issue you need to address in order to launch a process interactively is that the process needs FULL permissions to the interactive desktop which is “Winsta0\\Default”.  There is a lot of old sample code (http://support.microsoft.com/kb/165194 - I actually wrote this article) out there that demonstrates how to modify the security permissions to grant a user access to the Interactive desktop. Unfortunately this code will not work anymore since you can’t modify the permissions for the desktop that is located in a different session.  You can only modify the desktop in the session where your code is running in.

The recommend way to launch an interactive process is to determine the session ID of the session you are targeting and to obtain the token of the interactive user in that session.  If you know the session ID, you can call WTSQueryUserToken() to obtain the token.  You can then launch a process into this session as this user.  You do need to have the SeTcbPrivilege in order to make the call to WTSQueryUserToken() so it’s typically something only a highly privileged user should do.

If you want to launch a process as a different user (other than the interactive user running in the session), the best way to do this is to have a process running in that session call CreateProcessWithLogonW().  This is equivalent to using the runas command. 

How to create a certificate request on behalf of another user in C# on Windows 2003

$
0
0

If you're writing an application to create a certificate request, Microsoft provides the certificate enrollment controls.  On Windows XP and Windows 2003, XEnroll is the interface that's available for generating certificat requests.  Windows Vista made a clean break away from XEnroll and instead offers the more robust CertEnroll interface. 

If you need to generate a certificate requests on behalf of another user (such as a service that needs to provide certificate management), CertEnroll provides the properties and methods to do that.  An attribute called RequesterName has to be added to the request.  The value of this attribute is a domain\user value.  Also, an Enrollment Agent certificate must sign the request. 

Unfortunately, although Windows 2003 offers the ICEnroll4 interface, generating a request on behalf of another user isn't possible from .NET.  Although ICEnroll4 does provide a ICEnroll4::SignerCertificate property for setting up an enrollment agent certificate, it doesn't actually do anything. 

A C++ application can use the IEnroll4 interface and call IEnroll4::SetSignerCertificate, but that's not an automated class and can't be called from a .NET.

There is a way to get around this limitation with a .NET solution.  The key is to use ICEnroll4 and the SignedCms .NET class.  First ICEnroll4 can be used to generate the certificate request with the RequesterName attribute.  The second step is to use SignedCms to strip out the inner content (an inner CMC request with the RequesterName attriubte) and then resign the request with the enrollment agent certificate.  This in effect, creates a valid CMC certificate request on behalf of another user.

Below is example code that does this: 

class Program
{
    private const string ProviderName = "Microsoft Enhanced Cryptographic Provider v1.0";
    private const int PROV_RSA_FULL = 1;
    private const int XECR_CMC = 3;
    private const string TemplateName = "user";
    private const int AT_KEYEXCHANGE = 0x1;
    private const int CRYPT_EXPORTABLE = 1;

    static void Main(string[] args)
    {
        X509Store Store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
        ICEnroll4 certEnroll = new CEnroll2Class();

        Store.Open(OpenFlags.ReadOnly);
        X509Certificate2 EnrollCert = null;

        foreach (X509Certificate2 ECert in Store.Certificates)
        {
            foreach (X509Extension Ext in ECert.Extensions)
            {
                // Find Enhanced Key Usage Extension
                if (Ext.Oid.Value == "2.5.29.37")
                {
                    X509EnhancedKeyUsageExtension EnhExt = (X509EnhancedKeyUsageExtension)Ext;

                    for (int n = 0; n < EnhExt.EnhancedKeyUsages.Count; n++)
                    {
                        // We found an enrollment agent certificate
                        if (EnhExt.EnhancedKeyUsages[n].Value == "1.3.6.1.4.1.311.20.2.1")
                        {
                            EnrollCert = ECert;
                        }
                    }
                }
            }
        }

        certEnroll.ProviderName = ProviderName;
        certEnroll.addCertTypeToRequest(TemplateName);
        certEnroll.ProviderType = PROV_RSA_FULL;
        certEnroll.KeySpec = AT_KEYEXCHANGE;
        certEnroll.GenKeyFlags = CRYPT_EXPORTABLE;
        certEnroll.EnableSMIMECapabilities = 1;

        // Add RequesterName attribute
        certEnroll.addNameValuePairToSignature("RequesterName", "MyDomain\\TestUser");

        // Generate the request
        string certRequest = certEnroll.createRequest(XECR_CMC, "", "");

        // strip out header and footer
        certRequest = certRequest.Remove(0, "-----BEGIN NEW CERTIFICATE REQUEST-----\r\n".Length);
        certRequest = certRequest.Remove(certRequest.IndexOf("-----END NEW CERTIFICATE REQUEST-----"), "-----END NEW CERTIFICATE REQUEST-----".Length);

        if (EnrollCert != null)
        {
            // Get inner context of the request
            SignedCms decoder = new SignedCms();
            decoder.Decode(Convert.FromBase64String(certRequest));
            byte[] content = decoder.ContentInfo.Content;

            // Sign the inner content with an enrollment agent certificate
            Oid CMCDataOid = new Oid("1.3.6.1.5.5.7.12.2");
            ContentInfo ci = new ContentInfo(CMCDataOid, content);

            CmsSigner Signer = new CmsSigner();
            Signer.Certificate = EnrollCert;
            SignedCms SCms = new SignedCms(ci, false);

            SCms.ComputeSignature(Signer);
            string EncodedRequest = Convert.ToBase64String(SCms.Encode());
            Console.WriteLine(EncodedRequest);
        }
    }
}

Roll-up update KB 2775511. Report of data truncation when utilized with SMB 2.0 connections for multiple data read and writes to network share

$
0
0


Hi,

 

Writing today to provide a support update to the community on an issue that we are seeing in developer support on an optional Windows update. Specifically, we have a report were data is being truncated from an application utilizing network shares from a client Windows 7 that making requests for data storage to a Windows Vista, Windows 7, Windows Server 2008/2008 R2, or Windows 2012 machine.

 

The report is that data truncation issue occurs only after installation of optional update under KB 2775511 on Windows 7 SP1 client machines. To date, this is the report that we have on the issue. We are working closely with the reporting customer to resolve the report with progress being provided by the customer here:

     http://support.esri.com/en/knowledgebase/techarticles/detail/41119

 

In addition, we have reports that the following additional two updates can cause the data truncation issue under the same scenario:

    http://support.microsoft.com/kb/2732673

    http://support.microsoft.com/kb/2824408

 

The specific component has been identified to be in the RDBSS.SYS component. The updated RDBSS.SYS component has to be on the client machine only for the issue reported. In addition, the remote machine has to be able to support SMB 2.0 communication in order for the issue to surface.

For more background on these Microsoft updates, the above updates are released as hotfix releases to address specific issues. The KB 2775511 update is an cumulative hotfix update that is exclusively available via the http://catalog.update.microsoft.com site. By being available only through the windows update catalog, the KB 2775511 update is not considered a security update and is not being deployed broadly.  

 

In terms of workarounds, the following options are potential options while further investigation continues between Microsoft and the reporting customer:

 

  •  Not installing the KB 2775511 update and updates since release of the KB 2775511 update that has a newer RDBSS.sys component (KB 2732673, KB 2824408)
  •  Hosting the remote data on a machine running a lower version of SMB such as Windows 2003
  •  Disabling SMB 2.0 on the remote machine hosting the data being truncated.   Please note this is not recommended unless absolutely necessary as detailed in the following article by Microsoft on disabling SMB 2.0:

             http://support.microsoft.com/kb/2696547

 

 

As more information is available, this blog post will be updated.

 

 

 


Hotfix for GARP packets in Windows 7 and Server 2008 R2

$
0
0

Jeff here again.

In a previous blog post we covered GARPs, or Gratuitous
ARPs
. These are ARP packets that are broadcast by a client machine and
entered in to other ARP caches (IP to MAC address mapping) so they instantly
know where IP addresses are on the network. Windows XP and 2003 sent these
packets, but Vista/2008 and Windows 7/2008 R2 did not, Windows 8/2012 also send
these packets.

In order to make the versions of Windows more consistent, a
hotfix has been released that allows Windows 7 / 2008 R2 to also send these
Gratuitous ARP packets when an IP addresses is added to a NIC.

Please see this KB article for more information: Router does not update its
ARP table after an IP address fails over to a cluster node in Windows Server
2008 R2

You might get a high CPU usage while decrypting using RSA keys

$
0
0

 

You might get a high CPU usage while decrypting using RSA keys

 

 

The root cause of this issue (high CPU usage while decrypting using RSA keys) is as stated in the MSDN link http://msdn.microsoft.com/en-us/magazine/cc163676.aspx. The name of the article is Encrypting without Secrets” by Keith Brown.

 

The points to look at this article are (the below text is directly copied from the above link and is the writing of the Keith Brown the author of the article “Encrypting without Secrets”):

 

Key Size

The size of the key you generate impacts the level of security and inversely, the performance you'll get from the cryptosystem. Also, the longer the key you choose, the longer it'll take to generate in Key Manager. In a Virtual PC environment running on a reasonably fast machine, a 4096-bit key takes several seconds to generate, while a 16384-bit key takes several minutes! At the moment, Key Manager creates these keys on the user interface thread, which was expedient for a sample app, but an obvious improvement would be to generate the key asynchronously so the UI doesn't freeze up. Regardless of how long it takes to create the key pair, what you should care about is the security and performance trade-off at run time, so I ran some tests to time encryption and decryption using the five key sizes that Key Manager supports (see Figure 3).

Figure 3 Key Size and Runtime Performance 

Pay attention to the units in Figure 3. Encryption is measured in milliseconds, but decryption is measured in seconds. Private key operations are not cheap in RSA. If performance is critical, you can purchase specialized hardware to offload encryption and/or decryption from the main CPU, dramatically increasing performance without sacrificing security. This will require an alternate CSP, which will require a bit of tweaking of my code, but that's a small price to pay for the performance benefit you'll see. From a security perspective, current recommendations are to stick with RSA keys that are at least 2048 bits long as an absolute minimum; 4096 bits seems to be the sweet spot in the performance/security curve today. And in the future, you can go even higher. As you can see from Figure 3, my own tests include keys up to 16384 bits long.

Please take a look at the above two graphs. To generate a key pair for decryption it takes up to seconds of time compared to generating the key pairs for encryption. This is exactly what is happening in this situation.

The second point to note in this article is:

Decryptor.Decrypt unwinds the data structure by first peeling off the key container name and constructing an RSACryptoServiceProvider instance bound to that key container. It then decodes the base64-encoded payload and peels off the encrypted AES key, decrypting it using RSACryptoServiceProvider.Decrypt. That step is likely the most CPU-intensive part of the entire process if you're encrypting relatively small strings.

 

Considering all these the remedy is to reduce the RSA key length, if the string to encrypt and decrypt is relatively small in the application.

To do this you could use RSACryptoServiceProvider class constructor to set the key length as shown below.

RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider(384);

Also note that the RSACryptoServiceProvider supports key lengths from 384 bits to 16384 bits in increments of 8 bits if you have the Microsoft Enhanced Cryptographic Provider installed. It supports key lengths from 384 bits to 512 bits in increments of 8 bits if you have the Microsoft Base Cryptographic Provider installed.

We might consider reducing the key length to as small as possible in order to reduce the key pair generation time.

The second workaround is to use named key containers and use that key container every time when you are encrypting and decrypting data.

References:

http://msdn.microsoft.com/en-us/library/zseyf239.aspx

http://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider.keysize.aspx

-Shamik

Screen capture using Windows Media Encoder

$
0
0

If you have to screen capture using Windows Media Encoder please follow the steps below.

Start Windows Media Encoder (WM Encoder).

To download WM encoder please refers to the link http://www.microsoft.com/downloads/details.aspx?FamilyID=5691ba02-e496-465a-bba9-b2f1182cdf24&displaylang=en.

The file is “WMEncoder.exe” which is of size 9.45 MB approximately. Install it and you get Windows Media under Start-> All Programs.

 

 To capture the screen here are the steps.

 

1.  Start Windows Media Encoder.

2.  Select “Capture screen” from the “New Session” dialog.

 

 

3.  Click at OK.

4.  Specify what you would like to capture. You could capture a specific window, or a particular region of the screen or the entire screen.

  

5.  Click at “Next” and specify a file name where you would like to save the media.

 

6.  Select the compression factor to either low or medium or high.

7.  Click at next. You could also set the display information.

 

8.  Finally click “Finish”. It will give you the option to start encoding immediately or you could start it later from the menu.

 

In a typical example with compression factor set to high we see the following statistics:

 

The codec used is “Windows Media Video 9 Screen”.

The Windows Media Video 9 Screen codec is optimized for compressing sequential screenshots and highly static video that is captured from the computer display, which makes it ideal for delivering demos or demonstrating computer use for training. The codec takes advantage of the typical image simplicity and relative lack of motion to achieve a very high compression ratio.

This codec is available from Windows Media Player 6.4 or later and so it obviously available from Windows XP.

For more reading please refer to the link http://www.microsoft.com/windows/windowsmedia/forpros/codecs/video.aspx.

 

Let us look into some code. To set up you need to have Windows Media Encoder 9 Series SDK. Download it from the link http://www.microsoft.com/downloads/details.aspx?familyid=000A16F5-D62B-4303-BB22-F0C0861BE25B&displaylang=en.

 

Install it and you would get it added to your Start-> All Programs menu.

 

 

 

You also get the “Windows Media Encoder SDK” help file.

Please see the topic “Using a Screen Capture as a Source” from the help menu. It has the managed as well as the unmanaged reference.

Here is some unmanaged reference code that you could start with.

// ScreenCapture.cpp : Defines the entry point for the console application.

//

 

#include"stdafx.h"

 

// Include libraries.

#include<windows.h>

#include<atlbase.h>

#include<comdef.h>

#include"C:\WMSDK\WMEncSDK9\include\wmencode.h"

 

// Define the screen capture properties.

#define WMSCRNCAP_CAPTUREWINDOW     CComBSTR("CaptureWindow")

#define WMSCRNCAP_WINDOWLEFT        CComBSTR("Left")

#define WMSCRNCAP_WINDOWTOP         CComBSTR("Top")

#define WMSCRNCAP_WINDOWRIGHT       CComBSTR("Right")

#define WMSCRNCAP_WINDOWBOTTOM      CComBSTR("Bottom")

#define WMSCRNCAP_FLASHRECT         CComBSTR("FlashRect")

#define WMSCRNCAP_ENTIRESCREEN      CComBSTR("Screen")

#define WMSCRNCAP_WINDOWTITLE       CComBSTR("WindowTitle")

 

 

int _tmain(int argc, _TCHAR* argv[])

{

    // Declare variables.

    HRESULT hr = S_OK;

    IWMEncoder* pEncoder;

    IWMEncSourceGroupCollection* pSrcGrpColl;

    IWMEncSourceGroup* pSrcGrp;

    IWMEncSource* pSrc;

    IWMEncVideoSource2* pSrcVid;

    IPropertyBag* pPropertyBag;

    CComVariant varValue;

 

    // Initialize the COM library and retrieve a pointer to an IWMEncoder interface.

    hr = CoInitialize(NULL);

    if ( SUCCEEDED( hr ) )

    {

        hr = CoCreateInstance(CLSID_WMEncoder,

            NULL,

            CLSCTX_INPROC_SERVER,

            IID_IWMEncoder,

            (void**) &pEncoder);

    }

 

    // Retrieve the source group collection.

    if ( SUCCEEDED( hr ) )

    {

        hr = pEncoder->get_SourceGroupCollection(&pSrcGrpColl);

    }

 

    // Add a source group to the collection.

    if ( SUCCEEDED( hr ) )

    {

        hr = pSrcGrpColl->Add(CComBSTR("SG_1"), &pSrcGrp);

    }

    if ( SUCCEEDED( hr ) )

    {

        hr = pSrcGrp->AddSource(WMENC_VIDEO, &pSrc);

    }

 

    // Retrieve an IWMEncVideoSource2 pointer.

    if ( SUCCEEDED( hr ) )

    {

        hr = pSrc->QueryInterface(IID_IWMEncVideoSource2, (void**)&pSrcVid);

    }

 

    // Add a video source to the source group.

    if ( SUCCEEDED( hr ) )

    {

        hr = pSrcVid->SetInput(CComBSTR("ScreenCap://ScreenCapture1"));

    }

 

    // Retrieve a pointer to the property bag.

    if ( SUCCEEDED( hr ) )

    {

        hr = pSrcVid->QueryInterface(IID_IPropertyBag, (void**)&pPropertyBag);

    }

 

    // Set full screen capture.

    {

        varValue = true;

        if ( SUCCEEDED( hr ) )

        {

            hr = pPropertyBag->Write( WMSCRNCAP_ENTIRESCREEN, &varValue );

        }

    }

 

    // Set the capture area.

    {

        // nLeft, nRight, nTop, and nBottom are the dimensions to capture

        int nLeft, nRight, nTop, nBottom;

 

        nLeft = nTop = 0;

 

         // Get screen size

         nRight = GetSystemMetrics(SM_CXSCREEN);

         nBottom = GetSystemMetrics(SM_CYSCREEN);

 

        // Initialize the capture area. The size must be even.

        varValue = false;

        if ( SUCCEEDED( hr ) )

        {

            hr = pPropertyBag->Write( WMSCRNCAP_ENTIRESCREEN, &varValue );

        }

 

        varValue = nLeft;

        if ( SUCCEEDED( hr ) )

        {

            hr = pPropertyBag->Write( WMSCRNCAP_WINDOWLEFT, &varValue );

        }

 

        varValue = nRight;

        if ( SUCCEEDED( hr ) )

        {

            hr = pPropertyBag->Write( WMSCRNCAP_WINDOWRIGHT, &varValue );

        }

 

        varValue = nTop;

        if ( SUCCEEDED( hr ) )

        {

            hr = pPropertyBag->Write( WMSCRNCAP_WINDOWTOP, &varValue );

        }

 

        varValue = nBottom;

        if ( SUCCEEDED( hr ) )

        {

            hr = pPropertyBag->Write( WMSCRNCAP_WINDOWBOTTOM, &varValue );

        }

 

        varValue = true;

        if ( SUCCEEDED( hr ) )

        {

            hr = pPropertyBag->Write( WMSCRNCAP_FLASHRECT, &varValue );

        }

 

        // Continue configuring the encoding session.

 

        // Release pointers.

        if ( pSrcGrpColl )

        {

            pSrcGrpColl->Release();

            pSrcGrpColl = NULL;

        }

        if ( pSrcGrp )

        {

            pSrcGrp->Release();

            pSrcGrp = NULL;

        }

        if ( pSrcVid )

        {

            pSrcVid->Release();

            pSrcVid = NULL;

        }

        if ( pSrc )

        {

            pSrc->Release();

            pSrc = NULL;

        }

        if ( pPropertyBag )

        {

            pPropertyBag->Release();

            pPropertyBag = NULL;

        }

        if ( pEncoder )

        {

            pEncoder->Release();

            pEncoder = NULL;

        }

    }

 

    return 0;

}

 

-Shamik

How to use ADSI/LDAP API’s for querying active directory using credentials derived from a Smart Card

$
0
0

There are no ADSI/LDAP API’s that eventually could directly use the Smart Card Credentials.

We could follow the steps below:

1.  Get the user credentials by reading in the certificate from the Smart card.

2.  Call LogonUser() to get the user’s token.

3.  Use this token to impersonate the user.

4.  Under the impersonated user’s context, perform the ADSI/LDAP operations which will eventually run under the impersonated user.

 

In short after you have impersonated a user, the calling thread runs under the security context of this user and you need not have to pass any further credentials to the ADSI/LDAP API’s.

Please note: Calling LogonUser with marshaled certificate credentials requires that the smart card certificate be located in the personal certificate store otherwise LogonUser would fail with error 1312 (ERROR_NO_SUCH_LOGON_SESSION).

Example:

#include"stdafx.h"

#include<Iads.h>

#include<Adshlp.h>

 

#define MAX_CERT_SIMPLE_NAME_STR 1000

 

int SmartCardLogon (TCHAR * pPIN);

 

 

int _tmain(int argc, _TCHAR* argv[])

{

    if (argc != 2)

    {

        _tprintf(_T ("\nUSAGE: %ls PIN \n"), argv[0]);

        _tprintf(_T ("Example: \"%ls 1234 \"\n\n"), argv[0]);

 

        return 1;

    }

 

    SmartCardLogon(argv[1]);

 

    return 0;

}

 

int SmartCardLogon (TCHAR * pPIN)

{

    HANDLE     hToken;

    HCRYPTPROV hProv;

    HCRYPTKEY  hKey;

    HCERTSTORE hStoreHandle = NULL;

    HCRYPTHASH hHash;

 

    BOOL fStatus;

    BOOL fSave = FALSE;

    BOOL bStatus;

 

    SCARDCONTEXT     hSC;

    OPENCARDNAME_EX  dlgStruct;

    CERT_CREDENTIAL_INFO certInfo;

 

    WCHAR szReader[256];

    WCHAR szCard[256];

    WCHAR pProviderName[256];

 

    LONG             lReturn;

 

    DWORD lStatus;

    DWORD cchProvider       = 256;

    DWORD dwCertLen;

    DWORD dwLogonCertsCount = 0;

    DWORD dwHashLen         = CERT_HASH_LENGTH;

 

    BYTE* pCertBlob;

    PCCERT_CONTEXT pCertContext = NULL;

 

    LPTSTR  szMarshaledCred = NULL;

 

    // Establish a context.

    // It will be assigned to the structure's hSCardContext field.

    lReturn = SCardEstablishContext(

        SCARD_SCOPE_USER,

        NULL,

        NULL,

        &hSC );

 

    if ( SCARD_S_SUCCESS != lReturn )

    {

        _tprintf(_T("Failed SCardEstablishContext\n"));

        return 1;

    }

 

    // Initialize the structure.

    memset(&dlgStruct, 0, sizeof(dlgStruct));

    dlgStruct.dwStructSize = sizeof(dlgStruct);

    dlgStruct.hSCardContext = hSC;

    dlgStruct.dwFlags = SC_DLG_FORCE_UI;

    dlgStruct.lpstrRdr = szReader;

    dlgStruct.nMaxRdr = 256;

    dlgStruct.lpstrCard = szCard;

    dlgStruct.nMaxCard = 256;

    dlgStruct.lpstrTitle = L"My Select Card Title";

 

 

    // Display the select card dialog box.

    lReturn = SCardUIDlgSelectCard(&dlgStruct);

 

    if ( SCARD_S_SUCCESS != lReturn )

    {

        _tprintf(_T("Failed SCardUIDlgSelectCard - %x\n"), lReturn);

    }

    else

    {

        _tprintf(_T("Reader: %S\nCard: %S\n"), szReader, szCard);

    }

 

    lStatus = SCardGetCardTypeProviderName(

        dlgStruct.hSCardContext, // SCARDCONTEXT hContext,

        dlgStruct.lpstrCard,     // LPCTSTR szCardName,

        SCARD_PROVIDER_CSP,      // DWORD dwProviderId,

        pProviderName,           // LPTSTR szProvider,

        &cchProvider             // LPDWORD* pcchProvider

        );

 

    _tprintf(_T("SCardGetCardTypeProviderName returned: %u (a value of 0 is success)\n"), lStatus);

 

    if ( SCARD_S_SUCCESS != lReturn )

    {

        _tprintf(_T("Failed SCardGetCardTypeProviderName - %u\n"), lStatus );

    }

    else

    {

        _tprintf(_T("Provider name: %ls.\n"), pProviderName);

    }

 

    fStatus = CryptAcquireContext(

        &hProv,                  // HCRYPTPROV* phProv,

        NULL,                    // LPCTSTR pszContainer,

        pProviderName,           // LPCTSTR pszProvider,

        PROV_RSA_FULL,           // DWORD dwProvType,

        0                        // DWORD dwFlags

        );

 

    if (!fStatus)

    {

        _tprintf(_T("CryptAcquireContext failed: 0x%x\n"), GetLastError());

        return 1;

    }

    else

    {

        _tprintf(_T("CryptAcquireContext succeeded.\n"));

    }

 

    fStatus = CryptGetUserKey(

        hProv,                 // HCRYPTPROV hProv,

        AT_KEYEXCHANGE,        // DWORD dwKeySpec,

        &hKey                  // HCRYPTKEY* phUserKey

        );

 

    if (!fStatus)

    {

        _tprintf(_T("CryptGetUserKey failed: 0x%x\n"), GetLastError());

        return 1;

    }

    else

    {

        _tprintf(_T("CryptGetUserKey succeeded.\n"));

    }

 

    dwCertLen = 0;

    fStatus = CryptGetKeyParam(

        hKey,                  // HCRYPTKEY hKey,

        KP_CERTIFICATE,        // DWORD dwParam,

        NULL,                  // BYTE* pbData,

        &dwCertLen,            // DWORD* pdwDataLen,

        0                      // DWORD dwFlags

        );

 

    if (!fStatus)

    {

        _tprintf(_T("CryptGetUserKey failed: 0x%x\n"), GetLastError());

        return 1;

    }

    else

    {

        _tprintf(_T("CryptGetUserKey succeeded.\n"));

    }

 

    _tprintf(_T("dwCertLen: %u\n"), dwCertLen);

 

    pCertBlob = (BYTE*) malloc(dwCertLen);

 

    fStatus = CryptGetKeyParam(

        hKey,                  // HCRYPTKEY hKey,

        KP_CERTIFICATE,        // DWORD dwParam,

        pCertBlob,             // BYTE* pbData,

        &dwCertLen,            // DWORD* pdwDataLen,

        0                      // DWORD dwFlags

        );

 

    if (!fStatus)

    {

        _tprintf(_T("CryptGetUserKey failed: 0x%x\n"), GetLastError());

        return 1;

    }

    else

    {

        _tprintf(_T("CryptGetUserKey succeeded.\n"));

    }

 

    pCertContext = CertCreateCertificateContext(

        PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,

        pCertBlob,

        dwCertLen);

 

 

    if(pCertContext)

    {

        // print some info

        TCHAR Issuer[MAX_CERT_SIMPLE_NAME_STR + 1];

        TCHAR Subject[MAX_CERT_SIMPLE_NAME_STR + 1];

        CertNameToStr(X509_ASN_ENCODING,

            &pCertContext->pCertInfo->Subject,

            CERT_SIMPLE_NAME_STR,

            Subject,

            MAX_CERT_SIMPLE_NAME_STR);

 

        CertNameToStr(X509_ASN_ENCODING,

            &pCertContext->pCertInfo->Issuer,

            CERT_SIMPLE_NAME_STR,

            Issuer,

            MAX_CERT_SIMPLE_NAME_STR);

 

        _tprintf(_T("Subject:%s\n"), Subject);

        _tprintf(_T("Issuer:%s\n"), Issuer);

 

        ZeroMemory(&certInfo, sizeof(certInfo));

        certInfo.cbSize = sizeof(certInfo);

 

        // compute the SHA-1 hash of the certificate

        bStatus = CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);

 

        if (bStatus)

        {

            bStatus = CryptCreateHash(hProv, CALG_SHA1, NULL, 0, &hHash);

            if (bStatus)

            {

                bStatus = CryptHashData(hHash, pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, 0);

                if (bStatus)

                {

                    bStatus = CryptGetHashParam(hHash, HP_HASHVAL, certInfo.rgbHashOfCert, &dwHashLen, 0);

                }

                CryptDestroyHash(hHash);

            }

            CryptReleaseContext(hProv, 0);

        }

 

        if (bStatus)

        {

            bStatus = CredMarshalCredential(CertCredential, &certInfo, &szMarshaledCred);

            if (bStatus)

            {

                //make sure your account has enough privilage to execute LogonUser

                bStatus = LogonUser(szMarshaledCred,

                    NULL,

                    pPIN,

                    LOGON32_LOGON_NETWORK,

                    LOGON32_PROVIDER_DEFAULT,

                    &hToken);

 

                if (bStatus)

                {

                    _tprintf(_T("LogonUser success - test passed\n"));

 

                    //

                    // impersonate the user we just got a token for

                    //

                    if (ImpersonateLoggedOnUser(hToken))

                    {

                        TCHAR szName[255];

                        DWORD cbName=255;

 

                        //

                        // indicate who we logged on, to verify success

                        //

                        GetUserName(szName, &cbName);

                        _tprintf(_T("Successfully logged on user = %s\n"), szName);

 

                        // AD specific calls

                        HRESULT hr;

                        IADsUser *padsRoot1;

 

                        hr = CoInitialize(NULL);

 

                        //Adding code for the AdSystemInfo to check the current user from thread

                        IADsADSystemInfo *pSys;

 

                        hr = CoCreateInstance(CLSID_ADSystemInfo,

                            NULL,

                            CLSCTX_INPROC_SERVER,

                            IID_IADsADSystemInfo,

                            (void**)&pSys);

 

                        BSTR bstr;

                        hr = pSys->get_UserName(&bstr);

                        if (SUCCEEDED(hr)) {

                            _tprintf(_T("User: %S\n"), bstr);

                            SysFreeString(bstr);

                        }

 

                        //Finished AdSystemInfo

 

                        hr = ADsOpenObject(

                            L"LDAP://DC=FAREAST,DC=CORP,DC=MICROSOFT,DC=COM",

                            NULL,

                            NULL,

                            ADS_SECURE_AUTHENTICATION,

                            IID_IADs,

                            (LPVOID*)&padsRoot1

                            );

 

                        CoUninitialize();

                        // End

 

                        RevertToSelf();

                    }

 

                    CloseHandle(hToken);

                }

                else

                {

                    _tprintf(_T("LogonUser failed with error %d\n"), GetLastError());

                }

                CredFree(szMarshaledCred);

            }

            else

            {

                _tprintf(_T("CredMarshalCredential failed with error 0x%.8X\n"), GetLastError());

            }

        }

        else

        {

            _tprintf(_T("Failed to compute logon certificate hash\n"));

        }

 

        CertFreeCertificateContext(pCertContext);

    }

 

    return 0;

}

 

References:

http://msdn.microsoft.com/en-us/library/aa379479(VS.85).aspx

http://msdn.microsoft.com/en-us/library/aa376033(VS.85).aspx

http://msdn.microsoft.com/en-us/library/aa379886(VS.85).aspx

http://msdn.microsoft.com/en-us/library/aa378184(VS.85).aspx

http://msdn.microsoft.com/en-us/library/aa378612(v=VS.85).aspx

http://msdn.microsoft.com/en-us/library/aa746340(VS.85).aspx

http://msdn.microsoft.com/en-us/library/aa772238(VS.85).aspx

-Shamik

How to make your custom RNG (random number generator) implementation the default RNG provider for the system using CNG API's

$
0
0

 

If you have implemented your random number generator make sure that you register it using BCryptRegisterProvider function. Add the algorithm name to the list of symmetric cipher algorithm class using BCryptAddContextFunction.

 

Example:

 

BCryptAddContextFunction(

                        CRYPT_LOCAL,              // Scope: local machine only

                        NULL,                     // Application context: default

                        BCRYPT_RNG_INTERFACE,     // Algorithm class

                        BCRYPT_RNG_ALGORITHM,     // Algorithm name

                        CRYPT_PRIORITY_TOP

                       );

 

 

To use the CNG API's to make your custom RNG provider the default system RNG provider call:

 

BCryptOpenAlgorithmProvider(&hRandomAlg, BCRYPT_RNG_ALGORITHM, NULL, 0); 

 

This would select your own RNG implementation.

For post Vista OS’s, you don’t need the algorithm name for RNG algorithm when calling BCryptGenRandom.  By setting your implementation to the top, the BCryptGenRandom function will automatically handle opening and closing RNG algorithm handles for you if you call BCryptGenRandom with a NULL algorithm handle and set the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag.

Reference:

http://msdn.microsoft.com/en-us/library/aa375458(VS.85).aspx

-Shamik

Viewing all 126 articles
Browse latest View live


Latest Images

<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>