Authenticating a Server with Digital Signatures - c#

I understand how Non-repudiation and Integrity are achieved with Digital Signatures, but it's the Authentication that I don't grasp yet.
I'm developing a Client-Server application in C#, that should be capable of Authentication with Digital Certificates and Digital Signatures. I know how to check the validity and integrity of a Signature (with SignedCms.CheckSignature()), but how does this authenticates any of the parts involved?
For example:
The client asks the Server for a Digital Signature,
The client receives the signature and validates it,
If the validation succeeds, continue.
The client could be a victim of a man-in-the middle attack and receive a valid signature in step 2. The validation would succeed, but the client wouldn't be talking to the right server.
What am I missing?

You're missing trust of the signing certificate.
Consider SSL certificates, they have a signing path to a root CA which is trusted by Windows (or whatever OS). If the MITM presents a self signed cert, or one produced by an untrusted CA then it gets rejected by the browser and a warning is displayed. So a certificate is only trusted if it's issued by a CA that you know, or chains up to one you know.
For self signed certs it becomes more complicated, you need to securely exchange the key fingerprint, serial number or other constant identifier and validate that the signing key is in fact one you expect - one reason why self signed certs generally shouldn't be used for public facing web sites or other services.
So if there's an MITM attack, and the signature from the original machine is stripped, the message changed, and then resigned using an unknown certificate as long as you check the identity of the signing cert against something you trust then you'll reject the resigned message.
(in reality it gets more complicated, but you get the point I hope)

They could only receive a valid signature if the man in the middle possesses the private key with which to sign the request. I think the key thing you may be missing is that altering any aspect of the item which is digitally signed would invalidate the signature. The man in the middle can re-submit the request, but if they change it, the signature validation will fail.

Related

Open X509 Certificates Selection Using USB Token in C# Hosted on IIS

