OpenVPN 3 Core Library
Loading...
Searching...
No Matches
x509certinfo.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//
13// Generic functions for extracting X.509 Certificate info from
14// OpenSSL X509 objects
15
16#pragma once
17
18#include <cstring>
19#include <string>
20#include <vector>
21
22#include <openssl/ssl.h>
23#include <openssl/bio.h>
24#include <openssl/x509v3.h>
25#include <openssl/x509.h>
26
29
30namespace openvpn::OpenSSLPKI {
31
56static inline std::string x509_get_subject(::X509 *cert, bool new_format = false)
57{
58 if (!new_format)
59 {
61 X509_NAME_oneline(X509_get_subject_name(cert), nullptr, 0),
62 [](char *p)
63 { OPENSSL_free(p); });
64 if (subject)
65 return std::string(subject.get());
66 return std::string("");
67 }
68
69 unique_ptr_del<BIO> subject_bio(BIO_new(BIO_s_mem()),
70 [](BIO *p)
71 { BIO_free(p); });
72 if (subject_bio == nullptr)
73 {
74 return std::string("");
75 }
76
77 X509_NAME_print_ex(subject_bio.get(),
78 X509_get_subject_name(cert),
79 0,
80 XN_FLAG_SEP_CPLUS_SPC
81 | XN_FLAG_FN_SN
82 | ASN1_STRFLGS_UTF8_CONVERT
83 | ASN1_STRFLGS_ESC_CTRL);
84 if (BIO_eof(subject_bio.get()))
85 {
86 return std::string("");
87 }
88
89 BUF_MEM *subject_mem = nullptr;
90 BIO_get_mem_ptr(subject_bio.get(), &subject_mem);
91 return std::string(subject_mem->data,
92 subject_mem->data + subject_mem->length);
93}
94
95static inline std::string X509_get_pem_encoding(::X509 *cert)
96{
97 char *data;
98 BIO *bio = BIO_new(BIO_s_mem());
99 /* Even though PEM_write_bio_X509 should not modify the argument the official API does not have a const argument */
100 PEM_write_bio_X509(bio, cert);
101 size_t len = BIO_get_mem_data(bio, &data);
102 std::string certpem{data, len};
103 BIO_free(bio);
104 return certpem;
105}
106
112static inline std::string x509_get_signature_algorithm(const ::X509 *cert)
113{
114 int nid = X509_get_signature_nid(cert);
115 const char *sig = OBJ_nid2sn(nid);
116
117 if (sig)
118 {
119 return sig;
120 }
121 return "(error getting signature algorithm)";
122}
123
136static inline std::string x509_get_field(::X509 *cert, const int nid)
137{
138 static const char nullc = '\0';
139 std::string ret;
140 X509_NAME *x509_name = X509_get_subject_name(cert);
141 int i = X509_NAME_get_index_by_NID(x509_name, nid, -1);
142 if (i >= 0)
143 {
144 X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i);
145 if (ent)
146 {
147 ASN1_STRING *val = X509_NAME_ENTRY_get_data(ent);
148 unsigned char *buf;
149 buf = (unsigned char *)1; // bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8
150 // requires this workaround
151 const int len = ASN1_STRING_to_UTF8(&buf, val);
152 if (len > 0)
153 {
154 if (std::strlen((char *)buf) == static_cast<unsigned int>(len))
155 ret = (char *)buf;
156 OPENSSL_free(buf);
157 }
158 }
159 }
160 else
161 {
162 i = X509_get_ext_by_NID(cert, nid, -1);
163 if (i >= 0)
164 {
165 X509_EXTENSION *ext = X509_get_ext(cert, i);
166 if (ext)
167 {
168 BIO *bio = BIO_new(BIO_s_mem());
169 if (bio)
170 {
171 if (X509V3_EXT_print(bio, ext, 0, 0))
172 {
173 if (BIO_write(bio, &nullc, 1) == 1)
174 {
175 char *str;
176 const long len = BIO_get_mem_data(bio, &str);
177 if (std::strlen(str) == static_cast<size_t>(len))
178 ret = str;
179 }
180 }
181 BIO_free(bio);
182 }
183 }
184 }
185 }
186 return ret;
187}
188
198static inline std::string x509_get_serial(::X509 *cert)
199{
200 const ASN1_INTEGER *asn1_i = X509_get_serialNumber(cert);
201 BIGNUM *bignum = ASN1_INTEGER_to_BN(asn1_i, NULL);
202 char *openssl_serial = BN_bn2dec(bignum);
203 BN_free(bignum);
204
205 if (openssl_serial)
206 {
207 const std::string ret = openssl_serial;
208 OPENSSL_free(openssl_serial);
209 return ret;
210 }
211 return std::string();
212}
213
223static inline std::string x509_get_serial_hex(::X509 *cert)
224{
225 const ASN1_INTEGER *asn1_i = X509_get_serialNumber(cert);
226 return render_hex_sep(asn1_i->data, asn1_i->length, ':', false);
227}
228
235static inline std::size_t x509_fingerprint_size()
236{
237 return EVP_MD_size(EVP_sha256());
238}
239
240static inline std::vector<uint8_t> x509_get_fingerprint(const ::X509 *cert)
241{
242 std::vector<uint8_t> fingerprint;
243 fingerprint.resize(x509_fingerprint_size());
244
245 if (::X509_digest(cert, EVP_sha256(), fingerprint.data(), NULL) != 1)
246 throw OpenSSLException("OpenSSL error while calling X509_digest()");
247
248 return fingerprint;
249}
250
251} // namespace openvpn::OpenSSLPKI
static std::size_t x509_fingerprint_size()
static std::string x509_get_serial_hex(::X509 *cert)
static std::string x509_get_field(::X509 *cert, const int nid)
static std::string X509_get_pem_encoding(::X509 *cert)
static std::string x509_get_serial(::X509 *cert)
static std::vector< uint8_t > x509_get_fingerprint(const ::X509 *cert)
static std::string x509_get_subject(::X509 *cert, bool new_format=false)
static std::string x509_get_signature_algorithm(const ::X509 *cert)
std::unique_ptr< T, std::function< void(T *)> > unique_ptr_del
Definition uniqueptr.hpp:21
std::string render_hex_sep(const unsigned char *data, size_t size, const char sep, const bool caps=false)
Definition hexstr.hpp:178
os<< "Session Name: "<< tbc-> session_name<< '\n';os<< "Layer: "<< tbc-> layer str()<< '\n'
std::string ret
void ext(const std::string &path)
Definition test_path.cpp:24