@ -122,22 +122,57 @@ func (s pgpKey) MarshalBinary() ([]byte, error) {
body := new ( bytes . Buffer )
body := new ( bytes . Buffer )
armorEncoder , err := armor . Encode ( body , "PGP PUBLIC KEY" , nil )
armorEncoder , err := armor . Encode ( body , "PGP PUBLIC KEY" , nil )
if err != nil {
if err != nil {
return nil , fmt . Errorf ( "error initializing armor encoder: %w" , err )
return nil , fmt . Errorf ( "initializing armor encoder: %w" , err )
} else if err := s . entity . Serialize ( armorEncoder ) ; err != nil {
} else if err := s . entity . Serialize ( armorEncoder ) ; err != nil {
return nil , fmt . Errorf ( "error e ncoding public key: %w" , err )
return nil , fmt . Errorf ( "encoding public key: %w" , err )
} else if err := armorEncoder . Close ( ) ; err != nil {
} else if err := armorEncoder . Close ( ) ; err != nil {
return nil , fmt . Errorf ( "error closing armor encoder: %w" , err )
return nil , fmt . Errorf ( "closing armor encoder: %w" , err )
}
}
return body . Bytes ( ) , nil
return body . Bytes ( ) , nil
}
}
func ( s pgpKey ) userID ( ) ( * packet . UserId , error ) {
if l := len ( s . entity . Identities ) ; l == 0 {
return nil , errors . New ( "pgp key has no identity information" )
} else if l > 1 {
return nil , errors . New ( "multiple identities on a single pgp key is unsupported" )
}
var identity * openpgp . Identity
for _ , identity = range s . entity . Identities {
break
}
return identity . UserId , nil
}
func anonPGPSignifier ( pgpKey pgpKey , sigInt SignifierInterface ) ( SignifierInterface , error ) {
keyID := pgpKey . entity . PrimaryKey . KeyIdString ( )
userID , err := pgpKey . userID ( )
if err != nil {
return nil , err
}
pubKeyBody , err := pgpKey . MarshalBinary ( )
if err != nil {
return nil , err
}
return signifierMiddleware {
SignifierInterface : sigInt ,
signCallback : func ( cred * Credential ) {
cred . PGPSignature . PubKeyBody = string ( pubKeyBody )
cred . AnonID = fmt . Sprintf ( "%s %q" , keyID , userID . Email )
} ,
} , nil
}
// TestSignifierPGP returns a direct implementation of the SignifierInterface
// TestSignifierPGP returns a direct implementation of the SignifierInterface
// which uses a random private key generated in memory, as well as an armored
// which uses a random private key generated in memory, as well as an armored
// version of its public key.
// version of its public key.
//
//
// NOTE that the key returned is very weak, and should only be used for tests.
// NOTE that the key returned is very weak, and should only be used for tests.
func TestSignifierPGP ( accountID string , randReader io . Reader ) ( SignifierInterface , [ ] byte ) {
func TestSignifierPGP ( name string , anon bool , randReader io . Reader ) ( SignifierInterface , [ ] byte ) {
entity , err := openpgp . NewEntity ( accountID , "" , accountID + "@example.com" , & packet . Config {
entity , err := openpgp . NewEntity ( name , "" , name + "@example.com" , & packet . Config {
Rand : randReader ,
Rand : randReader ,
RSABits : 512 ,
RSABits : 512 ,
} )
} )
@ -151,7 +186,14 @@ func TestSignifierPGP(accountID string, randReader io.Reader) (SignifierInterfac
panic ( err )
panic ( err )
}
}
return accountSignifier ( accountID , pgpKey ) , pubKeyBody
if anon {
sigInt , err := anonPGPSignifier ( pgpKey , pgpKey )
if err != nil {
panic ( err )
}
return sigInt , pubKeyBody
}
return accountSignifier ( name , pgpKey ) , pubKeyBody
}
}
// SignifierPGP describes a pgp public key whose corresponding private key will
// SignifierPGP describes a pgp public key whose corresponding private key will
@ -185,23 +227,25 @@ func cmdGPG(stdin []byte, args ...string) ([]byte, error) {
// LoadSignifierPGP loads a pgp key using the given identifier. The key is
// LoadSignifierPGP loads a pgp key using the given identifier. The key is
// assumed to be stored in the client's keyring already.
// assumed to be stored in the client's keyring already.
//
//
// If setPubKeyBody is true, then CredentialPGPSignature instances produced by
// If this is being called for an anonymous user to use, then anon can be set to
// the returned Signifier will have their PubKeyBody field set.
// true. This will have the effect of setting the PubKeyBody and AnonID of all
func LoadSignifierPGP ( keyID string , setPubKeyBody bool ) ( SignifierInterface , error ) {
// produced Credentials.
func LoadSignifierPGP ( keyID string , anon bool ) ( SignifierInterface , error ) {
pubKey , err := cmdGPG ( nil , "-a" , "--export" , keyID )
pubKey , err := cmdGPG ( nil , "-a" , "--export" , keyID )
if err != nil {
if err != nil {
return nil , fmt . Errorf ( "loading public key: %w" , err )
return nil , fmt . Errorf ( "loading public key: %w" , err )
}
}
var sigInt SignifierInterface = & SignifierPGP { Body : string ( pubKey ) }
if setPubKeyBody {
sig := & SignifierPGP { Body : string ( pubKey ) }
sigInt = signifierMiddleware {
if ! anon {
SignifierInterface : sigInt ,
return sig , nil
signCallback : func ( cred * Credential ) {
}
cred . PGPSignature . PubKeyBody = string ( pubKey )
} ,
pgpKey , err := sig . load ( nil )
}
if err != nil {
return nil , err
}
}
return sigInt , nil
return anonPGPSignifier ( pgpKey , sig )
}
}
func ( s SignifierPGP ) load ( fs fs . FS ) ( pgpKey , error ) {
func ( s SignifierPGP ) load ( fs fs . FS ) ( pgpKey , error ) {