Update README and remove utils/web that the wireless-regdb.git sucked in.
[platform/upstream/crda.git] / reglib.c
1 #include <errno.h>
2 #include <stdio.h>
3 #include <arpa/inet.h>
4 #include "reglib.h"
5
6 #ifdef USE_OPENSSL
7 #include <openssl/objects.h>
8 #include <openssl/rsa.h>
9 #include <openssl/sha.h>
10 #endif
11
12 #ifdef USE_GCRYPT
13 #include <gcrypt.h>
14 #endif
15
16 #include "reglib.h"
17
18 #ifdef USE_OPENSSL
19 #include "keys-ssl.c"
20 #endif
21
22 #ifdef USE_GCRYPT
23 #include "keys-gcrypt.c"
24 #endif
25
26 void *crda_get_file_ptr(__u8 *db, int dblen, int structlen, __be32 ptr)
27 {
28         __u32 p = ntohl(ptr);
29
30         if (p > dblen - structlen) {
31                 fprintf(stderr, "Invalid database file, bad pointer!\n");
32                 exit(3);
33         }
34
35         return (void *)(db + p);
36 }
37
38 /*
39  * Checks the validity of the signature found on the regulatory
40  * database against the array 'keys'. Returns 1 if there exists
41  * at least one key in the array such that the signature is valid
42  * against that key; 0 otherwise.
43  */
44 int crda_verify_db_signature(__u8 *db, int dblen, int siglen)
45 {
46 #ifdef USE_OPENSSL
47         RSA *rsa;
48         __u8 hash[SHA_DIGEST_LENGTH];
49         unsigned int i;
50         int ok = 0;
51
52         rsa = RSA_new();
53         if (!rsa) {
54                 fprintf(stderr, "Failed to create RSA key.\n");
55                 goto out;
56         }
57
58         if (SHA1(db, dblen, hash) != hash) {
59                 fprintf(stderr, "Failed to calculate SHA1 sum.\n");
60                 RSA_free(rsa);
61                 goto out;
62         }
63
64         for (i = 0; (i < sizeof(keys)/sizeof(keys[0])) && (!ok); i++) {
65                 rsa->e = &keys[i].e;
66                 rsa->n = &keys[i].n;
67
68                 if (RSA_size(rsa) != siglen)
69                         continue;
70
71                 ok = RSA_verify(NID_sha1, hash, SHA_DIGEST_LENGTH,
72                                 db + dblen, siglen, rsa) == 1;
73         }
74
75         rsa->e = NULL;
76         rsa->n = NULL;
77         RSA_free(rsa);
78 #endif
79
80 #ifdef USE_GCRYPT
81         gcry_mpi_t mpi_e, mpi_n;
82         gcry_sexp_t rsa, signature, data;
83         __u8 hash[20];
84         unsigned int i;
85         int ok = 0;
86
87         /* initialise */
88         gcry_check_version(NULL);
89
90         /* hash the db */
91         gcry_md_hash_buffer(GCRY_MD_SHA1, hash, db, dblen);
92
93         if (gcry_sexp_build(&data, NULL, "(data (flags pkcs1) (hash sha1 %b))",
94                             20, hash)) {
95                 fprintf(stderr, "Failed to build data S-expression.\n");
96                 goto out;
97         }
98
99         if (gcry_sexp_build(&signature, NULL, "(sig-val (rsa (s %b)))",
100                             siglen, db + dblen)) {
101                 fprintf(stderr, "Failed to build signature S-expression.\n");
102                 goto out;
103         }
104
105         for (i = 0; (i < sizeof(keys)/sizeof(keys[0])) && (!ok); i++) {
106                 if (gcry_mpi_scan(&mpi_e, GCRYMPI_FMT_USG,
107                                 keys[i].e, keys[i].len_e, NULL) ||
108                     gcry_mpi_scan(&mpi_n, GCRYMPI_FMT_USG,
109                                 keys[i].n, keys[i].len_n, NULL)) {
110                         fprintf(stderr, "Failed to convert numbers.\n");
111                         goto out;
112                 }
113
114                 if (gcry_sexp_build(&rsa, NULL,
115                                     "(public-key (rsa (n %m) (e %m)))",
116                                     mpi_n, mpi_e)) {
117                         fprintf(stderr, "Failed to build RSA S-expression.\n");
118                         goto out;
119                 }
120
121                 ok = gcry_pk_verify(signature, data, rsa) == 0;
122         }
123 #endif
124
125 #if defined(USE_OPENSSL) || defined(USE_GCRYPT)
126         if (!ok)
127                 fprintf(stderr, "Database signature verification failed.\n");
128
129 out:
130         return ok;
131 #else
132         return 1;
133 #endif
134 }
135
136 void reg_rule2rd(__u8 *db, int dblen,
137         __be32 ruleptr, struct ieee80211_reg_rule *rd_reg_rule)
138 {
139         struct regdb_file_reg_rule *rule;
140         struct regdb_file_freq_range *freq;
141         struct regdb_file_power_rule *power;
142
143         struct ieee80211_freq_range *rd_freq_range = &rd_reg_rule->freq_range;
144         struct ieee80211_power_rule *rd_power_rule = &rd_reg_rule->power_rule;
145
146         rule  = crda_get_file_ptr(db, dblen, sizeof(*rule), ruleptr);
147         freq  = crda_get_file_ptr(db, dblen, sizeof(*freq), rule->freq_range_ptr);
148         power = crda_get_file_ptr(db, dblen, sizeof(*power), rule->power_rule_ptr);
149
150         rd_freq_range->start_freq_khz = ntohl(freq->start_freq);
151         rd_freq_range->end_freq_khz = ntohl(freq->end_freq);
152         rd_freq_range->max_bandwidth_khz = ntohl(freq->max_bandwidth);
153
154         rd_power_rule->max_antenna_gain = ntohl(power->max_antenna_gain);
155         rd_power_rule->max_eirp = ntohl(power->max_eirp);
156
157         rd_reg_rule->flags = ntohl(rule->flags);
158 }
159
160 /* Converts a file regdomain to ieee80211_regdomain, easier to manage */
161 struct ieee80211_regdomain *country2rd(__u8 *db, int dblen,
162         struct regdb_file_reg_country *country)
163 {
164         struct regdb_file_reg_rules_collection *rcoll;
165         struct ieee80211_regdomain *rd;
166         int i, num_rules, size_of_rd;
167
168         rcoll = crda_get_file_ptr(db, dblen, sizeof(*rcoll),
169                                 country->reg_collection_ptr);
170         num_rules = ntohl(rcoll->reg_rule_num);
171         /* re-get pointer with sanity checking for num_rules */
172         rcoll = crda_get_file_ptr(db, dblen,
173                         sizeof(*rcoll) + num_rules * sizeof(__be32),
174                         country->reg_collection_ptr);
175
176         size_of_rd = sizeof(struct ieee80211_regdomain) +
177                 num_rules * sizeof(struct ieee80211_reg_rule);
178
179         rd = malloc(size_of_rd);
180         if (!rd)
181                 return NULL;
182
183         memset(rd, 0, size_of_rd);
184
185         rd->alpha2[0] = country->alpha2[0];
186         rd->alpha2[1] = country->alpha2[1];
187         rd->n_reg_rules = num_rules;
188
189         for (i = 0; i < num_rules; i++) {
190                 reg_rule2rd(db, dblen, rcoll->reg_rule_ptrs[i],
191                         &rd->reg_rules[i]);
192         }
193
194         return rd;
195 }
196
197 /* Sanity check on a regulatory rule */
198 int is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
199 {
200         const struct ieee80211_freq_range *freq_range = &rule->freq_range;
201         __u32 freq_diff;
202
203         if (freq_range->start_freq_khz == 0 || freq_range->end_freq_khz == 0)
204                 return 0;
205
206         if (freq_range->start_freq_khz > freq_range->end_freq_khz)
207                 return 0;
208
209         freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
210
211         if (freq_diff == 0 || freq_range->max_bandwidth_khz > freq_diff)
212                 return 0;
213
214         return 1;
215 }
216
217 void print_reg_rule(struct ieee80211_reg_rule *rule)
218 {
219         struct ieee80211_freq_range *freq;
220         struct ieee80211_power_rule *power;
221
222         freq  = &rule->freq_range;
223         power = &rule->power_rule;
224
225         printf("\t(%.3f - %.3f @ %.3f), ",
226                ((float)(freq->start_freq_khz))/1000.0,
227                ((float)(freq->end_freq_khz))/1000.0,
228                ((float)(freq->max_bandwidth_khz))/1000.0);
229
230         printf("(");
231
232         if (power->max_antenna_gain)
233                 printf("%.2f, ", ((float)(power->max_antenna_gain)/100.0));
234         else
235                 printf("N/A, ");
236
237         if (power->max_eirp)
238                 printf("%.2f)", ((float)(power->max_eirp)/100.0));
239         else
240                 printf("N/A)");
241
242         if (rule->flags & RRF_NO_OFDM)
243                 printf(", NO-OFDM");
244         if (rule->flags & RRF_NO_CCK)
245                 printf(", NO-CCK");
246         if (rule->flags & RRF_NO_INDOOR)
247                 printf(", NO-INDOOR");
248         if (rule->flags & RRF_NO_OUTDOOR)
249                 printf(", NO-OUTDOOR");
250         if (rule->flags & RRF_DFS)
251                 printf(", DFS");
252         if (rule->flags & RRF_PTP_ONLY)
253                 printf(", PTP-ONLY");
254         if (rule->flags & RRF_PTMP_ONLY)
255                 printf(", PTMP-ONLY");
256         if (rule->flags & RRF_PASSIVE_SCAN)
257                 printf(", PASSIVE-SCAN");
258         if (rule->flags & RRF_NO_IBSS)
259                 printf(", NO-IBSS");
260
261         printf("\n");
262 }
263
264 void print_regdom(struct ieee80211_regdomain *rd)
265 {
266         unsigned int i;
267         printf("country %.2s:\n", rd->alpha2);
268         for (i = 0; i < rd->n_reg_rules; i++)
269                 print_reg_rule(&rd->reg_rules[i]);
270         printf("\n");
271 }
272