Package: http-signature-server
http-signature-serverHTTP server agnostic Python implementation of the server side of theIETF draft "Signing HTTP Messages", with no dependencies other than the Python standard library, althoughcryptographywould typically be used in client code to verify signatures using a public key.Seehttp-signature-clientfor a compatible client-side implementation.Installationpipinstallhttp-signature-serverUsagefromhttp_signature_serverimportverifydefverify(key_id,signature,signature_input):# If the key_id is not found, return None# If the key_id is found and the signature verifies the input, return True# If the key_is is found and the signature does not verify the input, return Falseerror,(key_id,verified_headers)=verify_headers(verify,max_skew,method,path,headers)iferrorisnotNone:# Return error or raise exception as neededRecipe: Verify using Ed25519 public keyfromcryptography.exceptionsimportInvalidSignaturefromcryptography.hazmat.backendsimportdefault_backendfromcryptography.hazmat.primitives.serializationimportload_pem_public_keypublic_key=\b'-----BEGIN PUBLIC KEY-----\n'\b'MCowBQYDK2VwAyEAe9+zIz+CH9E++J0qiE6aS657qzxsNWIEf2BZcUAQF94=\n'\b'-----END PUBLIC KEY-----\n'public_key=load_pem_public_key(public_key,backend=default_backend())defverify(key_id,signature,signature_input):# Could use the supplied key_id to lookup the public keytry:public_key.verify(signature,signature_input)exceptInvalidSignature:returnFalsereturnTrue# method, path, and headers would be taken from the incoming HTTP requesterror,(key_id,verified_headers)=verify_headers(verify,10,method,path,headers)Recipe: Create an Ed25519 public/private key pairfromcryptography.hazmat.primitives.asymmetric.ed25519importEd25519PrivateKeyfromcryptography.hazmat.primitives.serializationimportEncoding,NoEncryption,PrivateFormat,PublicFormatprivate_key=Ed25519PrivateKey.generate()print(private_key.private_bytes(encoding=Encoding.PEM,format=PrivateFormat.PKCS8,encryption_algorithm=NoEncryption()))print(private_key.public_key().public_bytes(encoding=Encoding.PEM,format=PublicFormat.SubjectPublicKeyInfo))APIParametersverify- A callable taking astrkey_idandbytessignatureandsignature_input. It must returnTrueifkey_idis known andsignature/signature_inputis verified, for example by a corresponding public key; returnFalseifkey_idis known but thesignature/signature_inputisnotverified; returnNoneotherwise.max_skew- A maximum integer number of seconds difference from the time an incoming signature claimed to be constructed, and the current time.method- The HTTP method of the request, such asGETorPOST.path- The full path of the request, including any query string.headers- A tuple of (key, value) pairs of HTTP headers to attempt to verify.ReturnsA tupleerror, (key_id, verified_headers).error- If the request is verified,None. Otherwise astrcontaining a short reason in English as to why verification failed.key_id- If the request is verified, thekeyIdfrom the incoming request. Otherwise,None.verified_headers- If the request is verified, the (key, value) HTTP header pairs that were verified by the signature; this will be a sub-tuple of theheadersparameter. Otherwise,None.What's implementedA deliberate subset of the signature algorithm is implemented/enforced:the(request-target)pseudo-header is required and verified;thecreatedparameter is required, and the corresponding(created)pseudo-header must be signed;theheadersparameter is required;theexpiresparameter, if sent, mustnotcorrespond to a signed(expires)pseudo-header;thealgorithmparameter is ignored if sent.There are a few places where the implementation is technically, and deliberately, non-conforming.The(created)pseudo-header: if this is in the future from the server's point of view, even 1 second, according to the spec verification should fail. Instead, there is a configurable maximum time skew that applies to the future as well as the past.Theexpiresparameter: if this is sent and in the past from the server's point of view, according to the spec verification should fail.Thealgorithmparameter: if it's sent but does not match what the server expects, according to the spec verification should fail.It is assumed that the(created)and(request-target)pseudo-headers were prepended to the list of real HTTP headers before canonicalisation at the client. This fact only makes a difference in the edge case of real HTTP headers called(created)or(request-target).