From c9b1ebc10bea80b7be294d75cada90c668b14ed6 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 9 Nov 2009 17:13:17 +0100 Subject: [PATCH 01/28] First try to gcry glue --- conf/common.rmk | 2 + conf/gcry.rmk | 52 +++++++++++++++ conf/i386-pc.rmk | 4 +- import_gcry.py | 136 ++++++++++++++++++++++++++++++++++++++ include/grub/crypto.h | 138 +++++++++++++++++++++++++++++++++++++++ include/grub/gcry_wrap.h | 36 ++++++++++ kern/crypto.c | 34 ++++++++++ 7 files changed, 401 insertions(+), 1 deletion(-) create mode 100644 conf/gcry.rmk create mode 100644 import_gcry.py create mode 100644 include/grub/crypto.h create mode 100644 include/grub/gcry_wrap.h create mode 100644 kern/crypto.c diff --git a/conf/common.rmk b/conf/common.rmk index e1ac5274c..0d19344a7 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -618,3 +618,5 @@ pkglib_MODULES += setjmp.mod setjmp_mod_SOURCES = lib/$(target_cpu)/setjmp.S setjmp_mod_ASFLAGS = $(COMMON_ASFLAGS) setjmp_mod_LDFLAGS = $(COMMON_LDFLAGS) + +include $(srcdir)/conf/gcry.mk diff --git a/conf/gcry.rmk b/conf/gcry.rmk new file mode 100644 index 000000000..0eb3c79bc --- /dev/null +++ b/conf/gcry.rmk @@ -0,0 +1,52 @@ +# -*- makefile -*- + +pkglib_MODULES += seed.mod +seed_mod_SOURCES = gcry/cipher/seed.c +seed_mod_ASFLAGS = $(COMMON_ASFLAGS) +seed_mod_LDFLAGS = $(COMMON_ASFLAGS) + +pkglib_MODULES += twofish.mod +twofish_mod_SOURCES = gcry/cipher/twofish.c +twofish_mod_ASFLAGS = $(COMMON_ASFLAGS) +twofish_mod_LDFLAGS = $(COMMON_ASFLAGS) + +pkglib_MODULES += des.mod +des_mod_SOURCES = gcry/cipher/des.c +des_mod_ASFLAGS = $(COMMON_ASFLAGS) +des_mod_LDFLAGS = $(COMMON_ASFLAGS) + +pkglib_MODULES += arcfour.mod +arcfour_mod_SOURCES = gcry/cipher/arcfour.c +arcfour_mod_ASFLAGS = $(COMMON_ASFLAGS) +arcfour_mod_LDFLAGS = $(COMMON_ASFLAGS) + +pkglib_MODULES += rfc2268.mod +rfc2268_mod_SOURCES = gcry/cipher/rfc2268.c +rfc2268_mod_ASFLAGS = $(COMMON_ASFLAGS) +rfc2268_mod_LDFLAGS = $(COMMON_ASFLAGS) + +pkglib_MODULES += cast5.mod +cast5_mod_SOURCES = gcry/cipher/cast5.c +cast5_mod_ASFLAGS = $(COMMON_ASFLAGS) +cast5_mod_LDFLAGS = $(COMMON_ASFLAGS) + +pkglib_MODULES += camellia-glue.mod +camellia-glue_mod_SOURCES = gcry/cipher/camellia-glue.c +camellia-glue_mod_ASFLAGS = $(COMMON_ASFLAGS) +camellia-glue_mod_LDFLAGS = $(COMMON_ASFLAGS) + +pkglib_MODULES += rijndael.mod +rijndael_mod_SOURCES = gcry/cipher/rijndael.c +rijndael_mod_ASFLAGS = $(COMMON_ASFLAGS) +rijndael_mod_LDFLAGS = $(COMMON_ASFLAGS) + +pkglib_MODULES += serpent.mod +serpent_mod_SOURCES = gcry/cipher/serpent.c +serpent_mod_ASFLAGS = $(COMMON_ASFLAGS) +serpent_mod_LDFLAGS = $(COMMON_ASFLAGS) + +pkglib_MODULES += blowfish.mod +blowfish_mod_SOURCES = gcry/cipher/blowfish.c +blowfish_mod_ASFLAGS = $(COMMON_ASFLAGS) +blowfish_mod_LDFLAGS = $(COMMON_ASFLAGS) + diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 373b942cc..0e3291782 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -58,13 +58,15 @@ kernel_img_SOURCES = kern/i386/pc/startup.S \ kern/generic/millisleep.c \ kern/env.c \ term/i386/pc/console.c term/i386/vga_common.c \ + kern/crypto.c \ symlist.c kernel_img_HEADERS = boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ partition.h msdos_partition.h reader.h symbol.h term.h time.h types.h \ machine/biosdisk.h machine/boot.h machine/console.h machine/init.h \ machine/memory.h machine/loader.h machine/vga.h machine/vbe.h \ - machine/kernel.h machine/pxe.h i386/pit.h list.h handler.h command.h + machine/kernel.h machine/pxe.h i386/pit.h list.h handler.h command.h \ + crypto.h kernel_img_CFLAGS = $(COMMON_CFLAGS) $(TARGET_IMG_CFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS) kernel_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)$(GRUB_KERNEL_MACHINE_LINK_ADDR) $(COMMON_CFLAGS) diff --git a/import_gcry.py b/import_gcry.py new file mode 100644 index 000000000..c751f5e6f --- /dev/null +++ b/import_gcry.py @@ -0,0 +1,136 @@ +import re +import sys +import os +import datetime + +if len (sys.argv) < 3: + print ("Usage: %s SOURCE DESTINATION" % sys.argv[0]) + exit (0) +indir = sys.argv[1] +outdir = sys.argv[2] + +basedir = os.path.join (outdir, "gcry") +os.makedirs (basedir) +cipher_dir_in = os.path.join (indir, "cipher") +cipher_dir_out = os.path.join (basedir, "cipher") +os.makedirs (cipher_dir_out) +cipher_files = os.listdir (cipher_dir_in) +conf = open (os.path.join (outdir, "conf", "gcry.rmk"), "w") +conf.write ("# -*- makefile -*-\n\n") +chlog = "" + +for cipher_file in cipher_files: + infile = os.path.join (cipher_dir_in, cipher_file) + outfile = os.path.join (cipher_dir_out, cipher_file) + if cipher_file == "ChangeLog": + continue + chlognew = " * %s" % cipher_file + nch = False + if re.match (".*\.[ch]$", cipher_file): + isc = re.match (".*\.c$", cipher_file) + f = open (infile, "r") + fw = open (outfile, "w") + fw.write ("/* This file was automatically imported with \n") + fw.write (" import_gcry.py. Please don't modify it */\n"); + ciphernames = [] + for line in f: + m = re.match ("#include <.*>", line) + if not m is None: + chmsg = "Removed including of %s" % \ + m.group () [len ("#include <"):len (m.group ()) - 1] + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s: %s" % (chlognew, chmsg) + nch = True + continue + m = re.match ("gcry_cipher_spec_t", line) + if isc and not m is None: + ciphername = line [len ("gcry_cipher_spec_t"):].strip () + ciphername = re.match("[a-zA-Z0-9_]*",ciphername).group () + ciphernames.append (ciphername) + fw.write (line) + if len (ciphernames) > 0: + modname = cipher_file [0:len(cipher_file) - 2] + chmsg = "(GRUB_MOD_INIT(%s)): New function\n" % modname + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s%s" % (chlognew, chmsg) + nch = True + fw.write ("\n\nGRUB_MOD_INIT(%s)\n" % modname) + fw.write ("{\n") + for ciphername in ciphernames: + chmsg = "Register cipher %s" % ciphername + chlognew = "%s\n %s" % (chlognew, chmsg) + fw.write (" grub_cipher_register (&%s);\n" % ciphername) + fw.write ("}") + chmsg = "(GRUB_MOD_FINI(%s)): New function\n" % modname + chlognew = "%s\n %s" % (chlognew, chmsg) + fw.write ("\n\nGRUB_MOD_FINI(%s)\n" % modname) + fw.write ("{\n") + for ciphername in ciphernames: + chmsg = "Unregister cipher %s" % ciphername + chlognew = "%s\n %s" % (chlognew, chmsg) + fw.write (" grub_cipher_unregister (&%s);\n" % ciphername) + fw.write ("}\n") + conf.write ("pkglib_MODULES += %s.mod\n" % modname) + conf.write ("%s_mod_SOURCES = gcry/cipher/%s\n" %\ + (modname, cipher_file)) + conf.write ("%s_mod_CFLAGS = $(COMMON_CFLAGS) -Wno-error\n" % modname) + conf.write ("%s_mod_LDFLAGS = $(COMMON_ASFLAGS)\n\n" % modname) + elif isc: + print ("WARNING: c file isn't a module: %s" % cipher_file) + f.close () + fw.close () + if nch: + chlog = "%s%s\n" % (chlog, chlognew) + continue + if re.match ("(Manifest|Makefile\.am)$", cipher_file): + chlog = "%s%sRemoved\n" % (chlog, chlognew) + continue + # Autogenerated files. Not even worth mentionning in ChangeLog + if re.match ("Makefile\.in$", cipher_file): + chlog = "%s%sRemoved\n" % (chlog, chlognew) + continue + chlog = "%s%sSkipped unknown file\n" % (chlog, chlognew) + print ("WARNING: unknown file %s" % cipher_file) + +outfile = os.path.join (cipher_dir_out, "types.h") +fw=open (outfile, "w") +fw.write ("#include \n") +fw.write ("#include \n") +chlog = "%s * types.h: New file.\n" % chlog +fw.close () + +outfile = os.path.join (cipher_dir_out, "cipher.h") +fw=open (outfile, "w") +fw.write ("#include \n") +fw.write ("#include \n") +chlog = "%s * cipher.h: Likewise.\n" % chlog +fw.close () + +outfile = os.path.join (cipher_dir_out, "g10lib.h") +fw=open (outfile, "w") +fw.write ("#include \n") +chlog = "%s * g10lib.h: Likewise.\n" % chlog +fw.close () + +infile = os.path.join (cipher_dir_in, "ChangeLog") +outfile = os.path.join (cipher_dir_out, "ChangeLog") + + +f=open (infile, "r") +fw=open (outfile, "w") +dt = datetime.date.today () +fw.write ("%04d-%02d-%02d Automatic import tool\n" % \ + (dt.year,dt.month, dt.day)) +fw.write ("\n") +fw.write (" Imported ciphers to GRUB\n") +fw.write ("\n") +fw.write (chlog) +fw.write ("\n") +for line in f: + fw.write (line) +f.close () +fw.close () diff --git a/include/grub/crypto.h b/include/grub/crypto.h new file mode 100644 index 000000000..36503c1a1 --- /dev/null +++ b/include/grub/crypto.h @@ -0,0 +1,138 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006 + * 2007, 2008, 2009 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +/* Contains elements based on gcrypt-module.h and gcrypt.h.in. + If it's changed please update this file. */ + +#ifndef GRUB_CIPHER_HEADER +#define GRUB_CIPHER_HEADER 1 + +#include +#include + +typedef enum + { + GPG_ERR_NO_ERROR, + GPG_ERR_BAD_MPI, + GPG_ERR_BAD_SECKEY, + GPG_ERR_BAD_SIGNATURE, + GPG_ERR_CIPHER_ALGO, + GPG_ERR_CONFLICT, + GPG_ERR_DECRYPT_FAILED, + GPG_ERR_DIGEST_ALGO, + GPG_ERR_GENERAL, + GPG_ERR_INTERNAL, + GPG_ERR_INV_ARG, + GPG_ERR_INV_CIPHER_MODE, + GPG_ERR_INV_FLAG, + GPG_ERR_INV_KEYLEN, + GPG_ERR_INV_OBJ, + GPG_ERR_INV_OP, + GPG_ERR_INV_SEXP, + GPG_ERR_INV_VALUE, + GPG_ERR_MISSING_VALUE, + GPG_ERR_NO_ENCRYPTION_SCHEME, + GPG_ERR_NO_OBJ, + GPG_ERR_NO_PRIME, + GPG_ERR_NO_SIGNATURE_SCHEME, + GPG_ERR_NOT_FOUND, + GPG_ERR_NOT_IMPLEMENTED, + GPG_ERR_NOT_SUPPORTED, + GPG_ERROR_CFLAGS, + GPG_ERR_PUBKEY_ALGO, + GPG_ERR_SELFTEST_FAILED, + GPG_ERR_TOO_SHORT, + GPG_ERR_UNSUPPORTED, + GPG_ERR_WEAK_KEY, + GPG_ERR_WRONG_KEY_USAGE, + GPG_ERR_WRONG_PUBKEY_ALGO, + } gcry_err_code_t; + +enum gcry_cipher_modes + { + GCRY_CIPHER_MODE_NONE = 0, /* Not yet specified. */ + GCRY_CIPHER_MODE_ECB = 1, /* Electronic codebook. */ + GCRY_CIPHER_MODE_CFB = 2, /* Cipher feedback. */ + GCRY_CIPHER_MODE_CBC = 3, /* Cipher block chaining. */ + GCRY_CIPHER_MODE_STREAM = 4, /* Used with stream ciphers. */ + GCRY_CIPHER_MODE_OFB = 5, /* Outer feedback. */ + GCRY_CIPHER_MODE_CTR = 6 /* Counter. */ + }; + +/* Type for the cipher_setkey function. */ +typedef gcry_err_code_t (*gcry_cipher_setkey_t) (void *c, + const unsigned char *key, + unsigned keylen); + +/* Type for the cipher_encrypt function. */ +typedef void (*gcry_cipher_encrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf); + +/* Type for the cipher_decrypt function. */ +typedef void (*gcry_cipher_decrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf); + +/* Type for the cipher_stencrypt function. */ +typedef void (*gcry_cipher_stencrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf, + unsigned int n); + +/* Type for the cipher_stdecrypt function. */ +typedef void (*gcry_cipher_stdecrypt_t) (void *c, + unsigned char *outbuf, + const unsigned char *inbuf, + unsigned int n); + +typedef struct gcry_cipher_oid_spec +{ + const char *oid; + int mode; +} gcry_cipher_oid_spec_t; + +/* Module specification structure for ciphers. */ +typedef struct gcry_cipher_spec +{ + const char *name; + const char **aliases; + gcry_cipher_oid_spec_t *oids; + grub_size_t blocksize; + grub_size_t keylen; + grub_size_t contextsize; + gcry_cipher_setkey_t setkey; + gcry_cipher_encrypt_t encrypt; + gcry_cipher_decrypt_t decrypt; + gcry_cipher_stencrypt_t stencrypt; + gcry_cipher_stdecrypt_t stdecrypt; +} gcry_cipher_spec_t; + +struct grub_cipher +{ + struct grub_cipher *next; + const char *name; +}; +typedef struct grub_cipher *grub_cipher_t; + +extern grub_cipher_t EXPORT_VAR (grub_ciphers); +void EXPORT_FUNC(grub_burn_stack) (grub_size_t size); + + +#endif diff --git a/include/grub/gcry_wrap.h b/include/grub/gcry_wrap.h new file mode 100644 index 000000000..364946d1b --- /dev/null +++ b/include/grub/gcry_wrap.h @@ -0,0 +1,36 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#ifndef GRUB_GCRY_WRAP_HEADER +#define GRUB_GCRY_WRAP_HEADER 1 + +#include +#include +#include +#include +#include + +typedef grub_uint32_t u32; +typedef grub_uint16_t u16; +typedef grub_uint8_t byte; +typedef grub_size_t size_t; + +#define _gcry_burn_stack grub_burn_stack +#define log_error(fmt, args...) grub_dprintf ("crypto", fmt, ## args) + +#endif diff --git a/kern/crypto.c b/kern/crypto.c new file mode 100644 index 000000000..7dd00c84d --- /dev/null +++ b/kern/crypto.c @@ -0,0 +1,34 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1999, 2001, 2002, 2003, 2007, + * 2008, 2009 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ +#include +#include + +grub_cipher_t grub_ciphers; + +/* Based on libgcrypt-1.4.4/src/misc.c. */ +void +grub_burn_stack (grub_size_t size) +{ + char buf[64]; + + grub_memset (buf, 0, sizeof (buf)); + size -= sizeof (buf); + if (size > 0) + grub_burn_stack (size); +} From 58806db8473505662ce9809a4ac996067808e7bf Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 9 Nov 2009 20:30:40 +0100 Subject: [PATCH 02/28] Improvements in headers --- conf/gcry.rmk | 52 ---------------------------------------- import_gcry.py | 4 ++-- include/grub/crypto.h | 48 +++++++++++++++++++++++++++++++++++++ include/grub/gcry_wrap.h | 2 ++ 4 files changed, 52 insertions(+), 54 deletions(-) delete mode 100644 conf/gcry.rmk diff --git a/conf/gcry.rmk b/conf/gcry.rmk deleted file mode 100644 index 0eb3c79bc..000000000 --- a/conf/gcry.rmk +++ /dev/null @@ -1,52 +0,0 @@ -# -*- makefile -*- - -pkglib_MODULES += seed.mod -seed_mod_SOURCES = gcry/cipher/seed.c -seed_mod_ASFLAGS = $(COMMON_ASFLAGS) -seed_mod_LDFLAGS = $(COMMON_ASFLAGS) - -pkglib_MODULES += twofish.mod -twofish_mod_SOURCES = gcry/cipher/twofish.c -twofish_mod_ASFLAGS = $(COMMON_ASFLAGS) -twofish_mod_LDFLAGS = $(COMMON_ASFLAGS) - -pkglib_MODULES += des.mod -des_mod_SOURCES = gcry/cipher/des.c -des_mod_ASFLAGS = $(COMMON_ASFLAGS) -des_mod_LDFLAGS = $(COMMON_ASFLAGS) - -pkglib_MODULES += arcfour.mod -arcfour_mod_SOURCES = gcry/cipher/arcfour.c -arcfour_mod_ASFLAGS = $(COMMON_ASFLAGS) -arcfour_mod_LDFLAGS = $(COMMON_ASFLAGS) - -pkglib_MODULES += rfc2268.mod -rfc2268_mod_SOURCES = gcry/cipher/rfc2268.c -rfc2268_mod_ASFLAGS = $(COMMON_ASFLAGS) -rfc2268_mod_LDFLAGS = $(COMMON_ASFLAGS) - -pkglib_MODULES += cast5.mod -cast5_mod_SOURCES = gcry/cipher/cast5.c -cast5_mod_ASFLAGS = $(COMMON_ASFLAGS) -cast5_mod_LDFLAGS = $(COMMON_ASFLAGS) - -pkglib_MODULES += camellia-glue.mod -camellia-glue_mod_SOURCES = gcry/cipher/camellia-glue.c -camellia-glue_mod_ASFLAGS = $(COMMON_ASFLAGS) -camellia-glue_mod_LDFLAGS = $(COMMON_ASFLAGS) - -pkglib_MODULES += rijndael.mod -rijndael_mod_SOURCES = gcry/cipher/rijndael.c -rijndael_mod_ASFLAGS = $(COMMON_ASFLAGS) -rijndael_mod_LDFLAGS = $(COMMON_ASFLAGS) - -pkglib_MODULES += serpent.mod -serpent_mod_SOURCES = gcry/cipher/serpent.c -serpent_mod_ASFLAGS = $(COMMON_ASFLAGS) -serpent_mod_LDFLAGS = $(COMMON_ASFLAGS) - -pkglib_MODULES += blowfish.mod -blowfish_mod_SOURCES = gcry/cipher/blowfish.c -blowfish_mod_ASFLAGS = $(COMMON_ASFLAGS) -blowfish_mod_LDFLAGS = $(COMMON_ASFLAGS) - diff --git a/import_gcry.py b/import_gcry.py index c751f5e6f..738c2c479 100644 --- a/import_gcry.py +++ b/import_gcry.py @@ -77,8 +77,8 @@ for cipher_file in cipher_files: conf.write ("pkglib_MODULES += %s.mod\n" % modname) conf.write ("%s_mod_SOURCES = gcry/cipher/%s\n" %\ (modname, cipher_file)) - conf.write ("%s_mod_CFLAGS = $(COMMON_CFLAGS) -Wno-error\n" % modname) - conf.write ("%s_mod_LDFLAGS = $(COMMON_ASFLAGS)\n\n" % modname) + conf.write ("%s_mod_CFLAGS = $(COMMON_CFLAGS) -Wno-missing-field-initializers -Wno-error\n" % modname) + conf.write ("%s_mod_LDFLAGS = $(COMMON_LDFLAGS)\n\n" % modname) elif isc: print ("WARNING: c file isn't a module: %s" % cipher_file) f.close () diff --git a/include/grub/crypto.h b/include/grub/crypto.h index 36503c1a1..ab482f467 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -63,6 +63,7 @@ typedef enum GPG_ERR_WRONG_KEY_USAGE, GPG_ERR_WRONG_PUBKEY_ALGO, } gcry_err_code_t; +#define gpg_err_code_t gcry_err_code_t enum gcry_cipher_modes { @@ -124,6 +125,53 @@ typedef struct gcry_cipher_spec gcry_cipher_stdecrypt_t stdecrypt; } gcry_cipher_spec_t; +/* Definition of a function used to report selftest failures. + DOMAIN is a string describing the function block: + "cipher", "digest", "pubkey or "random", + ALGO is the algorithm under test, + WHAT is a string describing what has been tested, + DESC is a string describing the error. */ +typedef void (*selftest_report_func_t)(const char *domain, + int algo, + const char *what, + const char *errdesc); + +/* Definition of the selftest functions. */ +typedef gpg_err_code_t (*selftest_func_t) + (int algo, int extended, selftest_report_func_t report); + +/* The type used to convey additional information to a cipher. */ +typedef gpg_err_code_t (*cipher_set_extra_info_t) + (void *c, int what, const void *buffer, grub_size_t buflen); + + +/* Extra module specification structures. These are used for internal + modules which provide more functions than available through the + public algorithm register APIs. */ +typedef struct cipher_extra_spec +{ + selftest_func_t selftest; + cipher_set_extra_info_t set_extra_info; +} cipher_extra_spec_t; + +/* (Forward declaration.) */ +struct gcry_md_context; + +/* This object is used to hold a handle to a message digest object. + This structure is private - only to be used by the public gcry_md_* + macros. */ +typedef struct gcry_md_handle +{ + /* Actual context. */ + struct gcry_md_context *ctx; + + /* Buffer management. */ + int bufpos; + int bufsize; + unsigned char buf[1]; +} *gcry_md_hd_t; + + struct grub_cipher { struct grub_cipher *next; diff --git a/include/grub/gcry_wrap.h b/include/grub/gcry_wrap.h index 364946d1b..6f415a2e5 100644 --- a/include/grub/gcry_wrap.h +++ b/include/grub/gcry_wrap.h @@ -25,6 +25,8 @@ #include #include +#define __GNU_LIBRARY__ + typedef grub_uint32_t u32; typedef grub_uint16_t u16; typedef grub_uint8_t byte; From 39f7c91b5088152adfd8a4e851a9d425125681b3 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 10 Nov 2009 01:01:11 +0100 Subject: [PATCH 03/28] base for ciphers and digests --- import_gcry.py | 31 ++++++++++++--- include/grub/crypto.h | 85 ++++++++++++++++++++++++++++++---------- include/grub/gcry_wrap.h | 33 ++++++++++++++++ kern/crypto.c | 4 +- 4 files changed, 126 insertions(+), 27 deletions(-) diff --git a/import_gcry.py b/import_gcry.py index 738c2c479..cc06142e6 100644 --- a/import_gcry.py +++ b/import_gcry.py @@ -33,6 +33,7 @@ for cipher_file in cipher_files: fw.write ("/* This file was automatically imported with \n") fw.write (" import_gcry.py. Please don't modify it */\n"); ciphernames = [] + mdnames = [] for line in f: m = re.match ("#include <.*>", line) if not m is None: @@ -49,9 +50,21 @@ for cipher_file in cipher_files: ciphername = line [len ("gcry_cipher_spec_t"):].strip () ciphername = re.match("[a-zA-Z0-9_]*",ciphername).group () ciphernames.append (ciphername) + m = re.match ("gcry_md_spec_t", line) + if isc and not m is None: + mdname = line [len ("gcry_md_spec_t"):].strip () + mdname = re.match("[a-zA-Z0-9_]*",mdname).group () + mdnames.append (mdname) fw.write (line) - if len (ciphernames) > 0: + if len (ciphernames) > 0 or len (mdnames) > 0: modname = cipher_file [0:len(cipher_file) - 2] + if re.match (".*-glue$", modname): + modfiles = "gcry/cipher/%s gcry/cipher/%s" \ + % (cipher_file, cipher_file.replace ("-glue.c", ".c")) + modname = modname.replace ("-glue", "") + else: + modfiles = "gcry/cipher/%s" % cipher_file + modname = "gcry_%s" % modname chmsg = "(GRUB_MOD_INIT(%s)): New function\n" % modname if nch: chlognew = "%s\n %s" % (chlognew, chmsg) @@ -64,6 +77,10 @@ for cipher_file in cipher_files: chmsg = "Register cipher %s" % ciphername chlognew = "%s\n %s" % (chlognew, chmsg) fw.write (" grub_cipher_register (&%s);\n" % ciphername) + for mdname in mdnames: + chmsg = "Register digest %s" % mdname + chlognew = "%s\n %s" % (chlognew, chmsg) + fw.write (" grub_md_register (&%s);\n" % mdname) fw.write ("}") chmsg = "(GRUB_MOD_FINI(%s)): New function\n" % modname chlognew = "%s\n %s" % (chlognew, chmsg) @@ -73,14 +90,18 @@ for cipher_file in cipher_files: chmsg = "Unregister cipher %s" % ciphername chlognew = "%s\n %s" % (chlognew, chmsg) fw.write (" grub_cipher_unregister (&%s);\n" % ciphername) + for mdname in mdnames: + chmsg = "Unregister MD %s" % mdname + chlognew = "%s\n %s" % (chlognew, chmsg) + fw.write (" grub_md_unregister (&%s);\n" % mdname) fw.write ("}\n") conf.write ("pkglib_MODULES += %s.mod\n" % modname) - conf.write ("%s_mod_SOURCES = gcry/cipher/%s\n" %\ - (modname, cipher_file)) + conf.write ("%s_mod_SOURCES = %s\n" %\ + (modname, modfiles)) conf.write ("%s_mod_CFLAGS = $(COMMON_CFLAGS) -Wno-missing-field-initializers -Wno-error\n" % modname) conf.write ("%s_mod_LDFLAGS = $(COMMON_LDFLAGS)\n\n" % modname) - elif isc: - print ("WARNING: c file isn't a module: %s" % cipher_file) + elif isc and cipher_file != "camellia.c": + print ("WARNING: C file isn't a module: %s" % cipher_file) f.close () fw.close () if nch: diff --git a/include/grub/crypto.h b/include/grub/crypto.h index ab482f467..bd236116d 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -123,6 +123,7 @@ typedef struct gcry_cipher_spec gcry_cipher_decrypt_t decrypt; gcry_cipher_stencrypt_t stencrypt; gcry_cipher_stdecrypt_t stdecrypt; + struct gcry_cipher_spec *next; } gcry_cipher_spec_t; /* Definition of a function used to report selftest failures. @@ -154,33 +155,75 @@ typedef struct cipher_extra_spec cipher_set_extra_info_t set_extra_info; } cipher_extra_spec_t; -/* (Forward declaration.) */ -struct gcry_md_context; +/* Type for the md_init function. */ +typedef void (*gcry_md_init_t) (void *c); -/* This object is used to hold a handle to a message digest object. - This structure is private - only to be used by the public gcry_md_* - macros. */ -typedef struct gcry_md_handle +/* Type for the md_write function. */ +typedef void (*gcry_md_write_t) (void *c, const void *buf, grub_size_t nbytes); + +/* Type for the md_final function. */ +typedef void (*gcry_md_final_t) (void *c); + +/* Type for the md_read function. */ +typedef unsigned char *(*gcry_md_read_t) (void *c); + +typedef struct gcry_md_oid_spec { - /* Actual context. */ - struct gcry_md_context *ctx; - - /* Buffer management. */ - int bufpos; - int bufsize; - unsigned char buf[1]; -} *gcry_md_hd_t; + const char *oidstring; +} gcry_md_oid_spec_t; - -struct grub_cipher +/* Module specification structure for message digests. */ +typedef struct gcry_md_spec { - struct grub_cipher *next; const char *name; -}; -typedef struct grub_cipher *grub_cipher_t; + unsigned char *asnoid; + int asnlen; + gcry_md_oid_spec_t *oids; + int mdlen; + gcry_md_init_t init; + gcry_md_write_t write; + gcry_md_final_t final; + gcry_md_read_t read; + grub_size_t contextsize; /* allocate this amount of context */ + struct gcry_md_spec *next; +} gcry_md_spec_t; + +extern gcry_cipher_spec_t *EXPORT_VAR (grub_ciphers); +extern gcry_md_spec_t *EXPORT_VAR (grub_digests); + +static inline void +grub_cipher_register (gcry_cipher_spec_t *cipher) +{ + cipher->next = grub_ciphers; + grub_ciphers = cipher; +} + +static inline void +grub_cipher_unregister (gcry_cipher_spec_t *cipher) +{ + gcry_cipher_spec_t **ciph; + for (ciph = &grub_ciphers; *ciph; ciph = &((*ciph)->next)) + if (*ciph == cipher) + *ciph = (*ciph)->next; +} + +static inline void +grub_md_register (gcry_md_spec_t *digest) +{ + digest->next = grub_digests; + grub_digests = digest; +} + +static inline void +grub_md_unregister (gcry_md_spec_t *cipher) +{ + gcry_md_spec_t **ciph; + for (ciph = &grub_digests; *ciph; ciph = &((*ciph)->next)) + if (*ciph == cipher) + *ciph = (*ciph)->next; +} + -extern grub_cipher_t EXPORT_VAR (grub_ciphers); void EXPORT_FUNC(grub_burn_stack) (grub_size_t size); - #endif diff --git a/include/grub/gcry_wrap.h b/include/grub/gcry_wrap.h index 6f415a2e5..37a1ee4d7 100644 --- a/include/grub/gcry_wrap.h +++ b/include/grub/gcry_wrap.h @@ -27,12 +27,45 @@ #define __GNU_LIBRARY__ +#define DIM ARRAY_SIZE + +typedef grub_uint64_t u64; typedef grub_uint32_t u32; typedef grub_uint16_t u16; typedef grub_uint8_t byte; typedef grub_size_t size_t; +#define U64_C(c) (c ## ULL) + #define _gcry_burn_stack grub_burn_stack #define log_error(fmt, args...) grub_dprintf ("crypto", fmt, ## args) + +#define PUBKEY_FLAG_NO_BLINDING (1 << 0) + +#define CIPHER_INFO_NO_WEAK_KEY 1 + +#define HAVE_U64_TYPEDEF 1 + +typedef union { + int a; + short b; + char c[1]; + long d; +#ifdef HAVE_U64_TYPEDEF + u64 e; +#endif + float f; + double g; +} PROPERLY_ALIGNED_TYPE; + +#define gcry_assert(x) grub_assert_real(__FILE__, __LINE__, x) + +static inline void +grub_assert_real (const char *file, int line, int cond) +{ + if (cond) + grub_fatal ("Assertion failed at %s:%d\n", file, line); +} + #endif diff --git a/kern/crypto.c b/kern/crypto.c index 7dd00c84d..83e2d96df 100644 --- a/kern/crypto.c +++ b/kern/crypto.c @@ -18,8 +18,10 @@ */ #include #include +#include -grub_cipher_t grub_ciphers; +gcry_cipher_spec_t *grub_ciphers = NULL; +gcry_md_spec_t *grub_digests = NULL; /* Based on libgcrypt-1.4.4/src/misc.c. */ void From 9f08f2a1fd8104b9038c14c8f3d487d4fa192837 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 10 Nov 2009 20:46:05 +0100 Subject: [PATCH 04/28] bugfix burn_stack --- kern/crypto.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kern/crypto.c b/kern/crypto.c index 83e2d96df..d097e1668 100644 --- a/kern/crypto.c +++ b/kern/crypto.c @@ -30,7 +30,6 @@ grub_burn_stack (grub_size_t size) char buf[64]; grub_memset (buf, 0, sizeof (buf)); - size -= sizeof (buf); - if (size > 0) - grub_burn_stack (size); + if (size > sizeof (buf)) + grub_burn_stack (size - sizeof (buf)); } From 20de16bb918776f0183069c82d5afa3356e0f809 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 10 Nov 2009 20:47:06 +0100 Subject: [PATCH 05/28] bugfix burn_stack --- commands/xnu_uuid.c | 311 ++------------------------------------------ conf/i386-pc.rmk | 2 +- 2 files changed, 13 insertions(+), 300 deletions(-) diff --git a/commands/xnu_uuid.c b/commands/xnu_uuid.c index 06e88e560..d7f86276b 100644 --- a/commands/xnu_uuid.c +++ b/commands/xnu_uuid.c @@ -31,12 +31,9 @@ #include #include #include +#include -struct tohash -{ - grub_uint8_t prefix[16]; - grub_uint64_t serial; -} __attribute__ ((packed)); +extern gcry_md_spec_t _gcry_digest_spec_md5; /* This prefix is used by xnu and boot-132 to hash together with volume serial. */ @@ -44,311 +41,27 @@ static grub_uint8_t hash_prefix[16] = {0xB3, 0xE2, 0x0F, 0x39, 0xF2, 0x92, 0x11, 0xD6, 0x97, 0xA4, 0x00, 0x30, 0x65, 0x43, 0xEC, 0xAC}; -#define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) ) -#define ror(x,n) ( ((x) >> (n)) | ((x) << (32-(n))) ) - -typedef struct { - grub_uint32_t A,B,C,D; /* chaining variables */ - grub_uint32_t nblocks; - grub_uint8_t buf[64]; - int count; -} MD5_CONTEXT; - -static void -md5_init( void *context ) -{ - MD5_CONTEXT *ctx = context; - - ctx->A = 0x67452301; - ctx->B = 0xefcdab89; - ctx->C = 0x98badcfe; - ctx->D = 0x10325476; - - ctx->nblocks = 0; - ctx->count = 0; -} - -/* These are the four functions used in the four steps of the MD5 algorithm - and defined in the RFC 1321. The first function is a little bit optimized - (as found in Colin Plumbs public domain implementation). */ -/* #define FF(b, c, d) ((b & c) | (~b & d)) */ -#define FF(b, c, d) (d ^ (b & (c ^ d))) -#define FG(b, c, d) FF (d, b, c) -#define FH(b, c, d) (b ^ c ^ d) -#define FI(b, c, d) (c ^ (b | ~d)) - - -/**************** - * transform n*64 grub_uint8_ts - */ -static void -transform ( MD5_CONTEXT *ctx, const unsigned char *data ) -{ - grub_uint32_t correct_words[16]; - register grub_uint32_t A = ctx->A; - register grub_uint32_t B = ctx->B; - register grub_uint32_t C = ctx->C; - register grub_uint32_t D = ctx->D; - grub_uint32_t *cwp = correct_words; - -#ifdef GRUB_CPU_WORDS_BIGENDIAN - { - int i; - const grub_uint32_t *p = (const grub_uint32_t *) data; - - for (i = 0; i < 16; i++) - correct_words[i] = grub_le_to_cpu32 (p[i]); - } -#else - grub_memcpy (correct_words, data, 64); -#endif - -#define OP(a, b, c, d, s, T) \ - do \ - { \ - a += FF (b, c, d) + (*cwp++) + T; \ - a = rol(a, s); \ - a += b; \ - } \ - while (0) - - /* Before we start, one word about the strange constants. - They are defined in RFC 1321 as - - T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64 - */ - - /* Round 1. */ - OP (A, B, C, D, 7, 0xd76aa478); - OP (D, A, B, C, 12, 0xe8c7b756); - OP (C, D, A, B, 17, 0x242070db); - OP (B, C, D, A, 22, 0xc1bdceee); - OP (A, B, C, D, 7, 0xf57c0faf); - OP (D, A, B, C, 12, 0x4787c62a); - OP (C, D, A, B, 17, 0xa8304613); - OP (B, C, D, A, 22, 0xfd469501); - OP (A, B, C, D, 7, 0x698098d8); - OP (D, A, B, C, 12, 0x8b44f7af); - OP (C, D, A, B, 17, 0xffff5bb1); - OP (B, C, D, A, 22, 0x895cd7be); - OP (A, B, C, D, 7, 0x6b901122); - OP (D, A, B, C, 12, 0xfd987193); - OP (C, D, A, B, 17, 0xa679438e); - OP (B, C, D, A, 22, 0x49b40821); - -#undef OP -#define OP(f, a, b, c, d, k, s, T) \ - do \ - { \ - a += f (b, c, d) + correct_words[k] + T; \ - a = rol(a, s); \ - a += b; \ - } \ - while (0) - - /* Round 2. */ - OP (FG, A, B, C, D, 1, 5, 0xf61e2562); - OP (FG, D, A, B, C, 6, 9, 0xc040b340); - OP (FG, C, D, A, B, 11, 14, 0x265e5a51); - OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa); - OP (FG, A, B, C, D, 5, 5, 0xd62f105d); - OP (FG, D, A, B, C, 10, 9, 0x02441453); - OP (FG, C, D, A, B, 15, 14, 0xd8a1e681); - OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8); - OP (FG, A, B, C, D, 9, 5, 0x21e1cde6); - OP (FG, D, A, B, C, 14, 9, 0xc33707d6); - OP (FG, C, D, A, B, 3, 14, 0xf4d50d87); - OP (FG, B, C, D, A, 8, 20, 0x455a14ed); - OP (FG, A, B, C, D, 13, 5, 0xa9e3e905); - OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8); - OP (FG, C, D, A, B, 7, 14, 0x676f02d9); - OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a); - - /* Round 3. */ - OP (FH, A, B, C, D, 5, 4, 0xfffa3942); - OP (FH, D, A, B, C, 8, 11, 0x8771f681); - OP (FH, C, D, A, B, 11, 16, 0x6d9d6122); - OP (FH, B, C, D, A, 14, 23, 0xfde5380c); - OP (FH, A, B, C, D, 1, 4, 0xa4beea44); - OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9); - OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60); - OP (FH, B, C, D, A, 10, 23, 0xbebfbc70); - OP (FH, A, B, C, D, 13, 4, 0x289b7ec6); - OP (FH, D, A, B, C, 0, 11, 0xeaa127fa); - OP (FH, C, D, A, B, 3, 16, 0xd4ef3085); - OP (FH, B, C, D, A, 6, 23, 0x04881d05); - OP (FH, A, B, C, D, 9, 4, 0xd9d4d039); - OP (FH, D, A, B, C, 12, 11, 0xe6db99e5); - OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8); - OP (FH, B, C, D, A, 2, 23, 0xc4ac5665); - - /* Round 4. */ - OP (FI, A, B, C, D, 0, 6, 0xf4292244); - OP (FI, D, A, B, C, 7, 10, 0x432aff97); - OP (FI, C, D, A, B, 14, 15, 0xab9423a7); - OP (FI, B, C, D, A, 5, 21, 0xfc93a039); - OP (FI, A, B, C, D, 12, 6, 0x655b59c3); - OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92); - OP (FI, C, D, A, B, 10, 15, 0xffeff47d); - OP (FI, B, C, D, A, 1, 21, 0x85845dd1); - OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f); - OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0); - OP (FI, C, D, A, B, 6, 15, 0xa3014314); - OP (FI, B, C, D, A, 13, 21, 0x4e0811a1); - OP (FI, A, B, C, D, 4, 6, 0xf7537e82); - OP (FI, D, A, B, C, 11, 10, 0xbd3af235); - OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb); - OP (FI, B, C, D, A, 9, 21, 0xeb86d391); - - /* Put checksum in context given as argument. */ - ctx->A += A; - ctx->B += B; - ctx->C += C; - ctx->D += D; -} - -/* The routine updates the message-digest context to - * account for the presence of each of the characters inBuf[0..inLen-1] - * in the message whose digest is being computed. - */ -static void -md5_write( void *context, const void *inbuf_arg , grub_size_t inlen) -{ - const unsigned char *inbuf = inbuf_arg; - MD5_CONTEXT *hd = context; - - if( hd->count == 64 ) /* flush the buffer */ - { - transform( hd, hd->buf ); - // _gcry_burn_stack (80+6*sizeof(void*)); - hd->count = 0; - hd->nblocks++; - } - if( !inbuf ) - return; - - if( hd->count ) - { - for( ; inlen && hd->count < 64; inlen-- ) - hd->buf[hd->count++] = *inbuf++; - md5_write( hd, NULL, 0 ); - if( !inlen ) - return; - } - // _gcry_burn_stack (80+6*sizeof(void*)); - - while( inlen >= 64 ) - { - transform( hd, inbuf ); - hd->count = 0; - hd->nblocks++; - inlen -= 64; - inbuf += 64; - } - for( ; inlen && hd->count < 64; inlen-- ) - hd->buf[hd->count++] = *inbuf++; - -} - - - -/* The routine final terminates the message-digest computation and - * ends with the desired message digest in mdContext->digest[0...15]. - * The handle is prepared for a new MD5 cycle. - * Returns 16 grub_uint8_ts representing the digest. - */ -static void -md5_final( void *context) -{ - MD5_CONTEXT *hd = context; - grub_uint32_t t, msb, lsb; - grub_uint32_t *p; - - md5_write(hd, NULL, 0); /* flush */; - - t = hd->nblocks; - /* multiply by 64 to make a grub_uint8_t count */ - lsb = t << 6; - msb = t >> 26; - /* add the count */ - t = lsb; - if( (lsb += hd->count) < t ) - msb++; - /* multiply by 8 to make a bit count */ - t = lsb; - lsb <<= 3; - msb <<= 3; - msb |= t >> 29; - - if( hd->count < 56 ) /* enough room */ - { - hd->buf[hd->count++] = 0x80; /* pad */ - while( hd->count < 56 ) - hd->buf[hd->count++] = 0; /* pad */ - } - else /* need one extra block */ - { - hd->buf[hd->count++] = 0x80; /* pad character */ - while( hd->count < 64 ) - hd->buf[hd->count++] = 0; - md5_write(hd, NULL, 0); /* flush */; - grub_memset(hd->buf, 0, 56 ); /* fill next block with zeroes */ - } - /* append the 64 bit count */ - hd->buf[56] = lsb ; - hd->buf[57] = lsb >> 8; - hd->buf[58] = lsb >> 16; - hd->buf[59] = lsb >> 24; - hd->buf[60] = msb ; - hd->buf[61] = msb >> 8; - hd->buf[62] = msb >> 16; - hd->buf[63] = msb >> 24; - transform( hd, hd->buf ); - // _gcry_burn_stack (80+6*sizeof(void*)); - - p = (grub_uint32_t *) hd->buf; -#define X(a) do { *p = grub_le_to_cpu32 (hd->a); p++; } while (0) - X(A); - X(B); - X(C); - X(D); -#undef X - -} - -/** - * GRUB2 Crypto Interface - * Written by Michael Gorven - */ -static grub_err_t -md5 (const char *in, grub_size_t insize, char *out) -{ - MD5_CONTEXT hd; - - md5_init (&hd); - md5_write (&hd, in, insize); - md5_final (&hd); - grub_memcpy (out, hd.buf, 16); - - return GRUB_ERR_NONE; -} - static grub_err_t grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)), int argc, char **args) { - struct tohash hashme; - grub_uint8_t xnu_uuid[16]; + grub_uint64_t serial; + grub_uint8_t *xnu_uuid; char uuid_string[sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]; char *ptr; + grub_uint8_t ctx[_gcry_digest_spec_md5.contextsize]; if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "UUID required"); - hashme.serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16)); - grub_memcpy (hashme.prefix, hash_prefix, sizeof (hashme.prefix)); + serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16)); + + _gcry_digest_spec_md5.init (&ctx); + _gcry_digest_spec_md5.write (&ctx, hash_prefix, sizeof (hash_prefix)); + _gcry_digest_spec_md5.write (&ctx, &serial, sizeof (serial)); + _gcry_digest_spec_md5.final (&ctx); + xnu_uuid = _gcry_digest_spec_md5.read (&ctx); - md5 ((char *) &hashme, sizeof (hashme), (char *) xnu_uuid); grub_sprintf (uuid_string, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", (unsigned int) xnu_uuid[0], (unsigned int) xnu_uuid[1], diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 0e3291782..45e1ccf91 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -125,7 +125,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ commands/search.c commands/blocklist.c commands/hexdump.c \ lib/hexdump.c commands/i386/pc/halt.c commands/reboot.c \ lib/envblk.c commands/loadenv.c \ - commands/gptsync.c commands/probe.c commands/xnu_uuid.c \ + commands/gptsync.c commands/probe.c \ commands/i386/cpuid.c \ commands/password.c commands/keystatus.c \ disk/host.c disk/loopback.c disk/scsi.c \ From a4bafc47107165a839d6aec22e4cef1724785914 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 10 Nov 2009 20:51:22 +0100 Subject: [PATCH 06/28] First working cipher import --- import_gcry.py | 90 +++++++++++++++++++-- include/grub/{gcry_wrap.h => cipher_wrap.h} | 13 +++ include/grub/crypto.h | 1 + 3 files changed, 99 insertions(+), 5 deletions(-) rename include/grub/{gcry_wrap.h => cipher_wrap.h} (92%) diff --git a/import_gcry.py b/import_gcry.py index cc06142e6..9a53a356a 100644 --- a/import_gcry.py +++ b/import_gcry.py @@ -10,10 +10,17 @@ indir = sys.argv[1] outdir = sys.argv[2] basedir = os.path.join (outdir, "gcry") -os.makedirs (basedir) +try: + os.makedirs (basedir) +except: + print ("WARNING: %s already exists" % basedir) cipher_dir_in = os.path.join (indir, "cipher") cipher_dir_out = os.path.join (basedir, "cipher") -os.makedirs (cipher_dir_out) +try: + os.makedirs (cipher_dir_out) +except: + print ("WARNING: %s already exists" % cipher_dir_out) + cipher_files = os.listdir (cipher_dir_in) conf = open (os.path.join (outdir, "conf", "gcry.rmk"), "w") conf.write ("# -*- makefile -*-\n\n") @@ -34,7 +41,33 @@ for cipher_file in cipher_files: fw.write (" import_gcry.py. Please don't modify it */\n"); ciphernames = [] mdnames = [] + hold = False + skip = False + skip2 = False for line in f: + if skip: + if line[0] == "}": + skip = False + continue + if skip2: + if not re.search (" *};", line) is None: + skip2 = False + continue + if hold: + hold = False + # We're optimising for size. + elif not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer)", line) is None: + skip = True + fname = re.match ("[a-zA-Z0-9_]*", line).group () + chmsg = "(%s): Removed." % fname + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue + else: + fw.write (holdline) m = re.match ("#include <.*>", line) if not m is None: chmsg = "Removed including of %s" % \ @@ -55,6 +88,46 @@ for cipher_file in cipher_files: mdname = line [len ("gcry_md_spec_t"):].strip () mdname = re.match("[a-zA-Z0-9_]*",mdname).group () mdnames.append (mdname) + m = re.match ("static const char \*selftest.*;$", line) + if not m is None: + fname = line[len ("static const char \*"):] + fname = re.match ("[a-zA-Z0-9_]*", fname).group () + chmsg = "(%s): Removed declaration." % fname + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue + m = re.match ("(static const char( |)\*|static gpg_err_code_t|void)$", line) + if not m is None: + hold = True + holdline = line + continue + m = re.match ("cipher_extra_spec_t", line) + if isc and not m is None: + skip2 = True + fname = line[len ("cipher_extra_spec_t "):] + fname = re.match ("[a-zA-Z0-9_]*", fname).group () + chmsg = "(%s): Removed." % fname + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue + m = re.match ("md_extra_spec_t", line) + if isc and not m is None: + skip2 = True + fname = line[len ("md_extra_spec_t "):] + fname = re.match ("[a-zA-Z0-9_]*", fname).group () + chmsg = "(%s): Removed." % fname + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue fw.write (line) if len (ciphernames) > 0 or len (mdnames) > 0: modname = cipher_file [0:len(cipher_file) - 2] @@ -120,20 +193,27 @@ for cipher_file in cipher_files: outfile = os.path.join (cipher_dir_out, "types.h") fw=open (outfile, "w") fw.write ("#include \n") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * types.h: New file.\n" % chlog fw.close () +outfile = os.path.join (cipher_dir_out, "memory.h") +fw=open (outfile, "w") +fw.write ("#include \n") +chlog = "%s * memory.h: New file.\n" % chlog +fw.close () + + outfile = os.path.join (cipher_dir_out, "cipher.h") fw=open (outfile, "w") fw.write ("#include \n") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * cipher.h: Likewise.\n" % chlog fw.close () outfile = os.path.join (cipher_dir_out, "g10lib.h") fw=open (outfile, "w") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * g10lib.h: Likewise.\n" % chlog fw.close () diff --git a/include/grub/gcry_wrap.h b/include/grub/cipher_wrap.h similarity index 92% rename from include/grub/gcry_wrap.h rename to include/grub/cipher_wrap.h index 37a1ee4d7..9e6242b7f 100644 --- a/include/grub/gcry_wrap.h +++ b/include/grub/cipher_wrap.h @@ -68,4 +68,17 @@ grub_assert_real (const char *file, int line, int cond) grub_fatal ("Assertion failed at %s:%d\n", file, line); } +/* Selftests are in separate modules. */ +static inline char * +selftest (void) +{ + return NULL; +} + +static inline int +fips_mode (void) +{ + return 0; +} + #endif diff --git a/include/grub/crypto.h b/include/grub/crypto.h index bd236116d..17f14de86 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -64,6 +64,7 @@ typedef enum GPG_ERR_WRONG_PUBKEY_ALGO, } gcry_err_code_t; #define gpg_err_code_t gcry_err_code_t +#define gpg_error_t gcry_err_code_t enum gcry_cipher_modes { From 63d7ad01ebf629007f8f42a9d3ae32a81d8fa805 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 10 Nov 2009 20:59:09 +0100 Subject: [PATCH 07/28] Fixed splitting error --- import_gcry.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/import_gcry.py b/import_gcry.py index 9a53a356a..ca03729af 100644 --- a/import_gcry.py +++ b/import_gcry.py @@ -56,7 +56,7 @@ for cipher_file in cipher_files: if hold: hold = False # We're optimising for size. - elif not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer)", line) is None: + if not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer)", line) is None: skip = True fname = re.match ("[a-zA-Z0-9_]*", line).group () chmsg = "(%s): Removed." % fname From 414f919237bd02e53a11066fcdc0c08e9adc8e2e Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 12 Nov 2009 18:08:44 +0100 Subject: [PATCH 08/28] Various cleanups and wrapper functions. Allocate disk id for LUKS. --- commands/xnu_uuid.c | 14 ++- import_gcry.py | 28 ++++++ include/grub/crypto.h | 202 +++++++++++++++++++++++++++++++++++------- include/grub/disk.h | 1 + 4 files changed, 206 insertions(+), 39 deletions(-) diff --git a/commands/xnu_uuid.c b/commands/xnu_uuid.c index d7f86276b..48c67d18e 100644 --- a/commands/xnu_uuid.c +++ b/commands/xnu_uuid.c @@ -33,8 +33,6 @@ #include #include -extern gcry_md_spec_t _gcry_digest_spec_md5; - /* This prefix is used by xnu and boot-132 to hash together with volume serial. */ static grub_uint8_t hash_prefix[16] @@ -49,18 +47,18 @@ grub_cmd_xnu_uuid (grub_command_t cmd __attribute__ ((unused)), grub_uint8_t *xnu_uuid; char uuid_string[sizeof ("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]; char *ptr; - grub_uint8_t ctx[_gcry_digest_spec_md5.contextsize]; + grub_uint8_t ctx[GRUB_MD_MD5->contextsize]; if (argc < 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, "UUID required"); serial = grub_cpu_to_be64 (grub_strtoull (args[0], 0, 16)); - _gcry_digest_spec_md5.init (&ctx); - _gcry_digest_spec_md5.write (&ctx, hash_prefix, sizeof (hash_prefix)); - _gcry_digest_spec_md5.write (&ctx, &serial, sizeof (serial)); - _gcry_digest_spec_md5.final (&ctx); - xnu_uuid = _gcry_digest_spec_md5.read (&ctx); + GRUB_MD_MD5->init (&ctx); + GRUB_MD_MD5->write (&ctx, hash_prefix, sizeof (hash_prefix)); + GRUB_MD_MD5->write (&ctx, &serial, sizeof (serial)); + GRUB_MD_MD5->final (&ctx); + xnu_uuid = GRUB_MD_MD5->read (&ctx); grub_sprintf (uuid_string, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", diff --git a/import_gcry.py b/import_gcry.py index ca03729af..39542d8c4 100644 --- a/import_gcry.py +++ b/import_gcry.py @@ -26,6 +26,20 @@ conf = open (os.path.join (outdir, "conf", "gcry.rmk"), "w") conf.write ("# -*- makefile -*-\n\n") chlog = "" +mdblocksizes = {"_gcry_digest_spec_crc32" : 1, + "_gcry_digest_spec_crc32_rfc1510" : 1, + "_gcry_digest_spec_crc24_rfc2440" : 1, + "_gcry_digest_spec_md4" : 64, + "_gcry_digest_spec_md5" : 64, + "_gcry_digest_spec_rmd160" : 64, + "_gcry_digest_spec_sha1" : 64, + "_gcry_digest_spec_sha224" : 64, + "_gcry_digest_spec_sha256" : 64, + "_gcry_digest_spec_sha384" : 128, + "_gcry_digest_spec_sha512" : 128, + "_gcry_digest_spec_tiger" : 64, + "_gcry_digest_spec_whirlpool" : 64} + for cipher_file in cipher_files: infile = os.path.join (cipher_dir_in, cipher_file) outfile = os.path.join (cipher_dir_out, cipher_file) @@ -44,6 +58,8 @@ for cipher_file in cipher_files: hold = False skip = False skip2 = False + ismd = False + iscomma = False for line in f: if skip: if line[0] == "}": @@ -53,6 +69,16 @@ for cipher_file in cipher_files: if not re.search (" *};", line) is None: skip2 = False continue + if ismd: + if not re.search (" *};", line) is None: + if not mdblocksizes.has_key (mdname): + print ("ERROR: Unknown digest blocksize: %s\n" % mdname) + exit (1) + if not iscomma: + fw.write (" ,\n") + fw.write (" .blocksize = %s\n" % mdblocksizes [mdname]) + ismd = False + iscomma = not re.search (",$", line) is None if hold: hold = False # We're optimising for size. @@ -85,9 +111,11 @@ for cipher_file in cipher_files: ciphernames.append (ciphername) m = re.match ("gcry_md_spec_t", line) if isc and not m is None: + assert (not ismd) mdname = line [len ("gcry_md_spec_t"):].strip () mdname = re.match("[a-zA-Z0-9_]*",mdname).group () mdnames.append (mdname) + ismd = True m = re.match ("static const char \*selftest.*;$", line) if not m is None: fname = line[len ("static const char \*"):] diff --git a/include/grub/crypto.h b/include/grub/crypto.h index 17f14de86..239b46666 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -25,6 +25,8 @@ #include #include +#include +#include typedef enum { @@ -127,35 +129,6 @@ typedef struct gcry_cipher_spec struct gcry_cipher_spec *next; } gcry_cipher_spec_t; -/* Definition of a function used to report selftest failures. - DOMAIN is a string describing the function block: - "cipher", "digest", "pubkey or "random", - ALGO is the algorithm under test, - WHAT is a string describing what has been tested, - DESC is a string describing the error. */ -typedef void (*selftest_report_func_t)(const char *domain, - int algo, - const char *what, - const char *errdesc); - -/* Definition of the selftest functions. */ -typedef gpg_err_code_t (*selftest_func_t) - (int algo, int extended, selftest_report_func_t report); - -/* The type used to convey additional information to a cipher. */ -typedef gpg_err_code_t (*cipher_set_extra_info_t) - (void *c, int what, const void *buffer, grub_size_t buflen); - - -/* Extra module specification structures. These are used for internal - modules which provide more functions than available through the - public algorithm register APIs. */ -typedef struct cipher_extra_spec -{ - selftest_func_t selftest; - cipher_set_extra_info_t set_extra_info; -} cipher_extra_spec_t; - /* Type for the md_init function. */ typedef void (*gcry_md_init_t) (void *c); @@ -180,12 +153,14 @@ typedef struct gcry_md_spec unsigned char *asnoid; int asnlen; gcry_md_oid_spec_t *oids; - int mdlen; + grub_size_t mdlen; gcry_md_init_t init; gcry_md_write_t write; gcry_md_final_t final; gcry_md_read_t read; grub_size_t contextsize; /* allocate this amount of context */ + /* Block size, needed for HMAC. */ + grub_size_t blocksize; struct gcry_md_spec *next; } gcry_md_spec_t; @@ -199,7 +174,7 @@ grub_cipher_register (gcry_cipher_spec_t *cipher) grub_ciphers = cipher; } -static inline void +static inline void grub_cipher_unregister (gcry_cipher_spec_t *cipher) { gcry_cipher_spec_t **ciph; @@ -224,7 +199,172 @@ grub_md_unregister (gcry_md_spec_t *cipher) *ciph = (*ciph)->next; } +static inline void +grub_crypto_hash (const gcry_md_spec_t *hash, void *out, void *in, + grub_size_t inlen) +{ + grub_uint8_t ctx[hash->contextsize]; + hash->init (&ctx); + hash->write (&ctx, in, inlen); + hash->final (&ctx); + grub_memcpy (out, hash->read (&ctx), hash->mdlen); +} + +static inline const gcry_md_spec_t * +grub_crypto_lookup_md_by_name (const char *name) +{ + const gcry_md_spec_t *md; + for (md = grub_digests; md; md = md->next) + if (grub_strcasecmp (name, md->name) == 0) + return md; + return NULL; +} + +typedef struct grub_crypto_cipher_handle +{ + const struct gcry_cipher_spec *cipher; + char ctx[0]; +} *grub_crypto_cipher_handle_t; + +static inline const gcry_cipher_spec_t * +grub_crypto_lookup_cipher_by_name (const char *name) +{ + const gcry_cipher_spec_t *ciph; + for (ciph = grub_ciphers; ciph; ciph = ciph->next) + { + const char **alias; + if (grub_strcasecmp (name, ciph->name) == 0) + return ciph; + if (!ciph->aliases) + continue; + for (alias = ciph->aliases; *alias; alias++) + if (grub_strcasecmp (name, *alias) == 0) + return ciph; + } + return NULL; +} + + +static inline grub_crypto_cipher_handle_t +grub_crypto_cipher_open (const struct gcry_cipher_spec *cipher) +{ + grub_crypto_cipher_handle_t ret; + ret = grub_malloc (sizeof (*ret) + cipher->contextsize); + if (!ret) + return NULL; + ret->cipher = cipher; + return ret; +} + +static inline gcry_err_code_t +grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher, + const unsigned char *key, + unsigned keylen) +{ + return cipher->cipher->setkey (cipher->ctx, key, keylen); +} + + +static inline void +grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher) +{ + grub_free (cipher); +} + + +static inline void +grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size) +{ + const grub_uint8_t *in1ptr = in1, *in2ptr = in2; + grub_uint8_t *outptr = out; + while (size--) + { + *outptr = *in1ptr ^ *in2ptr; + in1ptr++; + in2ptr++; + outptr++; + } +} + +static inline grub_err_t +grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size) +{ + grub_uint8_t *inptr, *outptr, *end; + if (size % cipher->cipher->blocksize != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "This encryption can't decrypt partial blocks"); + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + cipher->cipher->decrypt (cipher->ctx, outptr, inptr); + return GRUB_ERR_NONE; +} + +static inline grub_err_t +grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size) +{ + grub_uint8_t *inptr, *outptr, *end; + if (size % cipher->cipher->blocksize != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "This encryption can't decrypt partial blocks"); + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + cipher->cipher->encrypt (cipher->ctx, outptr, inptr); + return GRUB_ERR_NONE; +} + +static inline grub_err_t +grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv_in) +{ + grub_uint8_t *inptr, *outptr, *end; + void *iv; + if (size % cipher->cipher->blocksize != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "This encryption can't decrypt partial blocks"); + end = (grub_uint8_t *) in + size; + iv = iv_in; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + { + grub_crypto_xor (outptr, inptr, iv, cipher->cipher->blocksize); + cipher->cipher->encrypt (cipher->ctx, outptr, outptr); + iv = outptr; + } + grub_memcpy (iv_in, iv, cipher->cipher->blocksize); + return GRUB_ERR_NONE; +} + +static inline grub_err_t +grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv) +{ + grub_uint8_t *inptr, *outptr, *end; + grub_uint8_t ivt[cipher->cipher->blocksize]; + if (size % cipher->cipher->blocksize != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "This encryption can't decrypt partial blocks"); + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + { + grub_memcpy (ivt, inptr, cipher->cipher->blocksize); + cipher->cipher->decrypt (cipher->ctx, outptr, inptr); + grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize); + grub_memcpy (iv, ivt, cipher->cipher->blocksize); + } + return GRUB_ERR_NONE; +} + void EXPORT_FUNC(grub_burn_stack) (grub_size_t size); +extern gcry_md_spec_t _gcry_digest_spec_md5; +#define GRUB_MD_MD5 ((const gcry_md_spec_t *) &_gcry_digest_spec_md5) + #endif diff --git a/include/grub/disk.h b/include/grub/disk.h index de71bb588..cc801bc67 100644 --- a/include/grub/disk.h +++ b/include/grub/disk.h @@ -42,6 +42,7 @@ enum grub_disk_dev_id GRUB_DISK_DEVICE_PXE_ID, GRUB_DISK_DEVICE_SCSI_ID, GRUB_DISK_DEVICE_FILE_ID, + GRUB_DISK_DEVICE_LUKS_ID }; struct grub_disk; From d944246c6aa076458bc3ee4dbd8026e39015e8e8 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 12 Nov 2009 22:40:14 +0100 Subject: [PATCH 09/28] Created crypto module. Moved some functions to it. --- conf/common.rmk | 5 + conf/i386-pc.rmk | 4 +- include/grub/crypto.h | 211 ++++++--------------------------------- lib/crypto.c | 225 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 263 insertions(+), 182 deletions(-) create mode 100644 lib/crypto.c diff --git a/conf/common.rmk b/conf/common.rmk index 0d19344a7..35b4620f4 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -619,4 +619,9 @@ setjmp_mod_SOURCES = lib/$(target_cpu)/setjmp.S setjmp_mod_ASFLAGS = $(COMMON_ASFLAGS) setjmp_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES += crypto.mod +crypto_mod_SOURCES = lib/crypto.c +crypto_mod_CFLAGS = $(COMMON_CFLAGS) +crypto_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/gcry.mk diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index 45e1ccf91..ac9337e41 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -58,15 +58,13 @@ kernel_img_SOURCES = kern/i386/pc/startup.S \ kern/generic/millisleep.c \ kern/env.c \ term/i386/pc/console.c term/i386/vga_common.c \ - kern/crypto.c \ symlist.c kernel_img_HEADERS = boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ env.h err.h file.h fs.h kernel.h loader.h misc.h mm.h net.h parser.h \ partition.h msdos_partition.h reader.h symbol.h term.h time.h types.h \ machine/biosdisk.h machine/boot.h machine/console.h machine/init.h \ machine/memory.h machine/loader.h machine/vga.h machine/vbe.h \ - machine/kernel.h machine/pxe.h i386/pit.h list.h handler.h command.h \ - crypto.h + machine/kernel.h machine/pxe.h i386/pit.h list.h handler.h command.h kernel_img_CFLAGS = $(COMMON_CFLAGS) $(TARGET_IMG_CFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS) kernel_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS)$(GRUB_KERNEL_MACHINE_LINK_ADDR) $(COMMON_CFLAGS) diff --git a/include/grub/crypto.h b/include/grub/crypto.h index 239b46666..5cd7f02b4 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -164,205 +164,58 @@ typedef struct gcry_md_spec struct gcry_md_spec *next; } gcry_md_spec_t; -extern gcry_cipher_spec_t *EXPORT_VAR (grub_ciphers); -extern gcry_md_spec_t *EXPORT_VAR (grub_digests); - -static inline void -grub_cipher_register (gcry_cipher_spec_t *cipher) -{ - cipher->next = grub_ciphers; - grub_ciphers = cipher; -} - -static inline void -grub_cipher_unregister (gcry_cipher_spec_t *cipher) -{ - gcry_cipher_spec_t **ciph; - for (ciph = &grub_ciphers; *ciph; ciph = &((*ciph)->next)) - if (*ciph == cipher) - *ciph = (*ciph)->next; -} - -static inline void -grub_md_register (gcry_md_spec_t *digest) -{ - digest->next = grub_digests; - grub_digests = digest; -} - -static inline void -grub_md_unregister (gcry_md_spec_t *cipher) -{ - gcry_md_spec_t **ciph; - for (ciph = &grub_digests; *ciph; ciph = &((*ciph)->next)) - if (*ciph == cipher) - *ciph = (*ciph)->next; -} - -static inline void -grub_crypto_hash (const gcry_md_spec_t *hash, void *out, void *in, - grub_size_t inlen) -{ - grub_uint8_t ctx[hash->contextsize]; - hash->init (&ctx); - hash->write (&ctx, in, inlen); - hash->final (&ctx); - grub_memcpy (out, hash->read (&ctx), hash->mdlen); -} - -static inline const gcry_md_spec_t * -grub_crypto_lookup_md_by_name (const char *name) -{ - const gcry_md_spec_t *md; - for (md = grub_digests; md; md = md->next) - if (grub_strcasecmp (name, md->name) == 0) - return md; - return NULL; -} - typedef struct grub_crypto_cipher_handle { const struct gcry_cipher_spec *cipher; char ctx[0]; } *grub_crypto_cipher_handle_t; -static inline const gcry_cipher_spec_t * -grub_crypto_lookup_cipher_by_name (const char *name) -{ - const gcry_cipher_spec_t *ciph; - for (ciph = grub_ciphers; ciph; ciph = ciph->next) - { - const char **alias; - if (grub_strcasecmp (name, ciph->name) == 0) - return ciph; - if (!ciph->aliases) - continue; - for (alias = ciph->aliases; *alias; alias++) - if (grub_strcasecmp (name, *alias) == 0) - return ciph; - } - return NULL; -} +const gcry_cipher_spec_t * +grub_crypto_lookup_cipher_by_name (const char *name); +grub_crypto_cipher_handle_t +grub_crypto_cipher_open (const struct gcry_cipher_spec *cipher); -static inline grub_crypto_cipher_handle_t -grub_crypto_cipher_open (const struct gcry_cipher_spec *cipher) -{ - grub_crypto_cipher_handle_t ret; - ret = grub_malloc (sizeof (*ret) + cipher->contextsize); - if (!ret) - return NULL; - ret->cipher = cipher; - return ret; -} - -static inline gcry_err_code_t +gcry_err_code_t grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher, const unsigned char *key, - unsigned keylen) -{ - return cipher->cipher->setkey (cipher->ctx, key, keylen); -} + unsigned keylen); +void +grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher); -static inline void -grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher) -{ - grub_free (cipher); -} - - -static inline void -grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size) -{ - const grub_uint8_t *in1ptr = in1, *in2ptr = in2; - grub_uint8_t *outptr = out; - while (size--) - { - *outptr = *in1ptr ^ *in2ptr; - in1ptr++; - in2ptr++; - outptr++; - } -} - -static inline grub_err_t +void +grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size); +grub_err_t grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher, - void *out, void *in, grub_size_t size) -{ - grub_uint8_t *inptr, *outptr, *end; - if (size % cipher->cipher->blocksize != 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "This encryption can't decrypt partial blocks"); - end = (grub_uint8_t *) in + size; - for (inptr = in, outptr = out; inptr < end; - inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) - cipher->cipher->decrypt (cipher->ctx, outptr, inptr); - return GRUB_ERR_NONE; -} + void *out, void *in, grub_size_t size); -static inline grub_err_t +grub_err_t grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher, - void *out, void *in, grub_size_t size) -{ - grub_uint8_t *inptr, *outptr, *end; - if (size % cipher->cipher->blocksize != 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "This encryption can't decrypt partial blocks"); - end = (grub_uint8_t *) in + size; - for (inptr = in, outptr = out; inptr < end; - inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) - cipher->cipher->encrypt (cipher->ctx, outptr, inptr); - return GRUB_ERR_NONE; -} - -static inline grub_err_t + void *out, void *in, grub_size_t size); +grub_err_t grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher, void *out, void *in, grub_size_t size, - void *iv_in) -{ - grub_uint8_t *inptr, *outptr, *end; - void *iv; - if (size % cipher->cipher->blocksize != 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "This encryption can't decrypt partial blocks"); - end = (grub_uint8_t *) in + size; - iv = iv_in; - for (inptr = in, outptr = out; inptr < end; - inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) - { - grub_crypto_xor (outptr, inptr, iv, cipher->cipher->blocksize); - cipher->cipher->encrypt (cipher->ctx, outptr, outptr); - iv = outptr; - } - grub_memcpy (iv_in, iv, cipher->cipher->blocksize); - return GRUB_ERR_NONE; -} - -static inline grub_err_t + void *iv_in); +grub_err_t grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, void *out, void *in, grub_size_t size, - void *iv) -{ - grub_uint8_t *inptr, *outptr, *end; - grub_uint8_t ivt[cipher->cipher->blocksize]; - if (size % cipher->cipher->blocksize != 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "This encryption can't decrypt partial blocks"); - end = (grub_uint8_t *) in + size; - for (inptr = in, outptr = out; inptr < end; - inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) - { - grub_memcpy (ivt, inptr, cipher->cipher->blocksize); - cipher->cipher->decrypt (cipher->ctx, outptr, inptr); - grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize); - grub_memcpy (iv, ivt, cipher->cipher->blocksize); - } - return GRUB_ERR_NONE; -} + void *iv); +void +grub_cipher_register (gcry_cipher_spec_t *cipher); +void +grub_cipher_unregister (gcry_cipher_spec_t *cipher); +void +grub_md_register (gcry_md_spec_t *digest); +void +grub_md_unregister (gcry_md_spec_t *cipher); +void +grub_crypto_hash (const gcry_md_spec_t *hash, void *out, void *in, + grub_size_t inlen); +const gcry_md_spec_t * +grub_crypto_lookup_md_by_name (const char *name); - -void EXPORT_FUNC(grub_burn_stack) (grub_size_t size); +void grub_burn_stack (grub_size_t size); extern gcry_md_spec_t _gcry_digest_spec_md5; #define GRUB_MD_MD5 ((const gcry_md_spec_t *) &_gcry_digest_spec_md5) diff --git a/lib/crypto.c b/lib/crypto.c new file mode 100644 index 000000000..64c386dae --- /dev/null +++ b/lib/crypto.c @@ -0,0 +1,225 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006 + * 2007, 2008, 2009 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include + +static gcry_cipher_spec_t *grub_ciphers = NULL; +static gcry_md_spec_t *grub_digests = NULL; + +/* Based on libgcrypt-1.4.4/src/misc.c. */ +void +grub_burn_stack (grub_size_t size) +{ + char buf[64]; + + grub_memset (buf, 0, sizeof (buf)); + if (size > sizeof (buf)) + grub_burn_stack (size - sizeof (buf)); +} + + +void +grub_cipher_register (gcry_cipher_spec_t *cipher) +{ + cipher->next = grub_ciphers; + grub_ciphers = cipher; +} + +void +grub_cipher_unregister (gcry_cipher_spec_t *cipher) +{ + gcry_cipher_spec_t **ciph; + for (ciph = &grub_ciphers; *ciph; ciph = &((*ciph)->next)) + if (*ciph == cipher) + *ciph = (*ciph)->next; +} + +void +grub_md_register (gcry_md_spec_t *digest) +{ + digest->next = grub_digests; + grub_digests = digest; +} + +void +grub_md_unregister (gcry_md_spec_t *cipher) +{ + gcry_md_spec_t **ciph; + for (ciph = &grub_digests; *ciph; ciph = &((*ciph)->next)) + if (*ciph == cipher) + *ciph = (*ciph)->next; +} + +void +grub_crypto_hash (const gcry_md_spec_t *hash, void *out, void *in, + grub_size_t inlen) +{ + grub_uint8_t ctx[hash->contextsize]; + hash->init (&ctx); + hash->write (&ctx, in, inlen); + hash->final (&ctx); + grub_memcpy (out, hash->read (&ctx), hash->mdlen); +} + +const gcry_md_spec_t * +grub_crypto_lookup_md_by_name (const char *name) +{ + const gcry_md_spec_t *md; + for (md = grub_digests; md; md = md->next) + if (grub_strcasecmp (name, md->name) == 0) + return md; + return NULL; +} + +const gcry_cipher_spec_t * +grub_crypto_lookup_cipher_by_name (const char *name) +{ + const gcry_cipher_spec_t *ciph; + for (ciph = grub_ciphers; ciph; ciph = ciph->next) + { + const char **alias; + if (grub_strcasecmp (name, ciph->name) == 0) + return ciph; + if (!ciph->aliases) + continue; + for (alias = ciph->aliases; *alias; alias++) + if (grub_strcasecmp (name, *alias) == 0) + return ciph; + } + return NULL; +} + + +grub_crypto_cipher_handle_t +grub_crypto_cipher_open (const struct gcry_cipher_spec *cipher) +{ + grub_crypto_cipher_handle_t ret; + ret = grub_malloc (sizeof (*ret) + cipher->contextsize); + if (!ret) + return NULL; + ret->cipher = cipher; + return ret; +} + +gcry_err_code_t +grub_crypto_cipher_set_key (grub_crypto_cipher_handle_t cipher, + const unsigned char *key, + unsigned keylen) +{ + return cipher->cipher->setkey (cipher->ctx, key, keylen); +} + + +void +grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher) +{ + grub_free (cipher); +} + + +void +grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size) +{ + const grub_uint8_t *in1ptr = in1, *in2ptr = in2; + grub_uint8_t *outptr = out; + while (size--) + { + *outptr = *in1ptr ^ *in2ptr; + in1ptr++; + in2ptr++; + outptr++; + } +} + +grub_err_t +grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size) +{ + grub_uint8_t *inptr, *outptr, *end; + if (size % cipher->cipher->blocksize != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "This encryption can't decrypt partial blocks"); + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + cipher->cipher->decrypt (cipher->ctx, outptr, inptr); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size) +{ + grub_uint8_t *inptr, *outptr, *end; + if (size % cipher->cipher->blocksize != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "This encryption can't decrypt partial blocks"); + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + cipher->cipher->encrypt (cipher->ctx, outptr, inptr); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv_in) +{ + grub_uint8_t *inptr, *outptr, *end; + void *iv; + if (size % cipher->cipher->blocksize != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "This encryption can't decrypt partial blocks"); + end = (grub_uint8_t *) in + size; + iv = iv_in; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + { + grub_crypto_xor (outptr, inptr, iv, cipher->cipher->blocksize); + cipher->cipher->encrypt (cipher->ctx, outptr, outptr); + iv = outptr; + } + grub_memcpy (iv_in, iv, cipher->cipher->blocksize); + return GRUB_ERR_NONE; +} + +grub_err_t +grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, + void *out, void *in, grub_size_t size, + void *iv) +{ + grub_uint8_t *inptr, *outptr, *end; + grub_uint8_t ivt[cipher->cipher->blocksize]; + if (size % cipher->cipher->blocksize != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "This encryption can't decrypt partial blocks"); + end = (grub_uint8_t *) in + size; + for (inptr = in, outptr = out; inptr < end; + inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) + { + grub_memcpy (ivt, inptr, cipher->cipher->blocksize); + cipher->cipher->decrypt (cipher->ctx, outptr, inptr); + grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize); + grub_memcpy (iv, ivt, cipher->cipher->blocksize); + } + return GRUB_ERR_NONE; +} From fbf62978dcd4d42facffdcf99831e82a1979cdc3 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 13 Nov 2009 00:27:04 +0100 Subject: [PATCH 10/28] Improved error handling --- include/grub/crypto.h | 26 +++++++++++++------------ lib/crypto.c | 44 +++++++++++++++++++++++++++---------------- 2 files changed, 42 insertions(+), 28 deletions(-) diff --git a/include/grub/crypto.h b/include/grub/crypto.h index 5cd7f02b4..7a3461e3b 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -20,13 +20,14 @@ /* Contains elements based on gcrypt-module.h and gcrypt.h.in. If it's changed please update this file. */ -#ifndef GRUB_CIPHER_HEADER -#define GRUB_CIPHER_HEADER 1 +#ifndef GRUB_CRYPTO_HEADER +#define GRUB_CRYPTO_HEADER 1 #include #include -#include -#include +#include +/* For GRUB_ACCESS_DENIED. */ +#include typedef enum { @@ -64,6 +65,7 @@ typedef enum GPG_ERR_WEAK_KEY, GPG_ERR_WRONG_KEY_USAGE, GPG_ERR_WRONG_PUBKEY_ALGO, + GPG_ERR_OUT_OF_MEMORY } gcry_err_code_t; #define gpg_err_code_t gcry_err_code_t #define gpg_error_t gcry_err_code_t @@ -186,26 +188,23 @@ grub_crypto_cipher_close (grub_crypto_cipher_handle_t cipher); void grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size); -grub_err_t + +gcry_err_code_t grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher, void *out, void *in, grub_size_t size); -grub_err_t +gcry_err_code_t grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher, void *out, void *in, grub_size_t size); -grub_err_t +gcry_err_code_t grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher, void *out, void *in, grub_size_t size, void *iv_in); -grub_err_t +gcry_err_code_t grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, void *out, void *in, grub_size_t size, void *iv); void -grub_cipher_register (gcry_cipher_spec_t *cipher); -void -grub_cipher_unregister (gcry_cipher_spec_t *cipher); -void grub_md_register (gcry_md_spec_t *digest); void grub_md_unregister (gcry_md_spec_t *cipher); @@ -215,6 +214,9 @@ grub_crypto_hash (const gcry_md_spec_t *hash, void *out, void *in, const gcry_md_spec_t * grub_crypto_lookup_md_by_name (const char *name); +grub_err_t +grub_crypto_gcry_error (gcry_err_code_t in); + void grub_burn_stack (grub_size_t size); extern gcry_md_spec_t _gcry_digest_spec_md5; diff --git a/lib/crypto.c b/lib/crypto.c index 64c386dae..718d6e278 100644 --- a/lib/crypto.c +++ b/lib/crypto.c @@ -149,46 +149,49 @@ grub_crypto_xor (void *out, const void *in1, const void *in2, grub_size_t size) } } -grub_err_t +gcry_err_code_t grub_crypto_ecb_decrypt (grub_crypto_cipher_handle_t cipher, void *out, void *in, grub_size_t size) { grub_uint8_t *inptr, *outptr, *end; + if (!cipher->cipher->decrypt) + return GPG_ERR_NOT_SUPPORTED; if (size % cipher->cipher->blocksize != 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "This encryption can't decrypt partial blocks"); + return GPG_ERR_INV_ARG; end = (grub_uint8_t *) in + size; for (inptr = in, outptr = out; inptr < end; inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) cipher->cipher->decrypt (cipher->ctx, outptr, inptr); - return GRUB_ERR_NONE; + return GPG_ERR_NO_ERROR; } -grub_err_t +gcry_err_code_t grub_crypto_ecb_encrypt (grub_crypto_cipher_handle_t cipher, void *out, void *in, grub_size_t size) { grub_uint8_t *inptr, *outptr, *end; + if (!cipher->cipher->encrypt) + return GPG_ERR_NOT_SUPPORTED; if (size % cipher->cipher->blocksize != 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "This encryption can't decrypt partial blocks"); + return GPG_ERR_INV_ARG; end = (grub_uint8_t *) in + size; for (inptr = in, outptr = out; inptr < end; inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) cipher->cipher->encrypt (cipher->ctx, outptr, inptr); - return GRUB_ERR_NONE; + return GPG_ERR_NO_ERROR; } -grub_err_t +gcry_err_code_t grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher, void *out, void *in, grub_size_t size, void *iv_in) { grub_uint8_t *inptr, *outptr, *end; void *iv; + if (!cipher->cipher->decrypt) + return GPG_ERR_NOT_SUPPORTED; if (size % cipher->cipher->blocksize != 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "This encryption can't decrypt partial blocks"); + return GPG_ERR_INV_ARG; end = (grub_uint8_t *) in + size; iv = iv_in; for (inptr = in, outptr = out; inptr < end; @@ -199,19 +202,20 @@ grub_crypto_cbc_encrypt (grub_crypto_cipher_handle_t cipher, iv = outptr; } grub_memcpy (iv_in, iv, cipher->cipher->blocksize); - return GRUB_ERR_NONE; + return GPG_ERR_NO_ERROR; } -grub_err_t +gcry_err_code_t grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, void *out, void *in, grub_size_t size, void *iv) { grub_uint8_t *inptr, *outptr, *end; grub_uint8_t ivt[cipher->cipher->blocksize]; + if (!cipher->cipher->decrypt) + return GPG_ERR_NOT_SUPPORTED; if (size % cipher->cipher->blocksize != 0) - return grub_error (GRUB_ERR_BAD_ARGUMENT, - "This encryption can't decrypt partial blocks"); + return GPG_ERR_INV_ARG; end = (grub_uint8_t *) in + size; for (inptr = in, outptr = out; inptr < end; inptr += cipher->cipher->blocksize, outptr += cipher->cipher->blocksize) @@ -221,5 +225,13 @@ grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, grub_crypto_xor (outptr, outptr, iv, cipher->cipher->blocksize); grub_memcpy (iv, ivt, cipher->cipher->blocksize); } - return GRUB_ERR_NONE; + return GPG_ERR_NO_ERROR; +} + +grub_err_t +grub_crypto_gcry_error (gcry_err_code_t in) +{ + if (in == GPG_ERR_NO_ERROR) + return GRUB_ERR_NONE; + return GRUB_ACCESS_DENIED; } From 37f7911f01628181288aaf7fe9e3b871137d7972 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Fri, 13 Nov 2009 01:27:38 +0100 Subject: [PATCH 11/28] Fix compilation error --- include/grub/crypto.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/grub/crypto.h b/include/grub/crypto.h index 7a3461e3b..34b1cb078 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -205,6 +205,10 @@ grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, void *out, void *in, grub_size_t size, void *iv); void +grub_cipher_register (gcry_cipher_spec_t *cipher); +void +grub_cipher_unregister (gcry_cipher_spec_t *cipher); +void grub_md_register (gcry_md_spec_t *digest); void grub_md_unregister (gcry_md_spec_t *cipher); From 6e7d9194d1e8d605d0462260836f723ac7d6ef1a Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 24 Nov 2009 02:32:29 +0100 Subject: [PATCH 12/28] Add HMAC and PBKDF2 --- conf/common.rmk | 5 ++ import_gcry.py | 27 +++++++- include/grub/cipher_wrap.h | 2 +- include/grub/crypto.h | 38 +++++++++- lib/crypto.c | 137 ++++++++++++++++++++++++++++++++++++- lib/pbkdf2.c | 101 +++++++++++++++++++++++++++ 6 files changed, 302 insertions(+), 8 deletions(-) create mode 100644 lib/pbkdf2.c diff --git a/conf/common.rmk b/conf/common.rmk index 35b4620f4..3356c556b 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -624,4 +624,9 @@ crypto_mod_SOURCES = lib/crypto.c crypto_mod_CFLAGS = $(COMMON_CFLAGS) crypto_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES += pbkdf2.mod +pbkdf2_mod_SOURCES = lib/pbkdf2.c +pbkdf2_mod_CFLAGS = $(COMMON_CFLAGS) +pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS) + include $(srcdir)/conf/gcry.mk diff --git a/import_gcry.py b/import_gcry.py index 39542d8c4..ae5b76778 100644 --- a/import_gcry.py +++ b/import_gcry.py @@ -1,3 +1,21 @@ +#* +#* GRUB -- GRand Unified Bootloader +#* Copyright (C) 2009 Free Software Foundation, Inc. +#* +#* GRUB 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 3 of the License, or +#* (at your option) any later version. +#* +#* GRUB 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 GRUB. If not, see . +#* + import re import sys import os @@ -26,9 +44,12 @@ conf = open (os.path.join (outdir, "conf", "gcry.rmk"), "w") conf.write ("# -*- makefile -*-\n\n") chlog = "" -mdblocksizes = {"_gcry_digest_spec_crc32" : 1, - "_gcry_digest_spec_crc32_rfc1510" : 1, - "_gcry_digest_spec_crc24_rfc2440" : 1, +# Strictly speaking CRC32/CRC24 work on bytes so this value should be 1 +# But libgcrypt uses 64. Let's keep the value for compatibility. Since +# noone uses CRC24/CRC32 for HMAC this is no problem +mdblocksizes = {"_gcry_digest_spec_crc32" : 64, + "_gcry_digest_spec_crc32_rfc1510" : 64, + "_gcry_digest_spec_crc24_rfc2440" : 64, "_gcry_digest_spec_md4" : 64, "_gcry_digest_spec_md5" : 64, "_gcry_digest_spec_rmd160" : 64, diff --git a/include/grub/cipher_wrap.h b/include/grub/cipher_wrap.h index 9e6242b7f..60ab369f0 100644 --- a/include/grub/cipher_wrap.h +++ b/include/grub/cipher_wrap.h @@ -64,7 +64,7 @@ typedef union { static inline void grub_assert_real (const char *file, int line, int cond) { - if (cond) + if (!cond) grub_fatal ("Assertion failed at %s:%d\n", file, line); } diff --git a/include/grub/crypto.h b/include/grub/crypto.h index 34b1cb078..df15f9bb9 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -166,11 +166,15 @@ typedef struct gcry_md_spec struct gcry_md_spec *next; } gcry_md_spec_t; -typedef struct grub_crypto_cipher_handle +struct grub_crypto_cipher_handle { const struct gcry_cipher_spec *cipher; char ctx[0]; -} *grub_crypto_cipher_handle_t; +}; + +typedef struct grub_crypto_cipher_handle *grub_crypto_cipher_handle_t; + +struct grub_crypto_hmac_handle; const gcry_cipher_spec_t * grub_crypto_lookup_cipher_by_name (const char *name); @@ -213,7 +217,7 @@ grub_md_register (gcry_md_spec_t *digest); void grub_md_unregister (gcry_md_spec_t *cipher); void -grub_crypto_hash (const gcry_md_spec_t *hash, void *out, void *in, +grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in, grub_size_t inlen); const gcry_md_spec_t * grub_crypto_lookup_md_by_name (const char *name); @@ -223,7 +227,35 @@ grub_crypto_gcry_error (gcry_err_code_t in); void grub_burn_stack (grub_size_t size); +struct grub_crypto_hmac_handle * +grub_crypto_hmac_init (const struct gcry_md_spec *md, + const void *key, grub_size_t keylen); +void +grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd, void *data, + grub_size_t datalen); +gcry_err_code_t +grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out); + +gcry_err_code_t +grub_crypto_hmac_buffer (const struct gcry_md_spec *md, + const void *key, grub_size_t keylen, + void *data, grub_size_t datalen, void *out); + extern gcry_md_spec_t _gcry_digest_spec_md5; #define GRUB_MD_MD5 ((const gcry_md_spec_t *) &_gcry_digest_spec_md5) +#define GRUB_MD_SHA1 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha1) + +/* Implement PKCS#5 PBKDF2 as per RFC 2898. The PRF to use is HMAC variant + of digest supplied by MD. Inputs are the password P of length PLEN, + the salt S of length SLEN, the iteration counter C (> 0), and the + desired derived output length DKLEN. Output buffer is DK which + must have room for at least DKLEN octets. The output buffer will + be filled with the derived data. */ +gcry_err_code_t +grub_crypto_pbkdf2 (const struct gcry_md_spec *md, + const grub_uint8_t *P, grub_size_t Plen, + const grub_uint8_t *S, grub_size_t Slen, + unsigned int c, + grub_uint8_t *DK, grub_size_t dkLen); #endif diff --git a/lib/crypto.c b/lib/crypto.c index 718d6e278..3cb66f942 100644 --- a/lib/crypto.c +++ b/lib/crypto.c @@ -21,6 +21,13 @@ #include #include +struct grub_crypto_hmac_handle +{ + const struct gcry_md_spec *md; + void *ctx; + void *opad; +}; + static gcry_cipher_spec_t *grub_ciphers = NULL; static gcry_md_spec_t *grub_digests = NULL; @@ -69,7 +76,7 @@ grub_md_unregister (gcry_md_spec_t *cipher) } void -grub_crypto_hash (const gcry_md_spec_t *hash, void *out, void *in, +grub_crypto_hash (const gcry_md_spec_t *hash, void *out, const void *in, grub_size_t inlen) { grub_uint8_t ctx[hash->contextsize]; @@ -228,6 +235,134 @@ grub_crypto_cbc_decrypt (grub_crypto_cipher_handle_t cipher, return GPG_ERR_NO_ERROR; } +/* Based on gcry/cipher/md.c. */ +struct grub_crypto_hmac_handle * +grub_crypto_hmac_init (const struct gcry_md_spec *md, + const void *key, grub_size_t keylen) +{ + grub_uint8_t *helpkey = NULL; + grub_uint8_t *ipad = NULL, *opad = NULL; + void *ctx = NULL; + struct grub_crypto_hmac_handle *ret = NULL; + unsigned i; + + if (md->mdlen > md->blocksize) + return NULL; + + ctx = grub_malloc (md->contextsize); + if (!ctx) + goto err; + + if ( keylen > md->blocksize ) + { + helpkey = grub_malloc (md->mdlen); + if (!helpkey) + goto err; + grub_crypto_hash (md, helpkey, key, keylen); + + key = helpkey; + keylen = md->mdlen; + } + + ipad = grub_zalloc (md->blocksize); + if (!ipad) + goto err; + + opad = grub_zalloc (md->blocksize); + if (!opad) + goto err; + + grub_memcpy ( ipad, key, keylen ); + grub_memcpy ( opad, key, keylen ); + for (i=0; i < md->blocksize; i++ ) + { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + grub_free (helpkey); + helpkey = NULL; + + md->init (ctx); + + md->write (ctx, ipad, md->blocksize); /* inner pad */ + grub_memset (ipad, 0, md->blocksize); + grub_free (ipad); + ipad = NULL; + + ret = grub_malloc (sizeof (*ret)); + if (!ret) + goto err; + + ret->md = md; + ret->ctx = ctx; + ret->opad = opad; + + return ret; + + err: + grub_free (helpkey); + grub_free (ctx); + grub_free (ipad); + grub_free (opad); + return NULL; +} + +void +grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd, void *data, + grub_size_t datalen) +{ + hnd->md->write (hnd->ctx, data, datalen); +} + +gcry_err_code_t +grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out) +{ + grub_uint8_t *p; + grub_uint8_t *ctx2; + + ctx2 = grub_malloc (hnd->md->contextsize); + if (!ctx2) + return GPG_ERR_OUT_OF_MEMORY; + + hnd->md->final (hnd->ctx); + hnd->md->read (hnd->ctx); + p = hnd->md->read (hnd->ctx); + + hnd->md->init (ctx2); + hnd->md->write (ctx2, hnd->opad, hnd->md->blocksize); + hnd->md->write (ctx2, p, hnd->md->mdlen); + hnd->md->final (ctx2); + grub_memset (hnd->opad, 0, hnd->md->blocksize); + grub_free (hnd->opad); + grub_memset (hnd->ctx, 0, hnd->md->contextsize); + grub_free (hnd->ctx); + + grub_memcpy (out, hnd->md->read (ctx2), hnd->md->mdlen); + grub_memset (ctx2, 0, hnd->md->contextsize); + grub_free (ctx2); + + grub_memset (hnd, 0, sizeof (*hnd)); + grub_free (hnd); + + return GPG_ERR_NO_ERROR; +} + +gcry_err_code_t +grub_crypto_hmac_buffer (const struct gcry_md_spec *md, + const void *key, grub_size_t keylen, + void *data, grub_size_t datalen, void *out) +{ + struct grub_crypto_hmac_handle *hnd; + + hnd = grub_crypto_hmac_init (md, key, keylen); + if (!hnd) + return GPG_ERR_OUT_OF_MEMORY; + + grub_crypto_hmac_write (hnd, data, datalen); + return grub_crypto_hmac_fini (hnd, out); +} + + grub_err_t grub_crypto_gcry_error (gcry_err_code_t in) { diff --git a/lib/pbkdf2.c b/lib/pbkdf2.c new file mode 100644 index 000000000..f2d3ca97f --- /dev/null +++ b/lib/pbkdf2.c @@ -0,0 +1,101 @@ +/* gc-pbkdf2-sha1.c --- Password-Based Key Derivation Function a'la PKCS#5 + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2009 Free Software Foundation, Inc. + + 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, 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. */ + +/* Written by Simon Josefsson. */ + +#include +#include +#include + +/* Implement PKCS#5 PBKDF2 as per RFC 2898. The PRF to use is HMAC variant + of digest supplied by MD. Inputs are the password P of length PLEN, + the salt S of length SLEN, the iteration counter C (> 0), and the + desired derived output length DKLEN. Output buffer is DK which + must have room for at least DKLEN octets. The output buffer will + be filled with the derived data. */ +gcry_err_code_t +grub_crypto_pbkdf2 (const struct gcry_md_spec *md, + const grub_uint8_t *P, grub_size_t Plen, + const grub_uint8_t *S, grub_size_t Slen, + unsigned int c, + grub_uint8_t *DK, grub_size_t dkLen) +{ + unsigned int hLen = md->mdlen; + grub_uint8_t U[md->mdlen]; + grub_uint8_t T[md->mdlen]; + unsigned int u; + unsigned int l; + unsigned int r; + unsigned int i; + unsigned int k; + gcry_err_code_t rc; + grub_uint8_t *tmp; + grub_size_t tmplen = Slen + 4; + + if (c == 0) + return GPG_ERR_INV_ARG; + + if (dkLen == 0) + return GPG_ERR_INV_ARG; + + if (dkLen > 4294967295U) + return GPG_ERR_INV_ARG; + + l = ((dkLen - 1) / hLen) + 1; + r = dkLen - (l - 1) * hLen; + + tmp = grub_malloc (tmplen); + if (tmp == NULL) + return GPG_ERR_OUT_OF_MEMORY; + + grub_memcpy (tmp, S, Slen); + + for (i = 1; i <= l; i++) + { + grub_memset (T, 0, hLen); + + for (u = 1; u <= c; u++) + { + if (u == 1) + { + tmp[Slen + 0] = (i & 0xff000000) >> 24; + tmp[Slen + 1] = (i & 0x00ff0000) >> 16; + tmp[Slen + 2] = (i & 0x0000ff00) >> 8; + tmp[Slen + 3] = (i & 0x000000ff) >> 0; + + rc = grub_crypto_hmac_buffer (md, P, Plen, tmp, tmplen, U); + } + else + rc = grub_crypto_hmac_buffer (md, P, Plen, U, hLen, U); + + if (rc != GPG_ERR_NO_ERROR) + { + grub_free (tmp); + return rc; + } + + for (k = 0; k < hLen; k++) + T[k] ^= U[k]; + } + + grub_memcpy (DK + (i - 1) * hLen, T, i == l ? r : hLen); + } + + grub_free (tmp); + + return GPG_ERR_NO_ERROR; +} From 10e53efaee09c05c91f3f8b79230d45e3db6c496 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 15 Nov 2009 23:31:27 +0100 Subject: [PATCH 13/28] crypto_memcmp --- include/grub/crypto.h | 6 ++++++ lib/crypto.c | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/include/grub/crypto.h b/include/grub/crypto.h index df15f9bb9..4d8ce88b8 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -242,8 +242,11 @@ grub_crypto_hmac_buffer (const struct gcry_md_spec *md, void *data, grub_size_t datalen, void *out); extern gcry_md_spec_t _gcry_digest_spec_md5; +extern gcry_md_spec_t _gcry_digest_spec_sha1; +extern gcry_md_spec_t _gcry_digest_spec_sha256; #define GRUB_MD_MD5 ((const gcry_md_spec_t *) &_gcry_digest_spec_md5) #define GRUB_MD_SHA1 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha1) +#define GRUB_MD_SHA256 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha256) /* Implement PKCS#5 PBKDF2 as per RFC 2898. The PRF to use is HMAC variant of digest supplied by MD. Inputs are the password P of length PLEN, @@ -258,4 +261,7 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md, unsigned int c, grub_uint8_t *DK, grub_size_t dkLen); +int +grub_crypto_memcmp (void *a, void *b, grub_size_t n); + #endif diff --git a/lib/crypto.c b/lib/crypto.c index 3cb66f942..4b36dde6f 100644 --- a/lib/crypto.c +++ b/lib/crypto.c @@ -370,3 +370,18 @@ grub_crypto_gcry_error (gcry_err_code_t in) return GRUB_ERR_NONE; return GRUB_ACCESS_DENIED; } + +int +grub_crypto_memcmp (void *a, void *b, grub_size_t n) +{ + register grub_size_t counter = 0; + grub_uint8_t *pa, *pb; + + for (pa = a, pb = b; n; pa++, pb++, n--) + { + if (*pa != *pb) + counter++; + } + + return !!counter; +} From 228734ab023191ff8df42e83c615d7ab610a3aea Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 15 Nov 2009 23:36:42 +0100 Subject: [PATCH 14/28] MAX_PASSLEN based authentication --- commands/password.c | 13 ++++++++--- include/grub/auth.h | 7 +----- normal/auth.c | 56 ++------------------------------------------- 3 files changed, 13 insertions(+), 63 deletions(-) diff --git a/commands/password.c b/commands/password.c index 0e048797e..247e0bffd 100644 --- a/commands/password.c +++ b/commands/password.c @@ -26,18 +26,20 @@ static grub_dl_t my_mod; +#define MAX_PASSLEN 1024 + static grub_err_t check_password (const char *user, void *password) { - char entered[1024]; + char entered[MAX_PASSLEN]; grub_memset (entered, 0, sizeof (entered)); if (!GRUB_GET_PASSWORD (entered, sizeof (entered) - 1)) return GRUB_ACCESS_DENIED; - if (grub_auth_strcmp (entered, password) != 0) + if (grub_crypto_memcmp (entered, password, MAX_PASSLEN) != 0) return GRUB_ACCESS_DENIED; grub_auth_authenticate (user); @@ -51,13 +53,18 @@ grub_cmd_password (grub_command_t cmd __attribute__ ((unused)), { grub_err_t err; char *pass; + int copylen; if (argc != 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, "Two arguments expected."); - pass = grub_strdup (args[1]); + pass = grub_zalloc (MAX_PASSLEN); if (!pass) return grub_errno; + copylen = grub_strlen (argv[1]); + if (copylen >= MAX_PASSLEN) + copylen = MAX_PASSLEN - 1; + grub_memcpy (pass, argv[1], copylen); err = grub_auth_register_authentication (args[0], check_password, pass); if (err) diff --git a/include/grub/auth.h b/include/grub/auth.h index da930eeda..e72d984ae 100644 --- a/include/grub/auth.h +++ b/include/grub/auth.h @@ -15,7 +15,7 @@ * You should have received a copy of the GNU General Public License * along with GRUB. If not, see . */ -#ifndef GRUB_AURH_HEADER +#ifndef GRUB_AUTH_HEADER #define GRUB_AUTH_HEADER 1 #include @@ -26,11 +26,6 @@ string, len, \ '*', 0, 0) -/* Like strcmp but untimeable. Accepts NULL as second argument. */ -int grub_auth_strcmp (const char *user_input, const char *template); -/* Like strcmp but untimeable and ignores commas in needle. */ -int grub_auth_strword (const char *haystack, const char *needle); - typedef grub_err_t (*grub_auth_callback_t) (const char*, void *); grub_err_t grub_auth_register_authentication (const char *user, diff --git a/normal/auth.c b/normal/auth.c index c71262584..7d5a07d26 100644 --- a/normal/auth.c +++ b/normal/auth.c @@ -35,58 +35,6 @@ struct grub_auth_user struct grub_auth_user *users = NULL; -int -grub_auth_strcmp (const char *s1, const char *s2) -{ - int ret; - grub_uint64_t end; - - end = grub_get_time_ms () + 100; - ret = grub_strcmp (s1, s2); - - /* This prevents an attacker from deriving information about the - password from the time it took to execute this function. */ - while (grub_get_time_ms () < end); - - return ret; -} - -static int -grub_iswordseparator (int c) -{ - return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&'); -} - -int -grub_auth_strword (const char *haystack, const char *needle) -{ - const char *n_pos = needle; - int found = 0; - - while (grub_iswordseparator (*haystack)) - haystack++; - - while (*haystack) - { - int ok = 1; - /* Crawl both the needle and the haystack word we're on. */ - while(*haystack && !grub_iswordseparator (*haystack)) - { - if (*haystack == *n_pos && ok) - n_pos++; - else - ok = 0; - - haystack++; - } - - if (ok) - found = 1; - } - - return found; -} - grub_err_t grub_auth_register_authentication (const char *user, grub_auth_callback_t callback, @@ -193,8 +141,8 @@ is_authenticated (const char *userlist) return 0; name = ((struct grub_auth_user *) item)->name; - return (userlist && grub_auth_strword (userlist, name)) - || grub_auth_strword (superusers, name); + return (userlist && grub_strword (userlist, name)) + || grub_strword (superusers, name); } superusers = grub_env_get ("superusers"); From 53eb42a6fac7fa4dc13f485b2dff6127a484b036 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 15 Nov 2009 23:42:11 +0100 Subject: [PATCH 15/28] Compilation error fixed --- commands/password.c | 5 +++-- normal/auth.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/commands/password.c b/commands/password.c index 247e0bffd..99b993839 100644 --- a/commands/password.c +++ b/commands/password.c @@ -17,6 +17,7 @@ */ #include +#include #include #include #include @@ -61,10 +62,10 @@ grub_cmd_password (grub_command_t cmd __attribute__ ((unused)), pass = grub_zalloc (MAX_PASSLEN); if (!pass) return grub_errno; - copylen = grub_strlen (argv[1]); + copylen = grub_strlen (args[1]); if (copylen >= MAX_PASSLEN) copylen = MAX_PASSLEN - 1; - grub_memcpy (pass, argv[1], copylen); + grub_memcpy (pass, args[1], copylen); err = grub_auth_register_authentication (args[0], check_password, pass); if (err) diff --git a/normal/auth.c b/normal/auth.c index 7d5a07d26..0a8b5bc82 100644 --- a/normal/auth.c +++ b/normal/auth.c @@ -164,7 +164,7 @@ grub_auth_check_authentication (const char *userlist) auto int hook (grub_list_t item); int hook (grub_list_t item) { - if (grub_auth_strcmp (login, ((struct grub_auth_user *) item)->name) == 0) + if (grub_strcmp (login, ((struct grub_auth_user *) item)->name) == 0) cur = (struct grub_auth_user *) item; return 0; } From 0e3c54a5c515e4d3b956b46e800396c55b244804 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Tue, 24 Nov 2009 02:36:21 +0100 Subject: [PATCH 16/28] PBKDF2 passwords available --- .bzrignore | 56 ++++++ commands/password_pbkdf2.c | 202 ++++++++++++++++++++++ conf/common.rmk | 9 + conf/i386-coreboot.rmk | 2 +- conf/i386-efi.rmk | 2 +- conf/i386-ieee1275.rmk | 2 +- conf/i386-pc.rmk | 2 +- conf/powerpc-ieee1275.rmk | 2 +- conf/sparc64-ieee1275.rmk | 2 +- conf/x86_64-efi.rmk | 2 +- include/grub/crypto.h | 2 + util/grub-pbkdf2.c | 337 +++++++++++++++++++++++++++++++++++++ 12 files changed, 613 insertions(+), 7 deletions(-) create mode 100644 .bzrignore create mode 100644 commands/password_pbkdf2.c create mode 100644 util/grub-pbkdf2.c diff --git a/.bzrignore b/.bzrignore new file mode 100644 index 000000000..e5d7be2d4 --- /dev/null +++ b/.bzrignore @@ -0,0 +1,56 @@ +00_header +10_* +30_os-prober +40_custom +autom4te.cache +build_env.mk +.bzrignore +config.cache +config.h +config.h.in +config.log +config.status +configure +conf/*.mk +*.d +DISTLIST +docs/*.info +docs/stamp-vti +docs/version.texi +*.elf +*.exec +genkernsyms.sh +gensymlist.sh +grub-dumpbios +grub-editenv +grub-emu +grub_emu_init.c +grub_emu_init.h +grub-fstest +grub_fstest_init.c +grub_fstest_init.h +grub-install +grub-mk* +grub-pbkdf2 +grub-pe2elf +grub-probe +grub_probe_init.c +grub_probe_init.h +grub_script.tab.c +grub_script.tab.h +grub-setup +grub_setup_init.c +grub_setup_init.h +*.img +include/grub/cpu +include/grub/machine +*.lst +Makefile +*.mod +mod-*.c +*.pf2 +stamp-h +stamp-h1 +stamp-h.in +symlist.c +update-grub_lib diff --git a/commands/password_pbkdf2.c b/commands/password_pbkdf2.c new file mode 100644 index 000000000..44da0101e --- /dev/null +++ b/commands/password_pbkdf2.c @@ -0,0 +1,202 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * Copyright (C) 2009 Vladimir 'phcoder' Serbineko + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +static grub_dl_t my_mod; + +struct pbkdf2_password +{ + grub_uint8_t *salt; + grub_size_t saltlen; + unsigned int c; + grub_uint8_t *expected; + grub_size_t buflen; +}; + +static grub_err_t +check_password (const char *user, void *pin) +{ + char entered[1024]; + grub_uint8_t *buf; + struct pbkdf2_password *pass = pin; + gcry_err_code_t err; + + grub_memset (entered, 0, sizeof (entered)); + + if (!GRUB_GET_PASSWORD (entered, sizeof (entered) - 1)) + return GRUB_ACCESS_DENIED; + + buf = grub_malloc (pass->buflen); + if (!buf) + return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY); + + err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, (grub_uint8_t *) &entered, + grub_strlen (entered), + pass->salt, pass->saltlen, pass->c, + buf, pass->buflen); + if (err) + { + grub_free (buf); + return grub_crypto_gcry_error (err); + } + + if (grub_crypto_memcmp (buf, pass->expected, pass->buflen) != 0) + return GRUB_ACCESS_DENIED; + + grub_auth_authenticate (user); + + return GRUB_ERR_NONE; +} + +static inline int +hex2val (char hex) +{ + if ('0' <= hex && hex <= '9') + return hex - '0'; + if ('a' <= hex && hex <= 'f') + return hex - 'a' + 10; + if ('A' <= hex && hex <= 'F') + return hex - 'A' + 10; + return -1; +} + +static grub_err_t +grub_cmd_password (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + grub_err_t err; + char *ptr, *ptr2; + grub_uint8_t *ptro; + struct pbkdf2_password *pass; + + if (argc != 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Two arguments expected."); + + if (grub_memcmp (args[1], "grub.pbkdf2.sha512.", + sizeof ("grub.pbkdf2.sha512.") - 1) != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password."); + + ptr = args[1] + sizeof ("grub.pbkdf2.sha512.") - 1; + + pass = grub_malloc (sizeof (*pass)); + if (!pass) + return grub_errno; + + pass->c = grub_strtoul (ptr, &ptr, 0); + if (*ptr != '.') + { + grub_free (pass); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password."); + } + ptr++; + + ptr2 = grub_strchr (ptr, '.'); + if (!ptr2 || ((ptr2 - ptr) & 1) || grub_strlen (ptr2 + 1) & 1) + { + grub_free (pass); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "Incorrect PBKDF2 password."); + } + + pass->saltlen = (ptr2 - ptr) >> 1; + pass->buflen = grub_strlen (ptr2 + 1) >> 1; + ptro = pass->salt = grub_malloc (pass->saltlen); + if (!ptro) + { + grub_free (pass); + return grub_errno; + } + while (ptr < ptr2) + { + int hex1, hex2; + hex1 = hex2val (*ptr); + ptr++; + hex2 = hex2val (*ptr); + ptr++; + if (hex1 < 0 || hex2 < 0) + { + grub_free (pass->salt); + grub_free (pass); + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Incorrect PBKDF2 password."); + } + + *ptro = (hex1 << 4) | hex2; + ptro++; + } + + ptro = pass->expected = grub_malloc (pass->buflen); + if (!ptro) + { + grub_free (pass->salt); + grub_free (pass); + return grub_errno; + } + ptr = ptr2 + 1; + ptr2 += grub_strlen (ptr2); + while (ptr < ptr2) + { + int hex1, hex2; + hex1 = hex2val (*ptr); + ptr++; + hex2 = hex2val (*ptr); + ptr++; + if (hex1 < 0 || hex2 < 0) + { + grub_free (pass->expected); + grub_free (pass->salt); + grub_free (pass); + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "Incorrect PBKDF2 password."); + } + + *ptro = (hex1 << 4) | hex2; + ptro++; + } + + err = grub_auth_register_authentication (args[0], check_password, pass); + if (err) + { + grub_free (pass); + return err; + } + grub_dl_ref (my_mod); + return GRUB_ERR_NONE; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(password_pbkdf2) +{ + my_mod = mod; + cmd = grub_register_command ("password_pbkdf2", grub_cmd_password, + "password_pbkdf2 USER PBKDF2_PASSWORD", + "Set user password (PBKDF2). "); +} + +GRUB_MOD_FINI(password_pbkdf2) +{ + grub_unregister_command (cmd); +} diff --git a/conf/common.rmk b/conf/common.rmk index 3356c556b..eae37acde 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -629,4 +629,13 @@ pbkdf2_mod_SOURCES = lib/pbkdf2.c pbkdf2_mod_CFLAGS = $(COMMON_CFLAGS) pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For password_pbkdf2.mod. +pkglib_MODULES += password_pbkdf2.mod +password_pbkdf2_mod_SOURCES = commands/password_pbkdf2.c +password_pbkdf2_mod_CFLAGS = $(COMMON_CFLAGS) +password_pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS) + +bin_UTILITIES += grub-pbkdf2 +grub_pbkdf2_SOURCES = util/grub-pbkdf2.c lib/crypto.c gcry/cipher/sha512.c lib/pbkdf2.c util/misc.c kern/err.c + include $(srcdir)/conf/gcry.mk diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index 5645395b8..83a49d398 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -130,7 +130,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/partition.c kern/reader.c kern/term.c \ kern/rescue_reader.c kern/rescue_parser.c \ lib/arg.c normal/cmdline.c normal/misc.c \ - normal/handler.c normal/auth.c normal/autofs.c \ + normal/handler.c normal/auth.c lib/crypto.c normal/autofs.c \ normal/completion.c normal/datetime.c normal/main.c \ normal/menu_text.c \ normal/menu.c normal/menu_entry.c normal/menu_viewer.c \ diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk index 99ab06f64..6c9e8862f 100644 --- a/conf/i386-efi.rmk +++ b/conf/i386-efi.rmk @@ -57,7 +57,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/partition.c kern/reader.c kern/term.c \ kern/rescue_reader.c kern/rescue_parser.c \ lib/arg.c normal/cmdline.c normal/command.c normal/datetime.c \ - normal/auth.c normal/autofs.c \ + normal/auth.c lib/crypto.c normal/autofs.c \ normal/completion.c normal/context.c normal/main.c \ normal/menu.c normal/menu_entry.c normal/menu_viewer.c \ normal/menu_text.c \ diff --git a/conf/i386-ieee1275.rmk b/conf/i386-ieee1275.rmk index 4b640de49..6042676ea 100644 --- a/conf/i386-ieee1275.rmk +++ b/conf/i386-ieee1275.rmk @@ -85,7 +85,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/partition.c kern/reader.c kern/term.c \ kern/rescue_reader.c kern/rescue_parser.c \ lib/arg.c normal/cmdline.c normal/datetime.c normal/misc.c \ - normal/handler.c normal/auth.c normal/autofs.c \ + normal/handler.c normal/auth.c lib/crypto.c normal/autofs.c \ normal/completion.c normal/main.c normal/menu_text.c \ normal/menu.c normal/menu_entry.c normal/menu_viewer.c \ normal/color.c \ diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index ac9337e41..0372b529d 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -137,7 +137,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/partition.c kern/reader.c kern/term.c \ kern/rescue_reader.c kern/rescue_parser.c \ lib/arg.c normal/cmdline.c normal/datetime.c normal/misc.c \ - normal/handler.c normal/auth.c normal/autofs.c \ + normal/handler.c normal/auth.c lib/crypto.c normal/autofs.c \ normal/completion.c normal/main.c normal/color.c \ normal/menu.c normal/menu_entry.c normal/menu_viewer.c \ normal/menu_text.c \ diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk index ee7f9ec27..344aa17ac 100644 --- a/conf/powerpc-ieee1275.rmk +++ b/conf/powerpc-ieee1275.rmk @@ -65,7 +65,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/command.c kern/corecmd.c commands/extcmd.c \ lib/arg.c normal/cmdline.c normal/datetime.c \ normal/completion.c normal/misc.c \ - normal/handler.c normal/auth.c normal/autofs.c normal/main.c \ + normal/handler.c normal/auth.c lib/crypto.c normal/autofs.c normal/main.c \ normal/menu.c \ normal/menu_text.c \ normal/menu_entry.c normal/menu_viewer.c \ diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk index 62e951a5e..de67a131a 100644 --- a/conf/sparc64-ieee1275.rmk +++ b/conf/sparc64-ieee1275.rmk @@ -123,7 +123,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/command.c kern/corecmd.c commands/extcmd.c \ lib/arg.c normal/cmdline.c normal/datetime.c \ normal/completion.c normal/misc.c \ - normal/handler.c normal/auth.c normal/autofs.c normal/main.c \ + normal/handler.c normal/auth.c lib/crypto.c normal/autofs.c normal/main.c \ normal/menu.c \ normal/menu_text.c \ normal/menu_entry.c normal/menu_viewer.c \ diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk index 5be1b404f..d671f152b 100644 --- a/conf/x86_64-efi.rmk +++ b/conf/x86_64-efi.rmk @@ -53,7 +53,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ kern/command.c kern/corecmd.c commands/extcmd.c kern/file.c \ kern/fs.c commands/boot.c kern/main.c kern/misc.c kern/parser.c \ kern/partition.c kern/readerescue.c kern/term.c \ - lib/arg.c normal/cmdline.c normal/misc.c normal/auth.c \ + lib/arg.c normal/cmdline.c normal/misc.c normal/auth.c lib/crypto.c \ normal/autofs.c \ normal/completion.c normal/datetime.c normal/context.c \ normal/main.c \ diff --git a/include/grub/crypto.h b/include/grub/crypto.h index 4d8ce88b8..eb1898fe4 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -244,9 +244,11 @@ grub_crypto_hmac_buffer (const struct gcry_md_spec *md, extern gcry_md_spec_t _gcry_digest_spec_md5; extern gcry_md_spec_t _gcry_digest_spec_sha1; extern gcry_md_spec_t _gcry_digest_spec_sha256; +extern gcry_md_spec_t _gcry_digest_spec_sha512; #define GRUB_MD_MD5 ((const gcry_md_spec_t *) &_gcry_digest_spec_md5) #define GRUB_MD_SHA1 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha1) #define GRUB_MD_SHA256 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha256) +#define GRUB_MD_SHA512 ((const gcry_md_spec_t *) &_gcry_digest_spec_sha512) /* Implement PKCS#5 PBKDF2 as per RFC 2898. The PRF to use is HMAC variant of digest supplied by MD. Inputs are the password P of length PLEN, diff --git a/util/grub-pbkdf2.c b/util/grub-pbkdf2.c new file mode 100644 index 000000000..a05fa62b1 --- /dev/null +++ b/util/grub-pbkdf2.c @@ -0,0 +1,337 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 1992-1999,2001,2003,2004,2005,2009 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +/* Few functions to make crypto happy. */ +void * +grub_memmove (void *dest, const void *src, grub_size_t n) +{ + return memmove (dest, src, n); +} + +void * +grub_memset (void *s, int c, grub_size_t n) +{ + return memset (s, c, n); +} + +int +grub_vprintf (const char *fmt, va_list args) +{ + return vprintf (fmt, args); +} + +int +grub_vsprintf (char *str, const char *fmt, va_list args) +{ + return vsprintf (str, fmt, args); +} + +void +grub_abort (void) +{ + abort (); +} + +static struct option options[] = + { + {"iteration_count", required_argument, 0, 'c'}, + {"buflen", required_argument, 0, 'l'}, + {"saltlen", required_argument, 0, 's'}, + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try ``grub-scrypt --help'' for more information.\n"); + else + printf ("\ +Usage: grub-scrypt [OPTIONS]\n\ +\nOptions:\n\ + -c number, --iteration-count=number Number of PBKDF2 iterations\n\ + -l number, --buflen=number Length of generated hash\n\ + -s number, --salt=number Length of salt\n\ +\n\ +Report bugs to <%s>.\n", PACKAGE_BUGREPORT); + + exit (status); +} + +static void +hexify (char *hex, grub_uint8_t *bin, grub_size_t n) +{ + while (n--) + { + if (((*bin & 0xf0) >> 4) < 10) + *hex = ((*bin & 0xf0) >> 4) + '0'; + else + *hex = ((*bin & 0xf0) >> 4) + 'A' - 10; + hex++; + + if ((*bin & 0xf) < 10) + *hex = (*bin & 0xf) + '0'; + else + *hex = (*bin & 0xf) + 'A' - 10; + hex++; + bin++; + } + *hex = 0; +} + +int +main (int argc, char *argv[]) +{ + unsigned int c = 10000, buflen = 64, saltlen = 64; + char *pass1, *pass2; + char *bufhex, *salthex; + gcry_err_code_t gcry_err; + grub_uint8_t *buf, *salt; + ssize_t nr; + FILE *in, *out; + struct termios s, t; + int tty_changed; + + progname = "grub-pbkdf2"; + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "c:l:s:hvV", options, 0); + + if (c == -1) + break; + + switch (c) + { + case 'c': + c = strtoul (optarg, NULL, 0); + break; + + case 'l': + buflen = strtoul (optarg, NULL, 0); + break; + + case 's': + saltlen = strtoul (optarg, NULL, 0); + break; + + case 'h': + usage (0); + return 0; + + case 'V': + printf ("%s (%s) %s\n", progname, + PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + default: + usage (1); + return 1; + } + } + + bufhex = malloc (buflen * 2 + 1); + if (!bufhex) + grub_util_error ("Out of memory"); + buf = malloc (buflen); + if (!buf) + { + free (bufhex); + grub_util_error ("Out of memory"); + } + + salt = malloc (saltlen); + if (!salt) + { + free (bufhex); + free (buf); + grub_util_error ("Out of memory"); + } + salthex = malloc (saltlen * 2 + 1); + if (!salthex) + { + free (salt); + free (bufhex); + free (buf); + grub_util_error ("Out of memory"); + } + + /* Disable echoing. Based on glibc. */ + in = fopen ("/dev/tty", "w+c"); + if (in == NULL) + { + in = stdin; + out = stderr; + } + else + out = in; + + if (tcgetattr (fileno (in), &t) == 0) + { + /* Save the old one. */ + s = t; + /* Tricky, tricky. */ + t.c_lflag &= ~(ECHO|ISIG); + tty_changed = (tcsetattr (fileno (in), TCSAFLUSH, &t) == 0); + } + else + tty_changed = 0; + + printf ("Enter password: "); + pass1 = NULL; + { + grub_size_t n; + nr = getline (&pass1, &n, stdin); + } + if (nr < 0 || !pass1) + { + free (buf); + free (bufhex); + free (salthex); + free (salt); + /* Restore the original setting. */ + if (tty_changed) + (void) tcsetattr (fileno (in), TCSAFLUSH, &s); + grub_util_error ("Failure to read password"); + } + if (nr >= 1 && pass1[nr-1] == '\n') + pass1[nr-1] = 0; + + printf ("\nReenter password: "); + pass2 = NULL; + { + grub_size_t n; + nr = getline (&pass2, &n, stdin); + } + /* Restore the original setting. */ + if (tty_changed) + (void) tcsetattr (fileno (in), TCSAFLUSH, &s); + printf ("\n"); + + if (nr < 0 || !pass2) + { + memset (pass1, 0, strlen (pass1)); + free (pass1); + free (buf); + free (bufhex); + free (salthex); + free (salt); + grub_util_error ("Failure to read password"); + } + if (nr >= 1 && pass2[nr-1] == '\n') + pass2[nr-1] = 0; + + if (strcmp (pass1, pass2) != 0) + { + memset (pass1, 0, strlen (pass1)); + memset (pass2, 0, strlen (pass2)); + free (pass1); + free (pass2); + free (buf); + free (bufhex); + free (salthex); + free (salt); + grub_util_error ("Passwords don't match"); + } + memset (pass2, 0, strlen (pass2)); + free (pass2); + +#if ! defined (__linux__) && ! defined (__FreeBSD__) + printf ("WARNING: your random generator isn't known to be secure\n"); +#endif + + { + FILE *f; + size_t rd; + f = fopen ("/dev/random", "rb"); + if (!f) + { + memset (pass1, 0, strlen (pass1)); + free (pass1); + free (buf); + free (bufhex); + free (salthex); + free (salt); + fclose (f); + grub_util_error ("Couldn't retrieve random data for salt"); + } + rd = fread (salt, 1, saltlen, f); + if (rd != saltlen) + { + fclose (f); + memset (pass1, 0, strlen (pass1)); + free (pass1); + free (buf); + free (bufhex); + free (salthex); + free (salt); + fclose (f); + grub_util_error ("Couldn't retrieve random data for salt"); + } + fclose (f); + } + + gcry_err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, + (grub_uint8_t *) pass1, strlen (pass1), + salt, saltlen, + c, buf, buflen); + memset (pass1, 0, strlen (pass1)); + free (pass1); + + if (gcry_err) + { + memset (buf, 0, buflen); + memset (bufhex, 0, 2 * buflen); + free (buf); + free (bufhex); + memset (salt, 0, saltlen); + memset (salthex, 0, 2 * saltlen); + free (salt); + free (salthex); + grub_util_error ("Cryptographic error number %d", gcry_err); + } + + hexify (bufhex, buf, buflen); + hexify (salthex, salt, saltlen); + + printf ("Your PBKDF2 is grub.pbkdf2.sha512.%d.%s.%s\n", c, salthex, bufhex); + memset (buf, 0, buflen); + memset (bufhex, 0, 2 * buflen); + free (buf); + free (bufhex); + memset (salt, 0, saltlen); + memset (salthex, 0, 2 * saltlen); + free (salt); + free (salthex); + + return 0; +} From 5edd456216b1d6f648f405ba8a065235f015997a Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Mon, 16 Nov 2009 14:33:44 +0100 Subject: [PATCH 17/28] Remove leftover kern/crypto.c --- kern/crypto.c | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 kern/crypto.c diff --git a/kern/crypto.c b/kern/crypto.c deleted file mode 100644 index d097e1668..000000000 --- a/kern/crypto.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * GRUB -- GRand Unified Bootloader - * Copyright (C) 1999, 2001, 2002, 2003, 2007, - * 2008, 2009 Free Software Foundation, Inc. - * - * GRUB 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 3 of the License, or - * (at your option) any later version. - * - * GRUB 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 GRUB. If not, see . - */ -#include -#include -#include - -gcry_cipher_spec_t *grub_ciphers = NULL; -gcry_md_spec_t *grub_digests = NULL; - -/* Based on libgcrypt-1.4.4/src/misc.c. */ -void -grub_burn_stack (grub_size_t size) -{ - char buf[64]; - - grub_memset (buf, 0, sizeof (buf)); - if (size > sizeof (buf)) - grub_burn_stack (size - sizeof (buf)); -} From f78821e5bc473ce99b2bba9b9ce38e17f9149e3d Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 19 Nov 2009 23:10:40 +0100 Subject: [PATCH 18/28] Removed extraneous copyright line --- commands/password_pbkdf2.c | 1 - 1 file changed, 1 deletion(-) diff --git a/commands/password_pbkdf2.c b/commands/password_pbkdf2.c index 44da0101e..38481f362 100644 --- a/commands/password_pbkdf2.c +++ b/commands/password_pbkdf2.c @@ -1,7 +1,6 @@ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2009 Free Software Foundation, Inc. - * Copyright (C) 2009 Vladimir 'phcoder' Serbineko * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From a261f807286581cbc86b08fa8141cc617bc6b842 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 26 Nov 2009 17:14:39 +0100 Subject: [PATCH 19/28] Added origin notice to lib/pbkdf2.c --- lib/pbkdf2.c | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pbkdf2.c b/lib/pbkdf2.c index f2d3ca97f..083446ab9 100644 --- a/lib/pbkdf2.c +++ b/lib/pbkdf2.c @@ -16,6 +16,7 @@ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Written by Simon Josefsson. */ +/* Imported from gnulib. */ #include #include From 84c6b0863ff40de102f9f0845136d1964ad94f43 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Thu, 26 Nov 2009 17:34:22 +0100 Subject: [PATCH 20/28] renamed grub-pbkdf2 into grub-mkpasswd-pbkdf2 --- conf/common.rmk | 4 ++-- util/{grub-pbkdf2.c => grub-mkpasswd-pbkdf2.c} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename util/{grub-pbkdf2.c => grub-mkpasswd-pbkdf2.c} (99%) diff --git a/conf/common.rmk b/conf/common.rmk index 58b1d8a31..f680655ed 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -638,7 +638,7 @@ password_pbkdf2_mod_SOURCES = commands/password_pbkdf2.c password_pbkdf2_mod_CFLAGS = $(COMMON_CFLAGS) password_pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS) -bin_UTILITIES += grub-pbkdf2 -grub_pbkdf2_SOURCES = util/grub-pbkdf2.c lib/crypto.c lib/libgcrypt-grub/cipher/sha512.c lib/pbkdf2.c util/misc.c kern/err.c +bin_UTILITIES += grub-mkpasswd-pbkdf2 +grub_mkpasswd_pbkdf2_SOURCES = util/grub-mkpasswd-pbkdf2.c lib/crypto.c lib/libgcrypt-grub/cipher/sha512.c lib/pbkdf2.c util/misc.c kern/err.c include $(srcdir)/conf/gcry.mk diff --git a/util/grub-pbkdf2.c b/util/grub-mkpasswd-pbkdf2.c similarity index 99% rename from util/grub-pbkdf2.c rename to util/grub-mkpasswd-pbkdf2.c index a05fa62b1..ad52aae91 100644 --- a/util/grub-pbkdf2.c +++ b/util/grub-mkpasswd-pbkdf2.c @@ -120,7 +120,7 @@ main (int argc, char *argv[]) struct termios s, t; int tty_changed; - progname = "grub-pbkdf2"; + progname = "grub-mkpasswd-pbkdf2"; /* Check for options. */ while (1) From 9d1fafb96e554d6246ae14b42887f3d9774458b5 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 5 Dec 2009 16:33:39 +0100 Subject: [PATCH 21/28] Move include/grub/cipher_wrap.h to lib/libgcrypt_wrap/cipher_wrap.h --- conf/common.rmk | 1 + .../grub => lib/libgcrypt_wrap}/cipher_wrap.h | 0 util/import_gcry.py | 23 +++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) rename {include/grub => lib/libgcrypt_wrap}/cipher_wrap.h (100%) diff --git a/conf/common.rmk b/conf/common.rmk index f680655ed..376700be2 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -640,5 +640,6 @@ password_pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS) bin_UTILITIES += grub-mkpasswd-pbkdf2 grub_mkpasswd_pbkdf2_SOURCES = util/grub-mkpasswd-pbkdf2.c lib/crypto.c lib/libgcrypt-grub/cipher/sha512.c lib/pbkdf2.c util/misc.c kern/err.c +grub_mkpasswd_pbkdf2_CFLAGS += -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap include $(srcdir)/conf/gcry.mk diff --git a/include/grub/cipher_wrap.h b/lib/libgcrypt_wrap/cipher_wrap.h similarity index 100% rename from include/grub/cipher_wrap.h rename to lib/libgcrypt_wrap/cipher_wrap.h diff --git a/util/import_gcry.py b/util/import_gcry.py index b66de90cc..fe68c85a4 100644 --- a/util/import_gcry.py +++ b/util/import_gcry.py @@ -67,6 +67,12 @@ for cipher_file in cipher_files: if cipher_file == "ChangeLog": continue chlognew = " * %s" % cipher_file + if re.match ("(Manifest|Makefile\.am|ac\.c|cipher\.c|hash-common\.c|hmac-tests\.c|md\.c|pubkey\.c)$", cipher_file): + chlog = "%s%s: Removed\n" % (chlog, chlognew) + continue + # Autogenerated files. Not even worth mentionning in ChangeLog + if re.match ("Makefile\.in$", cipher_file): + continue nch = False if re.match (".*\.[ch]$", cipher_file): isc = re.match (".*\.c$", cipher_file) @@ -220,7 +226,7 @@ for cipher_file in cipher_files: conf.write ("pkglib_MODULES += %s.mod\n" % modname) conf.write ("%s_mod_SOURCES = %s\n" %\ (modname, modfiles)) - conf.write ("%s_mod_CFLAGS = $(COMMON_CFLAGS) -Wno-missing-field-initializers -Wno-error\n" % modname) + conf.write ("%s_mod_CFLAGS = $(COMMON_CFLAGS) -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap\n" % modname) conf.write ("%s_mod_LDFLAGS = $(COMMON_LDFLAGS)\n\n" % modname) elif isc and cipher_file != "camellia.c": print ("WARNING: C file isn't a module: %s" % cipher_file) @@ -229,26 +235,19 @@ for cipher_file in cipher_files: if nch: chlog = "%s%s\n" % (chlog, chlognew) continue - if re.match ("(Manifest|Makefile\.am)$", cipher_file): - chlog = "%s%sRemoved\n" % (chlog, chlognew) - continue - # Autogenerated files. Not even worth mentionning in ChangeLog - if re.match ("Makefile\.in$", cipher_file): - chlog = "%s%sRemoved\n" % (chlog, chlognew) - continue chlog = "%s%sSkipped unknown file\n" % (chlog, chlognew) print ("WARNING: unknown file %s" % cipher_file) outfile = os.path.join (cipher_dir_out, "types.h") fw=open (outfile, "w") fw.write ("#include \n") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * types.h: New file.\n" % chlog fw.close () outfile = os.path.join (cipher_dir_out, "memory.h") fw=open (outfile, "w") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * memory.h: New file.\n" % chlog fw.close () @@ -256,13 +255,13 @@ fw.close () outfile = os.path.join (cipher_dir_out, "cipher.h") fw=open (outfile, "w") fw.write ("#include \n") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * cipher.h: Likewise.\n" % chlog fw.close () outfile = os.path.join (cipher_dir_out, "g10lib.h") fw=open (outfile, "w") -fw.write ("#include \n") +fw.write ("#include \n") chlog = "%s * g10lib.h: Likewise.\n" % chlog fw.close () From fd39f820fdbd4fdb9d82cdc6befecdd25904709a Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 5 Dec 2009 18:59:36 +0100 Subject: [PATCH 22/28] fix mismerge with trunk (progname) --- conf/common.rmk | 2 +- util/grub-mkpasswd-pbkdf2.c | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/conf/common.rmk b/conf/common.rmk index 395d6b17b..0c6fb0cae 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -650,7 +650,7 @@ password_pbkdf2_mod_CFLAGS = $(COMMON_CFLAGS) password_pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS) bin_UTILITIES += grub-mkpasswd-pbkdf2 -grub_mkpasswd_pbkdf2_SOURCES = util/grub-mkpasswd-pbkdf2.c lib/crypto.c lib/libgcrypt-grub/cipher/sha512.c lib/pbkdf2.c util/misc.c kern/err.c +grub_mkpasswd_pbkdf2_SOURCES = gnulib/progname.c util/grub-mkpasswd-pbkdf2.c lib/crypto.c lib/libgcrypt-grub/cipher/sha512.c lib/pbkdf2.c util/misc.c kern/err.c grub_mkpasswd_pbkdf2_CFLAGS += -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap include $(srcdir)/conf/gcry.mk diff --git a/util/grub-mkpasswd-pbkdf2.c b/util/grub-mkpasswd-pbkdf2.c index ad52aae91..2f7c5efaa 100644 --- a/util/grub-mkpasswd-pbkdf2.c +++ b/util/grub-mkpasswd-pbkdf2.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -27,6 +28,7 @@ #include #include +#include "progname.h" /* Few functions to make crypto happy. */ void * @@ -120,7 +122,10 @@ main (int argc, char *argv[]) struct termios s, t; int tty_changed; - progname = "grub-mkpasswd-pbkdf2"; + set_program_name (argv[0]); + setlocale (LC_ALL, ""); + bindtextdomain (PACKAGE, LOCALEDIR); + textdomain (PACKAGE); /* Check for options. */ while (1) @@ -149,7 +154,7 @@ main (int argc, char *argv[]) return 0; case 'V': - printf ("%s (%s) %s\n", progname, + printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION); return 0; From c0a6bd447e6d551df5dc27128ad539f00abf7e39 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 5 Dec 2009 20:45:32 +0100 Subject: [PATCH 23/28] fix *-emu build --- conf/any-emu.rmk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conf/any-emu.rmk b/conf/any-emu.rmk index 9038b07df..cf13d2b67 100644 --- a/conf/any-emu.rmk +++ b/conf/any-emu.rmk @@ -45,7 +45,10 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ disk/raid.c disk/raid5_recover.c disk/raid6_recover.c \ disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ commands/parttool.c parttool/msdospart.c \ + lib/libgcrypt-grub/cipher/md5.c \ grub_emu_init.c gnulib/progname.c +grub_emu_CFLAGS += -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap + ifeq ($(target_cpu), i386) grub_emu_SOURCES += commands/i386/cpuid.c From b391bdb2f2c5ccf29da66cecdbfb7566656a704d Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 6 Dec 2009 20:11:50 +0100 Subject: [PATCH 24/28] Use dedicated simple password retriever for size of future crypto disks modules and simplify entering passwords routines --- commands/password.c | 19 +++++----------- commands/password_pbkdf2.c | 11 +++------ conf/common.rmk | 2 +- include/grub/auth.h | 9 +++----- include/grub/crypto.h | 10 ++++++--- lib/crypto.c | 46 ++++++++++++++++++++++++++++++++++++-- normal/auth.c | 20 +++++++---------- 7 files changed, 71 insertions(+), 46 deletions(-) diff --git a/commands/password.c b/commands/password.c index 99b993839..7bb2f0ae5 100644 --- a/commands/password.c +++ b/commands/password.c @@ -27,20 +27,11 @@ static grub_dl_t my_mod; -#define MAX_PASSLEN 1024 - static grub_err_t -check_password (const char *user, +check_password (const char *user, const char *entered, void *password) { - char entered[MAX_PASSLEN]; - - grub_memset (entered, 0, sizeof (entered)); - - if (!GRUB_GET_PASSWORD (entered, sizeof (entered) - 1)) - return GRUB_ACCESS_DENIED; - - if (grub_crypto_memcmp (entered, password, MAX_PASSLEN) != 0) + if (grub_crypto_memcmp (entered, password, GRUB_AUTH_MAX_PASSLEN) != 0) return GRUB_ACCESS_DENIED; grub_auth_authenticate (user); @@ -59,12 +50,12 @@ grub_cmd_password (grub_command_t cmd __attribute__ ((unused)), if (argc != 2) return grub_error (GRUB_ERR_BAD_ARGUMENT, "Two arguments expected."); - pass = grub_zalloc (MAX_PASSLEN); + pass = grub_zalloc (GRUB_AUTH_MAX_PASSLEN); if (!pass) return grub_errno; copylen = grub_strlen (args[1]); - if (copylen >= MAX_PASSLEN) - copylen = MAX_PASSLEN - 1; + if (copylen >= GRUB_AUTH_MAX_PASSLEN) + copylen = GRUB_AUTH_MAX_PASSLEN - 1; grub_memcpy (pass, args[1], copylen); err = grub_auth_register_authentication (args[0], check_password, pass); diff --git a/commands/password_pbkdf2.c b/commands/password_pbkdf2.c index 38481f362..51c8ea794 100644 --- a/commands/password_pbkdf2.c +++ b/commands/password_pbkdf2.c @@ -16,6 +16,7 @@ * along with GRUB. If not, see . */ +#include #include #include #include @@ -36,23 +37,17 @@ struct pbkdf2_password }; static grub_err_t -check_password (const char *user, void *pin) +check_password (const char *user, const char *entered, void *pin) { - char entered[1024]; grub_uint8_t *buf; struct pbkdf2_password *pass = pin; gcry_err_code_t err; - grub_memset (entered, 0, sizeof (entered)); - - if (!GRUB_GET_PASSWORD (entered, sizeof (entered) - 1)) - return GRUB_ACCESS_DENIED; - buf = grub_malloc (pass->buflen); if (!buf) return grub_crypto_gcry_error (GPG_ERR_OUT_OF_MEMORY); - err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, (grub_uint8_t *) &entered, + err = grub_crypto_pbkdf2 (GRUB_MD_SHA512, (grub_uint8_t *) entered, grub_strlen (entered), pass->salt, pass->saltlen, pass->c, buf, pass->buflen); diff --git a/conf/common.rmk b/conf/common.rmk index 0c6fb0cae..ad0e4942c 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -651,6 +651,6 @@ password_pbkdf2_mod_LDFLAGS = $(COMMON_LDFLAGS) bin_UTILITIES += grub-mkpasswd-pbkdf2 grub_mkpasswd_pbkdf2_SOURCES = gnulib/progname.c util/grub-mkpasswd-pbkdf2.c lib/crypto.c lib/libgcrypt-grub/cipher/sha512.c lib/pbkdf2.c util/misc.c kern/err.c -grub_mkpasswd_pbkdf2_CFLAGS += -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap +grub_mkpasswd_pbkdf2_CFLAGS += -Wno-missing-field-initializers -Wno-error -I$(srcdir)/lib/libgcrypt_wrap -DGRUB_MKPASSWD=1 include $(srcdir)/conf/gcry.mk diff --git a/include/grub/auth.h b/include/grub/auth.h index e72d984ae..747334451 100644 --- a/include/grub/auth.h +++ b/include/grub/auth.h @@ -19,14 +19,11 @@ #define GRUB_AUTH_HEADER 1 #include +#include -/* Macros for indistinguishibility. */ -#define GRUB_ACCESS_DENIED grub_error (GRUB_ERR_ACCESS_DENIED, "Access denied.") -#define GRUB_GET_PASSWORD(string, len) grub_cmdline_get ("Enter password: ", \ - string, len, \ - '*', 0, 0) +#define GRUB_AUTH_MAX_PASSLEN 1024 -typedef grub_err_t (*grub_auth_callback_t) (const char*, void *); +typedef grub_err_t (*grub_auth_callback_t) (const char *, const char *, void *); grub_err_t grub_auth_register_authentication (const char *user, grub_auth_callback_t callback, diff --git a/include/grub/crypto.h b/include/grub/crypto.h index eb1898fe4..3129131cb 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -26,8 +26,6 @@ #include #include #include -/* For GRUB_ACCESS_DENIED. */ -#include typedef enum { @@ -264,6 +262,12 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md, grub_uint8_t *DK, grub_size_t dkLen); int -grub_crypto_memcmp (void *a, void *b, grub_size_t n); +grub_crypto_memcmp (const void *a, const void *b, grub_size_t n); + +int +grub_password_get (char buf[], unsigned buf_size); + +/* For indistinguishibility. */ +#define GRUB_ACCESS_DENIED grub_error (GRUB_ERR_ACCESS_DENIED, "Access denied.") #endif diff --git a/lib/crypto.c b/lib/crypto.c index 4b36dde6f..06104bd4d 100644 --- a/lib/crypto.c +++ b/lib/crypto.c @@ -20,6 +20,7 @@ #include #include #include +#include struct grub_crypto_hmac_handle { @@ -372,10 +373,10 @@ grub_crypto_gcry_error (gcry_err_code_t in) } int -grub_crypto_memcmp (void *a, void *b, grub_size_t n) +grub_crypto_memcmp (const void *a, const void *b, grub_size_t n) { register grub_size_t counter = 0; - grub_uint8_t *pa, *pb; + const grub_uint8_t *pa, *pb; for (pa = a, pb = b; n; pa++, pb++, n--) { @@ -385,3 +386,44 @@ grub_crypto_memcmp (void *a, void *b, grub_size_t n) return !!counter; } + +#ifndef GRUB_MKPASSWD +int +grub_password_get (char buf[], unsigned buf_size) +{ + unsigned cur_len = 0; + int key; + + while (1) + { + key = GRUB_TERM_ASCII_CHAR (grub_getkey ()); + if (key == '\n' || key == '\r') + break; + + if (key == '\e') + { + cur_len = 0; + break; + } + + if (key == '\b') + { + cur_len--; + continue; + } + + if (!grub_isprint (key)) + continue; + + if (cur_len + 2 < buf_size) + buf[cur_len++] = key; + } + + grub_memset (buf + cur_len, 0, buf_size - cur_len); + + grub_putchar ('\n'); + grub_refresh (); + + return (key != '\e'); +} +#endif diff --git a/normal/auth.c b/normal/auth.c index 0a8b5bc82..d679fcc35 100644 --- a/normal/auth.c +++ b/normal/auth.c @@ -160,6 +160,7 @@ grub_auth_check_authentication (const char *userlist) struct grub_auth_user *cur = NULL; grub_err_t err; static unsigned long punishment_delay = 1; + char entered[GRUB_AUTH_MAX_PASSLEN]; auto int hook (grub_list_t item); int hook (grub_list_t item) @@ -189,22 +190,17 @@ grub_auth_check_authentication (const char *userlist) 0, 0, 0)) goto access_denied; + grub_printf ("Enter password: "); + + if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN)) + goto access_denied; + grub_list_iterate (GRUB_AS_LIST (users), hook); if (!cur || ! cur->callback) - { - grub_list_iterate (GRUB_AS_LIST (users), hook_any); + goto access_denied; - /* No users present at all. */ - if (!cur) - goto access_denied; - - /* Display any of available authentication schemes. */ - err = cur->callback (login, 0); - - goto access_denied; - } - err = cur->callback (login, cur->arg); + err = cur->callback (login, entered, cur->arg); if (is_authenticated (userlist)) { punishment_delay = 1; From 7316783f35a1c210007951d74f959e003088da8e Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 23 Dec 2009 17:33:35 +0100 Subject: [PATCH 25/28] Crypto module autoloading --- Makefile.in | 5 +- conf/any-emu.rmk | 2 +- conf/common.rmk | 2 +- include/grub/crypto.h | 2 + include/grub/normal.h | 2 + lib/crypto.c | 46 +++++++++---- normal/crypto.c | 153 ++++++++++++++++++++++++++++++++++++++++++ normal/main.c | 1 + util/import_gcry.py | 38 +++++++++-- 9 files changed, 230 insertions(+), 21 deletions(-) create mode 100644 normal/crypto.c diff --git a/Makefile.in b/Makefile.in index 46b380cd5..b28b660da 100644 --- a/Makefile.in +++ b/Makefile.in @@ -169,7 +169,7 @@ endif ### General targets. CLEANFILES += $(pkglib_DATA) $(pkgdata_DATA) po/*.mo -pkglib_DATA += moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst +pkglib_DATA += moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst video.lst crypto.lst moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep.awk cat $(DEFSYMFILES) /dev/null \ | $(AWK) -f $(srcdir)/genmoddep.awk $(UNDSYMFILES) > $@ \ @@ -193,6 +193,9 @@ parttool.lst: $(PARTTOOLFILES) video.lst: $(VIDEOFILES) cat $^ /dev/null | sort | uniq > $@ +crypto.lst: lib/libgcrypt-grub/cipher/crypto.lst + cp $^ $@ + ifneq (true, $(MAKEINFO)) info_INFOS += docs/grub.info endif diff --git a/conf/any-emu.rmk b/conf/any-emu.rmk index 451ab3393..a3b3c84d9 100644 --- a/conf/any-emu.rmk +++ b/conf/any-emu.rmk @@ -27,7 +27,7 @@ grub_emu_SOURCES = commands/minicmd.c commands/cat.c commands/cmp.c \ normal/handler.c normal/auth.c lib/crypto.c normal/autofs.c \ normal/completion.c normal/main.c normal/color.c \ normal/menu.c normal/menu_entry.c normal/menu_viewer.c \ - normal/menu_text.c \ + normal/menu_text.c normal/crypto.c \ script/main.c script/execute.c script/function.c \ script/lexer.c script/script.c grub_script.tab.c \ partmap/amiga.c partmap/apple.c partmap/msdos.c partmap/sun.c \ diff --git a/conf/common.rmk b/conf/common.rmk index 81372d20c..64be988b9 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -543,7 +543,7 @@ normal_mod_SOURCES = normal/main.c normal/cmdline.c normal/dyncmd.c \ normal/auth.c normal/autofs.c normal/handler.c \ normal/color.c normal/completion.c normal/datetime.c normal/menu.c \ normal/menu_entry.c normal/menu_text.c normal/menu_viewer.c \ - normal/misc.c + normal/misc.c normal/crypto.c normal_mod_CFLAGS = $(COMMON_CFLAGS) normal_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/include/grub/crypto.h b/include/grub/crypto.h index 3129131cb..48b52ee65 100644 --- a/include/grub/crypto.h +++ b/include/grub/crypto.h @@ -270,4 +270,6 @@ grub_password_get (char buf[], unsigned buf_size); /* For indistinguishibility. */ #define GRUB_ACCESS_DENIED grub_error (GRUB_ERR_ACCESS_DENIED, "Access denied.") +extern void (*grub_crypto_autoload_hook) (const char *name); + #endif diff --git a/include/grub/normal.h b/include/grub/normal.h index e55553de5..66b427bcb 100644 --- a/include/grub/normal.h +++ b/include/grub/normal.h @@ -95,6 +95,8 @@ void read_command_list (void); /* Defined in `autofs.c'. */ void read_fs_list (void); +void read_crypto_list (void); + #ifdef GRUB_UTIL void grub_normal_init (void); diff --git a/lib/crypto.c b/lib/crypto.c index 06104bd4d..021560d6c 100644 --- a/lib/crypto.c +++ b/lib/crypto.c @@ -32,6 +32,8 @@ struct grub_crypto_hmac_handle static gcry_cipher_spec_t *grub_ciphers = NULL; static gcry_md_spec_t *grub_digests = NULL; +void (*grub_crypto_autoload_hook) (const char *name) = NULL; + /* Based on libgcrypt-1.4.4/src/misc.c. */ void grub_burn_stack (grub_size_t size) @@ -91,28 +93,44 @@ const gcry_md_spec_t * grub_crypto_lookup_md_by_name (const char *name) { const gcry_md_spec_t *md; - for (md = grub_digests; md; md = md->next) - if (grub_strcasecmp (name, md->name) == 0) - return md; - return NULL; + int first = 1; + while (1) + { + for (md = grub_digests; md; md = md->next) + if (grub_strcasecmp (name, md->name) == 0) + return md; + if (grub_crypto_autoload_hook && first) + grub_crypto_autoload_hook (name); + else + return NULL; + first = 0; + } } const gcry_cipher_spec_t * grub_crypto_lookup_cipher_by_name (const char *name) { const gcry_cipher_spec_t *ciph; - for (ciph = grub_ciphers; ciph; ciph = ciph->next) + int first = 1; + while (1) { - const char **alias; - if (grub_strcasecmp (name, ciph->name) == 0) - return ciph; - if (!ciph->aliases) - continue; - for (alias = ciph->aliases; *alias; alias++) - if (grub_strcasecmp (name, *alias) == 0) - return ciph; + for (ciph = grub_ciphers; ciph; ciph = ciph->next) + { + const char **alias; + if (grub_strcasecmp (name, ciph->name) == 0) + return ciph; + if (!ciph->aliases) + continue; + for (alias = ciph->aliases; *alias; alias++) + if (grub_strcasecmp (name, *alias) == 0) + return ciph; + } + if (grub_crypto_autoload_hook && first) + grub_crypto_autoload_hook (name); + else + return NULL; + first = 0; } - return NULL; } diff --git a/normal/crypto.c b/normal/crypto.c new file mode 100644 index 000000000..67330272a --- /dev/null +++ b/normal/crypto.c @@ -0,0 +1,153 @@ +/* crypto.c - support crypto autoload */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +struct load_spec +{ + struct load_spec *next; + char *name; + char *modname; +}; + +struct load_spec *crypto_specs = NULL; + +static void +grub_crypto_autoload (const char *name) +{ + struct load_spec *cur; + grub_dl_t mod; + + for (cur = crypto_specs; cur; cur = cur->next) + if (grub_strcasecmp (name, cur->name) == 0) + { + mod = grub_dl_load (cur->modname); + if (mod) + grub_dl_ref (mod); + grub_errno = GRUB_ERR_NONE; + } +} + +static void +grub_crypto_spec_free (void) +{ + struct load_spec *cur, *next; + for (cur = crypto_specs; cur; cur = next) + { + next = cur->next; + grub_free (cur->name); + grub_free (cur->modname); + grub_free (cur); + } + crypto_specs = NULL; +} + + +/* Read the file crypto.lst for auto-loading. */ +void +read_crypto_list (void) +{ + const char *prefix; + char *filename; + grub_file_t file; + char *buf = NULL; + + prefix = grub_env_get ("prefix"); + if (!prefix) + { + grub_errno = GRUB_ERR_NONE; + return; + } + + filename = grub_malloc (grub_strlen (prefix) + sizeof ("/crypto.lst")); + if (!filename) + { + grub_errno = GRUB_ERR_NONE; + return; + } + + grub_sprintf (filename, "%s/crypto.lst", prefix); + file = grub_file_open (filename); + if (!file) + { + grub_errno = GRUB_ERR_NONE; + return; + } + + /* Override previous commands.lst. */ + grub_crypto_spec_free (); + + for (;; grub_free (buf)) + { + char *p, *name; + struct load_spec *cur; + + buf = grub_file_getline (file); + + if (! buf) + break; + + name = buf; + + p = grub_strchr (name, ':'); + if (! p) + continue; + + *p = '\0'; + while (*++p == ' ') + ; + + cur = grub_malloc (sizeof (*cur)); + if (!cur) + { + grub_errno = GRUB_ERR_NONE; + continue; + } + + cur->name = grub_strdup (name); + if (! name) + { + grub_errno = GRUB_ERR_NONE; + grub_free (cur); + continue; + } + + cur->modname = grub_strdup (p); + if (! cur->modname) + { + grub_errno = GRUB_ERR_NONE; + grub_free (cur); + grub_free (cur->name); + continue; + } + cur->next = crypto_specs; + crypto_specs = cur; + } + + grub_file_close (file); + + grub_errno = GRUB_ERR_NONE; + + grub_crypto_autoload_hook = grub_crypto_autoload; +} diff --git a/normal/main.c b/normal/main.c index 3166ea146..189244aa0 100644 --- a/normal/main.c +++ b/normal/main.c @@ -428,6 +428,7 @@ grub_normal_execute (const char *config, int nested, int batch) read_command_list (); read_fs_list (); read_handler_list (); + read_crypto_list (); grub_command_execute ("parser.grub", 0, 0); reader_nested = nested; diff --git a/util/import_gcry.py b/util/import_gcry.py index fe68c85a4..93bf5982f 100644 --- a/util/import_gcry.py +++ b/util/import_gcry.py @@ -61,6 +61,18 @@ mdblocksizes = {"_gcry_digest_spec_crc32" : 64, "_gcry_digest_spec_tiger" : 64, "_gcry_digest_spec_whirlpool" : 64} +cryptolist = open (os.path.join (cipher_dir_out, "crypto.lst"), "w") + +# rijndael is the only cipher using aliases. So no need for mangling, just +# hardcode it +cryptolist.write ("RIJNDAEL: gcry_rijndael\n"); +cryptolist.write ("RIJNDAEL192: gcry_rijndael\n"); +cryptolist.write ("RIJNDAEL256: gcry_rijndael\n"); +cryptolist.write ("AES128: gcry_rijndael\n"); +cryptolist.write ("AES-128: gcry_rijndael\n"); +cryptolist.write ("AES-192: gcry_rijndael\n"); +cryptolist.write ("AES-256: gcry_rijndael\n"); + for cipher_file in cipher_files: infile = os.path.join (cipher_dir_in, cipher_file) outfile = os.path.join (cipher_dir_out, cipher_file) @@ -86,7 +98,15 @@ for cipher_file in cipher_files: skip = False skip2 = False ismd = False + iscryptostart = False iscomma = False + isglue = False + if isc: + modname = cipher_file [0:len(cipher_file) - 2] + if re.match (".*-glue$", modname): + modname = modname.replace ("-glue", "") + isglue = True + modname = "gcry_%s" % modname for line in f: if skip: if line[0] == "}": @@ -96,6 +116,12 @@ for cipher_file in cipher_files: if not re.search (" *};", line) is None: skip2 = False continue + if iscryptostart: + s = re.search (" *\"([A-Z0-9_a-z]*)\"", line) + if not s is None: + sg = s.groups()[0] + cryptolist.write (("%s: %s\n") % (sg, modname)) + iscryptostart = False if ismd: if not re.search (" *};", line) is None: if not mdblocksizes.has_key (mdname): @@ -133,16 +159,20 @@ for cipher_file in cipher_files: continue m = re.match ("gcry_cipher_spec_t", line) if isc and not m is None: + assert (not iscryptostart) ciphername = line [len ("gcry_cipher_spec_t"):].strip () ciphername = re.match("[a-zA-Z0-9_]*",ciphername).group () ciphernames.append (ciphername) + iscryptostart = True m = re.match ("gcry_md_spec_t", line) if isc and not m is None: assert (not ismd) + assert (not iscryptostart) mdname = line [len ("gcry_md_spec_t"):].strip () mdname = re.match("[a-zA-Z0-9_]*",mdname).group () mdnames.append (mdname) ismd = True + iscryptostart = True m = re.match ("static const char \*selftest.*;$", line) if not m is None: fname = line[len ("static const char \*"):] @@ -185,14 +215,11 @@ for cipher_file in cipher_files: continue fw.write (line) if len (ciphernames) > 0 or len (mdnames) > 0: - modname = cipher_file [0:len(cipher_file) - 2] - if re.match (".*-glue$", modname): + if isglue: modfiles = "lib/libgcrypt-grub/cipher/%s lib/libgcrypt-grub/cipher/%s" \ % (cipher_file, cipher_file.replace ("-glue.c", ".c")) - modname = modname.replace ("-glue", "") else: modfiles = "lib/libgcrypt-grub/cipher/%s" % cipher_file - modname = "gcry_%s" % modname chmsg = "(GRUB_MOD_INIT(%s)): New function\n" % modname if nch: chlognew = "%s\n %s" % (chlognew, chmsg) @@ -238,6 +265,9 @@ for cipher_file in cipher_files: chlog = "%s%sSkipped unknown file\n" % (chlog, chlognew) print ("WARNING: unknown file %s" % cipher_file) +cryptolist.close () +chlog = "%s * crypto.lst: New file.\n" % chlog + outfile = os.path.join (cipher_dir_out, "types.h") fw=open (outfile, "w") fw.write ("#include \n") From 0eb11149c98134432021ef067c0b4e64dcb91984 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 23 Dec 2009 19:58:33 +0100 Subject: [PATCH 26/28] eliminate dead code and data in des.c --- util/import_gcry.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/util/import_gcry.py b/util/import_gcry.py index 93bf5982f..d71924d53 100644 --- a/util/import_gcry.py +++ b/util/import_gcry.py @@ -101,6 +101,7 @@ for cipher_file in cipher_files: iscryptostart = False iscomma = False isglue = False + skip_statement = False if isc: modname = cipher_file [0:len(cipher_file) - 2] if re.match (".*-glue$", modname): @@ -108,6 +109,10 @@ for cipher_file in cipher_files: isglue = True modname = "gcry_%s" % modname for line in f: + if skip_statement: + if not re.search (";", line) is None: + skip_statement = False + continue if skip: if line[0] == "}": skip = False @@ -132,10 +137,22 @@ for cipher_file in cipher_files: fw.write (" .blocksize = %s\n" % mdblocksizes [mdname]) ismd = False iscomma = not re.search (",$", line) is None + # Used only for selftests. + m = re.match ("(static byte|static unsigned char) (weak_keys_chksum)\[[0-9]*\] =", line) + if not m is None: + skip = True + fname = m.groups ()[1] + chmsg = "(%s): Removed." % fname + if nch: + chlognew = "%s\n %s" % (chlognew, chmsg) + else: + chlognew = "%s %s" % (chlognew, chmsg) + nch = True + continue if hold: hold = False # We're optimising for size. - if not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer)", line) is None: + if not re.match ("(run_selftests|selftest|_gcry_aes_c.._..c|_gcry_[a-z0-9]*_hash_buffer|tripledes_set2keys|do_tripledes_set_extra_info)", line) is None: skip = True fname = re.match ("[a-zA-Z0-9_]*", line).group () chmsg = "(%s): Removed." % fname @@ -184,11 +201,18 @@ for cipher_file in cipher_files: chlognew = "%s %s" % (chlognew, chmsg) nch = True continue - m = re.match ("(static const char( |)\*|static gpg_err_code_t|void)$", line) + m = re.match ("(static const char( |)\*|static gpg_err_code_t|void|static int|static gcry_err_code_t)$", line) if not m is None: hold = True holdline = line continue + m = re.match ("static int tripledes_set2keys \(.*\);", line) + if not m is None: + continue + m = re.match ("static int tripledes_set2keys \(", line) + if not m is None: + skip_statement = True + continue m = re.match ("cipher_extra_spec_t", line) if isc and not m is None: skip2 = True From a7a095c71ae9362e13bb0f38998fabd1398bba4d Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Wed, 23 Dec 2009 20:31:12 +0100 Subject: [PATCH 27/28] hashsum support --- commands/hashsum.c | 278 +++++++++++++++++++++++++++++++++++++++++++++ conf/common.rmk | 5 + 2 files changed, 283 insertions(+) create mode 100644 commands/hashsum.c diff --git a/commands/hashsum.c b/commands/hashsum.c new file mode 100644 index 000000000..60e17447b --- /dev/null +++ b/commands/hashsum.c @@ -0,0 +1,278 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB 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 3 of the License, or + * (at your option) any later version. + * + * GRUB 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 GRUB. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct grub_arg_option options[] = { + {"hash", 'h', 0, "Specify hash to use.", "HASH", ARG_TYPE_STRING}, + {"check", 'c', 0, "Check hash list file.", "FILE", ARG_TYPE_STRING}, + {"prefix", 'p', 0, "Base directory for hash list.", "DIRECTORY", + ARG_TYPE_STRING}, + {"keep-going", 'k', 0, "Don't stop after first error.", 0, 0}, + {0, 0, 0, 0, 0, 0} +}; + +struct { const char *name; const char *hashname; } aliases[] = + { + {"sha256sum", "sha256"}, + {"sha512sum", "sha512"}, + {"md5sum", "md5"}, + }; + +static inline int +hextoval (char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +static grub_err_t +hash_file (grub_file_t file, const gcry_md_spec_t *hash, void *result) +{ + grub_uint8_t context[hash->contextsize]; + char *readbuf[4096]; + + grub_memset (context, 0, sizeof (context)); + hash->init (context); + while (1) + { + grub_ssize_t r; + r = grub_file_read (file, readbuf, sizeof (readbuf)); + if (r < 0) + return grub_errno; + if (r == 0) + break; + hash->write (context, readbuf, r); + } + hash->final (context); + grub_memcpy (result, hash->read (context), hash->mdlen); + + return GRUB_ERR_NONE; +} + +static grub_err_t +check_list (const gcry_md_spec_t *hash, const char *hashfilename, + const char *prefix, int keep) +{ + grub_file_t hashlist, file; + char *buf = NULL; + grub_uint8_t expected[hash->mdlen]; + grub_uint8_t actual[hash->mdlen]; + grub_err_t err; + unsigned i; + unsigned unread = 0, mismatch = 0; + + hashlist = grub_file_open (hashfilename); + if (!hashlist) + return grub_errno; + + while (grub_free (buf), (buf = grub_file_getline (hashlist))) + { + const char *p = buf; + for (i = 0; i < hash->mdlen; i++) + { + int high, low; + high = hextoval (*p++); + low = hextoval (*p++); + if (high < 0 || low < 0) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); + expected[i] = (high << 4) | low; + } + if (*p++ != ' ' || *p++ != ' ') + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid hash list"); + if (prefix) + { + char *filename; + + filename = grub_malloc (grub_strlen (prefix) + + grub_strlen (p) + 2); + if (!filename) + return grub_errno; + grub_sprintf (filename, "%s/%s", prefix, p); + file = grub_file_open (filename); + grub_free (filename); + } + else + file = grub_file_open (p); + if (!file) + { + grub_file_close (hashlist); + grub_free (buf); + return grub_errno; + } + err = hash_file (file, hash, actual); + grub_file_close (file); + if (err) + { + grub_printf ("%s: READ ERROR\n", p); + if (!keep) + { + grub_file_close (hashlist); + grub_free (buf); + return err; + } + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + unread++; + continue; + } + if (grub_crypto_memcmp (expected, actual, hash->mdlen) != 0) + { + grub_printf ("%s: HASH MISMATCH\n", p); + if (!keep) + { + grub_file_close (hashlist); + grub_free (buf); + return grub_error (GRUB_ERR_TEST_FAILURE, + "hash of '%s' mismatches", p); + } + mismatch++; + continue; + } + grub_printf ("%s: OK\n", p); + } + if (mismatch || unread) + return grub_error (GRUB_ERR_TEST_FAILURE, + "%d files couldn't be read and hash " + "of %d files mismatches", unread, mismatch); + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_hashsum (struct grub_extcmd *cmd, + int argc, char **args) +{ + struct grub_arg_list *state = cmd->state; + const char *hashname = NULL; + const char *prefix = NULL; + const gcry_md_spec_t *hash; + unsigned i; + int keep = state[3].set; + unsigned unread = 0; + + for (i = 0; i < ARRAY_SIZE (aliases); i++) + if (grub_strcmp (cmd->cmd->name, aliases[i].name) == 0) + hashname = aliases[i].hashname; + if (state[0].set) + hashname = state[0].arg; + + if (!hashname) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "no hash specified"); + + hash = grub_crypto_lookup_md_by_name (hashname); + if (!hash) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown hash"); + + if (state[2].set) + prefix = state[2].arg; + + if (state[1].set) + { + if (argc != 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, + "--check is incompatible with file list"); + return check_list (hash, state[1].arg, prefix, keep); + } + + for (i = 0; i < (unsigned) argc; i++) + { + grub_uint8_t result[hash->mdlen]; + grub_file_t file; + grub_err_t err; + unsigned j; + file = grub_file_open (args[i]); + if (!file) + { + if (!keep) + return grub_errno; + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + unread++; + continue; + } + err = hash_file (file, hash, result); + grub_file_close (file); + if (err) + { + if (!keep) + return err; + grub_print_error (); + grub_errno = GRUB_ERR_NONE; + unread++; + continue; + } + for (j = 0; j < hash->mdlen; j++) + grub_printf ("%02x", result[j]); + grub_printf (" %s\n", args[i]); + } + + if (unread) + return grub_error (GRUB_ERR_TEST_FAILURE, "%d files couldn't be read.", + unread); + return GRUB_ERR_NONE; +} + +static grub_extcmd_t cmd, cmd_md5, cmd_sha256, cmd_sha512; + +GRUB_MOD_INIT(hashsum) +{ + cmd = grub_register_extcmd ("hashsum", grub_cmd_hashsum, + GRUB_COMMAND_FLAG_BOTH, + "hashsum -h HASH [-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]", + "Compute or check hash checksum.", + options); + cmd_md5 = grub_register_extcmd ("md5sum", grub_cmd_hashsum, + GRUB_COMMAND_FLAG_BOTH, + "md5sum [-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]", + "Compute or check hash checksum.", + options); + cmd_sha256 = grub_register_extcmd ("sha256sum", grub_cmd_hashsum, + GRUB_COMMAND_FLAG_BOTH, + "sha256sum [-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]", + "Compute or check hash checksum.", + options); + cmd_sha512 = grub_register_extcmd ("sha512sum", grub_cmd_hashsum, + GRUB_COMMAND_FLAG_BOTH, + "sha512sum [-c FILE [-p PREFIX]] " + "[FILE1 [FILE2 ...]]", + "Compute or check hash checksum.", + options); +} + +GRUB_MOD_FINI(hashsum) +{ + grub_unregister_extcmd (cmd); + grub_unregister_extcmd (cmd_md5); + grub_unregister_extcmd (cmd_sha256); + grub_unregister_extcmd (cmd_sha512); +} diff --git a/conf/common.rmk b/conf/common.rmk index 64be988b9..271384d53 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -649,6 +649,11 @@ crypto_mod_SOURCES = lib/crypto.c crypto_mod_CFLAGS = $(COMMON_CFLAGS) crypto_mod_LDFLAGS = $(COMMON_LDFLAGS) +pkglib_MODULES += hashsum.mod +hashsum_mod_SOURCES = commands/hashsum.c +hashsum_mod_CFLAGS = $(COMMON_CFLAGS) +hashsum_mod_LDFLAGS = $(COMMON_LDFLAGS) + pkglib_MODULES += pbkdf2.mod pbkdf2_mod_SOURCES = lib/pbkdf2.c pbkdf2_mod_CFLAGS = $(COMMON_CFLAGS) From 3851cc386e1d98f5407fadc2932815f0f6831205 Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 27 Dec 2009 22:29:22 +0100 Subject: [PATCH 28/28] Prevent NULL dereferencing when unregistering ciphers --- lib/crypto.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/crypto.c b/lib/crypto.c index 021560d6c..d11f0994f 100644 --- a/lib/crypto.c +++ b/lib/crypto.c @@ -59,7 +59,10 @@ grub_cipher_unregister (gcry_cipher_spec_t *cipher) gcry_cipher_spec_t **ciph; for (ciph = &grub_ciphers; *ciph; ciph = &((*ciph)->next)) if (*ciph == cipher) - *ciph = (*ciph)->next; + { + *ciph = (*ciph)->next; + break; + } } void @@ -75,7 +78,10 @@ grub_md_unregister (gcry_md_spec_t *cipher) gcry_md_spec_t **ciph; for (ciph = &grub_digests; *ciph; ciph = &((*ciph)->next)) if (*ciph == cipher) - *ciph = (*ciph)->next; + { + *ciph = (*ciph)->next; + break; + } } void