SubjectPublicKeyInfo.decode constructor

SubjectPublicKeyInfo.decode(
  1. Uint8List bytes, {
  2. required PubTextSource? source,
})

Decode from a sequence of bytes.

Implementation

SubjectPublicKeyInfo.decode(Uint8List bytes, {required this.source}) {
  String msg;

  try {
    // Parse the bytes as ASN.1

    List<ASN1Object> objects;

    try {
      objects = _asn1parseAll(bytes);
    } catch (e) {
      throw _SpkiMsg('bad ASN.1 encoding: $e');
    }

    // There must be only one top-level object

    if (objects.isEmpty) {
      throw _SpkiMsg(
          'no top-level objects (expecting 1, got ${objects.length})');
    }
    if (objects.length != 1) {
      throw _SpkiMsg(
          'too many top-level objects (expecting 1, got ${objects.length})');
    }

    // The top-level object must be a sequence of two items

    if (objects.first is! ASN1Sequence) {
      throw _SpkiMsg('top-level object is not a sequence');
    }
    // ignore: avoid_as
    final topSequence = objects.first as ASN1Sequence;

    if (topSequence.elements.length != 2) {
      throw _SpkiMsg('top-level sequence does not contain 2 items');
    }

    // 1. Algorithm information

    final a = topSequence.elements[0];

    if (a is! ASN1Sequence) {
      throw _SpkiMsg('algorithm-info is not a sequence');
    }
    final algorithmInfo = a;

    if (algorithmInfo.elements.isEmpty) {
      throw _SpkiMsg('algorithm-info is empty');
    }

    // First algorithm parameter is an OID that identifies the algorithm

    final a1 = algorithmInfo.elements[0];
    if (a1 is! ASN1ObjectIdentifier) {
      throw _SpkiMsg('algorithm-info does not contain OID');
    }
    algorithmOid = a1.identifier!;

    // Save rest of the algorithm parameters

    algorithmParameters = <ASN1Object>[];

    for (var i = 1; i < algorithmInfo.elements.length; i++) {
      algorithmParameters.add(algorithmInfo.elements[i]);
    }

    // 2. The data

    final bits = topSequence.elements[1];

    if (bits is! ASN1BitString) {
      throw _SpkiMsg('publicKey is not a bit string: ${bits.runtimeType}');
    }
    // ignore: avoid_as
    data = Uint8List.fromList(bits.stringValue);

    return; // success
  } on _SpkiMsg catch (e) {
    msg = e.message;
  } catch (e) {
    msg = 'unexpected: $e';
  }

  throw KeyBad('invalid public key: $msg');
}