December 15th, 2017

PowerShell support for certificate credentials

Doctor Scripto
Scripter

Summary: It’s not a very well-known feature, but the PSCredential object, and the PowerShell Get-Credential cmdlet, both support certificate credentials (including PIN-protected certificates). In this post, we take a look at how a certificate credential is marshaled inside a PSCredential object, how you can do this marshaling yourself, and how you can retrieve the original certificate from a PSCredential object supplied to you.

Most Win32 APIs that support the PSCredential object for credential validation already support certificates. However, if your code currently consumes a PSCredential, and you use the user name and password without expecting a certificate credential, you can make the necessary adjustments yourself.

All the code for this walkthrough can be found here.

Get a certificate inside a PSCredential object

The PSCredential object has only two properties, ‘UserName’ and ‘Password’. To wedge a certificate into this format, you must use the CredMarshalCredential API. This API takes a credential type, and a credential struct, and it produces a string representing the credential. As of the time of this writing, the credential types that are supported are CertCredential and UsernameTargetCredential.

This means we can generate a string from a certificate credential, and then set the ‘UserName’ field of the PSCredential object to this string. If the certificate is PIN protected, the PIN can be wrapped in a SecureString, and set as the Password property on the PSCredential.

This process is exactly what the Get-Credential cmdlet does in PowerShell (on Windows). If you run Get-Credential, you will get the standard credential dialog box.

Screenshot of credential request

Select the down arrow on the right side. From the drop-down list, you can select certificates that match the User Certificate criteria. (Generally, the dialog box shows certificates in the Personal and Trusted Root stores of the current user.)

Screenshot of list of certificates

Selecting my smart card results in the following:

Screenshot of smart card credentials

 

When I’m all done, the resulting output looks like this:

UserName                                                               Password ——–                                                                      ——– @@BkvQpJ93JShl3nkv7tyCbLL#wO                    System.Security.SecureString

As you can see, the ‘UserName’ field doesn’t really look like a user name. It is, in fact, the encoded certificate data returned from CredMarshalCredential.

This marshaled credential can now be used with many standard Windows authentication APIs, including LogonUser. However, if you’re building a .NET application, and you want to support PSCredentials that use a certificate, you will have to unpack this special UserName property. (This is true unless you only ever intend to pass along the marshaled credential to supporting APIs.) Let’s see how we can do that.

Get a certificate from a PSCredential.UserName blob

If you want to locate the certificate represented by a PSCredential.UserName data blob, you can use the CredUnmarshalCredential API, which is the logical inverse of our trusty CredMarshalCredential. You can pass your UserName string, and receive the CERT_CREDENTIAL_INFO struct back, which has the SHA-1 hash of the original certificate. Your application can then do any certificate lookup you want (assuming your application or service has the correct permissions).

For full details on how to perform this call, see the ReverseMarshal function in the example code here.

Matt Bongiovi

Software engineer, Active Directory Fabric team

 

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

1 comment

Discussion is closed. Login to edit/delete existing comments.

  • Travis Cutts

    Anyway that we can get some elaboration on this point, “However, if you’re building a .NET application, and you want to support PSCredentials that use a certificate, you will have to unpack this special UserName property”? I am getting a username in the format of @@ButtermilkBiscuits4Breakfast that is not valid to create a PSCredential and do not understand how to convert this to the proper format.