Why does openssl accept multiple keys after BEGIN PUBLIC KEY?
Viktor Dukhovni
openssl-users at dukhovni.org
Tue Oct 10 17:02:45 UTC 2023
On Tue, Oct 10, 2023 at 12:07:51PM +0200, David Bürgin wrote:
> When you inspect the following key with ‘openssl pkey’, it works fine:
>
> -----BEGIN PUBLIC KEY-----
> MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9oaro18Mt4FITtXvhy/v2N0d0
> aQJ285MgstG5QSgvFnXA+7Bww20hnLQZD4vOZbeIhdu4g5s8S6LWczqswDjVyD97
> 9j+RcZM+JcnHPEIvkn7YCKYnM3mvSQKmeRtm9kDVL0waKf+iZ5ZDYiLcfXCSIDnT
> 2SMxp3D9UNEfEZDMoQIDAQABMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK
> A5hv8tKZBw3cx+j0NMrbsOY5QfoUtxGeXjmGI89q63iFxBdSgrJW5wpthZfHcVHl
> roPW885ToeSrEdyUIVCokR7L8PP7Up0PGXUDPIFCQB7+jVV8ezLyxHSLGT81u7Be
> el5ybAgsal/GmhpeQXcEpnYpiqVcHL3XTlY8+34EQQIDAQAB
> -----END PUBLIC KEY-----
>
> However, there is something odd about it, openssl seems to be
> interested only in the first half of the key data:
>
> Well, that key actually contains two, concatenated
> SubjectPublicKeyInfos! I noticed this when I first used a different
> library, and processing failed.
The data between the PEM "BEGIN" and "END" markers is supposed to be a
block of base64 text that contains an ASN.1 DER encoding of the object
in question. In this case we see, that indeed there are two
back-to-back DER SPKI structures:
$ openssl asn1parse <<EOF
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9oaro18Mt4FITtXvhy/v2N0d0
aQJ285MgstG5QSgvFnXA+7Bww20hnLQZD4vOZbeIhdu4g5s8S6LWczqswDjVyD97
9j+RcZM+JcnHPEIvkn7YCKYnM3mvSQKmeRtm9kDVL0waKf+iZ5ZDYiLcfXCSIDnT
2SMxp3D9UNEfEZDMoQIDAQABMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDK
A5hv8tKZBw3cx+j0NMrbsOY5QfoUtxGeXjmGI89q63iFxBdSgrJW5wpthZfHcVHl
roPW885ToeSrEdyUIVCokR7L8PP7Up0PGXUDPIFCQB7+jVV8ezLyxHSLGT81u7Be
el5ybAgsal/GmhpeQXcEpnYpiqVcHL3XTlY8+34EQQIDAQAB
-----END PUBLIC KEY-----
EOF
0:d=0 hl=3 l= 159 cons: SEQUENCE
3:d=1 hl=2 l= 13 cons: SEQUENCE
5:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
16:d=2 hl=2 l= 0 prim: NULL
18:d=1 hl=3 l= 141 prim: BIT STRING
162:d=0 hl=3 l= 159 cons: SEQUENCE
165:d=1 hl=2 l= 13 cons: SEQUENCE
167:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
178:d=2 hl=2 l= 0 prim: NULL
180:d=1 hl=3 l= 141 prim: BIT STRING
Because ASN.1 objects have an explicit length, it is possible to process
just the first 162 bytes (3 byte header + 159 data), without checking
that this represents the entire content of the base64-encoded input.
> • Is openssl right in accepting this key? Why does it use only the
> first one?
OpenSSL "pkey" application (and perhaps more generally, the underlying
PEM_read_bio_PUBKEY(3)) did not check that the entire input buffer was
consumed, so only the first structure is processed. The only plausible
outcomes are to extract the first structure and ignore excess data, or
to the reject the input due to the excess data.
Note that the PEM layer relies on the "d2i" functions to read the
DER-encoded data, and the "d2i" functions support reading a portion of
an input buffer, filling in the decoded structure and returning a
pointer to the tail of the input stream, this supports reading of arrays
of DER-encoded objects, or just a single DER encoded object in a larger
"packet".
So what happens here, is that the PEM layer does not compare the "d2i"
end pointer with the end of the input buffer and the "trailing data"
is simply ignored. The check that's "missing" would be similar to:
https://github.com/vdukhovni/postfix/blob/master/postfix/src/tls/tls_certkey.c#L208-L214
> • Is the other library wrong in rejecting this key?
I don't think it is wrong to be strict.
> • Do relevant RFCs say something about such a ‘concatenated’ format?
I haven't seen anything that clearly prohibits ignoring excess input,
but there is certainly no expectation that it would be used. It can
either be rejected or ignored.
I don't see any explicit rules about this in:
https://datatracker.ietf.org/doc/html/rfc7468
Perhaps I did not read it closely enough, or the relevant normative
rules are in some other document.
--
Viktor.
More information about the openssl-users
mailing list