Microsoft KB Archive/280391

= How to send digitally signed messages by using CDOSYS/CDOEX =

Article ID: 280391

Article Last Modified on 10/25/2007

-

APPLIES TO


 * Microsoft Exchange Server 2003 Enterprise Edition
 * Microsoft Exchange Server 2003 Standard Edition
 * Microsoft Exchange 2000 Server Standard Edition
 * Microsoft Windows Server 2003, Enterprise Edition
 * Microsoft Windows Server 2003, Standard Edition (32-bit x86)
 * Microsoft Windows 2000 Advanced Server
 * Microsoft Windows 2000 Server
 * Microsoft Windows 2000 Professional Edition
 * Microsoft Windows XP Professional
 * Microsoft Windows XP Home Edition
 * Collaboration Data Objects for Exchange 2000
 * Microsoft Collaboration Data Objects 2.0

-



This article was previously published under Q280391



SUMMARY
Microsoft Collaboration Data Objects for Windows 2000 (CDOSYS) and Microsoft Collaboration Data Objects for Exchange 2000 (CDOEX) do not directly provide a way to digitally sign or encrypt a message. The application programming interface (API) does not expose any functionality to generate a valid signature. However, you can use the Cryptography API in combination with CDOSYS or CDOEX to digitally sign and/or encrypt a message.



MORE INFORMATION
You can use the COM version of the Cryptography API (CAPICOM) to easily sign and/or encrypt CDOSYS or CDOEX messages. You can obtain the CAPICOM DLL from the following Microsoft &quot;Platform SDK Redistributable: CAPICOM 1.0A&quot; Web site:

http://www.microsoft.com/downloads/details.aspx?FamilyID=860ee43a-a843-462f-abb5-ff88ea5896f6&DisplayLang=en

Digitally signing a message
 Start with a CDOSYS or CDOEX IMessage object. Configure this message with sender, recipient, subject, body, attachments, and any other necessary items. Create a new IMessage object. Open the existing message from step 1 by using this new message's IDatasource::OpenObject method.  Get the new IMessage object's IBodyPart root, and then set the following properties: oBodyPart.ContentMediaType = &quot;application/pkcs7-mime;smime-type=signed-data;name=&quot;&quot;smime.p7m&quot;&quot;&quot; oBodyPart.ContentTransferEncoding = &quot;base64&quot; oBodyPart.Fields(&quot;urn:schemas:mailheader:content-disposition&quot;) = &quot;attachment;FileName=&quot;&quot;smime.p7m&quot;&quot;&quot; oBodyPart.Fields.Update  Use the CAPICOM Signer object and the sender's certificate to sign the content of the new IMessage object. Send the new message, and then discard the original message.

Encrypting a message
 Start with a CDOSYS or CDOEX IMessage object. Configure this message with sender, recipient, subject, body, attachments, and any other necessary items.</li> Create a new IMessage object. Open the existing message from step 1 by using this new message's IDatasource::OpenObject method.</li>  Get the new IMessage object's IBodyPart root, and then set the following properties: oBodyPart.ContentMediaType = &quot;application/pkcs7-mime;smime-type=enveloped-data;name=smime.p7m;&quot; oBodyPart.ContentTransferEncoding = &quot;base64&quot; oBodyPart.Fields(&quot;urn:schemas:mailheader:content-disposition&quot;) = &quot;attachment;FileName=&quot;&quot;smime.p7m&quot;&quot;&quot; oBodyPart.Fields.Update </li> Use the CAPICOM EnvelopedData object and the recipient's certificate to encrypt the content of the new IMessage object.</li> Send the new message, and discard the original.</li></ol>

Digitally signing and encrypting a message
The steps are the same, but the order is important. You must first sign the message, and then encrypt the message.

Notes about the sample code

 * The sample calls two non-existent functions, GetCertForSignature and GetCertForEnvelope. The programmer must obtain the appropriate certificate.
 * The sample code requires references to the CAPICOM 1.0 Type Library, the Microsoft ActiveX Data Objects 2.5 Library, and the appropriate CDO Library.

