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

  1. 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:

  2. Call Store.Open to open the My store for the current user.

  3. Get the first certificate in the My store by retrieving the first item in the Store.Certificates collection.

  4. Call Certificate.Export to copy the contents of the certificate to a binary string.

  5. Call Utilities.BinaryStringToByteArray to convert the binary string to an array of bytes.

  6. 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.

  7. Generate a direct format name using the computer name and queue name provided by the caller.

  8. Set the MSMQQueueInfo.FormatName property.

  9. Call MSMQQueueInfo.Open to open the queue with send access.

  10. 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.

  11. Call MSMQMessage.Send to send a copy of the message to the destination queue referenced by the format name.

  12. 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