2011-05-08 14 views
17

Tengo problemas para entender los conceptos básicos de ASN.1.¿Cómo codifica ASN.1 un identificador de objeto?

Si un tipo es un OID, ¿se codifica realmente el número correspondiente en los datos binarios?

Por ejemplo, en esta definición:

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

¿El 1.3.6.1.5.5.7.48.1 correspondiente conseguir codificada en binario exactamente como esta?

Pregunto esto porque estoy tratando de comprender un valor específico que veo en un archivo DER (un certificado), que es 04020500, y no estoy seguro de cómo interpretarlo.

Respuesta

26

Sí, el OID está codificado en los datos binarios. El OID 1.3.6.1.5.5.7.48.1 que mencionas se convierte en 2b 06 01 05 05 07 30 01 (los dos primeros números están codificados en un solo byte, todos los números restantes también están codificados en un solo byte porque son todos más pequeño que 128).

Se encuentra una buena descripción de la codificación OID here.

Pero la mejor manera de analizar sus datos ASN.1 es pegarlos en un decodificador en línea, p. http://lapo.it/asn1js/.

+1

+1 para el decodificador asn.1. Gracias. si solo hubiera sabido entonces ... :-) –

+0

Pero, ¿cómo puedo saber cuál es un valor válido para un OID específico? En mi caso para OID 1.3.6.1.5.5.7.48.1.5 el valor (según entiendo) es 04020500. ¿Tiene una interpretación específica? – Cratylus

+0

Fuera del contexto, es muy difícil decir qué es 04020500. No parece un OID en absoluto. – Codo

13

Si todos los dígitos son inferiores o iguales a 127, entonces son muy suerte, ya que pueden ser representados con un solo octeto cada uno. La parte difícil es cuando tienes números más grandes que son comunes, como 1.2.840.113549.1.1.5 (sha1WithRsaEncryption). Estos ejemplos se centran en la decodificación, pero la codificación es todo lo contrario.

1. Los primeros dos dígitos '' se representan con un solo byte

Puede decodificar mediante la lectura del primer byte en un entero

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

produce los valores

1.2 

2. Los bytes subsiguientes se representan utilizando Variable Length Quantity, también llamada base 128.

VLQ tiene dos formas,

forma corta - Si el octeto comienza con 0, entonces simplemente se representa usando los 7 bits restantes.

Forma larga: si el octeto comienza con 1 (el bit más significativo), combine los siguientes 7 bits de ese octeto más los 7 bits de cada octeto subsiguiente hasta que encuentre un octeto con un 0 como el bit más significativo (esto marca el último octeto).

El valor 840 estaría representado con los dos bytes siguientes,

10000110 
01001000 

Combine to 00001101001000 and read as int. 

gran recurso para codificación BER, http://luca.ntop.org/Teaching/Appunti/asn1.html

El primer octeto tiene un valor 40 * valor1 + valor2.(Esto no es ambiguo, ya que value1 está limitado a los valores 0, 1 y 2; value2 está limitado a el rango 0 a 39 cuando value1 es 0 o 1; y, de acuerdo con X.208, n es siempre al menos 2.)

Los siguientes octetos, si los hay, codifican value3, ..., valuen. Cada valor está codificado en la base 128, el dígito más significativo primero, con el menor número posible de dígitos, y el bit más significativo de cada octeto, excepto el último en la codificación del valor establecido en "1". Ejemplo: El primer octeto de la codificación BER del identificador del objeto de RSA Data Security, Inc. es 40 * 1 + 2 = 42 = 2a16. La codificación de 840 = 6 * 128 + 4816 es 86 48 y la codificación de 113549 = 6 * 1282 + 7716 * 128 + d16 es 86 f7 0d. Esto lleva a la siguiente codificación BER:

06 06 86 48 86 2a f7 0d


Por último, aquí es un decodificador OID que acabo de escribir en 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; 
    } 

} 
+2

No estoy seguro de que su código para decodificar los dos primeros dígitos sea correcto. Considere el ejemplo de T-REC-X.690 de {2 100 3}.Para eso, el primer byte sería 180. Por lo tanto, para decodificar parece que su solución funciona si el primer byte es menor que 80. Cualquier cantidad mayor o igual a 80 significa que el primer dígito es 2, y el segundo se puede encontrar al restar 80. –

7

codificación OID para los maniquíes :):

  • cada componente OID se codifica a uno o más bytes (octetos)
  • codificación OID es sólo una concatenación de estas codificaciones de componentes OID
  • los dos primeros componentes están codificados de una manera especial (ver a continuación)
  • si el valor binario del componente OID tiene menos de 7 bits, la codificación es solo un octeto y mantiene el valor del componente (nota, mo st bit significativo, leftmost, siempre será 0)
  • de lo contrario, si tiene 8 y más bits, el valor se "disemina" en octetos múltiples - divide la representación binaria en trozos de 7 bits (desde la derecha), left-pad el primero con ceros si es necesario, y forma octetos de estos septetos agregando el bit 1 más significativo (izquierda), excepto desde el último trozo, que tendrá el bit 0 allí.
  • dos primeros componentes (XY) se codifican como que es un solo componente con un valor 40 * X + Y

Esta es una nueva formulación de la UIT-T Recomendación X.690 , capítulo 8,19

+0

Acabo de escribir el código para OID en VBA, lo escribí dos veces porque la documentación de Microsoft es incorrecta. Ahora que tengo una versión en funcionamiento, puedo dar fe de que esta es la mejor respuesta. Voto ascendente. –

Cuestiones relacionadas