3

relatively new to Flutter here (and programming in general). Only familiar with the more basic stuffs but I've now encountered the need to use a CertificatePinner such as this in flutter/dart: https://square.github.io/okhttp/3.x/okhttp/okhttp3/CertificatePinner.html (I've successfully implemented this in my previous kotlin/java project in android studio). My goal is to pin public key (not certificate)

All I have is the public key in the form of a string like shown below, nothing else: "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="

How do I go about achieving this? I've asked this in an open issue on github but haven't gotten any responses yet (https://github.com/dart-lang/sdk/issues/35981). Hoping someone has managed to achieve this.

I've also scoured through other sources. I think the closest one to a solution for me is How can I do public key pinning in Flutter? but I don't quite get what is being done there and I can't comment to ask questions there since I don't have enough reputation yet.

For comparison, all I want to do is achieve the same thing in flutter/dart what I could in java/kotlin with these few lines of code:

 String hostname = "publicobject.com";
 CertificatePinner certificatePinner = new CertificatePinner.Builder()
     .add(hostname, "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
     .build();

Thanks for your help

TWH
  • 185
  • 1
  • 2
  • 11

1 Answers1

1

Start with the code in the answer you refer to. That takes the certificate in DER format and starts decoding it.

ASN1Parser p = ASN1Parser(der);
ASN1Sequence signedCert = p.nextObject() as ASN1Sequence;
ASN1Sequence cert = signedCert.elements[0] as ASN1Sequence;
ASN1Sequence pubKeyElement = cert.elements[6] as ASN1Sequence;
// this is the Subject Public Key element, which describes the type of key and actual value

For example, if we decode the certificate of pub.dev we find that it's an RSA key with a modulus of 65537 and a value of 2347......:

SEQUENCE (2 elem)
  SEQUENCE (2 elem)
    OBJECT IDENTIFIER 1.2.840.113549.1.1.1 rsaEncryption (PKCS #1)
    NULL
  BIT STRING (1 elem)
    SEQUENCE (2 elem)
      INTEGER (2048 bit) 234782553149463204049153749736864715384123240676730175743244004248041…
      INTEGER 65537

From the RFC, the SPKI fingerprint is the SHA-256 hash of this whole element.

// you need to import dart:convert and package:crypto/crypto.dart
var hash = base64.encode(sha256.convert(pubKeyElement.contentBytes()).bytes);
var spkiFingerprint = 'sha256/$hash'; // should match the value you have

Caveats

The badCertificateCallback doesn't deliver the whole certificate chain, so you can't walk up the whole chain. What's worse is that it doesn't always seem to deliver the leaf certificate! Sometimes it delivers an intermediate certificate.

Community
  • 1
  • 1
Richard Heap
  • 48,344
  • 9
  • 130
  • 112
  • Did that help? Any other questions? – Richard Heap Dec 06 '19 at 21:49
  • Sorry just got a chance to get back to this. I think it worked. I definitely managed to produce a string in the form I expected ("sha256/AAAAA....."). But it seems to be a different one from the key I receive when I check it from my kotlin version of the app pinning the same url. It could be one of the caveats you mentioned. Regardless, thanks a lot for your help! – TWH Dec 07 '19 at 18:33
  • 1
    oh, also. it seems that I had to change this line: ```var hash = base64.encode(sha256.convert(pubKeyElement.contentBytes()));``` into ```var hash = base64.encode(sha256.convert(pubKeyElement.contentBytes()).bytes);``` I hope that doesn't cause the unintended result? (I had to do that because it gave an error "The argument type 'Digest' can't be assigned to the parameter type 'List'" without the .bytes at the end) – TWH Dec 07 '19 at 18:36
  • Yes, try printing `certificate.subject` to see if you got the correct certificate in the callback. – Richard Heap Dec 07 '19 at 18:36
  • Yeah got the right certificate (one of it from the chain at least), but they key still seems to be different. – TWH Dec 07 '19 at 18:41
  • I'll try to fiddle around while I'm working on this. Will update if I find out anything that seems useful. – TWH Dec 07 '19 at 18:54
  • I think the certificate I got from the callback is an intermediary one (as you warned). Also, i tried converting every element of the certificate instead of just the 7th one and then printing the hash. Still none of them matches the supposed value that I logged from the other control app. – TWH Dec 07 '19 at 19:13
  • hi @TWH I have same problem as you, did you managed to get the right certificate? – Tiago Santos Aug 25 '20 at 10:18