OpenVPN 3 Core Library
Loading...
Searching...
No Matches
cr.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// Encapsulate the state of a static or dynamic authentication challenge.
13
14#ifndef OPENVPN_AUTH_CR_H
15#define OPENVPN_AUTH_CR_H
16
17#include <string>
18#include <sstream>
19#include <vector>
20
24#include <openvpn/common/rc.hpp>
25
26// Static Challenge response:
27// SCRV1:<BASE64_PASSWORD>:<BASE64_RESPONSE>
28//
29// Dynamic Challenge:
30// CRV1:<FLAGS>:<STATE_ID>:<BASE64_USERNAME>:<CHALLENGE_TEXT>
31// FLAGS is a comma-separated list of options:
32// E -- echo
33// R -- response required
34//
35// Dynamic Challenge response:
36// Username: [username decoded from username_base64]
37// Password: CRV1::<STATE_ID>::<RESPONSE_TEXT>
38
39namespace openvpn {
40class ChallengeResponse : public RC<thread_unsafe_refcount>
41{
42 public:
44
45 OPENVPN_SIMPLE_EXCEPTION(dynamic_challenge_parse_error);
46 OPENVPN_SIMPLE_EXCEPTION(static_challenge_parse_error);
47
49 : echo(false), response_required(false)
50 {
51 }
52
53 explicit ChallengeResponse(const std::string &cookie)
54 : echo(false), response_required(false)
55 {
56 init(cookie);
57 }
58
59 ChallengeResponse(const std::string &cookie, const std::string &user)
60 : echo(false), response_required(false)
61 {
62 if (!is_dynamic(cookie) && cookie.find_first_of(':') == std::string::npos)
63 {
64 state_id = cookie;
65 username = user;
66 }
67 else
68 init(cookie);
69 }
70
71 void init(const std::string &cookie)
72 {
73 using StringList = std::vector<std::string>;
74 StringList sl;
75 sl.reserve(5);
76 Split::by_char_void<StringList, NullLex, Split::NullLimit>(sl, cookie, ':', 0, 4);
77 if (sl.size() != 5)
78 throw dynamic_challenge_parse_error();
79 if (sl[0] != "CRV1")
80 throw dynamic_challenge_parse_error();
81
82 // parse options
83 {
84 StringList opt;
85 opt.reserve(2);
86 Split::by_char_void<StringList, NullLex, Split::NullLimit>(opt, sl[1], ',');
87 for (StringList::const_iterator i = opt.begin(); i != opt.end(); ++i)
88 {
89 if (*i == "E")
90 echo = true;
91 else if (*i == "R")
92 response_required = true;
93 }
94 }
95
96 // save state ID
97 state_id = sl[2];
98
99 // save username
100 try
101 {
102 username = base64->decode(sl[3]);
103 }
104 catch (const Base64::base64_decode_error &)
105 {
106 throw dynamic_challenge_parse_error();
107 }
108
109 // save challenge
110 challenge_text = sl[4];
111 }
112
113 static bool is_dynamic(const std::string &s)
114 {
115 return s.starts_with("CRV1:");
116 }
117
118 static bool is_static(const std::string &s)
119 {
120 return s.starts_with("SCRV1:");
121 }
122
123 static void validate_dynamic(const std::string &cookie)
124 {
125 const ChallengeResponse cr(cookie);
126 }
127
128 std::string construct_dynamic_password(const std::string &response) const
129 {
130 return "CRV1::" + state_id + "::" + response;
131 }
132
133 static std::string construct_static_password(const std::string &password,
134 const std::string &response)
135 {
136 return "SCRV1:" + base64->encode(password) + ':' + base64->encode(response);
137 }
138
139 static void parse_static_cookie(const std::string &cookie,
140 std::string &password,
141 std::string &response)
142 {
143 using StringList = std::vector<std::string>;
144 StringList sl;
145 sl.reserve(3);
146 Split::by_char_void<StringList, NullLex, Split::NullLimit>(sl, cookie, ':');
147 if (sl.size() != 3)
148 throw static_challenge_parse_error();
149 if (sl[0] != "SCRV1")
150 throw static_challenge_parse_error();
151
152 // get password
153 try
154 {
155 password = base64->decode(sl[1]);
156 }
157 catch (const Base64::base64_decode_error &)
158 {
159 throw static_challenge_parse_error();
160 }
161
162 // get response
163 try
164 {
165 response = base64->decode(sl[2]);
166 }
167 catch (const Base64::base64_decode_error &)
168 {
169 throw static_challenge_parse_error();
170 }
171 }
172
173 static std::string generate_dynamic_challenge(const std::string &session_token,
174 const std::string &username,
175 const std::string &challenge,
176 const bool echo,
177 const bool response_required)
178 {
179 std::ostringstream os;
180 bool comma = false;
181 os << "CRV1:";
182 if (echo)
183 {
184 if (comma)
185 os << ",";
186 os << "E";
187 comma = true;
188 }
190 {
191 if (comma)
192 os << ",";
193 os << "R";
194 comma = true;
195 }
196 os << ':' << session_token;
197 os << ':' << base64->encode(username);
198 os << ':' << challenge;
199 return os.str();
200 }
201
202 const std::string &get_state_id() const
203 {
204 return state_id;
205 }
206 const std::string &get_username() const
207 {
208 return username;
209 }
210 bool get_echo() const
211 {
212 return echo;
213 }
215 {
216 return response_required;
217 }
218 const std::string &get_challenge_text() const
219 {
220 return challenge_text;
221 }
222
223 private:
224 bool echo;
226 std::string state_id;
227 std::string username;
228 std::string challenge_text;
229};
230} // namespace openvpn
231
232#endif
std::string encode(const V &data) const
Definition base64.hpp:139
size_t decode(void *data, size_t len, const std::string &str) const
Definition base64.hpp:186
static bool is_dynamic(const std::string &s)
Definition cr.hpp:113
bool get_echo() const
Definition cr.hpp:210
std::string construct_dynamic_password(const std::string &response) const
Definition cr.hpp:128
ChallengeResponse(const std::string &cookie, const std::string &user)
Definition cr.hpp:59
const std::string & get_username() const
Definition cr.hpp:206
void init(const std::string &cookie)
Definition cr.hpp:71
static void parse_static_cookie(const std::string &cookie, std::string &password, std::string &response)
Definition cr.hpp:139
std::string state_id
Definition cr.hpp:226
static std::string generate_dynamic_challenge(const std::string &session_token, const std::string &username, const std::string &challenge, const bool echo, const bool response_required)
Definition cr.hpp:173
static bool is_static(const std::string &s)
Definition cr.hpp:118
static std::string construct_static_password(const std::string &password, const std::string &response)
Definition cr.hpp:133
const std::string & get_state_id() const
Definition cr.hpp:202
std::string challenge_text
Definition cr.hpp:228
OPENVPN_SIMPLE_EXCEPTION(static_challenge_parse_error)
bool get_response_required() const
Definition cr.hpp:214
const std::string & get_challenge_text() const
Definition cr.hpp:218
static void validate_dynamic(const std::string &cookie)
Definition cr.hpp:123
std::string username
Definition cr.hpp:227
OPENVPN_SIMPLE_EXCEPTION(dynamic_challenge_parse_error)
ChallengeResponse(const std::string &cookie)
Definition cr.hpp:53
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
Definition rc.hpp:908
const Base64 * base64
Definition base64.hpp:299
std::ostringstream os