2008-10-23 23:05:14

by Davide Pesavento

[permalink] [raw]
Subject: [CRDA PATCH 1/6] Consolidate db signature validation in one function.

Both crda.c and dump.c had their own version of the code which
checks the validity of the signature on the regulatory db.
Having a common implementation shared by both files makes
maintenance easier and removes code duplication.

Signed-off-by: Davide Pesavento <[email protected]>
---
Makefile | 14 ++++----
crda.c | 111 +---------------------------------------------------------
dump.c | 117 ++-----------------------------------------------------------
regdb.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
regdb.h | 4 ++
5 files changed, 134 insertions(+), 231 deletions(-)
create mode 100644 regdb.c

diff --git a/Makefile b/Makefile
index 6d2faa6..69a2eba 100644
--- a/Makefile
+++ b/Makefile
@@ -17,23 +17,23 @@ INSTALL ?= install

CRDA_LIB = "/usr/lib/crda/"

-all: regulatory.bin warn crda
+all: regulatory.bin warn crda
@$(MAKE) --no-print-directory -f Makefile verify

regulatory.bin: db2bin.py key.priv.pem db.txt dbparse.py
@./db2bin.py regulatory.bin db.txt key.priv.pem

-crda: keys-gcrypt.c keys-ssl.c crda.c regdb.h
- $(CC) $(CFLAGS) $(LDFLAGS) -lnl -o $@ crda.c
+crda: keys-ssl.c keys-gcrypt.c regdb.h regdb.o crda.o
+ $(CC) $(CFLAGS) $(LDFLAGS) -lnl -o $@ regdb.o crda.o

clean:
- @rm -f regulatory.bin dump *~ *.pyc keys-*.c crda
+ @rm -f regulatory.bin crda dump *.o *~ *.pyc keys-*.c
@if test -f key.priv.pem && diff -qNs test-key key.priv.pem >/dev/null ; then \
rm -f key.priv.pem;\
fi

warn:
- @if test ! -f key.priv.pem || diff -qNs test-key key.priv.pem >/dev/null ; then \
+ @if test ! -f key.priv.pem || diff -qNs test-key key.priv.pem >/dev/null ; then \
echo '**************************************';\
echo '** WARNING! **';\
echo '** No key found, using TEST key! **';\
@@ -46,8 +46,8 @@ key.priv.pem:
generate_key:
openssl genrsa -out key.priv.pem 2048

-dump: dump.c regdb.h keys-ssl.c keys-gcrypt.c
- $(CC) $(CFLAGS) $(LDFLAGS) dump.c -o dump
+dump: keys-ssl.c keys-gcrypt.c regdb.h regdb.o dump.o
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ regdb.o dump.o

keys-ssl.c: key2pub.py $(wildcard *.pem)
@./key2pub.py --ssl *.pem > keys-ssl.c
diff --git a/crda.c b/crda.c
index b5e738f..cf493e8 100644
--- a/crda.c
+++ b/crda.c
@@ -21,21 +21,6 @@

#include "regdb.h"

