| From 338637ac08c19708eb35523894b44bbe3c726cfa Mon Sep 17 00:00:00 2001 |
| From: quentin <quentin@minster.io> |
| Date: Mon, 2 Apr 2018 18:07:50 +0200 |
| Subject: [PATCH] crda: Fix for OpenSSL 1.1.0: BIGNUM now opaque |
| |
| OpenSSL 1.1.0 makes most of OpenSSL's structures opaque, and provides |
| functions to manipulate them. This means it's no longer possible to |
| construct an OpenSSL BIGNUM directly from scratch, as was done in |
| keys-ssl.c. |
| |
| Use BN_bin2bn() (available since OpenSSL 0.9.8) to build the bignum from |
| its big-endian representation as a byte array. |
| |
| This also allows factoring the code in utils/key2pub.py as it's now the |
| same mechanism as with libgcrypt. |
| |
| This was tested with OpenSSL 1.1.0g. |
| |
| Signed-off-by: Quentin Minster <quentin@minster.io> |
| --- |
| Makefile | 12 +++---- |
| reglib.c | 44 +++++++++++++++++------ |
| utils/key2pub.py | 107 ++++++------------------------------------------------- |
| 3 files changed, 49 insertions(+), 114 deletions(-) |
| |
| diff --git a/Makefile b/Makefile |
| index a3ead30..a4e7373 100644 |
| --- a/Makefile |
| +++ b/Makefile |
| @@ -38,18 +38,16 @@ all: all_noverify verify |
| |
| all_noverify: $(LIBREG) crda intersect regdbdump db2rd optimize |
| |
| +$(LIBREG): keys.c |
| + |
| ifeq ($(USE_OPENSSL),1) |
| CFLAGS += -DUSE_OPENSSL -DPUBKEY_DIR=\"$(RUNTIME_PUBKEY_DIR)\" `pkg-config --cflags openssl` |
| LDLIBS += `pkg-config --libs openssl` |
| |
| -$(LIBREG): keys-ssl.c |
| - |
| else |
| CFLAGS += -DUSE_GCRYPT |
| LDLIBS += -lgcrypt |
| |
| -$(LIBREG): keys-gcrypt.c |
| - |
| endif |
| MKDIR ?= mkdir -p |
| INSTALL ?= install |
| @@ -109,10 +107,10 @@ $(REG_BIN): |
| $(NQ) |
| $(Q) exit 1 |
| |
| -keys-%.c: utils/key2pub.py $(wildcard $(PUBKEY_DIR)/*.pem) |
| +keys.c: utils/key2pub.py $(wildcard $(PUBKEY_DIR)/*.pem) |
| $(NQ) ' GEN ' $@ |
| $(NQ) ' Trusted pubkeys:' $(wildcard $(PUBKEY_DIR)/*.pem) |
| - $(Q)./utils/key2pub.py --$* $(wildcard $(PUBKEY_DIR)/*.pem) $@ |
| + $(Q)./utils/key2pub.py $(wildcard $(PUBKEY_DIR)/*.pem) $@ |
| |
| $(LIBREG): regdb.h reglib.h reglib.c |
| $(NQ) ' CC ' $@ |
| @@ -187,5 +185,5 @@ install: install-libreg install-libreg-headers crda crda.8.gz regdbdump.8.gz |
| |
| clean: |
| $(Q)rm -f $(LIBREG) crda regdbdump intersect db2rd optimize \ |
| - *.o *~ *.pyc keys-*.c *.gz \ |
| + *.o *~ *.pyc keys.c *.gz \ |
| udev/$(UDEV_LEVEL)regulatory.rules udev/regulatory.rules.parsed |
| diff --git a/reglib.c b/reglib.c |
| index e00e9b8..00f7f56 100644 |
| --- a/reglib.c |
| +++ b/reglib.c |
| @@ -22,6 +22,7 @@ |
| #include <openssl/rsa.h> |
| #include <openssl/sha.h> |
| #include <openssl/pem.h> |
| +#include <openssl/bn.h> |
| #endif |
| |
| #ifdef USE_GCRYPT |
| @@ -30,12 +31,8 @@ |
| |
| #include "reglib.h" |
| |
| -#ifdef USE_OPENSSL |
| -#include "keys-ssl.c" |
| -#endif |
| - |
| -#ifdef USE_GCRYPT |
| -#include "keys-gcrypt.c" |
| +#if defined(USE_OPENSSL) || defined(USE_GCRYPT) |
| +#include "keys.c" |
| #endif |
| |
| int debug = 0; |
| @@ -81,7 +78,8 @@ reglib_array_len(size_t baselen, unsigned int elemcount, size_t elemlen) |
| #ifdef USE_OPENSSL |
| int reglib_verify_db_signature(uint8_t *db, size_t dblen, size_t siglen) |
| { |
| - RSA *rsa; |
| + RSA *rsa = NULL; |
| + BIGNUM *rsa_e = NULL, *rsa_n = NULL; |
| uint8_t hash[SHA_DIGEST_LENGTH]; |
| unsigned int i; |
| int ok = 0; |
| @@ -102,15 +100,35 @@ int reglib_verify_db_signature(uint8_t *db, size_t dblen, size_t siglen) |
| goto out; |
| } |
| |
| - rsa->e = &keys[i].e; |
| - rsa->n = &keys[i].n; |
| + rsa_e = BN_bin2bn(keys[i].e, keys[i].len_e, NULL); |
| + if (!rsa_e) { |
| + fprintf(stderr, "Failed to convert value for RSA e.\n"); |
| + goto out; |
| + } |
| + rsa_n = BN_bin2bn(keys[i].n, keys[i].len_n, NULL); |
| + if (!rsa_n) { |
| + fprintf(stderr, "Failed to convert value for RSA n.\n"); |
| + goto out; |
| + } |
| + |
| +#if OPENSSL_VERSION_NUMBER < 0x10100000L |
| + rsa->e = rsa_e; |
| + rsa->n = rsa_n; |
| +#else |
| + if (RSA_set0_key(rsa, rsa_n, rsa_e, NULL) != 1) { |
| + fprintf(stderr, "Failed to set RSA key.\n"); |
| + goto out; |
| + } |
| +#endif |
| + /* BIGNUMs now owned by the RSA object */ |
| + rsa_e = NULL; |
| + rsa_n = NULL; |
| |
| ok = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH, |
| db + dblen, siglen, rsa) == 1; |
| |
| - rsa->e = NULL; |
| - rsa->n = NULL; |
| RSA_free(rsa); |
| + rsa = NULL; |
| } |
| if (!ok && (pubkey_dir = opendir(PUBKEY_DIR))) { |
| while (!ok && (nextfile = readdir(pubkey_dir))) { |
| @@ -123,6 +141,7 @@ int reglib_verify_db_signature(uint8_t *db, size_t dblen, size_t siglen) |
| ok = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH, |
| db + dblen, siglen, rsa) == 1; |
| RSA_free(rsa); |
| + rsa = NULL; |
| fclose(keyfile); |
| } |
| } |
| @@ -133,6 +152,9 @@ int reglib_verify_db_signature(uint8_t *db, size_t dblen, size_t siglen) |
| fprintf(stderr, "Database signature verification failed.\n"); |
| |
| out: |
| + RSA_free(rsa); |
| + BN_free(rsa_e); |
| + BN_free(rsa_n); |
| return ok; |
| } |
| #endif /* USE_OPENSSL */ |
| diff --git a/utils/key2pub.py b/utils/key2pub.py |
| index 9bb04cd..1919270 100755 |
| --- a/utils/key2pub.py |
| +++ b/utils/key2pub.py |
| @@ -9,84 +9,7 @@ except ImportError, e: |
| sys.stderr.write('On Debian GNU/Linux the package is called "python-m2crypto".\n') |
| sys.exit(1) |
| |
| -def print_ssl_64(output, name, val): |
| - while val[0] == '\0': |
| - val = val[1:] |
| - while len(val) % 8: |
| - val = '\0' + val |
| - vnew = [] |
| - while len(val): |
| - vnew.append((val[0], val[1], val[2], val[3], val[4], val[5], val[6], val[7])) |
| - val = val[8:] |
| - vnew.reverse() |
| - output.write('static BN_ULONG %s[%d] = {\n' % (name, len(vnew))) |
| - idx = 0 |
| - for v1, v2, v3, v4, v5, v6, v7, v8 in vnew: |
| - if not idx: |
| - output.write('\t') |
| - output.write('0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x, ' % (ord(v1), ord(v2), ord(v3), ord(v4), ord(v5), ord(v6), ord(v7), ord(v8))) |
| - idx += 1 |
| - if idx == 2: |
| - idx = 0 |
| - output.write('\n') |
| - if idx: |
| - output.write('\n') |
| - output.write('};\n\n') |
| - |
| -def print_ssl_32(output, name, val): |
| - while val[0] == '\0': |
| - val = val[1:] |
| - while len(val) % 4: |
| - val = '\0' + val |
| - vnew = [] |
| - while len(val): |
| - vnew.append((val[0], val[1], val[2], val[3], )) |
| - val = val[4:] |
| - vnew.reverse() |
| - output.write('static BN_ULONG %s[%d] = {\n' % (name, len(vnew))) |
| - idx = 0 |
| - for v1, v2, v3, v4 in vnew: |
| - if not idx: |
| - output.write('\t') |
| - output.write('0x%.2x%.2x%.2x%.2x, ' % (ord(v1), ord(v2), ord(v3), ord(v4))) |
| - idx += 1 |
| - if idx == 4: |
| - idx = 0 |
| - output.write('\n') |
| - if idx: |
| - output.write('\n') |
| - output.write('};\n\n') |
| - |
| -def print_ssl(output, name, val): |
| - import struct |
| - output.write('#include <stdint.h>\n') |
| - if len(struct.pack('@L', 0)) == 8: |
| - return print_ssl_64(output, name, val) |
| - else: |
| - return print_ssl_32(output, name, val) |
| - |
| -def print_ssl_keys(output, n): |
| - output.write(r''' |
| -struct pubkey { |
| - struct bignum_st e, n; |
| -}; |
| - |
| -#define KEY(data) { \ |
| - .d = data, \ |
| - .top = sizeof(data)/sizeof(data[0]), \ |
| -} |
| - |
| -#define KEYS(e,n) { KEY(e), KEY(n), } |
| - |
| -static struct pubkey keys[] = { |
| -''') |
| - for n in xrange(n + 1): |
| - output.write(' KEYS(e_%d, n_%d),\n' % (n, n)) |
| - output.write('};\n') |
| - pass |
| - |
| -def print_gcrypt(output, name, val): |
| - output.write('#include <stdint.h>\n') |
| +def print_bignum(output, name, val): |
| while val[0] == '\0': |
| val = val[1:] |
| output.write('static const uint8_t %s[%d] = {\n' % (name, len(val))) |
| @@ -103,11 +26,11 @@ def print_gcrypt(output, name, val): |
| output.write('\n') |
| output.write('};\n\n') |
| |
| -def print_gcrypt_keys(output, n): |
| +def print_keys(output, n): |
| output.write(r''' |
| struct key_params { |
| const uint8_t *e, *n; |
| - uint32_t len_e, len_n; |
| + const uint32_t len_e, len_n; |
| }; |
| |
| #define KEYS(_e, _n) { \ |
| @@ -120,25 +43,17 @@ static const struct key_params __attribute__ ((unused)) keys[] = { |
| for n in xrange(n + 1): |
| output.write(' KEYS(e_%d, n_%d),\n' % (n, n)) |
| output.write('};\n') |
| - |
| |
| -modes = { |
| - '--ssl': (print_ssl, print_ssl_keys), |
| - '--gcrypt': (print_gcrypt, print_gcrypt_keys), |
| -} |
| |
| -try: |
| - mode = sys.argv[1] |
| - files = sys.argv[2:-1] |
| - outfile = sys.argv[-1] |
| -except IndexError: |
| - mode = None |
| +files = sys.argv[1:-1] |
| +outfile = sys.argv[-1] |
| |
| -if not mode in modes: |
| - print 'Usage: %s [%s] input-file... output-file' % (sys.argv[0], '|'.join(modes.keys())) |
| +if len(files) == 0: |
| + print 'Usage: %s input-file... output-file' % (sys.argv[0], ) |
| sys.exit(2) |
| |
| output = open(outfile, 'w') |
| +output.write('#include <stdint.h>\n\n\n') |
| |
| # load key |
| idx = 0 |
| @@ -148,8 +63,8 @@ for f in files: |
| except RSA.RSAError: |
| key = RSA.load_key(f) |
| |
| - modes[mode][0](output, 'e_%d' % idx, key.e[4:]) |
| - modes[mode][0](output, 'n_%d' % idx, key.n[4:]) |
| + print_bignum(output, 'e_%d' % idx, key.e[4:]) |
| + print_bignum(output, 'n_%d' % idx, key.n[4:]) |
| idx += 1 |
| |
| -modes[mode][1](output, idx - 1) |
| +print_keys(output, idx - 1) |
| -- |
| 2.16.2 |
| |