[[PageOutline]]
= Proof of Account Ownership =
Provides a proof of project account ownership for users of a BOINC project using public key cryptography (SHA512 signature).
The user enters a message which is signed alongside their account ID using the project's private key, providing a standardized proof of account ownership to external systems.
This is an optional extension to the BOINC web server.
== User guide ==
=== Instructions ===
1. Login then navigate to the 'Proof of Account Ownership' page (usually on the "Your Account" page).
1. Enter the message you wish to be signed (typically supplied by the website that wants you to provide the proof of ownership).
1. Submit the form.
1. When successful the ownership proof will be shown on the website, copy and use the full contents to proof ownership of your account.
=== Example XML output ===
{{{
http://domain.tld/project_name/
1 Enter text
BASE64_SIGNED_MSG
}}}
== Project administrator guide ==
=== Changes to web server ===
See modifications introduced by [https://github.com/BOINC/boinc/pull/2965 PR#2965] if you want to cherry-pick the commits.
{{{
html/inc/util.inc - fixing ttok warnings
html/user/get_project_config.php - export public key safely
html/inc/user.inc - add link to account ownership form within the profile
html/user/account_ownership_action.php - new file
html/user/account_ownership_form.php - new file
}}}
=== Changes required to integrate this functionality: ===
1. Have a recent version of OpenSSL installed on your BOINC webserver that is used by PHP.
1. Install the latest BOINC [https://github.com/BOINC/boinc/pull/2965 PR#2965] web server changes
1. (optional) Configure reCAPTCHA in your `config.xml` so the form is protected.
1. Generate necessary OpenSSL keys in the /project_root/keys/ folder:
{{{
openssl genpkey -algorithm RSA -out ownership_sign_private.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -pubout -in ownership_sign_private.pem -out ownership_sign_public.pem
}}}
5. Adjust key permissions:
{{{
chown -R boincadm:boincadm ownership_sign_p*
chmod --reference upload_private ownership_sign_public.pem
chmod --reference upload_private ownership_sign_private.pem
}}}
6. Try the form, sign a message, attempt to verify the message using your public key and the decoded base64 message from the form.
=== Security ===
The private key needs to remain on the web server, however if this key is compromised then proof of account ownership could be forged. It's important to maintain an updated and secure BOINC project webserver to reduce the risk of this happening.
If you believe that the private key has been compromised, simply generate a new key pair to start from scratch, users will need to regenerate their signed messages to maintain a current proof of account ownership on external systems. In that case you might want to create a news item to inform users.
== External systems guide ==
=== Verifying signed messages ===
The content of the `signature` tag is a base64 encoded SHA512 signature of the content of the `msg` tag. See [https://boinc.berkeley.edu/trac/wiki/ProofOfOwnership#ExampleXMLoutput Example XML output] section above. Basically everything you need to verify the signature is in the XML snippet. You can use the `` to get the public key, which is published in the XML output from `get_project_config.php`.
The following scripts and procedures are just examples. You should create your own process on how the user needs to supply the generated XML snippet to you and how you do the verification. Also keep in mind that the structure of the snippet might be modified in the future and might differ slightly between projects.
=== Pre-requisites ===
Follow the above user guide with a project that has this feature enabled, copy the output XML text snippet and save to 'xml_data.xml'.
Extract the PUBLIC_KEY_VALUE from the XML output produced by '/get_project_config.php' into a file called 'ownership_sign_public.pem'. Don't include the 'ownership_signature_public_key' tags in the file, don't include trailing return/newline characters in the text file.
{{{
PUBLIC_KEY_VALUE
}}}
=== Python verification script ===
The below script takes the public key and the saved xml file and prints whether it's valid or not. Requires the following python modules: pycryptodome, base64, xmltodict
{{{
from Crypto.PublicKey import RSA # package: pycryptodome
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA512
from base64 import b64decode
import xmltodict # For handling XML data
with open('xml_data.xml') as fd: # Entire output XML snippet
boinc_xml_data = xmltodict.parse(fd.read())
with open('ownership_sign_public.pem') as f: # public key *.pem file
public_key_data = f.read()
message = boinc_xml_data['account_ownership_verification']['msg']
signature = boinc_xml_data['account_ownership_verification']['signature']
rsakey = RSA.importKey(public_key_data)
verifier = PKCS1_v1_5.new(rsakey)
digest = SHA512.new()
digest.update(bytes(message, encoding = "utf8"))
if verifier.verify(digest, b64decode(signature)):
print("Successfully verified Account Ownership.")
else:
print("Failed to verify UserID ownership.")
}}}
=== Linux command line ===
Create the following bash script with filename 'verify.sh'.
{{{
#!/bin/bash
SIG=$(sed -n 's/\(.*\)<\/signature>/\1/p' xml_data.xml)
MSG=$(sed -n 's/\(.*\)<\/msg>/\1/p' xml_data.xml)
echo -n $SIG > signature.txt
echo -n $MSG > msg.txt
base64 -d signature.txt > decoded_signature.txt
openssl dgst -sha512 -verify ownership_sign_public.pem -signature decoded_signature.txt msg.txt
}}}
Enable it to be executable then run the script
{{{
chmod +x verify.sh
./verify.sh
}}}
Expected successful output:
{{{
Verified OK
}}}