[PATCH 3/4] KEYS: CA link restriction
Stefan Berger
stefanb at linux.ibm.com
Mon Mar 14 12:00:33 UTC 2022
On 3/11/22 15:23, Stefan Berger wrote:
>
>
> On 3/11/22 13:44, Eric Snowberg wrote:
>>
>>
>>> On Mar 9, 2022, at 12:02 PM, Stefan Berger <stefanb at linux.ibm.com>
>>> wrote:
>>>
>>>
>>>
>>> On 3/9/22 13:13, Eric Snowberg wrote:
>>>>> On Mar 9, 2022, at 10:12 AM, Stefan Berger <stefanb at linux.ibm.com>
>>>>> wrote:
>>>>>
>>>>>
>>>>>
>>>>> On 3/8/22 13:02, Eric Snowberg wrote:
>>>>>>> On Mar 8, 2022, at 5:45 AM, Mimi Zohar <zohar at linux.ibm.com> wrote:
>>>>>>>
>>>>>>> On Mon, 2022-03-07 at 21:31 -0500, Stefan Berger wrote:
>>>>>>>>
>>>>>>>> On 3/7/22 18:38, Eric Snowberg wrote:
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>> On Mar 7, 2022, at 4:01 PM, Mimi Zohar <zohar at linux.ibm.com>
>>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>> On Mon, 2022-03-07 at 18:06 +0000, Eric Snowberg wrote:
>>>>>>>>>>>
>>>>>>>>>>>>> diff --git a/crypto/asymmetric_keys/restrict.c
>>>>>>>>>>>>> b/crypto/asymmetric_keys/restrict.c
>>>>>>>>>>>>> index 6b1ac5f5896a..49bb2ea7f609 100644
>>>>>>>>>>>>> --- a/crypto/asymmetric_keys/restrict.c
>>>>>>>>>>>>> +++ b/crypto/asymmetric_keys/restrict.c
>>>>>>>>>>>>> @@ -108,6 +108,49 @@ int restrict_link_by_signature(struct
>>>>>>>>>>>>> key *dest_keyring,
>>>>>>>>>>>>> return ret;
>>>>>>>>>>>>> }
>>>>>>>>>>>>> +/**
>>>>>>>>>>>>> + * restrict_link_by_ca - Restrict additions to a ring of
>>>>>>>>>>>>> CA keys
>>>>>>>>>>>>> + * @dest_keyring: Keyring being linked to.
>>>>>>>>>>>>> + * @type: The type of key being added.
>>>>>>>>>>>>> + * @payload: The payload of the new key.
>>>>>>>>>>>>> + * @trust_keyring: Unused.
>>>>>>>>>>>>> + *
>>>>>>>>>>>>> + * Check if the new certificate is a CA. If it is a CA,
>>>>>>>>>>>>> then mark the new
>>>>>>>>>>>>> + * certificate as being ok to link.
>>>>>>>>>>>>
>>>>>>>>>>>> CA = root CA here, right?
>>>>>>>>>>>
>>>>>>>>>>> Yes, I’ll update the comment
>>>>>>>>>>
>>>>>>>>>> Updating the comment is not enough. There's an existing
>>>>>>>>>> function named
>>>>>>>>>> "x509_check_for_self_signed()" which determines whether the
>>>>>>>>>> certificate
>>>>>>>>>> is self-signed.
>>>>>>>>>
>>>>>>>>> Originally I tried using that function. However when the
>>>>>>>>> restrict link code is called,
>>>>>>>>> all the necessary x509 information is no longer available.
>>>>>>>>> The code in
>>>>>>>>> restrict_link_by_ca is basically doing the equivalent to
>>>>>>>>> x509_check_for_self_signed.
>>>>>>>>> After verifying the cert has the CA flag set, the call to
>>>>>>>>> public_key_verify_signature
>>>>>>>>> validates the cert is self signed.
>>>>>>>>>
>>>>>>>> Isn't x509_cert_parse() being called as part of parsing the
>>>>>>>> certificate?
>>>>>>>> If so, it seems to check for a self-signed certificate every
>>>>>>>> time. You
>>>>>>>> could add something like the following to
>>>>>>>> x509_check_for_self_signed(cert):
>>>>>>>> pub->x509_self_signed = cert->self_signed = true;
>>>>>>>>
>>>>>>>> This could then reduce the function in 3/4 to something like:
>>>>>>>>
>>>>>>>> return payload->data[asym_crypto]->x509_self_signed;
>>>>>> When I was studying the restriction code, before writing this
>>>>>> patch, it looked like
>>>>>> it was written from the standpoint to be as generic as possible.
>>>>>> All code contained
>>>>>> within it works on either a public_key_signature or a public_key.
>>>>>> I had assumed it
>>>>>> was written this way to be used with different asymmetrical key
>>>>>> types now and in
>>>>>> the future. I called the public_key_verify_signature function
>>>>>> instead of interrogating
>>>>>> the x509 payload to keep in line with what I thought was the
>>>>>> original design. Let me
>>>>>> know if I should be carrying x509 code in here to make the change
>>>>>> above.
>>>>>
>>>>> It does not seem right if there were two functions trying to
>>>>> determine whether an x509 cert is self-signed. The existing is
>>>>> invoked as part of loading a key onto the machine keyring from what
>>>>> I can see. It has access to more data about the cert and therefore
>>>>> can do stronger tests, yours doesn't have access to the data. So I
>>>>> guess I would remember in a boolean in the public key structure
>>>>> that the x509 cert it comes from was self signed following the
>>>>> existing test. Key in your function may be that that
>>>>> payload->data[] array is guaranteed to be from the x509 cert as set
>>>>> in x509_key_preparse().
>>>>>
>>>>> https://elixir.bootlin.com/linux/v5.17-rc7/source/crypto/asymmetric_keys/x509_public_key.c#L236
>>>>>
>>>> I could add another bool to the public key structure to designate if
>>>> the key was self signed,
>>>> but this seems to go against what the kernel document states.
>>>> "Asymmetric / Public-key
>>>> Cryptography Key Type” [1] states:
>>>> "The “asymmetric” key type is designed to be a container for the
>>>> keys used in public-key
>>>> cryptography, without imposing any particular restrictions on the
>>>> form or mechanism of
>>>> the cryptography or form of the key.
>>>> The asymmetric key is given a subtype that defines what sort of data
>>>> is associated with
>>>> the key and provides operations to describe and destroy it. However,
>>>> no requirement is
>>>> made that the key data actually be stored in the key."
>>>> Now every public key type would need to fill in the information on
>>>> whether the key is self
>>>> signed or not. Instead of going through the
>>>> public_key_verify_signature function currently
>>>> used in this patch.
>>>
>>> Every public key extracted from a x509 certificate would have to set
>>> this field to true if the public key originates from a self-signed
>>> x509 cert. Is this different from this code here where now every
>>> public key would have to set the key_is_ca field?
>>
>> The information to determine if the key is a CA can not be derived
>> without help from
>> the specific key type. Up to this point, no one has needed it.
>>
>>>
>>> + if (v[1] != 0 && v[2] == ASN1_BOOL && v[3] == 1)
>>> + ctx->cert->pub->key_is_ca = true;
>>>
>>> The extension I would have suggested looked similar:
>>>
>>> cert->pub->x509_self_sign = cert->self_signed = true
>>>
>>> [ to be put here:
>>> https://elixir.bootlin.com/linux/v5.17-rc7/source/crypto/asymmetric_keys/x509_public_key.c#L147
>>> ]
>>
>> The information to determine if a key is self signed can be derived
>> without help
>> from the specific key type. This can be achieved without modification
>> to a generic
>> public header file. Adding a field to the public header would need to
>> either be
>> x509 specific or generic for all key types. Adding a x509 specific
>> field seems to
>> go against the goal outlined in the kernel documentation. Adding a
>> generic
>> self_signed field impacts all key types, now each needs to be modified
>> to fill in
>> the new field.
>>
>
> If we now called the generic field cert_self_signed we could let it
> indicate whether the certificate the key was extracted from was
> self-self signed. The next question then is how many different types of
> certificates does the key subsystem support besides x509 so we know
> where to set this field if necessary? I don't know of any other... x509
> seems to be the only type of certificate associated with struct public_key.
> What seems to be the case is that pkcs7 also runs the x509 cert parser
> to extract an x509 certificate, thus the flag will be set down this call
> path as well.
>
> https://elixir.bootlin.com/linux/latest/source/crypto/asymmetric_keys/pkcs7_parser.c#L408
>
>
> Further, the public_key struct is only used in a few places and only in
> the crypto/asymmetric_keys directory filled in. Its usage in pkcs8 seems
> not relevant for certs, so leaving cert_self_signed there uninitialized
> seems just right. The code in public_key.c seems to not deal with
> certificates. So what's left is the x509_cert_parser.c and the function
> x509_cert_parse() allocates it and then calls
> x509_check_for_self_signed(cert), which can set the flag.
>
> It looks to me giving it a generic name and only ever setting it to true
> iin x509_check_for_self_sign(cert) should work.
Otherwise maybe we could introduce
struct cert_info {
bool is_ca;
bool self_sign;
}
And use it like this:
+ if (v[1] != 0 && v[2] == ASN1_BOOL && v[3] == 1)
+ ctx->cert->cert_info->is_ca = true;
New index in the data array:
prep->payload.data[asym_subtype] = &public_key_subtype;
prep->payload.data[asym_key_ids] = kids;
prep->payload.data[asym_crypto] = cert->pub;
prep->payload.data[asym_auth] = cert->sig;
prep->payload.data[asym_cert_info] = cert->cert_info;
There are a few more places where this new array index would need to be
set to NULL.
More information about the Linux-security-module-archive
mailing list