logo_kerberos.gif

Difference between revisions of "Projects/ResponderForPKINIT"

From K5Wiki
Jump to: navigation, search
(Tentative Implementation)
(Tentative Implementation)
 
(4 intermediate revisions by the same user not shown)
Line 25: Line 25:
 
* Teach crypto_load_certs() to change its behavior to return a specific error to indicate when a given identity's keying material was protected by a PIN or password.
 
* Teach crypto_load_certs() to change its behavior to return a specific error to indicate when a given identity's keying material was protected by a PIN or password.
 
* Break pkinit_identity_initialize() up into two passes, one which calls crypto_load_certs() with this flag and returns immediately, to suss out which identities have protected keying information, and one which works like the current version, except that it will skip over anything which was loaded in the first pass. Special care will be needed for "DIR" identities, as the two-pass logic will have to be applied at the level where it's resolved things down to individual "FILE" identities internally, and for "PKCS11" identities, which may only specify a module, but which will need to be able to unambiguously refer to specific tokens and/or slots.
 
* Break pkinit_identity_initialize() up into two passes, one which calls crypto_load_certs() with this flag and returns immediately, to suss out which identities have protected keying information, and one which works like the current version, except that it will skip over anything which was loaded in the first pass. Special care will be needed for "DIR" identities, as the two-pass logic will have to be applied at the level where it's resolved things down to individual "FILE" identities internally, and for "PKCS11" identities, which may only specify a module, but which will need to be able to unambiguously refer to specific tokens and/or slots.
* In pkinit_clnt.c, add a client_prep_questions method which calls the first pass of pkinit_identity_initialize(), and which puts together a list of the identities which couldn't be loaded, due to a PIN or password being required, to pass to the responder callback. Suggested sample challenge for a ''pkinit'' question:
+
* In pkinit_clnt.c, add a client_prep_questions method which calls the first pass of pkinit_identity_initialize(), and which puts together a list of the identities which couldn't be loaded, due to a PIN or password being required, and any PIN-related warnings, to pass to the responder callback. Suggested sample challenge for a ''pkinit'' question:
{"identities": ["PKCS12:/path/to/blah", "FILE:/path/to/cert,/path/to/key"]}
+
{"PKCS12:/path/to/blah": 0, "FILE:/path/to/cert,/path/to/key": 0, "PKCS11:module=opensc-pkcs11.so:slotid=1:token=My Card": 4}
 
Suggested sample answer:
 
Suggested sample answer:
{"identities": {"PKCS12:/path/to/blah": "foo", "FILE:/path/to/cert,/path/to/key": "bar"}}
+
{"PKCS12:/path/to/blah": "foo", "FILE:/path/to/cert,/path/to/key": "bar"}
  +
  +
The challenge is an object whose keys are identity names, with their associated values being numbers corresponding to token flags. These flags convey the status of a token's pin, and will be set to zero or more of the flags ''KRB5_RESPONDER_PKINIT_FLAGS_TOKEN_USER_PIN_COUNT_LOW'', ''KRB5_RESPONDER_PKINIT_FLAGS_TOKEN_USER_PIN_FINAL_TRY'', and ''KRB5_RESPONDER_PKINIT_FLAGS_TOKEN_USER_PIN_LOCKED''.
 
* In the second pass of pkinit_identity_initialize(), use values provided in the answer, if there is one, to load identity information from locations in the answer. If no answer was available, use the prompter callback, as is done now, to solicit PINs and passwords for identities listed in the challenge.
 
* In the second pass of pkinit_identity_initialize(), use values provided in the answer, if there is one, to load identity information from locations in the answer. If no answer was available, use the prompter callback, as is done now, to solicit PINs and passwords for identities listed in the challenge.
 
  +
* Helper functions for parsing the challenge into a structure (''krb5_responder_pkinit_get_challenge'', ''krb5_responder_pkinit_challenge_free'') and setting answers (''krb5_responder_pkinit_set_answer'') will also be added.
'''Topic for discussion''': when using a PKCS11 client identity, the OpenSSL version of the plugin will read the token's info and add, to the text which it passes to the prompter callback, text indicating if the PIN is locked, is on its last try, or is low. Should the question format be modified to accommodate and carry this information? Would adding a ''warnings'' object, with keys matching elements from the ''identities'' array, with their corresponding warnings as values, be simplest?
 
{"identities": ["PKCS12:/path/to/blah"], "warnings": {"PKCS12:/path/to/blah": "PIN count low"}}
 
This is rejected because the warning text is still too hard to process in a dependable way, particularly if we have to add possible values. Another option is to just expose the "flags" value from the token's CK_TOKEN_INFO, if such flags are applicable, and leave it to the calling application to interpret the value:
 
{"identities": ["PKCS12:/path/to/blah"], "token-flags": {"PKCS12:/path/to/blah": 76}}
 
Another option is to expose selected flags as keys in an object which maps them to booleans:
 
{"identities": ["PKCS12:/path/to/blah"], "info": {"PKCS12:/path/to/blah": {"user-pin-locked": false, "user-pin-count-low": false}}}
 
