Failed Conditions
Push — develop ( c9e451...e08ac3 )
by Remco
03:48
created

src/Integration.php (11 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
		// Actions.
23
		add_action( 'current_screen', array( $this, 'maybe_download_private_certificate' ) );
24
		add_action( 'current_screen', array( $this, 'maybe_download_private_key' ) );
25
	}
26
27
	public function get_config_factory_class() {
28
		return __NAMESPACE__ . '\ConfigFactory';
29
	}
30
31
	public function get_settings_fields() {
32
		$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

32
		/** @scrutinizer ignore-call */ 
33
  $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...
33
34
		/*
35
		 * Private Key and Certificate
36
		 */
37
38
		// Private key and certificate information.
39
		$fields[] = array(
40
			'section'  => 'ideal',
41
			'methods'  => array( 'ideal-advanced-v3' ),
42
			'title'    => __( 'Private key and certificate', 'pronamic_ideal' ),
43
			'type'     => 'description',
44
			'callback' => array( $this, 'field_security' ),
45
		);
46
47
		// Organization.
48
		$fields[] = array(
49
			'filter'   => FILTER_SANITIZE_STRING,
50
			'section'  => 'ideal',
51
			'methods'  => array( 'ideal-advanced-v3' ),
52
			'group'    => 'pk-cert',
53
			'meta_key' => '_pronamic_gateway_organization',
54
			'title'    => __( 'Organization', 'pronamic_ideal' ),
55
			'type'     => 'text',
56
			'tooltip'  => __( 'Organization name, e.g. Pronamic', 'pronamic_ideal' ),
57
		);
58
59
		// Organization Unit.
60
		$fields[] = array(
61
			'filter'   => FILTER_SANITIZE_STRING,
62
			'section'  => 'ideal',
63
			'methods'  => array( 'ideal-advanced-v3' ),
64
			'group'    => 'pk-cert',
65
			'meta_key' => '_pronamic_gateway_organization_unit',
66
			'title'    => __( 'Organization Unit', 'pronamic_ideal' ),
67
			'type'     => 'text',
68
			'tooltip'  => __( 'Organization unit, e.g. Administration', 'pronamic_ideal' ),
69
		);
70
71
		// Locality.
72
		$fields[] = array(
73
			'filter'   => FILTER_SANITIZE_STRING,
74
			'section'  => 'ideal',
75
			'methods'  => array( 'ideal-advanced-v3' ),
76
			'group'    => 'pk-cert',
77
			'meta_key' => '_pronamic_gateway_locality',
78
			'title'    => __( 'City', 'pronamic_ideal' ),
79
			'type'     => 'text',
80
			'tooltip'  => __( 'City, e.g. Amsterdam', 'pronamic_ideal' ),
81
		);
82
83
		// State or Province.
84
		$fields[] = array(
85
			'filter'   => FILTER_SANITIZE_STRING,
86
			'section'  => 'ideal',
87
			'methods'  => array( 'ideal-advanced-v3' ),
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
			'filter'      => FILTER_SANITIZE_STRING,
102
			'section'     => 'ideal',
103
			'methods'     => array( 'ideal-advanced-v3' ),
104
			'group'       => 'pk-cert',
105
			'meta_key'    => '_pronamic_gateway_country',
106
			'title'       => __( 'Country', 'pronamic_ideal' ),
107
			'type'        => 'text',
108
			'tooltip'     => sprintf(
109
				'%s %s (ISO-3166-1 alpha-2)',
110
				__( '2 letter country code, e.g.', 'pronamic_ideal' ),
111
				strtoupper( $locale )
112
			),
113
			'size'        => 2,
114
			'description' => sprintf(
115
				'%s %s',
116
				__( '2 letter country code, e.g.', 'pronamic_ideal' ),
117
				strtoupper( $locale )
118
			),
119
		);
120
121
		// Email Address.
122
		$fields[] = array(
123
			'filter'   => FILTER_SANITIZE_STRING,
124
			'section'  => 'ideal',
125
			'methods'  => array( 'ideal-advanced-v3' ),
126
			'group'    => 'pk-cert',
127
			'meta_key' => '_pronamic_gateway_email',
128
			'title'    => __( 'E-mail address', 'pronamic_ideal' ),
129
			'tooltip'  => sprintf(
130
				/* translators: %s: admin email */
131
				__( 'E-mail address, e.g. %s', 'pronamic_ideal' ),
132
				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

132
				/** @scrutinizer ignore-type */ get_option( 'admin_email' )
Loading history...
133
			),
134
			'type'     => 'text',
135
		);
136
137
		// Number Days Valid.
138
		$fields[] = array(
139
			'filter'   => FILTER_SANITIZE_NUMBER_INT,
140
			'section'  => 'ideal',
141
			'methods'  => array( 'ideal-advanced-v3' ),
142
			'group'    => 'pk-cert',
143
			'meta_key' => '_pronamic_gateway_number_days_valid',
144
			'title'    => __( 'Number Days Valid', 'pronamic_ideal' ),
145
			'type'     => 'text',
146
			'default'  => 1825,
147
			'tooltip'  => __( 'Number of days the generated certificate will be valid for, e.g. 1825 days for the maximum duration of 5 years.', 'pronamic_ideal' ),
148
		);
149
150
		// Private Key Password.
151
		$fields[] = array(
152
			'filter'   => FILTER_SANITIZE_STRING,
153
			'section'  => 'ideal',
154
			'methods'  => array( 'ideal-advanced-v3' ),
155
			'group'    => 'pk-cert',
156
			'meta_key' => '_pronamic_gateway_ideal_private_key_password',
157
			'title'    => __( 'Private Key Password', 'pronamic_ideal' ),
158
			'type'     => 'text',
159
			'classes'  => array( 'regular-text', 'code' ),
160
			'default'  => wp_generate_password(),
161
			'tooltip'  => __( 'A random password which will be used for the generation of the private key and certificate.', 'pronamic_ideal' ),
162
		);
163
164
		// Private Key.
165
		$fields[] = array(
166
			'filter'   => FILTER_SANITIZE_STRING,
167
			'section'  => 'ideal',
168
			'methods'  => array( 'ideal-advanced-v3' ),
169
			'group'    => 'pk-cert',
170
			'meta_key' => '_pronamic_gateway_ideal_private_key',
171
			'title'    => __( 'Private Key', 'pronamic_ideal' ),
172
			'type'     => 'textarea',
173
			'callback' => array( $this, 'field_private_key' ),
174
			'classes'  => array( 'code' ),
175
			'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' ),
176
		);
