forked from OpenVPN/openvpn3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
verify_x509_name.hpp
138 lines (121 loc) · 4.08 KB
/
verify_x509_name.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012-2022 OpenVPN Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License Version 3
// as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program in the COPYING file.
// If not, see <http://www.gnu.org/licenses/>.
//
#pragma once
#include <openvpn/common/options.hpp>
namespace openvpn {
/**
* Parses the --verify-x509-name configuration option
* and provides the logic to validate an X.509 certificate subject
* against such an option.
*/
class VerifyX509Name
{
public:
enum Mode
{
VERIFY_X509_NONE = 0,
VERIFY_X509_SUBJECT_DN = 1,
VERIFY_X509_SUBJECT_RDN = 2,
VERIFY_X509_SUBJECT_RDN_PREFIX = 3
};
VerifyX509Name() = default;
VerifyX509Name(const OptionList &opt, const std::string &relay_prefix = "")
{
init(opt, relay_prefix);
}
~VerifyX509Name() = default;
void init(const OptionList &opt, const std::string &relay_prefix)
{
const Option *o = opt.get_ptr(relay_prefix + "verify-x509-name");
if (o)
{
o->min_args(1);
verify_value = o->get(1, 256);
// If the mode flag is not present, we default to subject.
// For details, see openvpn(8) man page.
mode = parse_x509_verify_mode(o->get_default(2, 256, "subject"));
}
}
std::string get_mode_str() const
{
switch (mode)
{
case VERIFY_X509_NONE:
return "VERIFY_X509_NONE";
case VERIFY_X509_SUBJECT_DN:
return "VERIFY_X509_SUBJECT_DN";
case VERIFY_X509_SUBJECT_RDN:
return "VERIFY_X509_SUBJECT_RDN";
case VERIFY_X509_SUBJECT_RDN_PREFIX:
return "VERIFY_X509_SUBJECT_RDN_PREFIX";
default:
return "VERIFY_X509_NONE";
}
}
Mode get_mode() const
{
return mode;
}
bool verify(const std::string &value) const
{
switch (mode)
{
case VERIFY_X509_NONE:
// If no verification is configured, it is always a pass
return true;
case VERIFY_X509_SUBJECT_DN:
// The input value is expected to be a full subject DN
// where a perfect match is expected
return verify_value == value;
case VERIFY_X509_SUBJECT_RDN:
// The input value is expected to be the certificate
// Common Name (CN), and a perfect patch is expected
return verify_value == value;
case VERIFY_X509_SUBJECT_RDN_PREFIX:
// The input value contains a prefix of the certificate
// Common Name (CN), where we only require a perfect match
// only on the matching prefix
return value.compare(0, verify_value.length(), verify_value) == 0;
}
return false;
}
private:
Mode mode = VERIFY_X509_NONE;
std::string verify_value;
static Mode parse_x509_verify_mode(const std::string &type)
{
if (type == "subject")
{
return VERIFY_X509_SUBJECT_DN;
}
else if (type == "name")
{
return VERIFY_X509_SUBJECT_RDN;
}
else if (type == "name-prefix")
{
return VERIFY_X509_SUBJECT_RDN_PREFIX;
}
throw option_error("Invalid verify-x509-name type: " + type);
}
}; // class VerifyX509Name
} // namespace openvpn