I am working on a requirement which required Digital Signature on PDF files in ASP.Net C# and developed one application who gets the client certificate using USB token on my local machine. But, When hosting this application on IIS server getting error 'Current Session is not Interactive'.
Anyone have any idea, how can we get X509Certificates from client machine in ASP.Net C# and this application hosted on IIS server not console application.
My code for reference:
private void getSign()
{
X509Store store = new X509Store(StoreLocation.CurrentUser);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
X509Certificate2 cert = null;
//manually chose the certificate in the store
X509Certificate2Collection sel = X509Certificate2UI.SelectFromCollection(store.Certificates, null, null, X509SelectionFlag.SingleSelection);
if (sel.Count > 0)
cert = sel[0];
else
{
//MessageBox.Show("Certificate not found");
return;
}
SignWithThisCert(cert);
}
Disclaimer: although, it is not a straight answer to your question, but may contain directions for you to get the right way depending on a business requirements. There are two major issues in your question. One of them I tried to discuss in comments, but may need to explain.
Let's try to analyze your initial post:
Task: let users to upload a PDF to web application and make it signed.
Requirements: the PDF must be signed by using a certificate stored on a client's USB token.
Your proposed solution: get client certificate (from the client) and perform signing on a server side.
Let's formalize terms and operations used in your scenario.
Signing: document signing is used to guarantee document integrity and ensure that the document was not tampered in any way after it was signed. Digital signaure provides information about the entity who performed signing. This adds non-repudiation feature. Once signed, signer cannot deny the signing fact and proves that the information in the document was correct at the signing time. Asymmetric signing requires private key. Associated public key can be used to verify and validate the signature.
Private key: is a part of a key pair which belongs to particular client. No one else should know private key.
Security boundaries: client (web browser or other web client) and web server run in different security boundaries and have different trust levels. They are under different administrative controls. As the result, web server has very limited access to client machine/data and vice versa: web client has very limited access to server machine/data.
Your proposed design assumes that client picks the document and upload it to a server. Then client picks a signing certificate (particularly, private key) and upload it to a server for signing operation.
Issue #1: once private key leaves client and is copied to your web application you are breaking security boundary. As the result, the key is no longer private, because web application possesses a knowledge of private key and it is stored (even if temporarily) in server memory. Or, in simple word, the key is leaked and compromised.
Client is no longer responsible for his key and operations made by the key. Client may deny anything that was made by using its private key. And deny signatures made by your web application.
Issue #2: your proposed design assumes that PDF is copied to a server as is. And only then it is signed. However, once the document (or its exact binary copy, to be more precise) touches the network, client is no longer responsible for document accuracy. Because the document may be transformed during transit or some code that touches the document between client and document signing code.
Once document leaves client machine, client is no longer responsible for document integrity, because the document is passed through various pieces of code that compose the document to a suitable for transmission format (encapsulation, for example). As the result, document sent by client and recieved by document signing code on a server side may not be the same. Document integrity is not guaranteed. Although, you can apply TLS to protect the document during transmit, there still are places where the document can be anonymously tampered and no one will notice that.
Again, due to the fact that client cannot guarantee that web application received the same document he sent, client can deny the document you are trying to sign and deny the signature. Thus, making signature useless, because it proves nothing.
Issue #3: (not really an issue, but worth explanation) provided piece of code doesn't perform intended task (even though, it looks working in dev environment). Your goal is to invoke certificate selection dialog on client to select proper certificate.
During testing, you are running all the code locally. In debugger, the web application runs under currently logged user (which is interactive session) and is able to show the certificate selection dialog. However, you can't easily identify in which context (client or server) it is executed, because both, client and server run on the same machine and under the same security context. In fact, it is called under server context.
When you deploy the application to web server, you see the difference. Web application runs under some application pool context (user account) and this session is not interactive. As the result, X509Certificate2UI class cannot show the dialog, because no one will see it and no one can press buttons on it. This behavior is consistent regardless if the client and server run on the same or different machines, because IIS (or other web server) immediately separate concerns and security boundaries, while debugger does not. And client and server will definitely run under different security contexts. Even if you force to use the same context, IIS will make a secondary non-interactive user session to run the web application.
In order to show certificate selection dialog on client, you have to have a deep interaction with client, for example, via Silverlight (not sure if X509Certificate2UI is available in Silverlight) or some ActiveX control. You have to run some code on client side to accomplish that.
All stated above shows potential issues in your initial design, they simply break basic security rules. Technologies and tools are designed to follow these rules, not break them. By pursuing your initial design you will be forced to constantly fight with technologies to break them and making your application very insecure and vulnerable.
Preferred solution: we identified common risks in your design: key leak and document integrity between client and signing code on a server. To easily mitigate all this, you should do the only thing: perform document signing on client side. by doing this, signing private key will never leak from client and document integirty will be guaranteed over the course of signing and receipt by web application.
Now, we can talk about certificate properties. Your requirement is to use the certificate which is stored on a USB token. I don't know what kind of token you mean here. Is is a standard USB mass storage with PFX on it, or it is cryptographic device (smart card with USB interface, which is usually referred to USB token. For example, Aladdin (SafeNet) eToken devices).
If it is USB mass storage device, then it can't be a part of requirement, because generic USB drive does not offer anything helpful to identify the source of the certificate. Any certificate can be easily copied to USB drive and any certificate can be copied from USB drive.
If it is USB smart card, then there is a way to identify whether the certificate came from this device, or other source. Smart cards have one unique property: private key never leaves the card. All operations are performed on a card (this is the reason why they are slow comparing to certificates stored on PC).
This is usually accomplished by adding extra information to signing certificate during certificate issuance. For example, by adding Certificate Policies certificate extension. This will require that CA operator/manager ensures that certificates with specified certificate policies is deployed to smart cards only.
If these processes are established, you can use the code on server side that accepts signed PDF document and examines signing certificate contents. For example, you read certificate policies and expect to see particular entry there. If it is presented, then you can safely make assumptions that the document was signed by using the certificate stored on a smart card, because the key cannot be copied to anywhere from card device. If the certificate does not contain specific entry in certificate policies, then you can reject the documment acceptance and ask client to use proper certificate.

How do I programmatically find whether the intermediate certificate was served by the web server?

