[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 2/4] crypto: Add RSA support



On Mon, May 12, 2025 at 1:38 PM Jan Beulich <jbeulich@xxxxxxxx> wrote:
>
> On 06.05.2025 16:32, Ross Lagerwall wrote:
> > In preparation for adding support for livepatch signing, add support for
> > RSA crypto.
>
> If this is needed just for live-patch, ...
>
> > --- a/xen/common/Makefile
> > +++ b/xen/common/Makefile
> > @@ -28,6 +28,7 @@ obj-$(CONFIG_LIVEPATCH) += livepatch.o livepatch_elf.o
> >  obj-$(CONFIG_LLC_COLORING) += llc-coloring.o
> >  obj-$(CONFIG_VM_EVENT) += mem_access.o
> >  obj-y += memory.o
> > +obj-y += mpi.o
>
> ... why would this be obj-y? Same for rsa.o further down.
>
> > --- /dev/null
> > +++ b/xen/common/mpi.c
> > @@ -0,0 +1,1724 @@
> > +/* mpi-pow.c  -  MPI functions
>
> Nit: This doesn't match the filename.
>
> > + *   Copyright (C) 1994, 1996, 1998, 2000 Free Software Foundation, Inc.
> > + *
> > + * This file is part of GnuPG.
> > + *
> > + * GnuPG is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * GnuPG is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write to the Free Software
> > + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
> > USA
> > + *
> > + * Note: This code is heavily based on the GNU MP Library.
> > + *    Actually it's the same code with only minor changes in the
> > + *    way the data is stored; this is to support the abstraction
> > + *    of an optional secure memory allocation which may be used
> > + *    to avoid revealing of sensitive data due to paging etc.
> > + *    The GNU MP Library itself is published under the LGPL;
> > + *    however I decided to publish this code under the plain GPL.
> > + *
> > + * mpi.c code extracted from linux @ eef0df6a5953, lib/mpi
>
> I fear this line would go unnoticed with future changes, and hence go stale
> rather easily. Menioning the origin in just the commit message ought to be
> sufficient.
>
> Btw - how heavily did you need to adjust the code to pass our Eclair scan?
> Depending on that I then might raise the question of converting to proper
> Xen style (it currently isn't even proper Linux style, afaict).

Few changes were needed to the code in this file so I preferred to keep
it in the original style.

Since a lot more adjustments were made to rsa.c, I opted to change that
to the Xen style.

>
> > + */
> > +
> > +#include <xen/mpi.h>
> > +#include <xen/lib.h>
> > +#include <xen/err.h>
> > +#include <xen/xmalloc.h>
> > +#include <xen/string.h>
> > +#include <xen/bitops.h>
> > +#include <xen/bug.h>
>
> Please sort alphabetically. Same for the other new files.
>
> > +#define MAX_EXTERN_MPI_BITS 16384
> > +
> > +/* Define it to a value which is good on most machines.
> > + * tested 4, 16, 32 and 64, where 16 gave the best performance when
> > + * checking a 768 and a 1024 bit ElGamal signature.
> > + * (wk 22.12.97) */
> > +#define KARATSUBA_THRESHOLD 16
> > +
> > +typedef mpi_limb_t *mpi_ptr_t;       /* pointer to a limb */
> > +typedef int mpi_size_t;              /* (must be a signed type) */
> > +
> > +/* Copy N limbs from S to D.  */
> > +#define MPN_COPY(d, s, n) \
> > +     do {                                    \
> > +             mpi_size_t _i;                  \
>
> With this and ...
>
> > +             for (_i = 0; _i < (n); _i++)    \
> > +                     (d)[_i] = (s)[_i];      \
> > +     } while (0)
> > +
> > +#define MPN_COPY_DECR(d, s, n) \
> > +     do {                                    \
> > +             mpi_size_t _i;                  \
>
> ... this I wonder why ...
>
> > +             for (_i = (n)-1; _i >= 0; _i--) \
> > +                     (d)[_i] = (s)[_i];      \
> > +     } while (0)
> > +
> > +/* Zero N limbs at D */
> > +#define MPN_ZERO(d, n) \
> > +     do {                                    \
> > +             int  _i;                        \
>
> ... this is plain int. There are apparently many similar issue.
>
> >[...]
> > +leave:
>
> Here and elsewhere - labels indented by at least one blank, please.
>
> > --- /dev/null
> > +++ b/xen/crypto/rsa.c
> > @@ -0,0 +1,194 @@
> > +/* rsa.c
> > +
> > +   The RSA publickey algorithm.
> > +
> > +   Copyright (C) 2001 Niels Möller
> > +
> > +   This file is part of GNU Nettle.
> > +
> > +   GNU Nettle is free software: you can redistribute it and/or
> > +   modify it under the terms of either:
> > +
> > +     * the GNU Lesser General Public License as published by the Free
> > +       Software Foundation; either version 3 of the License, or (at your
> > +       option) any later version.
> > +
> > +   or
> > +
> > +     * the GNU General Public License as published by the Free
> > +       Software Foundation; either version 2 of the License, or (at your
> > +       option) any later version.
> > +
> > +   or both in parallel, as here.
> > +
> > +   GNU Nettle is distributed in the hope that it will be useful,
> > +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> > +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> > +   General Public License for more details.
> > +
> > +   You should have received copies of the GNU General Public License and
> > +   the GNU Lesser General Public License along with this program.  If
> > +   not, see http://www.gnu.org/licenses/.
> > +*/
> > +
> > +#include <xen/rsa.h>
> > +#include <xen/lib.h>
> > +#include <xen/err.h>
> > +#include <xen/bug.h>
> > +#include <xen/string.h>
> > +
> > +void rsa_public_key_init(struct rsa_public_key *key)
> > +{
> > +    key->n = NULL;
> > +    key->e = NULL;
> > +    key->size = 0;
> > +}
> > +
> > +/*
> > + * Computes the size, in octets, of the modulo. Returns 0 if the
> > + * modulo is too small to be useful, or otherwise appears invalid.
> > + */
> > +static size_t rsa_check_size(MPI n)
> > +{
> > +    /* Round upwards */
> > +    size_t size;
> > +
> > +    /* Even moduli are invalid */
> > +    if ( mpi_test_bit(n, 0) == 0 )
> > +        return 0;
> > +
> > +    size = (mpi_get_nbits(n) + 7) / 8;
> > +
> > +    if ( size < RSA_MINIMUM_N_OCTETS )
> > +        return 0;
> > +
> > +    return size;
> > +}
> > +
> > +int rsa_public_key_prepare(struct rsa_public_key *key)
> > +{
> > +    if ( !key->n || !key->e || key->size )
> > +        return -EINVAL;
> > +
> > +    key->size = rsa_check_size(key->n);
> > +
> > +    return key->size > 0 ? 0 : -EINVAL;
> > +}
> > +
> > +/*
> > + * Formats the PKCS#1 padding, of the form
> > + *
> > + *   0x00 0x01 0xff ... 0xff 0x00 id ...digest...
> > + *
> > + * where the 0xff ... 0xff part consists of at least 8 octets. The
> > + * total size equals the octet size of n.
> > + */
> > +static uint8_t *pkcs1_signature_prefix(unsigned int key_size, uint8_t 
> > *buffer,
> > +                                       unsigned int id_size, const uint8_t 
> > *id,
> > +                                       unsigned int digest_size)
> > +{
> > +    unsigned int j;
> > +
> > +    if ( key_size < 11 + id_size + digest_size )
> > +        return NULL;
> > +
> > +    j = key_size - digest_size - id_size;
> > +
> > +    memcpy(buffer + j, id, id_size);
> > +    buffer[0] = 0;
> > +    buffer[1] = 1;
> > +    buffer[j - 1] = 0;
> > +
> > +    ASSERT(j >= 11);
> > +    memset(buffer + 2, 0xff, j - 3);
> > +
> > +    return buffer + j + id_size;
> > +}
> > +
> > +/*
> > + * From RFC 3447, Public-Key Cryptography Standards (PKCS) #1: RSA
> > + * Cryptography Specifications Version 2.1.
> > + *
> > + *     id-sha256    OBJECT IDENTIFIER ::=
> > + *       {joint-iso-itu-t(2) country(16) us(840) organization(1)
> > + *         gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1}
> > + */
> > +static const uint8_t
> > +sha256_prefix[] =
> > +{
> > +  /* 19 octets prefix, 32 octets hash, total 51 */
> > +  0x30,      49, /* SEQUENCE */
> > +    0x30,    13, /* SEQUENCE */
> > +      0x06,   9, /* OBJECT IDENTIFIER */
> > +        0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
> > +      0x05,   0, /* NULL */
> > +    0x04,    32  /* OCTET STRING */
> > +      /* Here comes the raw hash value */
> > +};
> > +
> > +static int pkcs1_rsa_sha256_encode(MPI *m, size_t key_size,
> > +                                   struct sha2_256_state *hash)
> > +{
> > +    uint8_t *ptr;
> > +    uint8_t *buf;
> > +
> > +    buf = xmalloc_bytes(key_size);
> > +    if ( !buf )
> > +        return -ENOMEM;
> > +
> > +    ptr = pkcs1_signature_prefix(key_size, buf,
> > +                                 sizeof(sha256_prefix), sha256_prefix,
> > +                                 SHA2_256_DIGEST_SIZE);
> > +    if ( !ptr )
> > +    {
> > +        xfree(buf);
> > +        return -EINVAL;
> > +    }
> > +
> > +    sha2_256_final(hash, ptr);
> > +    *m = mpi_read_raw_data(buf, key_size);
> > +    xfree(buf);
> > +    return 0;
> > +}
> > +
> > +static int rsa_verify(const struct rsa_public_key *key, MPI m, MPI s)
> > +{
> > +    int ret;
> > +    MPI m1;
> > +
> > +    /* (1) Validate 0 <= s < n */
> > +    if ( mpi_cmp_ui(s, 0) < 0 || mpi_cmp(s, key->n) >= 0 )
> > +        return -EINVAL;
> > +
> > +    m1 = mpi_alloc(key->size / BYTES_PER_MPI_LIMB);
> > +    if ( !m1 )
> > +        return -ENOMEM;
> > +
> > +    /* (2) m = s^e mod n */
> > +    ret = mpi_powm(m1, s, key->e, key->n);
> > +    if ( ret )
> > +        goto out;
> > +
> > +    ret = mpi_cmp (m, m1) ? -EINVAL : 0;
>
> You look to have striven to convert this file to Xen style; there's a stray
> blank here, though.
>
> > --- /dev/null
> > +++ b/xen/include/xen/mpi.h
> > @@ -0,0 +1,63 @@
> > +/* mpi.h  -  Multi Precision Integers
> > + *        Copyright (C) 1994, 1996, 1998, 1999,
> > + *                    2000, 2001 Free Software Foundation, Inc.
> > + *
> > + * This file is part of GNUPG.
> > + *
> > + * GNUPG is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
>
> While this may want to remain, accompany it with an SPDX header? (Same
> elsewhere perhaps.)

Sure.

>
> > + * GNUPG is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write to the Free Software
> > + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
> > USA
> > + *
> > + * Note: This code is heavily based on the GNU MP Library.
> > + *         Actually it's the same code with only minor changes in the
> > + *         way the data is stored; this is to support the abstraction
> > + *         of an optional secure memory allocation which may be used
> > + *         to avoid revealing of sensitive data due to paging etc.
> > + *         The GNU MP Library itself is published under the LGPL;
> > + *         however I decided to publish this code under the plain GPL.
> > + */
> > +
> > +#ifndef MPI_H
> > +#define MPI_H
>
> This imo wants at least a XEN_ prefix. Same in rsa.h.
>
> > +#include <xen/types.h>
> > +
> > +#define BYTES_PER_MPI_LIMB      (BITS_PER_LONG / 8)
> > +#define BITS_PER_MPI_LIMB       BITS_PER_LONG
> > +
> > +typedef unsigned long int mpi_limb_t;
> > +typedef signed long int mpi_limb_signed_t;
> > +
> > +struct mpi {
> > +    int alloced;        /* array size (# of allocated limbs) */
> > +    int nlimbs;         /* number of valid limbs */
> > +    int nbits;          /* the real number of valid bits (info only) */
>
> I understand the goal likely is to not meaningfully change the original, but
> none of these look like they can hold negative values, and ...
>
> > +    int sign;           /* indicates a negative number */
>
> ... this one looks like it's a boolean.
>
> > +    unsigned flags;     /* bit 0: array must be allocated in secure memory 
> > space */
>
> In Xen we use "unsigned int", not plain "unsigned".

I'd prefer not to change the type from int to something else but I'll
fix the unsigned style issue.

Ross



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.