Visual Basic Code Example: Requesting Authentication Using an External Certificate
Applies To: Windows 10, Windows 7, Windows 8, Windows 8.1, Windows Server 2008, Windows Server 2008 R2, Windows Server 2012, Windows Server 2012 R2, Windows Server Technical Preview, Windows Vista
This example provides a private Sub procedure that sends a single message with a request for authentication using an external certificate and requests acknowledgment messages so that the sending application can ascertain whether the message was authenticated and placed in the destination queue.
For information on how Message Queuing authenticates messages, see Message Authentication.
This example uses properties and methods of objects supplied with CAPICOM 2.0. First, it calls the Open method of the Store object to open the My store for the current user. Next, it obtains the first certificate in the My store as a Certificate object by retrieving the first item in the Certificates collection, which is a property of the Store object, and calls the Certificate.Export method to copy the contents of the certificate to a binary string. Then it calls the BinaryStringToByteArray method of the Utilities object to convert the binary string to an array of bytes. For information on downloading and installing CAPICOM 2.0, see the Platform SDK Redistributables Web Site.
This Sub procedure uses the first certificate that it finds in the My store. The example can be modified to select a specific certificate among the certificates in the My store. In that case the procedure must enumerate all the certificates in the store and choose the proper certificate for use.
This example can be run only on a computer operating in domain mode because only a domain user can register a certificate and Message Queuing does not use security identifiers (SIDs) in workgroup mode. You can modify the example for operation in workgroup mode by skipping the call to MSMQApplication.RegisterCertificate and setting the MSMQMessage.SenderIdType property of the message to MQMSG_SENDERID_TYPE_NONE so that Message Queuing will not attach the sender's SID to the message. In this case the receiving application will not be able to compare the certificate attached to the message to the registered external certificate or compare the sender's SID to the SID of the user who registered the certificate.
To request authentication using an external certificate
Declare the variables and objects needed to send a message with a request for authentication using an external certificate. This procedure declares the following CAPICOM and Message Queuing objects:
Store
Certificate
Utilities
Call Store.Open to open the My store for the current user.
Get the first certificate in the My store by retrieving the first item in the Store.Certificates collection.
Call Certificate.Export to copy the contents of the certificate to a binary string.
Call Utilities.BinaryStringToByteArray to convert the binary string to an array of bytes.
Call MSMQApplication.RegisterCertificate to register the external certificate if it is not already registered.
Note There is no need to explicitly declare and reference the MSMQApplication object to call its methods because MSMQApplication is a COM application object.
If this call generates error &HC00E002E because the external certificate is already registered, the procedure continues with the next step.
Generate a direct format name using the computer name and queue name provided by the caller.
Set the MSMQQueueInfo.FormatName property.
Call MSMQQueueInfo.Open to open the queue with send access.
Set message properties. This procedure sets the MSMQMessage.AuthLevel property to request authentication and attaches the external certificate to the message by setting the MSMQMessage.SenderCertificate property. The procedure also sets the MSMQMessage.Ack and MSMQMessage.AdminQueueInfo properties to request acknowledgment messages so that the sending application can ascertain whether the message was authenticated and placed in the destination queue.
Call MSMQMessage.Send to send a copy of the message to the destination queue referenced by the format name.
Call MSMQQueue.Close to close the queue and free resources.
Code Example
The following code example requires CAPICOM 2.0 and can be run on all versions of Message Queuing.
Private Sub RequestAuthExternal( _
ByVal strComputerName As String, _
ByVal strQueueName As String, _
ByVal strAdminPathName As String _
)
Dim st As New Store
Dim cert As Certificate
Dim sCert As String
Dim varCert As Variant
Dim utl As New Utilities
Dim strFormatName As String
Dim qinfo As New MSMQQueueInfo
Dim qDest As MSMQQueue
Dim msg As New MSMQMessage
Dim qinfoAdmin As New MSMQQueueInfo
Dim strAdminPathName As String
' Open the My store for the current user.
On Error GoTo ErrorHandler
st.Open CAPICOM_CURRENT_USER_STORE, CAPICOM_MY_STORE, CAPICOM_STORE_OPEN_READ_ONLY
' Get the first certificate in the My store.
Set cert = st.Certificates.Item(1)
' Copy the contents of the certificate to a binary string.
sCert = cert.Export(CAPICOM_ENCODE_BINARY)
' Convert the binary string to an array of bytes.
varCert = utl.BinaryStringToByteArray(sCert)
' Register the certificate.
RegisterCertificate Flags:=MQCERT_REGISTER_ALWAYS, ExternalCertificate:=varCert
CreateMessage:
' Create a direct format name.
strFormatName = "DIRECT=OS:" & strComputerName & "\" & strQueueName
' Set the FormatName property of the destination MSMQQueueInfo object.
qinfo.FormatName = strFormatName
' Open the queue.
Set qDest = qinfo.Open(MQ_SEND_ACCESS, MQ_DENY_NONE)
' Set message properties.
msg.Label = "Test Message"
msg.AuthLevel = MQMSG_AUTH_LEVEL_ALWAYS
msg.SenderCertificate = varCert
' Request acknowledgment messages.
msg.Ack = MQMSG_ACKNOWLEDGMENT_FULL_REACH_QUEUE
qinfoAdmin.PathName = strAdminPathName
qinfoAdmin.Refresh
Set msg.AdminQueueInfo = qinfoAdmin
' Send the message and close the queue.
msg.Send DestinationQueue:=qDest, Transaction:=MQ_NO_TRANSACTION
qDest.Close
Cleanup:
Set st = Nothing
Set cert = Nothing
Exit Sub
ErrorHandler:
If Err.Number = &HC00E002E Then GoTo CreateMessage:
MsgBox "Error " + Hex(Err.Number) + " was returned." _
+ Chr(13) + Err.Description
GoTo Cleanup
End Sub