Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add totally untested OMAC1-AES, CT-KIP-PRF-{AES,SHA256} #47

Closed
wants to merge 1 commit into from

Conversation

cemeyer
Copy link

@cemeyer cemeyer commented Sep 7, 2018

Add totally untested implementations of the OMAC1-AES ("CMAC") and
CT-KIP-PRF-* family of pseudo-random functions per relevant RFCs. It
compiles but that's about all I've tested.

Broken:

  • Only supports tomcrypt
  • Untested!!!
  • Mallocs in PRF-SHA256 variant to work around missing iterative
    sha256-hmac. Could add iterative hmac instead and skip malloc.

Re: #27

(Not necessarily useful to pull as-is, but may be useful as a starting place.)

@dlenski
Copy link

dlenski commented Sep 7, 2018

These Vary Speshul MAC Functions are so utterly solution-in-search-of-a-problem that I sorta doubt anyone is using the sha256 versions.

I presume that RSA really wants to use AES-based MAC because they make a bunch of hardware devices that can't really do anything except AES. Their software token only offers up the AES version in the list of algorithms it supports … so I wouldn't spend much time on the SHA256 version.

The RFC doesn't even contain test vectors for the CT-KIP-PRF-AES function. 👎

@cemeyer
Copy link
Author

cemeyer commented Sep 7, 2018

These are really PRFs, not MACs, right?

Sounds like we can just drop SHA for now; it's a pretty trivial extension of the same algorithm.

