@@ -99,6 +99,93 @@ def accept(opts = {})
99
99
end
100
100
end
101
101
102
+ #
103
+ # Parse a certificate in unified PEM format that contains a private key and
104
+ # one or more certificates. The first certificate is the primary, while any
105
+ # additional certificates are treated as intermediary certificates. This emulates
106
+ # the behavior of web servers like nginx.
107
+ #
108
+ # @param [String] ssl_cert
109
+ # @return [String, String, Array]
110
+ def self . ssl_parse_pem ( ssl_cert )
111
+ cert = nil
112
+ key = nil
113
+ chain = nil
114
+
115
+ certs = [ ]
116
+ ssl_cert . scan ( /-----BEGIN\s *[^\- ]+-----+\r ?\n [^\- ]*-----END\s *[^\- ]+-----\r ?\n ?/nm ) . each do |pem |
117
+ if pem =~ /PRIVATE KEY/
118
+ key = OpenSSL ::PKey ::RSA . new ( pem )
119
+ elsif pem =~ /CERTIFICATE/
120
+ certs << OpenSSL ::X509 ::Certificate . new ( pem )
121
+ end
122
+ end
123
+
124
+ cert = certs . shift
125
+ if certs . length > 0
126
+ chain = certs
127
+ end
128
+
129
+ [ key , cert , chain ]
130
+ end
131
+
132
+ #
133
+ # Shim for the ssl_parse_pem module method
134
+ #
135
+ def ssl_parse_pem ( ssl_cert )
136
+ Rex ::Socket ::SslTcpServer . ssl_parse_pem ( ssl_cert )
137
+ end
138
+
139
+ #
140
+ # Generate a realistic-looking but obstensibly fake SSL
141
+ # certificate.
142
+ #
143
+ # @return [String, String, Array]
144
+ def self . ssl_generate_certificate
145
+ key = OpenSSL ::PKey ::RSA . new ( 1024 ) { }
146
+ cert = OpenSSL ::X509 ::Certificate . new
147
+ cert . version = 2
148
+ cert . serial = rand ( 0xFFFFFFFF )
149
+ subject = OpenSSL ::X509 ::Name . new ( [
150
+ [ "C" , "US" ] ,
151
+ [ 'ST' , Rex ::Text . rand_state ( ) ] ,
152
+ [ "L" , Rex ::Text . rand_text_alpha ( rand ( 20 ) + 10 ) ] ,
153
+ [ "O" , Rex ::Text . rand_text_alpha ( rand ( 20 ) + 10 ) ] ,
154
+ [ "CN" , Rex ::Text . rand_hostname ] ,
155
+ ] )
156
+ issuer = OpenSSL ::X509 ::Name . new ( [
157
+ [ "C" , "US" ] ,
158
+ [ 'ST' , Rex ::Text . rand_state ( ) ] ,
159
+ [ "L" , Rex ::Text . rand_text_alpha ( rand ( 20 ) + 10 ) ] ,
160
+ [ "O" , Rex ::Text . rand_text_alpha ( rand ( 20 ) + 10 ) ] ,
161
+ [ "CN" , Rex ::Text . rand_hostname ] ,
162
+ ] )
163
+
164
+ cert . subject = subject
165
+ cert . issuer = issuer
166
+ cert . not_before = Time . now - ( 3600 * 365 )
167
+ cert . not_after = Time . now + ( 3600 * 365 )
168
+ cert . public_key = key . public_key
169
+ ef = OpenSSL ::X509 ::ExtensionFactory . new ( nil , cert )
170
+ cert . extensions = [
171
+ ef . create_extension ( "basicConstraints" , "CA:FALSE" ) ,
172
+ ef . create_extension ( "subjectKeyIdentifier" , "hash" ) ,
173
+ ef . create_extension ( "extendedKeyUsage" , "serverAuth" ) ,
174
+ ef . create_extension ( "keyUsage" , "keyEncipherment,dataEncipherment,digitalSignature" )
175
+ ]
176
+ ef . issuer_certificate = cert
177
+ cert . add_extension ef . create_extension ( "authorityKeyIdentifier" , "keyid:always,issuer:always" )
178
+ cert . sign ( key , OpenSSL ::Digest ::SHA1 . new )
179
+
180
+ [ key , cert , nil ]
181
+ end
182
+
183
+ #
184
+ # Shim for the ssl_generate_certificate module method
185
+ #
186
+ def ssl_generate_certificate
187
+ Rex ::Socket ::SslTcpServer . ssl_generate_certificate
188
+ end
102
189
103
190
#
104
191
# Create a new ssl context. If +ssl_cert+ is not given, generates a new
@@ -107,54 +194,19 @@ def accept(opts = {})
107
194
# @param [Rex::Socket::Parameters] params
108
195
# @return [::OpenSSL::SSL::SSLContext]
109
196
def makessl ( params )
110
- ssl_cert = params . ssl_cert
111
- if ssl_cert
112
- cert = OpenSSL ::X509 ::Certificate . new ( ssl_cert )
113
- key = OpenSSL ::PKey ::RSA . new ( ssl_cert )
197
+
198
+ if params . ssl_cert
199
+ key , cert , chain = ssl_parse_pem ( params . ssl_cert )
114
200
else
115
- key = OpenSSL ::PKey ::RSA . new ( 1024 ) { }
116
- cert = OpenSSL ::X509 ::Certificate . new
117
- cert . version = 2
118
- cert . serial = rand ( 0xFFFFFFFF )
119
- # name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]])
120
- subject = OpenSSL ::X509 ::Name . new ( [
121
- [ "C" , "US" ] ,
122
- [ 'ST' , Rex ::Text . rand_state ( ) ] ,
123
- [ "L" , Rex ::Text . rand_text_alpha ( rand ( 20 ) + 10 ) ] ,
124
- [ "O" , Rex ::Text . rand_text_alpha ( rand ( 20 ) + 10 ) ] ,
125
- [ "CN" , Rex ::Text . rand_hostname ] ,
126
- ] )
127
- issuer = OpenSSL ::X509 ::Name . new ( [
128
- [ "C" , "US" ] ,
129
- [ 'ST' , Rex ::Text . rand_state ( ) ] ,
130
- [ "L" , Rex ::Text . rand_text_alpha ( rand ( 20 ) + 10 ) ] ,
131
- [ "O" , Rex ::Text . rand_text_alpha ( rand ( 20 ) + 10 ) ] ,
132
- [ "CN" , Rex ::Text . rand_hostname ] ,
133
- ] )
134
-
135
- cert . subject = subject
136
- cert . issuer = issuer
137
- cert . not_before = Time . now - ( 3600 * 365 )
138
- cert . not_after = Time . now + ( 3600 * 365 )
139
- cert . public_key = key . public_key
140
- ef = OpenSSL ::X509 ::ExtensionFactory . new ( nil , cert )
141
- cert . extensions = [
142
- ef . create_extension ( "basicConstraints" , "CA:FALSE" ) ,
143
- ef . create_extension ( "subjectKeyIdentifier" , "hash" ) ,
144
- ef . create_extension ( "extendedKeyUsage" , "serverAuth" ) ,
145
- ef . create_extension ( "keyUsage" , "keyEncipherment,dataEncipherment,digitalSignature" )
146
- ]
147
- ef . issuer_certificate = cert
148
- cert . add_extension ef . create_extension ( "authorityKeyIdentifier" , "keyid:always,issuer:always" )
149
- cert . sign ( key , OpenSSL ::Digest ::SHA1 . new )
201
+ key , cert , chain = ssl_generate_certificate
150
202
end
151
203
152
204
ctx = OpenSSL ::SSL ::SSLContext . new ( )
153
205
ctx . key = key
154
206
ctx . cert = cert
207
+ ctx . extra_chain_cert = chain
155
208
ctx . options = 0
156
209
157
-
158
210
# Older versions of OpenSSL do not export the OP_NO_COMPRESSION symbol
159
211
if defined? ( OpenSSL ::SSL ::OP_NO_COMPRESSION )
160
212
# enable/disable the SSL/TLS-level compression
0 commit comments