-#ifdef USE_OPENSSL
-#include <openssl/objects.h>
-#include <openssl/bn.h>
-#include <openssl/rsa.h>
-#include <openssl/sha.h>
-
-#include "keys-ssl.c"
-#endif
-
-#ifdef USE_GCRYPT
-#include <gcrypt.h>
-
-#include "keys-gcrypt.c"
-#endif
-
struct nl80211_state {
struct nl_handle *nl_handle;
struct nl_cache *nl_cache;
@@ -199,18 +184,6 @@ int main(int argc, char **argv)
struct nlattr *nl_reg_rules;
int num_rules;

-#ifdef USE_OPENSSL
- RSA *rsa;
- __u8 hash[SHA_DIGEST_LENGTH];
- int ok = 0;
-#endif
-#ifdef USE_GCRYPT
- gcry_mpi_t mpi_e, mpi_n;
- gcry_sexp_t rsa, signature, data;
- __u8 hash[20];
- int ok = 0;
-#endif
-
const char regdb[] = "/usr/lib/crda/regulatory.bin";

if (argc != 1) {
@@ -274,90 +247,8 @@ int main(int argc, char **argv)
}

/* verify signature */
-#ifdef USE_OPENSSL
- rsa = RSA_new();
- if (!rsa) {
- fprintf(stderr, "Failed to create RSA key\n");
- return -EINVAL;
- }
-
- if (SHA1(db, dblen, hash) != hash) {
- fprintf(stderr, "Failed to calculate SHA sum\n");
- RSA_free(rsa);
- return -EINVAL;
- }
-
- for (i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) {
- rsa->e = &keys[i].e;
- rsa->n = &keys[i].n;
-
- if (RSA_size(rsa) != siglen)
- continue;
-
- ok = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
- db + dblen, siglen, rsa) == 1;
- if (ok)
- break;
- }
-
- rsa->e = NULL;
- rsa->n = NULL;
- RSA_free(rsa);
-
- if (!ok) {
- fprintf(stderr, "Database signature wrong\n");
+ if (!crda_verify_db_signature(db, dblen, siglen))
return -EINVAL;
- }
-
- BN_print_fp(stdout, &keys[0].n);
-#endif
-
-#ifdef USE_GCRYPT
- /* initialise */
- gcry_check_version(NULL);
-
- /* hash the db */
- gcry_md_hash_buffer(GCRY_MD_SHA1, hash, db, dblen);
-
- if (gcry_sexp_build(&data, NULL, "(data (flags pkcs1) (hash sha1 %b))",
- 20, hash)) {
- fprintf(stderr, "failed to build data expression\n");
- return 2;
- }
-
- if (gcry_sexp_build(&signature, NULL, "(sig-val (rsa (s %b)))",
- siglen, db + dblen)) {
- fprintf(stderr, "failed to build signature expression\n");
- return 2;
- }
-
- for (i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) {
- if (gcry_mpi_scan(&mpi_e, GCRYMPI_FMT_USG,
- keys[0].e, keys[0].len_e, NULL) ||
- gcry_mpi_scan(&mpi_n, GCRYMPI_FMT_USG,
- keys[0].n, keys[0].len_n, NULL)) {
- fprintf(stderr, "failed to convert numbers\n");
- return 2;
- }
-
- if (gcry_sexp_build(&rsa, NULL,
- "(public-key (rsa (n %m) (e %m)))",
- mpi_n, mpi_e)) {
- fprintf(stderr, "failed to build rsa key\n");
- return 2;
- }
-
- if (!gcry_pk_verify(signature, data, rsa)) {
- ok = 1;
- break;
- }
- }
-
- if (!ok) {
- fprintf(stderr, "Database signature wrong\n");
- return 2;
- }
-#endif

