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