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

Commit 1a3fb90

Browse files
committed
fixed read-only mode, introduced share-only mode, introduced human-readable public key download 403 response codes on errors
1 parent 592da95 commit 1a3fb90

File tree

13 files changed

+218
-102
lines changed

13 files changed

+218
-102
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
# 0.23b0 (2019-11-14)
2+
3+
* fixed read-only mode and introduced share-only mode
4+
* introduced human-readable page for downloading the public key under `/pub`
5+
* changed the download of the plain public key to `/pub?plain`
6+
* on errors the application now returns `403 Forbidden` response codes instead of `200 OK` response codes
7+
* updated README to reflect the new features
8+
19
# 0.22b0 (2019-11-13)
210

311
* improved URL parsing

README.md

+25-3
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,40 @@ To protect your secret from getting known by the server or an attacker, you can
1212

1313
### Share a Secret
1414

15-
Simply enter your secret on the default page of the Shared-Secrets service. You can decide to password-protect the entered secret before sending it to the server by checking the "Password-protected:" box, entering your password and pressing the "Protect!" button. After that, press the "Share the Secret!" button. The secret will be encrypted and converted into a secret sharing link.
15+
Simply enter your secret on the default page of the Shared-Secrets service. You can decide to password-protect the entered secret before sending it to the server by checking the "Password-protected:" box, entering your password and pressing the "Protect!" button. After that, press the "Share the Secret!" button. The secret will be encrypted and converted into a secret sharing link. In cases where you need the plain secret sharing link to be returned by the web page you can append the GET parameter `?plain` to the URL of the default page.
1616

1717
Secret sharing links can also be created by using a simple POST request:
1818

1919
```
2020
curl -X POST -d "plain&secret=<secret>" https://example.com/
21+
22+
# OR #
23+
24+
curl -X POST -d "secret=<secret>" https://example.com/?plain
2125
```
2226

2327
### Read a Secret
2428

25-
To retrieve the secret, simply open the secret sharing link and press the "Read the Secret!" button. Should your secret be password-protected, check the "Password-protected:" box, enter your password and read your actual secret by pressing the "Unprotect!" button.
29+
To retrieve the secret, simply open the secret sharing link and press the "Read the Secret!" button. Should your secret be password-protected, check the "Password-protected:" box, enter your password and read your actual secret by pressing the "Unprotect!" button. In cases where you need the plain secret to be returned by the web page you can append the GET parameter `?plain` to the secret sharing link **but be aware** that returning the plain secret does not support the Browser-based decryption.
2630

2731
Secrets can also be retrieved using a simple POST request:
2832

2933
```
30-
curl -X POST -d "plain" <secret sharing link>
34+
curl -X POST -d "plain" <secret-sharing-link>
35+
36+
# OR #
37+
38+
curl -X POST <secret-sharing-link>?plain
39+
```
40+
41+
### Download the Public Key
42+
43+
To download the public key of a Shared-Secrets instance in order to manually generate secret sharing links, simply visit the `/pub` page. In cases where you need the plain public key to be returned by the web page you can append the GET parameter `?plain` to the URL.
44+
45+
The public key can also be downloaded using a simple GET request:
46+
47+
```
48+
curl -X GET https://example.com/pub?plain
3149
```
3250

3351
## Installation
@@ -164,6 +182,10 @@ openssl genrsa -out ./rsa.key 2048
164182

165183
Copy the `config/config.php.default` file to `config/config.php` and set the necessary configuration items.
166184

185+
### Read-Only and Share-Only Instances
186+
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.
188+
167189
### TLS Recommendation
168190

169191
It is strongly recommended to use TLS to protect the connection between the server and the clients.

actions/pub.php

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

