Merge 0.10->trunk
[prosody.git] / util / sslconfig.lua
1 -- util to easily merge multiple sets of LuaSec context options
2
3 local type = type;
4 local pairs = pairs;
5 local rawset = rawset;
6 local t_concat = table.concat;
7 local t_insert = table.insert;
8 local setmetatable = setmetatable;
9
10 local _ENV = nil;
11
12 local handlers = { };
13 local finalisers = { };
14 local id = function (v) return v end
15
16 -- All "handlers" behave like extended rawset(table, key, value) with extra
17 -- processing usually merging the new value with the old in some reasonable
18 -- way
19 -- If a field does not have a defined handler then a new value simply
20 -- replaces the old.
21
22
23 -- Convert either a list or a set into a special type of set where each
24 -- item is either positive or negative in order for a later set of options
25 -- to be able to remove options from this set by filtering out the negative ones
26 function handlers.options(config, field, new)
27         local options = config[field] or { };
28         if type(new) ~= "table" then new = { new } end
29         for key, value in pairs(new) do
30                 if value == true or value == false then
31                         options[key] = value;
32                 else -- list item
33                         options[value] = true;
34                 end
35         end
36         config[field] = options;
37 end
38
39 handlers.verify = handlers.options;
40 handlers.verifyext = handlers.options;
41
42 -- finalisers take something produced by handlers and return what luasec
43 -- expects it to be
44
45 -- Produce a list of "positive" options from the set
46 function finalisers.options(options)
47         local output = {};
48         for opt, enable in pairs(options) do
49                 if enable then
50                         output[#output+1] = opt;
51                 end
52         end
53         return output;
54 end
55
56 finalisers.verify = finalisers.options;
57 finalisers.verifyext = finalisers.options;
58
59 -- We allow ciphers to be a list
60
61 function finalisers.ciphers(cipherlist)
62         if type(cipherlist) == "table" then
63                 return t_concat(cipherlist, ":");
64         end
65         return cipherlist;
66 end
67
68 -- protocol = "x" should enable only that protocol
69 -- protocol = "x+" should enable x and later versions
70
71 local protocols = { "sslv2", "sslv3", "tlsv1", "tlsv1_1", "tlsv1_2" };
72 for i = 1, #protocols do protocols[protocols[i] .. "+"] = i - 1; end
73
74 -- this interacts with ssl.options as well to add no_x
75 local function protocol(config)
76         local min_protocol = protocols[config.protocol];
77         if min_protocol then
78                 config.protocol = "sslv23";
79                 for i = 1, min_protocol do
80                         t_insert(config.options, "no_"..protocols[i]);
81                 end
82         end
83 end
84
85 -- Merge options from 'new' config into 'config'
86 local function apply(config, new)
87         if type(new) == "table" then
88                 for field, value in pairs(new) do
89                         (handlers[field] or rawset)(config, field, value);
90                 end
91         end
92 end
93
94 -- Finalize the config into the form LuaSec expects
95 local function final(config)
96         local output = { };
97         for field, value in pairs(config) do
98                 output[field] = (finalisers[field] or id)(value);
99         end
100         -- Need to handle protocols last because it adds to the options list
101         protocol(output);
102         return output;
103 end
104
105 local sslopts_mt = {
106         __index = {
107                 apply = apply;
108                 final = final;
109         };
110 };
111
112 local function new()
113         return setmetatable({options={}}, sslopts_mt);
114 end
115
116 return {
117         apply = apply;
118         final = final;
119         new = new;
120 };