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 else
67 return std::string("");
68 }
69
70 unique_ptr_del<BIO> subject_bio(BIO_new(BIO_s_mem()),
71 [](BIO *p)
72 { BIO_free(p); });
73 if (subject_bio == nullptr)
74 {
75 return std::string("");
76 }
77
78 X509_NAME_print_ex(subject_bio.get(),
79 X509_get_subject_name(cert),
80 0,
81 XN_FLAG_SEP_CPLUS_SPC
82 | XN_FLAG_FN_SN
83 | ASN1_STRFLGS_UTF8_CONVERT
84 | ASN1_STRFLGS_ESC_CTRL);
85 if (BIO_eof(subject_bio.get()))
86 {
87 return std::string("");
88 }
89
90 BUF_MEM *subject_mem = nullptr;
91 BIO_get_mem_ptr(subject_bio.get(), &subject_mem);
92 return std::string(subject_mem->data,
93 subject_mem->data + subject_mem->length);
94}
95
96static inline std::string X509_get_pem_encoding(::X509 *cert)
97{
98 char *data;
99 BIO *bio = BIO_new(BIO_s_mem());
100 /* Even though PEM_write_bio_X509 should not modify the argument the official API does not have a const argument */
101 PEM_write_bio_X509(bio, cert);
102 size_t len = BIO_get_mem_data(bio, &data);
103 std::string certpem{data, len};
104 BIO_free(bio);
105 return certpem;
106}
107
113static inline std::string x509_get_signature_algorithm(const ::X509 *cert)
114{
115 int nid = X509_get_signature_nid(cert);
116 const char *sig = OBJ_nid2sn(nid);
117
118 if (sig)
119 {
120 return sig;
121 }
122 else
123 return "(error getting signature algorithm)";
124}
125
138static inline std::string x509_get_field(::X509 *cert, const int nid)
139{
140 static const char nullc = '\0';
141 std::string ret;
142 X509_NAME *x509_name = X509_get_subject_name(cert);
143 int i = X509_NAME_get_index_by_NID(x509_name, nid, -1);
144 if (i >= 0)
145 {
146 X509_NAME_ENTRY *ent = X509_NAME_get_entry(x509_name, i);
147 if (ent)
148 {
149 ASN1_STRING *val = X509_NAME_ENTRY_get_data(ent);
150 unsigned char *buf;
151 buf = (unsigned char *)1; // bug in OpenSSL 0.9.6b ASN1_STRING_to_UTF8
152 // requires this workaround
153 const int len = ASN1_STRING_to_UTF8(&buf, val);
154 if (len > 0)
155 {
156 if (std::strlen((char *)buf) == static_cast<unsigned int>(len))
157 ret = (char *)buf;
158 OPENSSL_free(buf);
159 }
160 }
161 }
162 else
163 {
164 i = X509_get_ext_by_NID(cert, nid, -1);
165 if (i >= 0)
166 {
167 X509_EXTENSION *ext = X509_get_ext(cert, i);
168 if (ext)
169 {
170 BIO *bio = BIO_new(BIO_s_mem());
171 if (bio)
172 {
173 if (X509V3_EXT_print(bio, ext, 0, 0))
174 {
175 if (BIO_write(bio, &nullc, 1) == 1)
176 {
177 char *str;
178 const long len = BIO_get_mem_data(bio, &str);
179 if (std::strlen(str) == static_cast<size_t>(len))
180 ret = str;
181 }
182 }
183 BIO_free(bio);
184 }
185 }
186 }
187 }
188 return ret;
189}
190
200static inline std::string x509_get_serial(::X509 *cert)
201{
202 const ASN1_INTEGER *asn1_i = X509_get_serialNumber(cert);
203 BIGNUM *bignum = ASN1_INTEGER_to_BN(asn1_i, NULL);
204 char *openssl_serial = BN_bn2dec(bignum);
205 BN_free(bignum);
206
207 if (openssl_serial)
208 {
209 const std::string ret = openssl_serial;
210 OPENSSL_free(openssl_serial);
211 return ret;
212 }
213 return std::string();
214}
215
225static inline std::string x509_get_serial_hex(::X509 *cert)
226{
227 const ASN1_INTEGER *asn1_i = X509_get_serialNumber(cert);
228 return render_hex_sep(asn1_i->data, asn1_i->length, ':', false);
229}
230
237static inline std::size_t x509_fingerprint_size()
238{
239 return EVP_MD_size(EVP_sha256());
240}
241
242static inline std::vector<uint8_t> x509_get_fingerprint(const ::X509 *cert)
243{
244 std::vector<uint8_t> fingerprint;
245 fingerprint.resize(x509_fingerprint_size());
246
247 if (::X509_digest(cert, EVP_sha256(), fingerprint.data(), NULL) != 1)
248 throw OpenSSLException("OpenSSL error while calling X509_digest()");
249
250 return fingerprint;
251}
252
253} // 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:180
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