Skip to content

Commit 843996f

Browse files
committed
add elliptic curve support
1 parent 3dad9b4 commit 843996f

12 files changed

+504
-67
lines changed

.ycm_extra_conf.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import os
2+
import ycm_core
3+
4+
flags = [
5+
'-Wall',
6+
'-Wextra',
7+
'-Wno-variadic-macros',
8+
'-fexceptions',
9+
'-DNDEBUG',
10+
'-std=c++11',
11+
'-x',
12+
'c++',
13+
'-isystem', 'include',
14+
'-isystem', 'thirdparty/rapidjson/include',
15+
]
16+
17+
18+
compilation_database_folder = ''
19+
20+
if os.path.exists(compilation_database_folder):
21+
database = ycm_core.CompilationDatabase(compilation_database_folder)
22+
else:
23+
database = None
24+
25+
SOURCE_EXTENSIONS = ['.cpp']
26+
27+
28+
def DirectoryOfThisScript():
29+
return os.path.dirname(os.path.abspath(__file__))
30+
31+
32+
def MakeRelativePathsInFlagsAbsolute(flags, working_directory):
33+
if not working_directory:
34+
return list(flags)
35+
new_flags = []
36+
make_next_absolute = False
37+
path_flags = ['-isystem', '-I', '-iquote', '--sysroot=']
38+
for flag in flags:
39+
new_flag = flag
40+
41+
if make_next_absolute:
42+
make_next_absolute = False
43+
if not flag.startswith('/'):
44+
new_flag = os.path.join(working_directory, flag)
45+
46+
for path_flag in path_flags:
47+
if flag == path_flag:
48+
make_next_absolute = True
49+
break
50+
51+
if flag.startswith(path_flag):
52+
path = flag[len(path_flag):]
53+
new_flag = path_flag + os.path.join(working_directory, path)
54+
break
55+
56+
if new_flag:
57+
new_flags.append(new_flag)
58+
return new_flags
59+
60+
61+
def IsHeaderFile(filename):
62+
extension = os.path.splitext(filename)[1]
63+
return extension in ['.h', '.hpp']
64+
65+
66+
def GetCompilationInfoForFile(filename):
67+
# The compilation_commands.json file generated by CMake does not have
68+
# entries for header files. So we do our best by asking the db for flags
69+
# for a corresponding source file, if any. If one exists, the flags for
70+
# that file should be good enough.
71+
if IsHeaderFile(filename):
72+
basename = os.path.splitext(filename)[0]
73+
for extension in SOURCE_EXTENSIONS:
74+
replacement_file = basename + extension
75+
if os.path.exists(replacement_file):
76+
compilation_info = database.GetCompilationInfoForFile(
77+
replacement_file)
78+
if compilation_info.compiler_flags_:
79+
return compilation_info
80+
return None
81+
return database.GetCompilationInfoForFile(filename)
82+
83+
84+
def FlagsForFile(filename, **kwargs):
85+
if database:
86+
# Bear in mind that compilation_info.compiler_flags_ does NOT return a
87+
# python list, but a "list-like" StringVec object
88+
compilation_info = GetCompilationInfoForFile(filename)
89+
if not compilation_info:
90+
return None
91+
92+
final_flags = MakeRelativePathsInFlagsAbsolute(
93+
compilation_info.compiler_flags_,
94+
compilation_info.compiler_working_dir_)
95+
else:
96+
relative_to = DirectoryOfThisScript()
97+
final_flags = MakeRelativePathsInFlagsAbsolute(flags, relative_to)
98+
99+
return {
100+
'flags': final_flags,
101+
'do_cache': True
102+
}

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ cmake_minimum_required(VERSION 2.8)
22
project(libjose)
33
add_subdirectory(src)
44
add_subdirectory(tests)
5+
enable_testing()

