OpenSSL - extract hash algorithm from signature data (PKCS#1 v 1.5) PKCS#1 v 1.5 stores hash algorithm identifier that was used to digest the original message. I would like to know if and how to extract this information. 

I am working on a buffer containing the signature bytes and a buffer with public key.

I know it can be done (e.g. openssl rsautl does it with -verify and -asn1parse), but there is no sensible documentation for asn1 functions in openssl.
The hash identifier of a given RSASSA-PKCS1-v1_5 signature can only be obtained using the signature's public key¹. It's revealed by performing the signature verification steps 1 and 2/a/b/c (which basically gets the signature as an integer, raises it to the power $e$ modulo $N$ extracted from the public key, and converts back to bytes), then parsing the Encoded Message, which should be as per section 9.2 step 5, that is
$$\text{EM}=\mathtt{00}\mathbin\|\mathtt{01}\mathbin\|\mathtt{FF}\mathbin\|\ldots\|\mathtt{FF}\mathbin\|\mathtt{00}\mathbin\|T$$
where


the left two bytes $\mathtt{00}\mathbin\|\mathtt{01}$ are fixed, and followed by $f\ge8$ bytes at $\mathtt{FF}$ then a $\mathtt{00}$ ($f$ is maximal, that is for a $b$-bit public modulus $N$ the length of $T$ is $\left\lfloor(b-17)/8\right\rfloor-f$ bytes).
$T$ is ASN.1 DER encoded, containing the hash identifier and hash value.


The pragmatic approach to decode $T$ is to look at note 1 (or the table below, which comes from that).

MD2:         30 20 30 0C 06 08 2A 86 48 86 F7 0D 02 02 05 00 04 10 ∥ H
MD5:         30 20 30 0C 06 08 2A 86 48 86 F7 0D 02 05 05 00 04 10 ∥ H
SHA-1:       30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14 ∥ H
SHA-224:     30 2D 30 0D 06 09 60 86 48 01 65 03 04 02 04 05 00 04 1C ∥ H
SHA-256:     30 31 30 0D 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ∥ H
SHA-384:     30 41 30 0D 06 09 60 86 48 01 65 03 04 02 02 05 00 04 30 ∥ H
SHA-512:     30 51 30 0D 06 09 60 86 48 01 65 03 04 02 03 05 00 04 40 ∥ H
SHA-512/224: 30 2D 30 0D 06 09 60 86 48 01 65 03 04 02 05 05 00 04 1C ∥ H
SHA-512/256: 30 31 30 0D 06 09 60 86 48 01 65 03 04 02 06 05 00 04 20 ∥ H




If we dive into the fine print, this is a DigestInfoValue. For example, the last entry decodes as


30 31 &nbsp; Sequence of 49 bytes


30 0D &nbsp; Sequence of 13 bytes


06 09 &nbsp; OID of 9 bytes


60 86 48 01 65 03 04 02 06OID 2.16.840.1.101.3.4.2.6 meaning "SHA512-256 algorithm"

05 00 &nbsp; NULL for the Parameters field²

04 20 &nbsp; Octet string of 32 bytes


(the hash H follows as 32 bytes).




See this for how OIDs are encoded, and links to the ASN.1 DER specification. Examples can be thrown at Lapo Luchini's useful ASN.1 decoder.



¹  Given a signature, it's possible to make a new public/private key pair that makes this signature valid with any desired hash identifier and matching any desired known message (not only the the original) when checked with this new public key.

² This field must be present and NULL when encoding and checking $T$ in the context of RSASSA-PKCS1-v1_5. In other contexts a parser must accept that it is missing for the SHA algorithms, see the Exception in appendix B.1 and the two paragraphs above.