Difference between revisions of "Projects/ResponderForPKINIT"
(→Tentative Implementation) |
(→Tentative Implementation) |
||
Line 26: | Line 26: | ||
* 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, 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"]} |
+ | {"identities": ["PKCS12:/path/to/blah", "FILE:/path/to/cert,/path/to/key"], 'token-flags':{}} |
Suggested sample answer: |
Suggested sample answer: |
||
{"identities": {"PKCS12:/path/to/blah": "foo", "FILE:/path/to/cert,/path/to/key": "bar"}} |
{"identities": {"PKCS12:/path/to/blah": "foo", "FILE:/path/to/cert,/path/to/key": "bar"}} |
||
+ | |||
+ | The ''token-flags'' object a subset of the members of ''identities'' as keys, and numbers corresponding to token flags as their values. 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 at most one answer (''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": ["PKCS11:module_name=pkcs11.so,token=MacGuffin (token),slotid=1"], "warnings": {"PKCS11:module_name=pkcs11.so,token=MacGuffin (token),slotid=1": "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": ["PKCS11:module_name=pkcs11.so,token=MacGuffin (token),slotid=1"], "token-flags": {"PKCS11:module_name=pkcs11.so,token=MacGuffin (token),slotid=1": 71036}} |
||
− | Another option is to expose selected flags as keys in an object which maps them to booleans: |
||
− | {"identities": ["PKCS11:module_name=pkcs11.so,token=MacGuffin (token),slotid=1"], "token-flags": {"PKCS11:module_name=pkcs11.so,token=MacGuffin (token),slotid=1": {"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? |
||
− | ''The test script will attempt to load a soft token module using Python's ctypes module, and if found, it will configure and use that soft token. It could probably do this for more than one of the soft tokens that are out there, but that may have to be an ongoing effort.'' |
||
==Testing== |
==Testing== |
Revision as of 20:50, 16 February 2013
Contents
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, 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"], 'token-flags':{}}
Suggested sample answer:
{"identities": {"PKCS12:/path/to/blah": "foo", "FILE:/path/to/cert,/path/to/key": "bar"}}
The token-flags object a subset of the members of identities as keys, and numbers corresponding to token flags as their values. 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 at most one answer (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.
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.