Passing Authenticated Messages

To pass authenticated messages between MSMQ and another message queue system, the connector application (both transparent and non-transparent applications) must retrieve all the properties needed for authentication. This includes the property that contains the 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 signature.

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.

The properties used in the digital 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 application to MSMQ, the connector application needs to translate new property values and pass the new values on to MSMQ. If the messages are being sent from MSMQ to the other message queue system, the connector application must translate new property values and pass both these 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 perform the security operations (verify signature) 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 another message queue system to MSMQ, 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 MSMQ.

Note  For foreign message properties not supported by MSMQ, use PROPID_M_EXTENSION and PROPID_M_EXTENSION_LEN.

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