CCF
Loading...
Searching...
No Matches
cert.h
Go to the documentation of this file.
1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the Apache 2.0 License.
3#pragma once
4
8#include "tls/ca.h"
9
10#include <cstring>
11#include <memory>
12#include <openssl/x509.h>
13#include <optional>
14
15using namespace ccf::crypto::OpenSSL;
16
17namespace tls
18{
19 // This class represents the authentication/authorization context for a TLS
20 // session. At least, it contains the peer's CA. At most, it also contains our
21 // own private key/certificate which will be presented in the TLS handshake.
22 // The peer's certificate verification can be overridden with the auth
23 // parameter.
24 class Cert
25 {
26 private:
27 std::shared_ptr<CA> peer_ca;
28 std::optional<std::string> peer_hostname;
29 bool auth_required;
30
31 Unique_X509 own_cert;
33 std::shared_ptr<ccf::crypto::ECKeyPair_OpenSSL> own_pkey;
34 bool has_own_cert = false;
35
36 public:
38 std::shared_ptr<CA> peer_ca_,
39 std::optional<ccf::crypto::Pem> own_cert_ = std::nullopt,
40 std::optional<ccf::crypto::Pem> own_pkey_ = std::nullopt,
41 std::optional<std::string> peer_hostname_ = std::nullopt,
42 bool auth_required_ = true) :
43 peer_ca(std::move(peer_ca_)),
44 peer_hostname(std::move(peer_hostname_)),
45 auth_required(auth_required_)
46 {
47 if (own_cert_.has_value() && own_pkey_.has_value())
48 {
49 const auto certs =
51 has_own_cert = true;
52
53 {
54 Unique_BIO certbio(certs[0]);
55 own_cert = Unique_X509(certbio, true);
56 own_pkey =
57 std::make_shared<ccf::crypto::ECKeyPair_OpenSSL>(*own_pkey_);
58 }
59
60 if (certs.size() > 1)
61 {
62 for (auto it = certs.begin() + 1; it != certs.end(); ++it)
63 {
64 Unique_BIO certbio(*it);
65 Unique_X509 cert(certbio, true);
66
67 CHECK1(sk_X509_push(chain, cert));
68 CHECK1(X509_up_ref(cert));
69 }
70 }
71 }
72 }
73
74 ~Cert() = default;
75
76 void use(SSL* ssl, SSL_CTX* ssl_ctx)
77 {
78 if (peer_hostname.has_value())
79 {
80 // Peer hostname for SNI
81 SSL_set_tlsext_host_name(ssl, peer_hostname->c_str());
82 }
83
84 if (peer_ca)
85 {
86 peer_ca->use(ssl_ctx);
87 }
88
89 if (auth_required)
90 {
91 int opts = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
92 auto cb = [](int ok, x509_store_ctx_st*) {
93 LOG_DEBUG_FMT("peer certificate verified: {}", ok);
94 return ok;
95 };
96 SSL_CTX_set_verify(ssl_ctx, opts, cb);
97 SSL_set_verify(ssl, opts, cb);
98 }
99 else
100 {
101 // Calling set_verify with SSL_VERIFY_PEER forces the handshake to
102 // request a peer certificate. The server always sends it to the client
103 // but not the other way around. Some code relies on the server doing
104 // that, so we set this here. We return 1 from the validation callback
105 // (a common pattern in OpenSSL implementations) because we don't want
106 // to verify it here, just request it.
107 auto cb = [](int, x509_store_ctx_st*) { return 1; };
108 SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, cb);
109 SSL_set_verify(ssl, SSL_VERIFY_PEER, cb);
110 }
111
112 if (has_own_cert)
113 {
114 CHECK1(
115 SSL_CTX_use_cert_and_key(ssl_ctx, own_cert, *own_pkey, chain, 1));
116 CHECK1(SSL_use_cert_and_key(ssl, own_cert, *own_pkey, chain, 1));
117 }
118 }
119 };
120}
Definition cert.h:25
Cert(std::shared_ptr< CA > peer_ca_, std::optional< ccf::crypto::Pem > own_cert_=std::nullopt, std::optional< ccf::crypto::Pem > own_pkey_=std::nullopt, std::optional< std::string > peer_hostname_=std::nullopt, bool auth_required_=true)
Definition cert.h:37
void use(SSL *ssl, SSL_CTX *ssl_ctx)
Definition cert.h:76
~Cert()=default
#define LOG_DEBUG_FMT
Definition internal_logger.h:14
Definition openssl_wrappers.h:27
void CHECK1(int rc)
Throws if rc is not 1 and has error.
Definition openssl_wrappers.h:54
std::vector< ccf::crypto::Pem > split_x509_cert_bundle(const std::string_view &pem)
Definition pem.cpp:37
STL namespace.
Definition key_exchange.h:18
Definition openssl_wrappers.h:159
Definition openssl_wrappers.h:309
Definition openssl_wrappers.h:273