Add tests, remove duplicate signing functions (#1)

This commit is contained in:
wussler 2019-05-15 13:48:47 +02:00 committed by Daniel Huigens
parent 3e4e36b766
commit b074657c90
7 changed files with 157 additions and 128 deletions

View file

@ -168,10 +168,8 @@ const trimNewlines = false
signingKeyRing, err := ReadArmoredKeyRing(strings.NewReader(privkey))
signature, err := pgp.SignTextDetached(plaintext, signingKeyRing, passphrase, trimNewlines)
// or
signingKeyRing.Unlock([]byte(passphrase))
signature, err := pgp.SignTextDetached(plaintext, signingKeyRing, "", trimNewlines)
signature, err := signingKeyRing.SignTextDetached(plaintext, passphrase, trimNewlines)
// passphrase is optional if the key is already unlocked
```
To verify a signature either private or public keyring can be provided.
@ -188,10 +186,11 @@ const signature = `-----BEGIN PGP SIGNATURE-----
-----END PGP SIGNATURE-----`
const verifyTime = 0
const trimNewlines = false
signingKeyRing, err := ReadArmoredKeyRing(strings.NewReader(pubkey))
verified, err := pgp.VerifyTextDetachedSig(signature, signedPlainText, signingKeyRing, verifyTime)
verified, err := signingKeyRing.VerifyTextDetachedSig(signature, signedPlainText, verifyTime, trimNewlines)
```
### Detached signatures for binary data
@ -204,14 +203,11 @@ const privkey = `-----BEGIN PGP PRIVATE KEY BLOCK-----
...
-----END PGP PRIVATE KEY BLOCK-----` // encrypted private key
passphrase = "LongSecret"
const trimNewlines = false
signingKeyRing, err := ReadArmoredKeyRing(strings.NewReader(privkey))
signature, err := pgp.SignBinDetached(data, signingKeyRing, passphrase, trimNewlines)
// or
signingKeyRing.Unlock([]byte(passphrase))
signature, err := pgp.SignBinDetached(data, signingKeyRing, "", trimNewlines)
signature, err := signingKeyRing.SignBinDetached(data, passphrase)
// passphrase is optional if the key is already unlocked
```
To verify a signature either private or public keyring can be provided.
@ -231,5 +227,5 @@ const verifyTime = 0
signingKeyRing, err := ReadArmoredKeyRing(strings.NewReader(pubkey))
verified, err := pgp.VerifyBinDetachedSig(signature, data, signingKeyRing, verifyTime)
verified, err := signingKeyRing.VerifyBinDetachedSig(signature, data, verifyTime)
```

View file

@ -2,7 +2,6 @@ package crypto
import (
"encoding/base64"
"io/ioutil"
"strings"
"testing"
@ -13,13 +12,8 @@ import (
// `0ksB0fHC6Duezx/0TqpK/82HSl8+qCY0c2BCuyrSFoj6Dubd93T3//32jVYa624NYvfvxX+UxFKYKJxG09gFsU1IVc87cWvUgmUmgjU=`
func TestAttachmentGetKey(t *testing.T) {
testKeyPackets, err := ioutil.ReadFile("testdata/attachment_keypacket")
if err != nil {
t.Error("Expected no error while reading from file, got:", err)
return
}
testKeyPacketsDecoded, err := base64.StdEncoding.DecodeString(readTestFile("attachment_keypacket", false))
testKeyPacketsDecoded, err := base64.StdEncoding.DecodeString(string(testKeyPackets))
if err != nil {
t.Fatal("Expected no error while decoding base64 KeyPacket, got:", err)
}

View file

@ -304,76 +304,6 @@ func (kr *KeyRing) DecryptStringIfNeeded(data string) (decrypted string, err err
return
}
// SignString signs a string message, using this KeyRing. canonicalizeText identifies if newlines are canonicalized
func (kr *KeyRing) SignString(message string, canonicalizeText bool) (signed string, err error) {
var sig bytes.Buffer
err = kr.DetachedSign(&sig, strings.NewReader(message), canonicalizeText, true)
if err != nil {
return "", err
}
return sig.String(), nil
}
// DetachedSign will sign a separate ("detached") data from toSign, writing to
// w writer. The canonicalizeText identifies if newlines are canonicalized
func (kr *KeyRing) DetachedSign(w io.Writer, toSign io.Reader, canonicalizeText bool, armored bool) (err error) {
var signEntity *openpgp.Entity
for _, e := range kr.entities {
if e.PrivateKey != nil && !e.PrivateKey.Encrypted {
signEntity = e
break
}
}
if signEntity == nil {
return errKeyringNotUnlocked
}
config := &packet.Config{DefaultCipher: packet.CipherAES256,
Time: func() time.Time {
return GetGopenPGP().GetTime()
},
}
if canonicalizeText {
err = openpgp.ArmoredDetachSignText(w, signEntity, toSign, config)
} else {
if armored {
err = openpgp.ArmoredDetachSign(w, signEntity, toSign, config)
} else {
err = openpgp.DetachSign(w, signEntity, toSign, config)
}
}
return err
}
// VerifyString may return errors.ErrSignatureExpired (defined in
// golang.org/x/crypto/openpgp/errors) In this case signature has been verified
// successfully, but it is either expired or in the future.
func (kr *KeyRing) VerifyString(message, signature string, sign *KeyRing) (err error) {
messageReader := strings.NewReader(message)
signatureReader := strings.NewReader(signature)
err = nil
if sign != nil {
for _, e := range sign.entities {
if e.PrivateKey != nil && !e.PrivateKey.Encrypted {
_, err = openpgp.CheckArmoredDetachedSignature(kr.entities, messageReader, signatureReader, nil)
if err == nil || err == pgperrors.ErrSignatureExpired {
return
}
}
}
}
if err == nil {
return errKeyringNotUnlocked
}
return err
}
// Unlock tries to unlock as many keys as possible with the following password. Note
// that keyrings can contain keys locked with different passwords, and thus
// err == nil does not mean that all keys have been successfully decrypted.

View file

@ -32,10 +32,10 @@ var (
testPublicKeyRing *KeyRing
)
// var testIdentity = &Identity{
// Name: "UserID",
// Email: "",
// }
var testIdentity = &Identity{
Name: "UserID",
Email: "",
}
func init() {
var err error
@ -57,16 +57,16 @@ func init() {
}
func TestKeyRing_Decrypt(t *testing.T) {
ss, err := testPrivateKeyRing.DecryptString(readTestFile("keyring_token", false))
decString, err := testPrivateKeyRing.DecryptStringIfNeeded(readTestFile("keyring_token", false))
if err != nil {
t.Fatal("Cannot decrypt token:", err)
}
assert.Exactly(t, testToken, ss.String)
assert.Exactly(t, testToken, decString)
}
func TestKeyRing_Encrypt(t *testing.T) {
encrypted, err := testPublicKeyRing.EncryptString(testToken, nil)
encrypted, err := testPublicKeyRing.EncryptString(testToken, testPrivateKeyRing)
if err != nil {
t.Fatal("Cannot encrypt token:", err)
}
@ -79,6 +79,12 @@ func TestKeyRing_Encrypt(t *testing.T) {
}
assert.Exactly(t, testToken, ss.String)
signatureKeyRing := ss.Signed.KeyRing()
assert.Exactly(t, testPrivateKeyRing, signatureKeyRing)
isby := ss.Signed.IsBy(testPublicKeyRing)
assert.Exactly(t, true, isby)
}
func TestKeyRing_ArmoredPublicKeyString(t *testing.T) {
@ -112,3 +118,32 @@ func TestKeyRing_ArmoredPublicKeyString(t *testing.T) {
assert.Exactly(t, eb, b)
}
func TestCheckPassphrase(t *testing.T) {
encryptedKeyRing, _ := ReadArmoredKeyRing(strings.NewReader(readTestFile("keyring_privateKey", false)))
is_correct := encryptedKeyRing.CheckPassphrase("Wrong password")
assert.Exactly(t, false, is_correct)
is_correct = encryptedKeyRing.CheckPassphrase(testMailboxPassword)
assert.Exactly(t, true, is_correct)
}
func TestIdentities(t *testing.T) {
identities := testPrivateKeyRing.Identities()
assert.Len(t, identities, 1)
assert.Exactly(t, identities[0], testIdentity)
}
func TestFilterExpiredKeys(t *testing.T) {
expiredKey, _ := ReadArmoredKeyRing(strings.NewReader(readTestFile("key_expiredKey", false)))
keys := []*KeyRing {testPrivateKeyRing, expiredKey}
unexpired, err := FilterExpiredKeys(keys)
if err != nil {
t.Fatal("Expected no error while filtering expired keyrings, got:", err)
}
assert.Len(t, unexpired, 1)
assert.Exactly(t, unexpired[0], testPrivateKeyRing)
}

76
crypto/session_test.go Normal file
View file

@ -0,0 +1,76 @@
package crypto
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/ProtonMail/gopenpgp/constants"
)
var testRandomToken []byte
func TestRandomToken(t *testing.T) {
var err error
testRandomToken, err = pgp.RandomToken()
if err != nil {
t.Fatal("Expected no error while generating random token, got:", err)
}
assert.Len(t, testRandomToken, 32)
}
func TestRandomTokenWith(t *testing.T) {
token, err := pgp.RandomTokenWith(40)
if err != nil {
t.Fatal("Expected no error while generating random token, got:", err)
}
assert.Len(t, token, 40)
}
func TestAsymmetricKeyPacket(t *testing.T) {
symmetricKey := &SymmetricKey{
Key: testRandomToken,
Algo: constants.AES256,
}
privateKeyRing, _ := ReadArmoredKeyRing(strings.NewReader(readTestFile("keyring_privateKey", false)))
publicKey, _ := testPrivateKeyRing.GetArmoredPublicKey()
keyPacket, err := pgp.KeyPacketWithPublicKey(symmetricKey, publicKey)
if err != nil {
t.Fatal("Expected no error while generating key packet, got:", err)
}
// Password defined in keyring_test
outputSymmetricKey, err := pgp.GetSessionFromKeyPacket(keyPacket, privateKeyRing, testMailboxPassword)
if err != nil {
t.Fatal("Expected no error while decrypting key packet, got:", err)
}
assert.Exactly(t, symmetricKey, outputSymmetricKey)
}
func TestSymmetricKeyPacket(t *testing.T) {
symmetricKey := &SymmetricKey{
Key: testRandomToken,
Algo: constants.AES256,
}
password := "I like encryption"
keyPacket, err := pgp.SymmetricKeyPacketWithPassword(symmetricKey, password)
if err != nil {
t.Fatal("Expected no error while generating key packet, got:", err)
}
_, err = pgp.GetSessionFromSymmetricPacket(keyPacket, "Wrong password")
assert.EqualError(t, err, "password incorrect")
outputSymmetricKey, err := pgp.GetSessionFromSymmetricPacket(keyPacket, password)
if err != nil {
t.Fatal("Expected no error while decrypting key packet, got:", err)
}
assert.Exactly(t, symmetricKey, outputSymmetricKey)
}

View file

@ -15,21 +15,18 @@ import (
)
// SignTextDetached signs detached text type
func (pgp *GopenPGP) SignTextDetached(
plainText string, privateKey *KeyRing, passphrase string, trim bool,
) (string, error) {
//sign with 0x01 text
if trim {
plainText = internal.TrimNewlines(plainText)
}
signEntity, err := privateKey.GetSigningEntity(passphrase)
func (kr *KeyRing) SignTextDetached(plainText string, passphrase string, trimNewlines bool) (string, error) {
signEntity, err := kr.GetSigningEntity(passphrase)
if err != nil {
return "", err
}
config := &packet.Config{DefaultCipher: packet.CipherAES256, Time: pgp.getTimeGenerator()}
if trimNewlines {
plainText = internal.TrimNewlines(plainText)
}
att := strings.NewReader(plainText)
var outBuf bytes.Buffer
@ -42,9 +39,9 @@ func (pgp *GopenPGP) SignTextDetached(
}
// SignBinDetached Signs detached bin data using string key
func (pgp *GopenPGP) SignBinDetached(plainData []byte, privateKey *KeyRing, passphrase string) (string, error) {
func (kr *KeyRing) SignBinDetached(plainData []byte, passphrase string) (string, error) {
//sign with 0x00
signEntity, err := privateKey.GetSigningEntity(passphrase)
signEntity, err := kr.GetSigningEntity(passphrase)
if err != nil {
return "", err
}
@ -64,15 +61,26 @@ func (pgp *GopenPGP) SignBinDetached(plainData []byte, privateKey *KeyRing, pass
// VerifyTextDetachedSig verifies detached text
// - check if signature is valid using a given publicKey in binary format
func (pgp *GopenPGP) VerifyTextDetachedSig(
signature string, plainText string, publicKey *KeyRing, verifyTime int64,
func (kr *KeyRing) VerifyTextDetachedSig(
signature string, plainText string, verifyTime int64, trimNewlines bool,
) (bool, error) {
if trimNewlines {
plainText = internal.TrimNewlines(plainText)
}
origText := bytes.NewReader(bytes.NewBufferString(plainText).Bytes())
return verifySignature(publicKey.entities, origText, signature, verifyTime)
return verifySignature(kr.GetEntities(), origText, signature, verifyTime)
}
// VerifyBinDetachedSig verifies detached text in binary format
// - check if signature is valid using a given publicKey in binary format
func (kr *KeyRing) VerifyBinDetachedSig(signature string, plainData []byte, verifyTime int64) (bool, error) {
origText := bytes.NewReader(plainData)
return verifySignature(kr.GetEntities(), origText, signature, verifyTime)
}
// Internal
func verifySignature(
pubKeyEntries openpgp.EntityList, origText *bytes.Reader,
signature string, verifyTime int64,
@ -120,13 +128,3 @@ func verifySignature(
// }
return true, nil
}
// VerifyBinDetachedSig verifies detached text in binary format
// - check if signature is valid using a given publicKey in binary format
func (pgp *GopenPGP) VerifyBinDetachedSig(
signature string, plainData []byte, publicKey *KeyRing, verifyTime int64,
) (bool, error) {
origText := bytes.NewReader(plainData)
return verifySignature(publicKey.entities, origText, signature, verifyTime)
}

View file

@ -20,11 +20,11 @@ func TestSignTextDetached(t *testing.T) {
t.Fatal("Cannot read private key:", err)
}
signature, err = pgp.SignTextDetached(signedPlainText, signingKeyRing, "", true)
signature, err = signingKeyRing.SignTextDetached(signedPlainText, "", true)
assert.EqualError(t, err, "gopenpgp: cannot sign message, unable to unlock signer key")
// Password defined in keyring_test
signature, err = pgp.SignTextDetached(signedPlainText, signingKeyRing, testMailboxPassword, true)
signature, err = signingKeyRing.SignTextDetached(signedPlainText, testMailboxPassword, true)
if err != nil {
t.Fatal("Cannot generate signature with encrypted key:", err)
}
@ -37,7 +37,7 @@ func TestSignTextDetached(t *testing.T) {
t.Fatal("Cannot decrypt private key:", err)
}
signatureDec, err := pgp.SignTextDetached(signedPlainText, signingKeyRing, "", true)
signatureDec, err := signingKeyRing.SignTextDetached(signedPlainText, "", true)
if err != nil {
t.Fatal("Cannot generate signature with decrypted key:", err)
}
@ -52,11 +52,11 @@ func TestSignBinDetached(t *testing.T) {
// Reset keyring to locked state
signingKeyRing, _ = ReadArmoredKeyRing(strings.NewReader(readTestFile("keyring_privateKey", false)))
signatureBin, err = pgp.SignBinDetached([]byte(signedPlainText), signingKeyRing, "")
signatureBin, err = signingKeyRing.SignBinDetached([]byte(signedPlainText), "")
assert.EqualError(t, err, "gopenpgp: cannot sign message, unable to unlock signer key")
// Password defined in keyring_test
signatureBin, err = pgp.SignBinDetached([]byte(signedPlainText), signingKeyRing, testMailboxPassword)
signatureBin, err = signingKeyRing.SignBinDetached([]byte(signedPlainText), testMailboxPassword)
if err != nil {
t.Fatal("Cannot generate signature with encrypted key:", err)
}
@ -66,7 +66,7 @@ func TestSignBinDetached(t *testing.T) {
}
func TestVerifyTextDetachedSig(t *testing.T) {
verified, err := pgp.VerifyTextDetachedSig(signature, signedPlainText, signingKeyRing, testTime)
verified, err := signingKeyRing.VerifyTextDetachedSig(signature, signedPlainText, testTime, true)
if err != nil {
t.Fatal("Cannot verify plaintext signature:", err)
}
@ -75,14 +75,14 @@ func TestVerifyTextDetachedSig(t *testing.T) {
}
func TestVerifyTextDetachedSigWrong(t *testing.T) {
verified, err := pgp.VerifyTextDetachedSig(signature, "wrong text", signingKeyRing, testTime)
verified, err := signingKeyRing.VerifyTextDetachedSig(signature, "wrong text", testTime, true)
assert.EqualError(t, err, "gopenpgp: signer is empty")
assert.Exactly(t, false, verified)
}
func TestVerifyBinDetachedSig(t *testing.T) {
verified, err := pgp.VerifyBinDetachedSig(signatureBin, []byte(signedPlainText), signingKeyRing, testTime)
verified, err := signingKeyRing.VerifyBinDetachedSig(signatureBin, []byte(signedPlainText), testTime)
if err != nil {
t.Fatal("Cannot verify binary signature:", err)
}