My C# code uses HttpWebRequest to send requests to a web service via HTTP over SSL (https:// prefixed URLs). The service has it's coolservice.example.com certificate which is signed by certificate authority intermediate certificate which is in turn signed by the trusted root certificate authority certificate. The latter must be in the caller certificate store and marked as "trusted root", otherwise all that SSL trust chain thing makes no sense. However the intermediate certificate may come from either of the different sources:
the web server may serve it together with its own certificate (as in "here's my certificate and btw it was signed with this certificate which was signed with something you likely trust, please just check the signatures along the trust chain")
the caller may automagically retrieve the intermediate from the certificate authority (AIA protocol or something) - I know this because I've been interfacing with a web service which didn't have the intermediate certificate installed and "it just worked"
the caller may have the intermediate certificate installed in their store
I need to check that the web server properly serves (not only has in the trust store but actually serves the certificate) the intermediate while the SSL handshake is in progress. This test site even shows "sent by server" next to the intermediate. So I guess such check is possible.
How do I craft such a check with C# and .NET Framework?
So far I've only come across HttpWebRequest.ServerCertificateValidationCallback which accepts the web service certificate (X509Certificate object) and the trust chain (X509Chain object). The trust chain lists all the certificates in the chain however I cannot see anything detailing where the certificate was obtained.
How I programmatically find whether the intermediate certificate was server by the web server or it was obtained from elsewhere?

Using the same certificate for SSL communication and for signing EXEs and DLLs

