Passing Authenticated Messages

 

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

To pass authenticated messages between a Message Queuing system and a foreign messaging system, the connector application (both transparent and nontransparent connector applications) must retrieve all the properties needed for authentication. This includes the property that contains the MSMQ 1.0 signature of the sender, the sender's public key, the cryptographic provider needed to verify the signature, the hash algorithm used to create the signature, and all the message properties used in the MSMQ 1.0 signature.

Note

You cannot use MSMQ 2.0 signatures when passing authenticated messages between Message Queuing and foreign messaging systems.

Authentication Properties

The properties used to authenticate messages are:

Property Description
PROPID_M_SIGNATURE Contains signature.
PROPID_M_SENDER_CERT Contains public key of sender.
PROPID_M_PROV_NAME Name of cryptographic provider needed to verify signature.
PROPID_M_PROV_TYPE Type of cryptographic provider needed to verify signature.
PROPID_M_HASH_ALG Hash algorithm used to create signature.

Creating the MSMQ 1.0 Signature

The properties used to create the MSMQ 1.0 signature include:

PROPID_M_CORRELATIONID

PROPID_M_APPSPECIFIC

PROPID_M_BODY

PROPID_M_LABEL

PROPID_M_RESP_QUEUE

PROPID_M_ADMIN_QUEUE

Transparent connector applications must perform different operations depending on the direction of the messages. If the message is going from the foreign messaging system to a Message Queuing system, the connector application needs to translate the corresponding property values and pass the new values on to the Message Queuing system.

If the messages are being sent from the Message Queuing system to the foreign messaging system, the connector application must translate the values of the security properties and pass both the translated values and the original values on to the foreign application. The original values are needed to generate the hash value used to authenticate the signature.

Non-transparent applications can perform the security operations (verify the signature) and deliver the message to the foreign messaging system without security, so there is no need to pass on security properties. However, the applications do need to indicate that the message was verified when it passes on the message.

The code needed to perform security operations varies for each application. However, the pseudo-code provided in the following sample shows the basic elements needed to authenticate a message.

When messages are being sent from a foreign messaging system to a Message Queuing system, non-transparent applications must have access to the private signing keys of all the users on the foreign side. The application must compute the message's hash value, encrypt the hash value by applying the user's private signing key, and pass the message on to the Message Queuing system.

Signature Verification Pseudo-code

The following code describes the basic elements needed to authenticate a message

  1. Retrieve cryptographic provider information needed to perform the cryptographic operation required for signature verification.

    CryptProvName = GetMessageProperty
    (Message, PROPID_M_PROV_NAME)  
    CryptProvType = GetMessageProperty
    (Message, PROPID_M_PROV_TYPE)  
    
  2. Initialize the cryptographic provider.

    CryptProvider = AcquireCrpytoraphicConext(  
                                   CryptProvName,  
                                   CryptProvType)  
    
  3. Get the hash algorithm identifier and initialize a hash object. This object is used to perform the hashing and signature-verification operations.

    HashAlogorithm = GetMessageProperty
    (Message, PROPID_M_HASH_ALG)  
    HashObject = GetHashObject
    (CryptProvider, HashAlogorithm)  
    
  4. Get the six message properties that are required for calculating the hash value for the message.

    CorrelationId = GetMessageProperty
    (Message, PROPID_M_CORRELATIONID)  
    AppSpecific = GetMessageProperty
    (Message, PROPID_M_APPSPECIFIC)  
    MessageBody = GetMessageProperty
    (Message, PROPID_M_BODY)  
    MessageLabel = GetMessageProperty
    (Message, PROPID_M_LABEL)  
    RespQueueFormat = GetMessageProperty
    (Message, PROPID_M_RESP_QUEUE)  
    AdminQueueFormat = GetMessageProperty
    (Message, PROPID_M_ADMIN_QUEUE)  
    
  5. Compute the hash value for the message by adding (in order) each message property to the hash value. The order in which the properties are added is important. Changing the calculation order of the message properties causes signature verification to fail.

    HashData
    (HashObject, CorrelationId)  
    HashData
    (HashObject, AppSpecific)  
    if NotEmpty
    (MessageBody)  
            HashData
    (HashObject, MessageBody)  
    if NotEmpty
    (MessageLabel)  
            HashData
    (HashObject, MessageLabel)  
    if NotEmpty
    (RespQueueFormat)  
            HashData
    (HashObject, RespQueueFormat)  
    if NotEmpty
    (AdminQueueFormat)  
            HashData
    (HashObject, AdminQueueFormat)  
    
  6. Get the message signature.

    Note This property can only contain MSMQ 1.0 signatures.

    MessageSignature = GetMessageProperty
    (Message, PROPID_M_SIGNATURE)  
    
  7. Get the sender's certificate.

    SenderCert = GetMessageProperty
    (Message, PROPID_M_SENDER_CERT)  
    
  8. Get the sender's public key out from the sender's certificate.

    SenderPublicKey = GetPublicKeyFromCertificate(CryptProvider,  
                      SenderCert)  
    
  9. Verify the signature of the message according to the message hash value and the sender's public key.

    VerifySignature
    (HashObject, SenderPublicKey, MessageSignature)  
    

The result of the verify signature function indicates whether the signature is valid.