web-dev-qa-db-fra.com

Comment ASN1 code est-il un identifiant d'objet?

J'ai du mal à comprendre les concepts de base d'ASN.1.

Si un type est un OID, le nombre correspondant est-il réellement codé dans les données binaires?

Par exemple dans cette définition:

id-ad-ocsp         OBJECT IDENTIFIER ::= { id-ad 1 }

Est-ce que le 1.3.6.1.5.5.7.48.1 correspondant est-il codé dans le binaire exactement comme celui-ci?

Je demande cela parce que j'essaie de comprendre une valeur spécifique que je vois dans un fichier DER (un certificat), qui est 04020500, et je ne sais pas comment l'interpréter.

23
Cratylus

Oui, le OID est codé dans les données binaires. OID 1.3.6.1.5.5.7.48.1 Vous mentionnez devient 2B 06 01 05 05 07 30 01 (les deux premiers numéros sont codés dans un seul octet, tous les numéros restants sont codés dans un octet unique comme bien parce qu'ils sont tous plus petits que 128).

Une belle description de OID coding est trouvée ici .

Mais la meilleure façon d'analyser vos données ASN.1 est de coller dans un décodeur en ligne, par exemple. http://lapo.it/astn1js/ .

37
Codo

Si tous vos chiffres sont inférieurs ou égaux à 127, vous êtes très Lucky parce qu'ils peuvent être représentés avec un seul octet chacun. La partie délicate est lorsque vous avez des nombres plus importants qui sont courants, tels que 1.2.840.113549.1.1.5 (sha1WithRsaEncryption). Ces exemples se concentrent sur le décodage, mais le codage n'est que le contraire.

1. Les deux premiers "chiffres" sont représentés avec un octet unique

Vous pouvez décoder en lisant le premier octet dans un entier

var firstByteNumber = 42;
var firstDigit = firstByteNumber / 40;
var secondDigit = firstByteNumber % 40;

Produit les valeurs

1.2

2. Les octets ultérieurs sont représentés à l'aide de Quantité de longueur variable , également appelée base 128.

VLQ a deux formes,

Formulaire court - Si l'octet démarre avec 0, il est simplement représenté à l'aide des 7 bits restants.

Forme longue - si l'octet commence avec un 1 (le plus important de bit), combinez les 7 prochains bits de cet octet plus les 7 bits de chaque octet suivant jusqu'à ce que vous rencontriez un octet avec un 0 comme le bit le plus significatif (ceci marque le dernier octet).

La valeur 840 serait représentée avec les deux octets suivants,

10000110
01001000

Combine to 00001101001000 and read as int.

Grande ressource pour le codage BER, http://luca.ntop.org/teaching/appunti/astn1.html

Le premier octet a la valeur 40 * Value1 + Value2. (Ceci est sans ambiguïté, car la valeur1 est limitée aux valeurs 0, 1 et 2; la valeur2 est limitée à la plage 0 à 39 lorsque la valeur1 est 0 ou 1; et, selon X.208, N est toujours au moins 2.)

Les octets suivants, le cas échéant, encodent la valeur3, ..., valuen. Chaque valeur est codée de base 128, la plupart des chiffres significatifs d'abord, avec autant de chiffres que possible et le bit le plus significatif de chaque octet, à l'exception de la dernière partie de l'encodage de la valeur sur "1." Exemple: le premier octet de l'encodage BER de RSA Data Security, l'identificateur d'objet Inc. est de 40 * 1 + 2 = 42 = 2A16. Le codage de 840 = 6 * 128 + 4816 est 86 48 et le codage de 113549 = 6 * 1282 + 7716 * 128 + D16 est 86 F7 0D. Cela conduit à l'encodage BER suivant:

06 06 2A 86 48 86 F7 0D


Enfin, voici un OID décodeur que je viens d'écrire à Perl.

sub getOid {
    my $bytes = shift;

    #first 2 nodes are 'special';
    use integer;
    my $firstByte = shift @$bytes;
    my $number = unpack "C", $firstByte;
    my $nodeFirst = $number / 40;
    my $nodeSecond = $number % 40;

    my @oidDigits = ($nodeFirst, $nodeSecond);

    while (@$bytes) {
        my $num = convertFromVLQ($bytes);
        Push @oidDigits, $num;
    }

    return join '.', @oidDigits;
}

sub convertFromVLQ {
    my $bytes = shift;

    my $firstByte = shift @$bytes;
    my $bitString = unpack "B*", $firstByte;

    my $firstBit = substr $bitString, 0, 1;
    my $remainingBits = substr $bitString, 1, 7;

    my $remainingByte = pack "B*", '0' . $remainingBits;
    my $remainingInt = unpack "C", $remainingByte;

    if ($firstBit eq '0') {
        return $remainingInt;
    }
    else {
        my $bitBuilder = $remainingBits;

        my $nextFirstBit = "1";
        while ($nextFirstBit eq "1") {
            my $nextByte = shift @$bytes;
            my $nextBits = unpack "B*", $nextByte;

            $nextFirstBit = substr $nextBits, 0, 1;
            my $nextSevenBits = substr $nextBits, 1, 7;

            $bitBuilder .= $nextSevenBits;
        }

        my $MAX_BITS = 32;
        my $missingBits = $MAX_BITS - (length $bitBuilder);
        my $padding = 0 x $missingBits;
        $bitBuilder = $padding . $bitBuilder;

        my $finalByte = pack "B*", $bitBuilder;
        my $finalNumber = unpack "N", $finalByte;
        return $finalNumber;
    }

}
17
Despertar

Codage d'OID pour les nuls :):

  • chaque OID composant est codé sur un ou plusieurs octets (octets)
  • L'encodage OID n'est qu'une concaténation de ces OID Coodingings
  • les deux premiers composants sont codés de manière particulière (voir ci-dessous)
  • if OID Valeur binaire de composant comporte moins de 7 bits, le codage est juste un seul octet, en maintenant la valeur du composant (note, le bit le plus significatif, le plus à gauche, sera toujours 0)
  • sinon, si elle a 8 bits et plus, la valeur est "étendue" en plusieurs octets - divisez la représentation binaire en 7 morceaux (à droite), le pad gauche de la première avec des zéros si nécessaire et former des octets de ces septeces. En ajoutant le plus important (gauche) Bit 1, sauf du dernier morceau, qui aura un peu 0 là-bas.
  • les deux premiers composants (X.Y) sont codés comme un seul composant avec une valeur 40 * x + y

Il s'agit d'une reformulation de la recommandation de l'UIT-T X.69, chapitre 8.19

11
mykhal

Ceci est un fichier simpliste Python 3 Mise en œuvre de ce qui précède, resp. Une forme de chaîne d'un identificateur d'objet dans la forme ASN.1 DER ou BER.

def encode_variable_length_quantity(v:int) -> list:
    # Break it up in groups of 7 bits starting from the lowest significant bit
    # For all the other groups of 7 bits than lowest one, set the MSB to 1
    m = 0x00
    output = []
    while v >= 0x80:
        output.insert(0, (v & 0x7f) | m)
        v = v >> 7
        m = 0x80
    output.insert(0, v | m)
    return output

def encode_oid_string(oid_str:str) -> Tuple:
    a = [int(x) for x in oid_str.split('.')]
    oid = [a[0]*40 + a[1]] # First two items are coded by a1*40+a2
    # A rest is Variable-length_quantity
    for n in a[2:]:
        oid.extend(encode_variable_length_quantity(n))
    oid.insert(0, len(oid)) # Add a Length
    oid.insert(0, 0x06) # Add a Type (0x06 for Object Identifier)
    return Tuple(oid)

if __name__ == '__main__':
    oid = encode_oid_string("1.2.840.10045.3.1.7")
    print(oid)
2
Ales Teska