summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/crypto
diff options
context:
space:
mode:
authorYang Zhang <yang.z.zhang@intel.com>2015-08-28 09:58:54 +0800
committerYang Zhang <yang.z.zhang@intel.com>2015-09-01 12:44:00 +0800
commite44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch)
tree66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/ipxe/src/crypto
parent9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff)
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5 Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/ipxe/src/crypto')
-rw-r--r--qemu/roms/ipxe/src/crypto/aes_wrap.c124
-rw-r--r--qemu/roms/ipxe/src/crypto/arc4.c132
-rw-r--r--qemu/roms/ipxe/src/crypto/asn1.c847
-rw-r--r--qemu/roms/ipxe/src/crypto/axtls/aes.c457
-rw-r--r--qemu/roms/ipxe/src/crypto/axtls/bigint.h99
-rw-r--r--qemu/roms/ipxe/src/crypto/axtls/bigint_impl.h131
-rw-r--r--qemu/roms/ipxe/src/crypto/axtls/config.h13
-rw-r--r--qemu/roms/ipxe/src/crypto/axtls/crypto.h229
-rw-r--r--qemu/roms/ipxe/src/crypto/axtls/os_port.h54
-rw-r--r--qemu/roms/ipxe/src/crypto/axtls_aes.c160
-rw-r--r--qemu/roms/ipxe/src/crypto/bigint.c135
-rw-r--r--qemu/roms/ipxe/src/crypto/cbc.c104
-rw-r--r--qemu/roms/ipxe/src/crypto/certstore.c275
-rw-r--r--qemu/roms/ipxe/src/crypto/chap.c125
-rw-r--r--qemu/roms/ipxe/src/crypto/cms.c709
-rw-r--r--qemu/roms/ipxe/src/crypto/crc32.c55
-rw-r--r--qemu/roms/ipxe/src/crypto/crypto_null.c137
-rw-r--r--qemu/roms/ipxe/src/crypto/deflate.c1045
-rw-r--r--qemu/roms/ipxe/src/crypto/drbg.c427
-rw-r--r--qemu/roms/ipxe/src/crypto/entropy.c479
-rw-r--r--qemu/roms/ipxe/src/crypto/hash_df.c138
-rw-r--r--qemu/roms/ipxe/src/crypto/hmac.c123
-rw-r--r--qemu/roms/ipxe/src/crypto/hmac_drbg.c359
-rw-r--r--qemu/roms/ipxe/src/crypto/md5.c298
-rw-r--r--qemu/roms/ipxe/src/crypto/null_entropy.c36
-rw-r--r--qemu/roms/ipxe/src/crypto/ocsp.c960
-rw-r--r--qemu/roms/ipxe/src/crypto/privkey.c118
-rw-r--r--qemu/roms/ipxe/src/crypto/random_nz.c76
-rw-r--r--qemu/roms/ipxe/src/crypto/rbg.c115
-rw-r--r--qemu/roms/ipxe/src/crypto/rootcert.c119
-rw-r--r--qemu/roms/ipxe/src/crypto/rsa.c705
-rw-r--r--qemu/roms/ipxe/src/crypto/sha1.c272
-rw-r--r--qemu/roms/ipxe/src/crypto/sha1extra.c168
-rw-r--r--qemu/roms/ipxe/src/crypto/sha256.c256
-rw-r--r--qemu/roms/ipxe/src/crypto/x509.c1765
35 files changed, 11245 insertions, 0 deletions
diff --git a/qemu/roms/ipxe/src/crypto/aes_wrap.c b/qemu/roms/ipxe/src/crypto/aes_wrap.c
new file mode 100644
index 000000000..c09480e5a
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/aes_wrap.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <string.h>
+#include <ipxe/crypto.h>
+#include <ipxe/aes.h>
+
+/**
+ * Wrap a key or other data using AES Key Wrap (RFC 3394)
+ *
+ * @v kek Key Encryption Key, 16 bytes
+ * @v src Data to encrypt
+ * @v nblk Number of 8-byte blocks in @a data
+ * @ret dest Encrypted data (8 bytes longer than input)
+ *
+ * The algorithm is implemented such that @a src and @a dest may point
+ * to the same buffer.
+ */
+int aes_wrap ( const void *kek, const void *src, void *dest, int nblk )
+{
+ u8 *A = dest;
+ u8 B[16];
+ u8 *R;
+ int i, j;
+ void *aes_ctx = malloc ( AES_CTX_SIZE );
+
+ if ( ! aes_ctx )
+ return -1;
+
+ cipher_setkey ( &aes_algorithm, aes_ctx, kek, 16 );
+
+ /* Set up */
+ memset ( A, 0xA6, 8 );
+ memmove ( dest + 8, src, nblk * 8 );
+
+ /* Wrap */
+ for ( j = 0; j < 6; j++ ) {
+ R = dest + 8;
+ for ( i = 1; i <= nblk; i++ ) {
+ memcpy ( B, A, 8 );
+ memcpy ( B + 8, R, 8 );
+ cipher_encrypt ( &aes_algorithm, aes_ctx, B, B, 16 );
+ memcpy ( A, B, 8 );
+ A[7] ^= ( nblk * j ) + i;
+ memcpy ( R, B + 8, 8 );
+ R += 8;
+ }
+ }
+
+ free ( aes_ctx );
+ return 0;
+}
+
+/**
+ * Unwrap a key or other data using AES Key Wrap (RFC 3394)
+ *
+ * @v kek Key Encryption Key, 16 bytes
+ * @v src Data to decrypt
+ * @v nblk Number of 8-byte blocks in @e plaintext key
+ * @ret dest Decrypted data (8 bytes shorter than input)
+ * @ret rc Zero on success, nonzero on IV mismatch
+ *
+ * The algorithm is implemented such that @a src and @a dest may point
+ * to the same buffer.
+ */
+int aes_unwrap ( const void *kek, const void *src, void *dest, int nblk )
+{
+ u8 A[8], B[16];
+ u8 *R;
+ int i, j;
+ void *aes_ctx = malloc ( AES_CTX_SIZE );
+
+ if ( ! aes_ctx )
+ return -1;
+
+ cipher_setkey ( &aes_algorithm, aes_ctx, kek, 16 );
+
+ /* Set up */
+ memcpy ( A, src, 8 );
+ memmove ( dest, src + 8, nblk * 8 );
+
+ /* Unwrap */
+ for ( j = 5; j >= 0; j-- ) {
+ R = dest + ( nblk - 1 ) * 8;
+ for ( i = nblk; i >= 1; i-- ) {
+ memcpy ( B, A, 8 );
+ memcpy ( B + 8, R, 8 );
+ B[7] ^= ( nblk * j ) + i;
+ cipher_decrypt ( &aes_algorithm, aes_ctx, B, B, 16 );
+ memcpy ( A, B, 8 );
+ memcpy ( R, B + 8, 8 );
+ R -= 8;
+ }
+ }
+
+ free ( aes_ctx );
+
+ /* Check IV */
+ for ( i = 0; i < 8; i++ ) {
+ if ( A[i] != 0xA6 )
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/qemu/roms/ipxe/src/crypto/arc4.c b/qemu/roms/ipxe/src/crypto/arc4.c
new file mode 100644
index 000000000..91a732019
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/arc4.c
@@ -0,0 +1,132 @@
+/*
+ * The ARC4 stream cipher.
+ *
+ * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/crypto.h>
+#include <ipxe/arc4.h>
+
+#define SWAP( ary, i, j ) \
+ ({ u8 temp = ary[i]; ary[i] = ary[j]; ary[j] = temp; })
+
+/**
+ * Set ARC4 key
+ *
+ * @v ctxv ARC4 encryption context
+ * @v keyv Key to set
+ * @v keylen Length of key
+ *
+ * If an initialisation vector is to be used, it should be prepended
+ * to the key; ARC4 does not implement the @c setiv function because
+ * there is no standard length for an initialisation vector in the
+ * cipher.
+ */
+static int arc4_setkey ( void *ctxv, const void *keyv, size_t keylen )
+{
+ struct arc4_ctx *ctx = ctxv;
+ const u8 *key = keyv;
+ u8 *S = ctx->state;
+ int i, j;
+
+ for ( i = 0; i < 256; i++ ) {
+ S[i] = i;
+ }
+
+ for ( i = j = 0; i < 256; i++ ) {
+ j = ( j + S[i] + key[i % keylen] ) & 0xff;
+ SWAP ( S, i, j );
+ }
+
+ ctx->i = ctx->j = 0;
+ return 0;
+}
+
+/**
+ * Perform ARC4 encryption or decryption
+ *
+ * @v ctxv ARC4 encryption context
+ * @v srcv Data to encrypt or decrypt
+ * @v dstv Location to store encrypted or decrypted data
+ * @v len Length of data to operate on
+ *
+ * ARC4 is a stream cipher that works by generating a stream of PRNG
+ * data based on the key, and XOR'ing it with the data to be
+ * encrypted. Since XOR is symmetric, encryption and decryption in
+ * ARC4 are the same operation.
+ *
+ * If you pass a @c NULL source or destination pointer, @a len
+ * keystream bytes will be consumed without encrypting any data.
+ */
+static void arc4_xor ( void *ctxv, const void *srcv, void *dstv,
+ size_t len )
+{
+ struct arc4_ctx *ctx = ctxv;
+ const u8 *src = srcv;
+ u8 *dst = dstv;
+ u8 *S = ctx->state;
+ int i = ctx->i, j = ctx->j;
+
+ while ( len-- ) {
+ i = ( i + 1 ) & 0xff;
+ j = ( j + S[i] ) & 0xff;
+ SWAP ( S, i, j );
+ if ( srcv && dstv )
+ *dst++ = *src++ ^ S[(S[i] + S[j]) & 0xff];
+ }
+
+ ctx->i = i;
+ ctx->j = j;
+}
+
+static void arc4_setiv ( void *ctx __unused, const void *iv __unused )
+{
+ /* ARC4 does not use a fixed-length IV */
+}
+
+
+/**
+ * Perform ARC4 encryption or decryption, skipping initial keystream bytes
+ *
+ * @v key ARC4 encryption key
+ * @v keylen Key length
+ * @v skip Number of bytes of keystream to skip
+ * @v src Message to encrypt or decrypt
+ * @v msglen Length of message
+ * @ret dst Encrypted or decrypted message
+ */
+void arc4_skip ( const void *key, size_t keylen, size_t skip,
+ const void *src, void *dst, size_t msglen )
+{
+ struct arc4_ctx ctx;
+ arc4_setkey ( &ctx, key, keylen );
+ arc4_xor ( &ctx, NULL, NULL, skip );
+ arc4_xor ( &ctx, src, dst, msglen );
+}
+
+struct cipher_algorithm arc4_algorithm = {
+ .name = "ARC4",
+ .ctxsize = ARC4_CTX_SIZE,
+ .blocksize = 1,
+ .setkey = arc4_setkey,
+ .setiv = arc4_setiv,
+ .encrypt = arc4_xor,
+ .decrypt = arc4_xor,
+};
diff --git a/qemu/roms/ipxe/src/crypto/asn1.c b/qemu/roms/ipxe/src/crypto/asn1.c
new file mode 100644
index 000000000..6d880704f
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/asn1.c
@@ -0,0 +1,847 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <time.h>
+#include <ipxe/tables.h>
+#include <ipxe/asn1.h>
+
+/** @file
+ *
+ * ASN.1 encoding
+ *
+ */
+
+/* Disambiguate the various error causes */
+#define EINVAL_ASN1_EMPTY \
+ __einfo_error ( EINFO_EINVAL_ASN1_EMPTY )
+#define EINFO_EINVAL_ASN1_EMPTY \
+ __einfo_uniqify ( EINFO_EINVAL, 0x01, "Empty or underlength cursor" )
+#define EINVAL_ASN1_LEN_LEN \
+ __einfo_error ( EINFO_EINVAL_ASN1_LEN_LEN )
+#define EINFO_EINVAL_ASN1_LEN_LEN \
+ __einfo_uniqify ( EINFO_EINVAL, 0x02, "Length field overruns cursor" )
+#define EINVAL_ASN1_LEN \
+ __einfo_error ( EINFO_EINVAL_ASN1_LEN )
+#define EINFO_EINVAL_ASN1_LEN \
+ __einfo_uniqify ( EINFO_EINVAL, 0x03, "Field overruns cursor" )
+#define EINVAL_ASN1_BOOLEAN \
+ __einfo_error ( EINFO_EINVAL_ASN1_BOOLEAN )
+#define EINFO_EINVAL_ASN1_BOOLEAN \
+ __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid boolean" )
+#define EINVAL_ASN1_INTEGER \
+ __einfo_error ( EINFO_EINVAL_ASN1_INTEGER )
+#define EINFO_EINVAL_ASN1_INTEGER \
+ __einfo_uniqify ( EINFO_EINVAL, 0x04, "Invalid integer" )
+#define EINVAL_ASN1_TIME \
+ __einfo_error ( EINFO_EINVAL_ASN1_TIME )
+#define EINFO_EINVAL_ASN1_TIME \
+ __einfo_uniqify ( EINFO_EINVAL, 0x05, "Invalid time" )
+#define EINVAL_ASN1_ALGORITHM \
+ __einfo_error ( EINFO_EINVAL_ASN1_ALGORITHM )
+#define EINFO_EINVAL_ASN1_ALGORITHM \
+ __einfo_uniqify ( EINFO_EINVAL, 0x06, "Invalid algorithm" )
+#define EINVAL_BIT_STRING \
+ __einfo_error ( EINFO_EINVAL_BIT_STRING )
+#define EINFO_EINVAL_BIT_STRING \
+ __einfo_uniqify ( EINFO_EINVAL, 0x07, "Invalid bit string" )
+#define ENOTSUP_ALGORITHM \
+ __einfo_error ( EINFO_ENOTSUP_ALGORITHM )
+#define EINFO_ENOTSUP_ALGORITHM \
+ __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported algorithm" )
+#define ENOTTY_ALGORITHM \
+ __einfo_error ( EINFO_ENOTTY_ALGORITHM )
+#define EINFO_ENOTTY_ALGORITHM \
+ __einfo_uniqify ( EINFO_ENOTTY, 0x01, "Inappropriate algorithm" )
+
+/**
+ * Invalidate ASN.1 object cursor
+ *
+ * @v cursor ASN.1 object cursor
+ */
+void asn1_invalidate_cursor ( struct asn1_cursor *cursor ) {
+ static uint8_t asn1_invalid_object[] = { ASN1_END, 0 };
+
+ cursor->data = asn1_invalid_object;
+ cursor->len = 0;
+}
+
+/**
+ * Start parsing ASN.1 object
+ *
+ * @v cursor ASN.1 object cursor
+ * @v type Expected type, or ASN1_ANY
+ * @ret len Length of object body, or negative error
+ *
+ * The object cursor will be updated to point to the start of the
+ * object body (i.e. the first byte following the length byte(s)), and
+ * the length of the object body (i.e. the number of bytes until the
+ * following object tag, if any) is returned.
+ */
+static int asn1_start ( struct asn1_cursor *cursor, unsigned int type ) {
+ unsigned int len_len;
+ unsigned int len;
+
+ /* Sanity check */
+ if ( cursor->len < 2 /* Tag byte and first length byte */ ) {
+ if ( cursor->len )
+ DBGC ( cursor, "ASN1 %p too short\n", cursor );
+ return -EINVAL_ASN1_EMPTY;
+ }
+
+ /* Check the tag byte */
+ if ( ( type != ASN1_ANY ) && ( type != asn1_type ( cursor ) ) ) {
+ DBGC ( cursor, "ASN1 %p type mismatch (expected %d, got %d)\n",
+ cursor, type, *( ( uint8_t * ) cursor->data ) );
+ return -ENXIO;
+ }
+ cursor->data++;
+ cursor->len--;
+
+ /* Extract length of the length field and sanity check */
+ len_len = *( ( uint8_t * ) cursor->data );
+ if ( len_len & 0x80 ) {
+ len_len = ( len_len & 0x7f );
+ cursor->data++;
+ cursor->len--;
+ } else {
+ len_len = 1;
+ }
+ if ( cursor->len < len_len ) {
+ DBGC ( cursor, "ASN1 %p bad length field length %d (max "
+ "%zd)\n", cursor, len_len, cursor->len );
+ return -EINVAL_ASN1_LEN_LEN;
+ }
+
+ /* Extract the length and sanity check */
+ for ( len = 0 ; len_len ; len_len-- ) {
+ len <<= 8;
+ len |= *( ( uint8_t * ) cursor->data );
+ cursor->data++;
+ cursor->len--;
+ }
+ if ( cursor->len < len ) {
+ DBGC ( cursor, "ASN1 %p bad length %d (max %zd)\n",
+ cursor, len, cursor->len );
+ return -EINVAL_ASN1_LEN;
+ }
+
+ return len;
+}
+
+/**
+ * Enter ASN.1 object
+ *
+ * @v cursor ASN.1 object cursor
+ * @v type Expected type, or ASN1_ANY
+ * @ret rc Return status code
+ *
+ * The object cursor will be updated to point to the body of the
+ * current ASN.1 object. If any error occurs, the object cursor will
+ * be invalidated.
+ */
+int asn1_enter ( struct asn1_cursor *cursor, unsigned int type ) {
+ int len;
+
+ len = asn1_start ( cursor, type );
+ if ( len < 0 ) {
+ asn1_invalidate_cursor ( cursor );
+ return len;
+ }
+
+ cursor->len = len;
+ DBGC ( cursor, "ASN1 %p entered object type %02x (len %x)\n",
+ cursor, type, len );
+
+ return 0;
+}
+
+/**
+ * Skip ASN.1 object if present
+ *
+ * @v cursor ASN.1 object cursor
+ * @v type Expected type, or ASN1_ANY
+ * @ret rc Return status code
+ *
+ * The object cursor will be updated to point to the next ASN.1
+ * object. If any error occurs, the object cursor will not be
+ * modified.
+ */
+int asn1_skip_if_exists ( struct asn1_cursor *cursor, unsigned int type ) {
+ int len;
+
+ len = asn1_start ( cursor, type );
+ if ( len < 0 )
+ return len;
+
+ cursor->data += len;
+ cursor->len -= len;
+ DBGC ( cursor, "ASN1 %p skipped object type %02x (len %x)\n",
+ cursor, type, len );
+
+ if ( ! cursor->len ) {
+ DBGC ( cursor, "ASN1 %p reached end of object\n", cursor );
+ return -ENOENT;
+ }
+
+ return 0;
+}
+
+/**
+ * Skip ASN.1 object
+ *
+ * @v cursor ASN.1 object cursor
+ * @v type Expected type, or ASN1_ANY
+ * @ret rc Return status code
+ *
+ * The object cursor will be updated to point to the next ASN.1
+ * object. If any error occurs, the object cursor will be
+ * invalidated.
+ */
+int asn1_skip ( struct asn1_cursor *cursor, unsigned int type ) {
+ int rc;
+
+ if ( ( rc = asn1_skip_if_exists ( cursor, type ) ) != 0 ) {
+ asn1_invalidate_cursor ( cursor );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Shrink ASN.1 cursor to fit object
+ *
+ * @v cursor ASN.1 object cursor
+ * @v type Expected type, or ASN1_ANY
+ * @ret rc Return status code
+ *
+ * The object cursor will be shrunk to contain only the current ASN.1
+ * object. If any error occurs, the object cursor will be
+ * invalidated.
+ */
+int asn1_shrink ( struct asn1_cursor *cursor, unsigned int type ) {
+ struct asn1_cursor temp;
+ const void *end;
+ int len;
+
+ /* Find end of object */
+ memcpy ( &temp, cursor, sizeof ( temp ) );
+ len = asn1_start ( &temp, type );
+ if ( len < 0 ) {
+ asn1_invalidate_cursor ( cursor );
+ return len;
+ }
+ end = ( temp.data + len );
+
+ /* Shrink original cursor to contain only its first object */
+ cursor->len = ( end - cursor->data );
+
+ return 0;
+}
+
+/**
+ * Enter ASN.1 object of any type
+ *
+ * @v cursor ASN.1 object cursor
+ * @ret rc Return status code
+ */
+int asn1_enter_any ( struct asn1_cursor *cursor ) {
+ return asn1_enter ( cursor, ASN1_ANY );
+}
+
+/**
+ * Skip ASN.1 object of any type
+ *
+ * @v cursor ASN.1 object cursor
+ * @ret rc Return status code
+ */
+int asn1_skip_any ( struct asn1_cursor *cursor ) {
+ return asn1_skip ( cursor, ASN1_ANY );
+}
+
+/**
+ * Shrink ASN.1 object of any type
+ *
+ * @v cursor ASN.1 object cursor
+ * @ret rc Return status code
+ */
+int asn1_shrink_any ( struct asn1_cursor *cursor ) {
+ return asn1_shrink ( cursor, ASN1_ANY );
+}
+
+/**
+ * Parse value of ASN.1 boolean
+ *
+ * @v cursor ASN.1 object cursor
+ * @ret value Value, or negative error
+ */
+int asn1_boolean ( const struct asn1_cursor *cursor ) {
+ struct asn1_cursor contents;
+ const struct {
+ uint8_t value;
+ } __attribute__ (( packed )) *boolean;
+
+ /* Enter boolean */
+ memcpy ( &contents, cursor, sizeof ( contents ) );
+ asn1_enter ( &contents, ASN1_BOOLEAN );
+ if ( contents.len != sizeof ( *boolean ) )
+ return -EINVAL_ASN1_BOOLEAN;
+
+ /* Extract value */
+ boolean = contents.data;
+ return boolean->value;
+}
+
+/**
+ * Parse value of ASN.1 integer
+ *
+ * @v cursor ASN.1 object cursor
+ * @v value Value to fill in
+ * @ret rc Return status code
+ */
+int asn1_integer ( const struct asn1_cursor *cursor, int *value ) {
+ struct asn1_cursor contents;
+ uint8_t high_byte;
+ int rc;
+
+ /* Enter integer */
+ memcpy ( &contents, cursor, sizeof ( contents ) );
+ if ( ( rc = asn1_enter ( &contents, ASN1_INTEGER ) ) != 0 )
+ return rc;
+ if ( contents.len < 1 )
+ return -EINVAL_ASN1_INTEGER;
+
+ /* Initialise value according to sign byte */
+ *value = *( ( int8_t * ) contents.data );
+ contents.data++;
+ contents.len--;
+
+ /* Process value */
+ while ( contents.len ) {
+ high_byte = ( (*value) >> ( 8 * ( sizeof ( *value ) - 1 ) ) );
+ if ( ( high_byte != 0x00 ) && ( high_byte != 0xff ) ) {
+ DBGC ( cursor, "ASN1 %p integer overflow\n", cursor );
+ return -EINVAL_ASN1_INTEGER;
+ }
+ *value = ( ( *value << 8 ) | *( ( uint8_t * ) contents.data ) );
+ contents.data++;
+ contents.len--;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse ASN.1 bit string
+ *
+ * @v cursor ASN.1 cursor
+ * @v bits Bit string to fill in
+ * @ret rc Return status code
+ */
+int asn1_bit_string ( const struct asn1_cursor *cursor,
+ struct asn1_bit_string *bits ) {
+ struct asn1_cursor contents;
+ const struct {
+ uint8_t unused;
+ uint8_t data[0];
+ } __attribute__ (( packed )) *bit_string;
+ size_t len;
+ unsigned int unused;
+ uint8_t unused_mask;
+ const uint8_t *last;
+ int rc;
+
+ /* Enter bit string */
+ memcpy ( &contents, cursor, sizeof ( contents ) );
+ if ( ( rc = asn1_enter ( &contents, ASN1_BIT_STRING ) ) != 0 ) {
+ DBGC ( cursor, "ASN1 %p cannot locate bit string:\n", cursor );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return rc;
+ }
+
+ /* Validity checks */
+ if ( contents.len < sizeof ( *bit_string ) ) {
+ DBGC ( cursor, "ASN1 %p invalid bit string:\n", cursor );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return -EINVAL_BIT_STRING;
+ }
+ bit_string = contents.data;
+ len = ( contents.len - offsetof ( typeof ( *bit_string ), data ) );
+ unused = bit_string->unused;
+ unused_mask = ( 0xff >> ( 8 - unused ) );
+ last = ( bit_string->data + len - 1 );
+ if ( ( unused >= 8 ) ||
+ ( ( unused > 0 ) && ( len == 0 ) ) ||
+ ( ( *last & unused_mask ) != 0 ) ) {
+ DBGC ( cursor, "ASN1 %p invalid bit string:\n", cursor );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return -EINVAL_BIT_STRING;
+ }
+
+ /* Populate bit string */
+ bits->data = &bit_string->data;
+ bits->len = len;
+ bits->unused = unused;
+
+ return 0;
+}
+
+/**
+ * Parse ASN.1 bit string that must be an integral number of bytes
+ *
+ * @v cursor ASN.1 cursor
+ * @v bits Bit string to fill in
+ * @ret rc Return status code
+ */
+int asn1_integral_bit_string ( const struct asn1_cursor *cursor,
+ struct asn1_bit_string *bits ) {
+ int rc;
+
+ /* Parse bit string */
+ if ( ( rc = asn1_bit_string ( cursor, bits ) ) != 0 )
+ return rc;
+
+ /* Check that there are no unused bits at end of string */
+ if ( bits->unused ) {
+ DBGC ( cursor, "ASN1 %p invalid integral bit string:\n",
+ cursor );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return -EINVAL_BIT_STRING;
+ }
+
+ return 0;
+}
+
+/**
+ * Compare two ASN.1 objects
+ *
+ * @v cursor1 ASN.1 object cursor
+ * @v cursor2 ASN.1 object cursor
+ * @ret difference Difference as returned by memcmp()
+ *
+ * Note that invalid and empty cursors will compare as equal with each
+ * other.
+ */
+int asn1_compare ( const struct asn1_cursor *cursor1,
+ const struct asn1_cursor *cursor2 ) {
+ int difference;
+
+ difference = ( cursor2->len - cursor1->len );
+ return ( difference ? difference :
+ memcmp ( cursor1->data, cursor2->data, cursor1->len ) );
+}
+
+/**
+ * Identify ASN.1 algorithm by OID
+ *
+ * @v cursor ASN.1 object cursor
+
+ * @ret algorithm Algorithm, or NULL
+ */
+static struct asn1_algorithm *
+asn1_find_algorithm ( const struct asn1_cursor *cursor ) {
+ struct asn1_algorithm *algorithm;
+
+ for_each_table_entry ( algorithm, ASN1_ALGORITHMS ) {
+ if ( asn1_compare ( &algorithm->oid, cursor ) == 0 )
+ return algorithm;
+ }
+
+ return NULL;
+}
+
+/**
+ * Parse ASN.1 OID-identified algorithm
+ *
+ * @v cursor ASN.1 object cursor
+ * @ret algorithm Algorithm
+ * @ret rc Return status code
+ */
+int asn1_algorithm ( const struct asn1_cursor *cursor,
+ struct asn1_algorithm **algorithm ) {
+ struct asn1_cursor contents;
+ int rc;
+
+ /* Enter signatureAlgorithm */
+ memcpy ( &contents, cursor, sizeof ( contents ) );
+ asn1_enter ( &contents, ASN1_SEQUENCE );
+
+ /* Enter algorithm */
+ if ( ( rc = asn1_enter ( &contents, ASN1_OID ) ) != 0 ) {
+ DBGC ( cursor, "ASN1 %p cannot locate algorithm OID:\n",
+ cursor );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return -EINVAL_ASN1_ALGORITHM;
+ }
+
+ /* Identify algorithm */
+ *algorithm = asn1_find_algorithm ( &contents );
+ if ( ! *algorithm ) {
+ DBGC ( cursor, "ASN1 %p unrecognised algorithm:\n", cursor );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return -ENOTSUP_ALGORITHM;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse ASN.1 OID-identified public-key algorithm
+ *
+ * @v cursor ASN.1 object cursor
+ * @ret algorithm Algorithm
+ * @ret rc Return status code
+ */
+int asn1_pubkey_algorithm ( const struct asn1_cursor *cursor,
+ struct asn1_algorithm **algorithm ) {
+ int rc;
+
+ /* Parse algorithm */
+ if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
+ return rc;
+
+ /* Check algorithm has a public key */
+ if ( ! (*algorithm)->pubkey ) {
+ DBGC ( cursor, "ASN1 %p algorithm %s is not a public-key "
+ "algorithm:\n", cursor, (*algorithm)->name );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return -ENOTTY_ALGORITHM;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse ASN.1 OID-identified digest algorithm
+ *
+ * @v cursor ASN.1 object cursor
+ * @ret algorithm Algorithm
+ * @ret rc Return status code
+ */
+int asn1_digest_algorithm ( const struct asn1_cursor *cursor,
+ struct asn1_algorithm **algorithm ) {
+ int rc;
+
+ /* Parse algorithm */
+ if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
+ return rc;
+
+ /* Check algorithm has a digest */
+ if ( ! (*algorithm)->digest ) {
+ DBGC ( cursor, "ASN1 %p algorithm %s is not a digest "
+ "algorithm:\n", cursor, (*algorithm)->name );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return -ENOTTY_ALGORITHM;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse ASN.1 OID-identified signature algorithm
+ *
+ * @v cursor ASN.1 object cursor
+ * @ret algorithm Algorithm
+ * @ret rc Return status code
+ */
+int asn1_signature_algorithm ( const struct asn1_cursor *cursor,
+ struct asn1_algorithm **algorithm ) {
+ int rc;
+
+ /* Parse algorithm */
+ if ( ( rc = asn1_algorithm ( cursor, algorithm ) ) != 0 )
+ return rc;
+
+ /* Check algorithm has a public key */
+ if ( ! (*algorithm)->pubkey ) {
+ DBGC ( cursor, "ASN1 %p algorithm %s is not a signature "
+ "algorithm:\n", cursor, (*algorithm)->name );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return -ENOTTY_ALGORITHM;
+ }
+
+ /* Check algorithm has a digest */
+ if ( ! (*algorithm)->digest ) {
+ DBGC ( cursor, "ASN1 %p algorithm %s is not a signature "
+ "algorithm:\n", cursor, (*algorithm)->name );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return -ENOTTY_ALGORITHM;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse ASN.1 GeneralizedTime
+ *
+ * @v cursor ASN.1 cursor
+ * @v time Time to fill in
+ * @ret rc Return status code
+ *
+ * RFC 5280 section 4.1.2.5 places several restrictions on the allowed
+ * formats for UTCTime and GeneralizedTime, and mandates the
+ * interpretation of centuryless year values.
+ */
+int asn1_generalized_time ( const struct asn1_cursor *cursor, time_t *time ) {
+ struct asn1_cursor contents;
+ unsigned int have_century;
+ unsigned int type;
+ union {
+ struct {
+ uint8_t century;
+ uint8_t year;
+ uint8_t month;
+ uint8_t day;
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ } __attribute__ (( packed )) named;
+ uint8_t raw[7];
+ } pairs;
+ struct tm tm;
+ const uint8_t *data;
+ size_t remaining;
+ unsigned int tens;
+ unsigned int units;
+ unsigned int i;
+ int rc;
+
+ /* Determine time format utcTime/generalizedTime */
+ memcpy ( &contents, cursor, sizeof ( contents ) );
+ type = asn1_type ( &contents );
+ switch ( type ) {
+ case ASN1_UTC_TIME:
+ have_century = 0;
+ break;
+ case ASN1_GENERALIZED_TIME:
+ have_century = 1;
+ break;
+ default:
+ DBGC ( cursor, "ASN1 %p invalid time type %02x\n",
+ cursor, type );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return -EINVAL_ASN1_TIME;
+ }
+
+ /* Enter utcTime/generalizedTime */
+ if ( ( rc = asn1_enter ( &contents, type ) ) != 0 ) {
+ DBGC ( cursor, "ASN1 %p cannot locate %s time:\n", cursor,
+ ( ( type == ASN1_UTC_TIME ) ? "UTC" : "generalized" ) );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return rc;
+ }
+
+ /* Parse digit string a pair at a time */
+ memset ( &pairs, 0, sizeof ( pairs ) );
+ data = contents.data;
+ remaining = contents.len;
+ for ( i = ( have_century ? 0 : 1 ) ; i < sizeof ( pairs.raw ) ; i++ ) {
+ if ( remaining < 2 ) {
+ /* Some certificates violate the X.509 RFC by
+ * omitting the "seconds" value.
+ */
+ if ( i == ( sizeof ( pairs.raw ) - 1 ) )
+ break;
+ DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return -EINVAL_ASN1_TIME;
+ }
+ tens = data[0];
+ units = data[1];
+ if ( ! ( isdigit ( tens ) && isdigit ( units ) ) ) {
+ DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return -EINVAL_ASN1_TIME;
+ }
+ pairs.raw[i] = ( ( 10 * ( tens - '0' ) ) + ( units - '0' ) );
+ data += 2;
+ remaining -= 2;
+ }
+
+ /* Determine century if applicable */
+ if ( ! have_century )
+ pairs.named.century = ( ( pairs.named.year >= 50 ) ? 19 : 20 );
+
+ /* Check for trailing "Z" */
+ if ( ( remaining != 1 ) || ( data[0] != 'Z' ) ) {
+ DBGC ( cursor, "ASN1 %p invalid time:\n", cursor );
+ DBGC_HDA ( cursor, 0, cursor->data, cursor->len );
+ return -EINVAL_ASN1_TIME;
+ }
+
+ /* Fill in time */
+ tm.tm_year = ( ( ( pairs.named.century - 19 ) * 100 ) +
+ pairs.named.year );
+ tm.tm_mon = ( pairs.named.month - 1 );
+ tm.tm_mday = pairs.named.day;
+ tm.tm_hour = pairs.named.hour;
+ tm.tm_min = pairs.named.minute;
+ tm.tm_sec = pairs.named.second;
+
+ /* Convert to seconds since the Epoch */
+ *time = mktime ( &tm );
+
+ return 0;
+}
+
+/**
+ * Construct ASN.1 header
+ *
+ * @v header ASN.1 builder header
+ * @v type Type
+ * @v len Content length
+ * @ret header_len Header length
+ */
+static size_t asn1_header ( struct asn1_builder_header *header,
+ unsigned int type, size_t len ) {
+ unsigned int header_len = 2;
+ unsigned int len_len = 0;
+ size_t temp;
+
+ /* Construct header */
+ header->type = type;
+ if ( len < 0x80 ) {
+ header->length[0] = len;
+ } else {
+ for ( temp = len ; temp ; temp >>= 8 )
+ len_len++;
+ header->length[0] = ( 0x80 | len_len );
+ header_len += len_len;
+ for ( temp = len ; temp ; temp >>= 8 )
+ header->length[len_len--] = ( temp & 0xff );
+ }
+
+ return header_len;
+}
+
+/**
+ * Grow ASN.1 builder
+ *
+ * @v builder ASN.1 builder
+ * @v extra Extra space to prepend
+ * @ret rc Return status code
+ */
+static int asn1_grow ( struct asn1_builder *builder, size_t extra ) {
+ size_t new_len;
+ void *new;
+
+ /* As with the ASN1 parsing functions, make errors permanent */
+ if ( builder->len && ! builder->data )
+ return -ENOMEM;
+
+ /* Reallocate data buffer */
+ new_len = ( builder->len + extra );
+ new = realloc ( builder->data, new_len );
+ if ( ! new ) {
+ free ( builder->data );
+ builder->data = NULL;
+ return -ENOMEM;
+ }
+ builder->data = new;
+
+ /* Move existing data to end of buffer */
+ memmove ( ( builder->data + extra ), builder->data, builder->len );
+ builder->len = new_len;
+
+ return 0;
+}
+
+/**
+ * Prepend raw data to ASN.1 builder
+ *
+ * @v builder ASN.1 builder
+ * @v data Data to prepend
+ * @v len Length of data to prepend
+ * @ret rc Return status code
+ */
+int asn1_prepend_raw ( struct asn1_builder *builder, const void *data,
+ size_t len ) {
+ int rc;
+
+ /* Grow buffer */
+ if ( ( rc = asn1_grow ( builder, len ) ) != 0 )
+ return rc;
+
+ /* Populate data buffer */
+ memcpy ( builder->data, data, len );
+
+ return 0;
+}
+
+/**
+ * Prepend data to ASN.1 builder
+ *
+ * @v builder ASN.1 builder
+ * @v type Type
+ * @v data Data to prepend
+ * @v len Length of data to prepend
+ * @ret rc Return status code
+ */
+int asn1_prepend ( struct asn1_builder *builder, unsigned int type,
+ const void *data, size_t len ) {
+ struct asn1_builder_header header;
+ size_t header_len;
+ int rc;
+
+ /* Construct header */
+ header_len = asn1_header ( &header, type, len );
+
+ /* Grow buffer */
+ if ( ( rc = asn1_grow ( builder, header_len + len ) ) != 0 )
+ return rc;
+
+ /* Populate data buffer */
+ memcpy ( builder->data, &header, header_len );
+ memcpy ( ( builder->data + header_len ), data, len );
+
+ return 0;
+}
+
+/**
+ * Wrap ASN.1 builder
+ *
+ * @v builder ASN.1 builder
+ * @v type Type
+ * @ret rc Return status code
+ */
+int asn1_wrap ( struct asn1_builder *builder, unsigned int type ) {
+ struct asn1_builder_header header;
+ size_t header_len;
+ int rc;
+
+ /* Construct header */
+ header_len = asn1_header ( &header, type, builder->len );
+
+ /* Grow buffer */
+ if ( ( rc = asn1_grow ( builder, header_len ) ) != 0 )
+ return rc;
+
+ /* Populate data buffer */
+ memcpy ( builder->data, &header, header_len );
+
+ return 0;
+}
diff --git a/qemu/roms/ipxe/src/crypto/axtls/aes.c b/qemu/roms/ipxe/src/crypto/axtls/aes.c
new file mode 100644
index 000000000..bd99a7097
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/axtls/aes.c
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * AES implementation - this is a small code version. There are much faster
+ * versions around but they are much larger in size (i.e. they use large
+ * submix tables).
+ */
+
+#include <string.h>
+#include "os_port.h"
+#include "crypto.h"
+
+/* all commented out in skeleton mode */
+#ifndef CONFIG_SSL_SKELETON_MODE
+
+#define rot1(x) (((x) << 24) | ((x) >> 8))
+#define rot2(x) (((x) << 16) | ((x) >> 16))
+#define rot3(x) (((x) << 8) | ((x) >> 24))
+
+/*
+ * This cute trick does 4 'mul by two' at once. Stolen from
+ * Dr B. R. Gladman <brg@gladman.uk.net> but I'm sure the u-(u>>7) is
+ * a standard graphics trick
+ * The key to this is that we need to xor with 0x1b if the top bit is set.
+ * a 1xxx xxxx 0xxx 0xxx First we mask the 7bit,
+ * b 1000 0000 0000 0000 then we shift right by 7 putting the 7bit in 0bit,
+ * c 0000 0001 0000 0000 we then subtract (c) from (b)
+ * d 0111 1111 0000 0000 and now we and with our mask
+ * e 0001 1011 0000 0000
+ */
+#define mt 0x80808080
+#define ml 0x7f7f7f7f
+#define mh 0xfefefefe
+#define mm 0x1b1b1b1b
+#define mul2(x,t) ((t)=((x)&mt), \
+ ((((x)+(x))&mh)^(((t)-((t)>>7))&mm)))
+
+#define inv_mix_col(x,f2,f4,f8,f9) (\
+ (f2)=mul2(x,f2), \
+ (f4)=mul2(f2,f4), \
+ (f8)=mul2(f4,f8), \
+ (f9)=(x)^(f8), \
+ (f8)=((f2)^(f4)^(f8)), \
+ (f2)^=(f9), \
+ (f4)^=(f9), \
+ (f8)^=rot3(f2), \
+ (f8)^=rot2(f4), \
+ (f8)^rot1(f9))
+
+/*
+ * AES S-box
+ */
+static const uint8_t aes_sbox[256] =
+{
+ 0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,
+ 0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76,
+ 0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,
+ 0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0,
+ 0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,
+ 0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15,
+ 0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,
+ 0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75,
+ 0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,
+ 0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84,
+ 0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,
+ 0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF,
+ 0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,
+ 0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8,
+ 0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,
+ 0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2,
+ 0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,
+ 0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73,
+ 0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,
+ 0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB,
+ 0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,
+ 0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79,
+ 0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,
+ 0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08,
+ 0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,
+ 0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A,
+ 0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,
+ 0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E,
+ 0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,
+ 0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF,
+ 0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,
+ 0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16,
+};
+
+/*
+ * AES is-box
+ */
+static const uint8_t aes_isbox[256] =
+{
+ 0x52,0x09,0x6a,0xd5,0x30,0x36,0xa5,0x38,
+ 0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,
+ 0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,
+ 0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,
+ 0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,
+ 0xee,0x4c,0x95,0x0b,0x42,0xfa,0xc3,0x4e,
+ 0x08,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,
+ 0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,
+ 0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,
+ 0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,
+ 0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,
+ 0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,
+ 0x90,0xd8,0xab,0x00,0x8c,0xbc,0xd3,0x0a,
+ 0xf7,0xe4,0x58,0x05,0xb8,0xb3,0x45,0x06,
+ 0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0x0f,0x02,
+ 0xc1,0xaf,0xbd,0x03,0x01,0x13,0x8a,0x6b,
+ 0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,
+ 0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,
+ 0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,
+ 0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,
+ 0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,
+ 0x6f,0xb7,0x62,0x0e,0xaa,0x18,0xbe,0x1b,
+ 0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,
+ 0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,
+ 0x1f,0xdd,0xa8,0x33,0x88,0x07,0xc7,0x31,
+ 0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,
+ 0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0x0d,
+ 0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,
+ 0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,
+ 0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,
+ 0x17,0x2b,0x04,0x7e,0xba,0x77,0xd6,0x26,
+ 0xe1,0x69,0x14,0x63,0x55,0x21,0x0c,0x7d
+};
+
+static const unsigned char Rcon[30]=
+{
+ 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,
+ 0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,
+ 0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,
+ 0xb3,0x7d,0xfa,0xef,0xc5,0x91,
+};
+
+/* ----- static functions ----- */
+static void AES_encrypt(const AES_CTX *ctx, uint32_t *data);
+static void AES_decrypt(const AES_CTX *ctx, uint32_t *data);
+
+/* Perform doubling in Galois Field GF(2^8) using the irreducible polynomial
+ x^8+x^4+x^3+x+1 */
+static unsigned char AES_xtime(uint32_t x)
+{
+ return (x&0x80) ? (x<<1)^0x1b : x<<1;
+}
+
+/**
+ * Set up AES with the key/iv and cipher size.
+ */
+void AES_set_key(AES_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, AES_MODE mode)
+{
+ int i, ii;
+ uint32_t *W, tmp, tmp2;
+ const unsigned char *ip;
+ int words;
+
+ switch (mode)
+ {
+ case AES_MODE_128:
+ i = 10;
+ words = 4;
+ break;
+
+ case AES_MODE_256:
+ i = 14;
+ words = 8;
+ break;
+
+ default: /* fail silently */
+ return;
+ }
+
+ ctx->rounds = i;
+ ctx->key_size = words;
+ W = ctx->ks;
+ for (i = 0; i < words; i+=2)
+ {
+ W[i+0]= ((uint32_t)key[ 0]<<24)|
+ ((uint32_t)key[ 1]<<16)|
+ ((uint32_t)key[ 2]<< 8)|
+ ((uint32_t)key[ 3] );
+ W[i+1]= ((uint32_t)key[ 4]<<24)|
+ ((uint32_t)key[ 5]<<16)|
+ ((uint32_t)key[ 6]<< 8)|
+ ((uint32_t)key[ 7] );
+ key += 8;
+ }
+
+ ip = Rcon;
+ ii = 4 * (ctx->rounds+1);
+ for (i = words; i<ii; i++)
+ {
+ tmp = W[i-1];
+
+ if ((i % words) == 0)
+ {
+ tmp2 =(uint32_t)aes_sbox[(tmp )&0xff]<< 8;
+ tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<<16;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<24;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>24) ];
+ tmp=tmp2^(((unsigned int)*ip)<<24);
+ ip++;
+ }
+
+ if ((words == 8) && ((i % words) == 4))
+ {
+ tmp2 =(uint32_t)aes_sbox[(tmp )&0xff] ;
+ tmp2|=(uint32_t)aes_sbox[(tmp>> 8)&0xff]<< 8;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>16)&0xff]<<16;
+ tmp2|=(uint32_t)aes_sbox[(tmp>>24) ]<<24;
+ tmp=tmp2;
+ }
+
+ W[i]=W[i-words]^tmp;
+ }
+
+ /* copy the iv across */
+ memcpy(ctx->iv, iv, 16);
+}
+
+/**
+ * Change a key for decryption.
+ */
+void AES_convert_key(AES_CTX *ctx)
+{
+ int i;
+ uint32_t *k,w,t1,t2,t3,t4;
+
+ k = ctx->ks;
+ k += 4;
+
+ for (i= ctx->rounds*4; i > 4; i--)
+ {
+ w= *k;
+ w = inv_mix_col(w,t1,t2,t3,t4);
+ *k++ =w;
+ }
+}
+
+/**
+ * Encrypt a byte sequence (with a block size 16) using the AES cipher.
+ */
+void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{
+ int i;
+ uint32_t tin[4], tout[4], iv[4];
+
+ memcpy(iv, ctx->iv, AES_IV_SIZE);
+ for (i = 0; i < 4; i++)
+ tout[i] = ntohl(iv[i]);
+
+ for (length -= AES_BLOCKSIZE; length >= 0; length -= AES_BLOCKSIZE)
+ {
+ uint32_t msg_32[4];
+ uint32_t out_32[4];
+ memcpy(msg_32, msg, AES_BLOCKSIZE);
+ msg += AES_BLOCKSIZE;
+
+ for (i = 0; i < 4; i++)
+ tin[i] = ntohl(msg_32[i])^tout[i];
+
+ AES_encrypt(ctx, tin);
+
+ for (i = 0; i < 4; i++)
+ {
+ tout[i] = tin[i];
+ out_32[i] = htonl(tout[i]);
+ }
+
+ memcpy(out, out_32, AES_BLOCKSIZE);
+ out += AES_BLOCKSIZE;
+ }
+
+ for (i = 0; i < 4; i++)
+ iv[i] = htonl(tout[i]);
+ memcpy(ctx->iv, iv, AES_IV_SIZE);
+}
+
+/**
+ * Decrypt a byte sequence (with a block size 16) using the AES cipher.
+ */
+void AES_cbc_decrypt(AES_CTX *ctx, const uint8_t *msg, uint8_t *out, int length)
+{
+ int i;
+ uint32_t tin[4], xor[4], tout[4], data[4], iv[4];
+
+ memcpy(iv, ctx->iv, AES_IV_SIZE);
+ for (i = 0; i < 4; i++)
+ xor[i] = ntohl(iv[i]);
+
+ for (length -= 16; length >= 0; length -= 16)
+ {
+ uint32_t msg_32[4];
+ uint32_t out_32[4];
+ memcpy(msg_32, msg, AES_BLOCKSIZE);
+ msg += AES_BLOCKSIZE;
+
+ for (i = 0; i < 4; i++)
+ {
+ tin[i] = ntohl(msg_32[i]);
+ data[i] = tin[i];
+ }
+
+ AES_decrypt(ctx, data);
+
+ for (i = 0; i < 4; i++)
+ {
+ tout[i] = data[i]^xor[i];
+ xor[i] = tin[i];
+ out_32[i] = htonl(tout[i]);
+ }
+
+ memcpy(out, out_32, AES_BLOCKSIZE);
+ out += AES_BLOCKSIZE;
+ }
+
+ for (i = 0; i < 4; i++)
+ iv[i] = htonl(xor[i]);
+ memcpy(ctx->iv, iv, AES_IV_SIZE);
+}
+
+/**
+ * Encrypt a single block (16 bytes) of data
+ */
+static void AES_encrypt(const AES_CTX *ctx, uint32_t *data)
+{
+ /* To make this code smaller, generate the sbox entries on the fly.
+ * This will have a really heavy effect upon performance.
+ */
+ uint32_t tmp[4];
+ uint32_t tmp1, old_a0, a0, a1, a2, a3, row;
+ int curr_rnd;
+ int rounds = ctx->rounds;
+ const uint32_t *k = ctx->ks;
+
+ /* Pre-round key addition */
+ for (row = 0; row < 4; row++)
+ data[row] ^= *(k++);
+
+ /* Encrypt one block. */
+ for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
+ {
+ /* Perform ByteSub and ShiftRow operations together */
+ for (row = 0; row < 4; row++)
+ {
+ a0 = (uint32_t)aes_sbox[(data[row%4]>>24)&0xFF];
+ a1 = (uint32_t)aes_sbox[(data[(row+1)%4]>>16)&0xFF];
+ a2 = (uint32_t)aes_sbox[(data[(row+2)%4]>>8)&0xFF];
+ a3 = (uint32_t)aes_sbox[(data[(row+3)%4])&0xFF];
+
+ /* Perform MixColumn iff not last round */
+ if (curr_rnd < (rounds - 1))
+ {
+ tmp1 = a0 ^ a1 ^ a2 ^ a3;
+ old_a0 = a0;
+ a0 ^= tmp1 ^ AES_xtime(a0 ^ a1);
+ a1 ^= tmp1 ^ AES_xtime(a1 ^ a2);
+ a2 ^= tmp1 ^ AES_xtime(a2 ^ a3);
+ a3 ^= tmp1 ^ AES_xtime(a3 ^ old_a0);
+ }
+
+ tmp[row] = ((a0 << 24) | (a1 << 16) | (a2 << 8) | a3);
+ }
+
+ /* KeyAddition - note that it is vital that this loop is separate from
+ the MixColumn operation, which must be atomic...*/
+ for (row = 0; row < 4; row++)
+ data[row] = tmp[row] ^ *(k++);
+ }
+}
+
+/**
+ * Decrypt a single block (16 bytes) of data
+ */
+static void AES_decrypt(const AES_CTX *ctx, uint32_t *data)
+{
+ uint32_t tmp[4];
+ uint32_t xt0,xt1,xt2,xt3,xt4,xt5,xt6;
+ uint32_t a0, a1, a2, a3, row;
+ int curr_rnd;
+ int rounds = ctx->rounds;
+ const uint32_t *k = ctx->ks + ((rounds+1)*4);
+
+ /* pre-round key addition */
+ for (row=4; row > 0;row--)
+ data[row-1] ^= *(--k);
+
+ /* Decrypt one block */
+ for (curr_rnd = 0; curr_rnd < rounds; curr_rnd++)
+ {
+ /* Perform ByteSub and ShiftRow operations together */
+ for (row = 4; row > 0; row--)
+ {
+ a0 = aes_isbox[(data[(row+3)%4]>>24)&0xFF];
+ a1 = aes_isbox[(data[(row+2)%4]>>16)&0xFF];
+ a2 = aes_isbox[(data[(row+1)%4]>>8)&0xFF];
+ a3 = aes_isbox[(data[row%4])&0xFF];
+
+ /* Perform MixColumn iff not last round */
+ if (curr_rnd<(rounds-1))
+ {
+ /* The MDS cofefficients (0x09, 0x0B, 0x0D, 0x0E)
+ are quite large compared to encryption; this
+ operation slows decryption down noticeably. */
+ xt0 = AES_xtime(a0^a1);
+ xt1 = AES_xtime(a1^a2);
+ xt2 = AES_xtime(a2^a3);
+ xt3 = AES_xtime(a3^a0);
+ xt4 = AES_xtime(xt0^xt1);
+ xt5 = AES_xtime(xt1^xt2);
+ xt6 = AES_xtime(xt4^xt5);
+
+ xt0 ^= a1^a2^a3^xt4^xt6;
+ xt1 ^= a0^a2^a3^xt5^xt6;
+ xt2 ^= a0^a1^a3^xt4^xt6;
+ xt3 ^= a0^a1^a2^xt5^xt6;
+ tmp[row-1] = ((xt0<<24)|(xt1<<16)|(xt2<<8)|xt3);
+ }
+ else
+ tmp[row-1] = ((a0<<24)|(a1<<16)|(a2<<8)|a3);
+ }
+
+ for (row = 4; row > 0; row--)
+ data[row-1] = tmp[row-1] ^ *(--k);
+ }
+}
+
+#endif
diff --git a/qemu/roms/ipxe/src/crypto/axtls/bigint.h b/qemu/roms/ipxe/src/crypto/axtls/bigint.h
new file mode 100644
index 000000000..1f38c53d6
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/axtls/bigint.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BIGINT_HEADER
+#define BIGINT_HEADER
+
+#include "crypto.h"
+
+BI_CTX *bi_initialize(void);
+void bi_terminate(BI_CTX *ctx);
+void bi_permanent(bigint *bi);
+void bi_depermanent(bigint *bi);
+void bi_clear_cache(BI_CTX *ctx);
+void bi_free(BI_CTX *ctx, bigint *bi);
+bigint *bi_copy(bigint *bi);
+bigint *bi_clone(BI_CTX *ctx, const bigint *bi);
+void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size);
+bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len);
+bigint *int_to_bi(BI_CTX *ctx, comp i);
+
+/* the functions that actually do something interesting */
+bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_subtract(BI_CTX *ctx, bigint *bia,
+ bigint *bib, int *is_negative);
+bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, int is_mod);
+bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib);
+bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp);
+bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, bigint *bim, bigint *biexp);
+int bi_compare(bigint *bia, bigint *bib);
+void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset);
+void bi_free_mod(BI_CTX *ctx, int mod_offset);
+
+#ifdef CONFIG_SSL_FULL_MODE
+void bi_print(const char *label, bigint *bi);
+bigint *bi_str_import(BI_CTX *ctx, const char *data);
+#endif
+
+/**
+ * @def bi_mod
+ * Find the residue of B. bi_set_mod() must be called before hand.
+ */
+#define bi_mod(A, B) bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1)
+
+/**
+ * bi_residue() is technically the same as bi_mod(), but it uses the
+ * appropriate reduction technique (which is bi_mod() when doing classical
+ * reduction).
+ */
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+#define bi_residue(A, B) bi_mont(A, B)
+bigint *bi_mont(BI_CTX *ctx, bigint *bixy);
+#elif defined(CONFIG_BIGINT_BARRETT)
+#define bi_residue(A, B) bi_barrett(A, B)
+bigint *bi_barrett(BI_CTX *ctx, bigint *bi);
+#else /* if defined(CONFIG_BIGINT_CLASSICAL) */
+#define bi_residue(A, B) bi_mod(A, B)
+#endif
+
+#ifdef CONFIG_BIGINT_SQUARE
+bigint *bi_square(BI_CTX *ctx, bigint *bi);
+#else
+#define bi_square(A, B) bi_multiply(A, bi_copy(B), B)
+#endif
+
+#ifdef CONFIG_BIGINT_CRT
+bigint *bi_crt(BI_CTX *ctx, bigint *bi,
+ bigint *dP, bigint *dQ,
+ bigint *p, bigint *q,
+ bigint *qInv);
+#endif
+
+#endif
diff --git a/qemu/roms/ipxe/src/crypto/axtls/bigint_impl.h b/qemu/roms/ipxe/src/crypto/axtls/bigint_impl.h
new file mode 100644
index 000000000..09d8550ea
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/axtls/bigint_impl.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BIGINT_IMPL_HEADER
+#define BIGINT_IMPL_HEADER
+
+/* Maintain a number of precomputed variables when doing reduction */
+#define BIGINT_M_OFFSET 0 /**< Normal modulo offset. */
+#ifdef CONFIG_BIGINT_CRT
+#define BIGINT_P_OFFSET 1 /**< p modulo offset. */
+#define BIGINT_Q_OFFSET 2 /**< q module offset. */
+#define BIGINT_NUM_MODS 3 /**< The number of modulus constants used. */
+#else
+#define BIGINT_NUM_MODS 1
+#endif
+
+/* Architecture specific functions for big ints */
+#if defined(CONFIG_INTEGER_8BIT)
+#define COMP_RADIX 256U /**< Max component + 1 */
+#define COMP_MAX 0xFFFFU/**< (Max dbl comp -1) */
+#define COMP_BIT_SIZE 8 /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE 1 /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES 2 /**< Used For diagnostics only. */
+typedef uint8_t comp; /**< A single precision component. */
+typedef uint16_t long_comp; /**< A double precision component. */
+typedef int16_t slong_comp; /**< A signed double precision component. */
+#elif defined(CONFIG_INTEGER_16BIT)
+#define COMP_RADIX 65536U /**< Max component + 1 */
+#define COMP_MAX 0xFFFFFFFFU/**< (Max dbl comp -1) */
+#define COMP_BIT_SIZE 16 /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE 2 /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES 4 /**< Used For diagnostics only. */
+typedef uint16_t comp; /**< A single precision component. */
+typedef uint32_t long_comp; /**< A double precision component. */
+typedef int32_t slong_comp; /**< A signed double precision component. */
+#else /* regular 32 bit */
+#ifdef WIN32
+#define COMP_RADIX 4294967296i64
+#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64
+#else
+#define COMP_RADIX 4294967296ULL /**< Max component + 1 */
+#define COMP_MAX 0xFFFFFFFFFFFFFFFFULL/**< (Max dbl comp -1) */
+#endif
+#define COMP_BIT_SIZE 32 /**< Number of bits in a component. */
+#define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */
+#define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */
+typedef uint32_t comp; /**< A single precision component. */
+typedef uint64_t long_comp; /**< A double precision component. */
+typedef int64_t slong_comp; /**< A signed double precision component. */
+#endif
+
+/**
+ * @struct _bigint
+ * @brief A big integer basic object
+ */
+struct _bigint
+{
+ struct _bigint* next; /**< The next bigint in the cache. */
+ short size; /**< The number of components in this bigint. */
+ short max_comps; /**< The heapsize allocated for this bigint */
+ int refs; /**< An internal reference count. */
+ comp* comps; /**< A ptr to the actual component data */
+};
+
+typedef struct _bigint bigint; /**< An alias for _bigint */
+
+/**
+ * Maintains the state of the cache, and a number of variables used in
+ * reduction.
+ */
+typedef struct /**< A big integer "session" context. */
+{
+ bigint *active_list; /**< Bigints currently used. */
+ bigint *free_list; /**< Bigints not used. */
+ bigint *bi_radix; /**< The radix used. */
+ bigint *bi_mod[BIGINT_NUM_MODS]; /**< modulus */
+
+#if defined(CONFIG_BIGINT_MONTGOMERY)
+ bigint *bi_RR_mod_m[BIGINT_NUM_MODS]; /**< R^2 mod m */
+ bigint *bi_R_mod_m[BIGINT_NUM_MODS]; /**< R mod m */
+ comp N0_dash[BIGINT_NUM_MODS];
+#elif defined(CONFIG_BIGINT_BARRETT)
+ bigint *bi_mu[BIGINT_NUM_MODS]; /**< Storage for mu */
+#endif
+ bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */
+ bigint **g; /**< Used by sliding-window. */
+ int window; /**< The size of the sliding window */
+ int active_count; /**< Number of active bigints. */
+ int free_count; /**< Number of free bigints. */
+
+#ifdef CONFIG_BIGINT_MONTGOMERY
+ uint8_t use_classical; /**< Use classical reduction. */
+#endif
+ uint8_t mod_offset; /**< The mod offset we are using */
+} BI_CTX;
+
+#ifndef WIN32
+#define max(a,b) ((a)>(b)?(a):(b)) /**< Find the maximum of 2 numbers. */
+#define min(a,b) ((a)<(b)?(a):(b)) /**< Find the minimum of 2 numbers. */
+#endif
+
+#define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */
+
+#endif
diff --git a/qemu/roms/ipxe/src/crypto/axtls/config.h b/qemu/roms/ipxe/src/crypto/axtls/config.h
new file mode 100644
index 000000000..32fa3bf03
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/axtls/config.h
@@ -0,0 +1,13 @@
+#ifndef AXTLS_CONFIG_H
+#define AXTLS_CONFIG_H
+
+/**
+ * @file config.h
+ *
+ * Trick the axtls code into building within our build environment.
+ */
+
+#define CONFIG_SSL_ENABLE_CLIENT 1
+#define CONFIG_BIGINT_CLASSICAL 1
+
+#endif
diff --git a/qemu/roms/ipxe/src/crypto/axtls/crypto.h b/qemu/roms/ipxe/src/crypto/axtls/crypto.h
new file mode 100644
index 000000000..2c4cda4de
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/axtls/crypto.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2007, Cameron Rich
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of the axTLS project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file crypto.h
+ */
+
+#ifndef HEADER_CRYPTO_H
+#define HEADER_CRYPTO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "config.h"
+#include "bigint_impl.h"
+#include "bigint.h"
+
+#ifndef STDCALL
+#define STDCALL
+#endif
+#ifndef EXP_FUNC
+#define EXP_FUNC
+#endif
+
+
+/* enable features based on a 'super-set' capbaility. */
+#if defined(CONFIG_SSL_FULL_MODE)
+#define CONFIG_SSL_ENABLE_CLIENT
+#define CONFIG_SSL_CERT_VERIFICATION
+#elif defined(CONFIG_SSL_ENABLE_CLIENT)
+#define CONFIG_SSL_CERT_VERIFICATION
+#endif
+
+/**************************************************************************
+ * AES declarations
+ **************************************************************************/
+
+#define AES_MAXROUNDS 14
+#define AES_BLOCKSIZE 16
+#define AES_IV_SIZE 16
+
+typedef struct aes_key_st
+{
+ uint16_t rounds;
+ uint16_t key_size;
+ uint32_t ks[(AES_MAXROUNDS+1)*8];
+ uint8_t iv[AES_IV_SIZE];
+} AES_CTX;
+
+typedef enum
+{
+ AES_MODE_128,
+ AES_MODE_256
+} AES_MODE;
+
+void AES_set_key(AES_CTX *ctx, const uint8_t *key,
+ const uint8_t *iv, AES_MODE mode);
+void AES_cbc_encrypt(AES_CTX *ctx, const uint8_t *msg,
+ uint8_t *out, int length);
+void AES_cbc_decrypt(AES_CTX *ks, const uint8_t *in, uint8_t *out, int length);
+void AES_convert_key(AES_CTX *ctx);
+
+/**************************************************************************
+ * RC4 declarations
+ **************************************************************************/
+
+typedef struct
+{
+ uint8_t x, y, m[256];
+} RC4_CTX;
+
+void RC4_setup(RC4_CTX *s, const uint8_t *key, int length);
+void RC4_crypt(RC4_CTX *s, const uint8_t *msg, uint8_t *data, int length);
+
+/**************************************************************************
+ * SHA1 declarations
+ **************************************************************************/
+
+#define SHA1_SIZE 20
+
+/*
+ * This structure will hold context information for the SHA-1
+ * hashing operation
+ */
+typedef struct
+{
+ uint32_t Intermediate_Hash[SHA1_SIZE/4]; /* Message Digest */
+ uint32_t Length_Low; /* Message length in bits */
+ uint32_t Length_High; /* Message length in bits */
+ uint16_t Message_Block_Index; /* Index into message block array */
+ uint8_t Message_Block[64]; /* 512-bit message blocks */
+} SHA1_CTX;
+
+void SHA1_Init(SHA1_CTX *);
+void SHA1_Update(SHA1_CTX *, const uint8_t * msg, int len);
+void SHA1_Final(uint8_t *digest, SHA1_CTX *);
+
+/**************************************************************************
+ * MD2 declarations
+ **************************************************************************/
+
+#define MD2_SIZE 16
+
+typedef struct
+{
+ unsigned char cksum[16]; /* checksum of the data block */
+ unsigned char state[48]; /* intermediate digest state */
+ unsigned char buffer[16]; /* data block being processed */
+ int left; /* amount of data in buffer */
+} MD2_CTX;
+
+EXP_FUNC void STDCALL MD2_Init(MD2_CTX *ctx);
+EXP_FUNC void STDCALL MD2_Update(MD2_CTX *ctx, const uint8_t *input, int ilen);
+EXP_FUNC void STDCALL MD2_Final(uint8_t *digest, MD2_CTX *ctx);
+
+/**************************************************************************
+ * MD5 declarations
+ **************************************************************************/
+
+#define MD5_SIZE 16
+
+typedef struct
+{
+ uint32_t state[4]; /* state (ABCD) */
+ uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ uint8_t buffer[64]; /* input buffer */
+} MD5_CTX;
+
+EXP_FUNC void STDCALL MD5_Init(MD5_CTX *);
+EXP_FUNC void STDCALL MD5_Update(MD5_CTX *, const uint8_t *msg, int len);
+EXP_FUNC void STDCALL MD5_Final(uint8_t *digest, MD5_CTX *);
+
+/**************************************************************************
+ * HMAC declarations
+ **************************************************************************/
+void hmac_md5(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest);
+void hmac_sha1(const uint8_t *msg, int length, const uint8_t *key,
+ int key_len, uint8_t *digest);
+
+/**************************************************************************
+ * RSA declarations
+ **************************************************************************/
+
+typedef struct
+{
+ bigint *m; /* modulus */
+ bigint *e; /* public exponent */
+ bigint *d; /* private exponent */
+#ifdef CONFIG_BIGINT_CRT
+ bigint *p; /* p as in m = pq */
+ bigint *q; /* q as in m = pq */
+ bigint *dP; /* d mod (p-1) */
+ bigint *dQ; /* d mod (q-1) */
+ bigint *qInv; /* q^-1 mod p */
+#endif
+ int num_octets;
+ BI_CTX *bi_ctx;
+} RSA_CTX;
+
+void RSA_priv_key_new(RSA_CTX **rsa_ctx,
+ const uint8_t *modulus, int mod_len,
+ const uint8_t *pub_exp, int pub_len,
+ const uint8_t *priv_exp, int priv_len
+#ifdef CONFIG_BIGINT_CRT
+ , const uint8_t *p, int p_len,
+ const uint8_t *q, int q_len,
+ const uint8_t *dP, int dP_len,
+ const uint8_t *dQ, int dQ_len,
+ const uint8_t *qInv, int qInv_len
+#endif
+ );
+void RSA_pub_key_new(RSA_CTX **rsa_ctx,
+ const uint8_t *modulus, int mod_len,
+ const uint8_t *pub_exp, int pub_len);
+void RSA_free(RSA_CTX *ctx);
+int RSA_decrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint8_t *out_data,
+ int is_decryption);
+bigint *RSA_private(const RSA_CTX *c, bigint *bi_msg);
+#if defined(CONFIG_SSL_CERT_VERIFICATION) || defined(CONFIG_SSL_GENERATE_X509_CERT)
+bigint *RSA_sign_verify(BI_CTX *ctx, const uint8_t *sig, int sig_len,
+ bigint *modulus, bigint *pub_exp);
+bigint *RSA_public(const RSA_CTX * c, bigint *bi_msg);
+int RSA_encrypt(const RSA_CTX *ctx, const uint8_t *in_data, uint16_t in_len,
+ uint8_t *out_data, int is_signing);
+void RSA_print(const RSA_CTX *ctx);
+#endif
+
+/**************************************************************************
+ * RNG declarations
+ **************************************************************************/
+EXP_FUNC void STDCALL RNG_initialize(const uint8_t *seed_buf, int size);
+EXP_FUNC void STDCALL RNG_terminate(void);
+EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data);
+void get_random_NZ(int num_rand_bytes, uint8_t *rand_data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/qemu/roms/ipxe/src/crypto/axtls/os_port.h b/qemu/roms/ipxe/src/crypto/axtls/os_port.h
new file mode 100644
index 000000000..76313e204
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/axtls/os_port.h
@@ -0,0 +1,54 @@
+#ifndef AXTLS_OS_PORT_H
+#define AXTLS_OS_PORT_H
+
+/**
+ * @file os_port.h
+ *
+ * Trick the axtls code into building within our build environment.
+ */
+
+#include <stdint.h>
+#include <byteswap.h>
+
+/** All imported axTLS files are licensed using the three-clause BSD licence */
+FILE_LICENCE ( BSD3 );
+
+/** We can't actually abort, since we are effectively a kernel... */
+#define abort() assert ( 0 )
+
+/** rsa.c uses alloca() */
+#define alloca( size ) __builtin_alloca ( size )
+
+#include <ipxe/random_nz.h>
+static inline void get_random_NZ ( int num_rand_bytes, uint8_t *rand_data ) {
+ /* AXTLS does not check for failures when generating random
+ * data. Rely on the fact that get_random_nz() does not
+ * request prediction resistance (and so cannot introduce new
+ * failures) and therefore any potential failure must already
+ * have been encountered by e.g. tls_generate_random(), which
+ * does check for failures.
+ */
+ get_random_nz ( rand_data, num_rand_bytes );
+}
+
+/* Expose AES_encrypt() and AES_decrypt() in aes.o */
+#define aes 1
+#if OBJECT
+
+struct aes_key_st;
+
+static void AES_encrypt ( const struct aes_key_st *ctx, uint32_t *data );
+static void AES_decrypt ( const struct aes_key_st *ctx, uint32_t *data );
+
+void axtls_aes_encrypt ( void *ctx, uint32_t *data ) {
+ AES_encrypt ( ctx, data );
+}
+
+void axtls_aes_decrypt ( void *ctx, uint32_t *data ) {
+ AES_decrypt ( ctx, data );
+}
+
+#endif
+#undef aes
+
+#endif
diff --git a/qemu/roms/ipxe/src/crypto/axtls_aes.c b/qemu/roms/ipxe/src/crypto/axtls_aes.c
new file mode 100644
index 000000000..7f93c0ed7
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/axtls_aes.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/crypto.h>
+#include <ipxe/cbc.h>
+#include <ipxe/aes.h>
+#include "crypto/axtls/crypto.h"
+
+/** @file
+ *
+ * AES algorithm
+ *
+ */
+
+/**
+ * Set key
+ *
+ * @v ctx Context
+ * @v key Key
+ * @v keylen Key length
+ * @ret rc Return status code
+ */
+static int aes_setkey ( void *ctx, const void *key, size_t keylen ) {
+ struct aes_context *aes_ctx = ctx;
+ AES_MODE mode;
+ void *iv;
+
+ switch ( keylen ) {
+ case ( 128 / 8 ):
+ mode = AES_MODE_128;
+ break;
+ case ( 256 / 8 ):
+ mode = AES_MODE_256;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* IV is not a relevant concept at this stage; use a dummy
+ * value that will have no side-effects.
+ */
+ iv = &aes_ctx->axtls_ctx.iv;
+
+ AES_set_key ( &aes_ctx->axtls_ctx, key, iv, mode );
+
+ aes_ctx->decrypting = 0;
+
+ return 0;
+}
+
+/**
+ * Set initialisation vector
+ *
+ * @v ctx Context
+ * @v iv Initialisation vector
+ */
+static void aes_setiv ( void *ctx __unused, const void *iv __unused ) {
+ /* Nothing to do */
+}
+
+/**
+ * Call AXTLS' AES_encrypt() or AES_decrypt() functions
+ *
+ * @v axtls_ctx AXTLS AES context
+ * @v src Data to process
+ * @v dst Buffer for output
+ * @v func AXTLS AES function to call
+ */
+static void aes_call_axtls ( AES_CTX *axtls_ctx, const void *src, void *dst,
+ void ( * func ) ( const AES_CTX *axtls_ctx,
+ uint32_t *data ) ){
+ const uint32_t *srcl = src;
+ uint32_t *dstl = dst;
+ unsigned int i;
+
+ /* AXTLS' AES_encrypt() and AES_decrypt() functions both
+ * expect to deal with an array of four dwords in host-endian
+ * order.
+ */
+ for ( i = 0 ; i < 4 ; i++ )
+ dstl[i] = ntohl ( srcl[i] );
+ func ( axtls_ctx, dstl );
+ for ( i = 0 ; i < 4 ; i++ )
+ dstl[i] = htonl ( dstl[i] );
+}
+
+/**
+ * Encrypt data
+ *
+ * @v ctx Context
+ * @v src Data to encrypt
+ * @v dst Buffer for encrypted data
+ * @v len Length of data
+ */
+static void aes_encrypt ( void *ctx, const void *src, void *dst,
+ size_t len ) {
+ struct aes_context *aes_ctx = ctx;
+
+ assert ( len == AES_BLOCKSIZE );
+ if ( aes_ctx->decrypting )
+ assert ( 0 );
+ aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, axtls_aes_encrypt );
+}
+
+/**
+ * Decrypt data
+ *
+ * @v ctx Context
+ * @v src Data to decrypt
+ * @v dst Buffer for decrypted data
+ * @v len Length of data
+ */
+static void aes_decrypt ( void *ctx, const void *src, void *dst,
+ size_t len ) {
+ struct aes_context *aes_ctx = ctx;
+
+ assert ( len == AES_BLOCKSIZE );
+ if ( ! aes_ctx->decrypting ) {
+ AES_convert_key ( &aes_ctx->axtls_ctx );
+ aes_ctx->decrypting = 1;
+ }
+ aes_call_axtls ( &aes_ctx->axtls_ctx, src, dst, axtls_aes_decrypt );
+}
+
+/** Basic AES algorithm */
+struct cipher_algorithm aes_algorithm = {
+ .name = "aes",
+ .ctxsize = sizeof ( struct aes_context ),
+ .blocksize = AES_BLOCKSIZE,
+ .setkey = aes_setkey,
+ .setiv = aes_setiv,
+ .encrypt = aes_encrypt,
+ .decrypt = aes_decrypt,
+};
+
+/* AES with cipher-block chaining */
+CBC_CIPHER ( aes_cbc, aes_cbc_algorithm,
+ aes_algorithm, struct aes_context, AES_BLOCKSIZE );
diff --git a/qemu/roms/ipxe/src/crypto/bigint.c b/qemu/roms/ipxe/src/crypto/bigint.c
new file mode 100644
index 000000000..340128e2f
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/bigint.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <ipxe/bigint.h>
+
+/** @file
+ *
+ * Big integer support
+ */
+
+/**
+ * Perform modular multiplication of big integers
+ *
+ * @v multiplicand0 Element 0 of big integer to be multiplied
+ * @v multiplier0 Element 0 of big integer to be multiplied
+ * @v modulus0 Element 0 of big integer modulus
+ * @v result0 Element 0 of big integer to hold result
+ * @v size Number of elements in base, modulus, and result
+ * @v tmp Temporary working space
+ */
+void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0,
+ const bigint_element_t *multiplier0,
+ const bigint_element_t *modulus0,
+ bigint_element_t *result0,
+ unsigned int size, void *tmp ) {
+ const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand =
+ ( ( const void * ) multiplicand0 );
+ const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier =
+ ( ( const void * ) multiplier0 );
+ const bigint_t ( size ) __attribute__ (( may_alias )) *modulus =
+ ( ( const void * ) modulus0 );
+ bigint_t ( size ) __attribute__ (( may_alias )) *result =
+ ( ( void * ) result0 );
+ struct {
+ bigint_t ( size * 2 ) result;
+ bigint_t ( size * 2 ) modulus;
+ } *temp = tmp;
+ int rotation;
+ int i;
+
+ /* Sanity check */
+ assert ( sizeof ( *temp ) == bigint_mod_multiply_tmp_len ( modulus ) );
+
+ /* Perform multiplication */
+ bigint_multiply ( multiplicand, multiplier, &temp->result );
+
+ /* Rescale modulus to match result */
+ bigint_grow ( modulus, &temp->modulus );
+ rotation = ( bigint_max_set_bit ( &temp->result ) -
+ bigint_max_set_bit ( &temp->modulus ) );
+ for ( i = 0 ; i < rotation ; i++ )
+ bigint_rol ( &temp->modulus );
+
+ /* Subtract multiples of modulus */
+ for ( i = 0 ; i <= rotation ; i++ ) {
+ if ( bigint_is_geq ( &temp->result, &temp->modulus ) )
+ bigint_subtract ( &temp->modulus, &temp->result );
+ bigint_ror ( &temp->modulus );
+ }
+
+ /* Resize result */
+ bigint_shrink ( &temp->result, result );
+
+ /* Sanity check */
+ assert ( bigint_is_geq ( modulus, result ) );
+}
+
+/**
+ * Perform modular exponentiation of big integers
+ *
+ * @v base0 Element 0 of big integer base
+ * @v modulus0 Element 0 of big integer modulus
+ * @v exponent0 Element 0 of big integer exponent
+ * @v result0 Element 0 of big integer to hold result
+ * @v size Number of elements in base, modulus, and result
+ * @v exponent_size Number of elements in exponent
+ * @v tmp Temporary working space
+ */
+void bigint_mod_exp_raw ( const bigint_element_t *base0,
+ const bigint_element_t *modulus0,
+ const bigint_element_t *exponent0,
+ bigint_element_t *result0,
+ unsigned int size, unsigned int exponent_size,
+ void *tmp ) {
+ const bigint_t ( size ) __attribute__ (( may_alias )) *base =
+ ( ( const void * ) base0 );
+ const bigint_t ( size ) __attribute__ (( may_alias )) *modulus =
+ ( ( const void * ) modulus0 );
+ const bigint_t ( exponent_size ) __attribute__ (( may_alias ))
+ *exponent = ( ( const void * ) exponent0 );
+ bigint_t ( size ) __attribute__ (( may_alias )) *result =
+ ( ( void * ) result0 );
+ size_t mod_multiply_len = bigint_mod_multiply_tmp_len ( modulus );
+ struct {
+ bigint_t ( size ) base;
+ bigint_t ( exponent_size ) exponent;
+ uint8_t mod_multiply[mod_multiply_len];
+ } *temp = tmp;
+ static const uint8_t start[1] = { 0x01 };
+
+ memcpy ( &temp->base, base, sizeof ( temp->base ) );
+ memcpy ( &temp->exponent, exponent, sizeof ( temp->exponent ) );
+ bigint_init ( result, start, sizeof ( start ) );
+
+ while ( ! bigint_is_zero ( &temp->exponent ) ) {
+ if ( bigint_bit_is_set ( &temp->exponent, 0 ) ) {
+ bigint_mod_multiply ( result, &temp->base, modulus,
+ result, temp->mod_multiply );
+ }
+ bigint_ror ( &temp->exponent );
+ bigint_mod_multiply ( &temp->base, &temp->base, modulus,
+ &temp->base, temp->mod_multiply );
+ }
+}
diff --git a/qemu/roms/ipxe/src/crypto/cbc.c b/qemu/roms/ipxe/src/crypto/cbc.c
new file mode 100644
index 000000000..9bf0e8b49
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/cbc.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <assert.h>
+#include <ipxe/crypto.h>
+#include <ipxe/cbc.h>
+
+/** @file
+ *
+ * Cipher-block chaining
+ *
+ */
+
+/**
+ * XOR data blocks
+ *
+ * @v src Input data
+ * @v dst Second input data and output data buffer
+ * @v len Length of data
+ */
+static void cbc_xor ( const void *src, void *dst, size_t len ) {
+ const uint32_t *srcl = src;
+ uint32_t *dstl = dst;
+ unsigned int i;
+
+ /* Assume that block sizes will always be dword-aligned, for speed */
+ assert ( ( len % sizeof ( *srcl ) ) == 0 );
+
+ for ( i = 0 ; i < ( len / sizeof ( *srcl ) ) ; i++ )
+ dstl[i] ^= srcl[i];
+}
+
+/**
+ * Encrypt data
+ *
+ * @v ctx Context
+ * @v src Data to encrypt
+ * @v dst Buffer for encrypted data
+ * @v len Length of data
+ * @v raw_cipher Underlying cipher algorithm
+ * @v cbc_ctx CBC context
+ */
+void cbc_encrypt ( void *ctx, const void *src, void *dst, size_t len,
+ struct cipher_algorithm *raw_cipher, void *cbc_ctx ) {
+ size_t blocksize = raw_cipher->blocksize;
+
+ assert ( ( len % blocksize ) == 0 );
+
+ while ( len ) {
+ cbc_xor ( src, cbc_ctx, blocksize );
+ cipher_encrypt ( raw_cipher, ctx, cbc_ctx, dst, blocksize );
+ memcpy ( cbc_ctx, dst, blocksize );
+ dst += blocksize;
+ src += blocksize;
+ len -= blocksize;
+ }
+}
+
+/**
+ * Decrypt data
+ *
+ * @v ctx Context
+ * @v src Data to decrypt
+ * @v dst Buffer for decrypted data
+ * @v len Length of data
+ * @v raw_cipher Underlying cipher algorithm
+ * @v cbc_ctx CBC context
+ */
+void cbc_decrypt ( void *ctx, const void *src, void *dst, size_t len,
+ struct cipher_algorithm *raw_cipher, void *cbc_ctx ) {
+ size_t blocksize = raw_cipher->blocksize;
+ uint8_t next_cbc_ctx[blocksize];
+
+ assert ( ( len % blocksize ) == 0 );
+
+ while ( len ) {
+ memcpy ( next_cbc_ctx, src, blocksize );
+ cipher_decrypt ( raw_cipher, ctx, src, dst, blocksize );
+ cbc_xor ( cbc_ctx, dst, blocksize );
+ memcpy ( cbc_ctx, next_cbc_ctx, blocksize );
+ dst += blocksize;
+ src += blocksize;
+ len -= blocksize;
+ }
+}
diff --git a/qemu/roms/ipxe/src/crypto/certstore.c b/qemu/roms/ipxe/src/crypto/certstore.c
new file mode 100644
index 000000000..77cf6ebb6
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/certstore.c
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <stdlib.h>
+#include <ipxe/init.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/settings.h>
+#include <ipxe/malloc.h>
+#include <ipxe/crypto.h>
+#include <ipxe/asn1.h>
+#include <ipxe/x509.h>
+#include <ipxe/certstore.h>
+
+/** @file
+ *
+ * Certificate store
+ *
+ */
+
+/** Raw certificate data for all permanent stored certificates */
+#undef CERT
+#define CERT( _index, _path ) \
+ extern char stored_cert_ ## _index ## _data[]; \
+ extern char stored_cert_ ## _index ## _len[]; \
+ __asm__ ( ".section \".rodata\", \"a\", @progbits\n\t" \
+ "\nstored_cert_" #_index "_data:\n\t" \
+ ".incbin \"" _path "\"\n\t" \
+ "\nstored_cert_" #_index "_end:\n\t" \
+ ".equ stored_cert_" #_index "_len, " \
+ "( stored_cert_" #_index "_end - " \
+ " stored_cert_" #_index "_data )\n\t" \
+ ".previous\n\t" );
+CERT_ALL
+
+/** Raw certificate cursors for all permanent stored certificates */
+#undef CERT
+#define CERT( _index, _path ) { \
+ .data = stored_cert_ ## _index ## _data, \
+ .len = ( size_t ) stored_cert_ ## _index ## _len, \
+},
+static struct asn1_cursor certstore_raw[] = {
+ CERT_ALL
+};
+
+/** X.509 certificate structures for all permanent stored certificates */
+static struct x509_certificate certstore_certs[ sizeof ( certstore_raw ) /
+ sizeof ( certstore_raw[0] ) ];
+
+/** Certificate store */
+struct x509_chain certstore = {
+ .refcnt = REF_INIT ( ref_no_free ),
+ .links = LIST_HEAD_INIT ( certstore.links ),
+};
+
+/**
+ * Mark stored certificate as most recently used
+ *
+ * @v cert X.509 certificate
+ * @ret cert X.509 certificate
+ */
+static struct x509_certificate *
+certstore_found ( struct x509_certificate *cert ) {
+
+ /* Mark as most recently used */
+ list_del ( &cert->store.list );
+ list_add ( &cert->store.list, &certstore.links );
+ DBGC2 ( &certstore, "CERTSTORE found certificate %s\n",
+ x509_name ( cert ) );
+
+ return cert;
+}
+
+/**
+ * Find certificate in store
+ *
+ * @v raw Raw certificate data
+ * @ret cert X.509 certificate, or NULL if not found
+ */
+struct x509_certificate * certstore_find ( struct asn1_cursor *raw ) {
+ struct x509_certificate *cert;
+
+ /* Search for certificate within store */
+ list_for_each_entry ( cert, &certstore.links, store.list ) {
+ if ( asn1_compare ( raw, &cert->raw ) == 0 )
+ return certstore_found ( cert );
+ }
+ return NULL;
+}
+
+/**
+ * Find certificate in store corresponding to a private key
+ *
+ * @v key Private key
+ * @ret cert X.509 certificate, or NULL if not found
+ */
+struct x509_certificate * certstore_find_key ( struct asn1_cursor *key ) {
+ struct x509_certificate *cert;
+
+ /* Search for certificate within store */
+ list_for_each_entry ( cert, &certstore.links, store.list ) {
+ if ( pubkey_match ( cert->signature_algorithm->pubkey,
+ key->data, key->len,
+ cert->subject.public_key.raw.data,
+ cert->subject.public_key.raw.len ) == 0 )
+ return certstore_found ( cert );
+ }
+ return NULL;
+}
+
+/**
+ * Add certificate to store
+ *
+ * @v cert X.509 certificate
+ */
+void certstore_add ( struct x509_certificate *cert ) {
+
+ /* Add certificate to store */
+ cert->store.cert = cert;
+ x509_get ( cert );
+ list_add ( &cert->store.list, &certstore.links );
+ DBGC ( &certstore, "CERTSTORE added certificate %s\n",
+ x509_name ( cert ) );
+}
+
+/**
+ * Discard a stored certificate
+ *
+ * @ret discarded Number of cached items discarded
+ */
+static unsigned int certstore_discard ( void ) {
+ struct x509_certificate *cert;
+
+ /* Discard the least recently used certificate for which the
+ * only reference is held by the store itself.
+ */
+ list_for_each_entry_reverse ( cert, &certstore.links, store.list ) {
+ if ( cert->refcnt.count == 0 ) {
+ DBGC ( &certstore, "CERTSTORE discarded certificate "
+ "%s\n", x509_name ( cert ) );
+ list_del ( &cert->store.list );
+ x509_put ( cert );
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/** Certificate store cache discarder */
+struct cache_discarder certstore_discarder __cache_discarder ( CACHE_NORMAL ) ={
+ .discard = certstore_discard,
+};
+
+/**
+ * Construct permanent certificate store
+ *
+ */
+static void certstore_init ( void ) {
+ struct asn1_cursor *raw;
+ struct x509_certificate *cert;
+ int i;
+ int rc;
+
+ /* Skip if we have no permanent stored certificates */
+ if ( ! sizeof ( certstore_raw ) )
+ return;
+
+ /* Add certificates */
+ for ( i = 0 ; i < ( int ) ( sizeof ( certstore_raw ) /
+ sizeof ( certstore_raw[0] ) ) ; i++ ) {
+
+ /* Skip if certificate already present in store */
+ raw = &certstore_raw[i];
+ if ( ( cert = certstore_find ( raw ) ) != NULL ) {
+ DBGC ( &certstore, "CERTSTORE permanent certificate %d "
+ "is a duplicate of %s\n", i, x509_name ( cert ));
+ continue;
+ }
+
+ /* Parse certificate */
+ cert = &certstore_certs[i];
+ ref_init ( &cert->refcnt, ref_no_free );
+ if ( ( rc = x509_parse ( cert, raw ) ) != 0 ) {
+ DBGC ( &certstore, "CERTSTORE could not parse "
+ "permanent certificate %d: %s\n",
+ i, strerror ( rc ) );
+ continue;
+ }
+
+ /* Add certificate to store. Certificate will never
+ * be discarded from the store, since we retain a
+ * permanent reference to it.
+ */
+ certstore_add ( cert );
+ DBGC ( &certstore, "CERTSTORE permanent certificate %d is %s\n",
+ i, x509_name ( cert ) );
+ }
+}
+
+/** Certificate store initialisation function */
+struct init_fn certstore_init_fn __init_fn ( INIT_LATE ) = {
+ .initialise = certstore_init,
+};
+
+/** Additional certificate setting */
+static struct setting cert_setting __setting ( SETTING_CRYPTO, cert ) = {
+ .name = "cert",
+ .description = "Certificate",
+ .tag = DHCP_EB_CERT,
+ .type = &setting_type_hex,
+};
+
+/**
+ * Apply certificate store configuration settings
+ *
+ * @ret rc Return status code
+ */
+static int certstore_apply_settings ( void ) {
+ static struct x509_certificate *cert = NULL;
+ struct x509_certificate *old_cert;
+ void *cert_data;
+ int len;
+ int rc;
+
+ /* Record any existing additional certificate */
+ old_cert = cert;
+ cert = NULL;
+
+ /* Add additional certificate, if any */
+ if ( ( len = fetch_raw_setting_copy ( NULL, &cert_setting,
+ &cert_data ) ) >= 0 ) {
+ if ( ( rc = x509_certificate ( cert_data, len, &cert ) ) == 0 ){
+ DBGC ( &certstore, "CERTSTORE added additional "
+ "certificate %s\n", x509_name ( cert ) );
+ } else {
+ DBGC ( &certstore, "CERTSTORE could not parse "
+ "additional certificate: %s\n",
+ strerror ( rc ) );
+ /* Do not fail; leave as an unusable certificate */
+ }
+ free ( cert_data );
+ }
+
+ /* Free old additional certificiate. Do this after reparsing
+ * the additional certificate; in the common case that the
+ * certificate has not changed, this will allow the stored
+ * certificate to be reused.
+ */
+ x509_put ( old_cert );
+
+ return 0;
+}
+
+/** Certificate store settings applicator */
+struct settings_applicator certstore_applicator __settings_applicator = {
+ .apply = certstore_apply_settings,
+};
diff --git a/qemu/roms/ipxe/src/crypto/chap.c b/qemu/roms/ipxe/src/crypto/chap.c
new file mode 100644
index 000000000..db64371c7
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/chap.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/crypto.h>
+#include <ipxe/chap.h>
+
+/** @file
+ *
+ * CHAP protocol
+ *
+ */
+
+/**
+ * Initialise CHAP challenge/response
+ *
+ * @v chap CHAP challenge/response
+ * @v digest Digest algorithm to use
+ * @ret rc Return status code
+ *
+ * Initialises a CHAP challenge/response structure. This routine
+ * allocates memory, and so may fail. The allocated memory must
+ * eventually be freed by a call to chap_finish().
+ */
+int chap_init ( struct chap_response *chap,
+ struct digest_algorithm *digest ) {
+ size_t state_len;
+ void *state;
+
+ assert ( chap->digest == NULL );
+ assert ( chap->digest_context == NULL );
+ assert ( chap->response == NULL );
+
+ DBG ( "CHAP %p initialising with %s digest\n", chap, digest->name );
+
+ state_len = ( digest->ctxsize + digest->digestsize );
+ state = malloc ( state_len );
+ if ( ! state ) {
+ DBG ( "CHAP %p could not allocate %zd bytes for state\n",
+ chap, state_len );
+ return -ENOMEM;
+ }
+
+ chap->digest = digest;
+ chap->digest_context = state;
+ chap->response = ( state + digest->ctxsize );
+ chap->response_len = digest->digestsize;
+ digest_init ( chap->digest, chap->digest_context );
+ return 0;
+}
+
+/**
+ * Add data to the CHAP challenge
+ *
+ * @v chap CHAP response
+ * @v data Data to add
+ * @v len Length of data to add
+ */
+void chap_update ( struct chap_response *chap, const void *data,
+ size_t len ) {
+ assert ( chap->digest != NULL );
+ assert ( chap->digest_context != NULL );
+
+ if ( ! chap->digest )
+ return;
+
+ digest_update ( chap->digest, chap->digest_context, data, len );
+}
+
+/**
+ * Respond to the CHAP challenge
+ *
+ * @v chap CHAP response
+ *
+ * Calculates the final CHAP response value, and places it in @c
+ * chap->response, with a length of @c chap->response_len.
+ */
+void chap_respond ( struct chap_response *chap ) {
+ assert ( chap->digest != NULL );
+ assert ( chap->digest_context != NULL );
+ assert ( chap->response != NULL );
+
+ DBG ( "CHAP %p responding to challenge\n", chap );
+
+ if ( ! chap->digest )
+ return;
+
+ digest_final ( chap->digest, chap->digest_context, chap->response );
+}
+
+/**
+ * Free resources used by a CHAP response
+ *
+ * @v chap CHAP response
+ */
+void chap_finish ( struct chap_response *chap ) {
+ void *state = chap->digest_context;
+
+ DBG ( "CHAP %p finished\n", chap );
+
+ free ( state );
+ memset ( chap, 0, sizeof ( *chap ) );
+}
diff --git a/qemu/roms/ipxe/src/crypto/cms.c b/qemu/roms/ipxe/src/crypto/cms.c
new file mode 100644
index 000000000..b4a41de6c
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/cms.c
@@ -0,0 +1,709 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Cryptographic Message Syntax (PKCS #7)
+ *
+ * The format of CMS messages is defined in RFC 5652.
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <ipxe/asn1.h>
+#include <ipxe/x509.h>
+#include <ipxe/malloc.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/cms.h>
+
+/* Disambiguate the various error causes */
+#define EACCES_NON_SIGNING \
+ __einfo_error ( EINFO_EACCES_NON_SIGNING )
+#define EINFO_EACCES_NON_SIGNING \
+ __einfo_uniqify ( EINFO_EACCES, 0x01, "Not a signing certificate" )
+#define EACCES_NON_CODE_SIGNING \
+ __einfo_error ( EINFO_EACCES_NON_CODE_SIGNING )
+#define EINFO_EACCES_NON_CODE_SIGNING \
+ __einfo_uniqify ( EINFO_EACCES, 0x02, "Not a code-signing certificate" )
+#define EACCES_WRONG_NAME \
+ __einfo_error ( EINFO_EACCES_WRONG_NAME )
+#define EINFO_EACCES_WRONG_NAME \
+ __einfo_uniqify ( EINFO_EACCES, 0x04, "Incorrect certificate name" )
+#define EACCES_NO_SIGNATURES \
+ __einfo_error ( EINFO_EACCES_NO_SIGNATURES )
+#define EINFO_EACCES_NO_SIGNATURES \
+ __einfo_uniqify ( EINFO_EACCES, 0x05, "No signatures present" )
+#define EINVAL_DIGEST \
+ __einfo_error ( EINFO_EINVAL_DIGEST )
+#define EINFO_EINVAL_DIGEST \
+ __einfo_uniqify ( EINFO_EINVAL, 0x01, "Not a digest algorithm" )
+#define EINVAL_PUBKEY \
+ __einfo_error ( EINFO_EINVAL_PUBKEY )
+#define EINFO_EINVAL_PUBKEY \
+ __einfo_uniqify ( EINFO_EINVAL, 0x02, "Not a public-key algorithm" )
+#define ENOTSUP_SIGNEDDATA \
+ __einfo_error ( EINFO_ENOTSUP_SIGNEDDATA )
+#define EINFO_ENOTSUP_SIGNEDDATA \
+ __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Not a digital signature" )
+
+/** "pkcs7-signedData" object identifier */
+static uint8_t oid_signeddata[] = { ASN1_OID_SIGNEDDATA };
+
+/** "pkcs7-signedData" object identifier cursor */
+static struct asn1_cursor oid_signeddata_cursor =
+ ASN1_OID_CURSOR ( oid_signeddata );
+
+/**
+ * Parse CMS signature content type
+ *
+ * @v sig CMS signature
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int cms_parse_content_type ( struct cms_signature *sig,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+
+ /* Enter contentType */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_OID );
+
+ /* Check OID is pkcs7-signedData */
+ if ( asn1_compare ( &cursor, &oid_signeddata_cursor ) != 0 ) {
+ DBGC ( sig, "CMS %p does not contain signedData:\n", sig );
+ DBGC_HDA ( sig, 0, raw->data, raw->len );
+ return -ENOTSUP_SIGNEDDATA;
+ }
+
+ DBGC ( sig, "CMS %p contains signedData\n", sig );
+ return 0;
+}
+
+/**
+ * Parse CMS signature certificate list
+ *
+ * @v sig CMS signature
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int cms_parse_certificates ( struct cms_signature *sig,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ struct x509_certificate *cert;
+ int rc;
+
+ /* Enter certificates */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+
+ /* Add each certificate */
+ while ( cursor.len ) {
+
+ /* Add certificate to chain */
+ if ( ( rc = x509_append_raw ( sig->certificates, cursor.data,
+ cursor.len ) ) != 0 ) {
+ DBGC ( sig, "CMS %p could not append certificate: %s\n",
+ sig, strerror ( rc) );
+ DBGC_HDA ( sig, 0, cursor.data, cursor.len );
+ return rc;
+ }
+ cert = x509_last ( sig->certificates );
+ DBGC ( sig, "CMS %p found certificate %s\n",
+ sig, x509_name ( cert ) );
+
+ /* Move to next certificate */
+ asn1_skip_any ( &cursor );
+ }
+
+ return 0;
+}
+
+/**
+ * Identify CMS signature certificate by issuer and serial number
+ *
+ * @v sig CMS signature
+ * @v issuer Issuer
+ * @v serial Serial number
+ * @ret cert X.509 certificate, or NULL if not found
+ */
+static struct x509_certificate *
+cms_find_issuer_serial ( struct cms_signature *sig,
+ const struct asn1_cursor *issuer,
+ const struct asn1_cursor *serial ) {
+ struct x509_link *link;
+ struct x509_certificate *cert;
+
+ /* Scan through certificate list */
+ list_for_each_entry ( link, &sig->certificates->links, list ) {
+
+ /* Check issuer and serial number */
+ cert = link->cert;
+ if ( ( asn1_compare ( issuer, &cert->issuer.raw ) == 0 ) &&
+ ( asn1_compare ( serial, &cert->serial.raw ) == 0 ) )
+ return cert;
+ }
+
+ return NULL;
+}
+
+/**
+ * Parse CMS signature signer identifier
+ *
+ * @v sig CMS signature
+ * @v info Signer information to fill in
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int cms_parse_signer_identifier ( struct cms_signature *sig,
+ struct cms_signer_info *info,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ struct asn1_cursor serial;
+ struct asn1_cursor issuer;
+ struct x509_certificate *cert;
+ int rc;
+
+ /* Enter issuerAndSerialNumber */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Identify issuer */
+ memcpy ( &issuer, &cursor, sizeof ( issuer ) );
+ if ( ( rc = asn1_shrink ( &issuer, ASN1_SEQUENCE ) ) != 0 ) {
+ DBGC ( sig, "CMS %p/%p could not locate issuer: %s\n",
+ sig, info, strerror ( rc ) );
+ DBGC_HDA ( sig, 0, raw->data, raw->len );
+ return rc;
+ }
+ DBGC ( sig, "CMS %p/%p issuer is:\n", sig, info );
+ DBGC_HDA ( sig, 0, issuer.data, issuer.len );
+ asn1_skip_any ( &cursor );
+
+ /* Identify serialNumber */
+ memcpy ( &serial, &cursor, sizeof ( serial ) );
+ if ( ( rc = asn1_shrink ( &serial, ASN1_INTEGER ) ) != 0 ) {
+ DBGC ( sig, "CMS %p/%p could not locate serialNumber: %s\n",
+ sig, info, strerror ( rc ) );
+ DBGC_HDA ( sig, 0, raw->data, raw->len );
+ return rc;
+ }
+ DBGC ( sig, "CMS %p/%p serial number is:\n", sig, info );
+ DBGC_HDA ( sig, 0, serial.data, serial.len );
+
+ /* Identify certificate */
+ cert = cms_find_issuer_serial ( sig, &issuer, &serial );
+ if ( ! cert ) {
+ DBGC ( sig, "CMS %p/%p could not identify signer's "
+ "certificate\n", sig, info );
+ return -ENOENT;
+ }
+
+ /* Append certificate to chain */
+ if ( ( rc = x509_append ( info->chain, cert ) ) != 0 ) {
+ DBGC ( sig, "CMS %p/%p could not append certificate: %s\n",
+ sig, info, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Append remaining certificates to chain */
+ if ( ( rc = x509_auto_append ( info->chain,
+ sig->certificates ) ) != 0 ) {
+ DBGC ( sig, "CMS %p/%p could not append certificates: %s\n",
+ sig, info, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse CMS signature digest algorithm
+ *
+ * @v sig CMS signature
+ * @v info Signer information to fill in
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int cms_parse_digest_algorithm ( struct cms_signature *sig,
+ struct cms_signer_info *info,
+ const struct asn1_cursor *raw ) {
+ struct asn1_algorithm *algorithm;
+ int rc;
+
+ /* Identify algorithm */
+ if ( ( rc = asn1_digest_algorithm ( raw, &algorithm ) ) != 0 ) {
+ DBGC ( sig, "CMS %p/%p could not identify digest algorithm: "
+ "%s\n", sig, info, strerror ( rc ) );
+ DBGC_HDA ( sig, 0, raw->data, raw->len );
+ return rc;
+ }
+
+ /* Record digest algorithm */
+ info->digest = algorithm->digest;
+ DBGC ( sig, "CMS %p/%p digest algorithm is %s\n",
+ sig, info, algorithm->name );
+
+ return 0;
+}
+
+/**
+ * Parse CMS signature algorithm
+ *
+ * @v sig CMS signature
+ * @v info Signer information to fill in
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int cms_parse_signature_algorithm ( struct cms_signature *sig,
+ struct cms_signer_info *info,
+ const struct asn1_cursor *raw ) {
+ struct asn1_algorithm *algorithm;
+ int rc;
+
+ /* Identify algorithm */
+ if ( ( rc = asn1_pubkey_algorithm ( raw, &algorithm ) ) != 0 ) {
+ DBGC ( sig, "CMS %p/%p could not identify public-key "
+ "algorithm: %s\n", sig, info, strerror ( rc ) );
+ DBGC_HDA ( sig, 0, raw->data, raw->len );
+ return rc;
+ }
+
+ /* Record signature algorithm */
+ info->pubkey = algorithm->pubkey;
+ DBGC ( sig, "CMS %p/%p public-key algorithm is %s\n",
+ sig, info, algorithm->name );
+
+ return 0;
+}
+
+/**
+ * Parse CMS signature value
+ *
+ * @v sig CMS signature
+ * @v info Signer information to fill in
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int cms_parse_signature_value ( struct cms_signature *sig,
+ struct cms_signer_info *info,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Enter signature */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ if ( ( rc = asn1_enter ( &cursor, ASN1_OCTET_STRING ) ) != 0 ) {
+ DBGC ( sig, "CMS %p/%p could not locate signature:\n",
+ sig, info );
+ DBGC_HDA ( sig, 0, raw->data, raw->len );
+ return rc;
+ }
+
+ /* Record signature */
+ info->signature_len = cursor.len;
+ info->signature = malloc ( info->signature_len );
+ if ( ! info->signature )
+ return -ENOMEM;
+ memcpy ( info->signature, cursor.data, info->signature_len );
+ DBGC ( sig, "CMS %p/%p signature value is:\n", sig, info );
+ DBGC_HDA ( sig, 0, info->signature, info->signature_len );
+
+ return 0;
+}
+
+/**
+ * Parse CMS signature signer information
+ *
+ * @v sig CMS signature
+ * @v info Signer information to fill in
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int cms_parse_signer_info ( struct cms_signature *sig,
+ struct cms_signer_info *info,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Enter signerInfo */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Skip version */
+ asn1_skip ( &cursor, ASN1_INTEGER );
+
+ /* Parse sid */
+ if ( ( rc = cms_parse_signer_identifier ( sig, info, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Parse digestAlgorithm */
+ if ( ( rc = cms_parse_digest_algorithm ( sig, info, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Skip signedAttrs, if present */
+ asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+
+ /* Parse signatureAlgorithm */
+ if ( ( rc = cms_parse_signature_algorithm ( sig, info, &cursor ) ) != 0)
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Parse signature */
+ if ( ( rc = cms_parse_signature_value ( sig, info, &cursor ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Parse CMS signature from ASN.1 data
+ *
+ * @v sig CMS signature
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int cms_parse ( struct cms_signature *sig,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ struct cms_signer_info *info;
+ int rc;
+
+ /* Enter contentInfo */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse contentType */
+
+ if ( ( rc = cms_parse_content_type ( sig, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Enter content */
+ asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+
+ /* Enter signedData */
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Skip version */
+ asn1_skip ( &cursor, ASN1_INTEGER );
+
+ /* Skip digestAlgorithms */
+ asn1_skip ( &cursor, ASN1_SET );
+
+ /* Skip encapContentInfo */
+ asn1_skip ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse certificates */
+ if ( ( rc = cms_parse_certificates ( sig, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Skip crls, if present */
+ asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 1 ) );
+
+ /* Enter signerInfos */
+ asn1_enter ( &cursor, ASN1_SET );
+
+ /* Add each signerInfo. Errors are handled by ensuring that
+ * cms_put() will always be able to free any allocated memory.
+ */
+ while ( cursor.len ) {
+
+ /* Allocate signer information block */
+ info = zalloc ( sizeof ( *info ) );
+ if ( ! info )
+ return -ENOMEM;
+ list_add ( &info->list, &sig->info );
+
+ /* Allocate certificate chain */
+ info->chain = x509_alloc_chain();
+ if ( ! info->chain )
+ return -ENOMEM;
+
+ /* Parse signerInfo */
+ if ( ( rc = cms_parse_signer_info ( sig, info,
+ &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+ }
+
+ return 0;
+}
+
+/**
+ * Free CMS signature
+ *
+ * @v refcnt Reference count
+ */
+static void cms_free ( struct refcnt *refcnt ) {
+ struct cms_signature *sig =
+ container_of ( refcnt, struct cms_signature, refcnt );
+ struct cms_signer_info *info;
+ struct cms_signer_info *tmp;
+
+ list_for_each_entry_safe ( info, tmp, &sig->info, list ) {
+ list_del ( &info->list );
+ x509_chain_put ( info->chain );
+ free ( info->signature );
+ free ( info );
+ }
+ x509_chain_put ( sig->certificates );
+ free ( sig );
+}
+
+/**
+ * Create CMS signature
+ *
+ * @v data Raw signature data
+ * @v len Length of raw data
+ * @ret sig CMS signature
+ * @ret rc Return status code
+ *
+ * On success, the caller holds a reference to the CMS signature, and
+ * is responsible for ultimately calling cms_put().
+ */
+int cms_signature ( const void *data, size_t len, struct cms_signature **sig ) {
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Allocate and initialise signature */
+ *sig = zalloc ( sizeof ( **sig ) );
+ if ( ! *sig ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ ref_init ( &(*sig)->refcnt, cms_free );
+ INIT_LIST_HEAD ( &(*sig)->info );
+
+ /* Allocate certificate list */
+ (*sig)->certificates = x509_alloc_chain();
+ if ( ! (*sig)->certificates ) {
+ rc = -ENOMEM;
+ goto err_alloc_chain;
+ }
+
+ /* Initialise cursor */
+ cursor.data = data;
+ cursor.len = len;
+ asn1_shrink_any ( &cursor );
+
+ /* Parse signature */
+ if ( ( rc = cms_parse ( *sig, &cursor ) ) != 0 )
+ goto err_parse;
+
+ return 0;
+
+ err_parse:
+ err_alloc_chain:
+ cms_put ( *sig );
+ err_alloc:
+ return rc;
+}
+
+/**
+ * Calculate digest of CMS-signed data
+ *
+ * @v sig CMS signature
+ * @v info Signer information
+ * @v data Signed data
+ * @v len Length of signed data
+ * @v out Digest output
+ */
+static void cms_digest ( struct cms_signature *sig,
+ struct cms_signer_info *info,
+ userptr_t data, size_t len, void *out ) {
+ struct digest_algorithm *digest = info->digest;
+ uint8_t ctx[ digest->ctxsize ];
+ uint8_t block[ digest->blocksize ];
+ size_t offset = 0;
+ size_t frag_len;
+
+ /* Initialise digest */
+ digest_init ( digest, ctx );
+
+ /* Process data one block at a time */
+ while ( len ) {
+ frag_len = len;
+ if ( frag_len > sizeof ( block ) )
+ frag_len = sizeof ( block );
+ copy_from_user ( block, data, offset, frag_len );
+ digest_update ( digest, ctx, block, frag_len );
+ offset += frag_len;
+ len -= frag_len;
+ }
+
+ /* Finalise digest */
+ digest_final ( digest, ctx, out );
+
+ DBGC ( sig, "CMS %p/%p digest value:\n", sig, info );
+ DBGC_HDA ( sig, 0, out, digest->digestsize );
+}
+
+/**
+ * Verify digest of CMS-signed data
+ *
+ * @v sig CMS signature
+ * @v info Signer information
+ * @v cert Corresponding certificate
+ * @v data Signed data
+ * @v len Length of signed data
+ * @ret rc Return status code
+ */
+static int cms_verify_digest ( struct cms_signature *sig,
+ struct cms_signer_info *info,
+ struct x509_certificate *cert,
+ userptr_t data, size_t len ) {
+ struct digest_algorithm *digest = info->digest;
+ struct pubkey_algorithm *pubkey = info->pubkey;
+ struct x509_public_key *public_key = &cert->subject.public_key;
+ uint8_t digest_out[ digest->digestsize ];
+ uint8_t ctx[ pubkey->ctxsize ];
+ int rc;
+
+ /* Generate digest */
+ cms_digest ( sig, info, data, len, digest_out );
+
+ /* Initialise public-key algorithm */
+ if ( ( rc = pubkey_init ( pubkey, ctx, public_key->raw.data,
+ public_key->raw.len ) ) != 0 ) {
+ DBGC ( sig, "CMS %p/%p could not initialise public key: %s\n",
+ sig, info, strerror ( rc ) );
+ goto err_init;
+ }
+
+ /* Verify digest */
+ if ( ( rc = pubkey_verify ( pubkey, ctx, digest, digest_out,
+ info->signature,
+ info->signature_len ) ) != 0 ) {
+ DBGC ( sig, "CMS %p/%p signature verification failed: %s\n",
+ sig, info, strerror ( rc ) );
+ goto err_verify;
+ }
+
+ err_verify:
+ pubkey_final ( pubkey, ctx );
+ err_init:
+ return rc;
+}
+
+/**
+ * Verify CMS signature signer information
+ *
+ * @v sig CMS signature
+ * @v info Signer information
+ * @v data Signed data
+ * @v len Length of signed data
+ * @v time Time at which to validate certificates
+ * @v store Certificate store, or NULL to use default
+ * @v root Root certificate list, or NULL to use default
+ * @ret rc Return status code
+ */
+static int cms_verify_signer_info ( struct cms_signature *sig,
+ struct cms_signer_info *info,
+ userptr_t data, size_t len,
+ time_t time, struct x509_chain *store,
+ struct x509_root *root ) {
+ struct x509_certificate *cert;
+ int rc;
+
+ /* Validate certificate chain */
+ if ( ( rc = x509_validate_chain ( info->chain, time, store,
+ root ) ) != 0 ) {
+ DBGC ( sig, "CMS %p/%p could not validate chain: %s\n",
+ sig, info, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Extract code-signing certificate */
+ cert = x509_first ( info->chain );
+ assert ( cert != NULL );
+
+ /* Check that certificate can create digital signatures */
+ if ( ! ( cert->extensions.usage.bits & X509_DIGITAL_SIGNATURE ) ) {
+ DBGC ( sig, "CMS %p/%p certificate cannot create signatures\n",
+ sig, info );
+ return -EACCES_NON_SIGNING;
+ }
+
+ /* Check that certificate can sign code */
+ if ( ! ( cert->extensions.ext_usage.bits & X509_CODE_SIGNING ) ) {
+ DBGC ( sig, "CMS %p/%p certificate is not code-signing\n",
+ sig, info );
+ return -EACCES_NON_CODE_SIGNING;
+ }
+
+ /* Verify digest */
+ if ( ( rc = cms_verify_digest ( sig, info, cert, data, len ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Verify CMS signature
+ *
+ * @v sig CMS signature
+ * @v data Signed data
+ * @v len Length of signed data
+ * @v name Required common name, or NULL to check all signatures
+ * @v time Time at which to validate certificates
+ * @v store Certificate store, or NULL to use default
+ * @v root Root certificate list, or NULL to use default
+ * @ret rc Return status code
+ */
+int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
+ const char *name, time_t time, struct x509_chain *store,
+ struct x509_root *root ) {
+ struct cms_signer_info *info;
+ struct x509_certificate *cert;
+ int count = 0;
+ int rc;
+
+ /* Verify using all signerInfos */
+ list_for_each_entry ( info, &sig->info, list ) {
+ cert = x509_first ( info->chain );
+ if ( name && ( x509_check_name ( cert, name ) != 0 ) )
+ continue;
+ if ( ( rc = cms_verify_signer_info ( sig, info, data, len, time,
+ store, root ) ) != 0 )
+ return rc;
+ count++;
+ }
+
+ /* Check that we have verified at least one signature */
+ if ( count == 0 ) {
+ if ( name ) {
+ DBGC ( sig, "CMS %p had no signatures matching name "
+ "%s\n", sig, name );
+ return -EACCES_WRONG_NAME;
+ } else {
+ DBGC ( sig, "CMS %p had no signatures\n", sig );
+ return -EACCES_NO_SIGNATURES;
+ }
+ }
+
+ return 0;
+}
diff --git a/qemu/roms/ipxe/src/crypto/crc32.c b/qemu/roms/ipxe/src/crypto/crc32.c
new file mode 100644
index 000000000..cfef68c02
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/crc32.c
@@ -0,0 +1,55 @@
+/*
+ * Little-endian CRC32 implementation.
+ *
+ * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <ipxe/crc32.h>
+
+#define CRCPOLY 0xedb88320
+
+/**
+ * Calculate 32-bit little-endian CRC checksum
+ *
+ * @v seed Initial value
+ * @v data Data to checksum
+ * @v len Length of data
+ *
+ * Usually @a seed is initially zero or all one bits, depending on the
+ * protocol. To continue a CRC checksum over multiple calls, pass the
+ * return value from one call as the @a seed parameter to the next.
+ */
+u32 crc32_le ( u32 seed, const void *data, size_t len )
+{
+ u32 crc = seed;
+ const u8 *src = data;
+ u32 mult;
+ int i;
+
+ while ( len-- ) {
+ crc ^= *src++;
+ for ( i = 0; i < 8; i++ ) {
+ mult = ( crc & 1 ) ? CRCPOLY : 0;
+ crc = ( crc >> 1 ) ^ mult;
+ }
+ }
+
+ return crc;
+}
diff --git a/qemu/roms/ipxe/src/crypto/crypto_null.c b/qemu/roms/ipxe/src/crypto/crypto_null.c
new file mode 100644
index 000000000..ba05f7269
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/crypto_null.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Null crypto algorithm
+ */
+
+#include <string.h>
+#include <ipxe/crypto.h>
+
+static void digest_null_init ( void *ctx __unused ) {
+ /* Do nothing */
+}
+
+static void digest_null_update ( void *ctx __unused, const void *src __unused,
+ size_t len __unused ) {
+ /* Do nothing */
+}
+
+static void digest_null_final ( void *ctx __unused, void *out __unused ) {
+ /* Do nothing */
+}
+
+struct digest_algorithm digest_null = {
+ .name = "null",
+ .ctxsize = 0,
+ .blocksize = 1,
+ .digestsize = 0,
+ .init = digest_null_init,
+ .update = digest_null_update,
+ .final = digest_null_final,
+};
+
+static int cipher_null_setkey ( void *ctx __unused, const void *key __unused,
+ size_t keylen __unused ) {
+ /* Do nothing */
+ return 0;
+}
+
+static void cipher_null_setiv ( void *ctx __unused,
+ const void *iv __unused ) {
+ /* Do nothing */
+}
+
+static void cipher_null_encrypt ( void *ctx __unused, const void *src,
+ void *dst, size_t len ) {
+ memcpy ( dst, src, len );
+}
+
+static void cipher_null_decrypt ( void *ctx __unused, const void *src,
+ void *dst, size_t len ) {
+ memcpy ( dst, src, len );
+}
+
+struct cipher_algorithm cipher_null = {
+ .name = "null",
+ .ctxsize = 0,
+ .blocksize = 1,
+ .setkey = cipher_null_setkey,
+ .setiv = cipher_null_setiv,
+ .encrypt = cipher_null_encrypt,
+ .decrypt = cipher_null_decrypt,
+};
+
+static int pubkey_null_init ( void *ctx __unused, const void *key __unused,
+ size_t key_len __unused ) {
+ return 0;
+}
+
+static size_t pubkey_null_max_len ( void *ctx __unused ) {
+ return 0;
+}
+
+static int pubkey_null_encrypt ( void *ctx __unused,
+ const void *plaintext __unused,
+ size_t plaintext_len __unused,
+ void *ciphertext __unused ) {
+ return 0;
+}
+
+static int pubkey_null_decrypt ( void *ctx __unused,
+ const void *ciphertext __unused,
+ size_t ciphertext_len __unused,
+ void *plaintext __unused ) {
+ return 0;
+}
+
+static int pubkey_null_sign ( void *ctx __unused,
+ struct digest_algorithm *digest __unused,
+ const void *value __unused,
+ void *signature __unused ) {
+ return 0;
+}
+
+static int pubkey_null_verify ( void *ctx __unused,
+ struct digest_algorithm *digest __unused,
+ const void *value __unused,
+ const void *signature __unused ,
+ size_t signature_len __unused ) {
+ return 0;
+}
+
+static void pubkey_null_final ( void *ctx __unused ) {
+ /* Do nothing */
+}
+
+struct pubkey_algorithm pubkey_null = {
+ .name = "null",
+ .ctxsize = 0,
+ .init = pubkey_null_init,
+ .max_len = pubkey_null_max_len,
+ .encrypt = pubkey_null_encrypt,
+ .decrypt = pubkey_null_decrypt,
+ .sign = pubkey_null_sign,
+ .verify = pubkey_null_verify,
+ .final = pubkey_null_final,
+};
diff --git a/qemu/roms/ipxe/src/crypto/deflate.c b/qemu/roms/ipxe/src/crypto/deflate.c
new file mode 100644
index 000000000..91a489961
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/deflate.c
@@ -0,0 +1,1045 @@
+/*
+ * Copyright (C) 2014 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+#include <ipxe/uaccess.h>
+#include <ipxe/deflate.h>
+
+/** @file
+ *
+ * DEFLATE decompression algorithm
+ *
+ * This file implements the decompression half of the DEFLATE
+ * algorithm specified in RFC 1951.
+ *
+ * Portions of this code are derived from wimboot's xca.c.
+ *
+ */
+
+/**
+ * Byte reversal table
+ *
+ * For some insane reason, the DEFLATE format stores some values in
+ * bit-reversed order.
+ */
+static uint8_t deflate_reverse[256];
+
+/** Literal/length base values
+ *
+ * We include entries only for literal/length codes 257-284. Code 285
+ * does not fit the pattern (it represents a length of 258; following
+ * the pattern from the earlier codes would give a length of 259), and
+ * has no extra bits. Codes 286-287 are invalid, but can occur. We
+ * treat any code greater than 284 as meaning "length 285, no extra
+ * bits".
+ */
+static uint8_t deflate_litlen_base[28];
+
+/** Distance base values
+ *
+ * We include entries for all possible codes 0-31, avoiding the need
+ * to check for undefined codes 30 and 31 before performing the
+ * lookup. Codes 30 and 31 are never initialised, and will therefore
+ * be treated as meaning "14 extra bits, base distance 0".
+ */
+static uint16_t deflate_distance_base[32];
+
+/** Code length map */
+static uint8_t deflate_codelen_map[19] = {
+ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15
+};
+
+/** Static Huffman alphabet length patterns */
+static struct deflate_static_length_pattern deflate_static_length_patterns[] = {
+ /* Literal/length code lengths */
+ { 0x88, ( ( ( 143 - 0 ) + 1 ) / 2 ) },
+ { 0x99, ( ( ( 255 - 144 ) + 1 ) / 2 ) },
+ { 0x77, ( ( ( 279 - 256 ) + 1 ) / 2 ) },
+ { 0x88, ( ( ( 287 - 280 ) + 1 ) / 2 ) },
+ /* Distance code lengths */
+ { 0x55, ( ( ( 31 - 0 ) + 1 ) / 2 ) },
+ /* End marker */
+ { 0, 0 }
+};
+
+/**
+ * Transcribe binary value (for debugging)
+ *
+ * @v value Value
+ * @v bits Length of value (in bits)
+ * @ret string Transcribed value
+ */
+static const char * deflate_bin ( unsigned long value, unsigned int bits ) {
+ static char buf[ ( 8 * sizeof ( value ) ) + 1 /* NUL */ ];
+ char *out = buf;
+
+ /* Sanity check */
+ assert ( bits < sizeof ( buf ) );
+
+ /* Transcribe value */
+ while ( bits-- )
+ *(out++) = ( ( value & ( 1 << bits ) ) ? '1' : '0' );
+ *out = '\0';
+
+ return buf;
+}
+
+/**
+ * Set Huffman symbol length
+ *
+ * @v deflate Decompressor
+ * @v index Index within lengths
+ * @v bits Symbol length (in bits)
+ */
+static void deflate_set_length ( struct deflate *deflate, unsigned int index,
+ unsigned int bits ) {
+
+ deflate->lengths[ index / 2 ] |= ( bits << ( 4 * ( index % 2 ) ) );
+}
+
+/**
+ * Get Huffman symbol length
+ *
+ * @v deflate Decompressor
+ * @v index Index within lengths
+ * @ret bits Symbol length (in bits)
+ */
+static unsigned int deflate_length ( struct deflate *deflate,
+ unsigned int index ) {
+
+ return ( ( deflate->lengths[ index / 2 ] >> ( 4 * ( index % 2 ) ) )
+ & 0x0f );
+}
+
+/**
+ * Determine Huffman alphabet name (for debugging)
+ *
+ * @v deflate Decompressor
+ * @v alphabet Huffman alphabet
+ * @ret name Alphabet name
+ */
+static const char * deflate_alphabet_name ( struct deflate *deflate,
+ struct deflate_alphabet *alphabet ){
+
+ if ( alphabet == &deflate->litlen ) {
+ return "litlen";
+ } else if ( alphabet == &deflate->distance_codelen ) {
+ return "distance/codelen";
+ } else {
+ return "<UNKNOWN>";
+ }
+}
+
+/**
+ * Dump Huffman alphabet (for debugging)
+ *
+ * @v deflate Decompressor
+ * @v alphabet Huffman alphabet
+ */
+static void deflate_dump_alphabet ( struct deflate *deflate,
+ struct deflate_alphabet *alphabet ) {
+ struct deflate_huf_symbols *huf_sym;
+ unsigned int bits;
+ unsigned int huf;
+ unsigned int i;
+
+ /* Do nothing unless debugging is enabled */
+ if ( ! DBG_EXTRA )
+ return;
+
+ /* Dump symbol table for each utilised length */
+ for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) /
+ sizeof ( alphabet->huf[0] ) ) ; bits++ ) {
+ huf_sym = &alphabet->huf[ bits - 1 ];
+ if ( huf_sym->freq == 0 )
+ continue;
+ huf = ( huf_sym->start >> huf_sym->shift );
+ DBGC2 ( alphabet, "DEFLATE %p \"%s\" length %d start \"%s\" "
+ "freq %d:", deflate,
+ deflate_alphabet_name ( deflate, alphabet ), bits,
+ deflate_bin ( huf, huf_sym->bits ), huf_sym->freq );
+ for ( i = 0 ; i < huf_sym->freq ; i++ ) {
+ DBGC2 ( alphabet, " %03x",
+ huf_sym->raw[ huf + i ] );
+ }
+ DBGC2 ( alphabet, "\n" );
+ }
+
+ /* Dump quick lookup table */
+ DBGC2 ( alphabet, "DEFLATE %p \"%s\" quick lookup:", deflate,
+ deflate_alphabet_name ( deflate, alphabet ) );
+ for ( i = 0 ; i < ( sizeof ( alphabet->lookup ) /
+ sizeof ( alphabet->lookup[0] ) ) ; i++ ) {
+ DBGC2 ( alphabet, " %d", ( alphabet->lookup[i] + 1 ) );
+ }
+ DBGC2 ( alphabet, "\n" );
+}
+
+/**
+ * Construct Huffman alphabet
+ *
+ * @v deflate Decompressor
+ * @v alphabet Huffman alphabet
+ * @v count Number of symbols
+ * @v offset Starting offset within length table
+ * @ret rc Return status code
+ */
+static int deflate_alphabet ( struct deflate *deflate,
+ struct deflate_alphabet *alphabet,
+ unsigned int count, unsigned int offset ) {
+ struct deflate_huf_symbols *huf_sym;
+ unsigned int huf;
+ unsigned int cum_freq;
+ unsigned int bits;
+ unsigned int raw;
+ unsigned int adjustment;
+ unsigned int prefix;
+ int complete;
+
+ /* Clear symbol table */
+ memset ( alphabet->huf, 0, sizeof ( alphabet->huf ) );
+
+ /* Count number of symbols with each Huffman-coded length */
+ for ( raw = 0 ; raw < count ; raw++ ) {
+ bits = deflate_length ( deflate, ( raw + offset ) );
+ if ( bits )
+ alphabet->huf[ bits - 1 ].freq++;
+ }
+
+ /* Populate Huffman-coded symbol table */
+ huf = 0;
+ cum_freq = 0;
+ for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) /
+ sizeof ( alphabet->huf[0] ) ) ; bits++ ) {
+ huf_sym = &alphabet->huf[ bits - 1 ];
+ huf_sym->bits = bits;
+ huf_sym->shift = ( 16 - bits );
+ huf_sym->start = ( huf << huf_sym->shift );
+ huf_sym->raw = &alphabet->raw[cum_freq];
+ huf += huf_sym->freq;
+ if ( huf > ( 1U << bits ) ) {
+ DBGC ( alphabet, "DEFLATE %p \"%s\" has too many "
+ "symbols with lengths <=%d\n", deflate,
+ deflate_alphabet_name ( deflate, alphabet ),
+ bits );
+ return -EINVAL;
+ }
+ huf <<= 1;
+ cum_freq += huf_sym->freq;
+ }
+ complete = ( huf == ( 1U << bits ) );
+
+ /* Populate raw symbol table */
+ for ( raw = 0 ; raw < count ; raw++ ) {
+ bits = deflate_length ( deflate, ( raw + offset ) );
+ if ( bits ) {
+ huf_sym = &alphabet->huf[ bits - 1 ];
+ *(huf_sym->raw++) = raw;
+ }
+ }
+
+ /* Adjust Huffman-coded symbol table raw pointers and populate
+ * quick lookup table.
+ */
+ for ( bits = 1 ; bits <= ( sizeof ( alphabet->huf ) /
+ sizeof ( alphabet->huf[0] ) ) ; bits++ ) {
+ huf_sym = &alphabet->huf[ bits - 1 ];
+
+ /* Adjust raw pointer */
+ huf_sym->raw -= huf_sym->freq; /* Reset to first symbol */
+ adjustment = ( huf_sym->start >> huf_sym->shift );
+ huf_sym->raw -= adjustment; /* Adjust for quick indexing */
+
+ /* Populate quick lookup table */
+ for ( prefix = ( huf_sym->start >> DEFLATE_HUFFMAN_QL_SHIFT ) ;
+ prefix < ( 1 << DEFLATE_HUFFMAN_QL_BITS ) ; prefix++ ) {
+ alphabet->lookup[prefix] = ( bits - 1 );
+ }
+ }
+
+ /* Dump alphabet (for debugging) */
+ deflate_dump_alphabet ( deflate, alphabet );
+
+ /* Check that there are no invalid codes */
+ if ( ! complete ) {
+ DBGC ( alphabet, "DEFLATE %p \"%s\" is incomplete\n", deflate,
+ deflate_alphabet_name ( deflate, alphabet ) );
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * Attempt to accumulate bits from input stream
+ *
+ * @v deflate Decompressor
+ * @v in Compressed input data
+ * @v target Number of bits to accumulate
+ * @ret excess Number of excess bits accumulated (may be negative)
+ */
+static int deflate_accumulate ( struct deflate *deflate,
+ struct deflate_chunk *in,
+ unsigned int target ) {
+ uint8_t byte;
+
+ while ( deflate->bits < target ) {
+
+ /* Check for end of input */
+ if ( in->offset >= in->len )
+ break;
+
+ /* Acquire byte from input */
+ copy_from_user ( &byte, in->data, in->offset++,
+ sizeof ( byte ) );
+ deflate->accumulator = ( deflate->accumulator |
+ ( byte << deflate->bits ) );
+ deflate->rotalumucca = ( deflate->rotalumucca |
+ ( deflate_reverse[byte] <<
+ ( 24 - deflate->bits ) ) );
+ deflate->bits += 8;
+
+ /* Sanity check */
+ assert ( deflate->bits <=
+ ( 8 * sizeof ( deflate->accumulator ) ) );
+ }
+
+ return ( deflate->bits - target );
+}
+
+/**
+ * Consume accumulated bits from the input stream
+ *
+ * @v deflate Decompressor
+ * @v count Number of accumulated bits to consume
+ * @ret data Consumed bits
+ */
+static int deflate_consume ( struct deflate *deflate, unsigned int count ) {
+ int data;
+
+ /* Sanity check */
+ assert ( count <= deflate->bits );
+
+ /* Extract data and consume bits */
+ data = ( deflate->accumulator & ( ( 1 << count ) - 1 ) );
+ deflate->accumulator >>= count;
+ deflate->rotalumucca <<= count;
+ deflate->bits -= count;
+
+ return data;
+}
+
+/**
+ * Attempt to extract a fixed number of bits from input stream
+ *
+ * @v deflate Decompressor
+ * @v in Compressed input data
+ * @v target Number of bits to extract
+ * @ret data Extracted bits (or negative if not yet accumulated)
+ */
+static int deflate_extract ( struct deflate *deflate, struct deflate_chunk *in,
+ unsigned int target ) {
+ int excess;
+ int data;
+
+ /* Return immediately if we are attempting to extract zero bits */
+ if ( target == 0 )
+ return 0;
+
+ /* Attempt to accumulate bits */
+ excess = deflate_accumulate ( deflate, in, target );
+ if ( excess < 0 )
+ return excess;
+
+ /* Extract data and consume bits */
+ data = deflate_consume ( deflate, target );
+ DBGCP ( deflate, "DEFLATE %p extracted %s = %#x = %d\n", deflate,
+ deflate_bin ( data, target ), data, data );
+
+ return data;
+}
+
+/**
+ * Attempt to decode a Huffman-coded symbol from input stream
+ *
+ * @v deflate Decompressor
+ * @v in Compressed input data
+ * @v alphabet Huffman alphabet
+ * @ret code Raw code (or negative if not yet accumulated)
+ */
+static int deflate_decode ( struct deflate *deflate,
+ struct deflate_chunk *in,
+ struct deflate_alphabet *alphabet ) {
+ struct deflate_huf_symbols *huf_sym;
+ uint16_t huf;
+ unsigned int lookup_index;
+ int excess;
+ unsigned int raw;
+
+ /* Attempt to accumulate maximum required number of bits.
+ * There may be fewer bits than this remaining in the stream,
+ * even if the stream still contains some complete
+ * Huffman-coded symbols.
+ */
+ deflate_accumulate ( deflate, in, DEFLATE_HUFFMAN_BITS );
+
+ /* Normalise the bit-reversed accumulated value to 16 bits */
+ huf = ( deflate->rotalumucca >> 16 );
+
+ /* Find symbol set for this length */
+ lookup_index = ( huf >> DEFLATE_HUFFMAN_QL_SHIFT );
+ huf_sym = &alphabet->huf[ alphabet->lookup[ lookup_index ] ];
+ while ( huf < huf_sym->start )
+ huf_sym--;
+
+ /* Calculate number of excess bits, and return if not yet complete */
+ excess = ( deflate->bits - huf_sym->bits );
+ if ( excess < 0 )
+ return excess;
+
+ /* Consume bits */
+ deflate_consume ( deflate, huf_sym->bits );
+
+ /* Look up raw symbol */
+ raw = huf_sym->raw[ huf >> huf_sym->shift ];
+ DBGCP ( deflate, "DEFLATE %p decoded %s = %#x = %d\n", deflate,
+ deflate_bin ( ( huf >> huf_sym->shift ), huf_sym->bits ),
+ raw, raw );
+
+ return raw;
+}
+
+/**
+ * Discard bits up to the next byte boundary
+ *
+ * @v deflate Decompressor
+ */
+static void deflate_discard_to_byte ( struct deflate *deflate ) {
+
+ deflate_consume ( deflate, ( deflate->bits & 7 ) );
+}
+
+/**
+ * Copy data to output buffer (if available)
+ *
+ * @v out Output data buffer
+ * @v start Source data
+ * @v offset Starting offset within source data
+ * @v len Length to copy
+ */
+static void deflate_copy ( struct deflate_chunk *out,
+ userptr_t start, size_t offset, size_t len ) {
+ size_t out_offset = out->offset;
+ size_t copy_len;
+
+ /* Copy data one byte at a time, to allow for overlap */
+ if ( out_offset < out->len ) {
+ copy_len = ( out->len - out_offset );
+ if ( copy_len > len )
+ copy_len = len;
+ while ( copy_len-- ) {
+ memcpy_user ( out->data, out_offset++,
+ start, offset++, 1 );
+ }
+ }
+ out->offset += len;
+}
+
+/**
+ * Inflate compressed data
+ *
+ * @v deflate Decompressor
+ * @v in Compressed input data
+ * @v out Output data buffer
+ * @ret rc Return status code
+ *
+ * The caller can use deflate_finished() to determine whether a
+ * successful return indicates that the decompressor is merely waiting
+ * for more input.
+ *
+ * Data will not be written beyond the specified end of the output
+ * data buffer, but the offset within the output data buffer will be
+ * updated to reflect the amount that should have been written. The
+ * caller can use this to find the length of the decompressed data
+ * before allocating the output data buffer.
+ */
+int deflate_inflate ( struct deflate *deflate,
+ struct deflate_chunk *in,
+ struct deflate_chunk *out ) {
+
+ /* This could be implemented more neatly if gcc offered a
+ * means for enforcing tail recursion.
+ */
+ if ( deflate->resume ) {
+ goto *(deflate->resume);
+ } else switch ( deflate->format ) {
+ case DEFLATE_RAW: goto block_header;
+ case DEFLATE_ZLIB: goto zlib_header;
+ default: assert ( 0 );
+ }
+
+ zlib_header: {
+ int header;
+ int cm;
+
+ /* Extract header */
+ header = deflate_extract ( deflate, in, ZLIB_HEADER_BITS );
+ if ( header < 0 ) {
+ deflate->resume = &&zlib_header;
+ return 0;
+ }
+
+ /* Parse header */
+ cm = ( ( header >> ZLIB_HEADER_CM_LSB ) & ZLIB_HEADER_CM_MASK );
+ if ( cm != ZLIB_HEADER_CM_DEFLATE ) {
+ DBGC ( deflate, "DEFLATE %p unsupported ZLIB "
+ "compression method %d\n", deflate, cm );
+ return -ENOTSUP;
+ }
+ if ( header & ( 1 << ZLIB_HEADER_FDICT_BIT ) ) {
+ DBGC ( deflate, "DEFLATE %p unsupported ZLIB preset "
+ "dictionary\n", deflate );
+ return -ENOTSUP;
+ }
+
+ /* Process first block header */
+ goto block_header;
+ }
+
+ block_header: {
+ int header;
+ int bfinal;
+ int btype;
+
+ /* Extract block header */
+ header = deflate_extract ( deflate, in, DEFLATE_HEADER_BITS );
+ if ( header < 0 ) {
+ deflate->resume = &&block_header;
+ return 0;
+ }
+
+ /* Parse header */
+ deflate->header = header;
+ bfinal = ( header & ( 1 << DEFLATE_HEADER_BFINAL_BIT ) );
+ btype = ( header >> DEFLATE_HEADER_BTYPE_LSB );
+ DBGC ( deflate, "DEFLATE %p found %sblock type %#x\n",
+ deflate, ( bfinal ? "final " : "" ), btype );
+ switch ( btype ) {
+ case DEFLATE_HEADER_BTYPE_LITERAL:
+ goto literal_block;
+ case DEFLATE_HEADER_BTYPE_STATIC:
+ goto static_block;
+ case DEFLATE_HEADER_BTYPE_DYNAMIC:
+ goto dynamic_block;
+ default:
+ DBGC ( deflate, "DEFLATE %p unsupported block type "
+ "%#x\n", deflate, btype );
+ return -ENOTSUP;
+ }
+ }
+
+ literal_block: {
+
+ /* Discard any bits up to the next byte boundary */
+ deflate_discard_to_byte ( deflate );
+ }
+
+ literal_len: {
+ int len;
+
+ /* Extract LEN field */
+ len = deflate_extract ( deflate, in, DEFLATE_LITERAL_LEN_BITS );
+ if ( len < 0 ) {
+ deflate->resume = &&literal_len;
+ return 0;
+ }
+
+ /* Record length of literal data */
+ deflate->remaining = len;
+ DBGC2 ( deflate, "DEFLATE %p literal block length %#04zx\n",
+ deflate, deflate->remaining );
+ }
+
+ literal_nlen: {
+ int nlen;
+
+ /* Extract NLEN field */
+ nlen = deflate_extract ( deflate, in, DEFLATE_LITERAL_LEN_BITS);
+ if ( nlen < 0 ) {
+ deflate->resume = &&literal_nlen;
+ return 0;
+ }
+
+ /* Verify NLEN */
+ if ( ( ( deflate->remaining ^ ~nlen ) &
+ ( ( 1 << DEFLATE_LITERAL_LEN_BITS ) - 1 ) ) != 0 ) {
+ DBGC ( deflate, "DEFLATE %p invalid len/nlen "
+ "%#04zx/%#04x\n", deflate,
+ deflate->remaining, nlen );
+ return -EINVAL;
+ }
+ }
+
+ literal_data: {
+ size_t in_remaining;
+ size_t len;
+
+ /* Calculate available amount of literal data */
+ in_remaining = ( in->len - in->offset );
+ len = deflate->remaining;
+ if ( len > in_remaining )
+ len = in_remaining;
+
+ /* Copy data to output buffer */
+ deflate_copy ( out, in->data, in->offset, len );
+
+ /* Consume data from input buffer */
+ in->offset += len;
+ deflate->remaining -= len;
+
+ /* Finish processing if we are blocked */
+ if ( deflate->remaining ) {
+ deflate->resume = &&literal_data;
+ return 0;
+ }
+
+ /* Otherwise, finish block */
+ goto block_done;
+ }
+
+ static_block: {
+ struct deflate_static_length_pattern *pattern;
+ uint8_t *lengths = deflate->lengths;
+
+ /* Construct static Huffman lengths as per RFC 1950 */
+ for ( pattern = deflate_static_length_patterns ;
+ pattern->count ; pattern++ ) {
+ memset ( lengths, pattern->fill, pattern->count );
+ lengths += pattern->count;
+ }
+ deflate->litlen_count = 288;
+ deflate->distance_count = 32;
+ goto construct_alphabets;
+ }
+
+ dynamic_block:
+
+ dynamic_header: {
+ int header;
+ unsigned int hlit;
+ unsigned int hdist;
+ unsigned int hclen;
+
+ /* Extract block header */
+ header = deflate_extract ( deflate, in, DEFLATE_DYNAMIC_BITS );
+ if ( header < 0 ) {
+ deflate->resume = &&dynamic_header;
+ return 0;
+ }
+
+ /* Parse header */
+ hlit = ( ( header >> DEFLATE_DYNAMIC_HLIT_LSB ) &
+ DEFLATE_DYNAMIC_HLIT_MASK );
+ hdist = ( ( header >> DEFLATE_DYNAMIC_HDIST_LSB ) &
+ DEFLATE_DYNAMIC_HDIST_MASK );
+ hclen = ( ( header >> DEFLATE_DYNAMIC_HCLEN_LSB ) &
+ DEFLATE_DYNAMIC_HCLEN_MASK );
+ deflate->litlen_count = ( hlit + 257 );
+ deflate->distance_count = ( hdist + 1 );
+ deflate->length_index = 0;
+ deflate->length_target = ( hclen + 4 );
+ DBGC2 ( deflate, "DEFLATE %p dynamic block %d codelen, %d "
+ "litlen, %d distance\n", deflate,
+ deflate->length_target, deflate->litlen_count,
+ deflate->distance_count );
+
+ /* Prepare for decoding code length code lengths */
+ memset ( &deflate->lengths, 0, sizeof ( deflate->lengths ) );
+ }
+
+ dynamic_codelen: {
+ int len;
+ unsigned int index;
+ int rc;
+
+ /* Extract all code lengths */
+ while ( deflate->length_index < deflate->length_target ) {
+
+ /* Extract code length length */
+ len = deflate_extract ( deflate, in,
+ DEFLATE_CODELEN_BITS );
+ if ( len < 0 ) {
+ deflate->resume = &&dynamic_codelen;
+ return 0;
+ }
+
+ /* Store code length */
+ index = deflate_codelen_map[deflate->length_index++];
+ deflate_set_length ( deflate, index, len );
+ DBGCP ( deflate, "DEFLATE %p codelen for %d is %d\n",
+ deflate, index, len );
+ }
+
+ /* Generate code length alphabet */
+ if ( ( rc = deflate_alphabet ( deflate,
+ &deflate->distance_codelen,
+ ( DEFLATE_CODELEN_MAX_CODE + 1 ),
+ 0 ) ) != 0 )
+ return rc;
+
+ /* Prepare for decoding literal/length/distance code lengths */
+ memset ( &deflate->lengths, 0, sizeof ( deflate->lengths ) );
+ deflate->length_index = 0;
+ deflate->length_target = ( deflate->litlen_count +
+ deflate->distance_count );
+ deflate->length = 0;
+ }
+
+ dynamic_litlen_distance: {
+ int len;
+ int index;
+
+ /* Decode literal/length/distance code length */
+ len = deflate_decode ( deflate, in, &deflate->distance_codelen);
+ if ( len < 0 ) {
+ deflate->resume = &&dynamic_litlen_distance;
+ return 0;
+ }
+
+ /* Prepare for extra bits */
+ if ( len < 16 ) {
+ deflate->length = len;
+ deflate->extra_bits = 0;
+ deflate->dup_len = 1;
+ } else {
+ static const uint8_t dup_len[3] = { 3, 3, 11 };
+ static const uint8_t extra_bits[3] = { 2, 3, 7 };
+ index = ( len - 16 );
+ deflate->dup_len = dup_len[index];
+ deflate->extra_bits = extra_bits[index];
+ if ( index )
+ deflate->length = 0;
+ }
+ }
+
+ dynamic_litlen_distance_extra: {
+ int extra;
+ unsigned int dup_len;
+
+ /* Extract extra bits */
+ extra = deflate_extract ( deflate, in, deflate->extra_bits );
+ if ( extra < 0 ) {
+ deflate->resume = &&dynamic_litlen_distance_extra;
+ return 0;
+ }
+
+ /* Store code lengths */
+ dup_len = ( deflate->dup_len + extra );
+ while ( ( deflate->length_index < deflate->length_target ) &&
+ dup_len-- ) {
+ deflate_set_length ( deflate, deflate->length_index++,
+ deflate->length );
+ }
+
+ /* Process next literal/length or distance code
+ * length, if more are required.
+ */
+ if ( deflate->length_index < deflate->length_target )
+ goto dynamic_litlen_distance;
+
+ /* Construct alphabets */
+ goto construct_alphabets;
+ }
+
+ construct_alphabets: {
+ unsigned int distance_offset = deflate->litlen_count;
+ unsigned int distance_count = deflate->distance_count;
+ int rc;
+
+ /* Generate literal/length alphabet */
+ if ( ( rc = deflate_alphabet ( deflate, &deflate->litlen,
+ deflate->litlen_count, 0 ) ) !=0)
+ return rc;
+
+ /* Handle degenerate case of a single distance code
+ * (for which it is impossible to construct a valid,
+ * complete Huffman alphabet). RFC 1951 states:
+ *
+ * If only one distance code is used, it is encoded
+ * using one bit, not zero bits; in this case there
+ * is a single code length of one, with one unused
+ * code. One distance code of zero bits means that
+ * there are no distance codes used at all (the data
+ * is all literals).
+ *
+ * If we have only a single distance code, then we
+ * instead use two distance codes both with length 1.
+ * This results in a valid Huffman alphabet. The code
+ * "0" will mean distance code 0 (which is either
+ * correct or irrelevant), and the code "1" will mean
+ * distance code 1 (which is always irrelevant).
+ */
+ if ( deflate->distance_count == 1 ) {
+
+ deflate->lengths[0] = 0x11;
+ distance_offset = 0;
+ distance_count = 2;
+ }
+
+ /* Generate distance alphabet */
+ if ( ( rc = deflate_alphabet ( deflate,
+ &deflate->distance_codelen,
+ distance_count,
+ distance_offset ) ) != 0 )
+ return rc;
+ }
+
+ lzhuf_litlen: {
+ int code;
+ uint8_t byte;
+ unsigned int extra;
+ unsigned int bits;
+
+ /* Decode Huffman codes */
+ while ( 1 ) {
+
+ /* Decode Huffman code */
+ code = deflate_decode ( deflate, in, &deflate->litlen );
+ if ( code < 0 ) {
+ deflate->resume = &&lzhuf_litlen;
+ return 0;
+ }
+
+ /* Handle according to code type */
+ if ( code < DEFLATE_LITLEN_END ) {
+
+ /* Literal value: copy to output buffer */
+ byte = code;
+ DBGCP ( deflate, "DEFLATE %p literal %#02x "
+ "('%c')\n", deflate, byte,
+ ( isprint ( byte ) ? byte : '.' ) );
+ deflate_copy ( out, virt_to_user ( &byte ), 0,
+ sizeof ( byte ) );
+
+ } else if ( code == DEFLATE_LITLEN_END ) {
+
+ /* End of block */
+ goto block_done;
+
+ } else {
+
+ /* Length code: process extra bits */
+ extra = ( code - DEFLATE_LITLEN_END - 1 );
+ if ( extra < 28 ) {
+ bits = ( extra / 4 );
+ if ( bits )
+ bits--;
+ deflate->extra_bits = bits;
+ deflate->dup_len =
+ deflate_litlen_base[extra];
+ } else {
+ deflate->extra_bits = 0;
+ deflate->dup_len = 258;
+ }
+ goto lzhuf_litlen_extra;
+ }
+ }
+ }
+
+ lzhuf_litlen_extra: {
+ int extra;
+
+ /* Extract extra bits */
+ extra = deflate_extract ( deflate, in, deflate->extra_bits );
+ if ( extra < 0 ) {
+ deflate->resume = &&lzhuf_litlen_extra;
+ return 0;
+ }
+
+ /* Update duplicate length */
+ deflate->dup_len += extra;
+ }
+
+ lzhuf_distance: {
+ int code;
+ unsigned int extra;
+ unsigned int bits;
+
+ /* Decode Huffman code */
+ code = deflate_decode ( deflate, in,
+ &deflate->distance_codelen );
+ if ( code < 0 ) {
+ deflate->resume = &&lzhuf_distance;
+ return 0;
+ }
+
+ /* Process extra bits */
+ extra = code;
+ bits = ( extra / 2 );
+ if ( bits )
+ bits--;
+ deflate->extra_bits = bits;
+ deflate->dup_distance = deflate_distance_base[extra];
+ }
+
+ lzhuf_distance_extra: {
+ int extra;
+ size_t dup_len;
+ size_t dup_distance;
+
+ /* Extract extra bits */
+ extra = deflate_extract ( deflate, in, deflate->extra_bits );
+ if ( extra < 0 ) {
+ deflate->resume = &&lzhuf_distance_extra;
+ return 0;
+ }
+
+ /* Update duplicate distance */
+ dup_distance = ( deflate->dup_distance + extra );
+ dup_len = deflate->dup_len;
+ DBGCP ( deflate, "DEFLATE %p duplicate length %zd distance "
+ "%zd\n", deflate, dup_len, dup_distance );
+
+ /* Sanity check */
+ if ( dup_distance > out->offset ) {
+ DBGC ( deflate, "DEFLATE %p bad distance %zd (max "
+ "%zd)\n", deflate, dup_distance, out->offset );
+ return -EINVAL;
+ }
+
+ /* Copy data, allowing for overlap */
+ deflate_copy ( out, out->data, ( out->offset - dup_distance ),
+ dup_len );
+
+ /* Process next literal/length symbol */
+ goto lzhuf_litlen;
+ }
+
+ block_done: {
+
+ DBGCP ( deflate, "DEFLATE %p end of block\n", deflate );
+
+ /* If this was not the final block, process next block header */
+ if ( ! ( deflate->header & ( 1 << DEFLATE_HEADER_BFINAL_BIT ) ))
+ goto block_header;
+
+ /* Otherwise, process footer (if any) */
+ switch ( deflate->format ) {
+ case DEFLATE_RAW: goto finished;
+ case DEFLATE_ZLIB: goto zlib_footer;
+ default: assert ( 0 );
+ }
+ }
+
+ zlib_footer: {
+
+ /* Discard any bits up to the next byte boundary */
+ deflate_discard_to_byte ( deflate );
+ }
+
+ zlib_adler32: {
+ int excess;
+
+ /* Accumulate the 32 bits of checksum. We don't check
+ * the value, stop processing immediately afterwards,
+ * and so don't have to worry about the nasty corner
+ * cases involved in calling deflate_extract() to
+ * obtain a full 32 bits.
+ */
+ excess = deflate_accumulate ( deflate, in, ZLIB_ADLER32_BITS );
+ if ( excess < 0 ) {
+ deflate->resume = &&zlib_adler32;
+ return 0;
+ }
+
+ /* Finish processing */
+ goto finished;
+ }
+
+ finished: {
+ /* Mark as finished and terminate */
+ DBGCP ( deflate, "DEFLATE %p finished\n", deflate );
+ deflate->resume = NULL;
+ return 0;
+ }
+}
+
+/**
+ * Initialise decompressor
+ *
+ * @v deflate Decompressor
+ * @v format Compression format code
+ */
+void deflate_init ( struct deflate *deflate, enum deflate_format format ) {
+ static int global_init_done;
+ uint8_t i;
+ uint8_t bit;
+ uint8_t byte;
+ unsigned int base;
+ unsigned int bits;
+
+ /* Perform global initialisation if required */
+ if ( ! global_init_done ) {
+
+ /* Initialise byte reversal table */
+ for ( i = 255 ; i ; i-- ) {
+ for ( bit = 1, byte = 0 ; bit ; bit <<= 1 ) {
+ byte <<= 1;
+ if ( i & bit )
+ byte |= 1;
+ }
+ deflate_reverse[i] = byte;
+ }
+
+ /* Initialise literal/length extra bits table */
+ base = 3;
+ for ( i = 0 ; i < 28 ; i++ ) {
+ bits = ( i / 4 );
+ if ( bits )
+ bits--;
+ deflate_litlen_base[i] = base;
+ base += ( 1 << bits );
+ }
+ assert ( base == 259 ); /* sic */
+
+ /* Initialise distance extra bits table */
+ base = 1;
+ for ( i = 0 ; i < 30 ; i++ ) {
+ bits = ( i / 2 );
+ if ( bits )
+ bits--;
+ deflate_distance_base[i] = base;
+ base += ( 1 << bits );
+ }
+ assert ( base == 32769 );
+
+ /* Record global initialisation as complete */
+ global_init_done = 1;
+ }
+
+ /* Initialise structure */
+ memset ( deflate, 0, sizeof ( *deflate ) );
+ deflate->format = format;
+}
diff --git a/qemu/roms/ipxe/src/crypto/drbg.c b/qemu/roms/ipxe/src/crypto/drbg.c
new file mode 100644
index 000000000..9e0175d25
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/drbg.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * DRBG mechanism
+ *
+ * This mechanism is designed to comply with ANS X9.82 Part 3-2007
+ * Section 9. This standard is not freely available, but most of the
+ * text appears to be shared with NIST SP 800-90, which can be
+ * downloaded from
+ *
+ * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
+ *
+ * Where possible, references are given to both documents. In the
+ * case of any disagreement, ANS X9.82 takes priority over NIST SP
+ * 800-90. (In particular, note that some algorithms that are
+ * Approved by NIST SP 800-90 are not Approved by ANS X9.82.)
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/entropy.h>
+#include <ipxe/drbg.h>
+
+/**
+ * Instantiate DRBG
+ *
+ * @v state Algorithm state to be initialised
+ * @v personal Personalisation string
+ * @v personal_len Length of personalisation string
+ * @ret rc Return status code
+ *
+ * This is the Instantiate_function defined in ANS X9.82 Part 3-2007
+ * Section 9.2 (NIST SP 800-90 Section 9.1).
+ *
+ * Only a single security strength is supported, and prediction
+ * resistance is always enabled. The nonce is accounted for by
+ * increasing the entropy input, as per ANS X9.82 Part 3-2007 Section
+ * 8.4.2 (NIST SP 800-90 Section 8.6.7).
+ */
+int drbg_instantiate ( struct drbg_state *state, const void *personal,
+ size_t personal_len ) {
+ unsigned int entropy_bits = ( ( 3 * DRBG_SECURITY_STRENGTH + 1 ) / 2 );
+ size_t min_len = DRBG_MIN_ENTROPY_LEN_BYTES;
+ size_t max_len = DRBG_MAX_ENTROPY_LEN_BYTES;
+ uint8_t data[max_len];
+ int len;
+ int rc;
+
+ DBGC ( state, "DRBG %p instantiate\n", state );
+
+ /* Sanity checks */
+ assert ( state != NULL );
+
+ /* 1. If requested_instantiation_security_strength >
+ * highest_supported_security_strength, then return an
+ * ERROR_FLAG
+ */
+ if ( DRBG_SECURITY_STRENGTH > DRBG_MAX_SECURITY_STRENGTH ) {
+ DBGC ( state, "DRBG %p cannot support security strength %d\n",
+ state, DRBG_SECURITY_STRENGTH );
+ return -ENOTSUP;
+ }
+
+ /* 2. If prediction_resistance_flag is set, and prediction
+ * resistance is not supported, then return an ERROR_FLAG
+ *
+ * (Nothing to do since prediction resistance is always
+ * supported.)
+ */
+
+ /* 3. If the length of the personalization_string >
+ * max_personalization_string_length, return an ERROR_FLAG
+ */
+ if ( personal_len > DRBG_MAX_PERSONAL_LEN_BYTES ) {
+ DBGC ( state, "DRBG %p personalisation string too long (%zd "
+ "bytes)\n", state, personal_len );
+ return -ERANGE;
+ }
+
+ /* 4. Set security_strength to the nearest security strength
+ * greater than or equal to
+ * requested_instantiation_security_strength.
+ *
+ * (Nothing to do since we support only a single security
+ * strength.)
+ */
+
+ /* 5. Using the security_strength, select appropriate DRBG
+ * mechanism parameters.
+ *
+ * (Nothing to do since we support only a single security
+ * strength.)
+ */
+
+ /* 6. ( status, entropy_input ) = Get_entropy_input (
+ * security_strength, min_length, max_length,
+ * prediction_resistance_request )
+ * 7. If an ERROR is returned in step 6, return a
+ * CATASTROPHIC_ERROR_FLAG.
+ * 8. Obtain a nonce.
+ */
+ len = get_entropy_input ( entropy_bits, data, min_len,
+ sizeof ( data ) );
+ if ( len < 0 ) {
+ rc = len;
+ DBGC ( state, "DRBG %p could not get entropy input: %s\n",
+ state, strerror ( rc ) );
+ return rc;
+ }
+ assert ( len >= ( int ) min_len );
+ assert ( len <= ( int ) sizeof ( data ) );
+
+ /* 9. initial_working_state = Instantiate_algorithm (
+ * entropy_input, nonce, personalization_string ).
+ */
+ drbg_instantiate_algorithm ( state, data, len, personal, personal_len );
+
+ /* 10. Get a state_handle for a currently empty state. If an
+ * empty internal state cannot be found, return an
+ * ERROR_FLAG.
+ * 11. Set the internal state indicated by state_handle to
+ * the initial values for the internal state (i.e. set
+ * the working_state to the values returned as
+ * initial_working_state in step 9 and any other values
+ * required for the working_state, and set the
+ * administrative information to the appropriate values.
+ *
+ * (Almost nothing to do since the memory to hold the state
+ * was passed in by the caller and has already been updated
+ * in-situ.)
+ */
+ state->reseed_required = 0;
+ state->valid = 1;
+
+ /* 12. Return SUCCESS and state_handle. */
+ return 0;
+}
+
+/**
+ * Reseed DRBG
+ *
+ * @v state Algorithm state
+ * @v additional Additional input
+ * @v additional_len Length of additional input
+ * @ret rc Return status code
+ *
+ * This is the Reseed_function defined in ANS X9.82 Part 3-2007
+ * Section 9.3 (NIST SP 800-90 Section 9.2).
+ *
+ * Prediction resistance is always enabled.
+ */
+int drbg_reseed ( struct drbg_state *state, const void *additional,
+ size_t additional_len ) {
+ unsigned int entropy_bits = DRBG_SECURITY_STRENGTH;
+ size_t min_len = DRBG_MIN_ENTROPY_LEN_BYTES;
+ size_t max_len = DRBG_MAX_ENTROPY_LEN_BYTES;
+ uint8_t data[max_len];
+ int len;
+ int rc;
+
+ DBGC ( state, "DRBG %p reseed\n", state );
+
+ /* Sanity checks */
+ assert ( state != NULL );
+
+ /* 1. Using state_handle, obtain the current internal state.
+ * If state_handle indicates an invalid or empty internal
+ * state, return an ERROR_FLAG.
+ *
+ * (Almost nothing to do since the memory holding the internal
+ * state was passed in by the caller.)
+ */
+ if ( ! state->valid ) {
+ DBGC ( state, "DRBG %p not valid\n", state );
+ return -EINVAL;
+ }
+
+ /* 2. If prediction_resistance_request is set, and
+ * prediction_resistance_flag is not set, then return an
+ * ERROR_FLAG.
+ *
+ * (Nothing to do since prediction resistance is always
+ * supported.)
+ */
+
+ /* 3. If the length of the additional_input >
+ * max_additional_input_length, return an ERROR_FLAG.
+ */
+ if ( additional_len > DRBG_MAX_ADDITIONAL_LEN_BYTES ) {
+ DBGC ( state, "DRBG %p additional input too long (%zd bytes)\n",
+ state, additional_len );
+ return -ERANGE;
+ }
+
+ /* 4. ( status, entropy_input ) = Get_entropy_input (
+ * security_strength, min_length, max_length,
+ * prediction_resistance_request ).
+ *
+ * 5. If an ERROR is returned in step 4, return a
+ * CATASTROPHIC_ERROR_FLAG.
+ */
+ len = get_entropy_input ( entropy_bits, data, min_len,
+ sizeof ( data ) );
+ if ( len < 0 ) {
+ rc = len;
+ DBGC ( state, "DRBG %p could not get entropy input: %s\n",
+ state, strerror ( rc ) );
+ return rc;
+ }
+
+ /* 6. new_working_state = Reseed_algorithm ( working_state,
+ * entropy_input, additional_input ).
+ */
+ drbg_reseed_algorithm ( state, data, len, additional, additional_len );
+
+ /* 7. Replace the working_state in the internal state
+ * indicated by state_handle with the values of
+ * new_working_state obtained in step 6.
+ *
+ * (Nothing to do since the state has already been updated in-situ.)
+ */
+
+ /* 8. Return SUCCESS. */
+ return 0;
+}
+
+/**
+ * Generate pseudorandom bits using DRBG
+ *
+ * @v state Algorithm state
+ * @v additional Additional input
+ * @v additional_len Length of additional input
+ * @v prediction_resist Prediction resistance is required
+ * @v data Output buffer
+ * @v len Length of output buffer
+ * @ret rc Return status code
+ *
+ * This is the Generate_function defined in ANS X9.82 Part 3-2007
+ * Section 9.4 (NIST SP 800-90 Section 9.3).
+ *
+ * Requests must be for an integral number of bytes. Only a single
+ * security strength is supported. Prediction resistance is supported
+ * if requested.
+ */
+int drbg_generate ( struct drbg_state *state, const void *additional,
+ size_t additional_len, int prediction_resist,
+ void *data, size_t len ) {
+ int rc;
+
+ DBGC ( state, "DRBG %p generate\n", state );
+
+ /* Sanity checks */
+ assert ( state != NULL );
+ assert ( data != NULL );
+
+ /* 1. Using state_handle, obtain the current internal state
+ * for the instantiation. If state_handle indicates an
+ * invalid or empty internal state, then return an ERROR_FLAG.
+ *
+ * (Almost nothing to do since the memory holding the internal
+ * state was passed in by the caller.)
+ */
+ if ( ! state->valid ) {
+ DBGC ( state, "DRBG %p not valid\n", state );
+ return -EINVAL;
+ }
+
+ /* 2. If requested_number_of_bits >
+ * max_number_of_bits_per_request, then return an
+ * ERROR_FLAG.
+ */
+ if ( len > DRBG_MAX_GENERATED_LEN_BYTES ) {
+ DBGC ( state, "DRBG %p request too long (%zd bytes)\n",
+ state, len );
+ return -ERANGE;
+ }
+
+ /* 3. If requested_security_strength > the security_strength
+ * indicated in the internal state, then return an
+ * ERROR_FLAG.
+ *
+ * (Nothing to do since only a single security strength is
+ * supported.)
+ */
+
+ /* 4. If the length of the additional_input >
+ * max_additional_input_length, then return an ERROR_FLAG.
+ */
+ if ( additional_len > DRBG_MAX_ADDITIONAL_LEN_BYTES ) {
+ DBGC ( state, "DRBG %p additional input too long (%zd bytes)\n",
+ state, additional_len );
+ return -ERANGE;
+ }
+
+ /* 5. If prediction_resistance_request is set, and
+ * prediction_resistance_flag is not set, then return an
+ * ERROR_FLAG.
+ *
+ * (Nothing to do since prediction resistance is always
+ * supported.)
+ */
+
+ /* 6. Clear the reseed_required_flag. */
+ state->reseed_required = 0;
+
+ step_7:
+ /* 7. If reseed_required_flag is set, or if
+ * prediction_resistance_request is set, then
+ */
+ if ( state->reseed_required || prediction_resist ) {
+
+ /* 7.1 status = Reseed_function ( state_handle,
+ * prediction_resistance_request,
+ * additional_input )
+ * 7.2 If status indicates an ERROR, then return
+ * status.
+ */
+ if ( ( rc = drbg_reseed ( state, additional,
+ additional_len ) ) != 0 ) {
+ DBGC ( state, "DRBG %p could not reseed: %s\n",
+ state, strerror ( rc ) );
+ return rc;
+ }
+
+ /* 7.3 Using state_handle, obtain the new internal
+ * state.
+ *
+ * (Nothing to do since the internal state has been
+ * updated in-situ.)
+ */
+
+ /* 7.4 additional_input = the Null string. */
+ additional = NULL;
+ additional_len = 0;
+
+ /* 7.5 Clear the reseed_required_flag. */
+ state->reseed_required = 0;
+ }
+
+ /* 8. ( status, pseudorandom_bits, new_working_state ) =
+ * Generate_algorithm ( working_state,
+ * requested_number_of_bits, additional_input ).
+ */
+ rc = drbg_generate_algorithm ( state, additional, additional_len,
+ data, len );
+
+ /* 9. If status indicates that a reseed is required before
+ * the requested bits can be generated, then
+ */
+ if ( rc != 0 ) {
+
+ /* 9.1 Set the reseed_required_flag. */
+ state->reseed_required = 1;
+
+ /* 9.2 If the prediction_resistance_flag is set, then
+ * set the prediction_resistance_request
+ * indication.
+ */
+ prediction_resist = 1;
+
+ /* 9.3 Go to step 7. */
+ goto step_7;
+ }
+
+ /* 10. Replace the old working_state in the internal state
+ * indicated by state_handle with the values of
+ * new_working_state.
+ *
+ * (Nothing to do since the working state has already been
+ * updated in-situ.)
+ */
+
+ /* 11. Return SUCCESS and pseudorandom_bits. */
+ return 0;
+}
+
+/**
+ * Uninstantiate DRBG
+ *
+ * @v state Algorithm state
+ *
+ * This is the Uninstantiate_function defined in ANS X9.82 Part 3-2007
+ * Section 9.5 (NIST SP 800-90 Section 9.4).
+ */
+void drbg_uninstantiate ( struct drbg_state *state ) {
+
+ DBGC ( state, "DRBG %p uninstantiate\n", state );
+
+ /* Sanity checks */
+ assert ( state != NULL );
+
+ /* 1. If state_handle indicates an invalid state, then return
+ * an ERROR_FLAG.
+ *
+ * (Nothing to do since the memory holding the internal state
+ * was passed in by the caller.)
+ */
+
+ /* 2. Erase the contents of the internal state indicated by
+ * state_handle.
+ */
+ memset ( state, 0, sizeof ( *state ) );
+
+ /* 3. Return SUCCESS. */
+}
diff --git a/qemu/roms/ipxe/src/crypto/entropy.c b/qemu/roms/ipxe/src/crypto/entropy.c
new file mode 100644
index 000000000..c7045840e
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/entropy.c
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Entropy source
+ *
+ * This algorithm is designed to comply with ANS X9.82 Part 4 (April
+ * 2011 Draft) Section 13.3. This standard is unfortunately not
+ * freely available.
+ */
+
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/crypto.h>
+#include <ipxe/hash_df.h>
+#include <ipxe/entropy.h>
+
+/* Disambiguate the various error causes */
+#define EPIPE_REPETITION_COUNT_TEST \
+ __einfo_error ( EINFO_EPIPE_REPETITION_COUNT_TEST )
+#define EINFO_EPIPE_REPETITION_COUNT_TEST \
+ __einfo_uniqify ( EINFO_EPIPE, 0x01, "Repetition count test failed" )
+#define EPIPE_ADAPTIVE_PROPORTION_TEST \
+ __einfo_error ( EINFO_EPIPE_ADAPTIVE_PROPORTION_TEST )
+#define EINFO_EPIPE_ADAPTIVE_PROPORTION_TEST \
+ __einfo_uniqify ( EINFO_EPIPE, 0x02, "Adaptive proportion test failed" )
+
+/**
+ * Calculate cutoff value for the repetition count test
+ *
+ * @ret cutoff Cutoff value
+ *
+ * This is the cutoff value for the Repetition Count Test defined in
+ * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.2.
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+repetition_count_cutoff ( void ) {
+ double max_repetitions;
+ unsigned int cutoff;
+
+ /* The cutoff formula for the repetition test is:
+ *
+ * C = ( 1 + ( -log2(W) / H_min ) )
+ *
+ * where W is set at 2^(-30) (in ANS X9.82 Part 2 (October
+ * 2011 Draft) Section 8.5.2.1.3.1).
+ */
+ max_repetitions = ( 1 + ( 30 / min_entropy_per_sample() ) );
+
+ /* Round up to a whole number of repetitions. We don't have
+ * the ceil() function available, so do the rounding by hand.
+ */
+ cutoff = max_repetitions;
+ if ( cutoff < max_repetitions )
+ cutoff++;
+ linker_assert ( ( cutoff >= max_repetitions ), rounding_error );
+
+ /* Floating-point operations are not allowed in iPXE since we
+ * never set up a suitable environment. Abort the build
+ * unless the calculated number of repetitions is a
+ * compile-time constant.
+ */
+ linker_assert ( __builtin_constant_p ( cutoff ),
+ repetition_count_cutoff_not_constant );
+
+ return cutoff;
+}
+
+/**
+ * Perform repetition count test
+ *
+ * @v sample Noise sample
+ * @ret rc Return status code
+ *
+ * This is the Repetition Count Test defined in ANS X9.82 Part 2
+ * (October 2011 Draft) Section 8.5.2.1.2.
+ */
+static int repetition_count_test ( noise_sample_t sample ) {
+ static noise_sample_t most_recent_sample;
+ static unsigned int repetition_count = 0;
+
+ /* A = the most recently seen sample value
+ * B = the number of times that value A has been seen in a row
+ * C = the cutoff value above which the repetition test should fail
+ */
+
+ /* 1. For each new sample processed:
+ *
+ * (Note that the test for "repetition_count > 0" ensures that
+ * the initial value of most_recent_sample is treated as being
+ * undefined.)
+ */
+ if ( ( sample == most_recent_sample ) && ( repetition_count > 0 ) ) {
+
+ /* a) If the new sample = A, then B is incremented by one. */
+ repetition_count++;
+
+ /* i. If B >= C, then an error condition is raised
+ * due to a failure of the test
+ */
+ if ( repetition_count >= repetition_count_cutoff() )
+ return -EPIPE_REPETITION_COUNT_TEST;
+
+ } else {
+
+ /* b) Else:
+ * i. A = new sample
+ */
+ most_recent_sample = sample;
+
+ /* ii. B = 1 */
+ repetition_count = 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Window size for the adaptive proportion test
+ *
+ * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.1 allows
+ * five possible window sizes: 16, 64, 256, 4096 and 65536.
+ *
+ * We expect to generate relatively few (<256) entropy samples during
+ * a typical iPXE run; the use of a large window size would mean that
+ * the test would never complete a single cycle. We use a window size
+ * of 64, which is the smallest window size that permits values of
+ * H_min down to one bit per sample.
+ */
+#define ADAPTIVE_PROPORTION_WINDOW_SIZE 64
+
+/**
+ * Combine adaptive proportion test window size and min-entropy
+ *
+ * @v n N (window size)
+ * @v h H (min-entropy)
+ * @ret n_h (N,H) combined value
+ */
+#define APC_N_H( n, h ) ( ( (n) << 8 ) | (h) )
+
+/**
+ * Define a row of the adaptive proportion cutoff table
+ *
+ * @v h H (min-entropy)
+ * @v c16 Cutoff for N=16
+ * @v c64 Cutoff for N=64
+ * @v c256 Cutoff for N=256
+ * @v c4096 Cutoff for N=4096
+ * @v c65536 Cutoff for N=65536
+ */
+#define APC_TABLE_ROW( h, c16, c64, c256, c4096, c65536) \
+ case APC_N_H ( 16, h ) : return c16; \
+ case APC_N_H ( 64, h ) : return c64; \
+ case APC_N_H ( 256, h ) : return c256; \
+ case APC_N_H ( 4096, h ) : return c4096; \
+ case APC_N_H ( 65536, h ) : return c65536;
+
+/** Value used to represent "N/A" in adaptive proportion cutoff table */
+#define APC_NA 0
+
+/**
+ * Look up value in adaptive proportion test cutoff table
+ *
+ * @v n N (window size)
+ * @v h H (min-entropy)
+ * @ret cutoff Cutoff
+ *
+ * This is the table of cutoff values defined in ANS X9.82 Part 2
+ * (October 2011 Draft) Section 8.5.2.1.3.1.2.
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+adaptive_proportion_cutoff_lookup ( unsigned int n, unsigned int h ) {
+ switch ( APC_N_H ( n, h ) ) {
+ APC_TABLE_ROW ( 1, APC_NA, 51, 168, 2240, 33537 );
+ APC_TABLE_ROW ( 2, APC_NA, 35, 100, 1193, 17053 );
+ APC_TABLE_ROW ( 3, 10, 24, 61, 643, 8705 );
+ APC_TABLE_ROW ( 4, 8, 16, 38, 354, 4473 );
+ APC_TABLE_ROW ( 5, 6, 12, 25, 200, 2321 );
+ APC_TABLE_ROW ( 6, 5, 9, 17, 117, 1220 );
+ APC_TABLE_ROW ( 7, 4, 7, 15, 71, 653 );
+ APC_TABLE_ROW ( 8, 4, 5, 9, 45, 358 );
+ APC_TABLE_ROW ( 9, 3, 4, 7, 30, 202 );
+ APC_TABLE_ROW ( 10, 3, 4, 5, 21, 118 );
+ APC_TABLE_ROW ( 11, 2, 3, 4, 15, 71 );
+ APC_TABLE_ROW ( 12, 2, 3, 4, 11, 45 );
+ APC_TABLE_ROW ( 13, 2, 2, 3, 9, 30 );
+ APC_TABLE_ROW ( 14, 2, 2, 3, 7, 21 );
+ APC_TABLE_ROW ( 15, 1, 2, 2, 6, 15 );
+ APC_TABLE_ROW ( 16, 1, 2, 2, 5, 11 );
+ APC_TABLE_ROW ( 17, 1, 1, 2, 4, 9 );
+ APC_TABLE_ROW ( 18, 1, 1, 2, 4, 7 );
+ APC_TABLE_ROW ( 19, 1, 1, 1, 3, 6 );
+ APC_TABLE_ROW ( 20, 1, 1, 1, 3, 5 );
+ default:
+ return APC_NA;
+ }
+}
+
+/**
+ * Calculate cutoff value for the adaptive proportion test
+ *
+ * @ret cutoff Cutoff value
+ *
+ * This is the cutoff value for the Adaptive Proportion Test defined
+ * in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.1.2.
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+adaptive_proportion_cutoff ( void ) {
+ unsigned int h;
+ unsigned int n;
+ unsigned int cutoff;
+
+ /* Look up cutoff value in cutoff table */
+ n = ADAPTIVE_PROPORTION_WINDOW_SIZE;
+ h = min_entropy_per_sample();
+ cutoff = adaptive_proportion_cutoff_lookup ( n, h );
+
+ /* Fail unless cutoff value is a build-time constant */
+ linker_assert ( __builtin_constant_p ( cutoff ),
+ adaptive_proportion_cutoff_not_constant );
+
+ /* Fail if cutoff value is N/A */
+ linker_assert ( ( cutoff != APC_NA ),
+ adaptive_proportion_cutoff_not_applicable );
+
+ return cutoff;
+}
+
+/**
+ * Perform adaptive proportion test
+ *
+ * @v sample Noise sample
+ * @ret rc Return status code
+ *
+ * This is the Adaptive Proportion Test for the Most Common Value
+ * defined in ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.3.
+ */
+static int adaptive_proportion_test ( noise_sample_t sample ) {
+ static noise_sample_t current_counted_sample;
+ static unsigned int sample_count = ADAPTIVE_PROPORTION_WINDOW_SIZE;
+ static unsigned int repetition_count;
+
+ /* A = the sample value currently being counted
+ * B = the number of samples examined in this run of the test so far
+ * N = the total number of samples that must be observed in
+ * one run of the test, also known as the "window size" of
+ * the test
+ * B = the current number of times that S (sic) has been seen
+ * in the W (sic) samples examined so far
+ * C = the cutoff value above which the repetition test should fail
+ * W = the probability of a false positive: 2^-30
+ */
+
+ /* 1. The entropy source draws the current sample from the
+ * noise source.
+ *
+ * (Nothing to do; we already have the current sample.)
+ */
+
+ /* 2. If S = N, then a new run of the test begins: */
+ if ( sample_count == ADAPTIVE_PROPORTION_WINDOW_SIZE ) {
+
+ /* a. A = the current sample */
+ current_counted_sample = sample;
+
+ /* b. S = 0 */
+ sample_count = 0;
+
+ /* c. B = 0 */
+ repetition_count = 0;
+
+ } else {
+
+ /* Else: (the test is already running)
+ * a. S = S + 1
+ */
+ sample_count++;
+
+ /* b. If A = the current sample, then: */
+ if ( sample == current_counted_sample ) {
+
+ /* i. B = B + 1 */
+ repetition_count++;
+
+ /* ii. If S (sic) > C then raise an error
+ * condition, because the test has
+ * detected a failure
+ */
+ if ( repetition_count > adaptive_proportion_cutoff() )
+ return -EPIPE_ADAPTIVE_PROPORTION_TEST;
+
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Get entropy sample
+ *
+ * @ret entropy Entropy sample
+ * @ret rc Return status code
+ *
+ * This is the GetEntropy function defined in ANS X9.82 Part 2
+ * (October 2011 Draft) Section 6.5.1.
+ */
+static int get_entropy ( entropy_sample_t *entropy ) {
+ static int rc = 0;
+ noise_sample_t noise;
+
+ /* Any failure is permanent */
+ if ( rc != 0 )
+ return rc;
+
+ /* Get noise sample */
+ if ( ( rc = get_noise ( &noise ) ) != 0 )
+ return rc;
+
+ /* Perform Repetition Count Test and Adaptive Proportion Test
+ * as mandated by ANS X9.82 Part 2 (October 2011 Draft)
+ * Section 8.5.2.1.1.
+ */
+ if ( ( rc = repetition_count_test ( noise ) ) != 0 )
+ return rc;
+ if ( ( rc = adaptive_proportion_test ( noise ) ) != 0 )
+ return rc;
+
+ /* We do not use any optional conditioning component */
+ *entropy = noise;
+
+ return 0;
+}
+
+/**
+ * Calculate number of samples required for startup tests
+ *
+ * @ret num_samples Number of samples required
+ *
+ * ANS X9.82 Part 2 (October 2011 Draft) Section 8.5.2.1.5 requires
+ * that at least one full cycle of the continuous tests must be
+ * performed at start-up.
+ */
+static inline __attribute__ (( always_inline )) unsigned int
+startup_test_count ( void ) {
+ unsigned int num_samples;
+
+ /* At least max(N,C) samples shall be generated by the noise
+ * source for start-up testing.
+ */
+ num_samples = repetition_count_cutoff();
+ if ( num_samples < adaptive_proportion_cutoff() )
+ num_samples = adaptive_proportion_cutoff();
+ linker_assert ( __builtin_constant_p ( num_samples ),
+ startup_test_count_not_constant );
+
+ return num_samples;
+}
+
+/**
+ * Create next nonce value
+ *
+ * @ret nonce Nonce
+ *
+ * This is the MakeNextNonce function defined in ANS X9.82 Part 4
+ * (April 2011 Draft) Section 13.3.4.2.
+ */
+static uint32_t make_next_nonce ( void ) {
+ static uint32_t nonce;
+
+ /* The simplest implementation of a nonce uses a large counter */
+ nonce++;
+
+ return nonce;
+}
+
+/**
+ * Obtain entropy input temporary buffer
+ *
+ * @v num_samples Number of entropy samples
+ * @v tmp Temporary buffer
+ * @v tmp_len Length of temporary buffer
+ * @ret rc Return status code
+ *
+ * This is (part of) the implementation of the Get_entropy_input
+ * function (using an entropy source as the source of entropy input
+ * and condensing each entropy source output after each GetEntropy
+ * call) as defined in ANS X9.82 Part 4 (April 2011 Draft) Section
+ * 13.3.4.2.
+ *
+ * To minimise code size, the number of samples required is calculated
+ * at compilation time.
+ */
+int get_entropy_input_tmp ( unsigned int num_samples, uint8_t *tmp,
+ size_t tmp_len ) {
+ static unsigned int startup_tested = 0;
+ struct {
+ uint32_t nonce;
+ entropy_sample_t sample;
+ } __attribute__ (( packed )) data;;
+ uint8_t df_buf[tmp_len];
+ unsigned int i;
+ int rc;
+
+ /* Enable entropy gathering */
+ if ( ( rc = entropy_enable() ) != 0 )
+ return rc;
+
+ /* Perform mandatory startup tests, if not yet performed */
+ for ( ; startup_tested < startup_test_count() ; startup_tested++ ) {
+ if ( ( rc = get_entropy ( &data.sample ) ) != 0 )
+ goto err_get_entropy;
+ }
+
+ /* 3. entropy_total = 0
+ *
+ * (Nothing to do; the number of entropy samples required has
+ * already been precalculated.)
+ */
+
+ /* 4. tmp = a fixed n-bit value, such as 0^n */
+ memset ( tmp, 0, tmp_len );
+
+ /* 5. While ( entropy_total < min_entropy ) */
+ while ( num_samples-- ) {
+ /* 5.1. ( status, entropy_bitstring, assessed_entropy )
+ * = GetEntropy()
+ * 5.2. If status indicates an error, return ( status, Null )
+ */
+ if ( ( rc = get_entropy ( &data.sample ) ) != 0 )
+ goto err_get_entropy;
+
+ /* 5.3. nonce = MakeNextNonce() */
+ data.nonce = make_next_nonce();
+
+ /* 5.4. tmp = tmp XOR
+ * df ( ( nonce || entropy_bitstring ), n )
+ */
+ hash_df ( &entropy_hash_df_algorithm, &data, sizeof ( data ),
+ df_buf, sizeof ( df_buf ) );
+ for ( i = 0 ; i < tmp_len ; i++ )
+ tmp[i] ^= df_buf[i];
+
+ /* 5.5. entropy_total = entropy_total + assessed_entropy
+ *
+ * (Nothing to do; the number of entropy samples
+ * required has already been precalculated.)
+ */
+ }
+
+ /* Disable entropy gathering */
+ entropy_disable();
+
+ return 0;
+
+ err_get_entropy:
+ entropy_disable();
+ return rc;
+}
diff --git a/qemu/roms/ipxe/src/crypto/hash_df.c b/qemu/roms/ipxe/src/crypto/hash_df.c
new file mode 100644
index 000000000..adf1d87e4
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/hash_df.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Hash-based derivation function (Hash_df)
+ *
+ * This algorithm is designed to comply with ANS X9.82 Part 3-2007
+ * Section 10.5.2. This standard is not freely available, but most of
+ * the text appears to be shared with NIST SP 800-90, which can be
+ * downloaded from
+ *
+ * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
+ *
+ * Where possible, references are given to both documents. In the
+ * case of any disagreement, ANS X9.82 takes priority over NIST SP
+ * 800-90. (In particular, note that some algorithms that are
+ * Approved by NIST SP 800-90 are not Approved by ANS X9.82.)
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <byteswap.h>
+#include <ipxe/crypto.h>
+#include <ipxe/hash_df.h>
+
+/**
+ * Distribute entropy throughout a buffer
+ *
+ * @v hash Underlying hash algorithm
+ * @v input Input data
+ * @v input_len Length of input data, in bytes
+ * @v output Output buffer
+ * @v output_len Length of output buffer, in bytes
+ *
+ * This is the Hash_df function defined in ANS X9.82 Part 3-2007
+ * Section 10.5.2 (NIST SP 800-90 Section 10.4.1).
+ *
+ * The number of bits requested is implicit in the length of the
+ * output buffer. Requests must be for an integral number of bytes.
+ *
+ * The output buffer is filled incrementally with each iteration of
+ * the central loop, rather than constructing an overall "temp" and
+ * then taking the leftmost(no_of_bits_to_return) bits.
+ *
+ * There is no way for the Hash_df function to fail. The returned
+ * status SUCCESS is implicit.
+ */
+void hash_df ( struct digest_algorithm *hash, const void *input,
+ size_t input_len, void *output, size_t output_len ) {
+ uint8_t context[hash->ctxsize];
+ uint8_t digest[hash->digestsize];
+ size_t frag_len;
+ struct {
+ uint8_t pad[3];
+ uint8_t counter;
+ uint32_t no_of_bits_to_return;
+ } __attribute__ (( packed )) prefix;
+ void *temp;
+ size_t remaining;
+
+ DBGC ( &hash_df, "HASH_DF input:\n" );
+ DBGC_HDA ( &hash_df, 0, input, input_len );
+
+ /* Sanity checks */
+ assert ( input != NULL );
+ assert ( output != NULL );
+
+ /* 1. temp = the Null string
+ * 2. len = ceil ( no_of_bits_to_return / outlen )
+ *
+ * (Nothing to do. We fill the output buffer incrementally,
+ * rather than constructing the complete "temp" in-memory.
+ * "len" is implicit in the number of iterations required to
+ * fill the output buffer, and so is not calculated
+ * explicitly.)
+ */
+
+ /* 3. counter = an 8-bit binary value representing the integer "1" */
+ prefix.counter = 1;
+
+ /* 4. For i = 1 to len do */
+ for ( temp = output, remaining = output_len ; remaining > 0 ; ) {
+
+ /* Comment: in step 5.1 (sic), no_of_bits_to_return is
+ * used as a 32-bit string.
+ *
+ * 4.1 temp = temp || Hash ( counter || no_of_bits_to_return
+ * || input_string )
+ */
+ prefix.no_of_bits_to_return = htonl ( output_len * 8 );
+ digest_init ( hash, context );
+ digest_update ( hash, context, &prefix.counter,
+ ( sizeof ( prefix ) -
+ offsetof ( typeof ( prefix ), counter ) ) );
+ digest_update ( hash, context, input, input_len );
+ digest_final ( hash, context, digest );
+
+ /* 4.2 counter = counter + 1 */
+ prefix.counter++;
+
+ /* 5. requested_bits = Leftmost ( no_of_bits_to_return )
+ * of temp
+ *
+ * (We fill the output buffer incrementally.)
+ */
+ frag_len = sizeof ( digest );
+ if ( frag_len > remaining )
+ frag_len = remaining;
+ memcpy ( temp, digest, frag_len );
+ temp += frag_len;
+ remaining -= frag_len;
+ }
+
+ /* 6. Return SUCCESS and requested_bits */
+ DBGC ( &hash_df, "HASH_DF output:\n" );
+ DBGC_HDA ( &hash_df, 0, output, output_len );
+ return;
+}
diff --git a/qemu/roms/ipxe/src/crypto/hmac.c b/qemu/roms/ipxe/src/crypto/hmac.c
new file mode 100644
index 000000000..e9459198c
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/hmac.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/**
+ * @file
+ *
+ * Keyed-Hashing for Message Authentication
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <ipxe/crypto.h>
+#include <ipxe/hmac.h>
+
+/**
+ * Reduce HMAC key length
+ *
+ * @v digest Digest algorithm to use
+ * @v digest_ctx Digest context
+ * @v key Key
+ * @v key_len Length of key
+ */
+static void hmac_reduce_key ( struct digest_algorithm *digest,
+ void *key, size_t *key_len ) {
+ uint8_t digest_ctx[digest->ctxsize];
+
+ digest_init ( digest, digest_ctx );
+ digest_update ( digest, digest_ctx, key, *key_len );
+ digest_final ( digest, digest_ctx, key );
+ *key_len = digest->digestsize;
+}
+
+/**
+ * Initialise HMAC
+ *
+ * @v digest Digest algorithm to use
+ * @v digest_ctx Digest context
+ * @v key Key
+ * @v key_len Length of key
+ *
+ * The length of the key should be less than the block size of the
+ * digest algorithm being used. (If the key length is greater, it
+ * will be replaced with its own digest, and key_len will be updated
+ * accordingly).
+ */
+void hmac_init ( struct digest_algorithm *digest, void *digest_ctx,
+ void *key, size_t *key_len ) {
+ unsigned char k_ipad[digest->blocksize];
+ unsigned int i;
+
+ /* Reduce key if necessary */
+ if ( *key_len > sizeof ( k_ipad ) )
+ hmac_reduce_key ( digest, key, key_len );
+
+ /* Construct input pad */
+ memset ( k_ipad, 0, sizeof ( k_ipad ) );
+ memcpy ( k_ipad, key, *key_len );
+ for ( i = 0 ; i < sizeof ( k_ipad ) ; i++ ) {
+ k_ipad[i] ^= 0x36;
+ }
+
+ /* Start inner hash */
+ digest_init ( digest, digest_ctx );
+ digest_update ( digest, digest_ctx, k_ipad, sizeof ( k_ipad ) );
+}
+
+/**
+ * Finalise HMAC
+ *
+ * @v digest Digest algorithm to use
+ * @v digest_ctx Digest context
+ * @v key Key
+ * @v key_len Length of key
+ * @v hmac HMAC digest to fill in
+ *
+ * The length of the key should be less than the block size of the
+ * digest algorithm being used. (If the key length is greater, it
+ * will be replaced with its own digest, and key_len will be updated
+ * accordingly).
+ */
+void hmac_final ( struct digest_algorithm *digest, void *digest_ctx,
+ void *key, size_t *key_len, void *hmac ) {
+ unsigned char k_opad[digest->blocksize];
+ unsigned int i;
+
+ /* Reduce key if necessary */
+ if ( *key_len > sizeof ( k_opad ) )
+ hmac_reduce_key ( digest, key, key_len );
+
+ /* Construct output pad */
+ memset ( k_opad, 0, sizeof ( k_opad ) );
+ memcpy ( k_opad, key, *key_len );
+ for ( i = 0 ; i < sizeof ( k_opad ) ; i++ ) {
+ k_opad[i] ^= 0x5c;
+ }
+
+ /* Finish inner hash */
+ digest_final ( digest, digest_ctx, hmac );
+
+ /* Perform outer hash */
+ digest_init ( digest, digest_ctx );
+ digest_update ( digest, digest_ctx, k_opad, sizeof ( k_opad ) );
+ digest_update ( digest, digest_ctx, hmac, digest->digestsize );
+ digest_final ( digest, digest_ctx, hmac );
+}
diff --git a/qemu/roms/ipxe/src/crypto/hmac_drbg.c b/qemu/roms/ipxe/src/crypto/hmac_drbg.c
new file mode 100644
index 000000000..1e5f732e2
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/hmac_drbg.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * HMAC_DRBG algorithm
+ *
+ * This algorithm is designed to comply with ANS X9.82 Part 3-2007
+ * Section 10.2.2.2. This standard is not freely available, but most
+ * of the text appears to be shared with NIST SP 800-90, which can be
+ * downloaded from
+ *
+ * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
+ *
+ * Where possible, references are given to both documents. In the
+ * case of any disagreement, ANS X9.82 takes priority over NIST SP
+ * 800-90. (In particular, note that some algorithms that are
+ * Approved by NIST SP 800-90 are not Approved by ANS X9.82.)
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/crypto.h>
+#include <ipxe/hmac.h>
+#include <ipxe/hmac_drbg.h>
+
+/**
+ * Update the HMAC_DRBG key
+ *
+ * @v hash Underlying hash algorithm
+ * @v state HMAC_DRBG internal state
+ * @v data Provided data
+ * @v len Length of provided data
+ * @v single Single byte used in concatenation
+ *
+ * This function carries out the operation
+ *
+ * K = HMAC ( K, V || single || provided_data )
+ *
+ * as used by hmac_drbg_update()
+ */
+static void hmac_drbg_update_key ( struct digest_algorithm *hash,
+ struct hmac_drbg_state *state,
+ const void *data, size_t len,
+ const uint8_t single ) {
+ uint8_t context[ hash->ctxsize ];
+ size_t out_len = hash->digestsize;
+
+ DBGC ( state, "HMAC_DRBG_%s %p provided data :\n", hash->name, state );
+ DBGC_HDA ( state, 0, data, len );
+
+ /* Sanity checks */
+ assert ( hash != NULL );
+ assert ( state != NULL );
+ assert ( ( data != NULL ) || ( len == 0 ) );
+ assert ( ( single == 0x00 ) || ( single == 0x01 ) );
+
+ /* K = HMAC ( K, V || single || provided_data ) */
+ hmac_init ( hash, context, state->key, &out_len );
+ assert ( out_len == hash->digestsize );
+ hmac_update ( hash, context, state->value, out_len );
+ hmac_update ( hash, context, &single, sizeof ( single ) );
+ hmac_update ( hash, context, data, len );
+ hmac_final ( hash, context, state->key, &out_len, state->key );
+ assert ( out_len == hash->digestsize );
+
+ DBGC ( state, "HMAC_DRBG_%s %p K = HMAC ( K, V || %#02x || "
+ "provided_data ) :\n", hash->name, state, single );
+ DBGC_HDA ( state, 0, state->key, out_len );
+}
+
+/**
+ * Update the HMAC_DRBG value
+ *
+ * @v hash Underlying hash algorithm
+ * @v state HMAC_DRBG internal state
+ * @v data Provided data
+ * @v len Length of provided data
+ * @v single Single byte used in concatenation
+ *
+ * This function carries out the operation
+ *
+ * V = HMAC ( K, V )
+ *
+ * as used by hmac_drbg_update() and hmac_drbg_generate()
+ */
+static void hmac_drbg_update_value ( struct digest_algorithm *hash,
+ struct hmac_drbg_state *state ) {
+ uint8_t context[ hash->ctxsize ];
+ size_t out_len = hash->digestsize;
+
+ /* Sanity checks */
+ assert ( hash != NULL );
+ assert ( state != NULL );
+
+ /* V = HMAC ( K, V ) */
+ hmac_init ( hash, context, state->key, &out_len );
+ assert ( out_len == hash->digestsize );
+ hmac_update ( hash, context, state->value, out_len );
+ hmac_final ( hash, context, state->key, &out_len, state->value );
+ assert ( out_len == hash->digestsize );
+
+ DBGC ( state, "HMAC_DRBG_%s %p V = HMAC ( K, V ) :\n",
+ hash->name, state );
+ DBGC_HDA ( state, 0, state->value, out_len );
+}
+
+/**
+ * Update HMAC_DRBG internal state
+ *
+ * @v hash Underlying hash algorithm
+ * @v state HMAC_DRBG internal state
+ * @v data Provided data
+ * @v len Length of provided data
+ *
+ * This is the HMAC_DRBG_Update function defined in ANS X9.82 Part
+ * 3-2007 Section 10.2.2.2.2 (NIST SP 800-90 Section 10.1.2.2).
+ *
+ * The key and value are updated in-place within the HMAC_DRBG
+ * internal state.
+ */
+static void hmac_drbg_update ( struct digest_algorithm *hash,
+ struct hmac_drbg_state *state,
+ const void *data, size_t len ) {
+
+ DBGC ( state, "HMAC_DRBG_%s %p update\n", hash->name, state );
+
+ /* Sanity checks */
+ assert ( hash != NULL );
+ assert ( state != NULL );
+ assert ( ( data != NULL ) || ( len == 0 ) );
+
+ /* 1. K = HMAC ( K, V || 0x00 || provided_data ) */
+ hmac_drbg_update_key ( hash, state, data, len, 0x00 );
+
+ /* 2. V = HMAC ( K, V ) */
+ hmac_drbg_update_value ( hash, state );
+
+ /* 3. If ( provided_data = Null ), then return K and V */
+ if ( ! len )
+ return;
+
+ /* 4. K = HMAC ( K, V || 0x01 || provided_data ) */
+ hmac_drbg_update_key ( hash, state, data, len, 0x01 );
+
+ /* 5. V = HMAC ( K, V ) */
+ hmac_drbg_update_value ( hash, state );
+
+ /* 6. Return K and V */
+}
+
+/**
+ * Instantiate HMAC_DRBG
+ *
+ * @v hash Underlying hash algorithm
+ * @v state HMAC_DRBG internal state to be initialised
+ * @v entropy Entropy input
+ * @v entropy_len Length of entropy input
+ * @v personal Personalisation string
+ * @v personal_len Length of personalisation string
+ *
+ * This is the HMAC_DRBG_Instantiate_algorithm function defined in ANS
+ * X9.82 Part 3-2007 Section 10.2.2.2.3 (NIST SP 800-90 Section
+ * 10.1.2.3).
+ *
+ * The nonce must be included within the entropy input (i.e. the
+ * entropy input must contain at least 3/2 * security_strength bits of
+ * entropy, as per ANS X9.82 Part 3-2007 Section 8.4.2 (NIST SP 800-90
+ * Section 8.6.7).
+ *
+ * The key, value and reseed counter are updated in-place within the
+ * HMAC_DRBG internal state.
+ */
+void hmac_drbg_instantiate ( struct digest_algorithm *hash,
+ struct hmac_drbg_state *state,
+ const void *entropy, size_t entropy_len,
+ const void *personal, size_t personal_len ){
+ size_t out_len = hash->digestsize;
+
+ DBGC ( state, "HMAC_DRBG_%s %p instantiate\n", hash->name, state );
+
+ /* Sanity checks */
+ assert ( hash != NULL );
+ assert ( state != NULL );
+ assert ( entropy != NULL );
+ assert ( ( personal != NULL ) || ( personal_len == 0 ) );
+
+ /* 1. seed_material = entropy_input || nonce ||
+ * personalisation_string
+ */
+
+ /* 2. Key = 0x00 00..00 */
+ memset ( state->key, 0x00, out_len );
+
+ /* 3. V = 0x01 01...01 */
+ memset ( state->value, 0x01, out_len );
+
+ /* 4. ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V )
+ * 5. reseed_counter = 1
+ * 6. Return V, Key and reseed_counter as the
+ * initial_working_state
+ */
+ hmac_drbg_reseed ( hash, state, entropy, entropy_len,
+ personal, personal_len );
+}
+
+/**
+ * Reseed HMAC_DRBG
+ *
+ * @v hash Underlying hash algorithm
+ * @v state HMAC_DRBG internal state
+ * @v entropy Entropy input
+ * @v entropy_len Length of entropy input
+ * @v additional Additional input
+ * @v additional_len Length of additional input
+ *
+ * This is the HMAC_DRBG_Reseed_algorithm function defined in ANS X9.82
+ * Part 3-2007 Section 10.2.2.2.4 (NIST SP 800-90 Section 10.1.2.4).
+ *
+ * The key, value and reseed counter are updated in-place within the
+ * HMAC_DRBG internal state.
+ */
+void hmac_drbg_reseed ( struct digest_algorithm *hash,
+ struct hmac_drbg_state *state,
+ const void *entropy, size_t entropy_len,
+ const void *additional, size_t additional_len ) {
+ uint8_t seed_material[ entropy_len + additional_len ];
+
+ DBGC ( state, "HMAC_DRBG_%s %p (re)seed\n", hash->name, state );
+
+ /* Sanity checks */
+ assert ( hash != NULL );
+ assert ( state != NULL );
+ assert ( entropy != NULL );
+ assert ( ( additional != NULL ) || ( additional_len == 0 ) );
+
+ /* 1. seed_material = entropy_input || additional_input */
+ memcpy ( seed_material, entropy, entropy_len );
+ memcpy ( ( seed_material + entropy_len ), additional, additional_len );
+ DBGC ( state, "HMAC_DRBG_%s %p seed material :\n", hash->name, state );
+ DBGC_HDA ( state, 0, seed_material, sizeof ( seed_material ) );
+
+ /* 2. ( Key, V ) = HMAC_DBRG_Update ( seed_material, Key, V ) */
+ hmac_drbg_update ( hash, state, seed_material,
+ sizeof ( seed_material ) );
+
+ /* 3. reseed_counter = 1 */
+ state->reseed_counter = 1;
+
+ /* 4. Return V, Key and reseed_counter as the new_working_state */
+}
+
+/**
+ * Generate pseudorandom bits using HMAC_DRBG
+ *
+ * @v hash Underlying hash algorithm
+ * @v state HMAC_DRBG internal state
+ * @v additional Additional input
+ * @v additional_len Length of additional input
+ * @v data Output buffer
+ * @v len Length of output buffer
+ * @ret rc Return status code
+ *
+ * This is the HMAC_DRBG_Generate_algorithm function defined in ANS X9.82
+ * Part 3-2007 Section 10.2.2.2.5 (NIST SP 800-90 Section 10.1.2.5).
+ *
+ * Requests must be for an integral number of bytes.
+ *
+ * The key, value and reseed counter are updated in-place within the
+ * HMAC_DRBG internal state.
+ *
+ * Note that the only permitted error is "reseed required".
+ */
+int hmac_drbg_generate ( struct digest_algorithm *hash,
+ struct hmac_drbg_state *state,
+ const void *additional, size_t additional_len,
+ void *data, size_t len ) {
+ size_t out_len = hash->digestsize;
+ void *orig_data = data;
+ size_t orig_len = len;
+ size_t frag_len;
+
+ DBGC ( state, "HMAC_DRBG_%s %p generate\n", hash->name, state );
+
+ /* Sanity checks */
+ assert ( hash != NULL );
+ assert ( state != NULL );
+ assert ( data != NULL );
+ assert ( ( additional != NULL ) || ( additional_len == 0 ) );
+
+ /* 1. If reseed_counter > reseed_interval, then return an
+ * indication that a reseed is required
+ */
+ if ( state->reseed_counter > HMAC_DRBG_RESEED_INTERVAL ) {
+ DBGC ( state, "HMAC_DRBG_%s %p reseed interval exceeded\n",
+ hash->name, state );
+ return -ESTALE;
+ }
+
+ /* 2. If additional_input != Null, then
+ * ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V )
+ */
+ if ( additional_len )
+ hmac_drbg_update ( hash, state, additional, additional_len );
+
+ /* 3. temp = Null
+ * 4. While ( len ( temp ) < requested_number_of_bits ) do:
+ */
+ while ( len ) {
+
+ /* 4.1 V = HMAC ( Key, V ) */
+ hmac_drbg_update_value ( hash, state );
+
+ /* 4.2. temp = temp || V
+ * 5. returned_bits = Leftmost requested_number_of_bits
+ * of temp
+ */
+ frag_len = len;
+ if ( frag_len > out_len )
+ frag_len = out_len;
+ memcpy ( data, state->value, frag_len );
+ data += frag_len;
+ len -= frag_len;
+ }
+
+ /* 6. ( Key, V ) = HMAC_DRBG_Update ( additional_input, Key, V ) */
+ hmac_drbg_update ( hash, state, additional, additional_len );
+
+ /* 7. reseed_counter = reseed_counter + 1 */
+ state->reseed_counter++;
+
+ DBGC ( state, "HMAC_DRBG_%s %p generated :\n", hash->name, state );
+ DBGC_HDA ( state, 0, orig_data, orig_len );
+
+ /* 8. Return SUCCESS, returned_bits, and the new values of
+ * Key, V and reseed_counter as the new_working_state
+ */
+ return 0;
+}
diff --git a/qemu/roms/ipxe/src/crypto/md5.c b/qemu/roms/ipxe/src/crypto/md5.c
new file mode 100644
index 000000000..122c7d59e
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/md5.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * MD5 algorithm
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <assert.h>
+#include <ipxe/rotate.h>
+#include <ipxe/crypto.h>
+#include <ipxe/asn1.h>
+#include <ipxe/md5.h>
+
+/** MD5 variables */
+struct md5_variables {
+ /* This layout matches that of struct md5_digest_data,
+ * allowing for efficient endianness-conversion,
+ */
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ uint32_t w[16];
+} __attribute__ (( packed ));
+
+/** MD5 constants */
+static const uint32_t k[64] = {
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,
+ 0xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,
+ 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,
+ 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,
+ 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,
+ 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+};
+
+/** MD5 shift amounts */
+static const uint8_t r[64] = {
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
+ 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
+ 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+ 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
+};
+
+/**
+ * f(b,c,d) for steps 0 to 15
+ *
+ * @v v MD5 variables
+ * @ret f f(b,c,d)
+ */
+static uint32_t md5_f_0_15 ( struct md5_variables *v ) {
+ return ( v->d ^ ( v->b & ( v->c ^ v->d ) ) );
+}
+
+/**
+ * f(b,c,d) for steps 16 to 31
+ *
+ * @v v MD5 variables
+ * @ret f f(b,c,d)
+ */
+static uint32_t md5_f_16_31 ( struct md5_variables *v ) {
+ return ( v->c ^ ( v->d & ( v->b ^ v->c ) ) );
+}
+
+/**
+ * f(b,c,d) for steps 32 to 47
+ *
+ * @v v MD5 variables
+ * @ret f f(b,c,d)
+ */
+static uint32_t md5_f_32_47 ( struct md5_variables *v ) {
+ return ( v->b ^ v->c ^ v->d );
+}
+
+/**
+ * f(b,c,d) for steps 48 to 63
+ *
+ * @v v MD5 variables
+ * @ret f f(b,c,d)
+ */
+static uint32_t md5_f_48_63 ( struct md5_variables *v ) {
+ return ( v->c ^ ( v->b | (~v->d) ) );
+}
+
+/** An MD5 step function */
+struct md5_step {
+ /**
+ * Calculate f(b,c,d)
+ *
+ * @v v MD5 variables
+ * @ret f f(b,c,d)
+ */
+ uint32_t ( * f ) ( struct md5_variables *v );
+ /** Coefficient of i in g=ni+m */
+ uint8_t coefficient;
+ /** Constant term in g=ni+m */
+ uint8_t constant;
+};
+
+/** MD5 steps */
+static struct md5_step md5_steps[4] = {
+ /** 0 to 15 */
+ { .f = md5_f_0_15, .coefficient = 1, .constant = 0 },
+ /** 16 to 31 */
+ { .f = md5_f_16_31, .coefficient = 5, .constant = 1 },
+ /** 32 to 47 */
+ { .f = md5_f_32_47, .coefficient = 3, .constant = 5 },
+ /** 48 to 63 */
+ { .f = md5_f_48_63, .coefficient = 7, .constant = 0 },
+};
+
+/**
+ * Initialise MD5 algorithm
+ *
+ * @v ctx MD5 context
+ */
+static void md5_init ( void *ctx ) {
+ struct md5_context *context = ctx;
+
+ context->ddd.dd.digest.h[0] = cpu_to_le32 ( 0x67452301 );
+ context->ddd.dd.digest.h[1] = cpu_to_le32 ( 0xefcdab89 );
+ context->ddd.dd.digest.h[2] = cpu_to_le32 ( 0x98badcfe );
+ context->ddd.dd.digest.h[3] = cpu_to_le32 ( 0x10325476 );
+ context->len = 0;
+}
+
+/**
+ * Calculate MD5 digest of accumulated data
+ *
+ * @v context MD5 context
+ */
+static void md5_digest ( struct md5_context *context ) {
+ union {
+ union md5_digest_data_dwords ddd;
+ struct md5_variables v;
+ } u;
+ uint32_t *a = &u.v.a;
+ uint32_t *b = &u.v.b;
+ uint32_t *c = &u.v.c;
+ uint32_t *d = &u.v.d;
+ uint32_t *w = u.v.w;
+ uint32_t f;
+ uint32_t g;
+ uint32_t temp;
+ struct md5_step *step;
+ unsigned int i;
+
+ /* Sanity checks */
+ assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
+ linker_assert ( &u.ddd.dd.digest.h[0] == a, md5_bad_layout );
+ linker_assert ( &u.ddd.dd.digest.h[1] == b, md5_bad_layout );
+ linker_assert ( &u.ddd.dd.digest.h[2] == c, md5_bad_layout );
+ linker_assert ( &u.ddd.dd.digest.h[3] == d, md5_bad_layout );
+ linker_assert ( &u.ddd.dd.data.dword[0] == w, md5_bad_layout );
+
+ DBGC ( context, "MD5 digesting:\n" );
+ DBGC_HDA ( context, 0, &context->ddd.dd.digest,
+ sizeof ( context->ddd.dd.digest ) );
+ DBGC_HDA ( context, context->len, &context->ddd.dd.data,
+ sizeof ( context->ddd.dd.data ) );
+
+ /* Convert h[0..3] to host-endian, and initialise a, b, c, d,
+ * and w[0..15]
+ */
+ for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) /
+ sizeof ( u.ddd.dword[0] ) ) ; i++ ) {
+ le32_to_cpus ( &context->ddd.dword[i] );
+ u.ddd.dword[i] = context->ddd.dword[i];
+ }
+
+ /* Main loop */
+ for ( i = 0 ; i < 64 ; i++ ) {
+ step = &md5_steps[ i / 16 ];
+ f = step->f ( &u.v );
+ g = ( ( ( step->coefficient * i ) + step->constant ) % 16 );
+ temp = *d;
+ *d = *c;
+ *c = *b;
+ *b = ( *b + rol32 ( ( *a + f + k[i] + w[g] ), r[i] ) );
+ *a = temp;
+ DBGC2 ( context, "%2d : %08x %08x %08x %08x\n",
+ i, *a, *b, *c, *d );
+ }
+
+ /* Add chunk to hash and convert back to big-endian */
+ for ( i = 0 ; i < 4 ; i++ ) {
+ context->ddd.dd.digest.h[i] =
+ cpu_to_le32 ( context->ddd.dd.digest.h[i] +
+ u.ddd.dd.digest.h[i] );
+ }
+
+ DBGC ( context, "MD5 digested:\n" );
+ DBGC_HDA ( context, 0, &context->ddd.dd.digest,
+ sizeof ( context->ddd.dd.digest ) );
+}
+
+/**
+ * Accumulate data with MD5 algorithm
+ *
+ * @v ctx MD5 context
+ * @v data Data
+ * @v len Length of data
+ */
+static void md5_update ( void *ctx, const void *data, size_t len ) {
+ struct md5_context *context = ctx;
+ const uint8_t *byte = data;
+ size_t offset;
+
+ /* Accumulate data a byte at a time, performing the digest
+ * whenever we fill the data buffer
+ */
+ while ( len-- ) {
+ offset = ( context->len % sizeof ( context->ddd.dd.data ) );
+ context->ddd.dd.data.byte[offset] = *(byte++);
+ context->len++;
+ if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 )
+ md5_digest ( context );
+ }
+}
+
+/**
+ * Generate MD5 digest
+ *
+ * @v ctx MD5 context
+ * @v out Output buffer
+ */
+static void md5_final ( void *ctx, void *out ) {
+ struct md5_context *context = ctx;
+ uint64_t len_bits;
+ uint8_t pad;
+
+ /* Record length before pre-processing */
+ len_bits = cpu_to_le64 ( ( ( uint64_t ) context->len ) * 8 );
+
+ /* Pad with a single "1" bit followed by as many "0" bits as required */
+ pad = 0x80;
+ do {
+ md5_update ( ctx, &pad, sizeof ( pad ) );
+ pad = 0x00;
+ } while ( ( context->len % sizeof ( context->ddd.dd.data ) ) !=
+ offsetof ( typeof ( context->ddd.dd.data ), final.len ) );
+
+ /* Append length (in bits) */
+ md5_update ( ctx, &len_bits, sizeof ( len_bits ) );
+ assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
+
+ /* Copy out final digest */
+ memcpy ( out, &context->ddd.dd.digest,
+ sizeof ( context->ddd.dd.digest ) );
+}
+
+/** MD5 algorithm */
+struct digest_algorithm md5_algorithm = {
+ .name = "md5",
+ .ctxsize = sizeof ( struct md5_context ),
+ .blocksize = sizeof ( union md5_block ),
+ .digestsize = sizeof ( struct md5_digest ),
+ .init = md5_init,
+ .update = md5_update,
+ .final = md5_final,
+};
+
+/** "md5" object identifier */
+static uint8_t oid_md5[] = { ASN1_OID_MD5 };
+
+/** "md5" OID-identified algorithm */
+struct asn1_algorithm oid_md5_algorithm __asn1_algorithm = {
+ .name = "md5",
+ .digest = &md5_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_md5 ),
+};
diff --git a/qemu/roms/ipxe/src/crypto/null_entropy.c b/qemu/roms/ipxe/src/crypto/null_entropy.c
new file mode 100644
index 000000000..c56d5e76f
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/null_entropy.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Nonexistent entropy source
+ *
+ *
+ * This source provides no entropy and must NOT be used in a
+ * security-sensitive environment.
+ */
+
+#include <ipxe/entropy.h>
+
+PROVIDE_ENTROPY_INLINE ( null, min_entropy_per_sample );
+PROVIDE_ENTROPY_INLINE ( null, entropy_enable );
+PROVIDE_ENTROPY_INLINE ( null, entropy_disable );
+PROVIDE_ENTROPY_INLINE ( null, get_noise );
diff --git a/qemu/roms/ipxe/src/crypto/ocsp.c b/qemu/roms/ipxe/src/crypto/ocsp.c
new file mode 100644
index 000000000..66e47c57e
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/ocsp.c
@@ -0,0 +1,960 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/asn1.h>
+#include <ipxe/x509.h>
+#include <ipxe/sha1.h>
+#include <ipxe/base64.h>
+#include <ipxe/uri.h>
+#include <ipxe/ocsp.h>
+#include <config/crypto.h>
+
+/** @file
+ *
+ * Online Certificate Status Protocol
+ *
+ */
+
+/* Disambiguate the various error causes */
+#define EACCES_CERT_STATUS \
+ __einfo_error ( EINFO_EACCES_CERT_STATUS )
+#define EINFO_EACCES_CERT_STATUS \
+ __einfo_uniqify ( EINFO_EACCES, 0x01, \
+ "Certificate status not good" )
+#define EACCES_CERT_MISMATCH \
+ __einfo_error ( EINFO_EACCES_CERT_MISMATCH )
+#define EINFO_EACCES_CERT_MISMATCH \
+ __einfo_uniqify ( EINFO_EACCES, 0x02, \
+ "Certificate ID mismatch" )
+#define EACCES_NON_OCSP_SIGNING \
+ __einfo_error ( EINFO_EACCES_NON_OCSP_SIGNING )
+#define EINFO_EACCES_NON_OCSP_SIGNING \
+ __einfo_uniqify ( EINFO_EACCES, 0x03, \
+ "Not an OCSP signing certificate" )
+#define EACCES_STALE \
+ __einfo_error ( EINFO_EACCES_STALE )
+#define EINFO_EACCES_STALE \
+ __einfo_uniqify ( EINFO_EACCES, 0x04, \
+ "Stale (or premature) OCSP repsonse" )
+#define EACCES_NO_RESPONDER \
+ __einfo_error ( EINFO_EACCES_NO_RESPONDER )
+#define EINFO_EACCES_NO_RESPONDER \
+ __einfo_uniqify ( EINFO_EACCES, 0x05, \
+ "Missing OCSP responder certificate" )
+#define ENOTSUP_RESPONSE_TYPE \
+ __einfo_error ( EINFO_ENOTSUP_RESPONSE_TYPE )
+#define EINFO_ENOTSUP_RESPONSE_TYPE \
+ __einfo_uniqify ( EINFO_ENOTSUP, 0x01, \
+ "Unsupported OCSP response type" )
+#define ENOTSUP_RESPONDER_ID \
+ __einfo_error ( EINFO_ENOTSUP_RESPONDER_ID )
+#define EINFO_ENOTSUP_RESPONDER_ID \
+ __einfo_uniqify ( EINFO_ENOTSUP, 0x02, \
+ "Unsupported OCSP responder ID" )
+#define EPROTO_MALFORMED_REQUEST \
+ __einfo_error ( EINFO_EPROTO_MALFORMED_REQUEST )
+#define EINFO_EPROTO_MALFORMED_REQUEST \
+ __einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_MALFORMED_REQUEST, \
+ "Illegal confirmation request" )
+#define EPROTO_INTERNAL_ERROR \
+ __einfo_error ( EINFO_EPROTO_INTERNAL_ERROR )
+#define EINFO_EPROTO_INTERNAL_ERROR \
+ __einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_INTERNAL_ERROR, \
+ "Internal error in issuer" )
+#define EPROTO_TRY_LATER \
+ __einfo_error ( EINFO_EPROTO_TRY_LATER )
+#define EINFO_EPROTO_TRY_LATER \
+ __einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_TRY_LATER, \
+ "Try again later" )
+#define EPROTO_SIG_REQUIRED \
+ __einfo_error ( EINFO_EPROTO_SIG_REQUIRED )
+#define EINFO_EPROTO_SIG_REQUIRED \
+ __einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_SIG_REQUIRED, \
+ "Must sign the request" )
+#define EPROTO_UNAUTHORIZED \
+ __einfo_error ( EINFO_EPROTO_UNAUTHORIZED )
+#define EINFO_EPROTO_UNAUTHORIZED \
+ __einfo_uniqify ( EINFO_EPROTO, OCSP_STATUS_UNAUTHORIZED, \
+ "Request unauthorized" )
+#define EPROTO_STATUS( status ) \
+ EUNIQ ( EINFO_EPROTO, (status), EPROTO_MALFORMED_REQUEST, \
+ EPROTO_INTERNAL_ERROR, EPROTO_TRY_LATER, \
+ EPROTO_SIG_REQUIRED, EPROTO_UNAUTHORIZED )
+
+/** OCSP digest algorithm */
+#define ocsp_digest_algorithm sha1_algorithm
+
+/** OCSP digest algorithm identifier */
+static const uint8_t ocsp_algorithm_id[] =
+ { OCSP_ALGORITHM_IDENTIFIER ( ASN1_OID_SHA1 ) };
+
+/** OCSP basic response type */
+static const uint8_t oid_basic_response_type[] = { ASN1_OID_OCSP_BASIC };
+
+/** OCSP basic response type cursor */
+static struct asn1_cursor oid_basic_response_type_cursor =
+ ASN1_OID_CURSOR ( oid_basic_response_type );
+
+/**
+ * Free OCSP check
+ *
+ * @v refcnt Reference count
+ */
+static void ocsp_free ( struct refcnt *refcnt ) {
+ struct ocsp_check *ocsp =
+ container_of ( refcnt, struct ocsp_check, refcnt );
+
+ x509_put ( ocsp->cert );
+ x509_put ( ocsp->issuer );
+ free ( ocsp->uri_string );
+ free ( ocsp->request.builder.data );
+ free ( ocsp->response.data );
+ x509_put ( ocsp->response.signer );
+ free ( ocsp );
+}
+
+/**
+ * Build OCSP request
+ *
+ * @v ocsp OCSP check
+ * @ret rc Return status code
+ */
+static int ocsp_request ( struct ocsp_check *ocsp ) {
+ struct digest_algorithm *digest = &ocsp_digest_algorithm;
+ struct asn1_builder *builder = &ocsp->request.builder;
+ struct asn1_cursor *cert_id = &ocsp->request.cert_id;
+ uint8_t digest_ctx[digest->ctxsize];
+ uint8_t name_digest[digest->digestsize];
+ uint8_t pubkey_digest[digest->digestsize];
+ int rc;
+
+ /* Generate digests */
+ digest_init ( digest, digest_ctx );
+ digest_update ( digest, digest_ctx, ocsp->cert->issuer.raw.data,
+ ocsp->cert->issuer.raw.len );
+ digest_final ( digest, digest_ctx, name_digest );
+ digest_init ( digest, digest_ctx );
+ digest_update ( digest, digest_ctx,
+ ocsp->issuer->subject.public_key.raw_bits.data,
+ ocsp->issuer->subject.public_key.raw_bits.len );
+ digest_final ( digest, digest_ctx, pubkey_digest );
+
+ /* Construct request */
+ if ( ( rc = ( asn1_prepend_raw ( builder, ocsp->cert->serial.raw.data,
+ ocsp->cert->serial.raw.len ),
+ asn1_prepend ( builder, ASN1_OCTET_STRING,
+ pubkey_digest, sizeof ( pubkey_digest ) ),
+ asn1_prepend ( builder, ASN1_OCTET_STRING,
+ name_digest, sizeof ( name_digest ) ),
+ asn1_prepend ( builder, ASN1_SEQUENCE,
+ ocsp_algorithm_id,
+ sizeof ( ocsp_algorithm_id ) ),
+ asn1_wrap ( builder, ASN1_SEQUENCE ),
+ asn1_wrap ( builder, ASN1_SEQUENCE ),
+ asn1_wrap ( builder, ASN1_SEQUENCE ),
+ asn1_wrap ( builder, ASN1_SEQUENCE ),
+ asn1_wrap ( builder, ASN1_SEQUENCE ) ) ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" could not build request: %s\n",
+ ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( ocsp, "OCSP %p \"%s\" request is:\n",
+ ocsp, x509_name ( ocsp->cert ) );
+ DBGC2_HDA ( ocsp, 0, builder->data, builder->len );
+
+ /* Parse certificate ID for comparison with response */
+ cert_id->data = builder->data;
+ cert_id->len = builder->len;
+ if ( ( rc = ( asn1_enter ( cert_id, ASN1_SEQUENCE ),
+ asn1_enter ( cert_id, ASN1_SEQUENCE ),
+ asn1_enter ( cert_id, ASN1_SEQUENCE ),
+ asn1_enter ( cert_id, ASN1_SEQUENCE ) ) ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" could not locate certID: %s\n",
+ ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Build OCSP URI string
+ *
+ * @v ocsp OCSP check
+ * @ret rc Return status code
+ */
+static int ocsp_uri_string ( struct ocsp_check *ocsp ) {
+ struct x509_ocsp_responder *responder =
+ &ocsp->cert->extensions.auth_info.ocsp;
+ struct uri path_uri;
+ char *path_base64_string;
+ char *path_uri_string;
+ size_t path_len;
+ size_t len;
+ int rc;
+
+ /* Sanity check */
+ if ( ! responder->uri.len ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" has no OCSP URI\n",
+ ocsp, x509_name ( ocsp->cert ) );
+ rc = -ENOTTY;
+ goto err_no_uri;
+ }
+
+ /* Base64-encode the request as the URI path */
+ path_len = ( base64_encoded_len ( ocsp->request.builder.len )
+ + 1 /* NUL */ );
+ path_base64_string = malloc ( path_len );
+ if ( ! path_base64_string ) {
+ rc = -ENOMEM;
+ goto err_path_base64;
+ }
+ base64_encode ( ocsp->request.builder.data, ocsp->request.builder.len,
+ path_base64_string );
+
+ /* URI-encode the Base64-encoded request */
+ memset ( &path_uri, 0, sizeof ( path_uri ) );
+ path_uri.path = path_base64_string;
+ path_uri_string = format_uri_alloc ( &path_uri );
+ if ( ! path_uri_string ) {
+ rc = -ENOMEM;
+ goto err_path_uri;
+ }
+
+ /* Construct URI string */
+ len = ( responder->uri.len + strlen ( path_uri_string ) + 1 /* NUL */ );
+ ocsp->uri_string = zalloc ( len );
+ if ( ! ocsp->uri_string ) {
+ rc = -ENOMEM;
+ goto err_ocsp_uri;
+ }
+ memcpy ( ocsp->uri_string, responder->uri.data, responder->uri.len );
+ strcpy ( &ocsp->uri_string[responder->uri.len], path_uri_string );
+ DBGC2 ( ocsp, "OCSP %p \"%s\" URI is %s\n",
+ ocsp, x509_name ( ocsp->cert ), ocsp->uri_string );
+
+ /* Success */
+ rc = 0;
+
+ err_ocsp_uri:
+ free ( path_uri_string );
+ err_path_uri:
+ free ( path_base64_string );
+ err_path_base64:
+ err_no_uri:
+ return rc;
+}
+
+/**
+ * Create OCSP check
+ *
+ * @v cert Certificate to check
+ * @v issuer Issuing certificate
+ * @ret ocsp OCSP check
+ * @ret rc Return status code
+ */
+int ocsp_check ( struct x509_certificate *cert,
+ struct x509_certificate *issuer,
+ struct ocsp_check **ocsp ) {
+ int rc;
+
+ /* Sanity checks */
+ assert ( cert != NULL );
+ assert ( issuer != NULL );
+ assert ( issuer->valid );
+
+ /* Allocate and initialise check */
+ *ocsp = zalloc ( sizeof ( **ocsp ) );
+ if ( ! *ocsp ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+ ref_init ( &(*ocsp)->refcnt, ocsp_free );
+ (*ocsp)->cert = x509_get ( cert );
+ (*ocsp)->issuer = x509_get ( issuer );
+
+ /* Build request */
+ if ( ( rc = ocsp_request ( *ocsp ) ) != 0 )
+ goto err_request;
+
+ /* Build URI string */
+ if ( ( rc = ocsp_uri_string ( *ocsp ) ) != 0 )
+ goto err_uri_string;
+
+ return 0;
+
+ err_uri_string:
+ err_request:
+ ocsp_put ( *ocsp );
+ err_alloc:
+ *ocsp = NULL;
+ return rc;
+}
+
+/**
+ * Parse OCSP response status
+ *
+ * @v ocsp OCSP check
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int ocsp_parse_response_status ( struct ocsp_check *ocsp,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ uint8_t status;
+ int rc;
+
+ /* Enter responseStatus */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ if ( ( rc = asn1_enter ( &cursor, ASN1_ENUMERATED ) ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" could not locate responseStatus: "
+ "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ));
+ return rc;
+ }
+
+ /* Extract response status */
+ if ( cursor.len != sizeof ( status ) ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" invalid status:\n",
+ ocsp, x509_name ( ocsp->cert ) );
+ DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
+ return -EINVAL;
+ }
+ memcpy ( &status, cursor.data, sizeof ( status ) );
+
+ /* Check response status */
+ if ( status != OCSP_STATUS_SUCCESSFUL ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" response status %d\n",
+ ocsp, x509_name ( ocsp->cert ), status );
+ return EPROTO_STATUS ( status );
+ }
+
+ return 0;
+}
+
+/**
+ * Parse OCSP response type
+ *
+ * @v ocsp OCSP check
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int ocsp_parse_response_type ( struct ocsp_check *ocsp,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+
+ /* Enter responseType */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_OID );
+
+ /* Check responseType is "basic" */
+ if ( asn1_compare ( &oid_basic_response_type_cursor, &cursor ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" response type not supported:\n",
+ ocsp, x509_name ( ocsp->cert ) );
+ DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
+ return -ENOTSUP_RESPONSE_TYPE;
+ }
+
+ return 0;
+}
+
+/**
+ * Compare responder's certificate name
+ *
+ * @v ocsp OCSP check
+ * @v cert Certificate
+ * @ret difference Difference as returned by memcmp()
+ */
+static int ocsp_compare_responder_name ( struct ocsp_check *ocsp,
+ struct x509_certificate *cert ) {
+ struct ocsp_responder *responder = &ocsp->response.responder;
+
+ /* Compare responder ID with certificate's subject */
+ return asn1_compare ( &responder->id, &cert->subject.raw );
+}
+
+/**
+ * Compare responder's certificate public key hash
+ *
+ * @v ocsp OCSP check
+ * @v cert Certificate
+ * @ret difference Difference as returned by memcmp()
+ */
+static int ocsp_compare_responder_key_hash ( struct ocsp_check *ocsp,
+ struct x509_certificate *cert ) {
+ struct ocsp_responder *responder = &ocsp->response.responder;
+ struct asn1_cursor key_hash;
+ uint8_t ctx[SHA1_CTX_SIZE];
+ uint8_t digest[SHA1_DIGEST_SIZE];
+ int difference;
+
+ /* Enter responder key hash */
+ memcpy ( &key_hash, &responder->id, sizeof ( key_hash ) );
+ asn1_enter ( &key_hash, ASN1_OCTET_STRING );
+
+ /* Sanity check */
+ difference = ( sizeof ( digest ) - key_hash.len );
+ if ( difference )
+ return difference;
+
+ /* Generate SHA1 hash of certificate's public key */
+ digest_init ( &sha1_algorithm, ctx );
+ digest_update ( &sha1_algorithm, ctx,
+ cert->subject.public_key.raw_bits.data,
+ cert->subject.public_key.raw_bits.len );
+ digest_final ( &sha1_algorithm, ctx, digest );
+
+ /* Compare responder key hash with hash of certificate's public key */
+ return memcmp ( digest, key_hash.data, sizeof ( digest ) );
+}
+
+/**
+ * Parse OCSP responder ID
+ *
+ * @v ocsp OCSP check
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int ocsp_parse_responder_id ( struct ocsp_check *ocsp,
+ const struct asn1_cursor *raw ) {
+ struct ocsp_responder *responder = &ocsp->response.responder;
+ struct asn1_cursor *responder_id = &responder->id;
+ unsigned int type;
+
+ /* Enter responder ID */
+ memcpy ( responder_id, raw, sizeof ( *responder_id ) );
+ type = asn1_type ( responder_id );
+ asn1_enter_any ( responder_id );
+
+ /* Identify responder ID type */
+ switch ( type ) {
+ case ASN1_EXPLICIT_TAG ( 1 ) :
+ DBGC2 ( ocsp, "OCSP %p \"%s\" responder identified by name\n",
+ ocsp, x509_name ( ocsp->cert ) );
+ responder->compare = ocsp_compare_responder_name;
+ return 0;
+ case ASN1_EXPLICIT_TAG ( 2 ) :
+ DBGC2 ( ocsp, "OCSP %p \"%s\" responder identified by key "
+ "hash\n", ocsp, x509_name ( ocsp->cert ) );
+ responder->compare = ocsp_compare_responder_key_hash;
+ return 0;
+ default:
+ DBGC ( ocsp, "OCSP %p \"%s\" unsupported responder ID type "
+ "%d\n", ocsp, x509_name ( ocsp->cert ), type );
+ return -ENOTSUP_RESPONDER_ID;
+ }
+}
+
+/**
+ * Parse OCSP certificate ID
+ *
+ * @v ocsp OCSP check
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int ocsp_parse_cert_id ( struct ocsp_check *ocsp,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+
+ /* Check certID matches request */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_shrink_any ( &cursor );
+ if ( asn1_compare ( &cursor, &ocsp->request.cert_id ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" certID mismatch:\n",
+ ocsp, x509_name ( ocsp->cert ) );
+ DBGC_HDA ( ocsp, 0, ocsp->request.cert_id.data,
+ ocsp->request.cert_id.len );
+ DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
+ return -EACCES_CERT_MISMATCH;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse OCSP responses
+ *
+ * @v ocsp OCSP check
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int ocsp_parse_responses ( struct ocsp_check *ocsp,
+ const struct asn1_cursor *raw ) {
+ struct ocsp_response *response = &ocsp->response;
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Enter responses */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Enter first singleResponse */
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse certID */
+ if ( ( rc = ocsp_parse_cert_id ( ocsp, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Check certStatus */
+ if ( asn1_type ( &cursor ) != ASN1_IMPLICIT_TAG ( 0 ) ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" non-good certStatus:\n",
+ ocsp, x509_name ( ocsp->cert ) );
+ DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
+ return -EACCES_CERT_STATUS;
+ }
+ asn1_skip_any ( &cursor );
+
+ /* Parse thisUpdate */
+ if ( ( rc = asn1_generalized_time ( &cursor,
+ &response->this_update ) ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" could not parse thisUpdate: %s\n",
+ ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( ocsp, "OCSP %p \"%s\" this update was at time %lld\n",
+ ocsp, x509_name ( ocsp->cert ), response->this_update );
+ asn1_skip_any ( &cursor );
+
+ /* Parse nextUpdate, if present */
+ if ( asn1_type ( &cursor ) == ASN1_EXPLICIT_TAG ( 0 ) ) {
+ asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+ if ( ( rc = asn1_generalized_time ( &cursor,
+ &response->next_update ) ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" could not parse "
+ "nextUpdate: %s\n", ocsp,
+ x509_name ( ocsp->cert ), strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( ocsp, "OCSP %p \"%s\" next update is at time %lld\n",
+ ocsp, x509_name ( ocsp->cert ), response->next_update );
+ } else {
+ /* If no nextUpdate is present, this indicates that
+ * "newer revocation information is available all the
+ * time". Actually, this indicates that there is no
+ * point to performing the OCSP check, since an
+ * attacker could replay the response at any future
+ * time and it would still be valid.
+ */
+ DBGC ( ocsp, "OCSP %p \"%s\" responder is a moron\n",
+ ocsp, x509_name ( ocsp->cert ) );
+ response->next_update = time ( NULL );
+ }
+
+ return 0;
+}
+
+/**
+ * Parse OCSP response data
+ *
+ * @v ocsp OCSP check
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int ocsp_parse_tbs_response_data ( struct ocsp_check *ocsp,
+ const struct asn1_cursor *raw ) {
+ struct ocsp_response *response = &ocsp->response;
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Record raw tbsResponseData */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_shrink_any ( &cursor );
+ memcpy ( &response->tbs, &cursor, sizeof ( response->tbs ) );
+
+ /* Enter tbsResponseData */
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Skip version, if present */
+ asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+
+ /* Parse responderID */
+ if ( ( rc = ocsp_parse_responder_id ( ocsp, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Skip producedAt */
+ asn1_skip_any ( &cursor );
+
+ /* Parse responses */
+ if ( ( rc = ocsp_parse_responses ( ocsp, &cursor ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Parse OCSP certificates
+ *
+ * @v ocsp OCSP check
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int ocsp_parse_certs ( struct ocsp_check *ocsp,
+ const struct asn1_cursor *raw ) {
+ struct ocsp_response *response = &ocsp->response;
+ struct asn1_cursor cursor;
+ struct x509_certificate *cert;
+ int rc;
+
+ /* Enter certs */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse certificate, if present. The data structure permits
+ * multiple certificates, but the protocol requires that the
+ * OCSP signing certificate must either be the issuer itself,
+ * or must be directly issued by the issuer (see RFC2560
+ * section 4.2.2.2 "Authorized Responders"). We therefore
+ * need to identify only the single certificate matching the
+ * Responder ID.
+ */
+ while ( cursor.len ) {
+
+ /* Parse certificate */
+ if ( ( rc = x509_certificate ( cursor.data, cursor.len,
+ &cert ) ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" could not parse "
+ "certificate: %s\n", ocsp,
+ x509_name ( ocsp->cert ), strerror ( rc ) );
+ DBGC_HDA ( ocsp, 0, cursor.data, cursor.len );
+ return rc;
+ }
+
+ /* Use if this certificate matches the responder ID */
+ if ( response->responder.compare ( ocsp, cert ) == 0 ) {
+ response->signer = cert;
+ DBGC2 ( ocsp, "OCSP %p \"%s\" response is signed by ",
+ ocsp, x509_name ( ocsp->cert ) );
+ DBGC2 ( ocsp, "\"%s\"\n",
+ x509_name ( response->signer ) );
+ return 0;
+ }
+
+ /* Otherwise, discard this certificate */
+ x509_put ( cert );
+ asn1_skip_any ( &cursor );
+ }
+
+ DBGC ( ocsp, "OCSP %p \"%s\" missing responder certificate\n",
+ ocsp, x509_name ( ocsp->cert ) );
+ return -EACCES_NO_RESPONDER;
+}
+
+/**
+ * Parse OCSP basic response
+ *
+ * @v ocsp OCSP check
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int ocsp_parse_basic_response ( struct ocsp_check *ocsp,
+ const struct asn1_cursor *raw ) {
+ struct ocsp_response *response = &ocsp->response;
+ struct asn1_algorithm **algorithm = &response->algorithm;
+ struct asn1_bit_string *signature = &response->signature;
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Enter BasicOCSPResponse */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse tbsResponseData */
+ if ( ( rc = ocsp_parse_tbs_response_data ( ocsp, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Parse signatureAlgorithm */
+ if ( ( rc = asn1_signature_algorithm ( &cursor, algorithm ) ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" cannot parse signature "
+ "algorithm: %s\n",
+ ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( ocsp, "OCSP %p \"%s\" signature algorithm is %s\n",
+ ocsp, x509_name ( ocsp->cert ), (*algorithm)->name );
+ asn1_skip_any ( &cursor );
+
+ /* Parse signature */
+ if ( ( rc = asn1_integral_bit_string ( &cursor, signature ) ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" cannot parse signature: %s\n",
+ ocsp, x509_name ( ocsp->cert ), strerror ( rc ) );
+ return rc;
+ }
+ asn1_skip_any ( &cursor );
+
+ /* Parse certs, if present */
+ if ( ( asn1_type ( &cursor ) == ASN1_EXPLICIT_TAG ( 0 ) ) &&
+ ( ( rc = ocsp_parse_certs ( ocsp, &cursor ) ) != 0 ) )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Parse OCSP response bytes
+ *
+ * @v ocsp OCSP check
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int ocsp_parse_response_bytes ( struct ocsp_check *ocsp,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Enter responseBytes */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse responseType */
+ if ( ( rc = ocsp_parse_response_type ( ocsp, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Enter response */
+ asn1_enter ( &cursor, ASN1_OCTET_STRING );
+
+ /* Parse response */
+ if ( ( rc = ocsp_parse_basic_response ( ocsp, &cursor ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Parse OCSP response
+ *
+ * @v ocsp OCSP check
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int ocsp_parse_response ( struct ocsp_check *ocsp,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Enter OCSPResponse */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse responseStatus */
+ if ( ( rc = ocsp_parse_response_status ( ocsp, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Parse responseBytes */
+ if ( ( rc = ocsp_parse_response_bytes ( ocsp, &cursor ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Receive OCSP response
+ *
+ * @v ocsp OCSP check
+ * @v data Response data
+ * @v len Length of response data
+ * @ret rc Return status code
+ */
+int ocsp_response ( struct ocsp_check *ocsp, const void *data, size_t len ) {
+ struct ocsp_response *response = &ocsp->response;
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Duplicate data */
+ x509_put ( response->signer );
+ response->signer = NULL;
+ free ( response->data );
+ response->data = malloc ( len );
+ if ( ! response->data )
+ return -ENOMEM;
+ memcpy ( response->data, data, len );
+ cursor.data = response->data;
+ cursor.len = len;
+
+ /* Parse response */
+ if ( ( rc = ocsp_parse_response ( ocsp, &cursor ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * OCSP dummy root certificate store
+ *
+ * OCSP validation uses no root certificates, since it takes place
+ * only when there already exists a validated issuer certificate.
+ */
+static struct x509_root ocsp_root = {
+ .digest = &ocsp_digest_algorithm,
+ .count = 0,
+ .fingerprints = NULL,
+};
+
+/**
+ * Check OCSP response signature
+ *
+ * @v ocsp OCSP check
+ * @v signer Signing certificate
+ * @ret rc Return status code
+ */
+static int ocsp_check_signature ( struct ocsp_check *ocsp,
+ struct x509_certificate *signer ) {
+ struct ocsp_response *response = &ocsp->response;
+ struct digest_algorithm *digest = response->algorithm->digest;
+ struct pubkey_algorithm *pubkey = response->algorithm->pubkey;
+ struct x509_public_key *public_key = &signer->subject.public_key;
+ uint8_t digest_ctx[ digest->ctxsize ];
+ uint8_t digest_out[ digest->digestsize ];
+ uint8_t pubkey_ctx[ pubkey->ctxsize ];
+ int rc;
+
+ /* Generate digest */
+ digest_init ( digest, digest_ctx );
+ digest_update ( digest, digest_ctx, response->tbs.data,
+ response->tbs.len );
+ digest_final ( digest, digest_ctx, digest_out );
+
+ /* Initialise public-key algorithm */
+ if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data,
+ public_key->raw.len ) ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" could not initialise public key: "
+ "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ));
+ goto err_init;
+ }
+
+ /* Verify digest */
+ if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out,
+ response->signature.data,
+ response->signature.len ) ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" signature verification failed: "
+ "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ));
+ goto err_verify;
+ }
+
+ DBGC2 ( ocsp, "OCSP %p \"%s\" signature is correct\n",
+ ocsp, x509_name ( ocsp->cert ) );
+
+ err_verify:
+ pubkey_final ( pubkey, pubkey_ctx );
+ err_init:
+ return rc;
+}
+
+/**
+ * Validate OCSP response
+ *
+ * @v ocsp OCSP check
+ * @v time Time at which to validate response
+ * @ret rc Return status code
+ */
+int ocsp_validate ( struct ocsp_check *ocsp, time_t time ) {
+ struct ocsp_response *response = &ocsp->response;
+ struct x509_certificate *signer;
+ int rc;
+
+ /* Sanity checks */
+ assert ( response->data != NULL );
+
+ /* The response may include a signer certificate; if this is
+ * not present then the response must have been signed
+ * directly by the issuer.
+ */
+ signer = ( response->signer ? response->signer : ocsp->issuer );
+
+ /* Validate signer, if applicable. If the signer is not the
+ * issuer, then it must be signed directly by the issuer.
+ */
+ if ( signer != ocsp->issuer ) {
+ /* Forcibly invalidate the signer, since we need to
+ * ensure that it was signed by our issuer (and not
+ * some other issuer). This prevents a sub-CA's OCSP
+ * certificate from fraudulently signing OCSP
+ * responses from the parent CA.
+ */
+ x509_invalidate ( signer );
+ if ( ( rc = x509_validate ( signer, ocsp->issuer, time,
+ &ocsp_root ) ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" could not validate ",
+ ocsp, x509_name ( ocsp->cert ) );
+ DBGC ( ocsp, "signer \"%s\": %s\n",
+ x509_name ( signer ), strerror ( rc ) );
+ return rc;
+ }
+
+ /* If signer is not the issuer, then it must have the
+ * extendedKeyUsage id-kp-OCSPSigning.
+ */
+ if ( ! ( signer->extensions.ext_usage.bits &
+ X509_OCSP_SIGNING ) ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" ",
+ ocsp, x509_name ( ocsp->cert ) );
+ DBGC ( ocsp, "signer \"%s\" is not an OCSP-signing "
+ "certificate\n", x509_name ( signer ) );
+ return -EACCES_NON_OCSP_SIGNING;
+ }
+ }
+
+ /* Check OCSP response signature */
+ if ( ( rc = ocsp_check_signature ( ocsp, signer ) ) != 0 )
+ return rc;
+
+ /* Check OCSP response is valid at the specified time
+ * (allowing for some margin of error).
+ */
+ if ( response->this_update > ( time + TIMESTAMP_ERROR_MARGIN ) ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" response is not yet valid (at "
+ "time %lld)\n", ocsp, x509_name ( ocsp->cert ), time );
+ return -EACCES_STALE;
+ }
+ if ( response->next_update < ( time - TIMESTAMP_ERROR_MARGIN ) ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" response is stale (at time "
+ "%lld)\n", ocsp, x509_name ( ocsp->cert ), time );
+ return -EACCES_STALE;
+ }
+ DBGC2 ( ocsp, "OCSP %p \"%s\" response is valid (at time %lld)\n",
+ ocsp, x509_name ( ocsp->cert ), time );
+
+ /* Mark certificate as passing OCSP verification */
+ ocsp->cert->extensions.auth_info.ocsp.good = 1;
+
+ /* Validate certificate against issuer */
+ if ( ( rc = x509_validate ( ocsp->cert, ocsp->issuer, time,
+ &ocsp_root ) ) != 0 ) {
+ DBGC ( ocsp, "OCSP %p \"%s\" could not validate certificate: "
+ "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc ));
+ return rc;
+ }
+ DBGC ( ocsp, "OCSP %p \"%s\" successfully validated ",
+ ocsp, x509_name ( ocsp->cert ) );
+ DBGC ( ocsp, "using \"%s\"\n", x509_name ( signer ) );
+
+ return 0;
+}
diff --git a/qemu/roms/ipxe/src/crypto/privkey.c b/qemu/roms/ipxe/src/crypto/privkey.c
new file mode 100644
index 000000000..e010649c0
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/privkey.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/settings.h>
+#include <ipxe/x509.h>
+#include <ipxe/privkey.h>
+
+/** @file
+ *
+ * Private key
+ *
+ * Life would in theory be easier if we could use a single file to
+ * hold both the certificate and corresponding private key.
+ * Unfortunately, the only common format which supports this is
+ * PKCS#12 (aka PFX), which is too ugly to be allowed anywhere near my
+ * codebase. See, for reference and amusement:
+ *
+ * http://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html
+ */
+
+/* Allow private key to be overridden if not explicitly specified */
+#ifdef PRIVATE_KEY
+#define ALLOW_KEY_OVERRIDE 0
+#else
+#define ALLOW_KEY_OVERRIDE 1
+#endif
+
+/* Raw private key data */
+extern char private_key_data[];
+extern char private_key_len[];
+__asm__ ( ".section \".rodata\", \"a\", @progbits\n\t"
+ "\nprivate_key_data:\n\t"
+#ifdef PRIVATE_KEY
+ ".incbin \"" PRIVATE_KEY "\"\n\t"
+#endif /* PRIVATE_KEY */
+ ".size private_key_data, ( . - private_key_data )\n\t"
+ ".equ private_key_len, ( . - private_key_data )\n\t"
+ ".previous\n\t" );
+
+/** Private key */
+struct asn1_cursor private_key = {
+ .data = private_key_data,
+ .len = ( ( size_t ) private_key_len ),
+};
+
+/** Private key setting */
+static struct setting privkey_setting __setting ( SETTING_CRYPTO, privkey ) = {
+ .name = "privkey",
+ .description = "Private key",
+ .tag = DHCP_EB_KEY,
+ .type = &setting_type_hex,
+};
+
+/**
+ * Apply private key configuration settings
+ *
+ * @ret rc Return status code
+ */
+static int privkey_apply_settings ( void ) {
+ static void *key_data = NULL;
+ int len;
+
+ /* Allow private key to be overridden only if not explicitly
+ * specified at build time.
+ */
+ if ( ALLOW_KEY_OVERRIDE ) {
+
+ /* Restore default private key */
+ private_key.data = private_key_data;
+ private_key.len = ( ( size_t ) private_key_len );
+
+ /* Fetch new private key, if any */
+ free ( key_data );
+ if ( ( len = fetch_raw_setting_copy ( NULL, &privkey_setting,
+ &key_data ) ) >= 0 ) {
+ private_key.data = key_data;
+ private_key.len = len;
+ }
+ }
+
+ /* Debug */
+ if ( private_key.len ) {
+ DBGC ( &private_key, "PRIVKEY using %s private key:\n",
+ ( key_data ? "external" : "built-in" ) );
+ DBGC_HDA ( &private_key, 0, private_key.data, private_key.len );
+ } else {
+ DBGC ( &private_key, "PRIVKEY has no private key\n" );
+ }
+
+ return 0;
+}
+
+/** Private key settings applicator */
+struct settings_applicator privkey_applicator __settings_applicator = {
+ .apply = privkey_apply_settings,
+};
diff --git a/qemu/roms/ipxe/src/crypto/random_nz.c b/qemu/roms/ipxe/src/crypto/random_nz.c
new file mode 100644
index 000000000..f1d2e187d
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/random_nz.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * Random non-zero bytes
+ *
+ * The RSA algorithm requires the generation of random non-zero bytes,
+ * i.e. bytes in the range [0x01,0xff].
+ *
+ * This algorithm is designed to comply with ANS X9.82 Part 1-2006
+ * Section 9.2.1. This standard is not freely available, but most of
+ * the text appears to be shared with NIST SP 800-90, which can be
+ * downloaded from
+ *
+ * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf
+ *
+ * Where possible, references are given to both documents. In the
+ * case of any disagreement, ANS X9.82 takes priority over NIST SP
+ * 800-90. (In particular, note that some algorithms that are
+ * Approved by NIST SP 800-90 are not Approved by ANS X9.82.)
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <ipxe/rbg.h>
+#include <ipxe/random_nz.h>
+
+/**
+ * Get random non-zero bytes
+ *
+ * @v data Output buffer
+ * @v len Length of output buffer
+ * @ret rc Return status code
+ *
+ * This algorithm is designed to be isomorphic to the Simple Discard
+ * Method described in ANS X9.82 Part 1-2006 Section 9.2.1 (NIST SP
+ * 800-90 Section B.5.1.1).
+ */
+int get_random_nz ( void *data, size_t len ) {
+ uint8_t *bytes = data;
+ int rc;
+
+ while ( len ) {
+
+ /* Generate random byte */
+ if ( ( rc = rbg_generate ( NULL, 0, 0, bytes, 1 ) ) != 0 )
+ return rc;
+
+ /* Move to next byte if this byte is acceptable */
+ if ( *bytes != 0 ) {
+ bytes++;
+ len--;
+ }
+ }
+
+ return 0;
+}
diff --git a/qemu/roms/ipxe/src/crypto/rbg.c b/qemu/roms/ipxe/src/crypto/rbg.c
new file mode 100644
index 000000000..e2d06978c
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/rbg.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * RBG mechanism
+ *
+ * This mechanism is designed to comply with ANS X9.82 Part 4 (April
+ * 2011 Draft) Section 10. This standard is unfortunately not freely
+ * available.
+ *
+ * The chosen RBG design is that of a DRBG with a live entropy source
+ * with no conditioning function. Only a single security strength is
+ * supported. No seedfile is used since there may be no non-volatile
+ * storage available. The system UUID is used as the personalisation
+ * string.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <ipxe/init.h>
+#include <ipxe/settings.h>
+#include <ipxe/uuid.h>
+#include <ipxe/crypto.h>
+#include <ipxe/drbg.h>
+#include <ipxe/rbg.h>
+
+/** The RBG */
+struct random_bit_generator rbg;
+
+/**
+ * Start up RBG
+ *
+ * @ret rc Return status code
+ *
+ * This is the RBG_Startup function defined in ANS X9.82 Part 4 (April
+ * 2011 Draft) Section 9.1.2.2.
+ */
+static int rbg_startup ( void ) {
+ union uuid uuid;
+ int len;
+ int rc;
+
+ /* Try to obtain system UUID for use as personalisation
+ * string, in accordance with ANS X9.82 Part 3-2007 Section
+ * 8.5.2. If no UUID is available, proceed without a
+ * personalisation string.
+ */
+ if ( ( len = fetch_uuid_setting ( NULL, &uuid_setting, &uuid ) ) < 0 ) {
+ rc = len;
+ DBGC ( &rbg, "RBG could not fetch personalisation string: "
+ "%s\n", strerror ( rc ) );
+ len = 0;
+ }
+
+ /* Instantiate DRBG */
+ if ( ( rc = drbg_instantiate ( &rbg.state, &uuid, len ) ) != 0 ) {
+ DBGC ( &rbg, "RBG could not instantiate DRBG: %s\n",
+ strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Shut down RBG
+ *
+ */
+static void rbg_shutdown ( void ) {
+
+ /* Uninstantiate DRBG */
+ drbg_uninstantiate ( &rbg.state );
+}
+
+/** RBG startup function */
+static void rbg_startup_fn ( void ) {
+
+ /* Start up RBG. There is no way to report an error at this
+ * stage, but a failed startup will result in an invalid DRBG
+ * that refuses to generate bits.
+ */
+ rbg_startup();
+}
+
+/** RBG shutdown function */
+static void rbg_shutdown_fn ( int booting __unused ) {
+
+ /* Shut down RBG */
+ rbg_shutdown();
+}
+
+/** RBG startup table entry */
+struct startup_fn startup_rbg __startup_fn ( STARTUP_NORMAL ) = {
+ .startup = rbg_startup_fn,
+ .shutdown = rbg_shutdown_fn,
+};
diff --git a/qemu/roms/ipxe/src/crypto/rootcert.c b/qemu/roms/ipxe/src/crypto/rootcert.c
new file mode 100644
index 000000000..ae28905ac
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/rootcert.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <ipxe/crypto.h>
+#include <ipxe/sha256.h>
+#include <ipxe/x509.h>
+#include <ipxe/settings.h>
+#include <ipxe/dhcp.h>
+#include <ipxe/init.h>
+#include <ipxe/rootcert.h>
+
+/** @file
+ *
+ * Root certificate store
+ *
+ */
+
+/** Length of a root certificate fingerprint */
+#define FINGERPRINT_LEN SHA256_DIGEST_SIZE
+
+/* Allow trusted certificates to be overridden if not explicitly specified */
+#ifdef TRUSTED
+#define ALLOW_TRUST_OVERRIDE 0
+#else
+#define ALLOW_TRUST_OVERRIDE 1
+#endif
+
+/* Use iPXE root CA if no trusted certificates are explicitly specified */
+#ifndef TRUSTED
+#define TRUSTED \
+ /* iPXE root CA */ \
+ 0x9f, 0xaf, 0x71, 0x7b, 0x7f, 0x8c, 0xa2, 0xf9, 0x3c, 0x25, \
+ 0x6c, 0x79, 0xf8, 0xac, 0x55, 0x91, 0x89, 0x5d, 0x66, 0xd1, \
+ 0xff, 0x3b, 0xee, 0x63, 0x97, 0xa7, 0x0d, 0x29, 0xc6, 0x5e, \
+ 0xed, 0x1a,
+#endif
+
+/** Root certificate fingerprints */
+static const uint8_t fingerprints[] = { TRUSTED };
+
+/** Root certificate fingerprint setting */
+static struct setting trust_setting __setting ( SETTING_CRYPTO, trust ) = {
+ .name = "trust",
+ .description = "Trusted root certificate fingerprints",
+ .tag = DHCP_EB_TRUST,
+ .type = &setting_type_hex,
+};
+
+/** Root certificates */
+struct x509_root root_certificates = {
+ .digest = &sha256_algorithm,
+ .count = ( sizeof ( fingerprints ) / FINGERPRINT_LEN ),
+ .fingerprints = fingerprints,
+};
+
+/**
+ * Initialise root certificate
+ *
+ * The list of trusted root certificates can be specified at build
+ * time using the TRUST= build parameter. If no certificates are
+ * specified, then the default iPXE root CA certificate is trusted.
+ *
+ * If no certificates were explicitly specified, then we allow the
+ * list of trusted root certificate fingerprints to be overridden
+ * using the "trust" setting, but only at the point of iPXE
+ * initialisation. This prevents untrusted sources of settings
+ * (e.g. DHCP) from subverting the chain of trust, while allowing
+ * trustworthy sources (e.g. VMware GuestInfo or non-volatile stored
+ * options) to specify the trusted root certificate without requiring
+ * a rebuild.
+ */
+static void rootcert_init ( void ) {
+ void *external = NULL;
+ int len;
+
+ /* Allow trusted root certificates to be overridden only if
+ * not explicitly specified at build time.
+ */
+ if ( ALLOW_TRUST_OVERRIDE ) {
+
+ /* Fetch copy of "trust" setting, if it exists. This
+ * memory will never be freed.
+ */
+ if ( ( len = fetch_raw_setting_copy ( NULL, &trust_setting,
+ &external ) ) >= 0 ) {
+ root_certificates.fingerprints = external;
+ root_certificates.count = ( len / FINGERPRINT_LEN );
+ }
+ }
+
+ DBGC ( &root_certificates, "ROOTCERT using %d %s certificate(s):\n",
+ root_certificates.count, ( external ? "external" : "built-in" ));
+ DBGC_HDA ( &root_certificates, 0, root_certificates.fingerprints,
+ ( root_certificates.count * FINGERPRINT_LEN ) );
+}
+
+/** Root certificate initialiser */
+struct init_fn rootcert_init_fn __init_fn ( INIT_LATE ) = {
+ .initialise = rootcert_init,
+};
diff --git a/qemu/roms/ipxe/src/crypto/rsa.c b/qemu/roms/ipxe/src/crypto/rsa.c
new file mode 100644
index 000000000..0ab7b2ad3
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/rsa.c
@@ -0,0 +1,705 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/asn1.h>
+#include <ipxe/crypto.h>
+#include <ipxe/bigint.h>
+#include <ipxe/random_nz.h>
+#include <ipxe/md5.h>
+#include <ipxe/sha1.h>
+#include <ipxe/sha256.h>
+#include <ipxe/rsa.h>
+
+/** @file
+ *
+ * RSA public-key cryptography
+ *
+ * RSA is documented in RFC 3447.
+ */
+
+/* Disambiguate the various error causes */
+#define EACCES_VERIFY \
+ __einfo_error ( EINFO_EACCES_VERIFY )
+#define EINFO_EACCES_VERIFY \
+ __einfo_uniqify ( EINFO_EACCES, 0x01, "RSA signature incorrect" )
+
+/** "rsaEncryption" object identifier */
+static uint8_t oid_rsa_encryption[] = { ASN1_OID_RSAENCRYPTION };
+
+/** "md5WithRSAEncryption" object identifier */
+static uint8_t oid_md5_with_rsa_encryption[] =
+ { ASN1_OID_MD5WITHRSAENCRYPTION };
+
+/** "sha1WithRSAEncryption" object identifier */
+static uint8_t oid_sha1_with_rsa_encryption[] =
+ { ASN1_OID_SHA1WITHRSAENCRYPTION };
+
+/** "sha256WithRSAEncryption" object identifier */
+static uint8_t oid_sha256_with_rsa_encryption[] =
+ { ASN1_OID_SHA256WITHRSAENCRYPTION };
+
+/** "rsaEncryption" OID-identified algorithm */
+struct asn1_algorithm rsa_encryption_algorithm __asn1_algorithm = {
+ .name = "rsaEncryption",
+ .pubkey = &rsa_algorithm,
+ .digest = NULL,
+ .oid = ASN1_OID_CURSOR ( oid_rsa_encryption ),
+};
+
+/** "md5WithRSAEncryption" OID-identified algorithm */
+struct asn1_algorithm md5_with_rsa_encryption_algorithm __asn1_algorithm = {
+ .name = "md5WithRSAEncryption",
+ .pubkey = &rsa_algorithm,
+ .digest = &md5_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_md5_with_rsa_encryption ),
+};
+
+/** "sha1WithRSAEncryption" OID-identified algorithm */
+struct asn1_algorithm sha1_with_rsa_encryption_algorithm __asn1_algorithm = {
+ .name = "sha1WithRSAEncryption",
+ .pubkey = &rsa_algorithm,
+ .digest = &sha1_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_sha1_with_rsa_encryption ),
+};
+
+/** "sha256WithRSAEncryption" OID-identified algorithm */
+struct asn1_algorithm sha256_with_rsa_encryption_algorithm __asn1_algorithm = {
+ .name = "sha256WithRSAEncryption",
+ .pubkey = &rsa_algorithm,
+ .digest = &sha256_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_sha256_with_rsa_encryption ),
+};
+
+/** MD5 digestInfo prefix */
+static const uint8_t rsa_md5_prefix_data[] =
+ { RSA_DIGESTINFO_PREFIX ( MD5_DIGEST_SIZE, ASN1_OID_MD5 ) };
+
+/** SHA-1 digestInfo prefix */
+static const uint8_t rsa_sha1_prefix_data[] =
+ { RSA_DIGESTINFO_PREFIX ( SHA1_DIGEST_SIZE, ASN1_OID_SHA1 ) };
+
+/** SHA-256 digestInfo prefix */
+static const uint8_t rsa_sha256_prefix_data[] =
+ { RSA_DIGESTINFO_PREFIX ( SHA256_DIGEST_SIZE, ASN1_OID_SHA256 ) };
+
+/** MD5 digestInfo prefix */
+struct rsa_digestinfo_prefix rsa_md5_prefix __rsa_digestinfo_prefix = {
+ .digest = &md5_algorithm,
+ .data = rsa_md5_prefix_data,
+ .len = sizeof ( rsa_md5_prefix_data ),
+};
+
+/** SHA-1 digestInfo prefix */
+struct rsa_digestinfo_prefix rsa_sha1_prefix __rsa_digestinfo_prefix = {
+ .digest = &sha1_algorithm,
+ .data = rsa_sha1_prefix_data,
+ .len = sizeof ( rsa_sha1_prefix_data ),
+};
+
+/** SHA-256 digestInfo prefix */
+struct rsa_digestinfo_prefix rsa_sha256_prefix __rsa_digestinfo_prefix = {
+ .digest = &sha256_algorithm,
+ .data = rsa_sha256_prefix_data,
+ .len = sizeof ( rsa_sha256_prefix_data ),
+};
+
+/**
+ * Identify RSA prefix
+ *
+ * @v digest Digest algorithm
+ * @ret prefix RSA prefix, or NULL
+ */
+static struct rsa_digestinfo_prefix *
+rsa_find_prefix ( struct digest_algorithm *digest ) {
+ struct rsa_digestinfo_prefix *prefix;
+
+ for_each_table_entry ( prefix, RSA_DIGESTINFO_PREFIXES ) {
+ if ( prefix->digest == digest )
+ return prefix;
+ }
+ return NULL;
+}
+
+/**
+ * Free RSA dynamic storage
+ *
+ * @v context RSA context
+ */
+static void rsa_free ( struct rsa_context *context ) {
+
+ free ( context->dynamic );
+ context->dynamic = NULL;
+}
+
+/**
+ * Allocate RSA dynamic storage
+ *
+ * @v context RSA context
+ * @v modulus_len Modulus length
+ * @v exponent_len Exponent length
+ * @ret rc Return status code
+ */
+static int rsa_alloc ( struct rsa_context *context, size_t modulus_len,
+ size_t exponent_len ) {
+ unsigned int size = bigint_required_size ( modulus_len );
+ unsigned int exponent_size = bigint_required_size ( exponent_len );
+ bigint_t ( size ) *modulus;
+ bigint_t ( exponent_size ) *exponent;
+ size_t tmp_len = bigint_mod_exp_tmp_len ( modulus, exponent );
+ struct {
+ bigint_t ( size ) modulus;
+ bigint_t ( exponent_size ) exponent;
+ bigint_t ( size ) input;
+ bigint_t ( size ) output;
+ uint8_t tmp[tmp_len];
+ } __attribute__ (( packed )) *dynamic;
+
+ /* Free any existing dynamic storage */
+ rsa_free ( context );
+
+ /* Allocate dynamic storage */
+ dynamic = malloc ( sizeof ( *dynamic ) );
+ if ( ! dynamic )
+ return -ENOMEM;
+
+ /* Assign dynamic storage */
+ context->dynamic = dynamic;
+ context->modulus0 = &dynamic->modulus.element[0];
+ context->size = size;
+ context->max_len = modulus_len;
+ context->exponent0 = &dynamic->exponent.element[0];
+ context->exponent_size = exponent_size;
+ context->input0 = &dynamic->input.element[0];
+ context->output0 = &dynamic->output.element[0];
+ context->tmp = &dynamic->tmp;
+
+ return 0;
+}
+
+/**
+ * Parse RSA integer
+ *
+ * @v integer Integer to fill in
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int rsa_parse_integer ( struct asn1_cursor *integer,
+ const struct asn1_cursor *raw ) {
+
+ /* Enter integer */
+ memcpy ( integer, raw, sizeof ( *integer ) );
+ asn1_enter ( integer, ASN1_INTEGER );
+
+ /* Skip initial sign byte if applicable */
+ if ( ( integer->len > 1 ) &&
+ ( *( ( uint8_t * ) integer->data ) == 0x00 ) ) {
+ integer->data++;
+ integer->len--;
+ }
+
+ /* Fail if cursor or integer are invalid */
+ if ( ! integer->len )
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * Parse RSA modulus and exponent
+ *
+ * @v modulus Modulus to fill in
+ * @v exponent Exponent to fill in
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int rsa_parse_mod_exp ( struct asn1_cursor *modulus,
+ struct asn1_cursor *exponent,
+ const struct asn1_cursor *raw ) {
+ struct asn1_bit_string bits;
+ struct asn1_cursor cursor;
+ int is_private;
+ int rc;
+
+ /* Enter subjectPublicKeyInfo/RSAPrivateKey */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Determine key format */
+ if ( asn1_type ( &cursor ) == ASN1_INTEGER ) {
+
+ /* Private key */
+ is_private = 1;
+
+ /* Skip version */
+ asn1_skip_any ( &cursor );
+
+ } else {
+
+ /* Public key */
+ is_private = 0;
+
+ /* Skip algorithm */
+ asn1_skip ( &cursor, ASN1_SEQUENCE );
+
+ /* Enter subjectPublicKey */
+ if ( ( rc = asn1_integral_bit_string ( &cursor, &bits ) ) != 0 )
+ return rc;
+ cursor.data = bits.data;
+ cursor.len = bits.len;
+
+ /* Enter RSAPublicKey */
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+ }
+
+ /* Extract modulus */
+ if ( ( rc = rsa_parse_integer ( modulus, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Skip public exponent, if applicable */
+ if ( is_private )
+ asn1_skip ( &cursor, ASN1_INTEGER );
+
+ /* Extract publicExponent/privateExponent */
+ if ( ( rc = rsa_parse_integer ( exponent, &cursor ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Initialise RSA cipher
+ *
+ * @v ctx RSA context
+ * @v key Key
+ * @v key_len Length of key
+ * @ret rc Return status code
+ */
+static int rsa_init ( void *ctx, const void *key, size_t key_len ) {
+ struct rsa_context *context = ctx;
+ struct asn1_cursor modulus;
+ struct asn1_cursor exponent;
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Initialise context */
+ memset ( context, 0, sizeof ( *context ) );
+
+ /* Initialise cursor */
+ cursor.data = key;
+ cursor.len = key_len;
+
+ /* Parse modulus and exponent */
+ if ( ( rc = rsa_parse_mod_exp ( &modulus, &exponent, &cursor ) ) != 0 ){
+ DBGC ( context, "RSA %p invalid modulus/exponent:\n", context );
+ DBGC_HDA ( context, 0, cursor.data, cursor.len );
+ goto err_parse;
+ }
+
+ DBGC ( context, "RSA %p modulus:\n", context );
+ DBGC_HDA ( context, 0, modulus.data, modulus.len );
+ DBGC ( context, "RSA %p exponent:\n", context );
+ DBGC_HDA ( context, 0, exponent.data, exponent.len );
+
+ /* Allocate dynamic storage */
+ if ( ( rc = rsa_alloc ( context, modulus.len, exponent.len ) ) != 0 )
+ goto err_alloc;
+
+ /* Construct big integers */
+ bigint_init ( ( ( bigint_t ( context->size ) * ) context->modulus0 ),
+ modulus.data, modulus.len );
+ bigint_init ( ( ( bigint_t ( context->exponent_size ) * )
+ context->exponent0 ), exponent.data, exponent.len );
+
+ return 0;
+
+ rsa_free ( context );
+ err_alloc:
+ err_parse:
+ return rc;
+}
+
+/**
+ * Calculate RSA maximum output length
+ *
+ * @v ctx RSA context
+ * @ret max_len Maximum output length
+ */
+static size_t rsa_max_len ( void *ctx ) {
+ struct rsa_context *context = ctx;
+
+ return context->max_len;
+}
+
+/**
+ * Perform RSA cipher operation
+ *
+ * @v context RSA context
+ * @v in Input buffer
+ * @v out Output buffer
+ */
+static void rsa_cipher ( struct rsa_context *context,
+ const void *in, void *out ) {
+ bigint_t ( context->size ) *input = ( ( void * ) context->input0 );
+ bigint_t ( context->size ) *output = ( ( void * ) context->output0 );
+ bigint_t ( context->size ) *modulus = ( ( void * ) context->modulus0 );
+ bigint_t ( context->exponent_size ) *exponent =
+ ( ( void * ) context->exponent0 );
+
+ /* Initialise big integer */
+ bigint_init ( input, in, context->max_len );
+
+ /* Perform modular exponentiation */
+ bigint_mod_exp ( input, modulus, exponent, output, context->tmp );
+
+ /* Copy out result */
+ bigint_done ( output, out, context->max_len );
+}
+
+/**
+ * Encrypt using RSA
+ *
+ * @v ctx RSA context
+ * @v plaintext Plaintext
+ * @v plaintext_len Length of plaintext
+ * @v ciphertext Ciphertext
+ * @ret ciphertext_len Length of ciphertext, or negative error
+ */
+static int rsa_encrypt ( void *ctx, const void *plaintext,
+ size_t plaintext_len, void *ciphertext ) {
+ struct rsa_context *context = ctx;
+ void *temp;
+ uint8_t *encoded;
+ size_t max_len = ( context->max_len - 11 );
+ size_t random_nz_len = ( max_len - plaintext_len + 8 );
+ int rc;
+
+ /* Sanity check */
+ if ( plaintext_len > max_len ) {
+ DBGC ( context, "RSA %p plaintext too long (%zd bytes, max "
+ "%zd)\n", context, plaintext_len, max_len );
+ return -ERANGE;
+ }
+ DBGC ( context, "RSA %p encrypting:\n", context );
+ DBGC_HDA ( context, 0, plaintext, plaintext_len );
+
+ /* Construct encoded message (using the big integer output
+ * buffer as temporary storage)
+ */
+ temp = context->output0;
+ encoded = temp;
+ encoded[0] = 0x00;
+ encoded[1] = 0x02;
+ if ( ( rc = get_random_nz ( &encoded[2], random_nz_len ) ) != 0 ) {
+ DBGC ( context, "RSA %p could not generate random data: %s\n",
+ context, strerror ( rc ) );
+ return rc;
+ }
+ encoded[ 2 + random_nz_len ] = 0x00;
+ memcpy ( &encoded[ context->max_len - plaintext_len ],
+ plaintext, plaintext_len );
+
+ /* Encipher the encoded message */
+ rsa_cipher ( context, encoded, ciphertext );
+ DBGC ( context, "RSA %p encrypted:\n", context );
+ DBGC_HDA ( context, 0, ciphertext, context->max_len );
+
+ return context->max_len;
+}
+
+/**
+ * Decrypt using RSA
+ *
+ * @v ctx RSA context
+ * @v ciphertext Ciphertext
+ * @v ciphertext_len Ciphertext length
+ * @v plaintext Plaintext
+ * @ret plaintext_len Plaintext length, or negative error
+ */
+static int rsa_decrypt ( void *ctx, const void *ciphertext,
+ size_t ciphertext_len, void *plaintext ) {
+ struct rsa_context *context = ctx;
+ void *temp;
+ uint8_t *encoded;
+ uint8_t *end;
+ uint8_t *zero;
+ uint8_t *start;
+ size_t plaintext_len;
+
+ /* Sanity check */
+ if ( ciphertext_len != context->max_len ) {
+ DBGC ( context, "RSA %p ciphertext incorrect length (%zd "
+ "bytes, should be %zd)\n",
+ context, ciphertext_len, context->max_len );
+ return -ERANGE;
+ }
+ DBGC ( context, "RSA %p decrypting:\n", context );
+ DBGC_HDA ( context, 0, ciphertext, ciphertext_len );
+
+ /* Decipher the message (using the big integer input buffer as
+ * temporary storage)
+ */
+ temp = context->input0;
+ encoded = temp;
+ rsa_cipher ( context, ciphertext, encoded );
+
+ /* Parse the message */
+ end = ( encoded + context->max_len );
+ if ( ( encoded[0] != 0x00 ) || ( encoded[1] != 0x02 ) )
+ goto invalid;
+ zero = memchr ( &encoded[2], 0, ( end - &encoded[2] ) );
+ if ( ! zero )
+ goto invalid;
+ start = ( zero + 1 );
+ plaintext_len = ( end - start );
+
+ /* Copy out message */
+ memcpy ( plaintext, start, plaintext_len );
+ DBGC ( context, "RSA %p decrypted:\n", context );
+ DBGC_HDA ( context, 0, plaintext, plaintext_len );
+
+ return plaintext_len;
+
+ invalid:
+ DBGC ( context, "RSA %p invalid decrypted message:\n", context );
+ DBGC_HDA ( context, 0, encoded, context->max_len );
+ return -EINVAL;
+}
+
+/**
+ * Encode RSA digest
+ *
+ * @v context RSA context
+ * @v digest Digest algorithm
+ * @v value Digest value
+ * @v encoded Encoded digest
+ * @ret rc Return status code
+ */
+static int rsa_encode_digest ( struct rsa_context *context,
+ struct digest_algorithm *digest,
+ const void *value, void *encoded ) {
+ struct rsa_digestinfo_prefix *prefix;
+ size_t digest_len = digest->digestsize;
+ uint8_t *temp = encoded;
+ size_t digestinfo_len;
+ size_t max_len;
+ size_t pad_len;
+
+ /* Identify prefix */
+ prefix = rsa_find_prefix ( digest );
+ if ( ! prefix ) {
+ DBGC ( context, "RSA %p has no prefix for %s\n",
+ context, digest->name );
+ return -ENOTSUP;
+ }
+ digestinfo_len = ( prefix->len + digest_len );
+
+ /* Sanity check */
+ max_len = ( context->max_len - 11 );
+ if ( digestinfo_len > max_len ) {
+ DBGC ( context, "RSA %p %s digestInfo too long (%zd bytes, max"
+ "%zd)\n",
+ context, digest->name, digestinfo_len, max_len );
+ return -ERANGE;
+ }
+ DBGC ( context, "RSA %p encoding %s digest:\n",
+ context, digest->name );
+ DBGC_HDA ( context, 0, value, digest_len );
+
+ /* Construct encoded message */
+ *(temp++) = 0x00;
+ *(temp++) = 0x01;
+ pad_len = ( max_len - digestinfo_len + 8 );
+ memset ( temp, 0xff, pad_len );
+ temp += pad_len;
+ *(temp++) = 0x00;
+ memcpy ( temp, prefix->data, prefix->len );
+ temp += prefix->len;
+ memcpy ( temp, value, digest_len );
+ temp += digest_len;
+ assert ( temp == ( encoded + context->max_len ) );
+ DBGC ( context, "RSA %p encoded %s digest:\n", context, digest->name );
+ DBGC_HDA ( context, 0, encoded, context->max_len );
+
+ return 0;
+}
+
+/**
+ * Sign digest value using RSA
+ *
+ * @v ctx RSA context
+ * @v digest Digest algorithm
+ * @v value Digest value
+ * @v signature Signature
+ * @ret signature_len Signature length, or negative error
+ */
+static int rsa_sign ( void *ctx, struct digest_algorithm *digest,
+ const void *value, void *signature ) {
+ struct rsa_context *context = ctx;
+ void *temp;
+ int rc;
+
+ DBGC ( context, "RSA %p signing %s digest:\n", context, digest->name );
+ DBGC_HDA ( context, 0, value, digest->digestsize );
+
+ /* Encode digest (using the big integer output buffer as
+ * temporary storage)
+ */
+ temp = context->output0;
+ if ( ( rc = rsa_encode_digest ( context, digest, value, temp ) ) != 0 )
+ return rc;
+
+ /* Encipher the encoded digest */
+ rsa_cipher ( context, temp, signature );
+ DBGC ( context, "RSA %p signed %s digest:\n", context, digest->name );
+ DBGC_HDA ( context, 0, signature, context->max_len );
+
+ return context->max_len;
+}
+
+/**
+ * Verify signed digest value using RSA
+ *
+ * @v ctx RSA context
+ * @v digest Digest algorithm
+ * @v value Digest value
+ * @v signature Signature
+ * @v signature_len Signature length
+ * @ret rc Return status code
+ */
+static int rsa_verify ( void *ctx, struct digest_algorithm *digest,
+ const void *value, const void *signature,
+ size_t signature_len ) {
+ struct rsa_context *context = ctx;
+ void *temp;
+ void *expected;
+ void *actual;
+ int rc;
+
+ /* Sanity check */
+ if ( signature_len != context->max_len ) {
+ DBGC ( context, "RSA %p signature incorrect length (%zd "
+ "bytes, should be %zd)\n",
+ context, signature_len, context->max_len );
+ return -ERANGE;
+ }
+ DBGC ( context, "RSA %p verifying %s digest:\n",
+ context, digest->name );
+ DBGC_HDA ( context, 0, value, digest->digestsize );
+ DBGC_HDA ( context, 0, signature, signature_len );
+
+ /* Decipher the signature (using the big integer input buffer
+ * as temporary storage)
+ */
+ temp = context->input0;
+ expected = temp;
+ rsa_cipher ( context, signature, expected );
+ DBGC ( context, "RSA %p deciphered signature:\n", context );
+ DBGC_HDA ( context, 0, expected, context->max_len );
+
+ /* Encode digest (using the big integer output buffer as
+ * temporary storage)
+ */
+ temp = context->output0;
+ actual = temp;
+ if ( ( rc = rsa_encode_digest ( context, digest, value, actual ) ) !=0 )
+ return rc;
+
+ /* Verify the signature */
+ if ( memcmp ( actual, expected, context->max_len ) != 0 ) {
+ DBGC ( context, "RSA %p signature verification failed\n",
+ context );
+ return -EACCES_VERIFY;
+ }
+
+ DBGC ( context, "RSA %p signature verified successfully\n", context );
+ return 0;
+}
+
+/**
+ * Finalise RSA cipher
+ *
+ * @v ctx RSA context
+ */
+static void rsa_final ( void *ctx ) {
+ struct rsa_context *context = ctx;
+
+ rsa_free ( context );
+}
+
+/**
+ * Check for matching RSA public/private key pair
+ *
+ * @v private_key Private key
+ * @v private_key_len Private key length
+ * @v public_key Public key
+ * @v public_key_len Public key length
+ * @ret rc Return status code
+ */
+static int rsa_match ( const void *private_key, size_t private_key_len,
+ const void *public_key, size_t public_key_len ) {
+ struct asn1_cursor private_modulus;
+ struct asn1_cursor private_exponent;
+ struct asn1_cursor private_cursor;
+ struct asn1_cursor public_modulus;
+ struct asn1_cursor public_exponent;
+ struct asn1_cursor public_cursor;
+ int rc;
+
+ /* Initialise cursors */
+ private_cursor.data = private_key;
+ private_cursor.len = private_key_len;
+ public_cursor.data = public_key;
+ public_cursor.len = public_key_len;
+
+ /* Parse moduli and exponents */
+ if ( ( rc = rsa_parse_mod_exp ( &private_modulus, &private_exponent,
+ &private_cursor ) ) != 0 )
+ return rc;
+ if ( ( rc = rsa_parse_mod_exp ( &public_modulus, &public_exponent,
+ &public_cursor ) ) != 0 )
+ return rc;
+
+ /* Compare moduli */
+ if ( asn1_compare ( &private_modulus, &public_modulus ) != 0 )
+ return -ENOTTY;
+
+ return 0;
+}
+
+/** RSA public-key algorithm */
+struct pubkey_algorithm rsa_algorithm = {
+ .name = "rsa",
+ .ctxsize = sizeof ( struct rsa_context ),
+ .init = rsa_init,
+ .max_len = rsa_max_len,
+ .encrypt = rsa_encrypt,
+ .decrypt = rsa_decrypt,
+ .sign = rsa_sign,
+ .verify = rsa_verify,
+ .final = rsa_final,
+ .match = rsa_match,
+};
diff --git a/qemu/roms/ipxe/src/crypto/sha1.c b/qemu/roms/ipxe/src/crypto/sha1.c
new file mode 100644
index 000000000..e1bef669e
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/sha1.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * SHA-1 algorithm
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <assert.h>
+#include <ipxe/rotate.h>
+#include <ipxe/crypto.h>
+#include <ipxe/asn1.h>
+#include <ipxe/sha1.h>
+
+/** SHA-1 variables */
+struct sha1_variables {
+ /* This layout matches that of struct sha1_digest_data,
+ * allowing for efficient endianness-conversion,
+ */
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ uint32_t e;
+ uint32_t w[80];
+} __attribute__ (( packed ));
+
+/**
+ * f(a,b,c,d) for steps 0 to 19
+ *
+ * @v v SHA-1 variables
+ * @ret f f(a,b,c,d)
+ */
+static uint32_t sha1_f_0_19 ( struct sha1_variables *v ) {
+ return ( ( v->b & v->c ) | ( (~v->b) & v->d ) );
+}
+
+/**
+ * f(a,b,c,d) for steps 20 to 39 and 60 to 79
+ *
+ * @v v SHA-1 variables
+ * @ret f f(a,b,c,d)
+ */
+static uint32_t sha1_f_20_39_60_79 ( struct sha1_variables *v ) {
+ return ( v->b ^ v->c ^ v->d );
+}
+
+/**
+ * f(a,b,c,d) for steps 40 to 59
+ *
+ * @v v SHA-1 variables
+ * @ret f f(a,b,c,d)
+ */
+static uint32_t sha1_f_40_59 ( struct sha1_variables *v ) {
+ return ( ( v->b & v->c ) | ( v->b & v->d ) | ( v->c & v->d ) );
+}
+
+/** An SHA-1 step function */
+struct sha1_step {
+ /**
+ * Calculate f(a,b,c,d)
+ *
+ * @v v SHA-1 variables
+ * @ret f f(a,b,c,d)
+ */
+ uint32_t ( * f ) ( struct sha1_variables *v );
+ /** Constant k */
+ uint32_t k;
+};
+
+/** SHA-1 steps */
+static struct sha1_step sha1_steps[4] = {
+ /** 0 to 19 */
+ { .f = sha1_f_0_19, .k = 0x5a827999 },
+ /** 20 to 39 */
+ { .f = sha1_f_20_39_60_79, .k = 0x6ed9eba1 },
+ /** 40 to 59 */
+ { .f = sha1_f_40_59, .k = 0x8f1bbcdc },
+ /** 60 to 79 */
+ { .f = sha1_f_20_39_60_79, .k = 0xca62c1d6 },
+};
+
+/**
+ * Initialise SHA-1 algorithm
+ *
+ * @v ctx SHA-1 context
+ */
+static void sha1_init ( void *ctx ) {
+ struct sha1_context *context = ctx;
+
+ context->ddd.dd.digest.h[0] = cpu_to_be32 ( 0x67452301 );
+ context->ddd.dd.digest.h[1] = cpu_to_be32 ( 0xefcdab89 );
+ context->ddd.dd.digest.h[2] = cpu_to_be32 ( 0x98badcfe );
+ context->ddd.dd.digest.h[3] = cpu_to_be32 ( 0x10325476 );
+ context->ddd.dd.digest.h[4] = cpu_to_be32 ( 0xc3d2e1f0 );
+ context->len = 0;
+}
+
+/**
+ * Calculate SHA-1 digest of accumulated data
+ *
+ * @v context SHA-1 context
+ */
+static void sha1_digest ( struct sha1_context *context ) {
+ union {
+ union sha1_digest_data_dwords ddd;
+ struct sha1_variables v;
+ } u;
+ uint32_t *a = &u.v.a;
+ uint32_t *b = &u.v.b;
+ uint32_t *c = &u.v.c;
+ uint32_t *d = &u.v.d;
+ uint32_t *e = &u.v.e;
+ uint32_t *w = u.v.w;
+ uint32_t f;
+ uint32_t k;
+ uint32_t temp;
+ struct sha1_step *step;
+ unsigned int i;
+
+ /* Sanity checks */
+ assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
+ linker_assert ( &u.ddd.dd.digest.h[0] == a, sha1_bad_layout );
+ linker_assert ( &u.ddd.dd.digest.h[1] == b, sha1_bad_layout );
+ linker_assert ( &u.ddd.dd.digest.h[2] == c, sha1_bad_layout );
+ linker_assert ( &u.ddd.dd.digest.h[3] == d, sha1_bad_layout );
+ linker_assert ( &u.ddd.dd.digest.h[4] == e, sha1_bad_layout );
+ linker_assert ( &u.ddd.dd.data.dword[0] == w, sha1_bad_layout );
+
+ DBGC ( context, "SHA1 digesting:\n" );
+ DBGC_HDA ( context, 0, &context->ddd.dd.digest,
+ sizeof ( context->ddd.dd.digest ) );
+ DBGC_HDA ( context, context->len, &context->ddd.dd.data,
+ sizeof ( context->ddd.dd.data ) );
+
+ /* Convert h[0..4] to host-endian, and initialise a, b, c, d,
+ * e, and w[0..15]
+ */
+ for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) /
+ sizeof ( u.ddd.dword[0] ) ) ; i++ ) {
+ be32_to_cpus ( &context->ddd.dword[i] );
+ u.ddd.dword[i] = context->ddd.dword[i];
+ }
+
+ /* Initialise w[16..79] */
+ for ( i = 16 ; i < 80 ; i++ )
+ w[i] = rol32 ( ( w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16] ), 1 );
+
+ /* Main loop */
+ for ( i = 0 ; i < 80 ; i++ ) {
+ step = &sha1_steps[ i / 20 ];
+ f = step->f ( &u.v );
+ k = step->k;
+ temp = ( rol32 ( *a, 5 ) + f + *e + k + w[i] );
+ *e = *d;
+ *d = *c;
+ *c = rol32 ( *b, 30 );
+ *b = *a;
+ *a = temp;
+ DBGC2 ( context, "%2d : %08x %08x %08x %08x %08x\n",
+ i, *a, *b, *c, *d, *e );
+ }
+
+ /* Add chunk to hash and convert back to big-endian */
+ for ( i = 0 ; i < 5 ; i++ ) {
+ context->ddd.dd.digest.h[i] =
+ cpu_to_be32 ( context->ddd.dd.digest.h[i] +
+ u.ddd.dd.digest.h[i] );
+ }
+
+ DBGC ( context, "SHA1 digested:\n" );
+ DBGC_HDA ( context, 0, &context->ddd.dd.digest,
+ sizeof ( context->ddd.dd.digest ) );
+}
+
+/**
+ * Accumulate data with SHA-1 algorithm
+ *
+ * @v ctx SHA-1 context
+ * @v data Data
+ * @v len Length of data
+ */
+static void sha1_update ( void *ctx, const void *data, size_t len ) {
+ struct sha1_context *context = ctx;
+ const uint8_t *byte = data;
+ size_t offset;
+
+ /* Accumulate data a byte at a time, performing the digest
+ * whenever we fill the data buffer
+ */
+ while ( len-- ) {
+ offset = ( context->len % sizeof ( context->ddd.dd.data ) );
+ context->ddd.dd.data.byte[offset] = *(byte++);
+ context->len++;
+ if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 )
+ sha1_digest ( context );
+ }
+}
+
+/**
+ * Generate SHA-1 digest
+ *
+ * @v ctx SHA-1 context
+ * @v out Output buffer
+ */
+static void sha1_final ( void *ctx, void *out ) {
+ struct sha1_context *context = ctx;
+ uint64_t len_bits;
+ uint8_t pad;
+
+ /* Record length before pre-processing */
+ len_bits = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 );
+
+ /* Pad with a single "1" bit followed by as many "0" bits as required */
+ pad = 0x80;
+ do {
+ sha1_update ( ctx, &pad, sizeof ( pad ) );
+ pad = 0x00;
+ } while ( ( context->len % sizeof ( context->ddd.dd.data ) ) !=
+ offsetof ( typeof ( context->ddd.dd.data ), final.len ) );
+
+ /* Append length (in bits) */
+ sha1_update ( ctx, &len_bits, sizeof ( len_bits ) );
+ assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
+
+ /* Copy out final digest */
+ memcpy ( out, &context->ddd.dd.digest,
+ sizeof ( context->ddd.dd.digest ) );
+}
+
+/** SHA-1 algorithm */
+struct digest_algorithm sha1_algorithm = {
+ .name = "sha1",
+ .ctxsize = sizeof ( struct sha1_context ),
+ .blocksize = sizeof ( union sha1_block ),
+ .digestsize = sizeof ( struct sha1_digest ),
+ .init = sha1_init,
+ .update = sha1_update,
+ .final = sha1_final,
+};
+
+/** "sha1" object identifier */
+static uint8_t oid_sha1[] = { ASN1_OID_SHA1 };
+
+/** "sha1" OID-identified algorithm */
+struct asn1_algorithm oid_sha1_algorithm __asn1_algorithm = {
+ .name = "sha1",
+ .digest = &sha1_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_sha1 ),
+};
diff --git a/qemu/roms/ipxe/src/crypto/sha1extra.c b/qemu/roms/ipxe/src/crypto/sha1extra.c
new file mode 100644
index 000000000..cec0d35e5
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/sha1extra.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <string.h>
+#include <ipxe/crypto.h>
+#include <ipxe/sha1.h>
+#include <ipxe/hmac.h>
+#include <stdint.h>
+#include <byteswap.h>
+
+/**
+ * SHA1 pseudorandom function for creating derived keys
+ *
+ * @v key Master key with which this call is associated
+ * @v key_len Length of key
+ * @v label NUL-terminated ASCII string describing purpose of PRF data
+ * @v data Further data that should be included in the PRF
+ * @v data_len Length of further PRF data
+ * @v prf_len Bytes of PRF to generate
+ * @ret prf Pseudorandom function bytes
+ *
+ * This is the PRF variant used by 802.11, defined in IEEE 802.11-2007
+ * 8.5.5.1. EAP-FAST uses a different SHA1-based PRF, and TLS uses an
+ * MD5-based PRF.
+ */
+void prf_sha1 ( const void *key, size_t key_len, const char *label,
+ const void *data, size_t data_len, void *prf, size_t prf_len )
+{
+ u32 blk;
+ u8 keym[key_len]; /* modifiable copy of key */
+ u8 in[strlen ( label ) + 1 + data_len + 1]; /* message to HMAC */
+ u8 *in_blknr; /* pointer to last byte of in, block number */
+ u8 out[SHA1_DIGEST_SIZE]; /* HMAC-SHA1 result */
+ u8 sha1_ctx[SHA1_CTX_SIZE]; /* SHA1 context */
+ const size_t label_len = strlen ( label );
+
+ /* The HMAC-SHA-1 is calculated using the given key on the
+ message text `label', followed by a NUL, followed by one
+ byte indicating the block number (0 for first). */
+
+ memcpy ( keym, key, key_len );
+
+ memcpy ( in, label, strlen ( label ) + 1 );
+ memcpy ( in + label_len + 1, data, data_len );
+ in_blknr = in + label_len + 1 + data_len;
+
+ for ( blk = 0 ;; blk++ ) {
+ *in_blknr = blk;
+
+ hmac_init ( &sha1_algorithm, sha1_ctx, keym, &key_len );
+ hmac_update ( &sha1_algorithm, sha1_ctx, in, sizeof ( in ) );
+ hmac_final ( &sha1_algorithm, sha1_ctx, keym, &key_len, out );
+
+ if ( prf_len <= sizeof ( out ) ) {
+ memcpy ( prf, out, prf_len );
+ break;
+ }
+
+ memcpy ( prf, out, sizeof ( out ) );
+ prf_len -= sizeof ( out );
+ prf += sizeof ( out );
+ }
+}
+
+/**
+ * PBKDF2 key derivation function inner block operation
+ *
+ * @v passphrase Passphrase from which to derive key
+ * @v pass_len Length of passphrase
+ * @v salt Salt to include in key
+ * @v salt_len Length of salt
+ * @v iterations Number of iterations of SHA1 to perform
+ * @v blocknr Index of this block, starting at 1
+ * @ret block SHA1_SIZE bytes of PBKDF2 data
+ *
+ * The operation of this function is described in RFC 2898.
+ */
+static void pbkdf2_sha1_f ( const void *passphrase, size_t pass_len,
+ const void *salt, size_t salt_len,
+ int iterations, u32 blocknr, u8 *block )
+{
+ u8 pass[pass_len]; /* modifiable passphrase */
+ u8 in[salt_len + 4]; /* input buffer to first round */
+ u8 last[SHA1_DIGEST_SIZE]; /* output of round N, input of N+1 */
+ u8 sha1_ctx[SHA1_CTX_SIZE];
+ u8 *next_in = in; /* changed to `last' after first round */
+ int next_size = sizeof ( in );
+ int i;
+ unsigned int j;
+
+ blocknr = htonl ( blocknr );
+
+ memcpy ( pass, passphrase, pass_len );
+ memcpy ( in, salt, salt_len );
+ memcpy ( in + salt_len, &blocknr, 4 );
+ memset ( block, 0, sizeof ( last ) );
+
+ for ( i = 0; i < iterations; i++ ) {
+ hmac_init ( &sha1_algorithm, sha1_ctx, pass, &pass_len );
+ hmac_update ( &sha1_algorithm, sha1_ctx, next_in, next_size );
+ hmac_final ( &sha1_algorithm, sha1_ctx, pass, &pass_len, last );
+
+ for ( j = 0; j < sizeof ( last ); j++ ) {
+ block[j] ^= last[j];
+ }
+
+ next_in = last;
+ next_size = sizeof ( last );
+ }
+}
+
+/**
+ * PBKDF2 key derivation function using SHA1
+ *
+ * @v passphrase Passphrase from which to derive key
+ * @v pass_len Length of passphrase
+ * @v salt Salt to include in key
+ * @v salt_len Length of salt
+ * @v iterations Number of iterations of SHA1 to perform
+ * @v key_len Length of key to generate
+ * @ret key Generated key bytes
+ *
+ * This is used most notably in 802.11 WPA passphrase hashing, in
+ * which case the salt is the SSID, 4096 iterations are used, and a
+ * 32-byte key is generated that serves as the Pairwise Master Key for
+ * EAPOL authentication.
+ *
+ * The operation of this function is further described in RFC 2898.
+ */
+void pbkdf2_sha1 ( const void *passphrase, size_t pass_len,
+ const void *salt, size_t salt_len,
+ int iterations, void *key, size_t key_len )
+{
+ u32 blocks = ( key_len + SHA1_DIGEST_SIZE - 1 ) / SHA1_DIGEST_SIZE;
+ u32 blk;
+ u8 buf[SHA1_DIGEST_SIZE];
+
+ for ( blk = 1; blk <= blocks; blk++ ) {
+ pbkdf2_sha1_f ( passphrase, pass_len, salt, salt_len,
+ iterations, blk, buf );
+ if ( key_len <= sizeof ( buf ) ) {
+ memcpy ( key, buf, key_len );
+ break;
+ }
+
+ memcpy ( key, buf, sizeof ( buf ) );
+ key_len -= sizeof ( buf );
+ key += sizeof ( buf );
+ }
+}
diff --git a/qemu/roms/ipxe/src/crypto/sha256.c b/qemu/roms/ipxe/src/crypto/sha256.c
new file mode 100644
index 000000000..36e02b3c2
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/sha256.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+/** @file
+ *
+ * SHA-256 algorithm
+ *
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <byteswap.h>
+#include <assert.h>
+#include <ipxe/rotate.h>
+#include <ipxe/crypto.h>
+#include <ipxe/asn1.h>
+#include <ipxe/sha256.h>
+
+/** SHA-256 variables */
+struct sha256_variables {
+ /* This layout matches that of struct sha256_digest_data,
+ * allowing for efficient endianness-conversion,
+ */
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ uint32_t e;
+ uint32_t f;
+ uint32_t g;
+ uint32_t h;
+ uint32_t w[64];
+} __attribute__ (( packed ));
+
+/** SHA-256 constants */
+static const uint32_t k[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
+ 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
+ 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+ 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
+ 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
+ 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+/**
+ * Initialise SHA-256 algorithm
+ *
+ * @v ctx SHA-256 context
+ */
+static void sha256_init ( void *ctx ) {
+ struct sha256_context *context = ctx;
+
+ context->ddd.dd.digest.h[0] = cpu_to_be32 ( 0x6a09e667 );
+ context->ddd.dd.digest.h[1] = cpu_to_be32 ( 0xbb67ae85 );
+ context->ddd.dd.digest.h[2] = cpu_to_be32 ( 0x3c6ef372 );
+ context->ddd.dd.digest.h[3] = cpu_to_be32 ( 0xa54ff53a );
+ context->ddd.dd.digest.h[4] = cpu_to_be32 ( 0x510e527f );
+ context->ddd.dd.digest.h[5] = cpu_to_be32 ( 0x9b05688c );
+ context->ddd.dd.digest.h[6] = cpu_to_be32 ( 0x1f83d9ab );
+ context->ddd.dd.digest.h[7] = cpu_to_be32 ( 0x5be0cd19 );
+ context->len = 0;
+}
+
+/**
+ * Calculate SHA-256 digest of accumulated data
+ *
+ * @v context SHA-256 context
+ */
+static void sha256_digest ( struct sha256_context *context ) {
+ union {
+ union sha256_digest_data_dwords ddd;
+ struct sha256_variables v;
+ } u;
+ uint32_t *a = &u.v.a;
+ uint32_t *b = &u.v.b;
+ uint32_t *c = &u.v.c;
+ uint32_t *d = &u.v.d;
+ uint32_t *e = &u.v.e;
+ uint32_t *f = &u.v.f;
+ uint32_t *g = &u.v.g;
+ uint32_t *h = &u.v.h;
+ uint32_t *w = u.v.w;
+ uint32_t s0;
+ uint32_t s1;
+ uint32_t maj;
+ uint32_t t1;
+ uint32_t t2;
+ uint32_t ch;
+ unsigned int i;
+
+ /* Sanity checks */
+ assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
+ linker_assert ( &u.ddd.dd.digest.h[0] == a, sha256_bad_layout );
+ linker_assert ( &u.ddd.dd.digest.h[1] == b, sha256_bad_layout );
+ linker_assert ( &u.ddd.dd.digest.h[2] == c, sha256_bad_layout );
+ linker_assert ( &u.ddd.dd.digest.h[3] == d, sha256_bad_layout );
+ linker_assert ( &u.ddd.dd.digest.h[4] == e, sha256_bad_layout );
+ linker_assert ( &u.ddd.dd.digest.h[5] == f, sha256_bad_layout );
+ linker_assert ( &u.ddd.dd.digest.h[6] == g, sha256_bad_layout );
+ linker_assert ( &u.ddd.dd.digest.h[7] == h, sha256_bad_layout );
+ linker_assert ( &u.ddd.dd.data.dword[0] == w, sha256_bad_layout );
+
+ DBGC ( context, "SHA256 digesting:\n" );
+ DBGC_HDA ( context, 0, &context->ddd.dd.digest,
+ sizeof ( context->ddd.dd.digest ) );
+ DBGC_HDA ( context, context->len, &context->ddd.dd.data,
+ sizeof ( context->ddd.dd.data ) );
+
+ /* Convert h[0..7] to host-endian, and initialise a, b, c, d,
+ * e, f, g, h, and w[0..15]
+ */
+ for ( i = 0 ; i < ( sizeof ( u.ddd.dword ) /
+ sizeof ( u.ddd.dword[0] ) ) ; i++ ) {
+ be32_to_cpus ( &context->ddd.dword[i] );
+ u.ddd.dword[i] = context->ddd.dword[i];
+ }
+
+ /* Initialise w[16..63] */
+ for ( i = 16 ; i < 64 ; i++ ) {
+ s0 = ( ror32 ( w[i-15], 7 ) ^ ror32 ( w[i-15], 18 ) ^
+ ( w[i-15] >> 3 ) );
+ s1 = ( ror32 ( w[i-2], 17 ) ^ ror32 ( w[i-2], 19 ) ^
+ ( w[i-2] >> 10 ) );
+ w[i] = ( w[i-16] + s0 + w[i-7] + s1 );
+ }
+
+ /* Main loop */
+ for ( i = 0 ; i < 64 ; i++ ) {
+ s0 = ( ror32 ( *a, 2 ) ^ ror32 ( *a, 13 ) ^ ror32 ( *a, 22 ) );
+ maj = ( ( *a & *b ) ^ ( *a & *c ) ^ ( *b & *c ) );
+ t2 = ( s0 + maj );
+ s1 = ( ror32 ( *e, 6 ) ^ ror32 ( *e, 11 ) ^ ror32 ( *e, 25 ) );
+ ch = ( ( *e & *f ) ^ ( (~*e) & *g ) );
+ t1 = ( *h + s1 + ch + k[i] + w[i] );
+ *h = *g;
+ *g = *f;
+ *f = *e;
+ *e = ( *d + t1 );
+ *d = *c;
+ *c = *b;
+ *b = *a;
+ *a = ( t1 + t2 );
+ DBGC2 ( context, "%2d : %08x %08x %08x %08x %08x %08x %08x "
+ "%08x\n", i, *a, *b, *c, *d, *e, *f, *g, *h );
+ }
+
+ /* Add chunk to hash and convert back to big-endian */
+ for ( i = 0 ; i < 8 ; i++ ) {
+ context->ddd.dd.digest.h[i] =
+ cpu_to_be32 ( context->ddd.dd.digest.h[i] +
+ u.ddd.dd.digest.h[i] );
+ }
+
+ DBGC ( context, "SHA256 digested:\n" );
+ DBGC_HDA ( context, 0, &context->ddd.dd.digest,
+ sizeof ( context->ddd.dd.digest ) );
+}
+
+/**
+ * Accumulate data with SHA-256 algorithm
+ *
+ * @v ctx SHA-256 context
+ * @v data Data
+ * @v len Length of data
+ */
+static void sha256_update ( void *ctx, const void *data, size_t len ) {
+ struct sha256_context *context = ctx;
+ const uint8_t *byte = data;
+ size_t offset;
+
+ /* Accumulate data a byte at a time, performing the digest
+ * whenever we fill the data buffer
+ */
+ while ( len-- ) {
+ offset = ( context->len % sizeof ( context->ddd.dd.data ) );
+ context->ddd.dd.data.byte[offset] = *(byte++);
+ context->len++;
+ if ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 )
+ sha256_digest ( context );
+ }
+}
+
+/**
+ * Generate SHA-256 digest
+ *
+ * @v ctx SHA-256 context
+ * @v out Output buffer
+ */
+static void sha256_final ( void *ctx, void *out ) {
+ struct sha256_context *context = ctx;
+ uint64_t len_bits;
+ uint8_t pad;
+
+ /* Record length before pre-processing */
+ len_bits = cpu_to_be64 ( ( ( uint64_t ) context->len ) * 8 );
+
+ /* Pad with a single "1" bit followed by as many "0" bits as required */
+ pad = 0x80;
+ do {
+ sha256_update ( ctx, &pad, sizeof ( pad ) );
+ pad = 0x00;
+ } while ( ( context->len % sizeof ( context->ddd.dd.data ) ) !=
+ offsetof ( typeof ( context->ddd.dd.data ), final.len ) );
+
+ /* Append length (in bits) */
+ sha256_update ( ctx, &len_bits, sizeof ( len_bits ) );
+ assert ( ( context->len % sizeof ( context->ddd.dd.data ) ) == 0 );
+
+ /* Copy out final digest */
+ memcpy ( out, &context->ddd.dd.digest,
+ sizeof ( context->ddd.dd.digest ) );
+}
+
+/** SHA-256 algorithm */
+struct digest_algorithm sha256_algorithm = {
+ .name = "sha256",
+ .ctxsize = sizeof ( struct sha256_context ),
+ .blocksize = sizeof ( union sha256_block ),
+ .digestsize = sizeof ( struct sha256_digest ),
+ .init = sha256_init,
+ .update = sha256_update,
+ .final = sha256_final,
+};
+
+/** "sha256" object identifier */
+static uint8_t oid_sha256[] = { ASN1_OID_SHA256 };
+
+/** "sha256" OID-identified algorithm */
+struct asn1_algorithm oid_sha256_algorithm __asn1_algorithm = {
+ .name = "sha256",
+ .digest = &sha256_algorithm,
+ .oid = ASN1_OID_CURSOR ( oid_sha256 ),
+};
diff --git a/qemu/roms/ipxe/src/crypto/x509.c b/qemu/roms/ipxe/src/crypto/x509.c
new file mode 100644
index 000000000..4a02dad14
--- /dev/null
+++ b/qemu/roms/ipxe/src/crypto/x509.c
@@ -0,0 +1,1765 @@
+/*
+ * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program 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 any later version.
+ *
+ * This program 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER );
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <ipxe/list.h>
+#include <ipxe/base16.h>
+#include <ipxe/asn1.h>
+#include <ipxe/crypto.h>
+#include <ipxe/md5.h>
+#include <ipxe/sha1.h>
+#include <ipxe/sha256.h>
+#include <ipxe/rsa.h>
+#include <ipxe/rootcert.h>
+#include <ipxe/certstore.h>
+#include <ipxe/socket.h>
+#include <ipxe/in.h>
+#include <ipxe/x509.h>
+#include <config/crypto.h>
+
+/** @file
+ *
+ * X.509 certificates
+ *
+ * The structure of X.509v3 certificates is documented in RFC 5280
+ * section 4.1.
+ */
+
+/* Disambiguate the various error causes */
+#define ENOTSUP_ALGORITHM \
+ __einfo_error ( EINFO_ENOTSUP_ALGORITHM )
+#define EINFO_ENOTSUP_ALGORITHM \
+ __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unsupported algorithm" )
+#define ENOTSUP_EXTENSION \
+ __einfo_error ( EINFO_ENOTSUP_EXTENSION )
+#define EINFO_ENOTSUP_EXTENSION \
+ __einfo_uniqify ( EINFO_ENOTSUP, 0x02, "Unsupported extension" )
+#define EINVAL_ALGORITHM \
+ __einfo_error ( EINFO_EINVAL_ALGORITHM )
+#define EINFO_EINVAL_ALGORITHM \
+ __einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid algorithm type" )
+#define EINVAL_ALGORITHM_MISMATCH \
+ __einfo_error ( EINFO_EINVAL_ALGORITHM_MISMATCH )
+#define EINFO_EINVAL_ALGORITHM_MISMATCH \
+ __einfo_uniqify ( EINFO_EINVAL, 0x04, "Signature algorithm mismatch" )
+#define EINVAL_PATH_LEN \
+ __einfo_error ( EINFO_EINVAL_PATH_LEN )
+#define EINFO_EINVAL_PATH_LEN \
+ __einfo_uniqify ( EINFO_EINVAL, 0x05, "Invalid pathLenConstraint" )
+#define EINVAL_VERSION \
+ __einfo_error ( EINFO_EINVAL_VERSION )
+#define EINFO_EINVAL_VERSION \
+ __einfo_uniqify ( EINFO_EINVAL, 0x06, "Invalid version" )
+#define EACCES_WRONG_ISSUER \
+ __einfo_error ( EINFO_EACCES_WRONG_ISSUER )
+#define EINFO_EACCES_WRONG_ISSUER \
+ __einfo_uniqify ( EINFO_EACCES, 0x01, "Wrong issuer" )
+#define EACCES_NOT_CA \
+ __einfo_error ( EINFO_EACCES_NOT_CA )
+#define EINFO_EACCES_NOT_CA \
+ __einfo_uniqify ( EINFO_EACCES, 0x02, "Not a CA certificate" )
+#define EACCES_KEY_USAGE \
+ __einfo_error ( EINFO_EACCES_KEY_USAGE )
+#define EINFO_EACCES_KEY_USAGE \
+ __einfo_uniqify ( EINFO_EACCES, 0x03, "Incorrect key usage" )
+#define EACCES_EXPIRED \
+ __einfo_error ( EINFO_EACCES_EXPIRED )
+#define EINFO_EACCES_EXPIRED \
+ __einfo_uniqify ( EINFO_EACCES, 0x04, "Expired (or not yet valid)" )
+#define EACCES_PATH_LEN \
+ __einfo_error ( EINFO_EACCES_PATH_LEN )
+#define EINFO_EACCES_PATH_LEN \
+ __einfo_uniqify ( EINFO_EACCES, 0x05, "Maximum path length exceeded" )
+#define EACCES_UNTRUSTED \
+ __einfo_error ( EINFO_EACCES_UNTRUSTED )
+#define EINFO_EACCES_UNTRUSTED \
+ __einfo_uniqify ( EINFO_EACCES, 0x06, "Untrusted root certificate" )
+#define EACCES_OUT_OF_ORDER \
+ __einfo_error ( EINFO_EACCES_OUT_OF_ORDER )
+#define EINFO_EACCES_OUT_OF_ORDER \
+ __einfo_uniqify ( EINFO_EACCES, 0x07, "Validation out of order" )
+#define EACCES_EMPTY \
+ __einfo_error ( EINFO_EACCES_EMPTY )
+#define EINFO_EACCES_EMPTY \
+ __einfo_uniqify ( EINFO_EACCES, 0x08, "Empty certificate chain" )
+#define EACCES_OCSP_REQUIRED \
+ __einfo_error ( EINFO_EACCES_OCSP_REQUIRED )
+#define EINFO_EACCES_OCSP_REQUIRED \
+ __einfo_uniqify ( EINFO_EACCES, 0x09, "OCSP check required" )
+#define EACCES_WRONG_NAME \
+ __einfo_error ( EINFO_EACCES_WRONG_NAME )
+#define EINFO_EACCES_WRONG_NAME \
+ __einfo_uniqify ( EINFO_EACCES, 0x0a, "Incorrect certificate name" )
+#define EACCES_USELESS \
+ __einfo_error ( EINFO_EACCES_USELESS )
+#define EINFO_EACCES_USELESS \
+ __einfo_uniqify ( EINFO_EACCES, 0x0b, "No usable certificates" )
+
+/**
+ * Get X.509 certificate name (for debugging)
+ *
+ * @v cert X.509 certificate
+ * @ret name Name (for debugging)
+ */
+const char * x509_name ( struct x509_certificate *cert ) {
+ struct asn1_cursor *common_name = &cert->subject.common_name;
+ struct digest_algorithm *digest = &sha1_algorithm;
+ static char buf[64];
+ uint8_t fingerprint[ digest->digestsize ];
+ size_t len;
+
+ len = common_name->len;
+ if ( len ) {
+ /* Certificate has a commonName: use that */
+ if ( len > ( sizeof ( buf ) - 1 /* NUL */ ) )
+ len = ( sizeof ( buf ) - 1 /* NUL */ );
+ memcpy ( buf, common_name->data, len );
+ buf[len] = '\0';
+ } else {
+ /* Certificate has no commonName: use SHA-1 fingerprint */
+ x509_fingerprint ( cert, digest, fingerprint );
+ base16_encode ( fingerprint, sizeof ( fingerprint ), buf );
+ }
+ return buf;
+}
+
+/** "commonName" object identifier */
+static uint8_t oid_common_name[] = { ASN1_OID_COMMON_NAME };
+
+/** "commonName" object identifier cursor */
+static struct asn1_cursor oid_common_name_cursor =
+ ASN1_OID_CURSOR ( oid_common_name );
+
+/**
+ * Parse X.509 certificate version
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_version ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ int version;
+ int rc;
+
+ /* Enter version */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
+
+ /* Parse integer */
+ if ( ( rc = asn1_integer ( &cursor, &version ) ) != 0 ) {
+ DBGC ( cert, "X509 %p cannot parse version: %s\n",
+ cert, strerror ( rc ) );
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
+ return rc;
+ }
+
+ /* Sanity check */
+ if ( version < 0 ) {
+ DBGC ( cert, "X509 %p invalid version %d\n", cert, version );
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
+ return -EINVAL_VERSION;
+ }
+
+ /* Record version */
+ cert->version = version;
+ DBGC2 ( cert, "X509 %p is a version %d certificate\n",
+ cert, ( cert->version + 1 ) );
+
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate serial number
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_serial ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct x509_serial *serial = &cert->serial;
+ int rc;
+
+ /* Record raw serial number */
+ memcpy ( &serial->raw, raw, sizeof ( serial->raw ) );
+ if ( ( rc = asn1_shrink ( &serial->raw, ASN1_INTEGER ) ) != 0 ) {
+ DBGC ( cert, "X509 %p cannot shrink serialNumber: %s\n",
+ cert, strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( cert, "X509 %p issuer is:\n", cert );
+ DBGC2_HDA ( cert, 0, serial->raw.data, serial->raw.len );
+
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate issuer
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_issuer ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct x509_issuer *issuer = &cert->issuer;
+ int rc;
+
+ /* Record raw issuer */
+ memcpy ( &issuer->raw, raw, sizeof ( issuer->raw ) );
+ if ( ( rc = asn1_shrink ( &issuer->raw, ASN1_SEQUENCE ) ) != 0 ) {
+ DBGC ( cert, "X509 %p cannot shrink issuer: %s\n",
+ cert, strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( cert, "X509 %p issuer is:\n", cert );
+ DBGC2_HDA ( cert, 0, issuer->raw.data, issuer->raw.len );
+
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate validity
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_validity ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct x509_validity *validity = &cert->validity;
+ struct x509_time *not_before = &validity->not_before;
+ struct x509_time *not_after = &validity->not_after;
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Enter validity */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse notBefore */
+ if ( ( rc = asn1_generalized_time ( &cursor,
+ &not_before->time ) ) != 0 ) {
+ DBGC ( cert, "X509 %p cannot parse notBefore: %s\n",
+ cert, strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( cert, "X509 %p valid from time %lld\n",
+ cert, not_before->time );
+ asn1_skip_any ( &cursor );
+
+ /* Parse notAfter */
+ if ( ( rc = asn1_generalized_time ( &cursor,
+ &not_after->time ) ) != 0 ) {
+ DBGC ( cert, "X509 %p cannot parse notAfter: %s\n",
+ cert, strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( cert, "X509 %p valid until time %lld\n",
+ cert, not_after->time );
+
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate common name
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_common_name ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ struct asn1_cursor oid_cursor;
+ struct asn1_cursor name_cursor;
+ int rc;
+
+ /* Enter name */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Scan through name list */
+ for ( ; cursor.len ; asn1_skip_any ( &cursor ) ) {
+
+ /* Check for "commonName" OID */
+ memcpy ( &oid_cursor, &cursor, sizeof ( oid_cursor ) );
+ asn1_enter ( &oid_cursor, ASN1_SET );
+ asn1_enter ( &oid_cursor, ASN1_SEQUENCE );
+ memcpy ( &name_cursor, &oid_cursor, sizeof ( name_cursor ) );
+ asn1_enter ( &oid_cursor, ASN1_OID );
+ if ( asn1_compare ( &oid_common_name_cursor, &oid_cursor ) != 0)
+ continue;
+ asn1_skip_any ( &name_cursor );
+ if ( ( rc = asn1_enter_any ( &name_cursor ) ) != 0 ) {
+ DBGC ( cert, "X509 %p cannot locate name:\n", cert );
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
+ return rc;
+ }
+
+ /* Record common name */
+ memcpy ( &cert->subject.common_name, &name_cursor,
+ sizeof ( cert->subject.common_name ) );
+
+ return 0;
+ }
+
+ /* Certificates may not have a commonName */
+ DBGC2 ( cert, "X509 %p no commonName found:\n", cert );
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate subject
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_subject ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct x509_subject *subject = &cert->subject;
+ int rc;
+
+ /* Record raw subject */
+ memcpy ( &subject->raw, raw, sizeof ( subject->raw ) );
+ asn1_shrink_any ( &subject->raw );
+ DBGC2 ( cert, "X509 %p subject is:\n", cert );
+ DBGC2_HDA ( cert, 0, subject->raw.data, subject->raw.len );
+
+ /* Parse common name */
+ if ( ( rc = x509_parse_common_name ( cert, raw ) ) != 0 )
+ return rc;
+ DBGC2 ( cert, "X509 %p common name is \"%s\":\n", cert,
+ x509_name ( cert ) );
+
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate public key information
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_public_key ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct x509_public_key *public_key = &cert->subject.public_key;
+ struct asn1_algorithm **algorithm = &public_key->algorithm;
+ struct asn1_bit_string *raw_bits = &public_key->raw_bits;
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Record raw subjectPublicKeyInfo */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_shrink_any ( &cursor );
+ memcpy ( &public_key->raw, &cursor, sizeof ( public_key->raw ) );
+ DBGC2 ( cert, "X509 %p public key is:\n", cert );
+ DBGC2_HDA ( cert, 0, public_key->raw.data, public_key->raw.len );
+
+ /* Enter subjectPublicKeyInfo */
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse algorithm */
+ if ( ( rc = asn1_pubkey_algorithm ( &cursor, algorithm ) ) != 0 ) {
+ DBGC ( cert, "X509 %p could not parse public key algorithm: "
+ "%s\n", cert, strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( cert, "X509 %p public key algorithm is %s\n",
+ cert, (*algorithm)->name );
+ asn1_skip_any ( &cursor );
+
+ /* Parse bit string */
+ if ( ( rc = asn1_bit_string ( &cursor, raw_bits ) ) != 0 ) {
+ DBGC ( cert, "X509 %p could not parse public key bits: %s\n",
+ cert, strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate basic constraints
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_basic_constraints ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct x509_basic_constraints *basic = &cert->extensions.basic;
+ struct asn1_cursor cursor;
+ int ca = 0;
+ int path_len;
+ int rc;
+
+ /* Enter basicConstraints */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse "cA", if present */
+ if ( asn1_type ( &cursor ) == ASN1_BOOLEAN ) {
+ ca = asn1_boolean ( &cursor );
+ if ( ca < 0 ) {
+ rc = ca;
+ DBGC ( cert, "X509 %p cannot parse cA: %s\n",
+ cert, strerror ( rc ) );
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
+ return rc;
+ }
+ asn1_skip_any ( &cursor );
+ }
+ basic->ca = ca;
+ DBGC2 ( cert, "X509 %p is %sa CA certificate\n",
+ cert, ( basic->ca ? "" : "not " ) );
+
+ /* Ignore everything else unless "cA" is true */
+ if ( ! ca )
+ return 0;
+
+ /* Parse "pathLenConstraint", if present and applicable */
+ basic->path_len = X509_PATH_LEN_UNLIMITED;
+ if ( asn1_type ( &cursor ) == ASN1_INTEGER ) {
+ if ( ( rc = asn1_integer ( &cursor, &path_len ) ) != 0 ) {
+ DBGC ( cert, "X509 %p cannot parse pathLenConstraint: "
+ "%s\n", cert, strerror ( rc ) );
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
+ return rc;
+ }
+ if ( path_len < 0 ) {
+ DBGC ( cert, "X509 %p invalid pathLenConstraint %d\n",
+ cert, path_len );
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
+ return -EINVAL;
+ }
+ basic->path_len = path_len;
+ DBGC2 ( cert, "X509 %p path length constraint is %d\n",
+ cert, basic->path_len );
+ }
+
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate key usage
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_key_usage ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct x509_key_usage *usage = &cert->extensions.usage;
+ struct asn1_bit_string bit_string;
+ const uint8_t *bytes;
+ size_t len;
+ unsigned int i;
+ int rc;
+
+ /* Mark extension as present */
+ usage->present = 1;
+
+ /* Parse bit string */
+ if ( ( rc = asn1_bit_string ( raw, &bit_string ) ) != 0 ) {
+ DBGC ( cert, "X509 %p could not parse key usage: %s\n",
+ cert, strerror ( rc ) );
+ return rc;
+ }
+
+ /* Parse key usage bits */
+ bytes = bit_string.data;
+ len = bit_string.len;
+ if ( len > sizeof ( usage->bits ) )
+ len = sizeof ( usage->bits );
+ for ( i = 0 ; i < len ; i++ ) {
+ usage->bits |= ( *(bytes++) << ( 8 * i ) );
+ }
+ DBGC2 ( cert, "X509 %p key usage is %08x\n", cert, usage->bits );
+
+ return 0;
+}
+
+/** "id-kp-codeSigning" object identifier */
+static uint8_t oid_code_signing[] = { ASN1_OID_CODESIGNING };
+
+/** "id-kp-OCSPSigning" object identifier */
+static uint8_t oid_ocsp_signing[] = { ASN1_OID_OCSPSIGNING };
+
+/** Supported key purposes */
+static struct x509_key_purpose x509_key_purposes[] = {
+ {
+ .name = "codeSigning",
+ .bits = X509_CODE_SIGNING,
+ .oid = ASN1_OID_CURSOR ( oid_code_signing ),
+ },
+ {
+ .name = "ocspSigning",
+ .bits = X509_OCSP_SIGNING,
+ .oid = ASN1_OID_CURSOR ( oid_ocsp_signing ),
+ },
+};
+
+/**
+ * Parse X.509 certificate key purpose identifier
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_key_purpose ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct x509_extended_key_usage *ext_usage = &cert->extensions.ext_usage;
+ struct x509_key_purpose *purpose;
+ struct asn1_cursor cursor;
+ unsigned int i;
+ int rc;
+
+ /* Enter keyPurposeId */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ if ( ( rc = asn1_enter ( &cursor, ASN1_OID ) ) != 0 ) {
+ DBGC ( cert, "X509 %p invalid keyPurposeId:\n", cert );
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
+ return rc;
+ }
+
+ /* Identify key purpose */
+ for ( i = 0 ; i < ( sizeof ( x509_key_purposes ) /
+ sizeof ( x509_key_purposes[0] ) ) ; i++ ) {
+ purpose = &x509_key_purposes[i];
+ if ( asn1_compare ( &cursor, &purpose->oid ) == 0 ) {
+ DBGC2 ( cert, "X509 %p has key purpose %s\n",
+ cert, purpose->name );
+ ext_usage->bits |= purpose->bits;
+ return 0;
+ }
+ }
+
+ /* Ignore unrecognised key purposes */
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate extended key usage
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_extended_key_usage ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Enter extKeyUsage */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse each extended key usage in turn */
+ while ( cursor.len ) {
+ if ( ( rc = x509_parse_key_purpose ( cert, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+ }
+
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate OCSP access method
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_ocsp ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct x509_ocsp_responder *ocsp = &cert->extensions.auth_info.ocsp;
+ struct asn1_cursor *uri = &ocsp->uri;
+ int rc;
+
+ /* Enter accessLocation */
+ memcpy ( uri, raw, sizeof ( *uri ) );
+ if ( ( rc = asn1_enter ( uri, X509_GENERAL_NAME_URI ) ) != 0 ) {
+ DBGC ( cert, "X509 %p OCSP does not contain "
+ "uniformResourceIdentifier:\n", cert );
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
+ return rc;
+ }
+ DBGC2 ( cert, "X509 %p OCSP URI is:\n", cert );
+ DBGC2_HDA ( cert, 0, uri->data, uri->len );
+
+ return 0;
+}
+
+/** "id-ad-ocsp" object identifier */
+static uint8_t oid_ad_ocsp[] = { ASN1_OID_OCSP };
+
+/** Supported access methods */
+static struct x509_access_method x509_access_methods[] = {
+ {
+ .name = "OCSP",
+ .oid = ASN1_OID_CURSOR ( oid_ad_ocsp ),
+ .parse = x509_parse_ocsp,
+ },
+};
+
+/**
+ * Identify X.509 access method by OID
+ *
+ * @v oid OID
+ * @ret method Access method, or NULL
+ */
+static struct x509_access_method *
+x509_find_access_method ( const struct asn1_cursor *oid ) {
+ struct x509_access_method *method;
+ unsigned int i;
+
+ for ( i = 0 ; i < ( sizeof ( x509_access_methods ) /
+ sizeof ( x509_access_methods[0] ) ) ; i++ ) {
+ method = &x509_access_methods[i];
+ if ( asn1_compare ( &method->oid, oid ) == 0 )
+ return method;
+ }
+
+ return NULL;
+}
+
+/**
+ * Parse X.509 certificate access description
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_access_description ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ struct asn1_cursor subcursor;
+ struct x509_access_method *method;
+ int rc;
+
+ /* Enter keyPurposeId */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Try to identify access method */
+ memcpy ( &subcursor, &cursor, sizeof ( subcursor ) );
+ asn1_enter ( &subcursor, ASN1_OID );
+ method = x509_find_access_method ( &subcursor );
+ asn1_skip_any ( &cursor );
+ DBGC2 ( cert, "X509 %p found access method %s\n",
+ cert, ( method ? method->name : "<unknown>" ) );
+
+ /* Parse access location, if applicable */
+ if ( method && ( ( rc = method->parse ( cert, &cursor ) ) != 0 ) )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate authority information access
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_authority_info_access ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Enter authorityInfoAccess */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse each access description in turn */
+ while ( cursor.len ) {
+ if ( ( rc = x509_parse_access_description ( cert,
+ &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+ }
+
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate subject alternative name
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_subject_alt_name ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct x509_subject_alt_name *alt_name = &cert->extensions.alt_name;
+ struct asn1_cursor *names = &alt_name->names;
+ int rc;
+
+ /* Enter subjectAltName */
+ memcpy ( names, raw, sizeof ( *names ) );
+ if ( ( rc = asn1_enter ( names, ASN1_SEQUENCE ) ) != 0 ) {
+ DBGC ( cert, "X509 %p invalid subjectAltName: %s\n",
+ cert, strerror ( rc ) );
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
+ return rc;
+ }
+ DBGC2 ( cert, "X509 %p has subjectAltName:\n", cert );
+ DBGC2_HDA ( cert, 0, names->data, names->len );
+
+ return 0;
+}
+
+/** "id-ce-basicConstraints" object identifier */
+static uint8_t oid_ce_basic_constraints[] =
+ { ASN1_OID_BASICCONSTRAINTS };
+
+/** "id-ce-keyUsage" object identifier */
+static uint8_t oid_ce_key_usage[] =
+ { ASN1_OID_KEYUSAGE };
+
+/** "id-ce-extKeyUsage" object identifier */
+static uint8_t oid_ce_ext_key_usage[] =
+ { ASN1_OID_EXTKEYUSAGE };
+
+/** "id-pe-authorityInfoAccess" object identifier */
+static uint8_t oid_pe_authority_info_access[] =
+ { ASN1_OID_AUTHORITYINFOACCESS };
+
+/** "id-ce-subjectAltName" object identifier */
+static uint8_t oid_ce_subject_alt_name[] =
+ { ASN1_OID_SUBJECTALTNAME };
+
+/** Supported certificate extensions */
+static struct x509_extension x509_extensions[] = {
+ {
+ .name = "basicConstraints",
+ .oid = ASN1_OID_CURSOR ( oid_ce_basic_constraints ),
+ .parse = x509_parse_basic_constraints,
+ },
+ {
+ .name = "keyUsage",
+ .oid = ASN1_OID_CURSOR ( oid_ce_key_usage ),
+ .parse = x509_parse_key_usage,
+ },
+ {
+ .name = "extKeyUsage",
+ .oid = ASN1_OID_CURSOR ( oid_ce_ext_key_usage ),
+ .parse = x509_parse_extended_key_usage,
+ },
+ {
+ .name = "authorityInfoAccess",
+ .oid = ASN1_OID_CURSOR ( oid_pe_authority_info_access ),
+ .parse = x509_parse_authority_info_access,
+ },
+ {
+ .name = "subjectAltName",
+ .oid = ASN1_OID_CURSOR ( oid_ce_subject_alt_name ),
+ .parse = x509_parse_subject_alt_name,
+ },
+};
+
+/**
+ * Identify X.509 extension by OID
+ *
+ * @v oid OID
+ * @ret extension Extension, or NULL
+ */
+static struct x509_extension *
+x509_find_extension ( const struct asn1_cursor *oid ) {
+ struct x509_extension *extension;
+ unsigned int i;
+
+ for ( i = 0 ; i < ( sizeof ( x509_extensions ) /
+ sizeof ( x509_extensions[0] ) ) ; i++ ) {
+ extension = &x509_extensions[i];
+ if ( asn1_compare ( &extension->oid, oid ) == 0 )
+ return extension;
+ }
+
+ return NULL;
+}
+
+/**
+ * Parse X.509 certificate extension
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_extension ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ struct asn1_cursor subcursor;
+ struct x509_extension *extension;
+ int is_critical = 0;
+ int rc;
+
+ /* Enter extension */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Try to identify extension */
+ memcpy ( &subcursor, &cursor, sizeof ( subcursor ) );
+ asn1_enter ( &subcursor, ASN1_OID );
+ extension = x509_find_extension ( &subcursor );
+ asn1_skip_any ( &cursor );
+ DBGC2 ( cert, "X509 %p found extension %s\n",
+ cert, ( extension ? extension->name : "<unknown>" ) );
+
+ /* Identify criticality */
+ if ( asn1_type ( &cursor ) == ASN1_BOOLEAN ) {
+ is_critical = asn1_boolean ( &cursor );
+ if ( is_critical < 0 ) {
+ rc = is_critical;
+ DBGC ( cert, "X509 %p cannot parse extension "
+ "criticality: %s\n", cert, strerror ( rc ) );
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
+ return rc;
+ }
+ asn1_skip_any ( &cursor );
+ }
+
+ /* Handle unknown extensions */
+ if ( ! extension ) {
+ if ( is_critical ) {
+ /* Fail if we cannot handle a critical extension */
+ DBGC ( cert, "X509 %p cannot handle critical "
+ "extension:\n", cert );
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
+ return -ENOTSUP_EXTENSION;
+ } else {
+ /* Ignore unknown non-critical extensions */
+ return 0;
+ }
+ };
+
+ /* Extract extnValue */
+ if ( ( rc = asn1_enter ( &cursor, ASN1_OCTET_STRING ) ) != 0 ) {
+ DBGC ( cert, "X509 %p extension missing extnValue:\n", cert );
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
+ return rc;
+ }
+
+ /* Parse extension */
+ if ( ( rc = extension->parse ( cert, &cursor ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate extensions, if present
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_extensions ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Enter extensions, if present */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 3 ) );
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse each extension in turn */
+ while ( cursor.len ) {
+ if ( ( rc = x509_parse_extension ( cert, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+ }
+
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate tbsCertificate
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+static int x509_parse_tbscertificate ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct asn1_algorithm **algorithm = &cert->signature_algorithm;
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Record raw tbsCertificate */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ asn1_shrink_any ( &cursor );
+ memcpy ( &cert->tbs, &cursor, sizeof ( cert->tbs ) );
+
+ /* Enter tbsCertificate */
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse version, if present */
+ if ( asn1_type ( &cursor ) == ASN1_EXPLICIT_TAG ( 0 ) ) {
+ if ( ( rc = x509_parse_version ( cert, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+ }
+
+ /* Parse serialNumber */
+ if ( ( rc = x509_parse_serial ( cert, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Parse signature */
+ if ( ( rc = asn1_signature_algorithm ( &cursor, algorithm ) ) != 0 ) {
+ DBGC ( cert, "X509 %p could not parse signature algorithm: "
+ "%s\n", cert, strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( cert, "X509 %p tbsCertificate signature algorithm is %s\n",
+ cert, (*algorithm)->name );
+ asn1_skip_any ( &cursor );
+
+ /* Parse issuer */
+ if ( ( rc = x509_parse_issuer ( cert, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Parse validity */
+ if ( ( rc = x509_parse_validity ( cert, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Parse subject */
+ if ( ( rc = x509_parse_subject ( cert, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Parse subjectPublicKeyInfo */
+ if ( ( rc = x509_parse_public_key ( cert, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Parse extensions, if present */
+ if ( ( rc = x509_parse_extensions ( cert, &cursor ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Parse X.509 certificate from ASN.1 data
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @ret rc Return status code
+ */
+int x509_parse ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw ) {
+ struct x509_signature *signature = &cert->signature;
+ struct asn1_algorithm **signature_algorithm = &signature->algorithm;
+ struct asn1_bit_string *signature_value = &signature->value;
+ struct asn1_cursor cursor;
+ int rc;
+
+ /* Record raw certificate */
+ memcpy ( &cursor, raw, sizeof ( cursor ) );
+ memcpy ( &cert->raw, &cursor, sizeof ( cert->raw ) );
+
+ /* Enter certificate */
+ asn1_enter ( &cursor, ASN1_SEQUENCE );
+
+ /* Parse tbsCertificate */
+ if ( ( rc = x509_parse_tbscertificate ( cert, &cursor ) ) != 0 )
+ return rc;
+ asn1_skip_any ( &cursor );
+
+ /* Parse signatureAlgorithm */
+ if ( ( rc = asn1_signature_algorithm ( &cursor,
+ signature_algorithm ) ) != 0 ) {
+ DBGC ( cert, "X509 %p could not parse signature algorithm: "
+ "%s\n", cert, strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( cert, "X509 %p signatureAlgorithm is %s\n",
+ cert, (*signature_algorithm)->name );
+ asn1_skip_any ( &cursor );
+
+ /* Parse signatureValue */
+ if ( ( rc = asn1_integral_bit_string ( &cursor,
+ signature_value ) ) != 0 ) {
+ DBGC ( cert, "X509 %p could not parse signature value: %s\n",
+ cert, strerror ( rc ) );
+ return rc;
+ }
+ DBGC2 ( cert, "X509 %p signatureValue is:\n", cert );
+ DBGC2_HDA ( cert, 0, signature_value->data, signature_value->len );
+
+ /* Check that algorithm in tbsCertificate matches algorithm in
+ * signature
+ */
+ if ( signature->algorithm != (*signature_algorithm) ) {
+ DBGC ( cert, "X509 %p signature algorithm %s does not match "
+ "signatureAlgorithm %s\n",
+ cert, signature->algorithm->name,
+ (*signature_algorithm)->name );
+ return -EINVAL_ALGORITHM_MISMATCH;
+ }
+
+ return 0;
+}
+
+/**
+ * Create X.509 certificate
+ *
+ * @v data Raw certificate data
+ * @v len Length of raw data
+ * @ret cert X.509 certificate
+ * @ret rc Return status code
+ *
+ * On success, the caller holds a reference to the X.509 certificate,
+ * and is responsible for ultimately calling x509_put().
+ */
+int x509_certificate ( const void *data, size_t len,
+ struct x509_certificate **cert ) {
+ struct asn1_cursor cursor;
+ void *raw;
+ int rc;
+
+ /* Initialise cursor */
+ cursor.data = data;
+ cursor.len = len;
+ asn1_shrink_any ( &cursor );
+
+ /* Return stored certificate, if present */
+ if ( ( *cert = certstore_find ( &cursor ) ) != NULL ) {
+
+ /* Add caller's reference */
+ x509_get ( *cert );
+ return 0;
+ }
+
+ /* Allocate and initialise certificate */
+ *cert = zalloc ( sizeof ( **cert ) + cursor.len );
+ if ( ! *cert )
+ return -ENOMEM;
+ ref_init ( &(*cert)->refcnt, NULL );
+ raw = ( *cert + 1 );
+
+ /* Copy raw data */
+ memcpy ( raw, cursor.data, cursor.len );
+ cursor.data = raw;
+
+ /* Parse certificate */
+ if ( ( rc = x509_parse ( *cert, &cursor ) ) != 0 ) {
+ x509_put ( *cert );
+ *cert = NULL;
+ return rc;
+ }
+
+ /* Add certificate to store */
+ certstore_add ( *cert );
+
+ return 0;
+}
+
+/**
+ * Check X.509 certificate signature
+ *
+ * @v cert X.509 certificate
+ * @v public_key X.509 public key
+ * @ret rc Return status code
+ */
+static int x509_check_signature ( struct x509_certificate *cert,
+ struct x509_public_key *public_key ) {
+ struct x509_signature *signature = &cert->signature;
+ struct asn1_algorithm *algorithm = signature->algorithm;
+ struct digest_algorithm *digest = algorithm->digest;
+ struct pubkey_algorithm *pubkey = algorithm->pubkey;
+ uint8_t digest_ctx[ digest->ctxsize ];
+ uint8_t digest_out[ digest->digestsize ];
+ uint8_t pubkey_ctx[ pubkey->ctxsize ];
+ int rc;
+
+ /* Sanity check */
+ assert ( cert->signature_algorithm == cert->signature.algorithm );
+
+ /* Calculate certificate digest */
+ digest_init ( digest, digest_ctx );
+ digest_update ( digest, digest_ctx, cert->tbs.data, cert->tbs.len );
+ digest_final ( digest, digest_ctx, digest_out );
+ DBGC2 ( cert, "X509 %p \"%s\" digest:\n", cert, x509_name ( cert ) );
+ DBGC2_HDA ( cert, 0, digest_out, sizeof ( digest_out ) );
+
+ /* Check that signature public key algorithm matches signer */
+ if ( public_key->algorithm->pubkey != pubkey ) {
+ DBGC ( cert, "X509 %p \"%s\" signature algorithm %s does not "
+ "match signer's algorithm %s\n",
+ cert, x509_name ( cert ), algorithm->name,
+ public_key->algorithm->name );
+ rc = -EINVAL_ALGORITHM_MISMATCH;
+ goto err_mismatch;
+ }
+
+ /* Verify signature using signer's public key */
+ if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data,
+ public_key->raw.len ) ) != 0 ) {
+ DBGC ( cert, "X509 %p \"%s\" cannot initialise public key: "
+ "%s\n", cert, x509_name ( cert ), strerror ( rc ) );
+ goto err_pubkey_init;
+ }
+ if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out,
+ signature->value.data,
+ signature->value.len ) ) != 0 ) {
+ DBGC ( cert, "X509 %p \"%s\" signature verification failed: "
+ "%s\n", cert, x509_name ( cert ), strerror ( rc ) );
+ goto err_pubkey_verify;
+ }
+
+ /* Success */
+ rc = 0;
+
+ err_pubkey_verify:
+ pubkey_final ( pubkey, pubkey_ctx );
+ err_pubkey_init:
+ err_mismatch:
+ return rc;
+}
+
+/**
+ * Check X.509 certificate against issuer certificate
+ *
+ * @v cert X.509 certificate
+ * @v issuer X.509 issuer certificate
+ * @ret rc Return status code
+ */
+int x509_check_issuer ( struct x509_certificate *cert,
+ struct x509_certificate *issuer ) {
+ struct x509_public_key *public_key = &issuer->subject.public_key;
+ int rc;
+
+ /* Check issuer. In theory, this should be a full X.500 DN
+ * comparison, which would require support for a plethora of
+ * abominations such as TeletexString (which allows the
+ * character set to be changed mid-string using escape codes).
+ * In practice, we assume that anyone who deliberately changes
+ * the encoding of the issuer DN is probably a masochist who
+ * will rather enjoy the process of figuring out exactly why
+ * their certificate doesn't work.
+ *
+ * See http://www.cs.auckland.ac.nz/~pgut001/pubs/x509guide.txt
+ * for some enjoyable ranting on this subject.
+ */
+ if ( asn1_compare ( &cert->issuer.raw, &issuer->subject.raw ) != 0 ) {
+ DBGC ( cert, "X509 %p \"%s\" issuer does not match ",
+ cert, x509_name ( cert ) );
+ DBGC ( cert, "X509 %p \"%s\" subject\n",
+ issuer, x509_name ( issuer ) );
+ DBGC_HDA ( cert, 0, cert->issuer.raw.data,
+ cert->issuer.raw.len );
+ DBGC_HDA ( issuer, 0, issuer->subject.raw.data,
+ issuer->subject.raw.len );
+ return -EACCES_WRONG_ISSUER;
+ }
+
+ /* Check that issuer is allowed to sign certificates */
+ if ( ! issuer->extensions.basic.ca ) {
+ DBGC ( issuer, "X509 %p \"%s\" cannot sign ",
+ issuer, x509_name ( issuer ) );
+ DBGC ( issuer, "X509 %p \"%s\": not a CA certificate\n",
+ cert, x509_name ( cert ) );
+ return -EACCES_NOT_CA;
+ }
+ if ( issuer->extensions.usage.present &&
+ ( ! ( issuer->extensions.usage.bits & X509_KEY_CERT_SIGN ) ) ) {
+ DBGC ( issuer, "X509 %p \"%s\" cannot sign ",
+ issuer, x509_name ( issuer ) );
+ DBGC ( issuer, "X509 %p \"%s\": no keyCertSign usage\n",
+ cert, x509_name ( cert ) );
+ return -EACCES_KEY_USAGE;
+ }
+
+ /* Check signature */
+ if ( ( rc = x509_check_signature ( cert, public_key ) ) != 0 )
+ return rc;
+
+ return 0;
+}
+
+/**
+ * Calculate X.509 certificate fingerprint
+ *
+ * @v cert X.509 certificate
+ * @v digest Digest algorithm
+ * @v fingerprint Fingerprint buffer
+ */
+void x509_fingerprint ( struct x509_certificate *cert,
+ struct digest_algorithm *digest,
+ void *fingerprint ) {
+ uint8_t ctx[ digest->ctxsize ];
+
+ /* Calculate fingerprint */
+ digest_init ( digest, ctx );
+ digest_update ( digest, ctx, cert->raw.data, cert->raw.len );
+ digest_final ( digest, ctx, fingerprint );
+}
+
+/**
+ * Check X.509 root certificate
+ *
+ * @v cert X.509 certificate
+ * @v root X.509 root certificate list
+ * @ret rc Return status code
+ */
+int x509_check_root ( struct x509_certificate *cert, struct x509_root *root ) {
+ struct digest_algorithm *digest = root->digest;
+ uint8_t fingerprint[ digest->digestsize ];
+ const uint8_t *root_fingerprint = root->fingerprints;
+ unsigned int i;
+
+ /* Calculate certificate fingerprint */
+ x509_fingerprint ( cert, digest, fingerprint );
+
+ /* Check fingerprint against all root certificates */
+ for ( i = 0 ; i < root->count ; i++ ) {
+ if ( memcmp ( fingerprint, root_fingerprint,
+ sizeof ( fingerprint ) ) == 0 ) {
+ DBGC ( cert, "X509 %p \"%s\" is a root certificate\n",
+ cert, x509_name ( cert ) );
+ return 0;
+ }
+ root_fingerprint += sizeof ( fingerprint );
+ }
+
+ DBGC2 ( cert, "X509 %p \"%s\" is not a root certificate\n",
+ cert, x509_name ( cert ) );
+ return -ENOENT;
+}
+
+/**
+ * Check X.509 certificate validity period
+ *
+ * @v cert X.509 certificate
+ * @v time Time at which to check certificate
+ * @ret rc Return status code
+ */
+int x509_check_time ( struct x509_certificate *cert, time_t time ) {
+ struct x509_validity *validity = &cert->validity;
+
+ /* Check validity period */
+ if ( validity->not_before.time > ( time + TIMESTAMP_ERROR_MARGIN ) ) {
+ DBGC ( cert, "X509 %p \"%s\" is not yet valid (at time %lld)\n",
+ cert, x509_name ( cert ), time );
+ return -EACCES_EXPIRED;
+ }
+ if ( validity->not_after.time < ( time - TIMESTAMP_ERROR_MARGIN ) ) {
+ DBGC ( cert, "X509 %p \"%s\" has expired (at time %lld)\n",
+ cert, x509_name ( cert ), time );
+ return -EACCES_EXPIRED;
+ }
+
+ DBGC2 ( cert, "X509 %p \"%s\" is valid (at time %lld)\n",
+ cert, x509_name ( cert ), time );
+ return 0;
+}
+
+/**
+ * Validate X.509 certificate
+ *
+ * @v cert X.509 certificate
+ * @v issuer Issuing X.509 certificate (or NULL)
+ * @v time Time at which to validate certificate
+ * @v root Root certificate list, or NULL to use default
+ * @ret rc Return status code
+ *
+ * The issuing certificate must have already been validated.
+ *
+ * Validation results are cached: if a certificate has already been
+ * successfully validated then @c issuer, @c time, and @c root will be
+ * ignored.
+ */
+int x509_validate ( struct x509_certificate *cert,
+ struct x509_certificate *issuer,
+ time_t time, struct x509_root *root ) {
+ unsigned int max_path_remaining;
+ int rc;
+
+ /* Use default root certificate store if none specified */
+ if ( ! root )
+ root = &root_certificates;
+
+ /* Return success if certificate has already been validated */
+ if ( cert->valid )
+ return 0;
+
+ /* Fail if certificate is invalid at specified time */
+ if ( ( rc = x509_check_time ( cert, time ) ) != 0 )
+ return rc;
+
+ /* Succeed if certificate is a trusted root certificate */
+ if ( x509_check_root ( cert, root ) == 0 ) {
+ cert->valid = 1;
+ cert->path_remaining = ( cert->extensions.basic.path_len + 1 );
+ return 0;
+ }
+
+ /* Fail unless we have an issuer */
+ if ( ! issuer ) {
+ DBGC2 ( cert, "X509 %p \"%s\" has no issuer\n",
+ cert, x509_name ( cert ) );
+ return -EACCES_UNTRUSTED;
+ }
+
+ /* Fail unless issuer has already been validated */
+ if ( ! issuer->valid ) {
+ DBGC ( cert, "X509 %p \"%s\" ", cert, x509_name ( cert ) );
+ DBGC ( cert, "issuer %p \"%s\" has not yet been validated\n",
+ issuer, x509_name ( issuer ) );
+ return -EACCES_OUT_OF_ORDER;
+ }
+
+ /* Fail if issuing certificate cannot validate this certificate */
+ if ( ( rc = x509_check_issuer ( cert, issuer ) ) != 0 )
+ return rc;
+
+ /* Fail if path length constraint is violated */
+ if ( issuer->path_remaining == 0 ) {
+ DBGC ( cert, "X509 %p \"%s\" ", cert, x509_name ( cert ) );
+ DBGC ( cert, "issuer %p \"%s\" path length exceeded\n",
+ issuer, x509_name ( issuer ) );
+ return -EACCES_PATH_LEN;
+ }
+
+ /* Fail if OCSP is required */
+ if ( cert->extensions.auth_info.ocsp.uri.len &&
+ ( ! cert->extensions.auth_info.ocsp.good ) ) {
+ DBGC ( cert, "X509 %p \"%s\" requires an OCSP check\n",
+ cert, x509_name ( cert ) );
+ return -EACCES_OCSP_REQUIRED;
+ }
+
+ /* Calculate effective path length */
+ cert->path_remaining = ( issuer->path_remaining - 1 );
+ max_path_remaining = ( cert->extensions.basic.path_len + 1 );
+ if ( cert->path_remaining > max_path_remaining )
+ cert->path_remaining = max_path_remaining;
+
+ /* Mark certificate as valid */
+ cert->valid = 1;
+
+ DBGC ( cert, "X509 %p \"%s\" successfully validated using ",
+ cert, x509_name ( cert ) );
+ DBGC ( cert, "issuer %p \"%s\"\n", issuer, x509_name ( issuer ) );
+ return 0;
+}
+
+/**
+ * Check X.509 certificate alternative dNSName
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @v name Name
+ * @ret rc Return status code
+ */
+static int x509_check_dnsname ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw,
+ const char *name ) {
+ const char *fullname = name;
+ const char *dnsname = raw->data;
+ size_t len = raw->len;
+
+ /* Check for wildcards */
+ if ( ( len >= 2 ) && ( dnsname[0] == '*' ) && ( dnsname[1] == '.' ) ) {
+
+ /* Skip initial "*." */
+ dnsname += 2;
+ len -= 2;
+
+ /* Skip initial portion of name to be tested */
+ name = strchr ( name, '.' );
+ if ( ! name )
+ return -ENOENT;
+ name++;
+ }
+
+ /* Compare names */
+ if ( ! ( ( strlen ( name ) == len ) &&
+ ( memcmp ( name, dnsname, len ) == 0 ) ) )
+ return -ENOENT;
+
+ if ( name != fullname ) {
+ DBGC2 ( cert, "X509 %p \"%s\" found wildcard match for "
+ "\"*.%s\"\n", cert, x509_name ( cert ), name );
+ }
+ return 0;
+}
+
+/**
+ * Check X.509 certificate alternative iPAddress
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @v name Name
+ * @ret rc Return status code
+ */
+static int x509_check_ipaddress ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw,
+ const char *name ) {
+ struct sockaddr sa;
+ sa_family_t family;
+ const void *address;
+ int rc;
+
+ /* Determine address family */
+ if ( raw->len == sizeof ( struct in_addr ) ) {
+ struct sockaddr_in *sin = ( ( struct sockaddr_in * ) &sa );
+ family = AF_INET;
+ address = &sin->sin_addr;
+ } else if ( raw->len == sizeof ( struct in6_addr ) ) {
+ struct sockaddr_in6 *sin6 = ( ( struct sockaddr_in6 * ) &sa );
+ family = AF_INET6;
+ address = &sin6->sin6_addr;
+ } else {
+ DBGC ( cert, "X509 %p \"%s\" has iPAddress with unexpected "
+ "length %zd\n", cert, x509_name ( cert ), raw->len );
+ DBGC_HDA ( cert, 0, raw->data, raw->len );
+ return -EINVAL;
+ }
+
+ /* Attempt to convert name to a socket address */
+ if ( ( rc = sock_aton ( name, &sa ) ) != 0 ) {
+ DBGC2 ( cert, "X509 %p \"%s\" cannot parse \"%s\" as "
+ "iPAddress: %s\n", cert, x509_name ( cert ), name,
+ strerror ( rc ) );
+ return rc;
+ }
+ if ( sa.sa_family != family )
+ return -ENOENT;
+
+ /* Compare addresses */
+ if ( memcmp ( address, raw->data, raw->len ) != 0 )
+ return -ENOENT;
+
+ DBGC2 ( cert, "X509 %p \"%s\" found iPAddress match for \"%s\"\n",
+ cert, x509_name ( cert ), sock_ntoa ( &sa ) );
+ return 0;
+}
+
+/**
+ * Check X.509 certificate alternative name
+ *
+ * @v cert X.509 certificate
+ * @v raw ASN.1 cursor
+ * @v name Name
+ * @ret rc Return status code
+ */
+static int x509_check_alt_name ( struct x509_certificate *cert,
+ const struct asn1_cursor *raw,
+ const char *name ) {
+ struct asn1_cursor alt_name;
+ unsigned int type;
+
+ /* Enter generalName */
+ memcpy ( &alt_name, raw, sizeof ( alt_name ) );
+ type = asn1_type ( &alt_name );
+ asn1_enter_any ( &alt_name );
+
+ /* Check this name */
+ switch ( type ) {
+ case X509_GENERAL_NAME_DNS :
+ return x509_check_dnsname ( cert, &alt_name, name );
+ case X509_GENERAL_NAME_IP :
+ return x509_check_ipaddress ( cert, &alt_name, name );
+ default:
+ DBGC2 ( cert, "X509 %p \"%s\" unknown name of type %#02x:\n",
+ cert, x509_name ( cert ), type );
+ DBGC2_HDA ( cert, 0, alt_name.data, alt_name.len );
+ return -ENOTSUP;
+ }
+}
+
+/**
+ * Check X.509 certificate name
+ *
+ * @v cert X.509 certificate
+ * @v name Name
+ * @ret rc Return status code
+ */
+int x509_check_name ( struct x509_certificate *cert, const char *name ) {
+ struct asn1_cursor *common_name = &cert->subject.common_name;
+ struct asn1_cursor alt_name;
+ int rc;
+
+ /* Check commonName */
+ if ( x509_check_dnsname ( cert, common_name, name ) == 0 ) {
+ DBGC2 ( cert, "X509 %p \"%s\" commonName matches \"%s\"\n",
+ cert, x509_name ( cert ), name );
+ return 0;
+ }
+
+ /* Check any subjectAlternativeNames */
+ memcpy ( &alt_name, &cert->extensions.alt_name.names,
+ sizeof ( alt_name ) );
+ for ( ; alt_name.len ; asn1_skip_any ( &alt_name ) ) {
+ if ( ( rc = x509_check_alt_name ( cert, &alt_name,
+ name ) ) == 0 ) {
+ DBGC2 ( cert, "X509 %p \"%s\" subjectAltName matches "
+ "\"%s\"\n", cert, x509_name ( cert ), name );
+ return 0;
+ }
+ }
+
+ DBGC ( cert, "X509 %p \"%s\" does not match name \"%s\"\n",
+ cert, x509_name ( cert ), name );
+ return -EACCES_WRONG_NAME;
+}
+
+/**
+ * Free X.509 certificate chain
+ *
+ * @v refcnt Reference count
+ */
+static void x509_free_chain ( struct refcnt *refcnt ) {
+ struct x509_chain *chain =
+ container_of ( refcnt, struct x509_chain, refcnt );
+ struct x509_link *link;
+ struct x509_link *tmp;
+
+ DBGC2 ( chain, "X509 chain %p freed\n", chain );
+
+ /* Free each link in the chain */
+ list_for_each_entry_safe ( link, tmp, &chain->links, list ) {
+ x509_put ( link->cert );
+ list_del ( &link->list );
+ free ( link );
+ }
+
+ /* Free chain */
+ free ( chain );
+}
+
+/**
+ * Allocate X.509 certificate chain
+ *
+ * @ret chain X.509 certificate chain, or NULL
+ */
+struct x509_chain * x509_alloc_chain ( void ) {
+ struct x509_chain *chain;
+
+ /* Allocate chain */
+ chain = zalloc ( sizeof ( *chain ) );
+ if ( ! chain )
+ return NULL;
+
+ /* Initialise chain */
+ ref_init ( &chain->refcnt, x509_free_chain );
+ INIT_LIST_HEAD ( &chain->links );
+
+ DBGC2 ( chain, "X509 chain %p allocated\n", chain );
+ return chain;
+}
+
+/**
+ * Append X.509 certificate to X.509 certificate chain
+ *
+ * @v chain X.509 certificate chain
+ * @v cert X.509 certificate
+ * @ret rc Return status code
+ */
+int x509_append ( struct x509_chain *chain, struct x509_certificate *cert ) {
+ struct x509_link *link;
+
+ /* Allocate link */
+ link = zalloc ( sizeof ( *link ) );
+ if ( ! link )
+ return -ENOMEM;
+
+ /* Add link to chain */
+ link->cert = x509_get ( cert );
+ list_add_tail ( &link->list, &chain->links );
+ DBGC ( chain, "X509 chain %p added X509 %p \"%s\"\n",
+ chain, cert, x509_name ( cert ) );
+
+ return 0;
+}
+
+/**
+ * Append X.509 certificate to X.509 certificate chain
+ *
+ * @v chain X.509 certificate chain
+ * @v data Raw certificate data
+ * @v len Length of raw data
+ * @ret rc Return status code
+ */
+int x509_append_raw ( struct x509_chain *chain, const void *data,
+ size_t len ) {
+ struct x509_certificate *cert;
+ int rc;
+
+ /* Parse certificate */
+ if ( ( rc = x509_certificate ( data, len, &cert ) ) != 0 )
+ goto err_parse;
+
+ /* Append certificate to chain */
+ if ( ( rc = x509_append ( chain, cert ) ) != 0 )
+ goto err_append;
+
+ /* Drop reference to certificate */
+ x509_put ( cert );
+
+ return 0;
+
+ err_append:
+ x509_put ( cert );
+ err_parse:
+ return rc;
+}
+
+/**
+ * Identify X.509 certificate by subject
+ *
+ * @v certs X.509 certificate list
+ * @v subject Subject
+ * @ret cert X.509 certificate, or NULL if not found
+ */
+static struct x509_certificate *
+x509_find_subject ( struct x509_chain *certs,
+ const struct asn1_cursor *subject ) {
+ struct x509_link *link;
+ struct x509_certificate *cert;
+
+ /* Scan through certificate list */
+ list_for_each_entry ( link, &certs->links, list ) {
+
+ /* Check subject */
+ cert = link->cert;
+ if ( asn1_compare ( subject, &cert->subject.raw ) == 0 )
+ return cert;
+ }
+
+ return NULL;
+}
+
+/**
+ * Append X.509 certificates to X.509 certificate chain
+ *
+ * @v chain X.509 certificate chain
+ * @v certs X.509 certificate list
+ * @ret rc Return status code
+ *
+ * Certificates will be automatically appended to the chain based upon
+ * the subject and issuer names.
+ */
+int x509_auto_append ( struct x509_chain *chain, struct x509_chain *certs ) {
+ struct x509_certificate *cert;
+ struct x509_certificate *previous;
+ int rc;
+
+ /* Get current certificate */
+ cert = x509_last ( chain );
+ if ( ! cert ) {
+ DBGC ( chain, "X509 chain %p has no certificates\n", chain );
+ return -EACCES_EMPTY;
+ }
+
+ /* Append certificates, in order */
+ while ( 1 ) {
+
+ /* Find issuing certificate */
+ previous = cert;
+ cert = x509_find_subject ( certs, &cert->issuer.raw );
+ if ( ! cert )
+ break;
+ if ( cert == previous )
+ break;
+
+ /* Append certificate to chain */
+ if ( ( rc = x509_append ( chain, cert ) ) != 0 )
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Validate X.509 certificate chain
+ *
+ * @v chain X.509 certificate chain
+ * @v time Time at which to validate certificates
+ * @v store Certificate store, or NULL to use default
+ * @v root Root certificate list, or NULL to use default
+ * @ret rc Return status code
+ */
+int x509_validate_chain ( struct x509_chain *chain, time_t time,
+ struct x509_chain *store, struct x509_root *root ) {
+ struct x509_certificate *issuer = NULL;
+ struct x509_link *link;
+ int rc;
+
+ /* Use default certificate store if none specified */
+ if ( ! store )
+ store = &certstore;
+
+ /* Append any applicable certificates from the certificate store */
+ if ( ( rc = x509_auto_append ( chain, store ) ) != 0 )
+ return rc;
+
+ /* Find first certificate that can be validated as a
+ * standalone (i.e. is already valid, or can be validated as
+ * a trusted root certificate).
+ */
+ list_for_each_entry ( link, &chain->links, list ) {
+
+ /* Try validating this certificate as a standalone */
+ if ( ( rc = x509_validate ( link->cert, NULL, time,
+ root ) ) != 0 )
+ continue;
+
+ /* Work back up to start of chain, performing pairwise
+ * validation.
+ */
+ issuer = link->cert;
+ list_for_each_entry_continue_reverse ( link, &chain->links,
+ list ) {
+
+ /* Validate this certificate against its issuer */
+ if ( ( rc = x509_validate ( link->cert, issuer, time,
+ root ) ) != 0 )
+ return rc;
+ issuer = link->cert;
+ }
+
+ return 0;
+ }
+
+ DBGC ( chain, "X509 chain %p found no usable certificates\n", chain );
+ return -EACCES_USELESS;
+}
+
+/* Drag in certificate store */
+REQUIRE_OBJECT ( certstore );