Skip to content
This repository was archived by the owner on Feb 28, 2024. It is now read-only.

Commit 0b374b5

Browse files
committed
The certificate and/or key fingerprints are not computed for every request anymore
1 parent 7f7ac4c commit 0b374b5

9 files changed

+112
-136
lines changed

src/Developer/Encryption/FieldLevelEncryption.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,10 +117,10 @@ private static function encryptPayloadPath($payloadJsonObject, $jsonPathIn, $jso
117117
$outJsonObject->{$config->encryptedKeyFieldName} = $params->getEncryptedKeyValue();
118118
}
119119
if (!empty($config->encryptionCertificateFingerprintFieldName)) {
120-
$outJsonObject->{$config->encryptionCertificateFingerprintFieldName} = $params->getEncryptionCertificateFingerprintValue();
120+
$outJsonObject->{$config->encryptionCertificateFingerprintFieldName} = $config->encryptionCertificateFingerprint;
121121
}
122122
if (!empty($config->encryptionKeyFingerprintFieldName)) {
123-
$outJsonObject->{$config->encryptionKeyFingerprintFieldName} = $params->getEncryptionKeyFingerprintValue();
123+
$outJsonObject->{$config->encryptionKeyFingerprintFieldName} = $config->encryptionKeyFingerprint;
124124
}
125125
if (!empty($config->oaepPaddingDigestAlgorithmFieldName)) {
126126
$outJsonObject->{$config->oaepPaddingDigestAlgorithmFieldName} = $params->getOaepPaddingDigestAlgorithmValue();

src/Developer/Encryption/FieldLevelEncryptionConfig.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,12 @@ public function getEncryptionCertificateFingerprintHeaderName() {
158158
public function getEncryptionKeyFingerprintHeaderName() {
159159
return $this->encryptionKeyFingerprintHeaderName;
160160
}
161+
162+
public function getEncryptionCertificateFingerprint() {
163+
return $this->encryptionCertificateFingerprint;
164+
}
165+
166+
public function getEncryptionKeyFingerprint() {
167+
return $this->encryptionKeyFingerprint;
168+
}
161169
}

src/Developer/Encryption/FieldLevelEncryptionConfigBuilder.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
namespace Mastercard\Developer\Encryption;
44

55
use Mastercard\Developer\Json\JsonPath;
6+
use Mastercard\Developer\Utils\EncodingUtils;
7+
use phpseclib\Crypt\Hash;
68

79
/**
810
* A builder class for FieldLevelEncryptionConfig.
@@ -195,13 +197,17 @@ public function withEncryptionKeyFingerprintHeaderName($encryptionKeyFingerprint
195197
/**
196198
* Build a FieldLevelEncryptionConfig.
197199
* @see FieldLevelEncryptionConfig
200+
* @throws EncryptionException, InvalidArgumentException
198201
*/
199202
public function build() {
200203

201204
$this->checkJsonPathParameterValues();
202205
$this->checkParameterValues();
203206
$this->checkParameterConsistency();
204207

208+
$this->computeEncryptionCertificateFingerprintWhenNeeded();
209+
$this->computeEncryptionKeyFingerprintWhenNeeded();
210+
205211
$config = new FieldLevelEncryptionConfig();
206212
$config->encryptionCertificateFingerprintFieldName = $this->encryptionCertificateFingerprintFieldName;
207213
$config->encryptionKeyFingerprintFieldName = $this->encryptionKeyFingerprintFieldName;
@@ -283,4 +289,33 @@ private function checkParameterConsistency () {
283289
throw new \InvalidArgumentException('IV field name and encrypted key field name must be both set or both unset!');
284290
}
285291
}
292+
293+
private function computeEncryptionCertificateFingerprintWhenNeeded() {
294+
$providedEncryptionCertificate = $this->encryptionCertificate;
295+
if (empty($providedEncryptionCertificate) || !empty($this->encryptionCertificateFingerprint)) {
296+
// No encryption certificate set or certificate fingerprint already provided
297+
return;
298+
}
299+
try {
300+
$this->encryptionCertificateFingerprint = openssl_x509_fingerprint($providedEncryptionCertificate, 'sha256');
301+
} catch (\Exception $e) {
302+
throw new EncryptionException('Failed to compute encryption certificate fingerprint!', $e);
303+
}
304+
}
305+
306+
private function computeEncryptionKeyFingerprintWhenNeeded() {
307+
$providedEncryptionCertificate = $this->encryptionCertificate;
308+
if (empty($providedEncryptionCertificate) || !empty($this->encryptionKeyFingerprint)) {
309+
// No encryption certificate set or key fingerprint already provided
310+
return;
311+
}
312+
try {
313+
$publicKeyPem = openssl_pkey_get_details(openssl_pkey_get_public($providedEncryptionCertificate))['key'];
314+
$publicKeyDer = EncodingUtils::pemToDer($publicKeyPem, '-----BEGIN PUBLIC KEY-----', '-----END PUBLIC KEY-----');
315+
$hash = new Hash('sha256');
316+
$this->encryptionKeyFingerprint = EncodingUtils::encodeBytes($hash->hash($publicKeyDer), FieldValueEncoding::HEX);
317+
} catch (\Exception $e) {
318+
throw new EncryptionException('Failed to compute encryption key fingerprint!', $e);
319+
}
320+
}
286321
}

