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.
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/ .
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;
}
}
Codage d'OID pour les nuls :):
Il s'agit d'une reformulation de la recommandation de l'UIT-T X.69, chapitre 8.19
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)