Developers and Signers

No action on your part is necessary for Page Integrity to display the SHA-256 checksum hash of your web pages.

Web pages may be signed by developers, or third-party signers, such as a third-party trusted reviewer. A digital signature serves as a 'stamp of approval' of the page by the signer. Therefore, when signing web pages for browser-crypto applications, signers should ensure that:

  • The page functions 'as advertised'.
  • The user's secrets and private keys never leave the web browser.
  • All appropriate measures have been taken to mitigate any foreseeable attacks. This includes (but is not limited to) using subresource integrity to ensure the integrity of dependent javascript and css files, escaping and handling external content securely to mitigate cross-site scripting attacks, applying a strict content security policy, and any other appropriate measures.

To digitally sign a page with one or more cryptographic signatures, the following meta tag must be included in the head section of the page to be signed:

<meta name='pagesignatures' content='https://hostname.domain.tld/path/to/signatures.json'>
where https://hostname.domain.tld/path/to/signatures.json is the URL of a JSON file that will contain the signatures and the public keys needed to verify the signatures of the page source. This step must be completed before the page is signed as per the procedure below.

Signing keys and signatures can be created using either RSA cryptography or elliptic curve cryptography (ECC). ECC keys are shorter than RSA keys of equivalent strength, however some users may be more familiar with RSA cryptography. The necessary operations can be completed using openssl for either method.


Generating Keys

If you've not yet created a pair of signing keys, follow the instructions in this section for doing so. If you already have pair of signing keys, you can skip to the next step, signing web pages.

  • RSA

    Create an RSA private key:

    openssl genrsa -out private.pem 2048

    Derive the RSA public key from the private key:

    openssl rsa -in private.pem -pubout > public.pem

  • ECC

    Create an ECC private key:

    openssl ecparam -name prime256v1 -genkey -out private.pem

    Derive the ECC public key from the private key:

    openssl ec -in private.pem -pubout -out public.pem


Signing Web Pages

Once you've created a signing keypair, you can use openssl to sign the your page.

  • RSA

    openssl dgst -sha256 -sign private.pem -out signature.dat signedpage.html
  • ECC

    openssl dgst -sha256 -sign private.pem -out signature.dat signedpage.html

Once the signature has been created, the signature and public key must be stored in the signatures.json file, which is referenced in the meta tag of the signed page. The signtures.json file should be produced using the example below (which contains signatures for the sample page at https://www.pageintegrity.net/signedpage.html), as a template.

{
	"pagehash":
	{
		"algorithm":	"SHA-256", 
		"hash":		"ba1b3ef1a5a47bd8ee2f52b7a45725c175c4ca703299bef3d468ac2721e96709"
	},
	"signatures":
	[
		{
			"publickey": 	
			{
				"algorithm":	{"name": "RSASSA-PKCS1-v1_5", "hash": {"name": "SHA-256"}},
				"keydata":	"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0aY77NUoaBZ2rB536sNnZrrqmwaRQA44Maat2BjYP4U9sKUTxwu1VfNeNIuYyGiSTbH52X+rAYZXFCY1rPU3sETiRX9x3T36n8SiuyrPdklTUtYBfBj2wz27Q7D2PakKgTPyKNpRHsw1OZ2PVDOu/lJwGwVT4QCbTiXnG1aTny8sQ/H1bOj1qUWPhO91gECtFOJAC4h1uImMKk2vhA9+p9xxtqLOtu5wvmYkKH0BASadDMfUZT8x1ybWenUGw9aTn2ON/JB04RMZpir3J28TqykPO8g8zhcfKA1bdsk1/Y3YTV4nP3YmhjatZM/jM9qKjL7yBKHEJ5XvUnT5M/5cCwIDAQAB"
			},
			"signature":	
			{
				"algorithm":	{"name": "RSASSA-PKCS1-v1_5"},
				"signature":	"KeuSdzs5XGxhC5qIL3zgOM+2/Aeg32pF1nXo2g5Eil8oUXfu+O8QUn2C78gfjZucL9C8vC22ZFHaE6Fk403RvjqnRIx0dukgS0m5GG3fDltC1rjKRsfepONlLHTmmQqY3B9m7jF/uEJPttDOD8dCnaFiv9nRNSpJ+RP/aLCcfszhZuuoZ5esz84Vq43prI27AFoHaXB5arn4ziLrAnCCnv/pQFsIUlgAkV/vZUYpJZIEDqV4z6kHctu2Lkh2hf50TaRipP0Z9wj6M+8K7agNpS2D8mw8sUjv6TJeevqtiSzUxmVrEIcErgbZY1V9N8qCMHWD8PhRApOaGPeYEmwmgw=="
			}
		},
		{
			"publickey": 	
			{
				"algorithm":	{"name": "RSASSA-PKCS1-v1_5", "hash": {"name": "SHA-256"}},
				"keydata":	"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArDjsbjeswFNJ41onNsJnkg1APD1/ltfHzkBQFd9ezBSk90KsTxGKYcvQiydQL/UtugAi3Djr6e6nI1WiRo4C5dW8lBaIT/ptrmoNvbYYjMfmNZZpd0kxag3VHQALl2e5ATAB75BdQPTKw8gjbCypvA5mID1a8VllfOuyZDVdciC2DTGSZ6soOBnNAQQPcq3pVRBc6834e/498GGNWeTEu7bCBPmuqOy2+DATbo7/eBOvTGzDOVaQxaaoxq67zfEt/NE8yZiF9O35m8gvaBi1dAdSCkFzK5a/4ZwmZdvzcm5rDN9LZfs2cNn+MG8MGbxN8001bLj73akiRtUxqA5ShwIDAQAB"
			},
			"signature":	
			{
				"algorithm":	{"name": "RSASSA-PKCS1-v1_5"},
				"signature":	"omXPWebK9AKTK78vwRKpWvuRB9GWV7dGnia7BTybMjqXUHUSuFvIxqQ6nHyMYWzczWuxvIt8A4/bSmV9KlUJLJN7tXCFkdgt6AFNUQ1q6y3NATZEFBihf+dO19BGXASjQK54SMl+7wbmseE8Lc7lKxll9SRhorbBiJSoeobuZ/9UXcsHzGw9t7NuB0yiEkh/nWMxnfa48o4OFN5TjLMmhJIAsGQ5q3MkOqEL/4AxizAJqv8XT78V1w4Adcy0NNnbwXQsm5NBkRTw+CHGyA/onl4YKDubQ+fcFlfSIl2OPEBXer+Wdr15uSd6XGARaJVltLiJ8s3ycxtpFq1NiyYPEg=="
			}
		},
		{
			"publickey": 	
			{
				"algorithm":	{"name": "ECDSA", "namedCurve": "P-256"},
				"keydata":	"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGyYdxcz3Ea3jVpIk6iM2YYElX178Wn+DQ893sYp38lBpFNizeu0rvuT3TbWGt4N9XOxmBtzVER4ndtLAM4Mt8g=="
			},
			"signature":	
			{
				"algorithm":	{"name": "ECDSA", "hash": {"name": "SHA-256"}},
				"signature":	"8f9xy8tm4qaFW5WVn0GjK9lhlfJoupPo7PYTjjS+9plpOPXEOshIDRYyc1q21h01MhOckzWXsgqGIkzzhZ6/sg=="
			}
		}

	]
}

The values in the signatures.json file are produced from the key files and signature files created above as follows:

  • pagehash.algorithm is ‘SHA-256’

  • pagehash.hash is the SHA-256 hash of the source of the page being signed. This value can be computed using the following openssl command:
    openssl dgst -sha256 signedpage.html
  • signatures[] is an array. Each element in the array contains a signature of the signed page and the public key used to create the signature.

  • signatures[i].publickey.algorithm is:

    For an RSA public key:
    {"name": "RSASSA-PKCS1-v1_5", "hash": {"name": "SHA-256"}}

    For an ECC public key:

    {"name": "ECDSA", "namedCurve": "P-256"}

    Note: Only RSA and ECC keys with the above parameters are supported.

  • signatures[i].publickey.keydata is the base64-encoded public key produced by openssl above. Note: the openssl command above writes the public key to the public.key file in PEM format. The header, footer and line-breaks in this file should be removed, leaving just the base64-encoded public key for populating this field. The following command can be used to remove the header, footer, and line-breaks for the public.key PEM file:

    cat public.key | grep -v '-' | tr -d '\n'
  • signatures[i].signature.algorithm is:

    For an RSA signature:
    {"name": "RSASSA-PKCS1-v1_5"}

    For an ECC signature:

    {"name": "ECDSA", "hash": {"name": "SHA-256"}}

    Note: Only RSA and ECC signatures with the above parameters are supported.

  • signatures[i].signature.signature is the base64-encoded signature produced by openssl above.

    For an RSA signature, signature in the signature.dat file produced by openssl above must be base-64 encoded. The following openssl command can be used to do this:

    openssl base64 -in signature.dat | tr -d '\n'

    For an ECC signature, the s and r values must be extracted for the signature.dat file produced by openssl above. Then, these values must be concatenated, and base-64 encoded. The following openssl command can be used to do this:

    openssl asn1parse -inform der -in signature.dat | cut -d: -f4 | tr -d '\n' | xxd -p -r | base64 | tr -d '\n'