'****************************************************************** ' ' SignMessage ' ' Takes oMsg as input (non-secure message) and returns a new ' message that is digitally signed. ' '****************************************************************** Public Function SignMessage(oMsg As CDO.Message) As CDO.Message Dim oSecMsg As New CDO.Message Dim oBodyPart As CDO.IBodyPart Dim oSignedData As New CAPICOM.SignedData Dim strData As String Dim strContent As String Dim oStream As ADODB.Stream Dim oSigner As New CAPICOM.Signer Dim oCert As CAPICOM.Certificate Dim oAttr As New CAPICOM.Attribute Dim byteData As Byte On Error GoTo handle_error ' Copy input into output message oSecMsg.DataSource.OpenObject oMsg, cdoIMessage ' Set up main bodypart Set oBodyPart = oSecMsg.BodyPart oBodyPart.ContentMediaType = &quot;application/pkcs7-mime;smime-type=signed-data;name=&quot;&quot;smime.p7m&quot;&quot;&quot; oBodyPart.ContentTransferEncoding = &quot;base64&quot; oBodyPart.Fields(&quot;urn:schemas:mailheader:content-disposition&quot;) = &quot;attachment;FileName=&quot;&quot;smime.p7m&quot;&quot;&quot; oBodyPart.Fields.Update ' Get certificate Set oCert = GetCertForSignature(oSecMsg.From) ' If no cert, throw an error and exit If oCert Is Nothing Then MsgBox &quot;No valid certificate found for sender.&quot;,, &quot;Error&quot; Set SignMessage = Nothing End If   ' Add cert to signer object oSigner.Certificate = oCert ' Add signing time attribute to signer object oAttr.Name = CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME oAttr.Value = Now oSigner.AuthenticatedAttributes.Add oAttr

' Sign the content (root bodypart) strContent = oMsg.BodyPart.GetStream.ReadText oSignedData.Content = StrConv(strContent, vbFromUnicode)

strData = oSignedData.Sign(oSigner, False, CAPICOM_ENCODE_BINARY)

' Write the cms blob into the main bodypart ' let CDO do the base64 encoding Set oStream = oSecMsg.BodyPart.GetDecodedContentStream oStream.Type = adTypeBinary

' Get the string data as a byte array byteData = strData ' Write the data to the stream and flush it   oStream.Write byteData oStream.Flush GoTo cleanup ' Report error handle_error: MsgBox Err.Number & &quot;: &quot; & Err.Description,, &quot;Error:&quot; Set oSecMsg = Nothing ' Clean up memory cleanup: Set oBodyPart = Nothing Set oSignedData = Nothing Set oStream = Nothing Set oSigner = Nothing Set oCert = Nothing Set oAttr = Nothing ' Return new message Set SignMessage = oSecMsg End Function

'****************************************************************** ' ' EnvelopeMessage ' ' Takes oMsg as input (non-secure message) and returns a new ' message that is enveloped. ' '****************************************************************** Public Function EnvelopeMessage(oMsg As CDO.Message, iCertStore As Integer, Optional strQuery As String) As CDO.Message Dim oSecMsg As New CDO.Message Dim oBodyPart As CDO.IBodyPart Dim oEnvelopedData As New CAPICOM.EnvelopedData Dim oCert As CAPICOM.Certificate Dim oStream As ADODB.Stream Dim strData As String Dim strContent As String Dim byteData As Byte ' Copy input into output message oSecMsg.DataSource.OpenObject oMsg, cdoIMessage ' Set up main bodypart Set oBodyPart = oSecMsg.BodyPart oBodyPart.ContentMediaType = &quot;application/pkcs7-mime;smime-type=enveloped-data;name=smime.p7m;&quot;

oBodyPart.ContentTransferEncoding = &quot;base64&quot; oBodyPart.Fields(&quot;urn:schemas:mailheader:content-disposition&quot;) = &quot;attachment;FileName=&quot;&quot;smime.p7m&quot;&quot;&quot; oBodyPart.Fields.Update ' Get recipient's cert If strQuery = &quot;&quot; Then Set oCert = GetCertForEnvelope(oSecMsg.To, iCertStore) Else Set oCert = GetCertForEnvelope(oSecMsg.To, iCertStore, strQuery) End If   oEnvelopedData.Recipients.Add oCert ' Encrypt content strContent = oMsg.BodyPart.GetStream.ReadText oEnvelopedData.Content = StrConv(strContent, vbFromUnicode) strData = oEnvelopedData.Encrypt(CAPICOM_ENCODE_BINARY) ' Write the CMS blob into the main bodypart ' let CDO do the base64 encoding Set oStream = oSecMsg.BodyPart.GetDecodedContentStream oStream.Type = adTypeBinary ' Get the string data as a byte array byteData = strData ' Write the data to the stream and flush it   oStream.Write byteData oStream.Flush GoTo cleanup handle_error: MsgBox Err.Number & &quot;: &quot; & Err.Description,, &quot;Error:&quot; Set oSecMsg = Nothing ' Clean up memory cleanup: Set oBodyPart = Nothing Set oEnvelopedData = Nothing Set oStream = Nothing Set oCert = Nothing ' Return new message Set EnvelopeMessage = oSecMsg End Function

Keywords: kbenv kbhowto kbmsg KB280391

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.