You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
309 lines
8.4 KiB
309 lines
8.4 KiB
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(-)
|
|
|
|
--- 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
|
|
--- 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 */
|
|
--- a/utils/key2pub.py
|
|
+++ b/utils/key2pub.py
|
|
@@ -9,84 +9,7 @@ except ImportError as 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:1] == b'\0':
|
|
- val = val[1:]
|
|
- while len(val) % 8:
|
|
- val = b'\0' + val
|
|
- vnew = []
|
|
- while len(val):
|
|
- vnew.append((val[0:1], val[1:2], val[2:3], val[3:4], val[4:5], val[5:6], val[6:7], val[7:8]))
|
|
- 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:1] == b'\0':
|
|
- val = val[1:]
|
|
- while len(val) % 4:
|
|
- val = b'\0' + val
|
|
- vnew = []
|
|
- while len(val):
|
|
- vnew.append((val[0:1], val[1:2], val[2:3], val[3:4]))
|
|
- 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 range(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:1] == b'\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 range(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,10 +63,10 @@ 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)
|
|
|
|
output.close()
|