New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
x/crypto/openpgp: NewEntity creates malformed PGP key: unexpected EOF #25463
Comments
I believe you need to use e.SerializePrivate to get the gpg import to work. but if you want the full key exported you need to use both Serialize and SerializePrivate. |
@james-lawrence You should be able to export/armor just the public portion for distribution. I can import the key into my gpg key ring, but I have to add the option:
|
(CC: @FiloSottile) |
@onetwopunch try using SerializePrivate to ioutil.Discard then just the Serialize to your buffer. it may not work, but iirc you need to invoke SerializePrivate to trigger the self signing aspect (could be completely wrong, going off memory atm) |
@james-lawrence You're right: https://github.com/golang/crypto/blob/master/openpgp/keys.go#L550 Is this desired though? I'd think that we should have the When I change to use the I was able to update the Serialize method to give me what I need. I'm happy to create a pull request if a contributer deems it appropriate: diff --git a/openpgp/keys.go b/openpgp/keys.go
index fd582a8..5ff4218 100644
--- a/openpgp/keys.go
+++ b/openpgp/keys.go
@@ -29,6 +29,7 @@ type Entity struct {
Identities map[string]*Identity // indexed by Identity.Name
Revocations []*packet.Signature
Subkeys []Subkey
+ config *packet.Config
}
// An Identity represents an identity claimed by an Entity and zero or more
@@ -483,6 +484,7 @@ func NewEntity(name, comment, email string, config *packet.Config) (*Entity, err
PrimaryKey: packet.NewRSAPublicKey(currentTime, &signingPriv.PublicKey),
PrivateKey: packet.NewRSAPrivateKey(currentTime, signingPriv),
Identities: make(map[string]*Identity),
+ config: config,
}
isPrimaryId := true
e.Identities[uid.Id] = &Identity{
@@ -585,6 +587,12 @@ func (e *Entity) Serialize(w io.Writer) error {
if err != nil {
return err
}
+ if e.PrivateKey != nil {
+ err = ident.SelfSignature.SignUserId(ident.UserId.Id, e.PrimaryKey, e.PrivateKey, e.config)
+ if err != nil {
+ return err
+ }
+ }
err = ident.SelfSignature.Serialize(w)
if err != nil {
return err
@@ -601,6 +609,12 @@ func (e *Entity) Serialize(w io.Writer) error {
if err != nil {
return err
}
+ if e.PrivateKey != nil {
+ err = subkey.Sig.SignKey(subkey.PublicKey, e.PrivateKey, e.config)
+ if err != nil {
+ return err
+ }
+ }
err = subkey.Sig.Serialize(w)
if err != nil { |
@onetwopunch I would say its unnessarily confusing. just pointing you in the direction to unblock you, not making claims about the usability of the API. =) |
For now and for future users who have this problem, it can also be solved using your method like so: // Signs the identities of the entity reference
entity.SerializePrivate(bytes.NewBuffer(nil), conf)
// Serialize only the public key.
serializedEntity := bytes.NewBuffer(nil)
entity.Serialize(serializedEntity) I'm still happy to make a PR to clean this up a bit if someone wants. :) Thanks so much for the help @james-lawrence |
Please feel free to submit a fix as a PR. Thanks! You might want to look a bit more into what the most appropriate time to fill in the signature is. I would not expect Serialize to cause a sign op every time it's called. (But I haven't looked at the code in depth so you might be right.) |
@FiloSottile Thanks, I'll do that. I think I might just add a separate method with the same signature as |
We should fix |
Yeah that makes sense. I'll get started tonight |
@FiloSottile when you have a moment, would you mind having a look at the above PR? |
Notice that this changes the API and broke some of our fragile code. We had a function that created a key with NewEntity, and later changed the lifetime of a subkey. Since the signature was only done later, it worked. But now because of this change it suddenly stopped working and the subkeys had no expiration. |
Change https://golang.org/cl/118015 mentions this issue: |
Previously if you created a new Entity then ran `Serialize` _before_ running `SerializePrivate`, the resulting armored public key was corrupted, giving the error of `unexpected EOF`. This fix signs the public key with the private key upon creation of a NewEntity. Since SerializePrivate only is applicable to entities created with NewEntity per the docs we can also safely remove the signing portion from that function. Fixes golang#25463 Change-Id: I58b808987ee173079f33bce3d6c3527f9233b2cd GitHub-Last-Rev: 2c4b8e4d630a06d782816f8fbd3d59f01ece2565 GitHub-Pull-Request: golang/crypto#47 Reviewed-on: https://go-review.googlesource.com/114001 Reviewed-by: Filippo Valsorda <filippo@golang.org>
Signing was moved in NewEntity as it makes more sense there, but there might be code that relies on SerializePrivate to make signatures with parameters that were modified after NewEntity. As it used to always sign in SerializePrivate, it shouldn't break anything to sign in both places. Fixes golang/go#25463 Change-Id: Ia7f509daf31ac05fedc441225d554f333b288d70 Reviewed-on: https://go-review.googlesource.com/118015 Run-TryBot: Filippo Valsorda <filippo@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Yaron de Leeuw <jarondl@google.com> Reviewed-by: Alexandre Viau <viau.alexandre@gmail.com> Reviewed-by: Filippo Valsorda <filippo@golang.org>
Signing was moved in NewEntity as it makes more sense there, but there might be code that relies on SerializePrivate to make signatures with parameters that were modified after NewEntity. As it used to always sign in SerializePrivate, it shouldn't break anything to sign in both places. Fixes golang/go#25463 Change-Id: Ia7f509daf31ac05fedc441225d554f333b288d70 Reviewed-on: https://go-review.googlesource.com/118015 Run-TryBot: Filippo Valsorda <filippo@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Yaron de Leeuw <jarondl@google.com> Reviewed-by: Alexandre Viau <viau.alexandre@gmail.com> Reviewed-by: Filippo Valsorda <filippo@golang.org>
Signing was moved in NewEntity as it makes more sense there, but there might be code that relies on SerializePrivate to make signatures with parameters that were modified after NewEntity. As it used to always sign in SerializePrivate, it shouldn't break anything to sign in both places. Fixes golang/go#25463 Change-Id: Ia7f509daf31ac05fedc441225d554f333b288d70 Reviewed-on: https://go-review.googlesource.com/118015 Run-TryBot: Filippo Valsorda <filippo@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Yaron de Leeuw <jarondl@google.com> Reviewed-by: Alexandre Viau <viau.alexandre@gmail.com> Reviewed-by: Filippo Valsorda <filippo@golang.org>
Signing was moved in NewEntity as it makes more sense there, but there might be code that relies on SerializePrivate to make signatures with parameters that were modified after NewEntity. As it used to always sign in SerializePrivate, it shouldn't break anything to sign in both places. Fixes golang/go#25463 Change-Id: Ia7f509daf31ac05fedc441225d554f333b288d70 Reviewed-on: https://go-review.googlesource.com/118015 Run-TryBot: Filippo Valsorda <filippo@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Yaron de Leeuw <jarondl@google.com> Reviewed-by: Alexandre Viau <viau.alexandre@gmail.com> Reviewed-by: Filippo Valsorda <filippo@golang.org>
Signing was moved in NewEntity as it makes more sense there, but there might be code that relies on SerializePrivate to make signatures with parameters that were modified after NewEntity. As it used to always sign in SerializePrivate, it shouldn't break anything to sign in both places. Fixes golang/go#25463 Change-Id: Ia7f509daf31ac05fedc441225d554f333b288d70 Reviewed-on: https://go-review.googlesource.com/118015 Run-TryBot: Filippo Valsorda <filippo@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Yaron de Leeuw <jarondl@google.com> Reviewed-by: Alexandre Viau <viau.alexandre@gmail.com> Reviewed-by: Filippo Valsorda <filippo@golang.org>
Signing was moved in NewEntity as it makes more sense there, but there might be code that relies on SerializePrivate to make signatures with parameters that were modified after NewEntity. As it used to always sign in SerializePrivate, it shouldn't break anything to sign in both places. Fixes golang/go#25463 Change-Id: Ia7f509daf31ac05fedc441225d554f333b288d70 Reviewed-on: https://go-review.googlesource.com/118015 Run-TryBot: Filippo Valsorda <filippo@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Yaron de Leeuw <jarondl@google.com> Reviewed-by: Alexandre Viau <viau.alexandre@gmail.com> Reviewed-by: Filippo Valsorda <filippo@golang.org>
What I'm trying to do is programmatically generate a PGP keypair, store the private key somewhere only this program has access to write to, such as KMS or something, then use the public key. The problem I'm facing is that it seems my method of creating a key pair is not working such that it can be re-ingested by this same library.
I'm fully aware that I may be doing something wrong here, but on the off chance this is an actual error in the openpgp package I figured I might as well submit an issue.
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?Mac OSX
What did you do?
I'm trying to autogenerate a PGP key pair and validate the public key armored using the openpgp package in the following way:
What did you expect to see?
What did you see instead?
Also, using this same
createKeyPair
method but just outputting it to stdout then attempting to import it to gpg (instead of this validation code) also did not work but with a different error:The text was updated successfully, but these errors were encountered: