Discussion:
Failures in OpenPGP encrypted/signed file parsing
Chris Hacking
2012-11-06 08:02:50 UTC
Permalink
Hi all,

I'm currently writing an openPGP client in .NET, and trying to use the
BouncyCastle C# v1.7 implementation for the crypto. For reasons of requiring
that I target a specific .NET version, I had to recompile the library from
source (a few, mostly trivial, changes were made to get it to compile).[1]

I've gotten it to open and parse key data correctly, but it's throwing an
exception when trying to parse encrypted or signed data. Note that I'm not
trying to actually decrypt/verify the data, just read the packets of the
input stream. This happens both with my own files (generated using gpg) and
with the signed test files that come with the source.

The exception is IOException:"unknown PGP public key algorithm encountered".
The stack trace is as follows (namespaces and paths excluded due to me
needing to transcribe this all):
PublicKeyPacket.PublicKeyPacket(BcpgInputStream) @ line 50
BcpgInputStream.ReadPacket() @ line 220
PgpPublicKeyRing.PgpPublicKeyRing(inputStream) @ line 48
PgpObjectFactory.NextPgpObject() @ line 76
PgpObjectFactory.AllPgpObjects() @ line 136

The reason for the exception is a switch statement on a variable called
"algorithm" falling through the bottom. The variable is typed as a
PublicKeyAlgorithmTag (enum), but it has (depending on the file I test with)
values such as 129, 221, or 120, which don't map to any value of the enum.
The actual key algorithms used are ELG-E, RSA, and DSA, respectively
(according to GPG). The value is the same for different files signed with
the same key, at least in my testing so far, but different for files signed
by other keys of the same type (but different bit length on the asymmetric
key).

I'm not very familiar at all with the binary structure of openpgp data, so
I'm hoping somebody out there can help me figure out what is going on here.
Is the value not being masked and/or bit-shifted in a way that it should be?
Is the wrong value being read from the stream? I suspect that the latter
possibility is correct, as the code accurately identifies the key types when
parsing a file that's just a bunch of exported keys.

If anybody could help me out with this, I'd be greatly appreciative.

Thank you,
Chris


[1]: The target platform is Windows Runtime, the API family for Windows
Store apps. When using it with C#, the API is basically a subset of .NET
4.5. The preprocessor define for this platform is NETFX_CORE. My changes
mostly consisted of things like replacing deprecated functions with their
new forms, and generally only concerned manipulating strings (I had to add
Platform.ToUpperInvariant(String) because it's now done differently, for
example) and finishing working with streams (Close() is now deprecated; just
destruct or explicitly call Dispose()). I also had to remove (#if exclude) a
bit of code that tried to do things which Store apps aren't permitted to do
generally, such as talk to the system PKI stores. I did have to make one
change to actual crypto code; the entire System.Threading.Thread class is
now deprecated, so the core of the ThreadedSeedGenerator RNG, which operates
on the timing differences between threads, had to be re-written. I'm
moderately familiar with the approach, but cannot promise that my
implementation (using the new Tasks API for asynchronous code) is correct.

None of this should have any impact on processing a binary stream while it
is still open, however. With that said, if anybody would like (now, or when
I get it working...) I'm happy to return my changes to the community. I
can't easily generate a diff or patch at this time, but I could do so later.
I imagine there will be others attempting to use this API (which is, I
believe, also the target API for Windows Phone 8 apps, unlike the
Silverlight API used for WP7) in the future, and would like to help them
out.
Christoph Hannebauer
2012-11-07 09:08:18 UTC
Permalink
Hi Chris,

have you tried to run your code using the original version of Bouncy
Castle C#? In this case, you may not be able to run the code as a
Windows Store App, but at least you would find out whether your changes
to the Bouncy Castle code created the problem or whether it is something
else.

Additionally, a minimal code sample would help, so we can try and
reproduce the problem in our own development environments.

If I had to guess, I'd think that the value read for
PublicKeyAlgorithmTag is not actually the public key algorithm tag but
some other value, like the length of the packet or something. The
BcpgInputStream is not really robust in this regard: If you read a byte
manually from the underlying stream or call a method that reads data
directly from the BcpgInputStream (for example, by calling
GetInputStream()), then the stream will be out of sync and problems like
the one you described occur.

If you want to debug this further, you might also want to check out RFC
4880. The PGP packet format is described there.


Best

Chris2 ;-)
Post by Chris Hacking
Hi all,
I'm currently writing an openPGP client in .NET, and trying to use the
BouncyCastle C# v1.7 implementation for the crypto. For reasons of requiring
that I target a specific .NET version, I had to recompile the library from
source (a few, mostly trivial, changes were made to get it to compile).[1]
I've gotten it to open and parse key data correctly, but it's throwing an
exception when trying to parse encrypted or signed data. Note that I'm not
trying to actually decrypt/verify the data, just read the packets of the
input stream. This happens both with my own files (generated using gpg) and
with the signed test files that come with the source.
The exception is IOException:"unknown PGP public key algorithm encountered".
The stack trace is as follows (namespaces and paths excluded due to me
The reason for the exception is a switch statement on a variable called
"algorithm" falling through the bottom. The variable is typed as a
PublicKeyAlgorithmTag (enum), but it has (depending on the file I test with)
values such as 129, 221, or 120, which don't map to any value of the enum.
The actual key algorithms used are ELG-E, RSA, and DSA, respectively
(according to GPG). The value is the same for different files signed with
the same key, at least in my testing so far, but different for files signed
by other keys of the same type (but different bit length on the asymmetric
key).
I'm not very familiar at all with the binary structure of openpgp data, so
I'm hoping somebody out there can help me figure out what is going on here.
Is the value not being masked and/or bit-shifted in a way that it should be?
Is the wrong value being read from the stream? I suspect that the latter
possibility is correct, as the code accurately identifies the key types when
parsing a file that's just a bunch of exported keys.
If anybody could help me out with this, I'd be greatly appreciative.
Thank you,
Chris
[1]: The target platform is Windows Runtime, the API family for Windows
Store apps. When using it with C#, the API is basically a subset of .NET
4.5. The preprocessor define for this platform is NETFX_CORE. My changes
mostly consisted of things like replacing deprecated functions with their
new forms, and generally only concerned manipulating strings (I had to add
Platform.ToUpperInvariant(String) because it's now done differently, for
example) and finishing working with streams (Close() is now deprecated; just
destruct or explicitly call Dispose()). I also had to remove (#if exclude) a
bit of code that tried to do things which Store apps aren't permitted to do
generally, such as talk to the system PKI stores. I did have to make one
change to actual crypto code; the entire System.Threading.Thread class is
now deprecated, so the core of the ThreadedSeedGenerator RNG, which operates
on the timing differences between threads, had to be re-written. I'm
moderately familiar with the approach, but cannot promise that my
implementation (using the new Tasks API for asynchronous code) is correct.
None of this should have any impact on processing a binary stream while it
is still open, however. With that said, if anybody would like (now, or when
I get it working...) I'm happy to return my changes to the community. I
can't easily generate a diff or patch at this time, but I could do so later.
I imagine there will be others attempting to use this API (which is, I
believe, also the target API for Windows Phone 8 apps, unlike the
Silverlight API used for WP7) in the future, and would like to help them
out.
Loading...