src/Developer/Encryption/FieldLevelEncryptionParams.php

Lines changed: 3 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
namespace Mastercard\Developer\Encryption;
44
use Mastercard\Developer\Utils\EncodingUtils;
5-
use phpseclib\Crypt\Hash;
65
use phpseclib\Crypt\RSA;
76

87
/**
@@ -17,20 +16,14 @@ class FieldLevelEncryptionParams {
1716
private $ivValue;
1817
private $encryptedKeyValue;
1918
private $oaepPaddingDigestAlgorithmValue;
20-
private $encryptionCertificateFingerprintValue;
21-
private $encryptionKeyFingerprintValue;
2219
private $config;
2320
private $secretKey;
2421
private $iv;
2522

26-
public function __construct($config, $ivValue, $encryptedKeyValue,
27-
$oaepPaddingDigestAlgorithmValue = null, $encryptionCertificateFingerprintValue = null,
28-
$encryptionKeyFingerprintValue = null) {
23+
public function __construct($config, $ivValue, $encryptedKeyValue, $oaepPaddingDigestAlgorithmValue = null) {
2924
$this->ivValue = $ivValue;
3025
$this->encryptedKeyValue = $encryptedKeyValue;
3126
$this->oaepPaddingDigestAlgorithmValue = $oaepPaddingDigestAlgorithmValue;
32-
$this->encryptionCertificateFingerprintValue = $encryptionCertificateFingerprintValue;
33-
$this->encryptionKeyFingerprintValue = $encryptionKeyFingerprintValue;
3427
$this->config = $config;
3528
}
3629

@@ -54,13 +47,10 @@ public static function generate($config) {
5447
$encryptedSecretKeyBytes = self::wrapSecretKey($config, $secretKey);
5548
$encryptedKeyValue = EncodingUtils::encodeBytes($encryptedSecretKeyBytes, $config->fieldValueEncoding);
5649

57-
// Compute fingerprints and OAEP padding digest algorithm
58-
$encryptionCertificateFingerprintValue = self::getOrComputeEncryptionCertificateFingerprint($config);
59-
$encryptionKeyFingerprintValue = self::getOrComputeEncryptionKeyFingerprint($config);
50+
// Compute the OAEP padding digest algorithm
6051
$oaepPaddingDigestAlgorithmValue = str_replace('-', '', $config->oaepPaddingDigestAlgorithm);
6152

62-
$params = new FieldLevelEncryptionParams($config, $ivValue, $encryptedKeyValue, $oaepPaddingDigestAlgorithmValue,
63-
$encryptionCertificateFingerprintValue, $encryptionKeyFingerprintValue);
53+
$params = new FieldLevelEncryptionParams($config, $ivValue, $encryptedKeyValue, $oaepPaddingDigestAlgorithmValue);
6454
$params->secretKey = $secretKey;
6555
$params->iv = $iv;
6656
return $params;
@@ -74,14 +64,6 @@ public function getEncryptedKeyValue() {
7464
return $this->encryptedKeyValue;
7565
}
7666

77-
public function getEncryptionCertificateFingerprintValue() {
78-
return $this->encryptionCertificateFingerprintValue;
79-
}
80-
81-
public function getEncryptionKeyFingerprintValue() {
82-
return $this->encryptionKeyFingerprintValue;
83-
}
84-
8567
public function getOaepPaddingDigestAlgorithmValue() {
8668
return $this->oaepPaddingDigestAlgorithmValue;
8769
}
@@ -171,41 +153,4 @@ private static function toDsigXmlPrivateKey($raw) {
171153
' <D>' . base64_encode($raw['d']) . "</D>\r\n" .
172154
'</RSAKeyValue>';
173155
}
174-
175-
/**
176-
* @throws EncryptionException
177-
*/
178-
private static function getOrComputeEncryptionCertificateFingerprint($config) {
179-
try {
180-
$providedCertificateFingerprintValue = $config->encryptionCertificateFingerprint;
181-
if (!empty($providedCertificateFingerprintValue)) {
182-
return $providedCertificateFingerprintValue;
183-
} else {
184-
$encryptionCertificate = $config->encryptionCertificate;
185-
return openssl_x509_fingerprint($encryptionCertificate, 'sha256');
186-
}
187-
} catch (\Exception $e) {
188-
throw new EncryptionException('Failed to compute encryption certificate fingerprint!', $e);
189-
}
190-
}
191-
192-
/**
193-
* @throws EncryptionException
194-
*/
195-
private static function getOrComputeEncryptionKeyFingerprint($config) {
196-
try {
197-
$providedKeyFingerprintValue = $config->encryptionKeyFingerprint;
198-
if (!empty($providedKeyFingerprintValue)) {
199-
return $providedKeyFingerprintValue;
200-
} else {
201-
$encryptionCertificate = $config->encryptionCertificate;
202-
$publicKeyPem = openssl_pkey_get_details(openssl_pkey_get_public($encryptionCertificate))['key'];
203-
$publicKeyDer = EncodingUtils::pemToDer($publicKeyPem, '-----BEGIN PUBLIC KEY-----', '-----END PUBLIC KEY-----');
204-
$hash = new Hash('sha256');
205-
return EncodingUtils::encodeBytes($hash->hash($publicKeyDer), FieldValueEncoding::HEX);
206-
}
207-
} catch (\Exception $e) {
208-
throw new EncryptionException('Failed to compute encryption key fingerprint!', $e);
209-
}
210-
}
211156
}

