Failed Conditions
Push — develop ( e08ac3...f94cbf )
by Remco
03:45
created

src/Integration.php (12 issues)

1
<?php
2
3
namespace Pronamic\WordPress\Pay\Gateways\IDealAdvancedV3;
4
5
use Pronamic\WordPress\Pay\Gateways\IDeal\AbstractIntegration;
6
7
/**
8
 * Title: iDEAL Advanced v3 integration
9
 * Description:
10
 * Copyright: 2005-2019 Pronamic
11
 * Company: Pronamic
12
 *
13
 * @author  Remco Tolsma
14
 * @version 2.0.0
15
 * @since   2.0.0
16
 */
17
class Integration extends AbstractIntegration {
18
	/**
19
	 * Settings constructor.
20
	 */
21
	public function __construct() {
22
		// Supported features.
23
		$this->supports = array(
0 ignored issues
show
Bug Best Practice introduced by
The property supports does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
24
			'payment_status_request',
25
		);
26
27
		// Actions.
28
		add_action( 'current_screen', array( $this, 'maybe_download_private_certificate' ) );
29
		add_action( 'current_screen', array( $this, 'maybe_download_private_key' ) );
30
	}
31
32
	public function get_config_factory_class() {
33
		return __NAMESPACE__ . '\ConfigFactory';
34
	}
35
36
	public function get_settings_fields() {
37
		$fields = parent::get_settings_fields();
0 ignored issues
show
The method get_settings_fields() does not exist on Pronamic\WordPress\Pay\G...eal\AbstractIntegration. Did you maybe mean get_settings()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

37
		/** @scrutinizer ignore-call */ 
38
  $fields = parent::get_settings_fields();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
38
39
		/*
40
		 * Private Key and Certificate
41
		 */
42
43
		// Private key and certificate information.
44
		$fields[] = array(
45
			'section'  => 'general',
46
			'title'    => __( 'Private key and certificate', 'pronamic_ideal' ),
47
			'type'     => 'description',
48
			'callback' => array( $this, 'field_security' ),
49
		);
50
51
		// Organization.
52
		$fields[] = array(
53
			'section'  => 'general',
54
			'filter'   => FILTER_SANITIZE_STRING,
55
			'group'    => 'pk-cert',
56
			'meta_key' => '_pronamic_gateway_organization',
57
			'title'    => __( 'Organization', 'pronamic_ideal' ),
58
			'type'     => 'text',
59
			'tooltip'  => __( 'Organization name, e.g. Pronamic', 'pronamic_ideal' ),
60
		);
61
62
		// Organization Unit.
63
		$fields[] = array(
64
			'section'  => 'general',
65
			'filter'   => FILTER_SANITIZE_STRING,
66
			'group'    => 'pk-cert',
67
			'meta_key' => '_pronamic_gateway_organization_unit',
68
			'title'    => __( 'Organization Unit', 'pronamic_ideal' ),
69
			'type'     => 'text',
70
			'tooltip'  => __( 'Organization unit, e.g. Administration', 'pronamic_ideal' ),
71
		);
72
73
		// Locality.
74
		$fields[] = array(
75
			'section'  => 'general',
76
			'filter'   => FILTER_SANITIZE_STRING,
77
			'group'    => 'pk-cert',
78
			'meta_key' => '_pronamic_gateway_locality',
79
			'title'    => __( 'City', 'pronamic_ideal' ),
80
			'type'     => 'text',
81
			'tooltip'  => __( 'City, e.g. Amsterdam', 'pronamic_ideal' ),
82
		);
83
84
		// State or Province.
85
		$fields[] = array(
86
			'section'  => 'general',
87
			'filter'   => FILTER_SANITIZE_STRING,
88
			'group'    => 'pk-cert',
89
			'meta_key' => '_pronamic_gateway_state_or_province',
90
			'title'    => __( 'State / province', 'pronamic_ideal' ),
91
			'type'     => 'text',
92
			'tooltip'  => __( 'State or province, e.g. Friesland', 'pronamic_ideal' ),
93
		);
94
95
		// Country.
96
		$locale = explode( '_', get_locale() );
97
98
		$locale = array_pop( $locale );
99
100
		$fields[] = array(
101
			'section'     => 'general',
102
			'filter'      => FILTER_SANITIZE_STRING,
103
			'group'       => 'pk-cert',
104
			'meta_key'    => '_pronamic_gateway_country',
105
			'title'       => __( 'Country', 'pronamic_ideal' ),
106
			'type'        => 'text',
107
			'tooltip'     => sprintf(
108
				'%s %s (ISO-3166-1 alpha-2)',
109
				__( '2 letter country code, e.g.', 'pronamic_ideal' ),
110
				strtoupper( $locale )
111
			),
112
			'size'        => 2,
113
			'description' => sprintf(
114
				'%s %s',
115
				__( '2 letter country code, e.g.', 'pronamic_ideal' ),
116
				strtoupper( $locale )
117
			),
118
		);
119
120
		// Email Address.
121
		$fields[] = array(
122
			'section'  => 'general',
123
			'filter'   => FILTER_SANITIZE_STRING,
124
			'group'    => 'pk-cert',
125
			'meta_key' => '_pronamic_gateway_email',
126
			'title'    => __( 'E-mail address', 'pronamic_ideal' ),
127
			'tooltip'  => sprintf(
128
				/* translators: %s: admin email */
129
				__( 'E-mail address, e.g. %s', 'pronamic_ideal' ),
130
				get_option( 'admin_email' )
0 ignored issues
show
It seems like get_option('admin_email') can also be of type false; however, parameter $args of sprintf() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

130
				/** @scrutinizer ignore-type */ get_option( 'admin_email' )
Loading history...
131
			),
132
			'type'     => 'text',
133
		);
134
135
		// Number Days Valid.
136
		$fields[] = array(
137
			'section'  => 'general',
138
			'filter'   => FILTER_SANITIZE_NUMBER_INT,
139
			'group'    => 'pk-cert',
140
			'meta_key' => '_pronamic_gateway_number_days_valid',
141
			'title'    => __( 'Number Days Valid', 'pronamic_ideal' ),
142
			'type'     => 'text',
143
			'default'  => 1825,
144
			'tooltip'  => __( 'Number of days the generated certificate will be valid for, e.g. 1825 days for the maximum duration of 5 years.', 'pronamic_ideal' ),
145
		);
146
147
		// Private Key Password.
148
		$fields[] = array(
149
			'section'  => 'general',
150
			'filter'   => FILTER_SANITIZE_STRING,
151
			'group'    => 'pk-cert',
152
			'meta_key' => '_pronamic_gateway_ideal_private_key_password',
153
			'title'    => __( 'Private Key Password', 'pronamic_ideal' ),
154
			'type'     => 'text',
155
			'classes'  => array( 'regular-text', 'code' ),
156
			'default'  => wp_generate_password(),
157
			'tooltip'  => __( 'A random password which will be used for the generation of the private key and certificate.', 'pronamic_ideal' ),
158
		);
159
160
		// Private Key.
161
		$fields[] = array(
162
			'section'  => 'general',
163
			'filter'   => FILTER_SANITIZE_STRING,
164
			'group'    => 'pk-cert',
165
			'meta_key' => '_pronamic_gateway_ideal_private_key',
166
			'title'    => __( 'Private Key', 'pronamic_ideal' ),
167
			'type'     => 'textarea',
168
			'callback' => array( $this, 'field_private_key' ),
169
			'classes'  => array( 'code' ),
170
			'tooltip'  => __( 'The private key is used for secure communication with the payment provider. If left empty, the private key will be generated using the given private key password.', 'pronamic_ideal' ),
171
		);
172
173
		// Private Certificate.
174
		$fields[] = array(
175
			'section'  => 'general',
176
			'filter'   => FILTER_SANITIZE_STRING,
177
			'group'    => 'pk-cert',
178
			'meta_key' => '_pronamic_gateway_ideal_private_certificate',
179
			'title'    => __( 'Private Certificate', 'pronamic_ideal' ),
180
			'type'     => 'textarea',
181
			'callback' => array( $this, 'field_private_certificate' ),
182
			'classes'  => array( 'code' ),
183
			'tooltip'  => __( 'The certificate is used for secure communication with the payment provider. If left empty, the certificate will be generated using the private key and given organization details.', 'pronamic_ideal' ),
184
		);
185
186
		// Return.
187
		return $fields;
188
	}
189
190
	/**
191
	 * Field security
192
	 *
193
	 * @param array $field Field.
194
	 */
195
	public function field_security( $field ) {
196
		$certificate = get_post_meta( get_the_ID(), '_pronamic_gateway_ideal_private_certificate', true );
0 ignored issues
show
It seems like get_the_ID() can also be of type false; however, parameter $post_id of get_post_meta() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

196
		$certificate = get_post_meta( /** @scrutinizer ignore-type */ get_the_ID(), '_pronamic_gateway_ideal_private_certificate', true );
Loading history...
197
198
		?>
199
		<p>
200
			<?php if ( empty( $certificate ) ) : ?>
201
202
				<span
203
					class="dashicons dashicons-no"></span> <?php esc_html_e( 'The private key and certificate have not yet been configured.', 'pronamic_ideal' ); ?>
204
				<br/>
205
206
				<br/>
207
208
				<?php esc_html_e( 'A private key and certificate are required for communication with the payment provider. Enter the organization details from the iDEAL account below to generate these required files.', 'pronamic_ideal' ); ?>
209
210
			<?php else : ?>
211
212
				<span
213
					class="dashicons dashicons-yes"></span> <?php esc_html_e( 'A private key and certificate have been configured. The certificate must be uploaded to the payment provider dashboard to complete configuration.', 'pronamic_ideal' ); ?>
214
				<br/>
215
216
				<br/>
217
218
				<?php
219
220
				submit_button(
221
					__( 'Download certificate', 'pronamic_ideal' ),
222
					'secondary',
223
					'download_private_certificate',
224
					false
225
				);
226
227
				?>
228
229
				<a class="pronamic-pay-btn-link" href="#" id="pk-cert-fields-toggle"><?php esc_html_e( 'Show details…', 'pronamic_ideal' ); ?></a>
230
231
			<?php endif; ?>
232
		</p>
233
		<?php
234
	}
235
236
	/**
237
	 * Field private key.
238
	 *
239
	 * @param array $field Field.
240
	 */
241
	public function field_private_key( $field ) {
242
		$private_key          = get_post_meta( get_the_ID(), '_pronamic_gateway_ideal_private_key', true );
0 ignored issues
show
It seems like get_the_ID() can also be of type false; however, parameter $post_id of get_post_meta() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

242
		$private_key          = get_post_meta( /** @scrutinizer ignore-type */ get_the_ID(), '_pronamic_gateway_ideal_private_key', true );
Loading history...
243
		$private_key_password = get_post_meta( get_the_ID(), '_pronamic_gateway_ideal_private_key_password', true );
244
		$number_days_valid    = get_post_meta( get_the_ID(), '_pronamic_gateway_number_days_valid', true );
245
246
		$filename = __( 'ideal.key', 'pronamic_ideal' );
247
248
		if ( ! empty( $private_key_password ) && ! empty( $number_days_valid ) ) {
249
			$command = sprintf(
250
				'openssl genrsa -aes128 -out %s -passout pass:%s 2048',
251
				escapeshellarg( $filename ),
252
				escapeshellarg( $private_key_password )
253
			);
254
255
			?>
256
257
			<p><?php esc_html_e( 'OpenSSL command', 'pronamic_ideal' ); ?></p>
258
			<input id="pronamic_ideal_openssl_command_key" name="pronamic_ideal_openssl_command_key" value="<?php echo esc_attr( $command ); ?>" type="text" class="large-text code" readonly="readonly"/>
259
260
			<?php
261
		} else {
262
			printf(
263
				'<p class="pronamic-pay-description description">%s</p>',
264
				esc_html__( 'Leave empty and save the configuration to generate the private key or view the OpenSSL command.', 'pronamic_ideal' )
265
			);
266
		}
267
268
		?>
269
		<p>
270
			<?php
271
272
			if ( ! empty( $private_key ) ) {
273
				submit_button(
274
					__( 'Download', 'pronamic_ideal' ),
275
					'secondary',
276
					'download_private_key',
277
					false
278
				);
279
280
				echo ' ';
281
			}
282
283
			printf(
284
				'<label class="pronamic-pay-form-control-file-button button">%s <input type="file" name="%s" /></label>',
285
				esc_html__( 'Upload', 'pronamic_ideal' ),
286
				'_pronamic_gateway_ideal_private_key_file'
287
			);
288
289
			?>
290
		</p>
291
		<?php
292
	}
293
294
	/**
295
	 * Field private certificate.
296
	 *
297
	 * @param array $field Field.
298
	 */
299
	public function field_private_certificate( $field ) {
300
		$certificate = get_post_meta( get_the_ID(), '_pronamic_gateway_ideal_private_certificate', true );
0 ignored issues
show
It seems like get_the_ID() can also be of type false; however, parameter $post_id of get_post_meta() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

300
		$certificate = get_post_meta( /** @scrutinizer ignore-type */ get_the_ID(), '_pronamic_gateway_ideal_private_certificate', true );
Loading history...
301
302
		$private_key_password = get_post_meta( get_the_ID(), '_pronamic_gateway_ideal_private_key_password', true );
303
		$number_days_valid    = get_post_meta( get_the_ID(), '_pronamic_gateway_number_days_valid', true );
304
305
		$filename_key = __( 'ideal.key', 'pronamic_ideal' );
306
		$filename_cer = __( 'ideal.cer', 'pronamic_ideal' );
307
308
		// @link http://www.openssl.org/docs/apps/req.html
309
		$subj_args = array(
310
			'C'            => get_post_meta( get_the_ID(), '_pronamic_gateway_country', true ),
311
			'ST'           => get_post_meta( get_the_ID(), '_pronamic_gateway_state_or_province', true ),
312
			'L'            => get_post_meta( get_the_ID(), '_pronamic_gateway_locality', true ),
313
			'O'            => get_post_meta( get_the_ID(), '_pronamic_gateway_organization', true ),
314
			'OU'           => get_post_meta( get_the_ID(), '_pronamic_gateway_organization_unit', true ),
315
			'CN'           => get_post_meta( get_the_ID(), '_pronamic_gateway_organization', true ),
316
			'emailAddress' => get_post_meta( get_the_ID(), '_pronamic_gateway_email', true ),
317
		);
318
319
		$subj_args = array_filter( $subj_args );
320
321
		$subj = '';
322
		foreach ( $subj_args as $type => $value ) {
323
			$subj .= '/' . $type . '=' . addslashes( $value );
324
		}
325
326
		if ( ! empty( $subj ) ) {
327
			$command = trim(
328
				sprintf(
329
					'openssl req -x509 -sha256 -new -key %s -passin pass:%s -days %s -out %s %s',
330
					escapeshellarg( $filename_key ),
331
					escapeshellarg( $private_key_password ),
0 ignored issues
show
It seems like $private_key_password can also be of type false; however, parameter $arg of escapeshellarg() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

331
					escapeshellarg( /** @scrutinizer ignore-type */ $private_key_password ),
Loading history...
332
					escapeshellarg( $number_days_valid ),
333
					escapeshellarg( $filename_cer ),
334
					empty( $subj ) ? '' : sprintf( '-subj %s', escapeshellarg( $subj ) )
335
				)
336
			);
337
338
			?>
339
340
			<p><?php esc_html_e( 'OpenSSL command', 'pronamic_ideal' ); ?></p>
341
			<input id="pronamic_ideal_openssl_command_certificate" name="pronamic_ideal_openssl_command_certificate" value="<?php echo esc_attr( $command ); ?>" type="text" class="large-text code" readonly="readonly"/>
342
343
			<?php
344
		} else {
345
			printf(
346
				'<p class="pronamic-pay-description description">%s</p>',
347
				esc_html__( 'Leave empty and save the configuration to generate the certificate or view the OpenSSL command.', 'pronamic_ideal' )
348
			);
349
		}
350
351
		if ( ! empty( $certificate ) ) {
352
			$fingerprint = Security::get_sha_fingerprint( $certificate );
353
			$fingerprint = str_split( $fingerprint, 2 );
354
			$fingerprint = implode( ':', $fingerprint );
355
356
			echo '<dl>';
357
358
			echo '<dt>', esc_html__( 'SHA Fingerprint', 'pronamic_ideal' ), '</dt>';
359
			echo '<dd>', esc_html( $fingerprint ), '</dd>';
360
361
			$info = openssl_x509_parse( $certificate );
362
363
			if ( $info ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $info of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
364
				$date_format = __( 'M j, Y @ G:i', 'pronamic_ideal' );
365
366
				if ( isset( $info['validFrom_time_t'] ) ) {
367
					echo '<dt>', esc_html__( 'Valid From', 'pronamic_ideal' ), '</dt>';
368
					echo '<dd>', esc_html( date_i18n( $date_format, $info['validFrom_time_t'] ) ), '</dd>';
369
				}
370
371
				if ( isset( $info['validTo_time_t'] ) ) {
372
					echo '<dt>', esc_html__( 'Valid To', 'pronamic_ideal' ), '</dt>';
373
					echo '<dd>', esc_html( date_i18n( $date_format, $info['validTo_time_t'] ) ), '</dd>';
374
				}
375
			}
376
377
			echo '</dl>';
378
		}
379
380
		?>
381
		<p>
382
			<?php
383
384
			if ( ! empty( $certificate ) ) {
385
				submit_button(
386
					__( 'Download', 'pronamic_ideal' ),
387
					'secondary',
388
					'download_private_certificate',
389
					false
390
				);
391
392
				echo ' ';
393
			}
394
395
			printf(
396
				'<label class="pronamic-pay-form-control-file-button button">%s <input type="file" name="%s" /></label>',
397
				esc_html__( 'Upload', 'pronamic_ideal' ),
398
				'_pronamic_gateway_ideal_private_certificate_file'
399
			);
400
401
			?>
402
		</p>
403
		<?php
404
	}
405
406
	/**
407
	 * Download private certificate
408
	 */
409
	public function maybe_download_private_certificate() {
410
		if ( filter_has_var( INPUT_POST, 'download_private_certificate' ) ) {
411
			$post_id = filter_input( INPUT_POST, 'post_ID', FILTER_SANITIZE_STRING );
412
413
			$filename = sprintf( 'ideal-private-certificate-%s.cer', $post_id );
414
415
			header( 'Content-Description: File Transfer' );
416
			header( 'Content-Disposition: attachment; filename=' . $filename );
417
			header( 'Content-Type: application/x-x509-ca-cert; charset=' . get_option( 'blog_charset' ), true );
0 ignored issues
show
Are you sure get_option('blog_charset') of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

417
			header( 'Content-Type: application/x-x509-ca-cert; charset=' . /** @scrutinizer ignore-type */ get_option( 'blog_charset' ), true );
Loading history...
418
419
			echo get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true ); // xss ok.
0 ignored issues
show
Are you sure get_post_meta($post_id, ...ate_certificate', true) of type false|mixed|string can be used in echo? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

419
			echo /** @scrutinizer ignore-type */ get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true ); // xss ok.
Loading history...
420
421
			exit;
422
		}
423
	}