I have no idea what RSA is doing with them, though. I noticed the RFC lacked test vectors :-(.

@dlenski
Copy link

dlenski commented Sep 7, 2018

These are really PRFs, not MACs, right?

It's sort of unclear. The RFC really wants to call it a MAC.

Here's a slightly-commented version of the interesting parts of the client/server exchange, from my fakeserver.py, after removing the topmost layer of crud (base64 the whole XML doc, wrap it in SOAP).

  • Client→server: "Hello, I support these algorithms"
<ClientHello xmlns="http://www.rsasecurity.com/rsalabs/otps/schemas/2005/11/ct-kip#" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Version="1.0">
  <SupportedKeyTypes xmlns="">
    <Algorithm xsi:type="xsd:anyURI">http://www.rsasecurity.com/rsalabs/otps/schemas/2005/09/otps-wst#SecurID-AES</Algorithm>
  </SupportedKeyTypes>
  <SupportedEncryptionAlgorithms xmlns="">
    <Algorithm xsi:type="xsd:anyURI">http://www.w3.org/2001/04/xmlenc#rsa-1_5</Algorithm>
  </SupportedEncryptionAlgorithms>
  <SupportedMACAlgorithms xmlns="">
    <Algorithm xsi:type="xsd:anyURI">http://www.rsasecurity.com/rsalabs/otps/schemas/2005/11/ct-kip#ct-kip-prf-aes</Algorithm>
  </SupportedMACAlgorithms>
</ClientHello>
  • Server→Client: "Hello back, here is my 1024-bit RSA public key, and a cleartext nonce." And by cleartext I mean wrapped in 2 layers of base64 and 2 layers of XML with random namespaces, golly what fun.
<ServerHello xmlns="http://www.rsasecurity.com/rsalabs/otps/schemas/2005/12/ct-kip#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" SessionID="{sess}" Status="Continue" Version="1.0">
  <KeyType xmlns="">http://www.rsasecurity.com/rsalabs/otps/schemas/2005/09/otps-wst#SecurID-AES</KeyType>
  <EncryptionAlgorithm xmlns="">http://www.w3.org/2001/04/xmlenc#rsa-1_5</EncryptionAlgorithm>
  <EncryptionKey xmlns="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <ds:KeyValue xmlns="http://www.rsasecurity.com/rsalabs/otps/schemas/2005/12/ct-kip#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <!-- Server sends a 1024-byte RSA pubkey -->
      <ds:RSAKeyValue xmlns="http://www.rsasecurity.com/rsalabs/otps/schemas/2005/12/ct-kip#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <ds:Modulus>{mod}</ds:Modulus>
        <ds:Exponent>{exp}</ds:Exponent>
      </ds:RSAKeyValue>
    </ds:KeyValue>
  </EncryptionKey>
  <Payload xmlns="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <!-- Server sends a 16-byte nonce -->
    <Nonce xmlns="">{rb}</Nonce>
  </Payload>
  <Extensions xmlns="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Extension xmlns:ct-kip="http://www.rsasecurity.com/rsalabs/otps/schemas/2005/12/ct-kip#" xmlns="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <!-- Server repeats the same 16-byte nonce here -->
      <Data>{rb}</Data>
    </Extension>
  </Extensions>
  <MacAlgorithm xmlns="">http://www.rsasecurity.com/rsalabs/otps/schemas/2005/11/ct-kip#ct-kip-prf-aes</MacAlgorithm>
</ServerHello>
  • Client→Server: "Here is my 16-byte nonce, encrypted with the RSA public key you sent, using PKCS#1 OAEP padding."
<ClientNonce xmlns="http://www.rsasecurity.com/rsalabs/otps/schemas/2005/11/ct-kip#" Version="1.0" SessionID="$SESSIONID">
  <EncryptedNonce xmlns="">
    base64(  PKCS #1 OAEP encypt( RSA public key sent by server, 16-byte client nonce ) )
  </EncryptedNonce>
  <Extensions xmlns="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Extension xmlns="" xmlns:ct-kip="http://www.rsasecurity.com/rsalabs/otps/schemas/2005/12/ct-kip#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <!-- This simply echoes the value sent previously by the server -->
      <Data>base64(16-byte server nonce)</Data>
    </Extension>
  </Extensions>
</ClientNonce>
  • Server→Client: "I have taken your 16-byte nonce and my 16-byte nonce and combined them using some VARY SPESHUL ALGRRRITHUMS to create the token secret. Here is a bunch of other formulaic information about the token in plaintext. I am going to prove to you that everything went smoothly by attaching a MAC."
<ServerFinished xmlns="http://www.rsasecurity.com/rsalabs/otps/schemas/2005/12/ct-kip#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" SessionID="{sess}" Status="Success" Version="1.0">
  <TokenID xmlns="">{tid}</TokenID>
  <KeyID xmlns="">{tid}</KeyID>
  <KeyExpiryDate xmlns="">{exp}</KeyExpiryDate>
  <ServiceID xmlns="">RSA CT-KIP</ServiceID>
  <UserID xmlns=""/>
  <Extensions xmlns="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Extension xmlns="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Critical="true">
      <OTPFormat>Decimal</OTPFormat>
      <OTPLength>8</OTPLength>
      <OTPMode xmlns="http://www.rsasecurity.com/rsalabs/otps/schemas/2005/12/ct-kip#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
        <Time xmlns="http://www.rsasecurity.com/rsalabs/otps/schemas/2005/12/ct-kip#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" TimeInterval="60"/>
      </OTPMode>
    </Extension>
  </Extensions>
  <Mac xmlns="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" MacAlgorithm="http://www.rsasecurity.com/rsalabs/otps/schemas/2005/12/ct-kip#ct-kip-prf-aes">
    <!-- This is where all the securiteh goes -->
    {rmb}
  </Mac>
</ServerFinished>

So here's what RFC4758 has to say about this MAC:

https://tools.ietf.org/html/rfc4758#section-3.8.6:

: To avoid a false "Commit" message causing the token to end
up in an initialized state for which the server does not know the
stored key, messages must always be authenticated
with a MAC. The MAC shall be made using the already established
MAC algorithm. The MAC value shall be computed on the (ASCII)
string "MAC 2 computation" and R_C using an authentication key
K_AUTH. Again, this should be a special authentication key used
only for this purpose, but may also be an existing K_TOKEN. (In
this case, implementations must protect against attacks where
K_TOKEN is used to pre-compute MAC values.) If no authentication
key is present in the token, and no K_TOKEN existed before the CT-
KIP run, K_AUTH shall be the newly generated K_TOKEN.

If CT-KIP-PRF is used as the MAC algorithm, then the input
parameter s shall consist of the concatenation of the (ASCII)
string "MAC 2 computation" and R_C, and the parameter dsLen shall
be set to the length of R_C:

dsLen = len(R_C)

MAC = CT-KIP-PRF (K_AUTH, "MAC 2 computation" || R_C, dsLen)

When receiving a message with Status = "Success"
for which the MAC verifies, the CT-KIP client shall associate the
generated key K_TOKEN with the provided key identifier and store
this data permanently. After this operation, it shall not be
possible to overwrite the key unless knowledge of an authorizing
key is proven through a MAC on a later (and
) message.

The CT-KIP client must verify the MAC. The CT-KIP client must
terminate the CT-KIP session if the MAC does not verify, and must,
in this case, also delete any nonces, keys, and/or secrets
associated with the failed run of the CT-KIP protocol.

The MacType's MacAlgorithm attribute shall, when present, identify
the negotiated MAC algorithm.

where (https://tools.ietf.org/html/rfc4758#section-2.2):

K_AUTH Secret key used for authentication purposes
K_TOKEN Secret key used for token computations, generated in CT-KIP

My interpretation of the bolded part is that, when creating a new token, the key used for the MAC K_AUTH is the same as the key value used in the token itself at the conclusion of the exchange K_TOKEN.

Except that this diagram (Figure 2 in https://tools.ietf.org/html/rfc4758#section-3.3) suggests that the server's public key, and the client and server nonces (R_C and R_S) should be enough to derive the key.

   +----------------------+    +-------+     +----------------------+
   |    +------------+    |    |       |     |                      |
   |    | Server key |    |    |       |     |                      |
   | +<-|  Public    |------>------------->-------------+---------+ |
   | |  |  Private   |    |    |       |     |          |         | |
   | |  +------------+    |    |       |     |          |         | |
   | |        |           |    |       |     |          |         | |
   | V        V           |    |       |     |          V         V |
   | |   +---------+      |    |       |     |        +---------+ | |
   | |   | Decrypt |<-------<-------------<-----------| Encrypt | | |
   | |   +---------+      |    |       |     |        +---------+ | |
   | |      |  +--------+ |    |       |     |            ^       | |
   | |      |  | Server | |    |       |     |            |       | |
   | |      |  | Random |--->------------->------+  +----------+  | |
   | |      |  +--------+ |    |       |     |   |  | Client   |  | |
   | |      |      |      |    |       |     |   |  | Random   |  | |
   | |      |      |      |    |       |     |   |  +----------+  | |
   | |      |      |      |    |       |     |   |        |       | |
   | |      V      V      |    |       |     |   V        V       | |
   | |   +------------+   |    |       |     | +------------+     | |
   | +-->| CT-KIP PRF |   |    |       |     | | CT-KIP PRF |<----+ |
   |     +------------+   |    |       |     | +------------+       |
   |           |          |    |       |     |       |              |
   |           V          |    |       |     |       V              |
   |       +-------+      |    |       |     |   +-------+          |
   |       |  Key  |      |    |       |     |   |  Key  |          |
   |       +-------+      |    |       |     |   +-------+          |
   |       +-------+      |    |       |     |   +-------+          |
   |       |Key Id |-------->------------->------|Key Id |          |
   |       +-------+      |    |       |     |   +-------+          |
   +----------------------+    +-------+     +----------------------+
        CT-KIP Server        CT-KIP Client     CT-KIP Client (Token)
                               (PC Host)

   Figure 2: Principal data flow for CT-KIP key generation - using
   public server key

This diagram seems to totally contradict the claims elsewhere in the document that the key for the PRF is a secret key, since the key being used here for the PRF is an RSA public key… 🤦‍♂️

@cemeyer
Copy link
Author

cemeyer commented Sep 7, 2018

It's sort of unclear. The RFC really wants to call it a MAC.

The PRF also sometimes calls the PRF an encryption algorithm, too. I don't know what they are thinking.

Yeah I am facepalming over here too :-).

Edit: I posted some highlighted RFC excerpts on the earlier gist as well. The RFC documents several different salts for different steps of the negotiation; I'm not sure if those are the same ones the product uses.

@dlenski
Copy link

dlenski commented Sep 7, 2018

The RFC documents several different salts for different steps of the negotiation

The RFC is a dumpster fire. Is this thing really an "internet standard"?

And thanks, responding to your useful comments on the gist now.

@cemeyer
Copy link
Author

cemeyer commented Sep 7, 2018

The RFC is a dumpster fire. Is this thing really an "internet standard"?

I guess not!

This memo provides information for the Internet community. It does not specify an Internet standard of any kind.

😂

Add totally untested implementations of the OMAC1-AES ("CMAC") and
CT-KIP-PRF-AES pseudo-random function per relevant RFCs (but see also:
mistakes in the RFC mentioned in stoken-dev#27).  It compiles but that's about all
I've tested.

Broken:
* Only supports tomcrypt
* Untested!!!

Re: stoken-dev#27
@cemeyer
Copy link
Author

cemeyer commented Aug 13, 2019

We ended up just doing this in Python with @dlenski's ct-kit.py, but if someone ever wants to integrate that key negotiation protocol into stoken natively, this code (or similar) could be a useful component.

@cemeyer cemeyer closed this Aug 13, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants