File: cclist.hpp

package info (click to toggle)
openvpn3-client 25%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 19,276 kB
  • sloc: cpp: 190,085; python: 7,218; ansic: 1,866; sh: 1,361; java: 402; lisp: 81; makefile: 17
file content (155 lines) | stat: -rw-r--r-- 4,929 bytes parent folder | download
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//    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- OpenVPN Inc.
//
//    SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
//

#ifndef OPENVPN_PKI_CCLIST_H
#define OPENVPN_PKI_CCLIST_H

#include <string>
#include <sstream>
#include <fstream>

#include <openvpn/common/size.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/file.hpp>
#include <openvpn/common/string.hpp>

namespace openvpn {

// Parse a concatenated list of certs and CRLs (PEM format).
// Abstracts CertList and CRLList, so can be used with any crypto lib.
// CertList and CRLList must define Item type.
template <typename CertList, typename CRLList>
class CertCRLListTemplate
{
  public:
    OPENVPN_EXCEPTION(parse_cert_crl_error);

    CertCRLListTemplate()
    {
    }

    explicit CertCRLListTemplate(const std::string &content, const std::string &title)
    {
        from_string(content, title, &certs, &crls);
    }

    void parse_pem(const std::string &content, const std::string &title)
    {
        from_string(content, title, &certs, &crls);
    }

    void parse_pem_file(const std::string &filename)
    {
        from_file(filename, &certs, &crls);
    }

    std::string render_pem() const
    {
        return certs.render_pem() + crls.render_pem();
    }

    static void from_istream(std::istream &in, const std::string &title, CertList *cert_list, CRLList *crl_list)
    {
        static const char cert_start[] = "-----BEGIN CERTIFICATE-----";
        static const char cert_end[] = "-----END CERTIFICATE-----";
        static const char crl_start[] = "-----BEGIN X509 CRL-----";
        static const char crl_end[] = "-----END X509 CRL-----";

        enum
        {
            S_OUTSIDE, // outside of CERT or CRL block
            S_IN_CERT, // in CERT block
            S_IN_CRL,  // in CRL block
        };

        std::string line;
        int state = S_OUTSIDE;
        std::string item = "";
        int line_num = 0;

        while (std::getline(in, line))
        {
            line_num++;
            string::trim(line);
            if (state == S_OUTSIDE)
            {
                if (line == cert_start)
                {
                    if (!cert_list)
                        OPENVPN_THROW(parse_cert_crl_error, title << ":" << line_num << " : not expecting a CERT");
                    state = S_IN_CERT;
                }
                else if (line == crl_start)
                {
                    if (!crl_list)
                        OPENVPN_THROW(parse_cert_crl_error, title << ":" << line_num << " : not expecting a CRL");
                    state = S_IN_CRL;
                }
            }
            if (state != S_OUTSIDE)
            {
                item += line;
                item += "\n";
            }
            if (state == S_IN_CERT && line == cert_end)
            {
                try
                {
                    cert_list->emplace_back(item, title);
                }
                catch (const std::exception &e)
                {
                    OPENVPN_THROW(parse_cert_crl_error, title << ":" << line_num << " : error parsing CERT: " << e.what());
                }
                state = S_OUTSIDE;
                item = "";
            }
            if (state == S_IN_CRL && line == crl_end)
            {
                try
                {
                    crl_list->emplace_back(item);
                }
                catch (const std::exception &e)
                {
                    OPENVPN_THROW(parse_cert_crl_error, title << ":" << line_num << " : error parsing CRL: " << e.what());
                }
                state = S_OUTSIDE;
                item = "";
            }
        }
        if (state != S_OUTSIDE)
            OPENVPN_THROW(parse_cert_crl_error, title << " : CERT/CRL content ended unexpectedly without END marker");
    }

    static void from_string(const std::string &content, const std::string &title, CertList *cert_list, CRLList *crl_list = nullptr)
    {
        std::stringstream in(content);
        from_istream(in, title, cert_list, crl_list);
    }

    static void from_file(const std::string &filename, CertList *cert_list, CRLList *crl_list = nullptr)
    {
        std::ifstream ifs(filename.c_str());
        if (!ifs)
            OPENVPN_THROW(open_file_error, "cannot open CERT/CRL file " << filename);
        from_istream(ifs, filename, cert_list, crl_list);
        if (ifs.bad())
            OPENVPN_THROW(open_file_error, "cannot read CERT/CRL file " << filename);
    }

    CertList certs;
    CRLList crls;
};

} // namespace openvpn

#endif // OPENVPN_PKI_CCLIST_H