177
178
		// Private Certificate.
179
		$fields[] = array(
180
			'filter'   => FILTER_SANITIZE_STRING,
181
			'section'  => 'ideal',
182
			'methods'  => array( 'ideal-advanced-v3' ),
183
			'group'    => 'pk-cert',
184
			'meta_key' => '_pronamic_gateway_ideal_private_certificate',
185
			'title'    => __( 'Private Certificate', 'pronamic_ideal' ),
186
			'type'     => 'textarea',
187
			'callback' => array( $this, 'field_private_certificate' ),
188
			'classes'  => array( 'code' ),
189
			'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' ),
190
		);
191
192
		// Transaction feedback.
193
		$fields[] = array(
194
			'section' => 'ideal',
195
			'methods' => array( 'ideal-advanced-v3' ),
196
			'title'   => __( 'Transaction feedback', 'pronamic_ideal' ),
197
			'type'    => 'description',
198
			'html'    => __( 'Payment status updates will be processed without any additional configuration.', 'pronamic_ideal' ),
199
		);
200
201
		// Return.
202
		return $fields;
203
	}
204
205
	/**
206
	 * Field security
207
	 *
208
	 * @param array $field Field.
209
	 */
210
	public function field_security( $field ) {
211
		$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

211
		$certificate = get_post_meta( /** @scrutinizer ignore-type */ get_the_ID(), '_pronamic_gateway_ideal_private_certificate', true );
Loading history...
212
213
		?>
214
		<p>
215
			<?php if ( empty( $certificate ) ) : ?>
216
217
				<span
218
					class="dashicons dashicons-no"></span> <?php esc_html_e( 'The private key and certificate have not yet been configured.', 'pronamic_ideal' ); ?>
219
				<br/>
220
221
				<br/>
222
223
				<?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' ); ?>
224
225
			<?php else : ?>
226
227
				<span
228
					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' ); ?>
229
				<br/>
230
231
				<br/>
232
233
				<?php
234
235
				submit_button(
236
					__( 'Download certificate', 'pronamic_ideal' ),
237
					'secondary',
238
					'download_private_certificate',
239
					false
240
				);
241
242
				?>
243
244
				<a class="pronamic-pay-btn-link" href="#" id="pk-cert-fields-toggle"><?php esc_html_e( 'Show details…', 'pronamic_ideal' ); ?></a>
245
246
			<?php endif; ?>
247
		</p>
248
		<?php
249
	}
