Skip to content
This repository was archived by the owner on Mar 16, 2023. It is now read-only.

Commit 3bc63c9

Browse files
committed
creating secret sharing links and downloading the public key is now possible with only RSA public keys set as RSA_PRIVATE_KEYS
1 parent 1a3fb90 commit 3bc63c9

9 files changed

+110
-44
lines changed

CHANGELOG.md

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# 0.24b0 (2019-11-15)
2+
3+
* introduced helper functions `is_privkey()` and `is_pubkey()`
4+
* as a **share-only** doesn't need the private key, `RSA_PRIVATE_KEYS` can now also old RSA public keys
5+
* creating secret sharing links and downloading the public key now also works when RSA public keys are set as `RSA_PRIVATE_KEYS`
6+
* updated README to reflect the new feature
7+
18
# 0.23b0 (2019-11-14)
29

310
* fixed read-only mode and introduced share-only mode

README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,10 @@ Copy the `config/config.php.default` file to `config/config.php` and set the nec
184184

185185
### Read-Only and Share-Only Instances
186186

187-
The configuration allows you to set your instances into read-only and/or share-only mode. This can be useful if want to use a private **share-only** instance or custom software to create secret sharing sharing links but provide a public **read-only** instance to retrieve the generated secret sharing links.
187+
The configuration allows you to set your instances into read-only and/or share-only mode. This can be useful if want to use a private **share-only** instance or custom software to create secret sharing sharing links but provide a public **read-only** instance to retrieve the generated secret sharing links. There are two more things to consider:
188+
189+
* A **share-only** instance does not need access to the RSA private key as it will not decrypt secret sharing links. Therefore, it is possible to configure the RSA public key of the corresponding **read-only** instance into the `RSA_PRIVATE_KEYS` array of a **share-only** instance.
190+
* The basis for the creation of secret sharing link is the `SECRET_SHARING_URL` configuration value. In order for a **share-only** instance to generate correct secret sharing links you have to set the URL of the corresponding **read-only** instance as the `SECRET_SHARING_URL` configuration value of the **share-only** instance.
188191

189192
### TLS Recommendation
190193

actions/pub.php

