mirror of https://github.com/perkeep/perkeep.git
jsonsign: more tests
This commit is contained in:
parent
33e2d32f99
commit
ae15620ea2
|
@ -62,16 +62,50 @@ iNSWzNQiTT6k7fumOABCoSZsow/AJxQSxqKOJBjgpKjIKCgY
|
|||
=ru0J
|
||||
-----END PGP PUBLIC KEY BLOCK-----`
|
||||
|
||||
var pubKeyBlob1 = &blobref.TestBlob{pubKey1}
|
||||
var pubKey2 = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v1.4.10 (GNU/Linux)
|
||||
|
||||
mQENBEz61lcBCADRQhcb9LIQdV3LhU5f7cCjOctmLsL+y4k4VKmznssWORiNPEHQ
|
||||
13CxFLjRDN2OQYXi4NSqoUqHNMsRTUJTVW0CnznUUb11ibXLUYW/zbPN9dWs8PlI
|
||||
UZSScS1dxtGKKk+VfXrvc1LB6pqrjWmAgEwQxsBWToW2IFR/eMo1LiVU83dzpKU1
|
||||
n/yb8Jy9wizchspd9xecK2X0JnKLRIJklLTAKQ+XKP+cSwXmShcs+3pxu5f4piqF
|
||||
7oBfh9noFA0vdGYNBGVch3DfJwFcTmLkkGFZKdiehWncvVYT1jxUkJvc0K44ohDH
|
||||
smkG2VZm3rJCwi2GIWA/clLiDAhYM6vTI3oZABEBAAG0K0NhbWxpIFRlc3R1c2Vy
|
||||
IFR3byA8Y2FtbGkudGVzdEBleGFtcGxlLmNvbT6JATgEEwECACIFAkz61lcCGwMG
|
||||
CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEIUeCLJL7Fq1c44IAKOJjymoinXd
|
||||
9NOW7GfpHCmynzSflJJoRcRzsNz83lJbwITYCd1ExQxkO84sMKRPJiefc9epP/Hg
|
||||
8V4b1SwkGi+A8WaoH/OZtEM8HA7iEKmV+wjfZE6kt+y0trbxdu42W5hLz/uerrNl
|
||||
G+r90mBNjmJXsZxmwaZEFrLtFlqezCzdQSur35QLZMFvW6aoYFTAgOk1rk9lBtkC
|
||||
DePaadZQGHNWr+Rw2M5xXv9BZ4Rrjl6VLjE2DuqMSBVkelckBcsmRppaszF3J8y3
|
||||
9gd10xC+5/LVfhU8niDZjY3pIcjQwsYJ+Jdyce2OEYo1i6pQDiq2WewXdCJ28DVK
|
||||
1SX38WFB3Zm5AQ0ETPrWVwEIAMQ/dRCrkhy2D0SzJV5o/Z3uVf1nFLlEFfavV45F
|
||||
8wtG/Bi5EuZXoYqU+O79O7sPy9Dw3Qhxtvt159l6/sSLXYTBBs3HJ2zTVhI5tbAZ
|
||||
DMz4/wfkRP/h74KuXnWfin1ynswzqdPVXgrRvTsfHbkwbTaRwbx186VYqM17Wqy2
|
||||
hFAUCdQIIW0+X9upjGek+kESldSzeUV87fr3IN/pq6fRc90h8xAKfz6mMc7AAUUL
|
||||
NLNxb9y18u4Bw+fKgc6W7YxB+gQN1IajmgGPcqUTxNxydWF974iqsKnkZpzHg0Ce
|
||||
zGGLWzCAGzI8drltgJPBoGGo56U1s2hW6JzLUi03phV10H8AEQEAAYkBHwQYAQIA
|
||||
CQUCTPrWVwIbDAAKCRCFHgiyS+xatUPIB/9VPOeIxH5UcNYuZT+LW2tdcWPNhyQ+
|
||||
u5UC9DC2A3F9AYNYRwDcSVOMmqS8hPJxg/biFxFoGFgm14Vp0nd1blOHcmNXcDzk
|
||||
XTv2CKcUbgYpvDVmfCcEf6seSf+/RDbyj/VzebE6yvXuwsPus7ntbMw+Dum42z55
|
||||
XYiYsfEFu25RtxritG3eYklCKymdRg615pj8zoRpL5Z1NAy5QBb5sv5hPbdGSyqL
|
||||
Kw6aLcq2IU7kev6CYJVyXzJ1XtsYv/o7hzKKmZ5WcwuPc9Yqh6onJt1RC8jzz8Ry
|
||||
jyVNPb8AaaWVW1uZLg6Em61aKnbOG10B30m3CQ8dwBjF9hgmtcY0IZ/Y
|
||||
=OWHA
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
`
|
||||
|
||||
var pubKeyBlob1 = &blobref.TestBlob{pubKey1} // user 1
|
||||
var pubKeyBlob2 = &blobref.TestBlob{pubKey2} // user 2
|
||||
|
||||
var testFetcher = &TestFetcher{}
|
||||
|
||||
func init() {
|
||||
testFetcher.AddBlob(pubKeyBlob1)
|
||||
testFetcher.AddBlob(pubKeyBlob2)
|
||||
}
|
||||
|
||||
func TestSigningBadInput(t *testing.T) {
|
||||
sr := newRequest()
|
||||
sr := newRequest(1)
|
||||
|
||||
sr.UnsignedJson = ""
|
||||
_, err := sr.Sign()
|
||||
|
@ -90,29 +124,48 @@ func TestSigningBadInput(t *testing.T) {
|
|||
ExpectErrorContains(t, err, "\"camliSigner\" key is malformed or unsupported", "empty camliSigner")
|
||||
}
|
||||
|
||||
func newRequest() *SignRequest {
|
||||
func newRequest(userN int) *SignRequest {
|
||||
if userN < 1 || userN > 2 {
|
||||
panic("invalid userid")
|
||||
}
|
||||
suffix := ".gpg"
|
||||
if userN == 2 {
|
||||
suffix = "2.gpg"
|
||||
}
|
||||
return &SignRequest{
|
||||
UnsignedJson: "",
|
||||
Fetcher: testFetcher,
|
||||
UseAgent: false,
|
||||
ServerMode: true,
|
||||
SecretKeyringPath: "./testdata/test-secring.gpg",
|
||||
KeyringPath: "./testdata/test-keyring.gpg",
|
||||
SecretKeyringPath: "./testdata/test-secring" + suffix,
|
||||
KeyringPath: "./testdata/test-keyring" + suffix,
|
||||
}
|
||||
}
|
||||
|
||||
func TestSigning(t *testing.T) {
|
||||
sr := newRequest()
|
||||
sr.UnsignedJson = fmt.Sprintf(`{"camliVersion": 1, "camliSigner": %q }`, pubKeyBlob1.BlobRef().String())
|
||||
sr := newRequest(1)
|
||||
sr.UnsignedJson = fmt.Sprintf(`{"camliVersion": 1, "foo": "fooVal", "camliSigner": %q }`, pubKeyBlob1.BlobRef().String())
|
||||
signed, err := sr.Sign()
|
||||
AssertNil(t, err, "no error signing")
|
||||
Assert(t, strings.Contains(signed, `"camliSig":`), "got a camliSig")
|
||||
|
||||
vr := NewVerificationRequest(signed, testFetcher)
|
||||
if !vr.Verify() {
|
||||
t.Errorf("verification failed on signed json [%s]: %v", signed, vr.Err)
|
||||
t.Fatalf("verification failed on signed json [%s]: %v", signed, vr.Err)
|
||||
}
|
||||
t.Logf("TODO: finish these tests; verify things round-trip, verify GPG external-vs-Go sign & verify round-trip, test signatures from wrong signer don't verify, etc.")
|
||||
ExpectString(t, "fooVal", vr.PayloadMap["foo"].(string), "PayloadMap")
|
||||
ExpectString(t, "2931A67C26F5ABDA", vr.SignerKeyId, "SignerKeyId")
|
||||
|
||||
// Test a non-matching signature.
|
||||
fakeSigned := strings.Replace(signed, pubKeyBlob1.BlobRef().String(), pubKeyBlob2.BlobRef().String(), 1)
|
||||
vr = NewVerificationRequest(fakeSigned, testFetcher)
|
||||
if vr.Verify() {
|
||||
t.Fatalf("unexpected verification of faked signature")
|
||||
}
|
||||
AssertErrorContains(t, vr.Err, "OpenPGP signature invalid: hash tag doesn't match",
|
||||
"expected signature verification error")
|
||||
|
||||
t.Logf("TODO: verify GPG-vs-Go sign & verify interop both ways, once implemented.")
|
||||
}
|
||||
|
||||
type TestFetcher struct {
|
||||
|
|
|
@ -21,7 +21,7 @@ import (
|
|||
"os"
|
||||
"io"
|
||||
"crypto/openpgp/armor"
|
||||
"crypto/openpgp/packet"
|
||||
"crypto/openpgp/packet"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
|
|
@ -39,16 +39,16 @@ var flagSecretRing *string = flag.String("secret-keyring", "./test/test-secring.
|
|||
|
||||
|
||||
type SignRequest struct {
|
||||
UnsignedJson string
|
||||
Fetcher blobref.Fetcher
|
||||
UseAgent bool
|
||||
UnsignedJson string
|
||||
Fetcher blobref.Fetcher
|
||||
UseAgent bool
|
||||
|
||||
// In server-mode, don't use any default (user) keys
|
||||
// TODO: formalize what this means?
|
||||
ServerMode bool
|
||||
ServerMode bool
|
||||
|
||||
SecretKeyringPath string
|
||||
KeyringPath string
|
||||
KeyringPath string
|
||||
}
|
||||
|
||||
func (sr *SignRequest) publicRingPath() string {
|
||||
|
@ -109,12 +109,12 @@ func (sr *SignRequest) Sign() (signedJson string, err os.Error) {
|
|||
if len(trimmedJson) == 0 || trimmedJson[len(trimmedJson)-1] != '}' {
|
||||
return inputfail("json parameter lacks trailing '}'")
|
||||
}
|
||||
trimmedJson = trimmedJson[0:len(trimmedJson)-1]
|
||||
trimmedJson = trimmedJson[0 : len(trimmedJson)-1]
|
||||
|
||||
args := []string{"gpg",
|
||||
"--local-user", fmt.Sprintf("%X", pk.Fingerprint[len(pk.Fingerprint)-4:]),
|
||||
"--detach-sign",
|
||||
"--armor"}
|
||||
"--local-user", fmt.Sprintf("%X", pk.Fingerprint[len(pk.Fingerprint)-4:]),
|
||||
"--detach-sign",
|
||||
"--armor"}
|
||||
|
||||
if sr.UseAgent {
|
||||
args = append(args, "--use-agent")
|
||||
|
@ -134,9 +134,9 @@ func (sr *SignRequest) Sign() (signedJson string, err os.Error) {
|
|||
args,
|
||||
os.Environ(),
|
||||
".",
|
||||
exec.Pipe, // stdin
|
||||
exec.Pipe, // stdout
|
||||
exec.Pipe) // stderr
|
||||
exec.Pipe, // stdin
|
||||
exec.Pipe, // stdout
|
||||
exec.Pipe) // stderr
|
||||
if err != nil {
|
||||
return execfail("Failed to run gpg.")
|
||||
}
|
||||
|
@ -162,12 +162,11 @@ func (sr *SignRequest) Sign() (signedJson string, err os.Error) {
|
|||
|
||||
index1 := strings.Index(output, "\n\n")
|
||||
index2 := strings.Index(output, "\n-----")
|
||||
if (index1 == -1 || index2 == -1) {
|
||||
if index1 == -1 || index2 == -1 {
|
||||
return execfail("Failed to parse signature from gpg.")
|
||||
}
|
||||
inner := output[index1+2:index2]
|
||||
inner := output[index1+2 : index2]
|
||||
signature := strings.Replace(inner, "\n", "", -1)
|
||||
|
||||
return fmt.Sprintf("%s,\"camliSig\":\"%s\"}\n", trimmedJson, signature), nil
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
"crypto/sha1"
|
||||
)
|
||||
"crypto/sha1"
|
||||
)
|
||||
|
||||
var logf = log.Printf
|
||||
|
||||
|
@ -60,20 +60,22 @@ func reArmor(line string) string {
|
|||
// See doc/json-signing/* for background and details
|
||||
// on these variable names.
|
||||
type VerifyRequest struct {
|
||||
fetcher blobref.Fetcher // fetcher used to find public key blob
|
||||
fetcher blobref.Fetcher // fetcher used to find public key blob
|
||||
|
||||
ba []byte // "bytes all"
|
||||
bp []byte // "bytes payload" (the part that is signed)
|
||||
bpj []byte // "bytes payload, JSON" (BP + "}")
|
||||
bs []byte // "bytes signature", "{" + separator + camliSig, valid JSON
|
||||
|
||||
CamliSigner *blobref.BlobRef
|
||||
PayloadMap map[string]interface{} // The JSON values from BPJ
|
||||
CamliSig string
|
||||
ba []byte // "bytes all"
|
||||
bp []byte // "bytes payload" (the part that is signed)
|
||||
bpj []byte // "bytes payload, JSON" (BP + "}")
|
||||
bs []byte // "bytes signature", "{" + separator + camliSig, valid JSON
|
||||
|
||||
CamliSigner *blobref.BlobRef
|
||||
CamliSig string
|
||||
PublicKeyPacket *packet.PublicKey
|
||||
|
||||
Err os.Error // last error encountered
|
||||
// set if Verify() returns true:
|
||||
PayloadMap map[string]interface{} // The JSON values from BPJ
|
||||
SignerKeyId string
|
||||
|
||||
Err os.Error // last error encountered
|
||||
}
|
||||
|
||||
func (vr *VerifyRequest) fail(msg string) bool {
|
||||
|
@ -143,7 +145,7 @@ func (vr *VerifyRequest) FindAndParsePublicKeyBlob() bool {
|
|||
return vr.fail(fmt.Sprintf("error opening public key file: %v", err))
|
||||
}
|
||||
vr.PublicKeyPacket = pk
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
func (vr *VerifyRequest) VerifySignature() bool {
|
||||
|
@ -169,11 +171,12 @@ func (vr *VerifyRequest) VerifySignature() bool {
|
|||
return vr.fail("I can only verify binary signatures")
|
||||
}
|
||||
hash := sha1.New()
|
||||
hash.Write(vr.bp) // payload bytes
|
||||
hash.Write(vr.bp) // payload bytes
|
||||
err = vr.PublicKeyPacket.VerifySignature(hash, sig)
|
||||
if err != nil {
|
||||
return vr.fail(fmt.Sprintf("bad signature: %s", err))
|
||||
}
|
||||
vr.SignerKeyId = vr.PublicKeyPacket.KeyIdString()
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -181,7 +184,7 @@ func NewVerificationRequest(sjson string, fetcher blobref.Fetcher) (vr *VerifyRe
|
|||
vr = new(VerifyRequest)
|
||||
vr.ba = []byte(sjson)
|
||||
vr.fetcher = fetcher
|
||||
|
||||
|
||||
sigIndex := bytes.LastIndex(vr.ba, []byte(sigSeparator))
|
||||
if sigIndex == -1 {
|
||||
vr.Err = os.NewError("jsonsign: no 13-byte camliSig separator found in sjson")
|
||||
|
@ -189,12 +192,12 @@ func NewVerificationRequest(sjson string, fetcher blobref.Fetcher) (vr *VerifyRe
|
|||
}
|
||||
|
||||
// "Bytes Payload"
|
||||
vr.bp = vr.ba[0:sigIndex]
|
||||
vr.bp = vr.ba[:sigIndex]
|
||||
|
||||
// "Bytes Payload JSON". Note we re-use the memory (the ",")
|
||||
// from BA in BPJ, so we can't re-use that "," byte for
|
||||
// the opening "{" in "BS".
|
||||
vr.bpj = vr.ba[0:sigIndex+1]
|
||||
vr.bpj = vr.ba[:sigIndex+1]
|
||||
vr.bpj[sigIndex] = '}'
|
||||
vr.bs = []byte("{" + sjson[sigIndex+1:])
|
||||
return
|
||||
|
@ -209,7 +212,7 @@ func (vr *VerifyRequest) Verify() bool {
|
|||
vr.ParsePayloadMap() &&
|
||||
vr.FindAndParsePublicKeyBlob() &&
|
||||
vr.VerifySignature() {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
// Don't allow dumbs callers to accidentally check this
|
||||
|
|
Loading…
Reference in New Issue