250
251
	/**
252
	 * Field private key.
253
	 *
254
	 * @param array $field Field.
255
	 */
256
	public function field_private_key( $field ) {
257
		$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

257
		$private_key          = get_post_meta( /** @scrutinizer ignore-type */ get_the_ID(), '_pronamic_gateway_ideal_private_key', true );
Loading history...
258
		$private_key_password = get_post_meta( get_the_ID(), '_pronamic_gateway_ideal_private_key_password', true );
259
		$number_days_valid    = get_post_meta( get_the_ID(), '_pronamic_gateway_number_days_valid', true );
260
261
		$filename = __( 'ideal.key', 'pronamic_ideal' );
262
263
		if ( ! empty( $private_key_password ) && ! empty( $number_days_valid ) ) {
264
			$command = sprintf(
265
				'openssl genrsa -aes128 -out %s -passout pass:%s 2048',
266
				escapeshellarg( $filename ),
267
				escapeshellarg( $private_key_password )
268
			);
269
270
			?>
271
272
			<p><?php esc_html_e( 'OpenSSL command', 'pronamic_ideal' ); ?></p>
273
			<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"/>
274
275
			<?php
276
		} else {
277
			printf(
278
				'<p class="pronamic-pay-description description">%s</p>',
279
				esc_html__( 'Leave empty and save the configuration to generate the private key or view the OpenSSL command.', 'pronamic_ideal' )
280
			);
281
		}
282
283
		?>
284
		<p>
285
			<?php
286
287
			if ( ! empty( $private_key ) ) {
288
				submit_button(
289
					__( 'Download', 'pronamic_ideal' ),
290
					'secondary',
291
					'download_private_key',
292
					false
293
				);
294
295
				echo ' ';
296
			}
297
298
			printf(
299
				'<label class="pronamic-pay-form-control-file-button button">%s <input type="file" name="%s" /></label>',
300
				esc_html__( 'Upload', 'pronamic_ideal' ),
301
				'_pronamic_gateway_ideal_private_key_file'
302
			);
303
304
			?>
305
		</p>
306
		<?php
307
	}
308
309
	/**
310
	 * Field private certificate.
311
	 *
312
	 * @param array $field Field.
313
	 */
314
	public function field_private_certificate( $field ) {
315
		$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

315
		$certificate = get_post_meta( /** @scrutinizer ignore-type */ get_the_ID(), '_pronamic_gateway_ideal_private_certificate', true );
Loading history...
316
317
		$private_key_password = get_post_meta( get_the_ID(), '_pronamic_gateway_ideal_private_key_password', true );
318
		$number_days_valid    = get_post_meta( get_the_ID(), '_pronamic_gateway_number_days_valid', true );
319
320
		$filename_key = __( 'ideal.key', 'pronamic_ideal' );
321
		$filename_cer = __( 'ideal.cer', 'pronamic_ideal' );
322
323
		// @link http://www.openssl.org/docs/apps/req.html
324
		$subj_args = array(
325
			'C'            => get_post_meta( get_the_ID(), '_pronamic_gateway_country', true ),
326
			'ST'           => get_post_meta( get_the_ID(), '_pronamic_gateway_state_or_province', true ),
327
			'L'            => get_post_meta( get_the_ID(), '_pronamic_gateway_locality', true ),
328
			'O'            => get_post_meta( get_the_ID(), '_pronamic_gateway_organization', true ),
329
			'OU'           => get_post_meta( get_the_ID(), '_pronamic_gateway_organization_unit', true ),
330
			'CN'           => get_post_meta( get_the_ID(), '_pronamic_gateway_organization', true ),
331
			'emailAddress' => get_post_meta( get_the_ID(), '_pronamic_gateway_email', true ),
332
		);
333
334
		$subj_args = array_filter( $subj_args );
335
336
		$subj = '';
337
		foreach ( $subj_args as $type => $value ) {
338
			$subj .= '/' . $type . '=' . addslashes( $value );
339
		}
340
341
		if ( ! empty( $subj ) ) {
342
			$command = trim(
343
				sprintf(
344
					'openssl req -x509 -sha256 -new -key %s -passin pass:%s -days %s -out %s %s',
345
					escapeshellarg( $filename_key ),
346
					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

346
					escapeshellarg( /** @scrutinizer ignore-type */ $private_key_password ),
Loading history...
347
					escapeshellarg( $number_days_valid ),
348
					escapeshellarg( $filename_cer ),
349
					empty( $subj ) ? '' : sprintf( '-subj %s', escapeshellarg( $subj ) )
350
				)
351
			);
352
353
			?>
354
355
			<p><?php esc_html_e( 'OpenSSL command', 'pronamic_ideal' ); ?></p>
356
			<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"/>
357
358
			<?php
359
		} else {
360
			printf(
361
				'<p class="pronamic-pay-description description">%s</p>',
362
				esc_html__( 'Leave empty and save the configuration to generate the certificate or view the OpenSSL command.', 'pronamic_ideal' )
363
			);
364
		}
365
366
		if ( ! empty( $certificate ) ) {
367
			$fingerprint = Security::get_sha_fingerprint( $certificate );
368
			$fingerprint = str_split( $fingerprint, 2 );
369
			$fingerprint = implode( ':', $fingerprint );
370
371
			echo '<dl>';
372
373
			echo '<dt>', esc_html__( 'SHA Fingerprint', 'pronamic_ideal' ), '</dt>';
374
			echo '<dd>', esc_html( $fingerprint ), '</dd>';
375
376
			$info = openssl_x509_parse( $certificate );
377
378
			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...
379
				$date_format = __( 'M j, Y @ G:i', 'pronamic_ideal' );
380
381
				if ( isset( $info['validFrom_time_t'] ) ) {
382
					echo '<dt>', esc_html__( 'Valid From', 'pronamic_ideal' ), '</dt>';
383
					echo '<dd>', esc_html( date_i18n( $date_format, $info['validFrom_time_t'] ) ), '</dd>';
384
				}
385
386
				if ( isset( $info['validTo_time_t'] ) ) {
387
					echo '<dt>', esc_html__( 'Valid To', 'pronamic_ideal' ), '</dt>';
388
					echo '<dd>', esc_html( date_i18n( $date_format, $info['validTo_time_t'] ) ), '</dd>';
389
				}
390
			}
391
392
			echo '</dl>';
393
		}