num_countries = ntohl(header->reg_country_num);
countries = get_file_ptr(db, dblen,
diff --git a/dump.c b/dump.c
index b133915..89f16b2 100644
--- a/dump.c
+++ b/dump.c
@@ -1,29 +1,13 @@
+#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
-#include <sys/types.h>
#include <sys/stat.h>
-#include <unistd.h>
#include <fcntl.h>
#include <arpa/inet.h> /* ntohl */

#include "regdb.h"

-#ifdef USE_OPENSSL
-#include <openssl/objects.h>
-#include <openssl/bn.h>
-#include <openssl/rsa.h>
-#include <openssl/sha.h>
-
-#include "keys-ssl.c"
-#endif
-
-#ifdef USE_GCRYPT
-#include <gcrypt.h>
-
-#include "keys-gcrypt.c"
-#endif
-
static void *get_file_ptr(__u8 *db, int dblen, int structlen, __be32 ptr)
{
__u32 p = ntohl(ptr);
@@ -95,17 +79,6 @@ int main(int argc, char **argv)
struct regdb_file_header *header;
struct regdb_file_reg_country *countries;
int dblen, siglen, num_countries, i, j;
-#ifdef USE_OPENSSL
- RSA *rsa;
- __u8 hash[SHA_DIGEST_LENGTH];
- int ok = 0;
-#endif
-#ifdef USE_GCRYPT
- gcry_mpi_t mpi_e, mpi_n;
- gcry_sexp_t rsa, signature, data;
- __u8 hash[20];
- int ok = 0;
-#endif

if (argc != 2) {
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
@@ -153,92 +126,8 @@ int main(int argc, char **argv)
}

/* verify signature */
-#ifdef USE_OPENSSL
- rsa = RSA_new();
- if (!rsa) {
- fprintf(stderr, "Failed to create RSA key\n");
- return 2;
- }
-
- if (SHA1(db, dblen, hash) != hash) {
- fprintf(stderr, "Failed to calculate SHA sum\n");
- return 2;
- }
-
- for (i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) {
- rsa->e = &keys[i].e;
- rsa->n = &keys[i].n;
-
- if (RSA_size(rsa) != siglen)
- continue;
-
- ok = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
- db + dblen, siglen, rsa) == 1;
- if (ok)
- break;
- }
-
- if (!ok) {
- fprintf(stderr, "Database signature wrong\n");
- return 2;
- }
-
- rsa->e = NULL;
- rsa->n = NULL;
- RSA_free(rsa);
-
- BN_print_fp(stdout, &keys[0].n);
-
- return 0;
-#endif
-
-#ifdef USE_GCRYPT
- /* initialise */
- gcry_check_version(NULL);
-
- /* hash the db */
- gcry_md_hash_buffer(GCRY_MD_SHA1, hash, db, dblen);
-
- if (gcry_sexp_build(&data, NULL, "(data (flags pkcs1) (hash sha1 %b))",
- 20, hash)) {
- fprintf(stderr, "failed to build data expression\n");
- return 2;
- }
-
- if (gcry_sexp_build(&signature, NULL, "(sig-val (rsa (s %b)))",
- siglen, db + dblen)) {
- fprintf(stderr, "failed to build signature expression\n");
- return 2;
- }
-
- for (i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) {
- if (gcry_mpi_scan(&mpi_e, GCRYMPI_FMT_USG,
- keys[0].e, keys[0].len_e, NULL) ||
- gcry_mpi_scan(&mpi_n, GCRYMPI_FMT_USG,
- keys[0].n, keys[0].len_n, NULL)) {
- fprintf(stderr, "failed to convert numbers\n");
- return 2;
- }
-
- if (gcry_sexp_build(&rsa, NULL,
- "(public-key (rsa (n %m) (e %m)))",
- mpi_n, mpi_e)) {
- fprintf(stderr, "failed to build rsa key\n");
- return 2;
- }
-
- if (!gcry_pk_verify(signature, data, rsa)) {
- ok = 1;
- break;
- }
- }
-
- if (!ok) {
- fprintf(stderr, "Database signature wrong\n");
- return 2;
- }
-
-#endif
+ if (!crda_verify_db_signature(db, dblen, siglen))
+ return -EINVAL;

num_countries = ntohl(header->reg_country_num);
countries = get_file_ptr(db, dblen,
diff --git a/regdb.c b/regdb.c
new file mode 100644
index 0000000..385ba7d
--- /dev/null
+++ b/regdb.c
@@ -0,0 +1,119 @@
+#ifdef USE_OPENSSL
+#include <stdio.h>
+#include <openssl/objects.h>
+#include <openssl/rsa.h>
+#include <openssl/sha.h>
+#endif
+
+#ifdef USE_GCRYPT
+#include <stdio.h>
+#include <gcrypt.h>
+#endif
+
+#include "regdb.h"
+
+#ifdef USE_OPENSSL
+#include "keys-ssl.c"
+#endif
+
+#ifdef USE_GCRYPT
+#include "keys-gcrypt.c"
+#endif
+
+/*
+ * Checks the validity of the signature found on the regulatory
+ * database against the array 'keys'. Returns 1 if there exists
+ * at least one key in the array such that the signature is valid
+ * against that key; 0 otherwise.
+ */
+int crda_verify_db_signature(__u8 *db, int dblen, int siglen)
+{
+#ifdef USE_OPENSSL
+ RSA *rsa;
+ __u8 hash[SHA_DIGEST_LENGTH];
+ unsigned int i;
+ int ok = 0;
+
+ rsa = RSA_new();
+ if (!rsa) {
+ fprintf(stderr, "Failed to create RSA key.\n");
+ goto out;
+ }
+
+ if (SHA1(db, dblen, hash) != hash) {
+ fprintf(stderr, "Failed to calculate SHA1 sum.\n");
+ RSA_free(rsa);
+ goto out;
+ }
+
+ for (i = 0; (i < sizeof(keys)/sizeof(keys[0])) && (!ok); i++) {
+ rsa->e = &keys[i].e;
+ rsa->n = &keys[i].n;
+
+ if (RSA_size(rsa) != siglen)
+ continue;
+
+ ok = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
+ db + dblen, siglen, rsa) == 1;
+ }
+
+ rsa->e = NULL;
+ rsa->n = NULL;
+ RSA_free(rsa);
+#endif
+
+#ifdef USE_GCRYPT
+ gcry_mpi_t mpi_e, mpi_n;
+ gcry_sexp_t rsa, signature, data;
+ __u8 hash[20];
+ unsigned int i;
+ int ok = 0;
+
+ /* initialise */
+ gcry_check_version(NULL);
+
+ /* hash the db */
+ gcry_md_hash_buffer(GCRY_MD_SHA1, hash, db, dblen);
+
+ if (gcry_sexp_build(&data, NULL, "(data (flags pkcs1) (hash sha1 %b))",
+ 20, hash)) {
+ fprintf(stderr, "Failed to build data S-expression.\n");
+ goto out;
+ }
+
+ if (gcry_sexp_build(&signature, NULL, "(sig-val (rsa (s %b)))",
+ siglen, db + dblen)) {
+ fprintf(stderr, "Failed to build signature S-expression.\n");
+ goto out;
+ }
+
+ for (i = 0; (i < sizeof(keys)/sizeof(keys[0])) && (!ok); i++) {
+ if (gcry_mpi_scan(&mpi_e, GCRYMPI_FMT_USG,
+ keys[0].e, keys[0].len_e, NULL) ||
+ gcry_mpi_scan(&mpi_n, GCRYMPI_FMT_USG,
+ keys[0].n, keys[0].len_n, NULL)) {
+ fprintf(stderr, "Failed to convert numbers.\n");
+ goto out;
+ }
+
+ if (gcry_sexp_build(&rsa, NULL,
+ "(public-key (rsa (n %m) (e %m)))",
+ mpi_n, mpi_e)) {
+ fprintf(stderr, "Failed to build RSA S-expression.\n");
+ goto out;
+ }
+
+ ok = gcry_pk_verify(signature, data, rsa) == 0;
+ }
+#endif
+
+#if defined(USE_OPENSSL) || defined(USE_GCRYPT)
+ if (!ok)
+ fprintf(stderr, "Database signature verification failed.\n");
+
+out:
+ return ok;
+#else
+ return 1;
+#endif
+}
diff --git a/regdb.h b/regdb.h
index 09cc403..bee00a5 100644
--- a/regdb.h
+++ b/regdb.h
@@ -100,6 +100,10 @@ struct regdb_file_reg_country {
};


+/* functions */
+int crda_verify_db_signature(__u8 *db, int dblen, int siglen);
+
+
/*
* Verify that no unexpected padding is added to structures
* for some reason.
--
1.6.0.2



2008-10-23 23:22:41

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: [CRDA PATCH 1/6] Consolidate db signature validation in one function.

On Thu, Oct 23, 2008 at 4:04 PM, Davide Pesavento <[email protected]> wrote:

Very nice, thanks for all of these, applied and pushed.

Luis