'''Topic for discussion''': should helper functions, similar to krb5_responder_otp_get_challenge(), be added? If so, what should that API look like? '''YES'''; the API will look almost exactly like the krb5_responder_otp_XXX set of functions, but the type of the data structure which it returns will need to reflect what is exposed in the challange, and how it is exposed.
 
 
'''Topic for discussion''': how will we go about integrating testing with PKCS11 modules into the self-test suite?
 
   
 
==Testing==
 
==Testing==
Line 46: Line 37:
 
* We'll need a test program that lets us specify both that a particular response item is expected, and which response to supply for it, and which does not supply a prompter callback.
 
* We'll need a test program that lets us specify both that a particular response item is expected, and which response to supply for it, and which does not supply a prompter callback.
 
* We'll need to run tests using both encrypted and unencrypted copies of the keying material.
 
* We'll need to run tests using both encrypted and unencrypted copies of the keying material.
  +
* We'll need to opportunistically test with at least one software PKCS#11 module, if found.
   
 
==Documentation==
 
==Documentation==

Latest revision as of 08:29, 18 July 2013

This is an early stage project for MIT Kerberos. It is being fleshed out by its proponents. Feel free to help flesh out the details of this project. After the project is ready, it will be presented for review and approval.


Description

The addition of Projects/Responder support to libkrb5 allows clients to use a responder callback to answer questions posed by the password-based and OTP preauthentication mechanisms, all at once, and in doing so select which mechanisms can be used to send requests to a KDC.

Problem

Support for using responder callbacks has not been implemented for PKINIT. Applications which wish to continue to support PKINIT need to continue to provide a prompter callback, which reduces the usefulness of the responder callback machinery.

Proposal

Add support for filling in response items to the PKINIT plugin.

Expected Behavior

The naive expectation, that PKINIT will also make use of an application's responder callback, will be the correct one.

Design

Load identity information in two passes. The first will be done during the plugin's fill_response method, at which time the client will attempt to load all configured identities. Those which don't require a password or PIN to read their keying material will just succeed, and those which don't will be added to the list of identities which will be added to the response item set. The second pass will use answers from the response item set to load identities from their corresponding locations, or if there is no answer, attempt to use the prompter callback to solicit passwords and PINs, as it does now.

Tentative Implementation

  • Teach crypto_load_certs() to change its behavior to return a specific error to indicate when a given identity's keying material was protected by a PIN or password.
  • Break pkinit_identity_initialize() up into two passes, one which calls crypto_load_certs() with this flag and returns immediately, to suss out which identities have protected keying information, and one which works like the current version, except that it will skip over anything which was loaded in the first pass. Special care will be needed for "DIR" identities, as the two-pass logic will have to be applied at the level where it's resolved things down to individual "FILE" identities internally, and for "PKCS11" identities, which may only specify a module, but which will need to be able to unambiguously refer to specific tokens and/or slots.
  • In pkinit_clnt.c, add a client_prep_questions method which calls the first pass of pkinit_identity_initialize(), and which puts together a list of the identities which couldn't be loaded, due to a PIN or password being required, and any PIN-related warnings, to pass to the responder callback. Suggested sample challenge for a pkinit question:
   {"PKCS12:/path/to/blah": 0, "FILE:/path/to/cert,/path/to/key": 0, "PKCS11:module=opensc-pkcs11.so:slotid=1:token=My Card": 4}

Suggested sample answer:

   {"PKCS12:/path/to/blah": "foo", "FILE:/path/to/cert,/path/to/key": "bar"}

The challenge is an object whose keys are identity names, with their associated values being numbers corresponding to token flags. These flags convey the status of a token's pin, and will be set to zero or more of the flags KRB5_RESPONDER_PKINIT_FLAGS_TOKEN_USER_PIN_COUNT_LOW, KRB5_RESPONDER_PKINIT_FLAGS_TOKEN_USER_PIN_FINAL_TRY, and KRB5_RESPONDER_PKINIT_FLAGS_TOKEN_USER_PIN_LOCKED.

  • In the second pass of pkinit_identity_initialize(), use values provided in the answer, if there is one, to load identity information from locations in the answer. If no answer was available, use the prompter callback, as is done now, to solicit PINs and passwords for identities listed in the challenge.
  • Helper functions for parsing the challenge into a structure (krb5_responder_pkinit_get_challenge, krb5_responder_pkinit_challenge_free) and setting answers (krb5_responder_pkinit_set_answer) will also be added.

Testing

  • We'll need to add authenticated-client cases to the PKINIT tests, using keying material that's encrypted.
  • We'll need a test program that lets us specify both that a particular response item is expected, and which response to supply for it, and which does not supply a prompter callback.
  • We'll need to run tests using both encrypted and unencrypted copies of the keying material.
  • We'll need to opportunistically test with at least one software PKCS#11 module, if found.

Documentation

If we enumerate which in-tree preauth mechanisms use responder callbacks, PKINIT will need to be removed from a list of exceptions, if there is one, and added to the list of mechanisms which use responder callbacks.

Release notes

Like documentation, to whatever extent we note that PKINIT doesn't support responder callbacks, we'll need to correct the notes.