1616
1717class CryptKey
1818{
19+ /** @deprecated left for backward compatibility check */
1920 const RSA_KEY_PATTERN =
2021 '/^(-----BEGIN (RSA )?(PUBLIC|PRIVATE) KEY-----)\R.*(-----END (RSA )?(PUBLIC|PRIVATE) KEY-----)\R?$/s ' ;
2122
23+ private const FILE_PREFIX = 'file:// ' ;
24+
2225 /**
2326 * @var string
2427 */
@@ -36,36 +39,43 @@ class CryptKey
3639 */
3740 public function __construct ($ keyPath , $ passPhrase = null , $ keyPermissionsCheck = true )
3841 {
39- if ($ rsaMatch = \preg_match (static ::RSA_KEY_PATTERN , $ keyPath )) {
40- $ keyPath = $ this ->saveKeyToFile ($ keyPath );
41- } elseif ($ rsaMatch === false ) {
42- throw new \RuntimeException (
43- \sprintf ('PCRE error [%d] encountered during key match attempt ' , \preg_last_error ())
44- );
45- }
42+ $ this ->passPhrase = $ passPhrase ;
4643
47- if (\strpos ($ keyPath , 'file:// ' ) !== 0 ) {
48- $ keyPath = 'file:// ' . $ keyPath ;
49- }
44+ if (\is_file ($ keyPath )) {
45+ if (\strpos ($ keyPath , self ::FILE_PREFIX ) !== 0 ) {
46+ $ keyPath = self ::FILE_PREFIX . $ keyPath ;
47+ }
5048
51- if (!\file_exists ($ keyPath ) || !\is_readable ($ keyPath )) {
52- throw new LogicException (\sprintf ('Key path "%s" does not exist or is not readable ' , $ keyPath ));
49+ if (!\is_readable ($ keyPath )) {
50+ throw new LogicException (\sprintf ('Key path "%s" does not exist or is not readable ' , $ keyPath ));
51+ }
52+ $ isFileKey = true ;
53+ $ contents = \file_get_contents ($ keyPath );
54+ $ this ->keyPath = $ keyPath ;
55+ } else {
56+ $ isFileKey = false ;
57+ $ contents = $ keyPath ;
58+ $ this ->keyPath = $ this ->saveKeyToFile ($ keyPath );
5359 }
5460
5561 if ($ keyPermissionsCheck === true ) {
5662 // Verify the permissions of the key
57- $ keyPathPerms = \decoct (\fileperms ($ keyPath ) & 0777 );
63+ $ keyPathPerms = \decoct (\fileperms ($ this -> keyPath ) & 0777 );
5864 if (\in_array ($ keyPathPerms , ['400 ' , '440 ' , '600 ' , '640 ' , '660 ' ], true ) === false ) {
59- \trigger_error (\sprintf (
60- 'Key file "%s" permissions are not correct, recommend changing to 600 or 660 instead of %s ' ,
61- $ keyPath ,
62- $ keyPathPerms
63- ), E_USER_NOTICE );
65+ \trigger_error (
66+ \sprintf (
67+ 'Key file "%s" permissions are not correct, recommend changing to 600 or 660 instead of %s ' ,
68+ $ this ->keyPath ,
69+ $ keyPathPerms
70+ ),
71+ E_USER_NOTICE
72+ );
6473 }
6574 }
6675
67- $ this ->keyPath = $ keyPath ;
68- $ this ->passPhrase = $ passPhrase ;
76+ if (!$ this ->isValidKey ($ contents , $ this ->passPhrase ?? '' )) {
77+ throw new LogicException ('Unable to read key ' . ($ isFileKey ? " from file $ keyPath " : '' ));
78+ }
6979 }
7080
7181 /**
@@ -81,7 +91,7 @@ private function saveKeyToFile($key)
8191 $ keyPath = $ tmpDir . '/ ' . \sha1 ($ key ) . '.key ' ;
8292
8393 if (\file_exists ($ keyPath )) {
84- return ' file:// ' . $ keyPath ;
94+ return self :: FILE_PREFIX . $ keyPath ;
8595 }
8696
8797 if (\file_put_contents ($ keyPath , $ key ) === false ) {
@@ -96,7 +106,30 @@ private function saveKeyToFile($key)
96106 // @codeCoverageIgnoreEnd
97107 }
98108
99- return 'file:// ' . $ keyPath ;
109+ return self ::FILE_PREFIX . $ keyPath ;
110+ }
111+
112+ /**
113+ * Validate key contents.
114+ *
115+ * @param string $contents
116+ * @param string $passPhrase
117+ *
118+ * @return bool
119+ */
120+ private function isValidKey ($ contents , $ passPhrase )
121+ {
122+ $ pkey = \openssl_pkey_get_private ($ contents , $ passPhrase ) ?: \openssl_pkey_get_public ($ contents );
123+ if ($ pkey === false ) {
124+ return false ;
125+ }
126+ $ details = \openssl_pkey_get_details ($ pkey );
127+
128+ return $ details !== false && \in_array (
129+ $ details ['type ' ] ?? -1 ,
130+ [OPENSSL_KEYTYPE_RSA , OPENSSL_KEYTYPE_EC ],
131+ true
132+ );
100133 }
101134
102135 /**
0 commit comments