Welcome to TechNet Blogs Sign in | Join | Help

Granting IIS Access to a Certificate's Private Key

When you install an X.509 certificate into a cert store on your machine, only you end up having access to the private key. It turns out the private key is stored as nothing else than a file under the Documents and Settings folder. In order to give others permission to read the key (for example, an ASP.NET worker process when your WCF service is hosted), you simply have to modify the file's ACL appropriately.

I had to do this a long time ago when I first set up our secure RM interop endpoints. Back then, it was just a manual task and I ended up using WseCertificate2.exe - the WSE X.509 Certificate Tool. We recently automated the deployment and I needed a way to do this on the command line. I found out we shipped a tool in the WCF SDK called FindPrivateKey.exe just for this purpose. The tool quickly revealed the location of any private key belonging to any installed X.509 certificate. For example, I found the private key belonging to the OASIS Bob certificate with:

C:\FindPrivateKey.exe My LocalMachine -t "35 03 34 20 1b ee a6 50 2d 11 34 2f 93 ee a0 9f c0 b5 df 01"
Private key directory:
C:\Documents and Settings\onhrebic\Application Data\Microsoft\Crypto\RSA\S-1-5-21-2127521184-1604012920-1887927527-1660115
Private key file name:
7208e197d6e40f342b5e8c2629794d61_8bb36650-2933-4945-8ecb-e3c2f7042931

"35 03 34 20 1b ee a6 50 2d 11 34 2f 93 ee a0 9f c0 b5 df 01" is the key's thumbprint - for some reason I couldn't get -n "CN=Bob" to work. Combined with cacls.exe, the job was easy enough - as all the security SDK samples show:

for /f "delims='' %%i in ('FindPrivateKey.exe My LocalMachine -t "35 03 34 20 1b ee a6 50 2d 11 34 2f 93 ee a0 9f c0 b5 df 01" -a') do set PRIVATE_KEY_FILE=%%i
set WP_ACCOUNT=NT AUTHORITY\NETWORK SERVICE
(ver | findstr "5.1") && set WP_ACCOUNT=%COMPUTERNAME%\ASPNET
echo Y|cacls.exe "%PRIVATE_KEY_FILE%" /E /G "%WP_ACCOUNT%":R

It turns out there's another tool that's freely and more broadly available and even easier to use - WinHttpCertCfg.exe. The tool comes with the Windows Server 2003 Resource Kit Tools together with many other surprisingly useful utilities. The tool is specifically designed to work with ACLs. For example, I was able to view Bob's security list with this simple command:

C:\Program Files (x86)\Windows Resource Kits\Tools>winhttpcertcfg.exe -l -c LOCAL_MACHINE\My -s Bob
Microsoft (R) WinHTTP Certificate Configuration Tool
Copyright (C) Microsoft Corporation 2001.

Matching certificate:
CN=Bob
OU=OASIS Interop Test Cert
O=OASIS

Additional accounts and groups with access to the private key include:
    DOMAIN\onhrebic
    NT AUTHORITY\SYSTEM
    BUILTIN\Administrators

I was than able to easily give the ASP.NET worker process permissions with:

set WP_ACCOUNT=NETWORK SERVICE
(ver | findstr "5.1") && set WP_ACCOUNT=%COMPUTERNAME%\ASPNET
C:\Program Files (x86)\Windows Resource Kits\Tools\winhttpcertcfg.exe -g -c LOCAL_MACHINE\My -s Bob -a "%WP_ACCOUNT%"

Posted by onhrebic | 17 Comments

The WS-RM Sequence Lifetime in Indigo

There are two mechanisms in the WS-ReliableMessaging protocol that affect the lifetime of a sequence - the Expires element located in CreateSequence and CreateSequenceResponse messages and the InactivityTimeout policy assertion located in a service's WSDL. In Beta 1, Indigo simply ignores the first one and has a mechanism in place that tries to prevent the timeout defined by the second one from ever being actually reached. Indigo's architects and developers had good reasons to do things this way. It all makes sense when you think about the two reliable communication models that are currently available in the product - a queued one and a direct one. The queued communication model is meant mainly for long-running, disconnected, durable applications; on the other hand, the direct communication model is "alive" - both parties need to be online at the same time and their state is stored in-memory as they exchange their messages. This post addresses the second model.