include/libjose/jwa_ec.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,25 @@ namespace JOSE {
1010

1111
class JWA_EC {
1212
public:
13+
struct Curve {
14+
enum Type {
15+
P256,
16+
P384,
17+
P521,
18+
};
19+
};
1320
JWA_EC();
1421
explicit JWA_EC(const std::string &);
1522
~JWA_EC();
1623
operator bool() const {return valid_;}
1724
std::string to_pem() const;
25+
Curve::Type crv() const;
26+
std::string x() const;
27+
const ustring & x_raw() const;
28+
std::string y() const;
29+
const ustring & y_raw() const;
30+
std::string d() const;
31+
const ustring & d_raw() const;
1832
private:
1933
friend class JWA;
2034
JWA_EC(void *);

include/libjose/jwa_oct.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ class JWA_OCT {
1414
explicit JWA_OCT(const std::string &);
1515
~JWA_OCT();
1616
operator bool() const {return valid_;}
17-
const std::string & k() const;
17+
std::string k() const;
18+
const ustring & k_raw() const;
1819
private:
1920
friend class JWA;
2021
JWA_OCT(void *);

src/jwa_ec.cpp

Lines changed: 78 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,39 +38,78 @@ const boost::bimap<Key::Type, boost::bimaps::unordered_set_of<std::string>> Key:
3838
{Key::d, "d"},
3939
});
4040

41+
struct CurveImpl {
42+
typedef JWA_EC::Curve::Type Type;
43+
static const boost::bimap<Type, boost::bimaps::unordered_set_of<std::string>> lookup;
44+
static boost::optional<const std::string &> type2key(Type type) {
45+
auto i = lookup.left.find(type);
46+
if (i == lookup.left.end()) {
47+
return boost::none;
48+
}
49+
return i->second;
50+
}
51+
static boost::optional<Type> key2type(const std::string &key) {
52+
auto i = lookup.right.find(key);
53+
if (i == lookup.right.end()) {
54+
return boost::none;
55+
}
56+
return i->second;
57+
}
58+
};
59+
60+
const boost::bimap<JWA_EC::Curve::Type, boost::bimaps::unordered_set_of<std::string>> CurveImpl::lookup = make_bimap<JWA_EC::Curve::Type, boost::bimaps::unordered_set_of<std::string>>({
61+
{JWA_EC::Curve::P256, "P-256"},
62+
{JWA_EC::Curve::P384, "P-384"},
63+
{JWA_EC::Curve::P521, "P-521"},
64+
});
65+
4166
struct JWA_ECImpl {
4267
std::shared_ptr<rapidjson::Document> doc;
43-
std::string crv, x, y, d;
68+
JWA_EC::Curve::Type crv;
69+
ustring x, y, d;
70+
bool private_key;
4471
JWA_ECImpl(): doc{new rapidjson::Document} {}
4572
JWA_ECImpl(const std::string &json): doc{new rapidjson::Document} {
4673
doc->Parse(json.c_str());
4774
}
4875
JWA_ECImpl(void *_): doc{*reinterpret_cast<std::shared_ptr<rapidjson::Document>*>(_)} {}
4976
bool parse() {
77+
std::bitset<3> required;
78+
private_key = false;
5079
for (rapidjson::Value::ConstMemberIterator i = doc->MemberBegin(); i != doc->MemberEnd(); ++i) {
5180
auto key = Key::key2type(i->name.GetString());
5281
if (!key) {
5382
continue;
5483
}
55-
if (!i->value.IsString()) {
56-
return false;
57-
}
84+
if (!i->value.IsString()) {
85+
return false;
86+
}
5887
switch (*key) {
5988
case Key::crv:
60-
crv = i->value.GetString();
89+
{
90+
auto type = CurveImpl::key2type(i->value.GetString());
91+
if (!type) {
92+
return false;
93+
}
94+
required.set(0);
95+
crv = *type;
96+
}
6197
break;
6298
case Key::x:
63-
x = i->value.GetString();
99+
required.set(1);
100+
x = urlsafe_base64_decode(i->value.GetString());
64101
break;
65102
case Key::y:
66-
y = i->value.GetString();
103+
required.set(2);
104+
y = urlsafe_base64_decode(i->value.GetString());
67105
break;
68106
case Key::d:
69-
d = i->value.GetString();
107+
private_key = true;
108+
d = urlsafe_base64_decode(i->value.GetString());
70109
break;
71110
}
72111
}
73-
return true;
112+
return required.all();
74113
}
75114
};
76115

@@ -107,7 +146,36 @@ JWA_EC::~JWA_EC() {
107146
}
108147

109148
std::string JWA_EC::to_pem() const {
110-
return std::string{};
149+
if (impl(_)->private_key) {
150+
return ECPrivateKey2PEM(crv(), x_raw(), y_raw(), d_raw());
151+
} else {
152+
return ECPublicKey2PEM(crv(), x_raw(), y_raw());
153+
}
154+
}
155+
156+
JWA_EC::Curve::Type JWA_EC::crv() const {
157+
return impl(_)->crv;
158+
}
159+
160+
std::string JWA_EC::x() const {
161+
return urlsafe_base64_encode(x_raw());
162+
}
163+
const ustring & JWA_EC::x_raw() const {
164+
return impl(_)->x;
165+
}
166+
167+
std::string JWA_EC::y() const {
168+
return urlsafe_base64_encode(y_raw());
169+
}
170+
const ustring & JWA_EC::y_raw() const {
171+
return impl(_)->y;
172+
}
173+
174+
std::string JWA_EC::d() const {
175+
return urlsafe_base64_encode(d_raw());
176+
}
177+
const ustring & JWA_EC::d_raw() const {
178+
return impl(_)->d;
111179
}
112180

113181
} // namespace JOSE

src/jwa_oct.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const boost::bimap<Key::Type, boost::bimaps::unordered_set_of<std::string>> Key:
3434

3535
struct JWA_OCTImpl {
3636
std::shared_ptr<rapidjson::Document> doc;
37-
std::string k;
37+
ustring k;
3838
JWA_OCTImpl(): doc{new rapidjson::Document} {}
3939
JWA_OCTImpl(const std::string &json): doc{new rapidjson::Document} {
4040
doc->Parse(json.c_str());
@@ -46,14 +46,12 @@ struct JWA_OCTImpl {
4646
if (!key) {
4747
continue;
4848
}
49+
if (!i->value.IsString()) {
50+
return false;
51+
}
4952
switch (*key) {
5053
case Key::k:
51-
if (!i->value.IsString()) {
52-
return false;
53-
}
54-
k = i->value.GetString();
55-
break;
56-
default:
54+
k = urlsafe_base64_decode(i->value.GetString());
5755
break;
5856
}
5957
}
@@ -93,7 +91,10 @@ JWA_OCT::~JWA_OCT() {
9391
delete impl(_);
9492
}
9593

96-
const std::string & JWA_OCT::k() const {
94+
std::string JWA_OCT::k() const {
95+
return urlsafe_base64_encode(k_raw());
96+
}
97+
const ustring & JWA_OCT::k_raw() const {
9798
return impl(_)->k;
9899
}
99100

0 commit comments

Comments
 (0)