@@ -42,15 +42,18 @@ def create_root_context(cacerts:, crls: [], revocation: Puppet[:certificate_revo
42
42
# refers to the cacerts bundle in the puppet-agent package.
43
43
#
44
44
# 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.
47
47
#
48
48
# @param cacerts [Array<OpenSSL::X509::Certificate>] Array of trusted CA certs
49
49
# @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.
50
53
# @return [Puppet::SSL::SSLContext] A context to use to create connections
51
54
# @raise (see #create_context)
52
55
# @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 )
54
57
store = create_x509_store ( cacerts , [ ] , false , include_system_store : true )
55
58
56
59
if path
@@ -71,6 +74,30 @@ def create_system_context(cacerts:, path: Puppet[:ssl_trust_store])
71
74
end
72
75
end
73
76
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
+
74
101
Puppet ::SSL ::SSLContext . new ( store : store , cacerts : cacerts , crls : [ ] , revocation : false ) . freeze
75
102
end
76
103
0 commit comments