mirror of
https://github.com/fpagliughi/sockpp.git
synced 2026-01-12 00:04:45 +08:00
Added an OpenSSL certificate class
This commit is contained in:
@@ -36,18 +36,18 @@
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "sockpp/tcp_connector.h"
|
||||
#include "sockpp/tls/connector.h"
|
||||
#include "sockpp/tls/context.h"
|
||||
#include "sockpp/tls/error.h"
|
||||
#include "sockpp/version.h"
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
@@ -141,13 +141,27 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
cout << "Successful connection to " << addr << endl;
|
||||
|
||||
if (auto cert = conn.peer_certificate(); cert.empty()) {
|
||||
if (auto opt_cert = conn.peer_certificate(); !opt_cert) {
|
||||
cout << "No peer certificate" << endl;
|
||||
}
|
||||
else {
|
||||
ofstream fil("peer.cer", ios::binary);
|
||||
fil.write(reinterpret_cast<const char*>(cert.data()), cert.size());
|
||||
cout << "Wrote peer certificate to peer.cer" << endl;
|
||||
const auto& cert = opt_cert.value();
|
||||
|
||||
cout << "\nCertificate info:\n"
|
||||
<< " Subject: " << cert.subject_name() << '\n'
|
||||
<< " Issuer: " << cert.issuer_name() << '\n'
|
||||
<< " Valid dates: " << cert.not_before_str() << " - " << cert.not_after_str()
|
||||
<< endl;
|
||||
|
||||
ofstream derfil("peer.cer", ios::binary);
|
||||
auto der = cert.to_der();
|
||||
derfil.write(reinterpret_cast<const char*>(der.data()), der.size());
|
||||
cout << "\nWrote peer certificate to peer.cer" << endl;
|
||||
|
||||
ofstream pemfil("peer.pem");
|
||||
auto pem = cert.to_pem();
|
||||
pemfil.write(pem.data(), pem.size());
|
||||
cout << "\nWrote peer certificate to peer.pem" << endl;
|
||||
}
|
||||
|
||||
if (auto res = conn.write("HELO"); !res) {
|
||||
|
||||
111
include/sockpp/tls/openssl_certificate.h
Normal file
111
include/sockpp/tls/openssl_certificate.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @file openssl_certificate.h
|
||||
*
|
||||
* Socket type for OpenSSL TLS/SSL sockets.
|
||||
*
|
||||
* @author Frank Pagliughi
|
||||
* @date January 2025
|
||||
*/
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// This file is part of the "sockpp" C++ socket library.
|
||||
//
|
||||
// Copyright (c) 2025 Frank Pagliughi
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#ifndef __sockpp_tls_openssl_certificate_h
|
||||
#define __sockpp_tls_openssl_certificate_h
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include "sockpp/types.h"
|
||||
|
||||
namespace sockpp {
|
||||
|
||||
// Forward declaration
|
||||
class tls_socket;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* An X509 certificate implemented with OpenSSL.
|
||||
*/
|
||||
class tls_certificate
|
||||
{
|
||||
/** The certificate library struct */
|
||||
X509* cert_;
|
||||
|
||||
friend class tls_socket;
|
||||
|
||||
/** Object takes ownership of the pointer */
|
||||
tls_certificate(X509* cert) : cert_{cert} {}
|
||||
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
~tls_certificate() { ::X509_free(cert_); }
|
||||
/**
|
||||
* Gets the subject name for the certificate.
|
||||
* @return The subject name for the certificate.
|
||||
*/
|
||||
string subject_name() const;
|
||||
/**
|
||||
* Gets the subject name for the certificate.
|
||||
* @return The subject name for the certificate.
|
||||
*/
|
||||
string issuer_name() const;
|
||||
/**
|
||||
* Gets the certificate's "not before" date as a string.
|
||||
* @return The certificate's "not before" date as a string.
|
||||
*/
|
||||
string not_before_str() const;
|
||||
/**
|
||||
* Gets the certificate's "not after" date as a string.
|
||||
* @return The certificate's "not after" date as a string.
|
||||
*/
|
||||
string not_after_str() const;
|
||||
/**
|
||||
* Gets the certificate as a DER binary blob.
|
||||
* @return The certificate as a DER binary blob.
|
||||
*/
|
||||
binary to_der() const;
|
||||
/**
|
||||
* Gets the certificate as a PEM string.
|
||||
* @return The certificate as a PEM string.
|
||||
*/
|
||||
string to_pem() const;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
} // namespace sockpp
|
||||
|
||||
#endif // __sockpp_tls_openssl_certificate_h
|
||||
@@ -46,7 +46,10 @@
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "sockpp/stream_socket.h"
|
||||
#include "sockpp/tls/openssl_certificate.h"
|
||||
#include "sockpp/tls/openssl_context.h"
|
||||
#include "sockpp/tls/openssl_error.h"
|
||||
#include "sockpp/types.h"
|
||||
@@ -121,10 +124,11 @@ public:
|
||||
tls_socket& operator=(tls_socket&& rhs);
|
||||
|
||||
/**
|
||||
* Returns the peer's X.509 certificate data, in binary DER format.
|
||||
* Returns the peer's X.509 certificate.
|
||||
*/
|
||||
binary peer_certificate();
|
||||
std::optional<tls_certificate> peer_certificate();
|
||||
|
||||
#if 0
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -134,6 +138,7 @@ public:
|
||||
* certificate.
|
||||
*/
|
||||
string peer_certificate_status_message();
|
||||
#endif
|
||||
|
||||
// I/O primitives
|
||||
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
#define __sockpp_types_h
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
namespace sockpp {
|
||||
|
||||
|
||||
@@ -68,6 +68,7 @@ endif()
|
||||
|
||||
if(SOCKPP_WITH_OPENSSL)
|
||||
list(APPEND SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tls/openssl_certificate.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tls/openssl_context.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tls/openssl_socket.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/tls/openssl_error.cpp
|
||||
|
||||
112
src/tls/openssl_certificate.cpp
Normal file
112
src/tls/openssl_certificate.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// openssl_certificate.cpp
|
||||
//
|
||||
// --------------------------------------------------------------------------
|
||||
// This file is part of the "sockpp" C++ socket library.
|
||||
//
|
||||
// Copyright (c) 2025 Frank Pagliughi
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
||||
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
#include "sockpp/tls/openssl_certificate.h"
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/pem.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace sockpp {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
string tls_certificate::subject_name() const {
|
||||
auto name = X509_get_subject_name(cert_);
|
||||
if (!name)
|
||||
return string{};
|
||||
const char* name_str = X509_NAME_oneline(name, NULL, 0);
|
||||
return (name_str) ? string{name_str} : string{};
|
||||
}
|
||||
|
||||
// int X509_set_subject_name(X509 *x, const X509_NAME *name);
|
||||
|
||||
string tls_certificate::issuer_name() const {
|
||||
auto name = X509_get_issuer_name(cert_);
|
||||
if (!name)
|
||||
return string{};
|
||||
const char* name_str = X509_NAME_oneline(name, NULL, 0);
|
||||
return (name_str) ? string{name_str} : string{};
|
||||
}
|
||||
|
||||
// int X509_set_issuer_name(X509 *x, const X509_NAME *name);
|
||||
|
||||
string tls_certificate::not_before_str() const {
|
||||
auto tm = X509_get0_notBefore(cert_);
|
||||
return (tm && tm->data) ? string{(const char*)tm->data} : string{};
|
||||
}
|
||||
|
||||
string tls_certificate::not_after_str() const {
|
||||
auto tm = X509_get0_notAfter(cert_);
|
||||
return (tm && tm->data) ? string{(const char*)tm->data} : string{};
|
||||
}
|
||||
|
||||
binary tls_certificate::to_der() const {
|
||||
if (!cert_)
|
||||
return binary{};
|
||||
|
||||
uint8_t* buf = nullptr;
|
||||
int len = i2d_X509(cert_, &buf);
|
||||
|
||||
// TODO: Return an error result on <0?
|
||||
if (len <= 0)
|
||||
return binary{};
|
||||
|
||||
binary certBin{buf, size_t(len)};
|
||||
::OPENSSL_free(buf);
|
||||
|
||||
return certBin;
|
||||
}
|
||||
|
||||
string tls_certificate::to_pem() const {
|
||||
BIO* bio = ::BIO_new(BIO_s_mem());
|
||||
if (!bio || !::PEM_write_bio_X509(bio, cert_)) {
|
||||
::BIO_vfree(bio);
|
||||
return string{};
|
||||
}
|
||||
|
||||
size_t keylen = BIO_pending(bio);
|
||||
std::unique_ptr<char[]> key(new char[keylen]);
|
||||
|
||||
int len = ::BIO_read(bio, key.get(), (int)keylen);
|
||||
::BIO_vfree(bio);
|
||||
|
||||
return (len > 0) ? string{key.get(), (size_t)len} : string{};
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
} // namespace sockpp
|
||||
@@ -73,26 +73,17 @@ tls_socket& tls_socket::operator=(tls_socket&& rhs) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
binary tls_socket::peer_certificate() {
|
||||
std::optional<tls_certificate> tls_socket::peer_certificate() {
|
||||
// TODO: Implement this
|
||||
X509* cert = SSL_get0_peer_certificate(ssl_);
|
||||
X509* cert = SSL_get1_peer_certificate(ssl_);
|
||||
|
||||
if (!cert)
|
||||
return binary{};
|
||||
return std::nullopt;
|
||||
|
||||
uint8_t* buf = nullptr;
|
||||
int len = i2d_X509(cert, &buf);
|
||||
|
||||
// TODO: Return an error result on <0?
|
||||
if (len <= 0)
|
||||
return binary{};
|
||||
|
||||
binary certBin{buf, size_t(len)};
|
||||
OPENSSL_free(buf);
|
||||
|
||||
return certBin;
|
||||
return tls_certificate{cert};
|
||||
}
|
||||
|
||||
#if 0
|
||||
uint32_t tls_socket::peer_certificate_status() {
|
||||
// TODO: Implement this?
|
||||
return 0;
|
||||
@@ -104,7 +95,7 @@ string tls_socket::peer_certificate_status_message() {
|
||||
// TODO: Implement this?
|
||||
return string{};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
result<size_t> tls_socket::read(void* buf, size_t n) {
|
||||
size_t nx;
|
||||
|
||||
Reference in New Issue
Block a user