424
425
	/**
426
	 * Download private key
427
	 */
428
	public function maybe_download_private_key() {
429
		if ( filter_has_var( INPUT_POST, 'download_private_key' ) ) {
430
			$post_id = filter_input( INPUT_POST, 'post_ID', FILTER_SANITIZE_STRING );
431
432
			$filename = sprintf( 'ideal-private-key-%s.key', $post_id );
433
434
			header( 'Content-Description: File Transfer' );
435
			header( 'Content-Disposition: attachment; filename=' . $filename );
436
			header( 'Content-Type: application/pgp-keys; charset=' . get_option( 'blog_charset' ), true );
0 ignored issues
show
Are you sure get_option('blog_charset') of type false|mixed can be used in concatenation? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

436
			header( 'Content-Type: application/pgp-keys; charset=' . /** @scrutinizer ignore-type */ get_option( 'blog_charset' ), true );
Loading history...
437
438
			echo get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key', true ); // xss ok.
0 ignored issues
show
Are you sure get_post_meta($post_id, ...eal_private_key', true) of type false|mixed|string can be used in echo? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

438
			echo /** @scrutinizer ignore-type */ get_post_meta( $post_id, '_pronamic_gateway_ideal_private_key', true ); // xss ok.
Loading history...
439
440
			exit;
441
		}
442
	}
443
444
	/**
445
	 * Save post.
446
	 *
447
	 * @param array $data Data.
448
	 */
449
	public function save_post( $data ) {
450
		// Files.
451
		$files = array(
452
			'_pronamic_gateway_ideal_private_key_file' => '_pronamic_gateway_ideal_private_key',
453
			'_pronamic_gateway_ideal_private_certificate_file' => '_pronamic_gateway_ideal_private_certificate',
454
		);
455
456
		foreach ( $files as $name => $meta_key ) {
457
			if ( isset( $_FILES[ $name ] ) && UPLOAD_ERR_OK === $_FILES[ $name ]['error'] ) { // WPCS: input var okay.
458
				$value = file_get_contents( $_FILES[ $name ]['tmp_name'] ); // WPCS: input var okay. // WPCS: sanitization ok.
459
460
				$data[ $meta_key ] = $value;
461
			}
462
		}
463
464
		// Generate private key and certificate.
465
		if ( empty( $data['_pronamic_gateway_ideal_private_key_password'] ) ) {
466
			// Without private key password we can't create private key and certifiate.
467
			return $data;
468
		}
469
470
		if ( ! in_array( 'aes-128-cbc', openssl_get_cipher_methods(), true ) ) {
471
			// Without AES-128-CBC ciphter method we can't create private key and certificate.
472
			return $data;
473
		}
474
475
		// Private key.
476
		$pkey = openssl_pkey_get_private( $data['_pronamic_gateway_ideal_private_key'], $data['_pronamic_gateway_ideal_private_key_password'] );
477
478
		if ( false === $pkey ) {
479
			// If we can't open the private key we will create a new private key and certificate.
480
			if ( defined( 'OPENSSL_CIPHER_AES_128_CBC' ) ) {
481
				$cipher = OPENSSL_CIPHER_AES_128_CBC;
482
			} elseif ( defined( 'OPENSSL_CIPHER_3DES' ) ) {
483
				// @link https://www.pronamic.nl/wp-content/uploads/2011/12/iDEAL_Advanced_PHP_EN_V2.2.pdf
484
				$cipher = OPENSSL_CIPHER_3DES;
485
			} else {
486
				// Unable to create private key without cipher.
487
				return $data;
488
			}
489
490
			$args = array(
491
				'digest_alg'             => 'SHA256',
492
				'private_key_bits'       => 2048,
493
				'private_key_type'       => OPENSSL_KEYTYPE_RSA,
494
				'encrypt_key'            => true,
495
				'encrypt_key_cipher'     => $cipher,
496
				'subjectKeyIdentifier'   => 'hash',
497
				'authorityKeyIdentifier' => 'keyid:always,issuer:always',
498
				'basicConstraints'       => 'CA:true',
499
			);
500
501
			$pkey = openssl_pkey_new( $args );
502
503
			if ( false === $pkey ) {
504
				return $data;
505
			}
506
507
			// Export key.
508
			$result = openssl_pkey_export( $pkey, $private_key, $data['_pronamic_gateway_ideal_private_key_password'], $args );
509
510
			if ( false === $result ) {
511
				return $data;
512
			}
513
514
			$data['_pronamic_gateway_ideal_private_key'] = $private_key;
515
			// Delete private certificate since this is no longer valid.
516
			$data['_pronamic_gateway_ideal_private_certificate'] = null;
517
		}
518
519
		// Certificate.
520
		if ( empty( $data['_pronamic_gateway_ideal_private_certificate'] ) ) {
521
			$required_keys = array(
522
				'countryName',
523
				'stateOrProvinceName',
524
				'localityName',
525
				'organizationName',
526
				'commonName',
527
				'emailAddress',
528
			);
529
530
			$distinguished_name = array(
531
				'countryName'            => $data['_pronamic_gateway_country'],
532
				'stateOrProvinceName'    => $data['_pronamic_gateway_state_or_province'],
533
				'localityName'           => $data['_pronamic_gateway_locality'],
534
				'organizationName'       => $data['_pronamic_gateway_organization'],
535
				'organizationalUnitName' => $data['_pronamic_gateway_organization_unit'],
536
				'commonName'             => $data['_pronamic_gateway_organization'],
537
				'emailAddress'           => $data['_pronamic_gateway_email'],
538
			);
539
540
			$distinguished_name = array_filter( $distinguished_name );
541
542
			/*
543
			 * Create certificate only if distinguished name contains all required elements
544
			 *
545
			 * @link http://stackoverflow.com/questions/13169588/how-to-check-if-multiple-array-keys-exists
546
			 */
547
			if ( count( array_intersect_key( array_flip( $required_keys ), $distinguished_name ) ) === count( $required_keys ) ) {
548
				$csr = openssl_csr_new( $distinguished_name, $pkey );
549
550
				$cert = openssl_csr_sign( $csr, null, $pkey, $data['_pronamic_gateway_number_days_valid'], $args, time() );
551
552
				openssl_x509_export( $cert, $certificate );
553
554
				$data['_pronamic_gateway_ideal_private_certificate'] = $certificate;
555
			}
556
		}
557
558
		return $data;
559
	}
560
}
561