Let's cover the optional Expires element first. Indigo clients never generate it and Indigo services echo back whatever the client asked for as that's what's required by the WS-RM specification. That's also all an Indigo service will do - if the client was serious enough about the Expires duration to put it in the CreateSequence, it will be up to the client to enforce it, as well. There is nothing in the spec that says the RM Receiver is obligated to terminate the sequence when the duration expires.

The InactivityTimeout is more interesting. If there is no traffic on an RM sequence, and that includes application as well as protocol messages, for the duration of the inactivity timeout, the sequence can be considered terminated. An Indigo service resets its inactivity timer every time it receives a message on a given sequence. When the timer goes off, however, it will send a SequenceTerminated fault to the client and erase all state it had associated with that sequence. An Indigo client is different. An Indigo client wants to keep the "direct" sequence alive for the user and prevent the service from terminating it due to inactivity. To do this, it sends "keep-alive" messages. Keep-alives are simple AckRequested messages that probe the sequence to a) make sure it's not dead and b) to inform the service the client is still active. If an Indigo client doesn't receive acknowledgements for its keep-alives for the duration of the inactivity timeout, it will also terminate the sequence and send a SequenceTerminated fault to the service.

Let's get into the nitty-gritty details about when we actually send these keep-alive messages. We'll send the first one when the client hasn't heard back from the service for half of the inactivity timeout. At that point, we split the second half of the inactivity timeout into MaxRetryCount segments. If the server continues to respond with silence, we'll send one AckRequested at the end of every one of the calculated segments. The client will give up after MaxRetryCount AckRequesteds.

I hope this gave you some more insight into how Indigo deals with the lifetime of a sequence and that this will all come in handy when debugging isses that arise as a result of it - whether in Indigo-to-Indigo or cross-vendor configurations.

Posted by onhrebic | 21 Comments

Getting Static and Instance Property Values in MDbg

I've always wondered how to do this and only took the time to figure it out recently - how do you get the values of C# properties, especially if they're static, in MDbg? It was the magic keyword "funceval" and the knowledge of how properties live in IL that answered that question for me. In this particular case, I needed to get the app domain's configuration file. This is what I had to do:

[p#:1, t#:2] mdbg> funceval System.AppDomain.get_CurrentDomain
result = System.AppDomain
        _domainManager=<null>
        _LocalStore=System.Collections.Hashtable.SyncHashtable
        _FusionStore=System.AppDomainSetup
        _SecurityIdentity=<null>
        _Policies=<null>
        AssemblyLoad=<null>
        TypeResolve=<null>
        ResourceResolve=<null>
        AssemblyResolve=<null>
        ReflectionOnlyAssemblyResolve=<null>
        _DefaultContext=System.Runtime.Remoting.Contexts.Context
        _activationContext=<null>
        _applicationIdentity=<null>
        _applicationTrust=<null>
        _DefaultPrincipal=<null>
        _RemotingData=System.Runtime.Remoting.DomainSpecificRemotingData
        _processExit=System.EventHandler
        _domainUnload=System.EventHandler
        _unhandledException=System.UnhandledExceptionEventHandler
        _dummyField=1433136
        _PrincipalPolicy=System.Security.Principal.PrincipalPolicy
        _HasSetPolicy=False
        __identity=<null>
results saved to $result
STOP EvalComplete
IP: 133 @ ... - MAPPING_EXACT
[p#:1, t#:2] mdbg> funceval System.AppDomain.get_SetupInformation $result
result = System.AppDomainSetup
        _Entries=array [16]
        _LoaderOptimization=System.LoaderOptimization
        _AppBase=<null>
        _AppDomainInitializer=<null>
        _AppDomainInitializerArguments=<null>
        _ActivationArguments=<null>
        _ApplicationTrust=<null>
        _ConfigurationBytes=<null>
results saved to $result
STOP EvalComplete
IP: 133 @ ... - MAPPING_EXACT
[p#:1, t#:2] mdbg> funceval System.AppDomainSetup.get_ConfigurationFile $result
result = "C:\Test\Test.exe.config"
results saved to $result
STOP EvalComplete
IP: 133 @ ... - MAPPING_EXACT
[p#:1, t#:2] mdbg>

Clearly, no rocket science. All one needed to know is that a property lives as two methods in IL - get_PropertyName for the getter and set_PropertyName for the setter - and that the object the method is to be executed against (in the case of instance properties) must be provided as the first argument, just like it normally is. I'd love to hear about a better and easier way.

By the way, MDbg ships as a sample with the Whidbey SDK. You can get it at http://www.microsoft.com/downloads/details.aspx?FamilyID=38449A42-6B7A-4E28-80CE-C55645AB1310&displaylang=en.

Posted by onhrebic | 0 Comments

Testing WS-RM Interoperability

The ultimate goal of WS-* protocols is without any doubt interoperability. Companies that have a vested interest in the success of WS-* protocols go to great lenghts to ensure these open standards are truly interoperable in practice, and not just on paper. More often than not, vagueness, sometimes purposeful and sometimes unintentional, has far-reaching undesirable consequences on interoperability - despite the fact everyone agreed on and signed off on the specification, interpretations of it and thus its implementations will differ. To avoid this, companies implementing WS-* protocols will usually do one of the following to facilitate interop testing during product development and onward:

  • Attend a WS-* interoperability workshop. At such an event, interested companies come together bringing their unreleased implementations of given WS-* protocols together with basic applications called workshop scenarios. These applications conform to previously agreed to contracts and exercise a given protocol to a certain degree, typically the degree to which interoperability is desired at that point in time. What follows is days of non-stop face-to-face interop testing: every company announces the addresses at which its endpoints are listening and begins running its clients against the endpoints of others. Spec and implementation bugs are found, issues are raised, and the goal of seamless interoperability becomes that much more of a reality.
  • Host online endpoints. A company with a desire to do online interop testing would expose the same service endpoints and client applications that it did or would have at the workshop on a publicly accessible server on the Internet. It would then announce the existence of these endpoints and encourage others to test against them. From then on, at their convenience and as often as necessary, companies hit each other's endpoints with each other's clients to make sure everyone is on the same page.

Microsoft has its WS-RM endpoints available online, as well. They are located at http://131.107.153.195/SecureReliableMessaging.Latest/ReliableOneWay.svc, http://131.107.153.195/SecureReliableMessaging.Latest/ReliableOneWayDual.svc, and http://131.107.153.195/SecureReliableMessaging.Latest/ReliableRequestReplyDual.svc. The client application is at http://131.107.153.195/RM.Latest/RMClient.asmx. Feel free to send any questions regarding WS-RM interop, the workshop scenarios, or our endpoints my way!

Posted by onhrebic | 2 Comments

WSDL and WS-Addressing

I spent some time last weekend playing with BEA's WebLogic Server 9.0 to test WS-RM interoperability with Indigo. One problem I encountered was the fact that when presented with a WSDL generated by a BEA endpoint, Indigo's SvcUtil.exe generates a .config file with the mapAddressingHeadersToHttpHeaders attribute set to true on the httpTransport element. What this means is that all WS-Addressing headers (headers such as Action, To, From, MessageID, and ReplyTo) get stripped from the message and some (such as the Action header) get moved to the header on the HTTP request. This setting should only be on in the case Indigo is talking to a "V1" web service - a web service that doesn't support WS-Addressing. However, this wasn't the case with my BEA endpoint so this conversion was clearly incorrect.

It turns out there currently isn't an official policy assertion that indicates an endpoint's support for WS-Addressing. In Beta 1, Indigo simply uses the presence of a wsa:EndpointReference element inside the wsdl:port element to determine this. If it doesn't find one (which is the case with the BEA WSDL and nearly every other non-MS WSDL out there at this point) it will assume WS-Addressing is not supported and generate a client proxy that will have the previously mentioned setting set to true. Interestingly enough, this will happen even if the endpoint's policy declares a requirement for WS-RM (through the RMAssertion policy assertion) and SvcUtil.exe generates a WS-RM enabled client proxy (WS-RM requires support for WS-Addressing). The only thing a user can do at this point is manually update the generated .config file and explicitly set the setting to false.

The good news is there is currently an official proposal in the works that will make determining support for WS-Addressing a standard.

Posted by onhrebic | 0 Comments

WinFX Runtime Beta 1 Released

If you haven't heard about this already you are someone who probably won't care, but here it goes anyways: Beta 1 version of the WinFX Runtime is out! That's right, this is the "RTM" Beta 1 of Indigo and Avalon. You can download it from http://www.microsoft.com/downloads/details.aspx?FamilyId=CE888B4C-CCBD-452F-9D90-F4B7190CCA24&displaylang=en and run it on top of Whidbey Beta 2.

While we're on the subject of Indigo and Avalon - we now have official names for both technologies: Windows Communication Foundation and Windows Presentation Foundation, respectively. This announcement comes at about the same time Longhorn gets an official name, as well: Windows Vista.

You can find out more about Vista, WCF, and WPF at http://msdn.microsoft.com/windowsvista/.

Posted by onhrebic | 1 Comments

WS-RM Flow Control in Indigo

It is natural to assume all reliable messaging systems will implement some sort of congestion and flow control algorithms. This is bound to happen because we are driven to develop smart and efficient algorithms that will minimize the load on the computers and networks that support them. Indigo's WS-Reliable Messaging implementation is no different – it puts to use advanced congestion avoidance algorithms that have been tailored to the specific intricacies of SOAP messaging, the WS-RM protocol itself, and the kinds of networks WS-RM is expected to be used on. I will discuss what Indigo does about congestion control in the next installment of my blog; today, we will concentrate on WS-RM's flow control mechanisms.

You may have noticed a custom XML element appearing in all acknowledgements Indigo endpoints send: BufferRemaining. A concrete instance, inside a SequenceAcknowledgement, will look like this:

<r:SequenceAcknowledgement>
  <
r:Identifier>urn:uuid:7c96e44a-2158-44d5-aee3-f0daeec853e0</r:Identifier>
  <
r:AcknowledgementRangeUpper="1" Lower="1" />
  <
netrm:BufferRemaining xmlns:netrm="http://schemas.microsoft.com/net/2004/02/RM">31</netrm:BufferRemaining>
</
r:SequenceAcknowledgement>

If it existed, the normative outline for that element would be: <netrm:BufferRemaining ...> xs:unsignedLong </netrm:BufferRemaining>. By the way, this is currently the only element you’ll see in the http://schemas.microsoft.com/net/2004/02/RM namespace.

Now that we’ve covered its syntax, let’s cover its semantics. Its purpose won’t come as a big surprise: to inform the sender of the current status of the receiver’s buffer for incoming messages. More specifically, the number represents the number of messages the receiver would be able to accept and buffer from this point on before beginning to refuse them. The number will go down every time the receiving RM channel buffers a new message and go up every time a receiving application accepts a new message from that channel. The maximum size of the receiving channel’s buffer becomes the maximum value a BufferRemaining element can ever hold – in Indigo, this size is controlled by the BufferedMessagesQuota property on any RM enabled binding. By default, the value is 32.

Whenever an Indigo sender receives an acknowledgement, it updates its perceived size of the free space available on the receiver. The sender must do this because the actual value it uses is continuously changed as the sender sends out new messages. In other words, what the sender actually believes is the remaining buffer size is calculated by subtracting the number of outstanding messages (i.e. messages that have not yet been acknowledged) from the latest BufferRemaining value it received. For example, by default, if the sender sent 32 messages before receiving an acknowledgement with a BufferRemaining of 31 and which acknowledged the first message only, its perceived remaining buffer size would be 0.

An Indigo sender uses its perceived remaining buffer size in two important ways. It will begin piggy-backing AckRequested elements on all new messages it sends if the value drops below a certain point (currently 2) – it will do this to increase the chances of receiving an acknowledgement with an updated BufferRemaining that will hopefully indicate the real remaining buffer size on the receiver isn’t so low. More importantly and more obviously, it will stop sending any new messages and allow the server to catch up if the value ever drops down to 0. The only event that will resume message transfer is an acknowledgement from the receiver that free space became available. An Indigo receiver will send such a sole-purpose acknowledgement immediately after it detects it. You may be asking what happens in the case an asynchronous transport is used and the receiver can’t talk to the sender unless the sender talks to it first. We don't want to wait for an AckRequested keep-alive (which would only be sent, as another blog post will explain, after half the inactivity timeout), so what an Indigo client will do is begin periodically polling the receiver with AckRequested requests until it gets back a response that indicates new free space. Note that flow control over asynchronous transports wasn't implemented in Beta 1.

Finally, the BufferRemaining value always represents the actual free space regardless of the ordering of the session. This may be confusing at first. If the receiver is instructed to deliver messages in order, it must always ensure there is enough space in the buffer for all messages with message numbers higher than the last message received by the application and lower than that number plus the quota. For example, if the quota is 32 and no messages have been received so far, only messages 1 through 32 would be buffered even though the buffer is completely empty and BufferRemaining was 32. Any other message will be thrown away.

Posted by onhrebic | 8 Comments

Reliable Sequence Creation in WS-RM

The WS-ReliableMessaging spec does not address the issue of lost CreateSequence requests and lost CreateSequenceResponse replies. Despite that, it is clear that every implementation of WS-RM will want to do this and Indigo is one of them. Knowing how Indigo handles this may be useful if your application uses WS-RM, and especially useful if you are interoperating with another WS-RM stack.

In the case of both simplex and duplex RM, an Indigo client will send as many CreateSequence requests as necessary until it receives a matching CreateSequenceResponse reply. Indigo doesn't consider retrying a CreateSequence as a retransmission of the first attempt and thus every CreateSequence retry carries a unique MessageID. Indigo will do this up to MaxRetryCount at which point it will give up and the Open method will throw. Note that a received CreateSequenceResponse that is related to an old CreateSequence attempt (i.e. a new CreateSequence was sent after it) will not be accepted.

In the case of simplex RM, the server has an easy job - it will generate a new sequence identifier for every CreateSequence that comes in. Since each CreateSequence carries a unique MessageID, there can be no disagreement over whether the same sequence identifier should be sent for what may have been a CreateSequence retry. An Indigo client will consume and use the first CreateSequenceResponse it can and ignore all subsequent ones.

The situation is a bit more complex in the case of duplex RM where two sequence identifiers are involved - one being sent by the client to the service (the offered sequence identifier for messages flowing from the RM service to the RM client) and one being sent by the service to the client (the sequence identifier for messages flowing from the RM client to the RM service). An Indigo client doesn't have a lot to worry about - it will send CreateSequence requests with unique MessageIDs and keep the offered sequence identifier the same (you'll see later why there's no need to use a new one). The question is, what does the server do?

It turns out the server can no longer return a new sequence identifier for every CreateSequence. It must check the offered sequence identifier and, if it has seen it before, also return the same sequence identifier it has returned before. This has to happen so that there is no ambiguity over where messages should be sent later on. The server cannot have two different incoming sequence identifiers associated with the same outgoing sequence identifier.

Imagine the case a CreateSequence (with Offer ID X) is duplicated on the network (by the way, this is why it didn't matter if the client reused the same ID: the server may end up getting CreateSequence requests with the same offer ID anyways). If the server returned different sequence identifiers (A and B) it would have two association records in its memory (X-A and X-B). This isn't a state a server wants to be in because once X-A is established, establishing X-B would be an error. Even worse, if the server only kept the latest association on record (so the association for sequence X would change from A to B after the server received the second CS), the client sending a message with ID A would now be locked out.

This hopefully gives you a better idea about why Indigo's reliable channels take care of session initiation the way they do.

Posted by onhrebic | 168 Comments

Introduction

You're reading Ondrej's new blog. I've joined the ranks of Indigo bloggers with the intent to write about what definitely won't come as a surprise to you: the kind of things I work on every day! You may find this interesting if you are a curious Indigo explorer or a techie friend of mine. I'm guessing that would be about it.

With the usual first post small talk out of the way, let's see what this blog is really all about. I am a Software Design Engineer in Test on the WS-ReliableMessaging Indigo team. I own protocol and interop for WS-RM, and I write and test SOAP level intermediaries and routers built using our product. Most entries you'll find here will surely revolve around those two concepts.

To get your hands on the latest and greatest release of Indigo yet, click on http://www.microsoft.com/downloads/details.aspx?FamilyId=B789BC8D-4F25-4823-B6AA-C5EDF432D0C1&displaylang=en and download the Indigo Beta 1 RC.

Posted by onhrebic | 3 Comments
 
Page view tracker