8

I'm taking the Azure lab LoadBalancing with WCF and recognise what I have been told is bad from a security perspective, but am not sure if it applies here.

Can someone look at this code and tell me if different certificates should be used in production code?

public class RsaSessionSecurityTokenHandler : SessionSecurityTokenHandler
    {
        public RsaSessionSecurityTokenHandler(X509Certificate2 certificate)
        {
            List<CookieTransform> transforms = new List<CookieTransform>();
            transforms.Add(new DeflateCookieTransform());
            transforms.Add(new RsaEncryptionCookieTransform(certificate));
            transforms.Add(new RsaSignatureCookieTransform(certificate));
            this.SetTransforms(transforms);
        }

        public override ClaimsIdentityCollection ValidateToken(SessionSecurityToken token, string endpointId)
        {
            if (token == null)
            {
                throw new ArgumentNullException("token");
            }
            if (String.IsNullOrEmpty(endpointId))
            {
                throw new ArgumentException("endpointId");
            }

            // in active cases where absolute uris are used check the all parts of the token's 
            // endpoint id and this endpoint's id for equality except the port number
            Uri listenerEndpointId;
            bool listenerHasUri = Uri.TryCreate(endpointId, UriKind.Absolute, out listenerEndpointId);
            Uri tokenEndpointId;
            bool tokenHasUri = Uri.TryCreate(token.EndpointId, UriKind.Absolute, out tokenEndpointId);
            if (listenerHasUri && tokenHasUri)
            {
                if (listenerEndpointId.Scheme != tokenEndpointId.Scheme ||
                    listenerEndpointId.DnsSafeHost != tokenEndpointId.DnsSafeHost ||
                    listenerEndpointId.AbsolutePath != tokenEndpointId.AbsolutePath)
                {
                    throw new SecurityTokenValidationException(String.Format("The incoming token for '{0}' is not scoped to the endpoint '{1}'.", tokenEndpointId, listenerEndpointId));
                }
            }
            // in all other cases, fall back to string comparison
            else if (String.Equals(endpointId, token.EndpointId, StringComparison.Ordinal) == false)
            {
                throw new SecurityTokenValidationException(String.Format("The incoming token for '{0}' is not scoped to the endpoint '{1}'.", token.EndpointId, endpointId));
            }

            return this.ValidateToken(token);
        }
    }
AviD
  • 72,708
  • 22
  • 137
  • 218
makerofthings7
  • 50,488
  • 54
  • 253
  • 542
  • 1
    Perhaps not *exact* duplicate, but probably related: http://security.stackexchange.com/q/1806/953 Short answer there is you don't use the same key because an escrow copy of the encryption key (for data recovery purposes) would defeat one of the tenets (non-repudiation) of digital signatures. – Iszi Apr 15 '11 at 18:39
  • 1
    If you want expert cryptographic review, posting a snippet of C# code is not the way to go about it. There are probably few cryptographers who also know all the APIs this code is using by heart. If you want review of the cryptography, you should be providing a language- and API-independent specification of the operation that is being performed, to sufficient detail that someone could independently implement an interoperable implementation in another language with no fancy libraries. If you can't provide that spec, you don't understand what the code is doing well enough to trust it. – D.W. Jul 16 '11 at 05:52

5 Answers5

6

It is a general best practice to use two separate key pairs (and hence certificates) for signature vs. encryption. I just refreshed myself on the reasons why:

  • When a key is used for encryption, it's often wise to escrow it so that if it's lost, the encrypted content is not also lost. However, non-repudiation associated with a signature certificate isn't viable with multiple copies of the key pair around. So you don't want to escrow the signature certificate. From Wikipedia

That's the best one I've heard of. A lot of the time what I'm told is "just do it", and given that often one has to work within the constraints of the PKI one is forced to use, that's a fair enough statement.

Personally, I think for a simple PKI, bundling the two together - especially if you are using the "encryption" capabilities of the key for something like SSL - a transitory type of encryption for just point to point communication - then the security risk is not that high.

However -- sometimes you have to be ready to work with any PKI that comes along. So if the code had hard coded the assumption that the encryption certificate and the signing certificate will always be the same thing, then I think you have an interoperability problem.

