|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH 2/4] crypto: Add RSA support
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).
> + */
> +
> +#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.)
> + * 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".
> + /* bit 1: not used */
> + /* bit 2: the limb is a pointer to some m_alloced data */
I think these comments would better be padded to align with the earlier one.
The individual bits likely also want corresponding #define-s.
> --- /dev/null
> +++ b/xen/include/xen/rsa.h
> @@ -0,0 +1,72 @@
> +/* rsa.h
> +
> + The RSA publickey algorithm.
> +
> + Copyright (C) 2001, 2002 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/.
> +*/
> +
> +#ifndef RSA_H
> +#define RSA_H
> +
> +#include <xen/mpi.h>
> +#include <xen/sha2.h>
This isn't needed here, is it? All you need is ...
> +#include <xen/types.h>
> +
> +/*
> + * This limit is somewhat arbitrary. Technically, the smallest modulo
> + * which makes sense at all is 15 = 3*5, phi(15) = 8, size 4 bits. But
> + * for ridiculously small keys, not all odd e are possible (e.g., for
> + * 5 bits, the only possible modulo is 3*7 = 21, phi(21) = 12, and e =
> + * 3 don't work). The smallest size that makes sense with pkcs#1, and
> + * which allows RSA encryption of one byte messages, is 12 octets, 89
> + * bits.
> + */
> +#define RSA_MINIMUM_N_OCTETS 12
> +#define RSA_MINIMUM_N_BITS (8 * RSA_MINIMUM_N_OCTETS - 7)
> +
> +struct rsa_public_key
> +{
> + /*
> + * Size of the modulo, in octets. This is also the size of all
> + * signatures that are created or verified with this key.
> + */
> + size_t size;
> + MPI n; /* Modulo */
> + MPI e; /* Public exponent */
> +};
> +
> +void rsa_public_key_init(struct rsa_public_key *key);
> +
> +int rsa_public_key_prepare(struct rsa_public_key *key);
> +
> +int rsa_sha256_verify(const struct rsa_public_key *key,
> + struct sha2_256_state *hash,
... a forward decl of this type.
Jan
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |