Opened 5 years ago

Closed 5 years ago

Last modified 2 years ago

#13042 closed defect (fixed)

torspec isn't very clear about the encodings used for `onion-key` and `signing-key`

Reported by: isis Owned by:
Priority: Medium Milestone: Tor: 0.2.6.x-final
Component: Core Tor/Tor Version:
Severity: Keywords: leekspin, stem, bridgedb, tor-descriptors, tor-spec
Cc: Sebastian, atagar, isis, nickm Actual Points:
Parent ID: Points:
Reviewer: Sponsor:

Description

Currently, in dir-spec.txt, it is specified that:

    "signing-key" NL a public key in PEM format

       [Exactly once]

       The OR's long-term identity key.  It MUST be 1024 bits.

and

    "onion-key" NL a public key in PEM format

       [Exactly once]

       This key is used to encrypt CREATE cells for this OR.  The key MUST be
       accepted for at least 1 week after any new key is published in a
       subsequent descriptor. It MUST be 1024 bits.

However, according to this commit added to Stem in #5810, verifying signatures created with the signing-key isn't so easy. With that code, Stem is able to verify descriptor signatures created by Tor, yet not those created by Leekspin, which clearly means the spec is unclear on this matter (and Leekspin is Doing It Wrong).

My current understanding after looking at crypto_pk_public_checksig() in Tor, the OpenSSL source, and Stem's signature verification code above is that the signing-key and onion-key are formatted as follows:

  1. OpenSSL PEM-encoded export of public halves of keys.
  2. The PEM-encoded keys are stripped of their ----BEGIN... and -----END... headers.
  3. The keys are then PKCS#1 padded.
  4. Next, the PKCS#1-padded, PEM-encoded raw keys are encoded as an ASN.1 DER sequence.
  5. That ASN.1 DER sequence is then base64 encoded.
  6. Finally, the -----BEGIN... and -----END... headers are stuck back on the keys, and they are shoved into the descriptor.


Questions:

  • Is the above understanding of the order of encodings correct?
  • Which version of PCKS#1? Any version? Anything newer than v1.5? Only v2.0?
  • I understand the use of PKCS#1 to protect against padding attacks, but doesn't Bleichenbacher's attack still work against PKCS#1 v1.0?
  • Why aren't we using the PKCS#1 probabilistic signature schemes (RSASSA-PSS/EMSA-PSS) used in PKCS#1 v2.0?
  • For the signatures, the descriptor document "through the newline on the router-signature line" is PKCS#1-padded, then digested. Does this include the newline character?
  • Also, the spec is unclear as to whether
    1. the descriptor document is PKCS#1-padded, then digested, then signed,
    or
    1. the descriptor document is digested, then signed, and the signature is PKCS#1-padded.
      "router-signature" NL Signature NL
      
         [At end, exactly once]
      
         The "SIGNATURE" object contains a signature of the PKCS1-padded
         hash of the entire router descriptor, taken from the beginning of the
         "router" line, through the newline after the "router-signature" line.
         The router descriptor is invalid unless the signature is performed
         with the router's identity key.
      
  • Is it any specific type of ASN.1 DER sequence?
  • Why are we using ASN.1? Does it protect against something? It just seems to send parsers to early graves. Why can't we just do the base64 encoding after PKCS#1?
  • Why? Oh why? Cthulhu fhtagn... Why? The insanity...

Child Tickets

Change History (5)

comment:1 in reply to:  description Changed 5 years ago by nickm

Replying to isis:

Currently, in dir-spec.txt, it is specified that:

    "signing-key" NL a public key in PEM format

       [Exactly once]

       The OR's long-term identity key.  It MUST be 1024 bits.

and

    "onion-key" NL a public key in PEM format

       [Exactly once]

       This key is used to encrypt CREATE cells for this OR.  The key MUST be
       accepted for at least 1 week after any new key is published in a
       subsequent descriptor. It MUST be 1024 bits.

However, according to this commit added to Stem in #5810, verifying signatures created with the signing-key isn't so easy. With that code, Stem is able to verify descriptor signatures created by Tor, yet not those created by Leekspin, which clearly means the spec is unclear on this matter (and Leekspin is Doing It Wrong).

My current understanding after looking at crypto_pk_public_checksig() in Tor, the OpenSSL source, and Stem's signature verification code above is that the signing-key and onion-key are formatted as follows:

  1. OpenSSL PEM-encoded export of public halves of keys.
  2. The PEM-encoded keys are stripped of their ----BEGIN... and -----END... headers.
  3. The keys are then PKCS#1 padded.
  4. Next, the PKCS#1-padded, PEM-encoded raw keys are encoded as an ASN.1 DER sequence.
  5. That ASN.1 DER sequence is then base64 encoded.
  6. Finally, the -----BEGIN... and -----END... headers are stuck back on the keys, and they are shoved into the descriptor.


Questions:

  • Is the above understanding of the order of encodings correct?

That sounds pretty weird. It's just whatever PEM_write_bio_RSAPublicKey does. That's documented in the "pem" manpage for openssl. (in the openssl distro as doc/crypto/pem.pod). That seems to be implemented in terms of a bunch of macros in crypto/pem/pem.h, which then use i2d_RSAPublicKey. Those are just doing asn.1 encoding/decoding, as implemented in crypto/rsa/rsa_ameth.h

No, it's not exactly pretty, but asn.1 never is.

  • Which version of PCKS#1? Any version? Anything newer than v1.5? Only v2.0?

Do they encode RSA public keys differently?

  • I understand the use of PKCS#1 to protect against padding attacks, but doesn't Bleichenbacher's attack still work against PKCS#1 v1.0?

That's not relevant for key encoding, surely?

Also, it's not relevant for signatures; only encryption.

  • Why aren't we using the PKCS#1 probabilistic signature schemes (RSASSA-PSS/EMSA-PSS) used in PKCS#1 v2.0?

PSS wasn't widely available enough when we started making server descriptors. The reason we don't change is that we don't use RSA to sign anything secret and then reveal the signature without the secret.

  • For the signatures, the descriptor document "through the newline on the router-signature line" is PKCS#1-padded, then digested. Does this include the newline character?

Yes.

  • Also, the spec is unclear as to whether
    1. the descriptor document is PKCS#1-padded, then digested, then signed,
    or
    1. the descriptor document is digested, then signed, and the signature is PKCS#1-padded.

Digest, then pad, then sign. (Padding a signature does no good and protects against nothing.)

"router-signature" NL Signature NL

   [At end, exactly once]

   The "SIGNATURE" object contains a signature of the PKCS1-padded
   hash of the entire router descriptor, taken from the beginning of the
   "router" line, through the newline after the "router-signature" line.
   The router descriptor is invalid unless the signature is performed
   with the router's identity key.
  • Is it any specific type of ASN.1 DER sequence?
  • Why are we using ASN.1? Does it protect against something? It just seems to send parsers to early graves. Why can't we just do the base64 encoding after PKCS#1?

I think you might be confusing encoding and padding? We don't use ASN.1 in generating signatures; we're only using it for key encoding. Similarly, we don't use PKCS1 padding for encoding keys; we only use it the signatures here.

The reason "why" is "that's how openssl likes to encode public keys."

  • Why? Oh why? Cthulhu fhtagn... Why? The insanity...

You write a protocol, maintain it for a decade, and this kind of thing seems bound to happen...

Or to be more constructive ...This is the perfect opportunity for you to review proposals 220 and 228, since they are about to add new signature types, and look for ambiguities. (224 too if you're feeling brave) ;)

comment:2 Changed 5 years ago by nickm

Keywords: tor-spec added
Milestone: Tor: 0.2.6.x-final

comment:3 Changed 5 years ago by nickm

Resolution: fixed
Status: newclosed

Clarified in tor-spec a bit.

comment:4 Changed 2 years ago by teor

Keywords: torspec, leekspin, stem, bridgedb, tor-descriptors tor-spectorspec, leekspin, stem, bridgedb, tor-descriptors, tor-spec

Consistently use tor-spec across all tickets (add tor-spec).

comment:5 Changed 2 years ago by teor

Keywords: torspec removed

Consistently use tor-spec across all tickets (remove torspec).

Note: See TracTickets for help on using tickets.