How to manually verify signatures on x509 certificates in Flutter/Dart

595

I am doing this using x509b package from pub.dev. The original x509 package is seemingly not updated anymore and uses an outdated version of asn1lib. In my version I am using both x509 and asn1lib itself. Pretty sure there are cleaner/more performant ways, but this does the trick for me.

I also use the extracted public key from my root certificate directly instead of using the entire certificate, but I am sure you can also do that step with these libraries.

The tbsCertificate property from x509 library seems wrong, so I extract the TBS Certificate part manually using ASN1Parser.

The decodePEM function was taken from the example in asn1lib repo.

import 'dart:convert';
import 'dart:typed_data';
import 'package:x509b/x509.dart' as x509;
import 'package:asn1lib/asn1lib.dart';

bool verifyCertificate() {
    var strX1PublicKeyInfo = "-----BEGIN PUBLIC KEY-----\nSOME PUBLIC KEY\n-----END PUBLIC KEY-----";
    var strX2Certificate = "-----BEGIN CERTIFICATE-----\nSOME CERTIFICATE\n-----END CERTIFICATE-----";

    var x1PublicKey = (x509.parsePem(strX1PublicKeyInfo).single as x509.SubjectPublicKeyInfo).subjectPublicKey as x509.RsaPublicKey;
    var x2Certificate = x509.parsePem(strX2Certificate).single as x509.X509Certificate;
    var x2CertificateDER = decodePEM(strX2Certificate);

    var asn1Parser = ASN1Parser(x2CertificateDER);
    var seq = asn1Parser.nextObject() as ASN1Sequence;
    var tbsSequence = seq.elements[0] as ASN1Sequence;

    var signature = x509.Signature(Uint8List.fromList(x2Certificate.signatureValue!));
    var verifier = x1PublicKey.createVerifier(x509.algorithms.signing.rsa.sha256);

    return verifier.verify(tbsSequence.encodedBytes, signature)
}

Uint8List decodePEM(pem) {
  var startsWith = [
    '-----BEGIN PUBLIC KEY-----',
    '-----BEGIN PRIVATE KEY-----',
    '-----BEGIN CERTIFICATE-----',
  ];
  var endsWith = [
    '-----END PUBLIC KEY-----',
    '-----END PRIVATE KEY-----',
    '-----END CERTIFICATE-----'
  ];

  //HACK
  for (var s in startsWith) {
    if (pem.startsWith(s)) pem = pem.substring(s.length);
  }

  for (var s in endsWith) {
    if (pem.endsWith(s)) pem = pem.substring(0, pem.length - s.length);
  }

  //Dart base64 decoder does not support line breaks
  pem = pem.replaceAll('\n', '');
  pem = pem.replaceAll('\r', '');
  return Uint8List.fromList(base64.decode(pem));
}
Share:
595
Eugene Alitz
Author by

Eugene Alitz

Updated on December 25, 2022

Comments

  • Eugene Alitz
    Eugene Alitz over 1 year

    I have two X509Certificate objects x1(root) and x2 in .pem format.

    I want to verify that x2 was signed by x1 manually.

    How to exactly do this in Flutter/Dart?

    I found this article, but all operations there is done in terminal with openssl and at some stage there is need to convert .pem to .der for extracting of signature from the certificate.

    Also i know that C# have such methodfor verifying and i cannot find any analog in the flutter/dart

    • Marco7757
      Marco7757 over 2 years
      Did you ever find an answer to this problem?