As a last thing - I'm a little confused on the code - I'm assuming that "ValidateToken" does the validation of the signature on the token, right? It can't be both decrypting and validating the signature using the same key pair... encryption is for sending to the key pair holder, signing is for verifying information from the key pair holder. Is it just doing a signature validation here?

bethlakshmi
  • 11,656
  • 1
  • 28
  • 59
5

Many have pointed out key escrow as a reason for separating encryption and signature keys. Many have also mentioned that this shared use of keys is fine in this particular case. But nobody has mentioned the cryptographic problems in sharing keys for both signing and encryption

If you look at official standards for cryptography, most of them specify that different keys are used for different algorithms. For X509 certificates, the key usage part has very specific controls for what the key is used for. And for example, NIST has this to say about elliptic curve keys:

ECDSA keys shall only be used for the generation and verification of ECDSA digital signatures.

The reason for this is that if multiple different algorithms are used with the same key, then security must be proven for the combination of all the algorithms together, instead of just for one algorithm. Otherwise, an attacker might use one algorithm to produce a value that he couldn't calculate himself to attack the security of another algorithm.

For example, hypothetically, a key agreement protocol that signs arbitrary remote values could be used to fake valid signatures. Or perhaps sending a public key to be signed could reveal a value useful in attacking key agreement. Or concretely in the case of RSA, if secure padding wasn't used, sending a value to be signed can give a decryption of a ciphertext if the same key is used.

So, unless you can be very certain that both signing and encryption algorithms can indeed be used together with the same key, securely, you shouldn't do that. Even if you are very certain, it's bad cryptographic practice. And if you need to follow standards, they won't let you, anyhow.

Nakedible
  • 4,531
  • 4
  • 26
  • 22
4

In this particular scenario, this technique is fine.

You use the same cryptographic key (in this case an X.509 cert) to encrypt-to-self. The sample you mention implements a session token (simply speaking a protected cookie), which is shared between multiple similar web services sitting behind a load balancer. So the 'signature' (in this particular scenario) does not have the security goal of providing non-repudiation, but of data-origin-authentication, i.e. basically figuring out whether the session token was created by one of the peer services.

NB: In other scenarios, where the signature serves a non-repudiation goal, you should use separate key material (as correctly pointed out by the other answers here).

chgeuer
  • 79
  • 1
3

Can someone look at this code and tell me if different certificates should be used in production code?

First, any code that is use for a security function should be designed, design reviewed, implemented, code reviewed, and tested before puting in a production environment. Just because the code came from MSDN does not mean that it is secure. Even if you decide to use the code as written, please do not skip the design. The design may help you notice larger system wide issues.

As bethlakshmi and Rook noted the certificate is being used for encryption (confidentiality) and digital signing (identification and authentication). In general you should use different certificaticates (or keys) for different functions. Or more simply, a certificate should be used for only one function.

In this instance, it looks ok to use the same certificate for both functions. Even if one of the operations fail and the message is still sent out, it doesn't look like any part of the certificate would be exposed unless RsaEncryptionCookieTransform or RsaEncryptionCookieTransform were faulty. And sending a message with a successful encryption but no signature or a signature but no encyryption looks ok.

If you do decide to use one certificate for both functions make sure you highlight it in your key management plan and your threat model.

this.josh
  • 8,843
  • 2
  • 29
  • 51
1

There is nothing wrong with this approach. Its important to note that encryption!=authentication. Using encryption doesn't guarantee that the message hasn't been tampered with, however by signing the message you can make this guarantee.

rook
  • 47,004
  • 10
  • 94
  • 182
  • 1
    Or more accurately, the recipient can be assured that the message has not been tampered with since it was signed. Unfortunately there are no guarantees that someone else didn't create a message and sign it with a pilfered key. – Rory Alsop Apr 16 '11 at 18:42
  • 1
    @Rory Alsop♦ Correct, i thought that was implicit. – rook Apr 16 '11 at 18:59
  • @Rory @Rook Thanks for taking a look at this. I thought that since the encrypted payload contains a variable string (or set of strings) this may open up cryptographic Oracles of some type. – makerofthings7 Apr 17 '11 at 02:16