@@ -42,15 +42,18 @@ def create_root_context(cacerts:, crls: [], revocation: Puppet[:certificate_revo
4242 # refers to the cacerts bundle in the puppet-agent package.
4343 #
4444 # Connections made from the returned context will authenticate the server,
45- # i.e. `VERIFY_PEER`, but will not use a client certificate and will not
46- # perform revocation checking.
45+ # i.e. `VERIFY_PEER`, but will not use a client certificate (unless requested)
46+ # and will not perform revocation checking.
4747 #
4848 # @param cacerts [Array<OpenSSL::X509::Certificate>] Array of trusted CA certs
4949 # @param path [String, nil] A file containing additional trusted CA certs.
50+ # @param include_client_cert [true, false] If true, the client cert will be added to the context
51+ # allowing mutual TLS authentication. The default is false. If the client cert doesn't exist
52+ # then the option will be ignored.
5053 # @return [Puppet::SSL::SSLContext] A context to use to create connections
5154 # @raise (see #create_context)
5255 # @api private
53- def create_system_context ( cacerts :, path : Puppet [ :ssl_trust_store ] )
56+ def create_system_context ( cacerts :, path : Puppet [ :ssl_trust_store ] , include_client_cert : false )
5457 store = create_x509_store ( cacerts , [ ] , false , include_system_store : true )
5558
5659 if path
@@ -71,6 +74,30 @@ def create_system_context(cacerts:, path: Puppet[:ssl_trust_store])
7174 end
7275 end
7376
77+ if include_client_cert
78+ cert_provider = Puppet ::X509 ::CertProvider . new
79+ private_key = cert_provider . load_private_key ( Puppet [ :certname ] , required : false )
80+ client_cert = cert_provider . load_client_cert ( Puppet [ :certname ] , required : false )
81+
82+ if private_key && client_cert
83+ client_chain = verify_cert_with_store ( store , client_cert )
84+
85+ if !private_key . is_a? ( OpenSSL ::PKey ::RSA ) && !private_key . is_a? ( OpenSSL ::PKey ::EC )
86+ raise Puppet ::SSL ::SSLError , _ ( "Unsupported key '%{type}'" ) % { type : private_key . class . name }
87+ end
88+
89+ unless client_cert . check_private_key ( private_key )
90+ raise Puppet ::SSL ::SSLError , _ ( "The certificate for '%{name}' does not match its private key" ) % { name : subject ( client_cert ) }
91+ end
92+
93+ return Puppet ::SSL ::SSLContext . new (
94+ store : store , cacerts : cacerts , crls : [ ] ,
95+ private_key : private_key , client_cert : client_cert , client_chain : client_chain ,
96+ revocation : false
97+ ) . freeze
98+ end
99+ end
100+
74101 Puppet ::SSL ::SSLContext . new ( store : store , cacerts : cacerts , crls : [ ] , revocation : false ) . freeze
75102 end
76103
0 commit comments