blob: 218110ba45da26832a8fbedbdadade6318c03a9b [file] [log] [blame]
#include <errno.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <dirent.h>
#include "reglib.h"
#ifdef USE_OPENSSL
#include <openssl/objects.h>
#include <openssl/rsa.h>
#include <openssl/sha.h>
#include <openssl/pem.h>
#endif
#ifdef USE_GCRYPT
#include <gcrypt.h>
#endif
#include "reglib.h"
#ifdef USE_OPENSSL
#include "keys-ssl.c"
#endif
#ifdef USE_GCRYPT
#include "keys-gcrypt.c"
#endif
void *crda_get_file_ptr(__u8 *db, int dblen, int structlen, __be32 ptr)
{
__u32 p = ntohl(ptr);
if (p > dblen - structlen) {
fprintf(stderr, "Invalid database file, bad pointer!\n");
exit(3);
}
return (void *)(db + p);
}
/*
* 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;
DIR *pubkey_dir;
struct dirent *nextfile;
FILE *keyfile;
char filename[PATH_MAX];
if (SHA1(db, dblen, hash) != hash) {
fprintf(stderr, "Failed to calculate SHA1 sum.\n");
goto out;
}
for (i = 0; (i < sizeof(keys)/sizeof(keys[0])) && (!ok); i++) {
rsa = RSA_new();
if (!rsa) {
fprintf(stderr, "Failed to create RSA key.\n");
goto out;
}
rsa->e = &keys[i].e;
rsa->n = &keys[i].n;
ok = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
db + dblen, siglen, rsa) == 1;
rsa->e = NULL;
rsa->n = NULL;
RSA_free(rsa);
}
if (!ok && (pubkey_dir = opendir(PUBKEY_DIR))) {
while (!ok && (nextfile = readdir(pubkey_dir))) {
snprintf(filename, PATH_MAX, "%s/%s", PUBKEY_DIR,
nextfile->d_name);
if ((keyfile = fopen(filename, "rb"))) {
rsa = PEM_read_RSA_PUBKEY(keyfile,
NULL, NULL, NULL);
if (rsa)
ok = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
db + dblen, siglen, rsa) == 1;
RSA_free(rsa);
fclose(keyfile);
}
}
closedir(pubkey_dir);
}
#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[i].e, keys[i].len_e, NULL) ||
gcry_mpi_scan(&mpi_n, GCRYMPI_FMT_USG,
keys[i].n, keys[i].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
}