OASIS PKCS 11 TC

 View Only
  • 1.  Private values for ML-DSA and similar

    Posted 10-31-2024 15:11
    So prompted by a discussion on the PQC Forum I was looking at our
    definition of CKA_VALUE for ML-DSA and it says:

    Big Integer: Private value as defined in [FIPS 204]


    However FIPS 204 does not define "Private Value" in the glossary.
    and mentions private values only in the part that explains ML-DSA
    construction to define two private values (S1, S2) that constitute the
    private key.

    In order to ensure maximum interoperability the implementation should
    definitely be able to get as input (on import) a Seed value that is
    used to then reconstitute the full private key, and be able to always
    export a seed value.

    There is quite a lot of people that think private keys should always be
    stored as seed values and reconstructed when read into memory.

    In any case the current text is not clear enough and needs improvement
    to avoid interoperability issues.


    We should discuss this at the next meeting if possible.

    Simo.

    --
    Simo Sorce
    Distinguished Engineer
    RHEL Crypto Team
    Red Hat, Inc


  • 2.  RE: Private values for ML-DSA and similar

    Posted 10-31-2024 17:10

    THALES GROUP LIMITED DISTRIBUTION to email recipients

     

    Hi

    Agreed that we need to discuss this.  The IETF world may be moving in a direction that is different than the one we took.

     

    The Big Integer text in the current working draft is outdated.

     

    the latest version of "kem_algs" has an updated description where CKA_VALUE is defined as a byte array, as defined in FIPS 203.  The intent of the new text was to map CKA_VALUE to the serialized key format that is defined in FIPS 203. So that we could use the specifications format and remove any interoperability issues.  This was decided a bit before the whole seed discussions started (or maybe it was decided after the initial seed discussions died off).  If we keep our definition the way it is, we should add a few more words to make it more clear what it means.

     

    But I also agree that if the IETF world decides to adopt the seed(s) as a format (this applies for ML-KEM and ML-DSA), we would need to try and support what they support. 

     

    Thanks

    Darren

     






  • 3.  RE: Private values for ML-DSA and similar

    Posted 10-31-2024 17:22
    [Simo Sorce]
    > There is quite a lot of people that think private keys should always be
    > stored as seed values and reconstructed when read into memory.

    I'd rephrase that as there is a very small group of people that are pushing the concept that private keys should never be encoded and should always be derived from an input seed.

    The concept of requiring a seed value to always be present is simply not generally supportable and makes little sense when you work through all the possible contexts of usage.

    Those who are pushing that concept are doing so in the context of keys being ephemeral and mostly in the context of ML-KEM and to not have to define a persistent key format and that the "generation" cost is trivial. This isn't generally applicable.

    And to be exceedingly clear, there is absolutely no requirement or suggesting within any of the NIST specifications that implementations should operate off a SEED value and see that as the private key - and in fact the concept of an externally provided seed does not universally exist in the NIST docs. Basically you end up seeing a "seed" as the PRNG output values in some algorithms and they are not defined as an alternate input key generation mechanism.

    FIPS-203 (allows for the concept that implementations might choose to store the seed in place of the private key but does not require that this be supported - and it is clear it is a SEED not a private key value format)

    There is also an explicit note: As prescribed in Section 3.3, the interfaces specified in this section should not be made available to applications other than for testing purposes, and the random seeds (as specified in ML-KEM.KeyGen and ML-KEM.Encaps in Section 7) shall be generated by the cryptographic module.

    FIPS-204 (no seed input defined, you are changing the internal algorithm RNG output)

    FIPS-205 (no seed input defined, you are changing the internal algorithm RNG output)

    Tim.







  • 4.  RE: Private values for ML-DSA and similar

    Posted 11-01-2024 10:30
    Some comments on Tim's reply follow, but the reason we are raising
    this is that there is a good chance some protocols will want to
    define at least ML-KEM and ML-DSA import/export methods to use seeds
    for storage/transmission.

    Specifically PKCS#12 files have been explicitly metioned.

    And the fact is you can always seed -> private-key and you can never
    private-key -> seed. So storing the seeds to be able to properly
    export keys *should* definitely be a strong consideration here.


    On Thu, 2024-10-31 at 21:21 +0000, Tim Hudson via OASIS wrote:
    > I'd rephrase that as there is a very small group of people
    > that are pushing the concept that private keys should never
    > be encoded and should always be derived from an input seed.

    Not sure it matters if they are relatively many or a few, there are
    influential people in IETF that lean that way. And I think they have
    reasonable arguments too.

    > The concept of requiring a seed value to always be present
    > is simply not generally supportable and makes little sense
    > when you work through all the possible contexts of usage.

    I am not sure I understand this point, given the seed you can
    always regenerate the key, so it should be generally supportable.
    Of course some implementations may want to permanently store the
    expanded keys as well for performance reasons, but if you can
    store the expanded key, storing along side it the generation seed
    to be used as an export format is not a big deal.

    > Those who are pushing that concept are doing so in the context
    > of keys being ephemeral and mostly in the context of ML-KEM
    > and to not have to define a persistent key format and that the
    > "generation" cost is trivial. This isn't generally applicable.

    What part is not generally applicable? That generation cost is high?

    In any case that is not the only argument. Many make the argument that
    storing seeds is much simpler for small devices as it reduces the size
    of permanent storage and regenerating the key doubles as a test that
    the key is well formed which is an operation you need to do for FIPS
    certified modules.
    Storing seeds also reduces ambiguity and allows implementations to
    organize the expanded format as they see fit.

    > And to be exceedingly clear, there is absolutely no requirement
    > or suggesting within any of the NIST specifications that
    > implementations should operate off a SEED value and see that
    > as the private key

    I have seen no one make this argument, so I do not see the relevance
    TBH.

    > - and in fact the concept of an externally provided seed does not
    > universally exist in the NIST docs. Basically you end up seeing a
    > "seed" as the PRNG output values in some algorithms and they are
    > not defined as an alternate input key generation mechanism.

    I this case it would be key re-constitution, and not generation.
    The key generation happened the first time when the seed was
    actually generated.

    > FIPS-203 (allows for the concept that implementations might
    > choose to store the seed in place of the private key but does
    > not require that this be supported - and it is clear it is a
    > SEED not a private key value format)

    It is clear the SEED is a seed, it is also clear it is as sensitive
    and equivalent to the private key. if you have access to the seed
    you know the private key.

    > There is also an explicit note: As prescribed in Section 3.3,
    > the interfaces specified in this section should not be made
    > available to applications other than for testing purposes,

    I do not see the relevance of this, private key re-computation
    from a seed would be an internal operation anyway.

    > and the random seeds (as specified in ML-KEM.KeyGen and
    > ML-KEM.Encaps in Section 7) shall be generated by the
    > cryptographic module.

    And so they shall, I do not get what point you are trying to
    make here? Care to elaborate ?

    > FIPS-204 (no seed input defined, you are changing the
    > internal algorithm RNG output)

    Look at Algorithm 6. The first line is:

    Input: Seed 𝜉 ∈ 𝔹32


    So input seed is clearly defined.

    > FIPS-205 (no seed input defined, you are changing the
    > internal algorithm RNG output)

    In 205 there isn't a single seed indeed, but there is a seed and a prf
    for public keys and a seed and root for the public key, but then again
    I have seen nobody claiming we need to use seed storage for SLH-DSA,
    only for ML-DSA and ML-KEM.


    HTH,
    Simo.


    Simo Sorce
    Distinguished Engineer
    RHEL Crypto Team
    Red Hat, Inc




  • 5.  RE: Private values for ML-DSA and similar

    Posted 11-01-2024 12:24
    Also this is just in from PQC-Froum:

    For both FIPS 203 and FIPS 204, a KeyGen seed is considered an
    acceptable alternative format for the private (i.e., decapsulation
    or signing) key. In particular, generating the seed in one
    cryptographic module and then importing it into another
    cryptographic module is allowed.


    So I would say there is no "normative" issue here.


    On Fri, 2024-11-01 at 10:29 -0400, Simo Sorce wrote:
    > Some comments on Tim's reply follow, but the reason we are raising
    > this is that there is a good chance some protocols will want to
    > define at least ML-KEM and ML-DSA import/export methods to use seeds
    > for storage/transmission.
    >
    > Specifically PKCS#12 files have been explicitly metioned.
    >
    > And the fact is you can always seed -> private-key and you can never
    > private-key -> seed. So storing the seeds to be able to properly
    > export keys *should* definitely be a strong consideration here.
    >
    >
    > On Thu, 2024-10-31 at 21:21 +0000, Tim Hudson via OASIS wrote:
    > > I'd rephrase that as there is a very small group of people
    > > that are pushing the concept that private keys should never
    > > be encoded and should always be derived from an input seed.
    >
    > Not sure it matters if they are relatively many or a few, there are
    > influential people in IETF that lean that way. And I think they have
    > reasonable arguments too.
    >
    > > The concept of requiring a seed value to always be present
    > > is simply not generally supportable and makes little sense
    > > when you work through all the possible contexts of usage.
    >
    > I am not sure I understand this point, given the seed you can
    > always regenerate the key, so it should be generally supportable.
    > Of course some implementations may want to permanently store the
    > expanded keys as well for performance reasons, but if you can
    > store the expanded key, storing along side it the generation seed
    > to be used as an export format is not a big deal.
    >
    > > Those who are pushing that concept are doing so in the context
    > > of keys being ephemeral and mostly in the context of ML-KEM
    > > and to not have to define a persistent key format and that the
    > > "generation" cost is trivial. This isn't generally applicable.
    >
    > What part is not generally applicable? That generation cost is high?
    >
    > In any case that is not the only argument. Many make the argument that
    > storing seeds is much simpler for small devices as it reduces the size
    > of permanent storage and regenerating the key doubles as a test that
    > the key is well formed which is an operation you need to do for FIPS
    > certified modules.
    > Storing seeds also reduces ambiguity and allows implementations to
    > organize the expanded format as they see fit.
    >
    > > And to be exceedingly clear, there is absolutely no requirement
    > > or suggesting within any of the NIST specifications that
    > > implementations should operate off a SEED value and see that
    > > as the private key
    >
    > I have seen no one make this argument, so I do not see the relevance
    > TBH.
    >
    > > - and in fact the concept of an externally provided seed does not
    > > universally exist in the NIST docs. Basically you end up seeing a
    > > "seed" as the PRNG output values in some algorithms and they are
    > > not defined as an alternate input key generation mechanism.
    >
    > I this case it would be key re-constitution, and not generation.
    > The key generation happened the first time when the seed was
    > actually generated.
    >
    > > FIPS-203 (allows for the concept that implementations might
    > > choose to store the seed in place of the private key but does
    > > not require that this be supported - and it is clear it is a
    > > SEED not a private key value format)
    >
    > It is clear the SEED is a seed, it is also clear it is as sensitive
    > and equivalent to the private key. if you have access to the seed
    > you know the private key.
    >
    > > There is also an explicit note: As prescribed in Section 3.3,
    > > the interfaces specified in this section should not be made
    > > available to applications other than for testing purposes,
    >
    > I do not see the relevance of this, private key re-computation
    > from a seed would be an internal operation anyway.
    >
    > > and the random seeds (as specified in ML-KEM.KeyGen and
    > > ML-KEM.Encaps in Section 7) shall be generated by the
    > > cryptographic module.
    >
    > And so they shall, I do not get what point you are trying to
    > make here? Care to elaborate ?
    >
    > > FIPS-204 (no seed input defined, you are changing the
    > > internal algorithm RNG output)
    >
    > Look at Algorithm 6. The first line is:
    >
    > Input: Seed 𝜉 ∈ 𝔹32
    >
    >
    > So input seed is clearly defined.
    >
    > > FIPS-205 (no seed input defined, you are changing the
    > > internal algorithm RNG output)
    >
    > In 205 there isn't a single seed indeed, but there is a seed and a prf
    > for public keys and a seed and root for the public key, but then again
    > I have seen nobody claiming we need to use seed storage for SLH-DSA,
    > only for ML-DSA and ML-KEM.
    >
    >
    > HTH,
    > Simo.
    >
    >
    > Simo Sorce
    > Distinguished Engineer
    > RHEL Crypto Team
    > Red Hat, Inc

    --
    Simo Sorce
    Distinguished Engineer
    RHEL Crypto Team
    Red Hat, Inc




  • 6.  RE: Private values for ML-DSA and similar

    Posted 11-07-2024 15:34

    THALES GROUP LIMITED DISTRIBUTION to email recipients

     

    Hi,

    I started to write up response to the IETF group about what we discussed today to get some early feedback from them but hit a bit of a problem with the C_Wrap/C_Unwrap use case.  I'll put a big caveat on what I send over there that it is pre-draft and is subject to change.

     

    Here is what I have so far.

     

    Currently we define a CKA_VALUE attribute for ML-DSA and ML-KEM private keys that contains the encoded private key value as defined in FIPS 203 and FIPS 204.  Based on today's discussion, we will be adding an additional attribute CKA_SEED that will store the seed(s) values.  This attribute will be 32-bytes for ML-DSA and 64-bytes for ML-KEM.   I don't think there is any need to have the two ML-KEM seeds stored as two separate attributes. IETF is treating them the same.

     

    When an ML-KEM or ML-DSA private key is generated using C_GenerateKeyPair, both CKA_VALUE and CKA_SEED attributes will be populated.

     

    The CKA_SEED attribute is a sensitive attribute just like CKA_VALUE.  The ability to read CKA_SEED via the C_GetAttributeValue API depends on the key's attributes and any vendor specific security policies of the token.  So if CKA_VALUE can be read, CKA_SEED can be read.

     

    When creating a ML-KEM or ML-DSA private key object using C_CreateObject, an application will be able to specify only CKA_VALUE, only CKA_SEED, or both CKA_VALUE and CKA_SEED. The reasoning for the flexibility in this use case is to support use-cases where an application ONLY has the encoded private key and does not have a seed, or only has a seed.  This allows them to still be able to create the object in the token and use it.  If an application creates a private key with out a CKA_SEED, then the CKA_SEED attribute will not be populated on the private key.  This should be fine as any application that is creating private keys without a seed shouldn't expect/need to read back the seed.  And if only the SEED is provided, a token could recompute the expanded key immediately or on depend, depending on their internal design.

     

    But I'm still struggling with the C_Wrap/C_Unwrap use-case though. Currently when wrapping/unwrapping private keys, we only support PKCS#8 formatted private keys. IETF hasn't finalized on their plans yet.  I would say they are in the early stages at best.  The initial proposal is something like this:

    ML-*PrivateKeySeed ::= OCTET STRING (SIZE X) -- X is 32 for ML-DSA and 64 for ML-KEM

    ML-*PrivateKeyFull ::= OCTET STRING

    ML-*PrivateKey ::= CHOICE {
              ML-*PrivateKeySeed,
          [0] ML-*PrivateKeyFull }

    (where ML-* means ML-DSA or ML-KEM)

    And they define the default/preferred format as being ML-*PrivateKeySeed.  So we are saying that for C_UnwrapKey, we can support both formats similar to how we support them for C_CreateObject.  But for C_WrapKey we don't have a deterministic way to define what is returned other than to say that we always use ML-*PrivateKeySeed if we can, otherwise we use ML-*PrivateKeyFull.  T

     

    Is this how we want to proceed?

     

     






  • 7.  RE: Private values for ML-DSA and similar

    Posted 11-07-2024 17:55

    Nit:

    " And if only the SEED is provided, a token could recompute the expanded key immediately or on depend, depending on their internal design."

    on depend -> on demand

    I think we should propose a different ML-*PrivateKey like the following:

    ML-*PrivateKey ::= SEQUENCE {
      seed          [0] OCTET_STRING (SIZE X) OPTIONAL,
      privateKey    [1] OCTET_STRING OPTIONAL,
    }

    Where seed should always be preferred.

    But both can be provided for convenience.

    This way we can always provide all we have (or just the seed if we default to that).

    As for the behavior of C_Wrap() I think we can do what you propose as the default, and if ever turns out we need a specific behavior we'll simply have to add a CKM_ML_*_WRAP_BEHAVIOR mechanism to a future spec that will do what is needed ...



    ------------------------------
    Simo Sorce
    Red Hat
    ------------------------------



  • 8.  RE: Private values for ML-DSA and similar

    Posted 11-07-2024 18:42
    On 11/7/24 12:35 PM, Darren Johnson via OASIS wrote:
    0100019308573b34-f61cb5f6-e27f-4b7c-8317-67129ad4b733-000000@email.amazonses.com">
    THALES GROUP LIMITED DISTRIBUTION to email recipients Hi, I started to write up response to the IETF group about what we discussed today... -posted to the "OASIS PKCS 11 TC" community

    Hi,

    I started to write up response to the IETF group about what we discussed today to get some early feedback from them but hit a bit of a problem with the C_Wrap/C_Unwrap use case.  I'll put a big caveat on what I send over there that it is pre-draft and is subject to change.

    C_Wrap and C_Unwrap expects pkcs8 data, so however the IETF defines it. This is the primary way I would expect keys to be transferred between tokens. If the data doesn't have all the components (the IETF makes Seed or the generated key optional), it may not be importable into all devices.

     

    Here is what I have so far.

     

    Currently we define a CKA_VALUE attribute for ML-DSA and ML-KEM private keys that contains the encoded private key value as defined in FIPS 203 and FIPS 204.  Based on today's discussion, we will be adding an additional attribute CKA_SEED that will store the seed(s) values.  This attribute will be 32-bytes for ML-DSA and 64-bytes for ML-KEM.   I don't think there is any need to have the two ML-KEM seeds stored as two separate attributes. IETF is treating them the same.

     

    When an ML-KEM or ML-DSA private key is generated using C_GenerateKeyPair, both CKA_VALUE and CKA_SEED attributes will be populated.

    I thought we decided this was token specific. Not all tokens could handle both values? But I'm ok with making both mandatory.

     

    The CKA_SEED attribute is a sensitive attribute just like CKA_VALUE.  The ability to read CKA_SEED via the C_GetAttributeValue API depends on the key's attributes and any vendor specific security policies of the token.  So if CKA_VALUE can be read, CKA_SEED can be read.

     

    When creating a ML-KEM or ML-DSA private key object using C_CreateObject, an application will be able to specify only CKA_VALUE, only CKA_SEED, or both CKA_VALUE and CKA_SEED. The reasoning for the flexibility in this use case is to support use-cases where an application ONLY has the encoded private key and does not have a seed, or only has a seed.  This allows them to still be able to create the object in the token and use it.  If an application creates a private key with out a CKA_SEED, then the CKA_SEED attribute will not be populated on the private key.  This should be fine as any application that is creating private keys without a seed shouldn't expect/need to read back the seed.  And if only the SEED is provided, a token could recompute the expanded key immediately or on depend, depending on their internal design.

    So we definitely decided that the token could reject one or the other of these cases. A slow token may not regenerate CKA_VALUE and fail if CKA_VALUE is not specified. A token with limitted space may require CKA_SEED. If the application supplies both it is guarrenteed to work.

     

    But I'm still struggling with the C_Wrap/C_Unwrap use-case though. Currently when wrapping/unwrapping private keys, we only support PKCS#8 formatted private keys. IETF hasn't finalized on their plans yet.  I would say they are in the early stages at best.  The initial proposal is something like this:

    ML-*PrivateKeySeed ::= OCTET STRING (SIZE X) -- X is 32 for ML-DSA and 64 for ML-KEM

    ML-*PrivateKeyFull ::= OCTET STRING

    ML-*PrivateKey ::= CHOICE {
              ML-*PrivateKeySeed,
          [0] ML-*PrivateKeyFull }

    (where ML-* means ML-DSA or ML-KEM)

    And they define the default/preferred format as being ML-*PrivateKeySeed.  So we are saying that for C_UnwrapKey, we can support both formats similar to how we support them for C_CreateObject.  But for C_WrapKey we don't have a deterministic way to define what is returned other than to say that we always use ML-*PrivateKeySeed if we can, otherwise we use ML-*PrivateKeyFull.  T

     

    Is this how we want to proceed?

    They don't have an option to return both? That at would be the prefered, and what is returned is token specific. If the token doesn't have the seed, it can't return it.

    bob

     







  • 9.  RE: Private values for ML-DSA and similar

    Posted 11-07-2024 20:29

    THALES GROUP LIMITED DISTRIBUTION to email recipients

     

    Thanks for those corrections Bob. I think I missed those points on the call.  Kids and supper.

    And thanks Simo for that editorial fix.

    I've added some responses below.

     

     






  • 10.  RE: Private values for ML-DSA and similar

    Posted 01-13-2025 01:26
    [ Bob Relyea ] 
    > So we definitely decided that the token could reject one or the other of these cases. 
    > A slow token may not regenerate CKA_VALUE and fail if CKA_VALUE is not specified. 
    > A token with limitted space may require CKA_SEED. If the application supplies both 
    > it is guarrenteed to work.

    The challenge that exists and has been recognised via a few of the folks within the IETF is that they want to mandate that the SEED value is always available and can always be provided.
    It isn't just an option or an alternative - it is mandatory to support.

    [ Mike Ounsworth on LAMPS mailing list]

    IETF is making the choice to only support seed-based private keys in P8, P12, etc. So by "compatible" I mean:

     

      1. PKCS#11 has a mandatory-to-implement seed-based private key import.
      2. Where private key export is supported, it has an optional seed-based private key export.
      3. ML-DSA and ML-KEM KeyGen requires HSMs to keep the seed. Even if you don't support seed-based export now, you at least have the option to get it out later.

    Publishing an RFC that only supports seed-based private keys without alignment with the hardware community sounds like 10 years of interop nightmares.

    And I do think this is a step too far and the IETF position here is not sensible. You can argue that supporting the SEED as an optional import format can make sense (and that still remains to actually be confirmed if that will be supported for FIPS140-3 validations as the CMVP has to date not made any definitive statement to that effect outside of a permitted testing context even in the latest SP draft at https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-227.ipd.pdf). There are also many more fun issues about not using the defined interface for SLH-DSA.

    For our current state of things in the PKCS#11 3.2 drafts we don't handle 1) [it is optional] and we don't handle 3) [as the specification does not require it - we leave it up to the implementer]. 

    One thing that you can be sure of is that current implementations won't support exporting the SEED or accept the SEED incoming as what should be used - as the concept of doing that is a rather new view. It would be different if all these discussions had been had back at the IPD level and sorted out - but these discussions are happening after the final version and after quite a few folks already had input and export formats sorted out based on existing approaches.

    The challenge that exists and has been recognised via a few of the folks within the IETF is that they want to mandate that the SEED value is always available and can always be provided. NIST has not done so - there is no requirement to preserve the SEED value beyond the internal key generation step. 

    There is also the issue of having to determine multiple different input formats within the PKCS#8 because of a lack of willingness to have an ASN1 choice value to indicate SEED or private key format. And also whether or not the private key format should have an enclosing OCTET string around it like EdDSA etc. All of these things are entangled in the process of change of views on how to handle things. See https://github.com/lamps-wg/kyber-certificates where there are some latest examples.

    For everything "normal" to date the PrivateKey value in an octet string was always itself valid ASN1 for further parsing (either an RSA key in its ASN1 glory or an EC or DH key - always known to be ASN1. Now with the ASN1 octet removed we break that "rule". 

    The OpenSSL approach going into OpenSSL-3.5 is to accept the PKCS#8 with the SEED or with the stated private key format from FIPS203 based on the length of the value and produce the SEED form if the SEED is available or output or the private key format from FIPS203 otherwise. For ML-KEM there is little point in going to PKCS#8 v2 to allow for the optional public key to be added as the public key is explicitly contained within the private key format within the standard. 

    You can see that "fun" in the pull release targeting the ML-KEM feature branch (the base code is merged into the feature branch, this PR handles the PKCS#8 and SubjectPublicKeyInfo encode/code handling.


    Specific lines having to work off lengths for the input handling (including the octet string/non-octet string handling).


    The OpenSSL viewpoint is pretty aligned with PKCS#11 - there is a way to work with the SEED but there is no requirement to mandate that the SEED must always be available. If it is there it is used, if it is not present everything still works. KMIP has also not moved to mandating SEED. 

    Hopefully this concrete information will inform a discussion on the topic.

    I do not think we should be mandating that all implementations must preserve and support SEED import and SEED export - that is not in the standard itself, and I don't see that as appropriate for PKCS#8, or PKCS#11 or KMIP or OpenSSL to dictate and mandatory requirement of this nature that is not within the underlying algorithm specification. 

    My view would be different if FIPS203 stated the SEED must be accepted as an input format and that the SEED must be preserved and must always be available as an export format.

    Tim.