394
395
		?>
396
		<p>
397
			<?php
398
399
			if ( ! empty( $certificate ) ) {
400
				submit_button(
401
					__( 'Download', 'pronamic_ideal' ),
402
					'secondary',
403
					'download_private_certificate',
404
					false
405
				);
406
407
				echo ' ';
408
			}
409
410
			printf(
411
				'<label class="pronamic-pay-form-control-file-button button">%s <input type="file" name="%s" /></label>',
412
				esc_html__( 'Upload', 'pronamic_ideal' ),
413
				'_pronamic_gateway_ideal_private_certificate_file'
414
			);
415
416
			?>
417
		</p>
418
		<?php
419
	}
420
421
	/**
422
	 * Download private certificate
423
	 */
424
	public function maybe_download_private_certificate() {
425
		if ( filter_has_var( INPUT_POST, 'download_private_certificate' ) ) {
426
			$post_id = filter_input( INPUT_POST, 'post_ID', FILTER_SANITIZE_STRING );
427
428
			$filename = sprintf( 'ideal-private-certificate-%s.cer', $post_id );
429
430
			header( 'Content-Description: File Transfer' );
431
			header( 'Content-Disposition: attachment; filename=' . $filename );
432
			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

432
			header( 'Content-Type: application/x-x509-ca-cert; charset=' . /** @scrutinizer ignore-type */ get_option( 'blog_charset' ), true );
Loading history...
433
434
			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

434
			echo /** @scrutinizer ignore-type */ get_post_meta( $post_id, '_pronamic_gateway_ideal_private_certificate', true ); // xss ok.
Loading history...
435
436
			exit;
437
		}
438
	}
439
440
	/**
441
	 * Download private key
442
	 */
443
	public function maybe_download_private_key() {
444
		if ( filter_has_var( INPUT_POST, 'download_private_key' ) ) {
445
			$post_id = filter_input( INPUT_POST, 'post_ID', FILTER_SANITIZE_STRING );
446
447
			$filename = sprintf( 'ideal-private-key-%s.key', $post_id );
448
449
			header( 'Content-Description: File Transfer' );
450
			header( 'Content-Disposition: attachment; filename=' . $filename );
451
			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

451
			header( 'Content-Type: application/pgp-keys; charset=' . /** @scrutinizer ignore-type */ get_option( 'blog_charset' ), true );
Loading history...
452
453
			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

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