mirror of https://github.com/perkeep/perkeep.git
Clean up and break up verification code
More testable and readable.
This commit is contained in:
parent
5d1ff03248
commit
c297269e15
|
@ -61,6 +61,142 @@ func openArmoredPublicKeyFile(fileName string) (*packet.PublicKeyPacket, os.Erro
|
|||
return &pk, nil
|
||||
}
|
||||
|
||||
// See doc/json-signing/* for background and details
|
||||
// on these variable names.
|
||||
type VerifyRequest struct {
|
||||
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
|
||||
|
||||
PublicKeyPacket *packet.PublicKeyPacket
|
||||
|
||||
Err os.Error // last error encountered
|
||||
}
|
||||
|
||||
func (vr *VerifyRequest) fail(msg string) bool {
|
||||
vr.Err = os.NewError(msg)
|
||||
return false
|
||||
}
|
||||
|
||||
func (vr *VerifyRequest) ParseSigMap() bool {
|
||||
sigMap := make(map[string]interface{})
|
||||
if err := json.Unmarshal(vr.bs, &sigMap); err != nil {
|
||||
return vr.fail("Invalid JSON in signature")
|
||||
}
|
||||
|
||||
if len(sigMap) != 1 {
|
||||
return vr.fail("signature JSON didn't have exactly 1 key")
|
||||
}
|
||||
|
||||
sigVal, hasCamliSig := sigMap["camliSig"]
|
||||
if !hasCamliSig {
|
||||
return vr.fail("no 'camliSig' key in signature")
|
||||
}
|
||||
|
||||
var ok bool
|
||||
vr.CamliSig, ok = sigVal.(string)
|
||||
if !ok {
|
||||
return vr.fail("camliSig not a string")
|
||||
}
|
||||
|
||||
log.Printf("camliSig = [%s]", vr.CamliSig)
|
||||
return true
|
||||
}
|
||||
|
||||
func (vr *VerifyRequest) ParsePayloadMap() bool {
|
||||
vr.PayloadMap = make(map[string]interface{})
|
||||
pm := vr.PayloadMap
|
||||
|
||||
if err := json.Unmarshal(vr.bpj, &pm); err != nil {
|
||||
return vr.fail("parse error; payload JSON is invalid")
|
||||
}
|
||||
log.Printf("Got json: %v", pm)
|
||||
|
||||
if _, hasVersion := pm["camliVersion"]; !hasVersion {
|
||||
return vr.fail("Missing 'camliVersion' in the JSON payload")
|
||||
}
|
||||
|
||||
signer, hasSigner := pm["camliSigner"]
|
||||
if !hasSigner {
|
||||
return vr.fail("Missing 'camliSigner' in the JSON payload")
|
||||
}
|
||||
|
||||
if _, ok := signer.(string); !ok {
|
||||
return vr.fail("Invalid 'camliSigner' in the JSON payload")
|
||||
}
|
||||
|
||||
vr.CamliSigner = blobref.Parse(signer.(string))
|
||||
if vr.CamliSigner == nil {
|
||||
return vr.fail("Malformed 'camliSigner' blobref in the JSON payload")
|
||||
}
|
||||
|
||||
log.Printf("Signer: %v", vr.CamliSigner)
|
||||
return true
|
||||
}
|
||||
|
||||
func (vr *VerifyRequest) FindAndParsePublicKeyBlob() bool {
|
||||
// verify that we have the public key signature file
|
||||
publicKeyFile := fmt.Sprintf("%s/%s.camli", *flagPubKeyDir, vr.CamliSigner.String())
|
||||
pk, err := openArmoredPublicKeyFile(publicKeyFile)
|
||||
if err != nil {
|
||||
return vr.fail(fmt.Sprintf("Error opening public key file: %v", err))
|
||||
}
|
||||
log.Printf("Public key packet: %v", pk)
|
||||
vr.PublicKeyPacket = pk
|
||||
return true;
|
||||
}
|
||||
|
||||
func (vr *VerifyRequest) VerifySignature() bool {
|
||||
log.Printf("TODO: implement VerifySignature")
|
||||
return false
|
||||
}
|
||||
|
||||
func NewVerificationRequest(sjson string) (vr *VerifyRequest) {
|
||||
vr = new(VerifyRequest)
|
||||
vr.ba = []byte(sjson)
|
||||
|
||||
sigIndex := bytes.LastIndex(vr.ba, []byte(sigSeparator))
|
||||
if sigIndex == -1 {
|
||||
vr.Err = os.NewError("no 13-byte camliSig separator found in sjson")
|
||||
return
|
||||
}
|
||||
|
||||
// "Bytes Payload"
|
||||
vr.bp = vr.ba[0: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[sigIndex] = '}'
|
||||
vr.bs = []byte("{" + sjson[sigIndex+1:])
|
||||
|
||||
log.Printf("BP = [%s]", string(vr.bp))
|
||||
log.Printf("BPJ = [%s]", string(vr.bpj))
|
||||
log.Printf("BS = [%s]", string(vr.bs))
|
||||
|
||||
if !(vr.ParseSigMap() &&
|
||||
vr.ParsePayloadMap() &&
|
||||
vr.FindAndParsePublicKeyBlob() &&
|
||||
vr.VerifySignature()) {
|
||||
// Don't allow dumbs callers to accidentally check this
|
||||
// if it's not valid.
|
||||
vr.PayloadMap = nil
|
||||
if vr.Err == nil {
|
||||
// The other functions just fill this in already,
|
||||
// but just in case:
|
||||
vr.Err = os.NewError("Verification failed")
|
||||
}
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func handleVerify(conn http.ResponseWriter, req *http.Request) {
|
||||
if !(req.Method == "POST" && req.URL.Path == "/camli/sig/verify") {
|
||||
http_util.BadRequestError(conn, "Inconfigured handler.")
|
||||
|
@ -83,89 +219,13 @@ func handleVerify(conn http.ResponseWriter, req *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
// See doc/json-signing/* for background and details
|
||||
// on these variable names.
|
||||
|
||||
BA := []byte(sjson)
|
||||
sigIndex := bytes.LastIndex(BA, []byte(sigSeparator))
|
||||
if sigIndex == -1 {
|
||||
verifyFail("no 13-byte camliSig separator found in sjson")
|
||||
vreq := NewVerificationRequest(sjson)
|
||||
log.Printf("Request is: %q", vreq)
|
||||
if vreq.Err != nil {
|
||||
verifyFail(vreq.Err.String())
|
||||
return
|
||||
}
|
||||
|
||||
// "Bytes Payload"
|
||||
BP := BA[0: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".
|
||||
BPJ := BA[0:sigIndex+1]
|
||||
BPJ[sigIndex] = '}'
|
||||
|
||||
BS := []byte("{" + sjson[sigIndex+1:])
|
||||
|
||||
log.Printf("BP = [%s]", string(BP))
|
||||
log.Printf("BPJ = [%s]", string(BPJ))
|
||||
log.Printf("BS = [%s]", string(BS))
|
||||
|
||||
sjsonKeys := make(map[string]interface{})
|
||||
if err := json.Unmarshal(BPJ, &sjsonKeys); err != nil {
|
||||
verifyFail("parse error; JSON is invalid")
|
||||
return
|
||||
}
|
||||
log.Printf("Got json: %v", sjsonKeys)
|
||||
|
||||
if _, hasVersion := sjsonKeys["camliVersion"]; !hasVersion {
|
||||
verifyFail("Missing 'camliVersion' in the JSON payload")
|
||||
return
|
||||
}
|
||||
|
||||
signer, hasSigner := sjsonKeys["camliSigner"]
|
||||
if !hasSigner {
|
||||
verifyFail("Missing 'camliSigner' in the JSON payload")
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := signer.(string); !ok {
|
||||
verifyFail("Invalid 'camliSigner' in the JSON payload")
|
||||
return
|
||||
}
|
||||
|
||||
signerBlob := blobref.Parse(signer.(string))
|
||||
if signerBlob == nil {
|
||||
verifyFail("Malformed 'camliSigner' blobref in the JSON payload")
|
||||
return
|
||||
}
|
||||
log.Printf("Signer: %v", signerBlob)
|
||||
|
||||
sigKeyMap := make(map[string]interface{})
|
||||
if err := json.Unmarshal(BS, &sigKeyMap); err != nil {
|
||||
verifyFail("parse error; signature JSON invalid")
|
||||
return
|
||||
}
|
||||
log.Printf("Got sigKeyMap: %v", sigKeyMap)
|
||||
if len(sigKeyMap) != 1 {
|
||||
verifyFail("signature JSON didn't have exactly 1 key")
|
||||
return
|
||||
}
|
||||
sigVal, hasCamliSig := sigKeyMap["camliSig"]
|
||||
if !hasCamliSig {
|
||||
verifyFail("no 'camliSig' key in signature")
|
||||
return
|
||||
}
|
||||
|
||||
log.Printf("sigValu = [%s]", sigVal)
|
||||
|
||||
// verify that we have the public key signature file
|
||||
publicKeyFile := fmt.Sprintf("%s/%s.camli", *flagPubKeyDir, signerBlob.String())
|
||||
|
||||
pk, err := openArmoredPublicKeyFile(publicKeyFile)
|
||||
if err != nil {
|
||||
verifyFail(fmt.Sprintf("Error opening public key file: %v", err))
|
||||
return
|
||||
}
|
||||
log.Printf("Public key packet: %v", pk)
|
||||
|
||||
log.Printf("TODO: finish implementing")
|
||||
conn.WriteHeader(http.StatusNotImplemented)
|
||||
conn.Write([]byte("TODO: implement"))
|
||||
|
|
Loading…
Reference in New Issue