6-
function get_public_key() {
6+
function get_public_key(&$error) {
77
$result = null;
8+
$error = false;
89

9-
# for shared-secrets we only support encryption with one key
10-
$keys = array_keys(RSA_PRIVATE_KEYS);
11-
$pubkey = open_pubkey(RSA_PRIVATE_KEYS[$keys[count($keys)-1]]);
12-
if (null !== $pubkey) {
13-
try {
14-
$result = get_keypem($pubkey);
15-
} finally {
16-
openssl_pkey_free($pubkey);
10+
# only proceed when the read-only mode is not enabled
11+
if (!READ_ONLY) {
12+
# for shared-secrets we only support encryption with one key
13+
$keys = array_keys(RSA_PRIVATE_KEYS);
14+
$pubkey = open_pubkey(RSA_PRIVATE_KEYS[$keys[count($keys)-1]]);
15+
if (null !== $pubkey) {
16+
try {
17+
$result = get_keypem($pubkey);
18+
} finally {
19+
openssl_pkey_free($pubkey);
20+
}
21+
} else {
22+
if (DEBUG_MODE) {
23+
$error = "Public key could not be read.";
24+
}
1725
}
26+
} else {
27+
$error = "The creation of secret sharing links is disabled.";
28+
}
29+
30+
# set default error if non is given
31+
if ((null === $result) && (false === $error)) {
32+
$error = "An unknown error occured.";
1833
}
1934

2035
return $result;

actions/read.php

+48-43
Original file line numberDiff line numberDiff line change
@@ -7,76 +7,81 @@ function read_secret($secret, &$error = null) {
77
$result = null;
88
$error = false;
99

10-
# handle secret decoding
11-
$secret = parse_secret_url($secret);
10+
# only proceed when the share-only mode is not enabled
11+
if (!SHARE_ONLY) {
12+
# handle secret decoding
13+
$secret = parse_secret_url($secret);
1214

13-
# only proceed when the secret is not empty
14-
if (!empty($secret)) {
15-
$keys = array_keys(RSA_PRIVATE_KEYS);
16-
$recipients = [];
17-
foreach ($keys as $key) {
18-
$privkey = open_privkey(RSA_PRIVATE_KEYS[$key]);
19-
if (null !== $privkey) {
20-
$recipients[] = $privkey;
21-
}
22-
}
23-
24-
try {
25-
$decrypted_secret = decrypt_v01($secret, $recipients, $decrypt_error, $fingerprint);
26-
} finally {
27-
$keys = array_keys($recipients);
15+
# only proceed when the secret is not empty
16+
if (!empty($secret)) {
17+
$keys = array_keys(RSA_PRIVATE_KEYS);
18+
$recipients = [];
2819
foreach ($keys as $key) {
29-
openssl_pkey_free($recipients[$key]);
20+
$privkey = open_privkey(RSA_PRIVATE_KEYS[$key]);
21+
if (null !== $privkey) {
22+
$recipients[] = $privkey;
23+
}
3024
}
3125

32-
zeroize_array($recipients);
33-
}
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+
}
3433

35-
if (null !== $decrypted_secret) {
36-
if ($link = mysqli_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_DB, MYSQL_PORT)) {
37-
try {
38-
if ($statement = mysqli_prepare($link, MYSQL_WRITE)) {
39-
$fingerprint = bin2hex($fingerprint);
34+
zeroize_array($recipients);
35+
}
36+
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);
4042

41-
if (mysqli_stmt_bind_param($statement, "s", $fingerprint)) {
42-
if (mysqli_stmt_execute($statement)) {
43-
if (1 === mysqli_affected_rows($link)) {
44-
$result = $decrypted_secret;
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+
} else {
48+
$error = "Secret has already been retrieved.";
49+
}
4550
} else {
46-
$error = "Secret has already been retrieved.";
51+
if (DEBUG_MODE) {
52+
$error = "Insert statement could not be executed";
53+
}
4754
}
4855
} else {
4956
if (DEBUG_MODE) {
50-
$error = "Insert statement could not be executed";
57+
$error = "Insert statement parameters could not be bound.";
5158
}
5259
}
5360
} else {
5461
if (DEBUG_MODE) {
55-
$error = "Insert statement parameters could not be bound.";
62+
$error = "Insert statement could not be prepared.";
5663
}
5764
}
58-
} else {
59-
if (DEBUG_MODE) {
60-
$error = "Insert statement could not be prepared.";
61-
}
65+
} finally {
66+
mysqli_close($link);
67+
}
68+
} else {
69+
if (DEBUG_MODE) {
70+
$error = "Database connection could not be established.";
6271
}
63-
} finally {
64-
mysqli_close($link);
6572
}
6673
} else {
6774
if (DEBUG_MODE) {
68-
$error = "Database connection could not be established.";
75+
$error = "Decryption failed: $decrypt_error";
6976
}
7077
}
7178
} else {
7279
if (DEBUG_MODE) {
73-
$error = "Decryption failed: $decrypt_error";
80+
$error = "The secret must not be empty.";
7481
}
7582
}
7683
} else {
77-
if (DEBUG_MODE) {
78-
$error = "The secret must not be empty.";
79-
}
84+
$error = "The retrieval of secret sharing links is disabled.";
8085
}
8186

8287
# set default error if non is given

actions/share.php

+32-27
Original file line numberDiff line numberDiff line change
@@ -7,43 +7,48 @@ function share_secret($secret, &$error = null) {
77
$result = null;
88
$error = false;
99

10-
# only proceed when the secret is not empty
11-
if (!empty($secret)) {
12-
# only proceed when the secret is not too long
13-
if (MAX_PARAM_SIZE >= strlen($secret)) {
14-
# for shared-secrets we only support encryption with one key
15-
$keys = array_keys(RSA_PRIVATE_KEYS);
16-
$pubkey = open_pubkey(RSA_PRIVATE_KEYS[$keys[count($keys)-1]]);
17-
if (null !== $pubkey) {
18-
try {
19-
$recipients = [$pubkey];
10+
# only proceed when the read-only mode is not enabled
11+
if (!READ_ONLY) {
12+
# only proceed when the secret is not empty
13+
if (!empty($secret)) {
14+
# only proceed when the secret is not too long
15+
if (MAX_PARAM_SIZE >= strlen($secret)) {
16+
# for shared-secrets we only support encryption with one key
17+
$keys = array_keys(RSA_PRIVATE_KEYS);
18+
$pubkey = open_pubkey(RSA_PRIVATE_KEYS[$keys[count($keys)-1]]);
19+
if (null !== $pubkey) {
2020
try {
21-
$encrypted_secret = encrypt_v01($secret, $recipients, $encrypt_error);
22-
} finally {
23-
zeroize_array($recipients);
24-
}
21+
$recipients = [$pubkey];
22+
try {
23+
$encrypted_secret = encrypt_v01($secret, $recipients, $encrypt_error);
24+
} finally {
25+
zeroize_array($recipients);
26+
}
2527

26-
if (null !== $encrypted_secret) {
27-
# return the secret sharing URL
28-
$result = get_secret_url($encrypted_secret);
29-
} else {
30-
if (DEBUG_MODE) {
31-
$error = "Encryption failed: $encrypt_error";
28+
if (null !== $encrypted_secret) {
29+
# return the secret sharing URL
30+
$result = get_secret_url($encrypted_secret);
31+
} else {
32+
if (DEBUG_MODE) {
33+
$error = "Encryption failed: $encrypt_error";
34+
}
3235
}
36+
} finally {
37+
openssl_pkey_free($pubkey);
38+
}
39+
} else {
40+
if (DEBUG_MODE) {
41+
$error = "Public key could not be read.";
3342
}
34-
} finally {
35-
openssl_pkey_free($pubkey);
3643
}
3744
} else {
38-
if (DEBUG_MODE) {
39-
$error = "Public key could not be read.";
40-
}
45+
$error = "The secret must at most be ".MAX_PARAM_SIZE." characters long.";
4146
}
4247
} else {
43-
$error = "The secret must at most be ".MAX_PARAM_SIZE." characters long.";
48+
$error = "The secret must not be empty.";
4449
}
4550
} else {
46-
$error = "The secret must not be empty.";
51+
$error = "The creation of secret sharing links is disabled.";
4752
}
4853

4954
# set default error if non is given

config/config.php.default

+8-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,13 @@
3333
# this is the default timezone for the execution of the script
3434
define("DEFAULT_TIMEZONE", "Europe/Berlin");
3535

36-
# this enables or disables the read-only mode of the instance
36+
# this enables or disables the read-only mode of the instance,
37+
# by using the read-only mode you need another instance to create secret sharing links,
38+
# this separation can be useful if you only want to be internally able to create links
3739
define("READ_ONLY", false);
3840

41+
# this enables or disables the share-only mode of the instance,
42+
# by using the share-only mode you need another instance to read secret sharing links,
43+
# this separation can be useful if you only want to be internally able to create links
44+
define("SHARE_ONLY", false);
45+

index.php

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

3-
# Shared-Secrets v0.22b0
3+
# Shared-Secrets v0.23b0
44
#
55
# Copyright (c) 2016-2019, SysEleven GmbH
66
# All rights reserved.
@@ -55,6 +55,11 @@
5555
define("READ_ONLY", false);
5656
}
5757

58+
# prepare share-only mode
59+
if (!defined("SHARE_ONLY")) {
60+
define("SHARE_ONLY", false);
61+
}
62+
5863
# prepare request method
5964
define("REQUEST_METHOD", strtolower($_SERVER["REQUEST_METHOD"]));
6065

@@ -72,26 +77,19 @@
7277

7378
# prepare URI
7479
$uri = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH);
75-
# handle URL encoded URIs
7680
if (false !== strpos($uri, URL_ENCODE_MARKER)) {
7781
$uri = urldecode($uri);
7882
}
79-
# remove leading slash
80-
if (0 === stripos($uri, "/")) {
81-
$uri = substr($uri, 1);
82-
}
83-
define("SECRET_URI", $uri);
83+
define("SECRET_URI", nolead($uri, "/"));
8484

8585
# prepare action name, show read page by default
8686
$action = READ_PAGE_NAME;
87-
# show share page if no URI is given
8887
if (empty(SECRET_URI)) {
88+
# show share page if no URI is given
8989
$action = SHARE_PAGE_NAME;
90-
} else {
90+
} elseif (in_array(SECRET_URI, array(HOW_PAGE_NAME, IMPRINT_PAGE_NAME, PUB_PAGE_NAME))) {
9191
# show pages based on page URI
92-
if (in_array(SECRET_URI, array(HOW_PAGE_NAME, IMPRINT_PAGE_NAME, PUB_PAGE_NAME))) {
93-
$action = SECRET_URI;
94-
}
92+
$action = SECRET_URI;
9593
}
9694
define("SECRET_ACTION", $action);
9795

pages/how/get.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
<h3>Get the correct public key.</h3>
2121
<p>First of all you have to retrieve the correct public key to encrypt your secret:<br/>
22-
<pre>wget -O "./secrets.pub" "<?= html(trail(SECRET_SHARING_URL, "/")) ?>pub"</pre></p>
22+
<pre>wget -O "./secrets.pub" "<?= html(trail(SECRET_SHARING_URL, "/")) ?>pub?plain"</pre></p>
2323

2424
<h3>Encrypt the secret you want to share.</h3>
2525
<p>To create a secret sharing link you have to do certain steps that are decribed here:

0 commit comments

Comments
 (0)