13 #include <arpa/inet.h> /* ntohl */
19 #include <openssl/objects.h>
20 #include <openssl/rsa.h>
21 #include <openssl/sha.h>
22 #include <openssl/pem.h>
36 #include "keys-gcrypt.c"
39 void *crda_get_file_ptr(uint8_t *db, int dblen, int structlen, uint32_t ptr)
41 uint32_t p = ntohl(ptr);
43 if (p > dblen - structlen) {
44 fprintf(stderr, "Invalid database file, bad pointer!\n");
48 return (void *)(db + p);
52 * Checks the validity of the signature found on the regulatory
53 * database against the array 'keys'. Returns 1 if there exists
54 * at least one key in the array such that the signature is valid
55 * against that key; 0 otherwise.
57 int crda_verify_db_signature(uint8_t *db, int dblen, int siglen)
61 uint8_t hash[SHA_DIGEST_LENGTH];
65 struct dirent *nextfile;
67 char filename[PATH_MAX];
69 if (SHA1(db, dblen, hash) != hash) {
70 fprintf(stderr, "Failed to calculate SHA1 sum.\n");
74 for (i = 0; (i < sizeof(keys)/sizeof(keys[0])) && (!ok); i++) {
77 fprintf(stderr, "Failed to create RSA key.\n");
84 ok = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
85 db + dblen, siglen, rsa) == 1;
91 if (!ok && (pubkey_dir = opendir(PUBKEY_DIR))) {
92 while (!ok && (nextfile = readdir(pubkey_dir))) {
93 snprintf(filename, PATH_MAX, "%s/%s", PUBKEY_DIR,
95 if ((keyfile = fopen(filename, "rb"))) {
96 rsa = PEM_read_RSA_PUBKEY(keyfile,
99 ok = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
100 db + dblen, siglen, rsa) == 1;
105 closedir(pubkey_dir);
110 gcry_mpi_t mpi_e, mpi_n;
111 gcry_sexp_t rsa, signature, data;
117 gcry_check_version(NULL);
120 gcry_md_hash_buffer(GCRY_MD_SHA1, hash, db, dblen);
122 if (gcry_sexp_build(&data, NULL, "(data (flags pkcs1) (hash sha1 %b))",
124 fprintf(stderr, "Failed to build data S-expression.\n");
128 if (gcry_sexp_build(&signature, NULL, "(sig-val (rsa (s %b)))",
129 siglen, db + dblen)) {
130 fprintf(stderr, "Failed to build signature S-expression.\n");
134 for (i = 0; (i < sizeof(keys)/sizeof(keys[0])) && (!ok); i++) {
135 if (gcry_mpi_scan(&mpi_e, GCRYMPI_FMT_USG,
136 keys[i].e, keys[i].len_e, NULL) ||
137 gcry_mpi_scan(&mpi_n, GCRYMPI_FMT_USG,
138 keys[i].n, keys[i].len_n, NULL)) {
139 fprintf(stderr, "Failed to convert numbers.\n");
143 if (gcry_sexp_build(&rsa, NULL,
144 "(public-key (rsa (n %m) (e %m)))",
146 fprintf(stderr, "Failed to build RSA S-expression.\n");
150 ok = gcry_pk_verify(signature, data, rsa) == 0;
154 #if defined(USE_OPENSSL) || defined(USE_GCRYPT)
156 fprintf(stderr, "Database signature verification failed.\n");
165 static void reg_rule2rd(uint8_t *db, int dblen,
166 uint32_t ruleptr, struct ieee80211_reg_rule *rd_reg_rule)
168 struct regdb_file_reg_rule *rule;
169 struct regdb_file_freq_range *freq;
170 struct regdb_file_power_rule *power;
172 struct ieee80211_freq_range *rd_freq_range = &rd_reg_rule->freq_range;
173 struct ieee80211_power_rule *rd_power_rule = &rd_reg_rule->power_rule;
175 rule = crda_get_file_ptr(db, dblen, sizeof(*rule), ruleptr);
176 freq = crda_get_file_ptr(db, dblen, sizeof(*freq), rule->freq_range_ptr);
177 power = crda_get_file_ptr(db, dblen, sizeof(*power), rule->power_rule_ptr);
179 rd_freq_range->start_freq_khz = ntohl(freq->start_freq);
180 rd_freq_range->end_freq_khz = ntohl(freq->end_freq);
181 rd_freq_range->max_bandwidth_khz = ntohl(freq->max_bandwidth);
183 rd_power_rule->max_antenna_gain = ntohl(power->max_antenna_gain);
184 rd_power_rule->max_eirp = ntohl(power->max_eirp);
186 rd_reg_rule->flags = ntohl(rule->flags);
189 /* Converts a file regdomain to ieee80211_regdomain, easier to manage */
190 static struct ieee80211_regdomain *
191 country2rd(uint8_t *db, int dblen,
192 struct regdb_file_reg_country *country)
194 struct regdb_file_reg_rules_collection *rcoll;
195 struct ieee80211_regdomain *rd;
196 int i, num_rules, size_of_rd;
198 rcoll = crda_get_file_ptr(db, dblen, sizeof(*rcoll),
199 country->reg_collection_ptr);
200 num_rules = ntohl(rcoll->reg_rule_num);
201 /* re-get pointer with sanity checking for num_rules */
202 rcoll = crda_get_file_ptr(db, dblen,
203 sizeof(*rcoll) + num_rules * sizeof(uint32_t),
204 country->reg_collection_ptr);
206 size_of_rd = sizeof(struct ieee80211_regdomain) +
207 num_rules * sizeof(struct ieee80211_reg_rule);
209 rd = malloc(size_of_rd);
213 memset(rd, 0, size_of_rd);
215 rd->alpha2[0] = country->alpha2[0];
216 rd->alpha2[1] = country->alpha2[1];
217 rd->dfs_region = country->creqs & 0x3;
218 rd->n_reg_rules = num_rules;
220 for (i = 0; i < num_rules; i++) {
221 reg_rule2rd(db, dblen, rcoll->reg_rule_ptrs[i],
228 struct ieee80211_regdomain *
229 reglib_get_rd_idx(unsigned int idx, const char *file)
234 struct regdb_file_header *header;
235 struct regdb_file_reg_country *countries;
236 int dblen, siglen, num_countries;
237 struct ieee80211_regdomain *rd = NULL;
238 struct regdb_file_reg_country *country;
240 fd = open(file, O_RDONLY);
245 if (fstat(fd, &stat))
248 dblen = stat.st_size;
250 db = mmap(NULL, dblen, PROT_READ, MAP_PRIVATE, fd, 0);
251 if (db == MAP_FAILED)
254 header = crda_get_file_ptr(db, dblen, sizeof(*header), 0);
256 if (ntohl(header->magic) != REGDB_MAGIC)
259 if (ntohl(header->version) != REGDB_VERSION)
262 siglen = ntohl(header->signature_length);
263 /* adjust dblen so later sanity checks don't run into the signature */
266 if (dblen <= (int)sizeof(*header))
269 /* verify signature */
270 if (!crda_verify_db_signature(db, dblen, siglen))
273 num_countries = ntohl(header->reg_country_num);
274 countries = crda_get_file_ptr(db, dblen,
275 sizeof(struct regdb_file_reg_country) * num_countries,
276 header->reg_country_ptr);
278 if (idx >= num_countries)
281 country = countries + idx;
283 rd = country2rd(db, dblen, country);
290 struct ieee80211_regdomain *
291 reglib_get_rd_alpha2(const char *alpha2, const char *file)
296 struct regdb_file_header *header;
297 struct regdb_file_reg_country *countries;
298 int dblen, siglen, num_countries;
299 struct ieee80211_regdomain *rd = NULL;
300 struct regdb_file_reg_country *country;
302 bool found_country = false;
304 fd = open(file, O_RDONLY);
309 if (fstat(fd, &stat))
312 dblen = stat.st_size;
314 db = mmap(NULL, dblen, PROT_READ, MAP_PRIVATE, fd, 0);
315 if (db == MAP_FAILED)
318 header = crda_get_file_ptr(db, dblen, sizeof(*header), 0);
320 if (ntohl(header->magic) != REGDB_MAGIC)
323 if (ntohl(header->version) != REGDB_VERSION)
326 siglen = ntohl(header->signature_length);
327 /* adjust dblen so later sanity checks don't run into the signature */
330 if (dblen <= (int)sizeof(*header))
333 /* verify signature */
334 if (!crda_verify_db_signature(db, dblen, siglen))
337 num_countries = ntohl(header->reg_country_num);
338 countries = crda_get_file_ptr(db, dblen,
339 sizeof(struct regdb_file_reg_country) * num_countries,
340 header->reg_country_ptr);
342 for (i = 0; i < num_countries; i++) {
343 country = countries + i;
344 if (memcmp(country->alpha2, alpha2, 2) == 0) {
353 rd = country2rd(db, dblen, country);