src/Developer/Interceptors/PsrHttpMessageEncryptionInterceptor.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ public function interceptRequest(RequestInterface &$request) {
4545
$params = FieldLevelEncryptionParams::generate($this->config);
4646
self::updateHeader($request, $this->config->getIvHeaderName(), $params->getIvValue());
4747
self::updateHeader($request, $this->config->getEncryptedKeyHeaderName(), $params->getEncryptedKeyValue());
48-
self::updateHeader($request, $this->config->getEncryptionCertificateFingerprintHeaderName(), $params->getEncryptionCertificateFingerprintValue());
49-
self::updateHeader($request, $this->config->getEncryptionKeyFingerprintHeaderName(), $params->getEncryptionKeyFingerprintValue());
48+
self::updateHeader($request, $this->config->getEncryptionCertificateFingerprintHeaderName(), $this->config->getEncryptionCertificateFingerprint());
49+
self::updateHeader($request, $this->config->getEncryptionKeyFingerprintHeaderName(), $this->config->getEncryptionKeyFingerprint());
5050
self::updateHeader($request, $this->config->getOaepPaddingDigestAlgorithmHeaderName(), $params->getOaepPaddingDigestAlgorithmValue());
5151
$encryptedPayload = FieldLevelEncryption::encryptPayload($payload, $this->config, $params);
5252
} else {

tests/Developer/Encryption/FieldLevelEncryptionConfigBuilderTest.php

Lines changed: 55 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,61 @@
88

99
class FieldLevelEncryptionConfigBuilderTest extends TestCase {
1010

11+
public function testBuild_Nominal() {
12+
$config = FieldLevelEncryptionConfigBuilder::aFieldLevelEncryptionConfig()
13+
->withEncryptionPath('$.payload', '$.encryptedPayload')
14+
->withEncryptionCertificate(TestUtils::getTestEncryptionCertificate())
15+
->withEncryptionCertificateFingerprint('97A2FFE9F0D48960EF31E87FCD7A55BF7843FB4A9EEEF01BDB6032AD6FEF146B')
16+
->withEncryptionKeyFingerprint('F806B26BC4870E26986C70B6590AF87BAF4C2B56BB50622C51B12212DAFF2810')
17+
->withEncryptionCertificateFingerprintFieldName('publicCertificateFingerprint')
18+
->withEncryptionCertificateFingerprintHeaderName('x-public-certificate-fingerprint')
19+
->withEncryptionKeyFingerprintFieldName('publicKeyFingerprint')
20+
->withEncryptionKeyFingerprintHeaderName('x-public-key-fingerprint')
21+
->withDecryptionPath('$.encryptedPayload', '$.payload')
22+
->withDecryptionKey(TestUtils::getTestDecryptionKey())
23+
->withOaepPaddingDigestAlgorithm('SHA-512')
24+
->withOaepPaddingDigestAlgorithmFieldName('oaepPaddingDigestAlgorithm')
25+
->withOaepPaddingDigestAlgorithmHeaderName('x-oaep-padding-digest-algorithm')
26+
->withEncryptedValueFieldName('encryptedValue')
27+
->withEncryptedKeyFieldName('encryptedKey')
28+
->withEncryptedKeyHeaderName('x-encrypted-key')
29+
->withIvFieldName('iv')
30+
->withIvHeaderName('x-iv')
31+
->withFieldValueEncoding(FieldValueEncoding::BASE64)
32+
->build();
33+
$this->assertNotEmpty($config);
34+
$this->assertEquals(1, sizeof($config->encryptionPaths));
35+
$this->assertNotEmpty($config->encryptionCertificate);
36+
$this->assertEquals('97A2FFE9F0D48960EF31E87FCD7A55BF7843FB4A9EEEF01BDB6032AD6FEF146B', $config->encryptionCertificateFingerprint);
37+
$this->assertEquals('F806B26BC4870E26986C70B6590AF87BAF4C2B56BB50622C51B12212DAFF2810', $config->encryptionKeyFingerprint);
38+
$this->assertEquals('publicCertificateFingerprint', $config->encryptionCertificateFingerprintFieldName);
39+
$this->assertEquals('x-public-certificate-fingerprint', $config->encryptionCertificateFingerprintHeaderName);
40+
$this->assertEquals('publicKeyFingerprint', $config->encryptionKeyFingerprintFieldName);
41+
$this->assertEquals('x-public-key-fingerprint', $config->encryptionKeyFingerprintHeaderName);
42+
$this->assertEquals(1, sizeof($config->decryptionPaths));
43+
$this->assertNotEmpty($config->decryptionKey);
44+
$this->assertEquals('SHA-512', $config->oaepPaddingDigestAlgorithm);
45+
$this->assertEquals('encryptedValue', $config->encryptedValueFieldName);
46+
$this->assertEquals('encryptedKey', $config->encryptedKeyFieldName);
47+
$this->assertEquals('x-encrypted-key', $config->encryptedKeyHeaderName);
48+
$this->assertEquals('iv', $config->ivFieldName);
49+
$this->assertEquals('x-iv', $config->ivHeaderName);
50+
$this->assertEquals('oaepPaddingDigestAlgorithm', $config->oaepPaddingDigestAlgorithmFieldName);
51+
$this->assertEquals('x-oaep-padding-digest-algorithm', $config->oaepPaddingDigestAlgorithmHeaderName);
52+
$this->assertEquals(FieldValueEncoding::BASE64, $config->fieldValueEncoding);
53+
}
54+
55+
public function testBuild_ShouldComputeCertificateAndKeyFingerprints_WhenFingerprintsNotSet() {
56+
$config = TestUtils::getTestFieldLevelEncryptionConfigBuilder()
57+
->withEncryptionCertificateFingerprint(null)
58+
->withEncryptionKeyFingerprint(null)
59+
->withEncryptionCertificate(TestUtils::getTestEncryptionCertificate())
60+
->withDecryptionKey(TestUtils::getTestDecryptionKey())
61+
->build();
62+
$this->assertEquals('761b003c1eade3a5490e5000d37887baa5e6ec0e226c07706e599451fc032a79', $config->encryptionKeyFingerprint);
63+
$this->assertEquals('80810fc13a8319fcf0e2ec322c82a4c304b782cc3ce671176343cfe8160c2279', $config->encryptionCertificateFingerprint);
64+
}
65+
1166
public function testBuild_ShouldThrowInvalidArgumentException_WhenNotDefiniteDecryptionPath() {
1267
$this->expectException(\InvalidArgumentException::class);
1368
$this->expectExceptionMessage('JSON paths for decryption must point to a single item!');
@@ -140,48 +195,4 @@ public function testBuild_ShouldThrowInvalidArgumentException_WhenEncryptedKeyAn
140195
->withFieldValueEncoding(FieldValueEncoding::HEX)
141196
->build();
142197
}
143-
144-
public function testBuild_Nominal() {
145-
$config = FieldLevelEncryptionConfigBuilder::aFieldLevelEncryptionConfig()
146-
->withEncryptionPath('$.payload', '$.encryptedPayload')
147-
->withEncryptionCertificate(TestUtils::getTestEncryptionCertificate())
148-
->withEncryptionCertificateFingerprint('97A2FFE9F0D48960EF31E87FCD7A55BF7843FB4A9EEEF01BDB6032AD6FEF146B')
149-
->withEncryptionKeyFingerprint('F806B26BC4870E26986C70B6590AF87BAF4C2B56BB50622C51B12212DAFF2810')
150-
->withEncryptionCertificateFingerprintFieldName('publicCertificateFingerprint')
151-
->withEncryptionCertificateFingerprintHeaderName('x-public-certificate-fingerprint')
152-
->withEncryptionKeyFingerprintFieldName('publicKeyFingerprint')
153-
->withEncryptionKeyFingerprintHeaderName('x-public-key-fingerprint')
154-
->withDecryptionPath('$.encryptedPayload', '$.payload')
155-
->withDecryptionKey(TestUtils::getTestDecryptionKey())
156-
->withOaepPaddingDigestAlgorithm('SHA-512')
157-
->withOaepPaddingDigestAlgorithmFieldName('oaepPaddingDigestAlgorithm')
158-
->withOaepPaddingDigestAlgorithmHeaderName('x-oaep-padding-digest-algorithm')
159-
->withEncryptedValueFieldName('encryptedValue')
160-
->withEncryptedKeyFieldName('encryptedKey')
161-
->withEncryptedKeyHeaderName('x-encrypted-key')
162-
->withIvFieldName('iv')
163-
->withIvHeaderName('x-iv')
164-
->withFieldValueEncoding(FieldValueEncoding::BASE64)
165-
->build();
166-
$this->assertNotEmpty($config);
167-
$this->assertEquals(1, sizeof($config->encryptionPaths));
168-
$this->assertNotEmpty($config->encryptionCertificate);
169-
$this->assertEquals('97A2FFE9F0D48960EF31E87FCD7A55BF7843FB4A9EEEF01BDB6032AD6FEF146B', $config->encryptionCertificateFingerprint);
170-
$this->assertEquals('F806B26BC4870E26986C70B6590AF87BAF4C2B56BB50622C51B12212DAFF2810', $config->encryptionKeyFingerprint);
171-
$this->assertEquals('publicCertificateFingerprint', $config->encryptionCertificateFingerprintFieldName);
172-
$this->assertEquals('x-public-certificate-fingerprint', $config->encryptionCertificateFingerprintHeaderName);
173-
$this->assertEquals('publicKeyFingerprint', $config->encryptionKeyFingerprintFieldName);
174-
$this->assertEquals('x-public-key-fingerprint', $config->encryptionKeyFingerprintHeaderName);
175-
$this->assertEquals(1, sizeof($config->decryptionPaths));
176-
$this->assertNotEmpty($config->decryptionKey);
177-
$this->assertEquals('SHA-512', $config->oaepPaddingDigestAlgorithm);
178-
$this->assertEquals('encryptedValue', $config->encryptedValueFieldName);
179-
$this->assertEquals('encryptedKey', $config->encryptedKeyFieldName);
180-
$this->assertEquals('x-encrypted-key', $config->encryptedKeyHeaderName);
181-
$this->assertEquals('iv', $config->ivFieldName);
182-
$this->assertEquals('x-iv', $config->ivHeaderName);
183-
$this->assertEquals('oaepPaddingDigestAlgorithm', $config->oaepPaddingDigestAlgorithmFieldName);
184-
$this->assertEquals('x-oaep-padding-digest-algorithm', $config->oaepPaddingDigestAlgorithmHeaderName);
185-
$this->assertEquals(FieldValueEncoding::BASE64, $config->fieldValueEncoding);
186-
}
187198
}

0 commit comments

Comments
 (0)