OPENSSL_KEYTYPE_RSA, 'private_key_bits' => 2048, ) ); if ( false === $pkey ) { return new \WP_Error( 'esipher_keystore_keygen', __( 'Could not generate the signing key.', 'esipher' ) ); } $dn = array( 'organizationName' => 'Esipher', 'commonName' => self::sanitize_dn( $common_name ), ); $csr = openssl_csr_new( $dn, $pkey, array( 'digest_alg' => 'sha256' ) ); if ( false === $csr ) { return new \WP_Error( 'esipher_keystore_csr', __( 'Could not prepare the signing certificate.', 'esipher' ) ); } // Play requires a validity well beyond any realistic app lifetime // (its own guidance is "at least until 2033" / 25+ years). 10000 // days ≈ 27 years, and openssl_csr_sign takes days. $cert = openssl_csr_sign( $csr, null, $pkey, 10000, array( 'digest_alg' => 'sha256' ) ); if ( false === $cert ) { return new \WP_Error( 'esipher_keystore_sign', __( 'Could not self-sign the signing certificate.', 'esipher' ) ); } $p12 = ''; $ok = openssl_pkcs12_export( $cert, $p12, $pkey, $password, array( 'friendly_name' => self::ALIAS ) ); if ( ! $ok || '' === $p12 ) { return new \WP_Error( 'esipher_keystore_export', __( 'Could not package the Android keystore.', 'esipher' ) ); } $fingerprint = openssl_x509_fingerprint( $cert, 'sha256' ); return array( 'p12_base64' => base64_encode( $p12 ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- transporting a binary keystore as text. 'fingerprint_sha256' => $fingerprint ? self::colonize( $fingerprint ) : '', 'alias' => self::ALIAS, ); } /** * @param string $name * * @return string A non-empty, comma/plus-free CN of at most 64 chars. */ private static function sanitize_dn( $name ) { $name = trim( preg_replace( '/[,+"\\\\<>;=\r\n]+/', ' ', (string) $name ) ); $name = '' !== $name ? $name : 'Esipher App'; return function_exists( 'mb_substr' ) ? mb_substr( $name, 0, 64 ) : substr( $name, 0, 64 ); } /** * "aabbcc" -> "AA:BB:CC" for display. * * @param string $hex * * @return string */ private static function colonize( $hex ) { return implode( ':', str_split( strtoupper( $hex ), 2 ) ); } }