I have a certificate issued by an official organization to be used for SSL communication, can I use the same certificate to sign my EXEs or DLLs.
If not, what is the critiria for the certificate to be used to sign EXEs and DLLs and other binaries?
A certificate usually has usage constraints, basic constraints and extended constraints (extended key usage, EKU). It depends on those settings what you can use it for. These settings can include client and server authorization, code signing (this is what you're interested in), whether you can use your certificate as an intermediate CA, etc.
Here's a nice overview of possible EKU's: http://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/x509/extensions/extendedkeyusage.html . And basic constraints: http://javadoc.iaik.tugraz.at/iaik_jce/current/iaik/x509/extensions/BasicConstraints.html . The Windows built-in certificate viewer GUI displays all these constraints nicely, in a human readable form, so you don't need to decode OID's or strange field names.
As said in the other answer, X.509 certificates include KeyUsage and ExtKeyUsage extensions, which describe, what the certificate may be used for.
Most (if not all) Certificate Authorities won't issue the certificate valid for both SSL/TLS and for code signing for commercial reasons and also for security reasons.
On the other hand, if you use a self-signed certificate and validate this certificate in your own code, then nothing prevents you from generating the certificate with KeyUsage set to what you need and validating it accordingly.

Fundamental of certificate based authentication

I searched a lot and found many answer on how to implement certificate based authenticate in wcf. But my questions are related to fundamental of it.
While implementing Certificate based authentication on production, does client provides its certificate which server needs to add on its trusted people store? Or server provides a certificate (signed by server).
I guess while configuring wcf server, we just configure certificate location and store. We never bind it with any domain. So any client that present this certificate can access my service. And in case certificate needs to be bound to a domain. They why cannot we just allow all requests from that domain.
When client calls a wcf service, it present its certificate. Does this certificate only carry public key? And can this certificate by stolen (as it travels on network) and used by hacker to consume the web service.
I have idea about how ssl woks. In case of ssl, browser take care of all this stuff but in case of wcf service (when we want to allow only specific client to access our service) how it gets managed.
Thanks In advance.
Let me make it simple :
I want to create a web service and i want that three clients (A, B and C) can use it. I want to authenticate these three clients by certificate. While setting up, do these clients need to send their certificates to me. Or I have to create certificate for them? Will client share their private key as well (while setting up)
Do I need to put these certificates into trusted people store?
When they request for webservice, they will present their certificate (with public key only). If they present it with public key only, hackers can steal this public key and request for my web service. How will my webservice distinguish between hacker/actual client.
While implementing Certificate based authentication on production, does client provides its certificate which server needs to add on its trusted people store? Or server provides a certificate (signed by server).
In a secure service, a server certificate is mandatory. Client certificate is optional. The server can be configured to ignore, accept, or require client certificates.
I guess while configuring wcf server, we just configure certificate location and store. We never bind it with any domain. So any client that present this certificate can access my service. And in case certificate needs to be bound to a domain. They why cannot we just allow all requests from that domain.
Not sure how you'd bind to a domain without a client certificate. You mean with reverse DNS lookup? That requires an IP address, and a malicious user can spoof it.
The typical means of restricting access via client certificates it to map one of the fields in the client certificate (typically the subject or domain) to a user account. You can have one-to-one mappings (each client certificate represents a single user) or many-to-one mappings (if the client has a certificate that is in a list, he is treated as a certain user). If the certificate isn't mapped, the user is treated as anonymous. More information here assuming you are using IIS.
When client calls a wcf service, it present its certificate. Does this certificate only carry public key? And can this certificate by stolen (as it travels on network) and used by hacker to consume the web service.
The certificate FILE that you handle during setup contains both the public and private key. The certificate itself is contained in that file; it contains a payload that includes the public key and a MAC signature, but does not include the private key.
The private key is put into secure storage and is never sent in any HTTP request. Only the certificate (and its public key) are sent over the wire. The whole file is not sent.
Edit to Respond to Further Questions
I want to create a web service and i want that three clients (A, B and C) can use it. I want to authenticate these three clients by certificate. While setting up, do these clients need to send their certificates to me. Or I have to create certificate for them?
During set up, a client certificate must be generated by a certificate authority (CA). You can actually serve the role as an intermediate CA (for production certificates) who derives his authority from a root CA (such as Verisign). In order to do that you must request a certificate from the root authority. They will issue you a certificate with its own public key, and give you a private key, so that you will have the ability to generate and digitally sign certificates of your own. You typically have to pay for this privilege.
In addition, you can become your own root CA! This is common during the development phase. Basically you generate your own public and private keys and start generating your own certificates. These are called self-signed certificates. The down side of being your own CA is that nobody will recognize your public key, so in order for anybody to use your certificates they would you have manually add you to their list of trusted root authorities.
Will client share their private key as well (while setting up)
No, nobody ever shares a private key with anybody, throughout the entire PKI. Ever. This is exactly why it is referred to as a private key. The only exception is when you are a certificate authority and you are generating a private key in order to create a certificate. In this case the private key must be carefully guarded during handling. It is never, ever sent over the wire as part of SSL communications.
Do I need to put these certificates into trusted people store?
Yes and no. If you are using a self-signed certificate, yes. If you are using a certificate that was signed by an CA that in turn has a certificate that was signed by a root CA, the root CA must also be in the list of trusted root authorities, but you probably don't have to add it. It should be there automatically. That is the whole purpose of using trusted root authorities-- everybody is supposed to know about them and should recognize their public keys. Root certificates are typically distributed to browsers automatically during installation and kept up to date using the browser's patch and update services.
When they request for webservice, they will present their certificate (with public key only). If they present it with public key only, hackers can steal this public key and request for my web service. How will my webservice distinguish between hacker/actual client.
This is a great question.
It's important to recognize that an SSL handshake includes a lot more than sharing certificates. There is also, among other things, a challenge/response step. Here's how it works:
Your server will generate a random number or time stamp ("challenge") and send it to your browser, challenging it to encrypt it. The browser will then encrypt the challenge using the private key (which it only has access to). This "response" is then sent back to the server for verification. The server uses the public key from the client certificate to decrypt the response. Since only the client has the private key, and since the public key is publicly known and verifiable (because it is contained in a signed and tamperproof certificate), the server can tell that the response had to have been encrypted by the client associated with the certificate. And because the challenge was generated by the server, and is different every time, a hacker cannot impersonate the client by replaying the response from a previous challenge.
While implementing Certificate based authentication on production, does client provides its certificate which server needs to add on its trusted people store?
Yes, if the server asks for it, otherwise no.
Or server provides a certificate (signed by server).
Always. These aren't mutually exclusive. Both can happen.
I guess while configuring wcf server, we just configure certificate location and store. We never bind it with any domain. So any client that present this certificate can access my service. And in case certificate needs to be bound to a domain. They why cannot we just allow all requests from that domain.
I can't make head or tail of any of that.
When client calls a wcf service, it present its certificate.
If the server asks for it.
Does this certificate only carry public key?
Yes.
And can this certificate by stolen (as it travels on network) and used by hacker to consume the web service.
No, because it only contains the public key.
EDIT Re 'Let me make it simple':
While setting up, do these clients need to send their certificates to me.
Only if they are self-signed.
Or I have to create certificate for them?
That's another possibility, but then you would have to become a mini-CA (Certificate Authority). Too broad.
Will client share their private key as well (while setting up)
Definitely not.
Do I need to put these certificates into trusted people store?
There is no such thing as a 'trusted people store'. There is a trusted certificate store, which usually only contains CA certificates. You only need to add the actual client certificates if they are self-signed. You might need to add their CA certificate if it isn't already there.
When they request for webservice, they will present their certificate (with public key only). If they present it with public key only, hackers can steal this public key and request for my web service.
I've already answered that. No.
How will my webservice distinguish between hacker/actual client.
They won't 'just' present their certificate: they will also provide a digital signature over it signed by their private key. Possesion of the certificate alone is worthless to an attacker. Without the private key they cannot even get past the TLS handshake. Your web service won't even see them.

Comparison of the relative merits and appropriate scenarios for the supported WCF authentication credentials

I'm trying to select the correct authentication mechanism for a WCF service. This article explains what the supported credentials are - I just don't understand how to decide between them.
Please could somebody supply an explanation of when each of the authentication options are appropriate to use, and the advantages/disadvantages of each over the others.
For reference, the authentication options are:
None
Basic
Digest
Ntlm
Windows
Certificate
Password
Note: I have seen a great MSDN article on this, but I cannot for the life of me find it anymore.
None:
Pretty straightforward - use this when you don't want to identify or authenticate your users.
Basic and Digest:
These authentication types aren't used much any more, but occasionally you might need to connect to an older web service hosted in IIS, which might be configured to use Basic or Digest authentication. Traffic won't be encrypted. For Basic, the password will be sent in plain text, and for Digest the password will be sent in a poorly encrypted form. Avoid using these authentication types.
NTLM and Windows:
NTLM uses the NT LAN Manager to control security. Windows, by default, will use Kerberos (ie Active Directory) to control security. If Kerberos is not available, it will default to NTLM. Only use NTLM if you specifically need to avoid Kerberos (I cannot think of a scenario where you would want to do this, but part of WCFs greatness is its flexibility).
Certificate:
If your users have their own certificates which can be used to identify them, you might consider using this authentication mode. Passwords can be guessed - it is very hard to guess a certificate, so this is a pretty secure mode of authentication (provided the certificate itself is secure).
Password:
Use Password when you want to create your own method of validating a users username and password. This might involve accessing an existing user credential store in a custom database. You will need to write your own UserNamePasswordValidator - example at http://nayyeri.net/custom-username-and-password-authentication-in-wcf-3-5.
To summarize, I usually choose Windows as the authentication mode. It is secure and simple and works for most people in an enterprise environment. If you're creating a new service and for some reason Windows cannot be used, go for Certificate or Password. If you're hooking into an older SOAP service hosted in IIS, you may need to look at using None, Basic or Digest.
Although I asked this question I will add what I know about Certificates as this is something I have worked with - though if my understanding is imperfect, I'd be happy to be corrected.
An X.509 certificate consists of a Public Key and a Private Key and issued by a trusted Certificate Authority (you can self-sign a certificate, this limits the usefulness of the certificate to trusted sources only). The CA will charge a fee for the certificate, and it will expire after a period of time.
The Public Key does not need to be protected and is given to the server. The Private Key is kept private and is used by the client. Messages encrypted by the Private Key can be decrypted by the Public Key.
A request from a client has a digital signature embedded in the SOAP. This is generated using the Private Key. When the server receives the request, it uses the Public Key to read the signature. If the signature can be read, then the request is considered genuine.
Within Active Directory, there is a mechanism whereby an X.509 certificate can be mapped to a user account, so you can impersonate a user with a certain permission set based on the X.509 authentication.
The benefits of X.509, are:
that it can be used across domains; and
that the Private Key can be securely stored in the client's Certificate Store. So there is no .config file containing credentials.
Failure to control the distribution and storage of a Private Key is akin to writing a username/password on a post-it note and sticking it on your monitor.

Categories