+8-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@ function get_public_key(&$error) {
1111
if (!READ_ONLY) {
1212
# for shared-secrets we only support encryption with one key
1313
$keys = array_keys(RSA_PRIVATE_KEYS);
14-
$pubkey = open_pubkey(RSA_PRIVATE_KEYS[$keys[count($keys)-1]]);
14+
$pubkey = null;
15+
if (is_pubkey(RSA_PRIVATE_KEYS[$keys[count($keys)-1]])) {
16+
# open the public key
17+
$pubkey = openssl_pkey_get_public(RSA_PRIVATE_KEYS[$keys[count($keys)-1]]);
18+
} elseif (is_privkey(RSA_PRIVATE_KEYS[$keys[count($keys)-1]])) {
19+
# extract the public key from the private key
20+
$pubkey = open_pubkey(RSA_PRIVATE_KEYS[$keys[count($keys)-1]]);
21+
}
1522
if (null !== $pubkey) {
1623
try {
1724
$result = get_keypem($pubkey);

actions/read.php

+41-32
Original file line numberDiff line numberDiff line change
@@ -17,62 +17,71 @@ function read_secret($secret, &$error = null) {
1717
$keys = array_keys(RSA_PRIVATE_KEYS);
1818
$recipients = [];
1919
foreach ($keys as $key) {
20-
$privkey = open_privkey(RSA_PRIVATE_KEYS[$key]);
21-
if (null !== $privkey) {
22-
$recipients[] = $privkey;
20+
if (is_privkey(RSA_PRIVATE_KEYS[$key])) {
21+
# open the private key
22+
$privkey = open_privkey(RSA_PRIVATE_KEYS[$key]);
23+
if (null !== $privkey) {
24+
$recipients[] = $privkey;
25+
}
2326
}
2427
}
2528

26-
try {
27-
$decrypted_secret = decrypt_v01($secret, $recipients, $decrypt_error, $fingerprint);
28-
} finally {
29-
$keys = array_keys($recipients);
30-
foreach ($keys as $key) {
31-
openssl_pkey_free($recipients[$key]);
32-
}
29+
if (0 < count($recipients)) {
30+
try {
31+
$decrypted_secret = decrypt_v01($secret, $recipients, $decrypt_error, $fingerprint);
32+
} finally {
33+
$keys = array_keys($recipients);
34+
foreach ($keys as $key) {
35+
openssl_pkey_free($recipients[$key]);
36+
}
3337

34-
zeroize_array($recipients);
35-
}
38+
zeroize_array($recipients);
39+
}
3640

37-
if (null !== $decrypted_secret) {
38-
if ($link = mysqli_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB, MYSQL_PORT)) {
39-
try {
40-
if ($statement = mysqli_prepare($link, MYSQL_WRITE)) {
41-
$fingerprint = bin2hex($fingerprint);
41+
if (null !== $decrypted_secret) {
42+
if ($link = mysqli_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB, MYSQL_PORT)) {
43+
try {
44+
if ($statement = mysqli_prepare($link, MYSQL_WRITE)) {
45+
$fingerprint = bin2hex($fingerprint);
4246

43-
if (mysqli_stmt_bind_param($statement, "s", $fingerprint)) {
44-
if (mysqli_stmt_execute($statement)) {
45-
if (1 === mysqli_affected_rows($link)) {
46-
$result = $decrypted_secret;
47+
if (mysqli_stmt_bind_param($statement, "s", $fingerprint)) {
48+
if (mysqli_stmt_execute($statement)) {
49+
if (1 === mysqli_affected_rows($link)) {
50+
$result = $decrypted_secret;
51+
} else {
52+
$error = "Secret has already been retrieved.";
53+
}
4754
} else {
48-
$error = "Secret has already been retrieved.";
55+
if (DEBUG_MODE) {
56+
$error = "Insert statement could not be executed";
57+
}
4958
}
5059
} else {
5160
if (DEBUG_MODE) {
52-
$error = "Insert statement could not be executed";
61+
$error = "Insert statement parameters could not be bound.";
5362
}
5463
}
5564
} else {
5665
if (DEBUG_MODE) {
57-
$error = "Insert statement parameters could not be bound.";
66+
$error = "Insert statement could not be prepared.";
5867
}
5968
}
60-
} else {
61-
if (DEBUG_MODE) {
62-
$error = "Insert statement could not be prepared.";
63-
}
69+
} finally {
70+
mysqli_close($link);
71+
}
72+
} else {
73+
if (DEBUG_MODE) {
74+
$error = "Database connection could not be established.";
6475
}
65-
} finally {
66-
mysqli_close($link);
6776
}
6877
} else {
6978
if (DEBUG_MODE) {
70-
$error = "Database connection could not be established.";
79+
$error = "Decryption failed: $decrypt_error";
7180
}
7281
}
7382
} else {
7483
if (DEBUG_MODE) {
75-
$error = "Decryption failed: $decrypt_error";
84+
$error = "Private key could not be read.";
7685
}
7786
}
7887
} else {

actions/share.php

+8-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,14 @@ function share_secret($secret, &$error = null) {
1515
if (MAX_PARAM_SIZE >= strlen($secret)) {
1616
# for shared-secrets we only support encryption with one key
1717
$keys = array_keys(RSA_PRIVATE_KEYS);
18-
$pubkey = open_pubkey(RSA_PRIVATE_KEYS[$keys[count($keys)-1]]);
18+
$pubkey = null;
19+
if (is_pubkey(RSA_PRIVATE_KEYS[$keys[count($keys)-1]])) {
20+
# open the public key
21+
$pubkey = openssl_pkey_get_public(RSA_PRIVATE_KEYS[$keys[count($keys)-1]]);
22+
} elseif (is_privkey(RSA_PRIVATE_KEYS[$keys[count($keys)-1]])) {
23+
# extract the public key from the private key
24+
$pubkey = open_pubkey(RSA_PRIVATE_KEYS[$keys[count($keys)-1]]);
25+
}
1926
if (null !== $pubkey) {
2027
try {
2128
$recipients = [$pubkey];

config/config.php.default

+6-3
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
# prevent direct access
44
if (!defined("SYS11_SECRETS")) { die(""); }
55

6-
# this is an array containing the supported RSA privated keys for encryption and decryption, the LAST private key
7-
# within the array is used to encrypt new secrets while all private keys are used to decrypt secrets, this allows
8-
# for smooth key rollovers
6+
# this is an array containing the supported RSA privated keys for encryption and decryption, the LAST RSA private key
7+
# within the array is used to encrypt new secrets while all RSA private keys are used to decrypt secrets, this allows
8+
# for smooth key rollovers; for share-only instances it is sufficient to set the RSA public key of the corresponding
9+
# read-only instance here
910
define("RSA_PRIVATE_KEYS", ["-----BEGIN RSA PRIVATE KEY-----\n".
11+
"...\n".
12+
"...\n".
1013
"...\n".
1114
"-----END RSA PRIVATE KEY-----"]);
1215

index.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?php
22

3-
# Shared-Secrets v0.23b0
3+
# Shared-Secrets v0.24b0
44
#
55
# Copyright (c) 2016-2019, SysEleven GmbH
66
# All rights reserved.

lib/shared-secrets.def.php

+4-2
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@
4141
define("OPENSSL_MACMESSAGE", "macmessage");
4242
define("OPENSSL_MESSAGE", "message");
4343
define("OPENSSL_NONCE", "nonce");
44-
define("OPENSSL_PEM_HEAD", "-----BEGIN PUBLIC KEY-----");
45-
define("OPENSSL_PEM_TAIL", "-----END PUBLIC KEY-----");
44+
define("OPENSSL_PEM_HEAD_PRIV", "-----BEGIN RSA PRIVATE KEY-----");
45+
define("OPENSSL_PEM_TAIL_PRIV", "-----END RSA PRIVATE KEY-----");
46+
define("OPENSSL_PEM_HEAD_PUB", "-----BEGIN PUBLIC KEY-----");
47+
define("OPENSSL_PEM_TAIL_PUB", "-----END PUBLIC KEY-----");
4648
define("OPENSSL_RSAKEYCOUNT", "rsakeycount");
4749
define("OPENSSL_RSAKEYIDS", "rsakeyids");
4850
define("OPENSSL_RSAKEYLENGTHS", "rsakeylengths");

lib/shared-secrets.exec.php

+31-3
Original file line numberDiff line numberDiff line change
@@ -457,14 +457,42 @@ function encrypt_v01($message, $recipients, &$error = null) {
457457
return $result;
458458
}
459459

460+
function is_privkey($string) {
461+
$result = false;
462+
463+
if (is_string($string)) {
464+
// cleanup
465+
$string = trim($string);
466+
467+
$result = ((0 === strcasecmp(OPENSSL_PEM_HEAD_PRIV, substr($string, 0, strlen(OPENSSL_PEM_HEAD_PRIV)))) &&
468+
(0 === strcasecmp(OPENSSL_PEM_TAIL_PRIV, substr($string, -strlen(OPENSSL_PEM_TAIL_PRIV)))));
469+
}
470+
471+
return $result;
472+
}
473+
474+
function is_pubkey($string) {
475+
$result = false;
476+
477+
if (is_string($string)) {
478+
// cleanup
479+
$string = trim($string);
480+
481+
$result = ((0 === strcasecmp(OPENSSL_PEM_HEAD_PUB, substr($string, 0, strlen(OPENSSL_PEM_HEAD_PUB)))) &&
482+
(0 === strcasecmp(OPENSSL_PEM_TAIL_PUB, substr($string, -strlen(OPENSSL_PEM_TAIL_PUB)))));
483+
}
484+
485+
return $result;
486+
}
487+
460488
function get_keyid($key) {
461489
$result = null;
462490

463491
$keypem = get_keypem($key);
464492
if (null !== $keypem) {
465-
if ((OPENSSL_PEM_HEAD === substr($keypem, 0, strlen(OPENSSL_PEM_HEAD))) &&
466-
(OPENSSL_PEM_TAIL === substr($keypem, -strlen(OPENSSL_PEM_TAIL)))) {
467-
$keyid = str_replace(["\n", "\r"], "", substr($keypem, strlen(OPENSSL_PEM_HEAD), -strlen(OPENSSL_PEM_TAIL)));
493+
if (is_pubkey($keypem)) {
494+
$keyid = str_replace(["\n", "\r"], "",
495+
substr($keypem, strlen(OPENSSL_PEM_HEAD_PUB), -strlen(OPENSSL_PEM_TAIL_PUB)));
468496
$keyid = base64_decode($keyid, true);
469497
if (false !== $keyid) {
470498
$result = hash("sha256", $keyid, true);

0 commit comments

Comments
 (0)