5

I want to the pin the public key of my server so that any request made to the server has to have that public key (this is to prevent proxies like Charles sniffing the data).

I had done something similar in Android with Volley.

How can I do the same with Flutter?

grooveplex
  • 2,492
  • 4
  • 28
  • 30
Harsh Bhikadia
  • 10,095
  • 9
  • 49
  • 70
  • Possible duplicate of [How to do SSL pinning via self generated signed certificates in flutter?](https://stackoverflow.com/questions/51323603/how-to-do-ssl-pinning-via-self-generated-signed-certificates-in-flutter) – Richard Heap Feb 16 '19 at 23:59
  • 3
    I found this before. I want to pin Public Key and not the cert. – Harsh Bhikadia Feb 17 '19 at 00:27

2 Answers2

8

Create your client with a SecurityContext with no trusted roots to force the bad certificate callback, even for a good certificate.

SecurityContext(withTrustedRoots: false);

In the bad certificate callback, parse the DER encoded certificate using the asn1lib package. For example:

ASN1Parser p = ASN1Parser(der);
ASN1Sequence signedCert = p.nextObject() as ASN1Sequence;
ASN1Sequence cert = signedCert.elements[0] as ASN1Sequence;
ASN1Sequence pubKeyElement = cert.elements[6] as ASN1Sequence;

ASN1BitString pubKeyBits = pubKeyElement.elements[1] as ASN1BitString;

List<int> encodedPubKey = pubKeyBits.stringValue;
// could stop here and compare the encoded key parts, or...

// parse them into their modulus/exponent parts, and test those
// (assumes RSA public key)
ASN1Parser rsaParser = ASN1Parser(encodedPubKey);
ASN1Sequence keySeq = rsaParser.nextObject() as ASN1Sequence;
ASN1Integer modulus = keySeq.elements[0] as ASN1Integer;
ASN1Integer exponent = keySeq.elements[1] as ASN1Integer;

print(modulus.valueAsBigInteger);
print(exponent);
Richard Heap
  • 48,344
  • 9
  • 130
  • 112
  • the library and code you mentioned is giving public key of Intermediate Certificate instead of the leaf certificate for Let's Encrypt certificate – Harsh Bhikadia Nov 13 '19 at 10:04
  • paste the der or pem into https://lapo.it/asn1js/ to confirm which ASN.1 fields you need to extract and adapt as necessary. – Richard Heap Nov 13 '19 at 10:15
  • 2
    looks like the `badCertificateCallback` is being called with the parent cert (issuer cert of Lets Encrypt) – Harsh Bhikadia Nov 13 '19 at 10:39
  • That feels like you might need to open an issue. – Richard Heap Nov 13 '19 at 10:47
  • Have posted it on gitter chat of dart. meanwhile you can look into the pem cert that i am receiving in the callback : http://shorturl.at/bwFQX – Harsh Bhikadia Nov 13 '19 at 13:27
  • 1
    as a temporary implementation I am thinking of pinning and validating the PublicKey of Let'sCrypt(5yr validity) and also checking the hostname passed in the callback if it is of the server. what do you think? – Harsh Bhikadia Nov 14 '19 at 11:14
  • as Let'sCrypt is in general a "trusted" issuer and has a good mechanism of validating the domain owner, hence we can assume that no attacker would be issued cert with my domain by LetsCrypt. Considering that i want to prevent charles procy like server to snoop the trafic. – Harsh Bhikadia Nov 14 '19 at 11:16
  • @HarshBhikadia Have you logged this issue under dart? Can you share the link here? – Sahil Patel Apr 22 '20 at 07:58
  • 1
    @SahilPatel Check this issue https://github.com/dart-lang/sdk/issues/39425 – Harsh Bhikadia Apr 23 '20 at 09:20
  • @HarshBhikadia can you please elaborate on your thinking. I am also studying these things. may be we can work together to fix these things. – Jiten Basnet Apr 24 '20 at 05:19
  • @JitenBasnet are you planning to use self signed cert? then the solution in the answer will work for you. but if you are using CA issued certificate then `badCertificateCallback` would not be called with your certificate but the certificate of the CA, which is an unexpected behaviour for which I have filed [an issue](https://github.com/dart-lang/sdk/issues/39425) – Harsh Bhikadia Apr 24 '20 at 05:26
  • @HarshBhikadia we are a payment service provider. I think of buying/registering CA issued certificate as well. Also what would that be best self signed needed to be updated client with new app when it expires or CA issued certificate ? so quite in delemma. – Jiten Basnet Apr 24 '20 at 05:40
  • if the service is also going to run on browser or something then I suggest you go with some trusted CA. – Harsh Bhikadia Apr 24 '20 at 07:11
  • Currently we want to secure the api only to know that only valid client has been using our app. yes trusted CA are recommended. One thing though,do trusted CA also provides with der,cert,pem kind of file for us after we register them so that we use them just like setting up self signed certificate ? – Jiten Basnet Apr 24 '20 at 16:35
  • Yes, with a CA you can still end up with the relevant PEM and PFX etc files. (Your private key never leaves your building, just the CSR.) Please note that certificate pinning does NOT ensure that only valid clients access the server. To achieve that you could use client side certificates, credentials, some shared secret, etc – Richard Heap Apr 24 '20 at 17:45
  • @RichardHeap can you please tell where do i buy/register client side certificate. If i use client certificate, do i need server side certification as well ? How do client side certificate make sure they are valid user, server need to have some mechanism right ? And what would that be ? – Jiten Basnet Apr 27 '20 at 04:07
  • That's not related to this question. Best to ask a new one. – Richard Heap Apr 27 '20 at 10:02
1

Key rotation reduces risk. When an attacker obtains an old server hard drive or backup file and gets an old server private key from it, they cannot impersonate the current server if the key has been rotated. Therefore always generate a new key when updating certificates. Configure the client to trust the old key and the new key. Wait for your users to update to the new version of the client. Then deploy the new key to your servers. Then you can remove the old key from the client.

Server key pinning is only needed if you're not rotating keys. That's bad security practice.

You should do certificate pinning with rotation. I have added example code in How to do SSL pinning via self generated signed certificates in flutter?

M. Leonhard
  • 1,332
  • 1
  • 18
  • 20