Failed Conditions
Push — develop ( 5c5209...c9e451 )
by Remco
03:27
created

src/Integration.php (10 issues)

1
<?php
2
3
namespace Pronamic\WordPress\Pay\Gateways\IDealAdvancedV3;
4
5
/**
6
 * Title: iDEAL Advanced v3 integration
7
 * Description:
8
 * Copyright: 2005-2019 Pronamic
9
 * Company: Pronamic
10
 *
11
 * @author  Remco Tolsma
12
 * @version 2.0.0
13
 * @since   2.0.0
14
 */
15
class Integration extends AbstractIntegration {
16
	/**
17
	 * Settings constructor.
18
	 */
19
	public function __construct() {
20
		// Actions.
21
		add_action( 'current_screen', array( $this, 'maybe_download_private_certificate' ) );
22
		add_action( 'current_screen', array( $this, 'maybe_download_private_key' ) );
23
	}
24
25
26
	public function get_settings_fields() {
27
		$fields = array();
28
29
		/*
30
		 * Private Key and Certificate
31
		 */
32
33
		// Private key and certificate information.
34
		$fields[] = array(
35
			'section'  => 'ideal',
36
			'methods'  => array( 'ideal-advanced-v3' ),
37
			'title'    => __( 'Private key and certificate', 'pronamic_ideal' ),
38
			'type'     => 'description',
39
			'callback' => array( $this, 'field_security' ),
40
		);
41
42
		// Organization.
43
		$fields[] = array(
44
			'filter'   => FILTER_SANITIZE_STRING,
45
			'section'  => 'ideal',
46
			'methods'  => array( 'ideal-advanced-v3' ),
47
			'group'    => 'pk-cert',
48
			'meta_key' => '_pronamic_gateway_organization',
49
			'title'    => __( 'Organization', 'pronamic_ideal' ),
50
			'type'     => 'text',
51
			'tooltip'  => __( 'Organization name, e.g. Pronamic', 'pronamic_ideal' ),
52
		);
53
54
		// Organization Unit.
55
		$fields[] = array(
56
			'filter'   => FILTER_SANITIZE_STRING,
57
			'section'  => 'ideal',
58
			'methods'  => array( 'ideal-advanced-v3' ),
59
			'group'    => 'pk-cert',
60
			'meta_key' => '_pronamic_gateway_organization_unit',
61
			'title'    => __( 'Organization Unit', 'pronamic_ideal' ),
62
			'type'     => 'text',
63
			'tooltip'  => __( 'Organization unit, e.g. Administration', 'pronamic_ideal' ),
64
		);
65
66
		// Locality.
67
		$fields[] = array(
68
			'filter'   => FILTER_SANITIZE_STRING,
69
			'section'  => 'ideal',
70
			'methods'  => array( 'ideal-advanced-v3' ),
71
			'group'    => 'pk-cert',
72
			'meta_key' => '_pronamic_gateway_locality',
73
			'title'    => __( 'City', 'pronamic_ideal' ),
74
			'type'     => 'text',
75
			'tooltip'  => __( 'City, e.g. Amsterdam', 'pronamic_ideal' ),
76
		);
77
78
		// State or Province.
79
		$fields[] = array(
80
			'filter'   => FILTER_SANITIZE_STRING,
81
			'section'  => 'ideal',
82
			'methods'  => array( 'ideal-advanced-v3' ),
83
			'group'    => 'pk-cert',
84
			'meta_key' => '_pronamic_gateway_state_or_province',
85
			'title'    => __( 'State / province', 'pronamic_ideal' ),
86
			'type'     => 'text',
87
			'tooltip'  => __( 'State or province, e.g. Friesland', 'pronamic_ideal' ),
88
		);
89
90
		// Country.
91
		$locale = explode( '_', get_locale() );
92
93
		$locale = array_pop( $locale );
94
95
		$fields[] = array(
96
			'filter'      => FILTER_SANITIZE_STRING,
97
			'section'     => 'ideal',
98
			'methods'     => array( 'ideal-advanced-v3' ),
99
			'group'       => 'pk-cert',
100
			'meta_key'    => '_pronamic_gateway_country',
101
			'title'       => __( 'Country', 'pronamic_ideal' ),
102
			'type'        => 'text',
103
			'tooltip'     => sprintf(
104
				'%s %s (ISO-3166-1 alpha-2)',
105
				__( '2 letter country code, e.g.', 'pronamic_ideal' ),
106
				strtoupper( $locale )
107
			),
108
			'size'        => 2,
109
			'description' => sprintf(
110
				'%s %s',
111
				__( '2 letter country code, e.g.', 'pronamic_ideal' ),
112
				strtoupper( $locale )
113
			),
114
		);
115
116
		// Email Address.
117
		$fields[] = array(
118
			'filter'   => FILTER_SANITIZE_STRING,
119
			'section'  => 'ideal',
120
			'methods'  => array( 'ideal-advanced-v3' ),
121
			'group'    => 'pk-cert',
122
			'meta_key' => '_pronamic_gateway_email',
123
			'title'    => __( 'E-mail address', 'pronamic_ideal' ),
124
			'tooltip'  => sprintf(
125
				/* translators: %s: admin email */
126
				__( 'E-mail address, e.g. %s', 'pronamic_ideal' ),
127
				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

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

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

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

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

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

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

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

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

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